From 47f33cec2582101485ed93d041d069118a62b5cf Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Mon, 31 Jan 2022 15:56:05 -0500 Subject: [PATCH] QPDFJob: add test cases --- libqpdf/QPDFJob_json.cc | 8 ++ qpdf/qpdf.testcov | 7 ++ qpdf/qtest/qpdf.test | 87 +++++++++++++++ .../qtest/qpdf/bad-bare-option-false-json.out | 10 ++ qpdf/qtest/qpdf/bad-choice-mismatch-json.out | 10 ++ .../bad-encrypt-duplicate-key-length-json.out | 10 ++ .../bad-encrypt-missing-password-json.out | 10 ++ .../qpdf/bad-encrypt-no-key-length-json.out | 10 ++ .../qpdf/bad-json-bare-option-false.json | 7 ++ qpdf/qtest/qpdf/bad-json-choice-mismatch.json | 7 ++ ...bad-json-encrypt-duplicate-key-length.json | 14 +++ .../bad-json-encrypt-missing-password.json | 11 ++ .../qpdf/bad-json-encrypt-no-key-length.json | 10 ++ qpdf/qtest/qpdf/bad-json-error-json.out | 10 ++ qpdf/qtest/qpdf/bad-json-json-error.json | 10 ++ qpdf/qtest/qpdf/bad-json-pages-no-file.json | 9 ++ qpdf/qtest/qpdf/bad-json-schema-error.json | 12 +++ qpdf/qtest/qpdf/bad-pages-no-file-json.out | 10 ++ qpdf/qtest/qpdf/bad-schema-error-json.out | 11 ++ qpdf/qtest/qpdf/job-api.out | 8 ++ qpdf/qtest/qpdf/job-json-add-attachments.json | 27 +++++ qpdf/qtest/qpdf/job-json-add-attachments.pdf | Bin 0 -> 1715 bytes qpdf/qtest/qpdf/job-json-choice-match.json | 12 +++ qpdf/qtest/qpdf/job-json-choice-match.pdf | Bin 0 -> 743 bytes .../qtest/qpdf/job-json-copy-attachments.json | 26 +++++ qpdf/qtest/qpdf/job-json-copy-attachments.pdf | Bin 0 -> 2527 bytes qpdf/qtest/qpdf/job-json-empty-input.json | 23 ++++ qpdf/qtest/qpdf/job-json-empty-input.pdf | Bin 0 -> 2546 bytes qpdf/qtest/qpdf/job-json-encrypt-128.json | 19 ++++ qpdf/qtest/qpdf/job-json-encrypt-128.pdf | Bin 0 -> 7439 bytes ...ob-json-encrypt-256-with-restrictions.json | 20 ++++ ...job-json-encrypt-256-with-restrictions.out | 16 +++ qpdf/qtest/qpdf/job-json-encrypt-40.json | 19 ++++ qpdf/qtest/qpdf/job-json-encrypt-40.pdf | 39 +++++++ .../qpdf/job-json-input-file-password.json | 14 +++ .../qpdf/job-json-input-file-password.pdf | Bin 0 -> 7343 bytes qpdf/qtest/qpdf/job-json-misc-options.json | 13 +++ qpdf/qtest/qpdf/job-json-misc-options.pdf | Bin 0 -> 1285 bytes qpdf/qtest/qpdf/job-json-output.json | 16 +++ qpdf/qtest/qpdf/job-json-output.out.json | 28 +++++ qpdf/qtest/qpdf/job-json-replace-input.json | 12 +++ qpdf/qtest/qpdf/job-json-replace-input.pdf | Bin 0 -> 743 bytes .../job-json-underlay-overlay-password.json | 23 ++++ .../job-json-underlay-overlay-password.pdf | Bin 0 -> 2098 bytes .../qtest/qpdf/job-json-underlay-overlay.json | 23 ++++ qpdf/qtest/qpdf/job-json-underlay-overlay.pdf | Bin 0 -> 17541 bytes qpdf/qtest/qpdf/job-partial-json.out | 3 + qpdf/qtest/qpdf/job-partial.json | 12 +++ qpdf/qtest/qpdf/job-show-encryption.json | 5 + qpdf/qtest/qpdf/test84.pdf | 101 ++++++++++++++++++ qpdf/test_driver.cc | 82 +++++++++++++- 51 files changed, 802 insertions(+), 2 deletions(-) create mode 100644 qpdf/qtest/qpdf/bad-bare-option-false-json.out create mode 100644 qpdf/qtest/qpdf/bad-choice-mismatch-json.out create mode 100644 qpdf/qtest/qpdf/bad-encrypt-duplicate-key-length-json.out create mode 100644 qpdf/qtest/qpdf/bad-encrypt-missing-password-json.out create mode 100644 qpdf/qtest/qpdf/bad-encrypt-no-key-length-json.out create mode 100644 qpdf/qtest/qpdf/bad-json-bare-option-false.json create mode 100644 qpdf/qtest/qpdf/bad-json-choice-mismatch.json create mode 100644 qpdf/qtest/qpdf/bad-json-encrypt-duplicate-key-length.json create mode 100644 qpdf/qtest/qpdf/bad-json-encrypt-missing-password.json create mode 100644 qpdf/qtest/qpdf/bad-json-encrypt-no-key-length.json create mode 100644 qpdf/qtest/qpdf/bad-json-error-json.out create mode 100644 qpdf/qtest/qpdf/bad-json-json-error.json create mode 100644 qpdf/qtest/qpdf/bad-json-pages-no-file.json create mode 100644 qpdf/qtest/qpdf/bad-json-schema-error.json create mode 100644 qpdf/qtest/qpdf/bad-pages-no-file-json.out create mode 100644 qpdf/qtest/qpdf/bad-schema-error-json.out create mode 100644 qpdf/qtest/qpdf/job-api.out create mode 100644 qpdf/qtest/qpdf/job-json-add-attachments.json create mode 100644 qpdf/qtest/qpdf/job-json-add-attachments.pdf create mode 100644 qpdf/qtest/qpdf/job-json-choice-match.json create mode 100644 qpdf/qtest/qpdf/job-json-choice-match.pdf create mode 100644 qpdf/qtest/qpdf/job-json-copy-attachments.json create mode 100644 qpdf/qtest/qpdf/job-json-copy-attachments.pdf create mode 100644 qpdf/qtest/qpdf/job-json-empty-input.json create mode 100644 qpdf/qtest/qpdf/job-json-empty-input.pdf create mode 100644 qpdf/qtest/qpdf/job-json-encrypt-128.json create mode 100644 qpdf/qtest/qpdf/job-json-encrypt-128.pdf create mode 100644 qpdf/qtest/qpdf/job-json-encrypt-256-with-restrictions.json create mode 100644 qpdf/qtest/qpdf/job-json-encrypt-256-with-restrictions.out create mode 100644 qpdf/qtest/qpdf/job-json-encrypt-40.json create mode 100644 qpdf/qtest/qpdf/job-json-encrypt-40.pdf create mode 100644 qpdf/qtest/qpdf/job-json-input-file-password.json create mode 100644 qpdf/qtest/qpdf/job-json-input-file-password.pdf create mode 100644 qpdf/qtest/qpdf/job-json-misc-options.json create mode 100644 qpdf/qtest/qpdf/job-json-misc-options.pdf create mode 100644 qpdf/qtest/qpdf/job-json-output.json create mode 100644 qpdf/qtest/qpdf/job-json-output.out.json create mode 100644 qpdf/qtest/qpdf/job-json-replace-input.json create mode 100644 qpdf/qtest/qpdf/job-json-replace-input.pdf create mode 100644 qpdf/qtest/qpdf/job-json-underlay-overlay-password.json create mode 100644 qpdf/qtest/qpdf/job-json-underlay-overlay-password.pdf create mode 100644 qpdf/qtest/qpdf/job-json-underlay-overlay.json create mode 100644 qpdf/qtest/qpdf/job-json-underlay-overlay.pdf create mode 100644 qpdf/qtest/qpdf/job-partial-json.out create mode 100644 qpdf/qtest/qpdf/job-partial.json create mode 100644 qpdf/qtest/qpdf/job-show-encryption.json create mode 100644 qpdf/qtest/qpdf/test84.pdf diff --git a/libqpdf/QPDFJob_json.cc b/libqpdf/QPDFJob_json.cc index da1e19e2..2da427c3 100644 --- a/libqpdf/QPDFJob_json.cc +++ b/libqpdf/QPDFJob_json.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -108,6 +109,7 @@ Handlers::addBare(bare_handler_t fn) jh->addBoolHandler([this, fn](std::string const& path, bool v){ if (! v) { + QTC::TC("qpdf", "QPDFJob json bare not true"); usage(path + ": value must be true"); } else @@ -140,12 +142,14 @@ Handlers::addChoices(char const** choices, { if (strcmp(*i, p) == 0) { + QTC::TC("qpdf", "QPDFJob json choice match"); matches = true; break; } } if (! matches) { + QTC::TC("qpdf", "QPDFJob json choice mismatch"); std::ostringstream msg; msg << path + ": unexpected value; expected one of "; bool first = true; @@ -307,6 +311,7 @@ Handlers::beginOutputOptionsEncrypt(JSON j) { if (key_len != 0) { + QTC::TC("qpdf", "QPDFJob json encrypt duplicate key length"); usage("exactly one of 40bit, 128bit, or 256bit must be given"); } key_len = QUtil::string_to_int(key.c_str()); @@ -322,12 +327,14 @@ Handlers::beginOutputOptionsEncrypt(JSON j) }); if (key_len == 0) { + QTC::TC("qpdf", "QPDFJob json encrypt no key length"); usage("exactly one of 40bit, 128bit, or 256bit must be given;" " an empty dictionary may be supplied for one of them" " to set the key length without imposing any restrictions"); } if (! (user_password_seen && owner_password_seen)) { + QTC::TC("qpdf", "QPDFJob json encrypt missing password"); usage("the user and owner password are both required; use the empty" " string for the user password if you don't want a password"); } @@ -550,6 +557,7 @@ Handlers::beginOptionsPages(JSON j) }); if (! file_seen) { + QTC::TC("qpdf", "QPDFJob json pages no file"); usage("file is required in page specification"); } this->c_pages->pageSpec( diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index f3936bd4..6648815a 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -630,3 +630,10 @@ qpdf check password password correct 0 qpdf check password not encrypted 0 QPDFJob_config password file 0 QPDFJob_config password stdin 0 +QPDFJob json bare not true 0 +QPDFJob json choice mismatch 0 +QPDFJob json choice match 0 +QPDFJob json encrypt no key length 0 +QPDFJob json encrypt duplicate key length 0 +QPDFJob json encrypt missing password 0 +QPDFJob json pages no file 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index f847cee8..040567cf 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -370,6 +370,93 @@ foreach my $f (@dangling) {$td->FILE => "a.pdf"}, {$td->FILE => "$f-dangling-out.pdf"}); } +show_ntests(); +# ---------- +$td->notify("--- QPDFJob Tests ---"); + +open(F, ">auto-txt") or die; +print F "from file"; +close(F); + +my @bad_json = ( + "bare-option-false", + "choice-mismatch", + "encrypt-duplicate-key-length", + "encrypt-missing-password", + "encrypt-no-key-length", + "pages-no-file", + "schema-error", + "json-error" + ); +my @good_json = ( + "choice-match", + "input-file-password", + "empty-input", + "replace-input", + "encrypt-40", + "encrypt-128", + "encrypt-256-with-restrictions", + "add-attachments", + "copy-attachments", + "underlay-overlay", + "underlay-overlay-password", + "misc-options", + ); +$n_tests += 4 + scalar(@bad_json) + (2 * scalar(@good_json)); + + +foreach my $i (@bad_json) +{ + $td->runtest("QPDFJob bad json: $i", + {$td->COMMAND => "qpdf --job-json-file=bad-json-$i.json"}, + {$td->FILE => "bad-$i-json.out", $td->EXIT_STATUS => 2}, + $td->NORMALIZE_NEWLINES); +} + +foreach my $i (@good_json) +{ + if ($i eq 'replace-input') + { + copy("minimal.pdf", 'a.pdf'); + } + $td->runtest("QPDFJob good json: $i", + {$td->COMMAND => "qpdf --job-json-file=job-json-$i.json"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + if ($i =~ m/encrypt-256/) + { + $td->runtest("check encryption $i", + {$td->COMMAND => + "qpdf a.pdf --password=u" . + " --job-json-file=job-show-encryption.json"}, + {$td->FILE => "job-json-$i.out", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + } + else + { + $td->runtest("check good json $i output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "job-json-$i.pdf"}); + } +} + + +$td->runtest("QPDFJob json partial", + {$td->COMMAND => "test_driver 83 - job-partial.json"}, + {$td->FILE => "job-partial-json.out", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("QPDFJob API", + {$td->COMMAND => "test_driver 84 -"}, + {$td->FILE => "job-api.out", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "test84.pdf"}); +$td->runtest("json output from job", + {$td->COMMAND => "qpdf --job-json-file=job-json-output.json"}, + {$td->FILE => "job-json-output.out.json", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + show_ntests(); # ---------- $td->notify("--- Form Tests ---"); diff --git a/qpdf/qtest/qpdf/bad-bare-option-false-json.out b/qpdf/qtest/qpdf/bad-bare-option-false-json.out new file mode 100644 index 00000000..6fa389f7 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-bare-option-false-json.out @@ -0,0 +1,10 @@ + +qpdf: error with job-json file bad-json-bare-option-false.json: .output.options.qdf: value must be true +Run qpdf--job-json-help for information on the file format. + +For help: + qpdf--help=usage usage information + qpdf--help=topic help on a topic + qpdf--help=--option help on an option + qpdf--help general help and a topic list + diff --git a/qpdf/qtest/qpdf/bad-choice-mismatch-json.out b/qpdf/qtest/qpdf/bad-choice-mismatch-json.out new file mode 100644 index 00000000..16f7aac9 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-choice-mismatch-json.out @@ -0,0 +1,10 @@ + +qpdf: error with job-json file bad-json-choice-mismatch.json: .output.options.objectStreams: unexpected value; expected one of disable, preserve, generate +Run qpdf--job-json-help for information on the file format. + +For help: + qpdf--help=usage usage information + qpdf--help=topic help on a topic + qpdf--help=--option help on an option + qpdf--help general help and a topic list + diff --git a/qpdf/qtest/qpdf/bad-encrypt-duplicate-key-length-json.out b/qpdf/qtest/qpdf/bad-encrypt-duplicate-key-length-json.out new file mode 100644 index 00000000..20490205 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-encrypt-duplicate-key-length-json.out @@ -0,0 +1,10 @@ + +qpdf: error with job-json file bad-json-encrypt-duplicate-key-length.json: exactly one of 40bit, 128bit, or 256bit must be given +Run qpdf--job-json-help for information on the file format. + +For help: + qpdf--help=usage usage information + qpdf--help=topic help on a topic + qpdf--help=--option help on an option + qpdf--help general help and a topic list + diff --git a/qpdf/qtest/qpdf/bad-encrypt-missing-password-json.out b/qpdf/qtest/qpdf/bad-encrypt-missing-password-json.out new file mode 100644 index 00000000..41e09114 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-encrypt-missing-password-json.out @@ -0,0 +1,10 @@ + +qpdf: error with job-json file bad-json-encrypt-missing-password.json: the user and owner password are both required; use the empty string for the user password if you don't want a password +Run qpdf--job-json-help for information on the file format. + +For help: + qpdf--help=usage usage information + qpdf--help=topic help on a topic + qpdf--help=--option help on an option + qpdf--help general help and a topic list + diff --git a/qpdf/qtest/qpdf/bad-encrypt-no-key-length-json.out b/qpdf/qtest/qpdf/bad-encrypt-no-key-length-json.out new file mode 100644 index 00000000..475937c6 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-encrypt-no-key-length-json.out @@ -0,0 +1,10 @@ + +qpdf: error with job-json file bad-json-encrypt-no-key-length.json: exactly one of 40bit, 128bit, or 256bit must be given; an empty dictionary may be supplied for one of them to set the key length without imposing any restrictions +Run qpdf--job-json-help for information on the file format. + +For help: + qpdf--help=usage usage information + qpdf--help=topic help on a topic + qpdf--help=--option help on an option + qpdf--help general help and a topic list + diff --git a/qpdf/qtest/qpdf/bad-json-bare-option-false.json b/qpdf/qtest/qpdf/bad-json-bare-option-false.json new file mode 100644 index 00000000..c42380a9 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-bare-option-false.json @@ -0,0 +1,7 @@ +{ + "output": { + "options": { + "qdf": false + } + } +} diff --git a/qpdf/qtest/qpdf/bad-json-choice-mismatch.json b/qpdf/qtest/qpdf/bad-json-choice-mismatch.json new file mode 100644 index 00000000..45143a14 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-choice-mismatch.json @@ -0,0 +1,7 @@ +{ + "output": { + "options": { + "objectStreams": "potato" + } + } +} diff --git a/qpdf/qtest/qpdf/bad-json-encrypt-duplicate-key-length.json b/qpdf/qtest/qpdf/bad-json-encrypt-duplicate-key-length.json new file mode 100644 index 00000000..4afa96fd --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-encrypt-duplicate-key-length.json @@ -0,0 +1,14 @@ +{ + "output": { + "options": { + "encrypt": { + "userPassword": "", + "ownerPassword": "someOwnerThing", + "256bit": { + }, + "128bit": { + } + } + } + } +} diff --git a/qpdf/qtest/qpdf/bad-json-encrypt-missing-password.json b/qpdf/qtest/qpdf/bad-json-encrypt-missing-password.json new file mode 100644 index 00000000..8c9a14a5 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-encrypt-missing-password.json @@ -0,0 +1,11 @@ +{ + "output": { + "options": { + "encrypt": { + "userPassword": "", + "256bit": { + } + } + } + } +} diff --git a/qpdf/qtest/qpdf/bad-json-encrypt-no-key-length.json b/qpdf/qtest/qpdf/bad-json-encrypt-no-key-length.json new file mode 100644 index 00000000..997dfe79 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-encrypt-no-key-length.json @@ -0,0 +1,10 @@ +{ + "output": { + "options": { + "encrypt": { + "userPassword": "", + "ownerPassword": "someOwnerThing" + } + } + } +} diff --git a/qpdf/qtest/qpdf/bad-json-error-json.out b/qpdf/qtest/qpdf/bad-json-error-json.out new file mode 100644 index 00000000..e8933d72 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-error-json.out @@ -0,0 +1,10 @@ + +qpdf: error with job-json file bad-json-json-error.json: JSON: offset 130: unexpected dictionary end delimiter +Run qpdf--job-json-help for information on the file format. + +For help: + qpdf--help=usage usage information + qpdf--help=topic help on a topic + qpdf--help=--option help on an option + qpdf--help general help and a topic list + diff --git a/qpdf/qtest/qpdf/bad-json-json-error.json b/qpdf/qtest/qpdf/bad-json-json-error.json new file mode 100644 index 00000000..439434a8 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-json-error.json @@ -0,0 +1,10 @@ +{ + "output": { + "options": { + "encrypt": { + "userPassword": "", + "ownerPassword": "someOwnerThing", + } + } + } +} diff --git a/qpdf/qtest/qpdf/bad-json-pages-no-file.json b/qpdf/qtest/qpdf/bad-json-pages-no-file.json new file mode 100644 index 00000000..5d855a32 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-pages-no-file.json @@ -0,0 +1,9 @@ +{ + "options": { + "pages": [ + { + "range": "1-z" + } + ] + } +} diff --git a/qpdf/qtest/qpdf/bad-json-schema-error.json b/qpdf/qtest/qpdf/bad-json-schema-error.json new file mode 100644 index 00000000..d4d289ac --- /dev/null +++ b/qpdf/qtest/qpdf/bad-json-schema-error.json @@ -0,0 +1,12 @@ +{ + "output": { + "potato": { + "encrypt": { + "userPassword": "", + "ownerPassword": "someOwnerThing", + "256bit": { + } + } + } + } +} diff --git a/qpdf/qtest/qpdf/bad-pages-no-file-json.out b/qpdf/qtest/qpdf/bad-pages-no-file-json.out new file mode 100644 index 00000000..35b0f9c0 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-pages-no-file-json.out @@ -0,0 +1,10 @@ + +qpdf: error with job-json file bad-json-pages-no-file.json: file is required in page specification +Run qpdf--job-json-help for information on the file format. + +For help: + qpdf--help=usage usage information + qpdf--help=topic help on a topic + qpdf--help=--option help on an option + qpdf--help general help and a topic list + diff --git a/qpdf/qtest/qpdf/bad-schema-error-json.out b/qpdf/qtest/qpdf/bad-schema-error-json.out new file mode 100644 index 00000000..700a4099 --- /dev/null +++ b/qpdf/qtest/qpdf/bad-schema-error-json.out @@ -0,0 +1,11 @@ + +qpdf: error with job-json file bad-json-schema-error.json: qpdf: job json has errors: + json key ".output": key "potato" is not present in schema but appears in object +Run qpdf--job-json-help for information on the file format. + +For help: + qpdf--help=usage usage information + qpdf--help=topic help on a topic + qpdf--help=--option help on an option + qpdf--help general help and a topic list + diff --git a/qpdf/qtest/qpdf/job-api.out b/qpdf/qtest/qpdf/job-api.out new file mode 100644 index 00000000..47b00ecf --- /dev/null +++ b/qpdf/qtest/qpdf/job-api.out @@ -0,0 +1,8 @@ +normal +error caught by check +finished config +usage: an input file name is required +error caught by run +finished config +usage: an input file name is required +test 84 done diff --git a/qpdf/qtest/qpdf/job-json-add-attachments.json b/qpdf/qtest/qpdf/job-json-add-attachments.json new file mode 100644 index 00000000..9eb03ca4 --- /dev/null +++ b/qpdf/qtest/qpdf/job-json-add-attachments.json @@ -0,0 +1,27 @@ +{ + "input": { + "file": "minimal.pdf" + }, + "output": { + "file": "a.pdf", + "options": { + "staticId": true + } + }, + "options": { + "addAttachment": [ + { + "file": "auto-txt", + "moddate": "D:20220131134246-05'00'", + "creationdate": "D:20220131134246-05'00'" + }, + { + "file": "auto-txt", + "moddate": "D:20220131134246-05'00'", + "creationdate": "D:20220131134246-05'00'", + "filename": "auto2", + "key": "auto2-key" + } + ] + } +} diff --git a/qpdf/qtest/qpdf/job-json-add-attachments.pdf b/qpdf/qtest/qpdf/job-json-add-attachments.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f4db626bea3bdefb6dfd937eaab7e6995fa1c0c2 GIT binary patch literal 1715 zcmd^A&2G~`5H3`eiX{%b!5|UQ3WB}6{)tgk(I&MTl|o5caj1H5>`iK#*pZ&O@#UYIEOg1GvCa7^X;UtTlI?M5z`8vet-C*5ilTW zzS7EN(4YBTo`HPZ>^6BA^3aPqXrbs+hqX1(cl|csNkR_#e#X~@@Pnf+k3}{-$$%+O zeedi9T`IotJ4qV@H6DjDi3GZu>;P8$o=A$KFIK@+(aJ!J$NX#+EM+;If{+<c?Rrn`1o=t#dTRCtgiG?EE9Rlz0F!DE&K6Y>5$0igUm%^bONQ#d6MCv?C zdTB5kuZJkZ{s|BnH=1sm1PzXiN>L0=!%0derwWps$Z;j*zKD{z>I)7l)yLGJ)F6xyW>V8G8rFToxQ`5> z+OBhHL~l5_SYOWPw0c2*%Hy^;0^;CcqmJMyes?fyl?PJE$a5yJn6B1;zy09zxBab) zFSVtGJEx01RPE?!q+dD1|FUtZw!HBXpJwTLJ~QpIzWe<(+cW5k<=W!MukYRtp4`2+ zH2ASR&}$FRf9@@x|4MIP-dwo2aceL~w~}U_cEiuO(yhM5JEvSkfscDC#u-L&8}ye^ zydG!K#2}X$R*2i7(Q68|kffOL_fXRcYjVky=4Gw}ygF46y?9^1VZOQgDQ{^85ULsD z2W-n?7PMe&Be(bTb0^&V==XTnc~BAYN~YK6k)b5HvVhicVI literal 0 HcmV?d00001 diff --git a/qpdf/qtest/qpdf/job-json-choice-match.json b/qpdf/qtest/qpdf/job-json-choice-match.json new file mode 100644 index 00000000..555e0f5b --- /dev/null +++ b/qpdf/qtest/qpdf/job-json-choice-match.json @@ -0,0 +1,12 @@ +{ + "input": { + "file": "minimal.pdf" + }, + "output": { + "file": "a.pdf", + "options": { + "deterministicId": true, + "objectStreams": "generate" + } + } +} diff --git a/qpdf/qtest/qpdf/job-json-choice-match.pdf b/qpdf/qtest/qpdf/job-json-choice-match.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b0a7e2e9d16fee0f0272ddd7f1f8a2764d56186f GIT binary patch literal 743 zcmY!laBZ^4|D>$ol3WFSpVYkck_-hS zBVz@9x6GW9)FL3AlUS1KlA4^K0#xXyU<#5cDlSnlGE=a#<0>vGN=?k=s+i;2AJ~1! zK%nLRU(wI}mt1oFCmdR--c->c_d~(%$*rX&N%$K$ zer(hXnWo$xRAe&W`Awc{#DqSDKbUXIx1XN z^8_6{_`aDgJae7GlLR-}tH!ghjI~XGM=ycdRvu%wQlD{+eR_gEjD!(+O z@J*fbqT@W4E~;Ygdl~vC$1Y9HOM!Y6$N~kOIZ_Zp1I@$&dzc{yQZd)VpnwbI#vukq zfgGO9o6hz&oN!Q7VLfq;f4dBwHa77ZH@229Gvl zBkV5Fhs0h$Vo`3f0w~g*^K(jb^NJNr6!Zg%Qd2UMOY(~p42^*Csh}UO5UpUSU%@me>W}wVh9TT literal 0 HcmV?d00001 diff --git a/qpdf/qtest/qpdf/job-json-copy-attachments.json b/qpdf/qtest/qpdf/job-json-copy-attachments.json new file mode 100644 index 00000000..7aa531b6 --- /dev/null +++ b/qpdf/qtest/qpdf/job-json-copy-attachments.json @@ -0,0 +1,26 @@ +{ + "input": { + "file": "minimal.pdf" + }, + "output": { + "file": "a.pdf", + "options": { + "staticId": true + } + }, + "options": { + "copyAttachmentsFrom": [ + { + "file": "job-json-add-attachments.pdf" + }, + { + "file": "20-pages.pdf", + "password": "user" + }, + { + "file": "job-json-add-attachments.pdf", + "prefix": "p-" + } + ] + } +} diff --git a/qpdf/qtest/qpdf/job-json-copy-attachments.pdf b/qpdf/qtest/qpdf/job-json-copy-attachments.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ab49f624cc83ec8b67a4c2a8b51496ae798d1b15 GIT binary patch literal 2527 zcmd^B&2G~`5H3`eiX{%b!6H$$6$E?Nzd=z&o78Gl3MFa9A?m@gH>qi2SN5i)oOl7= zfD@0v3vf*-2u^S=FTo8lyLMtHZdLBhX)`GmOlUa_*cS6L1Fu~ zRH-2OxzndH;-}4in|dDgY`+H*0y+(}wuaEKY7>qzX-W z@AMc{st$8{VHX}sH1N0)4m547g;tya3rlRsR*@!N3jrw|(bH9=Cz9h*rex$rshTNd z2RTdJk+G#}I0zWRNZ$6n7`2d#B}AXd>ev{D*>x3=;@qMn+Va(6cfNX6cMfwTf>wvuHy%ftfRJ z4FhU6BeRr(4Xo&}Ri^c@suX4VC3@B+dSwC&a2k&&kfn)?MGky0MPlhR!jOM-h}|p3 zG&Yc2uc1~&#TwSj#DD}_WwWdj$b~@+O;s(Gm}PzKdJXZZ6Ei1bqIg6x3~6a;^Mx(_ E19QZ)VE_OC literal 0 HcmV?d00001 diff --git a/qpdf/qtest/qpdf/job-json-empty-input.json b/qpdf/qtest/qpdf/job-json-empty-input.json new file mode 100644 index 00000000..c124169c --- /dev/null +++ b/qpdf/qtest/qpdf/job-json-empty-input.json @@ -0,0 +1,23 @@ +{ + "input": { + "empty": true + }, + "output": { + "file": "a.pdf", + "options": { + "staticId": true + } + }, + "options": { + "pages": [ + { + "file": "minimal.pdf" + }, + { + "file": "20-pages.pdf", + "password": "user", + "range": "1-5" + } + ] + } +} diff --git a/qpdf/qtest/qpdf/job-json-empty-input.pdf b/qpdf/qtest/qpdf/job-json-empty-input.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b93a91135074c81b4731040ee9b50a3ef534c4c6 GIT binary patch literal 2546 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 spa_{tGzTYoVCRD;3==@8C_=f4rXgQI=Ly7> +endobj +2 0 obj +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +3 0 obj +<< /Contents 4 0 R /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 5 0 R >> /ProcSet 6 0 R >> /Type /Page >> +endobj +4 0 obj +<< /Length 48 /Filter /FlateDecode >> +stream +´æ@!Ò©¯ e›îºŠ\ †Në‘ §ŽK3Ù3­GAG5â‚|'j4oeendstream +endobj +5 0 obj +<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> +endobj +6 0 obj +[ /PDF /Text ] +endobj +7 0 obj +<< /Filter /Standard /Length 40 /O <853fee3f6550fc3bc212797eaed99cc9be53347583a738e25fdfb1242bf93366> /P -4 /R 2 /U <5c78313a3f3f17efd751ded6e1f69b40e384ea413e49df3af00c031a9f4185c0> /V 1 >> +endobj +xref +0 8 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000123 00000 n +0000000266 00000 n +0000000384 00000 n +0000000491 00000 n +0000000521 00000 n +trailer << /Root 1 0 R /Size 8 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] /Encrypt 7 0 R >> +startxref +727 +%%EOF diff --git a/qpdf/qtest/qpdf/job-json-input-file-password.json b/qpdf/qtest/qpdf/job-json-input-file-password.json new file mode 100644 index 00000000..8f22aad0 --- /dev/null +++ b/qpdf/qtest/qpdf/job-json-input-file-password.json @@ -0,0 +1,14 @@ +{ + "input": { + "file": "20-pages.pdf", + "password": "user" + }, + "output": { + "file": "a.pdf", + "options": { + "staticId": true, + "staticAesIv": true, + "compressStreams": "n" + } + } +} diff --git a/qpdf/qtest/qpdf/job-json-input-file-password.pdf b/qpdf/qtest/qpdf/job-json-input-file-password.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dc56bf36ec58960c94e4aee56a87d71d6d0fa5d5 GIT binary patch literal 7343 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 literal 0 HcmV?d00001 diff --git a/qpdf/qtest/qpdf/job-json-misc-options.json b/qpdf/qtest/qpdf/job-json-misc-options.json new file mode 100644 index 00000000..3056f2fe --- /dev/null +++ b/qpdf/qtest/qpdf/job-json-misc-options.json @@ -0,0 +1,13 @@ +{ + "input": { + "file": "minimal.pdf" + }, + "output": { + "file": "a.pdf", + "options": { + "staticId": true, + "linearize": true, + "compressStreams": "n" + } + } +} diff --git a/qpdf/qtest/qpdf/job-json-misc-options.pdf b/qpdf/qtest/qpdf/job-json-misc-options.pdf new file mode 100644 index 0000000000000000000000000000000000000000..be88f1e14af432d9daf2269ed66d4e67a15ccf0c GIT binary patch literal 1285 zcmc&!J&O}T7(NfN*wW7KZ30^8?96^ch?q;36ZI}63l<@ex$GqFk=r?TCr7mMeuiM> zFOd5K9tbx65PKWJLVRbEy)15FC2lqQ&dmGqd`xT5iyzWQj@A0~htFCU zVvf@Umc9L`2WAC1R56d)%@~gM=Q%$N8nMu6-i?^kI2U=fm@0U-6a{E>hf*rQJs1KR zA;=H`85H6I(W6llG4iwrP5`=950N5$YD#(-6pLu-NWp?qOp+0Z;4HZ^4|D>$ol3WFSpVYkck_-hS zBVz@9x6GW9)FL3AlUS1KlA4^K0#xXyU<#5cDlSnlGE=a#<0>vGN=?k=s+i;2AJ~1! zK%nLRU(wI}mt1oFCmdR--c->c_d~(%$*rX&N%$K$ zer(hXnWo$xRAe&W`Awc{#DqSDKbUXIx1XN z^8_6{_`aDgJae7GlLR-}tH!ghjI~XGM=ycdRvu%wQlD{+eR_gEjD!(+O z@J*fbqT@W4E~;Ygdl~vC$1Y9HOM!Y6$N~kOIZ_Zp1I@$&dzc{yQZd)VpnwbI#vukq zfgGO9o6hz&oN!Q7VLfq;f4dBwHa77ZH@229Gvl zBkV5Fhs0h$Vo`3f0w~g*^K(jb^NJNr6!Zg%Qd2UMOY(~p42^*Csh}UO5UpUSU4R{VPa-vW@2n? zVQge>X=+DUMJ!74Nls#5QgdUg6ZqKK$ax~!Mg5;K+dsxlrz99mzBAwD!U&4ulEk8t TilWpsE)!ETE>%@me>W}wSu6&d literal 0 HcmV?d00001 diff --git a/qpdf/qtest/qpdf/job-json-underlay-overlay-password.json b/qpdf/qtest/qpdf/job-json-underlay-overlay-password.json new file mode 100644 index 00000000..304c1654 --- /dev/null +++ b/qpdf/qtest/qpdf/job-json-underlay-overlay-password.json @@ -0,0 +1,23 @@ +{ + "input": { + "file": "minimal.pdf" + }, + "output": { + "file": "a.pdf", + "options": { + "staticId": true + } + }, + "options": { + "underlay": { + "file": "20-pages.pdf", + "password": "user", + "from": "5" + }, + "overlay": { + "file": "job-json-encrypt-128.pdf", + "password": "o", + "from": "7" + } + } +} diff --git a/qpdf/qtest/qpdf/job-json-underlay-overlay-password.pdf b/qpdf/qtest/qpdf/job-json-underlay-overlay-password.pdf new file mode 100644 index 0000000000000000000000000000000000000000..31c0e1f8852d27de234a3c87890c18e65e1379ee GIT binary patch literal 2098 zcmcIlTWAwO6pbx`xLPRqLa;Cui_f|{yV*^GHP#w~QEO|GYN7UHn@;O$vMamWHcAx{ zDj|ie7MN%56P_TbuYv_+s5ej|?)|qKu&1&P1n=qT)nS0ONGw0r^ zYV`T5;Z}jEdi7)Q7XtwYw6z<*3#Pyj}*W?PMXD z&N%GSx>OTD!0uDp4bTDv>e`xdo{N`rCDS=q)kLaEyqwfaq@zSf7aeh&depASby^&+ z;_yd;JaBnN?T_;S5>|pZY4S}oL6XU%fowXH%YLMGnny_l)~`fOq~mu~HjxiSw07!b zm^zYUO#J5NREf_XuH*Kj;XQK7DujY@)VuojvivkzfN`hR4H>;Yq!0qQo|` zXmP@VO3tzXRp5)Ger8geQuA`Vo6fCi);?oFA;+9Ssgn&vCBW`M(Qafa5gD+%ReTnT z+6mahin>!Zl$_y!9K%ZYV;P6K+Ds~YB7XdTt_EnVoQjEl2viG}l+TYBp|}ZJGvz^L zl-TGfZLY%8)ZE4@Y za(mhAU~(q;VrWg@xuKb`eOZ0qz!v*>`BvM?jZ0Yz@w8MH&bMARb%m60H7P5Oyz&Zp z0XF8^Nq+6Zxn4m`|HK01#NsqmB%d&EYRk`0oVhj0mTj1RcX+-^PJO*QICSS^*Yo;o$qPTfgvOg6ReZl%nR?yh z2~4FXlh>ZbVfTZ;tTMJ?$F{LmAFb5ox6+(w!%7Sp)j=&Ls|(6DOTa>6h50=4u%6zWVq}DBvBMZ&;hbGh#Mh!fSR*O_|yw*kjIG?*aRN;ngW}Xv)V)s zcfx{o5^u$D@z!;2!HVmaEH(%^tIY{Grrh0x!6oIE+&e+?W-Q=q>`Y-k8|@@n*i0`|i2t zcb0qax#v!NR(eJ<(}%al@4d4Arj?;+%3CyQqZpzAVkKw8Vl3%`#FV=+Wmbn(1`;sD#w% zt}+U+9^-TSUA{z3hmfB-f;8_;kDp>`%0Ap(R7#Dfcr+LRJw^1C&{IZF1w9!We?U>P zDFzM@d|)vc+yR4oU~m@q!XgEf4 zV2_ZodCAzknzI}~u@I24M=035l%|~~8{p??8)cvmu)l%ZD+QaEg3YTL>jUirjpV={ zpR@^`khQ>a@(AdHly4la^C_SKx@_@@T#a~Q; z)v`UqT>^3=;IjneQ_@{dZxPy&m-<1PWtz2YZBlj1u&|3^b3rDimZs)pw3BOXhhV?o zfDYMQI&4t*vumqf{x;w7>bX@PL>{(;4J)@SCwXWmKBJM^YZ-&B3rLXM8g!|3^zm6- zF3snK56z*ama(lWR(7(q`*Hoznxk(Y>{>DZU`?*2)rg9fy)7Sg=o1!Yu_ckbwUbpX z8<2viSH3T;)xD~NMEql|h2xupoLY z366HYFa~FY!|!v$EI6FG>Dnh)OVt$sP4IDsZh(`687u4nHLFh=y&>WGs>Jf)si~hG z%i4c9{hoW<9Tsb+F=~7q#oV8_e@N<>bqT`Y%yqKD+)=8~$} z8+Um9bZo!j$ddCvW&dAek!=G$X zHMZkmu3f&f$Di!ox+dw}_A7_qKelq<`q|rGRQ9h+8@jFHlO5s9$~L9U z`LOE9H`a*L`=*cc_UikWf4186Xw+jQDsb1L8k8BcJUZ^tbr@Q=M<+`vN3-4D8E|{b z)`x^oJKLypzWF-@UK^Z^ZTHrs_Umx_C!Ay8Zb_qQPRo zH*?;}WJlaP7PzqAJ3nH@&Zvy#r}E$1IOW6kk5_%+`>M-*!$uzByKLFIq~LDk_Rn1p z%do^mkQ&l%u1qm-?JQHOPhFJC%$`}$6$ zudF_q)Z@F;ay7Sd_|Eqt3TDL&Bz0tV)J6xssy0Gp)Y@%}*>O52VAQOQCIS0p;xsy{ zR$=@c!$3@Y!?#cfowpt7mQ#A&eoK(QN^nbEL1thoejkYluf9Ajd; zbdZGc5}F8LmE%!s=A&XP;rZ8=LYN}6PC~2u)exz&Gr*XJ+|c(F3zN)rmpT$P!ltVRFK(08`XQL zs`zE>JCq^3G+^K9HkO3%mkHshZbb$4S8v~uovw(pqsOP7T(ETjRi(c-^P=|7zDVVmjkOCGlM*P<1lM*RO4^|h%qg2#u!W4CXk?+ z7S`$pO`AcewdclxruFtZ4ejTE7C35&O|%t|pc(AJLttsBxJq>GQdq6 zA3|qsxI|5rGEhV}#8vXJ%kOqN>MWrf>6ivCoo0aIxm%@dbrsX$+Be87`1YfER~1%z z1h#b{AB^hH#)B#Ixh7jdCXSY^^sPTi6a;X8aWZv_2Cu5ZKgtuJ!32|z#=z579gTxk zS2~&ikCAjV32x|hGzC`52h+ecUV;b1!#Z4DI}uhx=x8!b!3NX7)nI}z%No#l1Da?+ zlSvw9z=Jd3!5Q%240vz`Ja_{hJPY?I!SeDvT!QOp0;x-0G@wcF%7X4)P+dgO6p|*e z@H$ZNy8lXa3$nr!xQ6TLAh)c*JO7M=Ou0I3pMFsAj zg4;DtNgdV-FokUV4#-Zc+yCv)(IgO0`<&_s9%UDr;6 zmnVX03e6Gi6b9a0*R^8}XdJw+p=-yJaYK>dS%R*e3~vqVXbL=53!;J97;dF?GzRVz zbu?blj~N7S!hb=)Ca?kllfa6h6#^@UVF}x17>f^;q&gZe5}2|AybP^tCrX4qSV`>r;)bCDKvor z4}O_K|1M9Hw#Jiw1k43q1`6iO^YFTfjs^lRK@&+k;3arDRrf9k90W}ve2@`nSg#TM zu0WF*2#i)Xzt7<=0XIwFuSX2^O!lHuTksnn*z{;SgP;@#tN1@9F<`IDwola*;e~#gS@v;C}P{jKu= literal 0 HcmV?d00001 diff --git a/qpdf/qtest/qpdf/job-partial-json.out b/qpdf/qtest/qpdf/job-partial-json.out new file mode 100644 index 00000000..bc86596f --- /dev/null +++ b/qpdf/qtest/qpdf/job-partial-json.out @@ -0,0 +1,3 @@ +calling initializeFromJson +usage: an input file name is required +test 83 done diff --git a/qpdf/qtest/qpdf/job-partial.json b/qpdf/qtest/qpdf/job-partial.json new file mode 100644 index 00000000..ff2587c1 --- /dev/null +++ b/qpdf/qtest/qpdf/job-partial.json @@ -0,0 +1,12 @@ +{ + "output": { + "options": { + "encrypt": { + "userPassword": "", + "ownerPassword": "", + "256bit": { + } + } + } + } +} diff --git a/qpdf/qtest/qpdf/job-show-encryption.json b/qpdf/qtest/qpdf/job-show-encryption.json new file mode 100644 index 00000000..0a785ec6 --- /dev/null +++ b/qpdf/qtest/qpdf/job-show-encryption.json @@ -0,0 +1,5 @@ +{ + "inspect": { + "showEncryption": true + } +} diff --git a/qpdf/qtest/qpdf/test84.pdf b/qpdf/qtest/qpdf/test84.pdf new file mode 100644 index 00000000..0d065c16 --- /dev/null +++ b/qpdf/qtest/qpdf/test84.pdf @@ -0,0 +1,101 @@ +%PDF-1.3 +%¿÷¢þ +%QDF-1.0 + +%% Original object ID: 1 0 +1 0 obj +<< + /Pages 2 0 R + /Type /Catalog +>> +endobj + +%% Original object ID: 2 0 +2 0 obj +<< + /Count 1 + /Kids [ + 3 0 R + ] + /Type /Pages +>> +endobj + +%% Page 1 +%% Original object ID: 3 0 +3 0 obj +<< + /Contents 4 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 6 0 R + >> + /ProcSet 7 0 R + >> + /Type /Page +>> +endobj + +%% Contents for page 1 +%% Original object ID: 4 0 +4 0 obj +<< + /Length 5 0 R +>> +stream +BT + /F1 24 Tf + 72 720 Td + (Potato) Tj +ET +endstream +endobj + +5 0 obj +44 +endobj + +%% Original object ID: 6 0 +6 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +%% Original object ID: 5 0 +7 0 obj +[ + /PDF + /Text +] +endobj + +xref +0 8 +0000000000 65535 f +0000000052 00000 n +0000000133 00000 n +0000000242 00000 n +0000000484 00000 n +0000000583 00000 n +0000000629 00000 n +0000000774 00000 n +trailer << + /Root 1 0 R + /Size 8 + /ID [] +>> +startxref +809 +%%EOF diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 65b2038c..4158b030 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -3140,6 +3142,81 @@ static void test_82(QPDF& pdf, char const* arg2) assert(! str.isOrHasName("/Marvin")); } +static void test_83(QPDF& pdf, char const* arg2) +{ + // Test QPDFJob json with partial = false. For testing with + // partial = true, we just use qpdf --job-json-file. + + QPDFJob j; + PointerHolder file_buf; + size_t size; + QUtil::read_file_into_memory(arg2, file_buf, size); + try + { + std::cout << "calling initializeFromJson" << std::endl; + j.initializeFromJson(std::string(file_buf.getPointer(), size)); + std::cout << "called initializeFromJson" << std::endl; + } + catch (QPDFUsage& e) + { + std::cerr << "usage: " << e.what() << std::endl; + } + catch (std::exception& e) + { + std::cerr << "exception: " << e.what() << std::endl; + } +} + +static void test_84(QPDF& pdf, char const* arg2) +{ + // Test QPDFJob API + + std::cout << "normal" << std::endl; + { + QPDFJob j; + j.config() + ->inputFile("minimal.pdf") + ->outputFile("a.pdf") + ->qdf() + ->deterministicId() + ->objectStreams("preserve") + ->checkConfiguration(); + j.run(); + } + + std::cout << "error caught by check" << std::endl; + try + { + QPDFJob j; + j.config() + ->outputFile("a.pdf") + ->qdf(); + std::cout << "finished config" << std::endl; + j.checkConfiguration(); + assert(false); + } + catch (QPDFUsage& e) + { + std::cout << "usage: " << e.what() << std::endl; + } + + std::cout << "error caught by run" << std::endl; + try + { + QPDFJob j; + j.config() + ->outputFile("a.pdf") + ->qdf(); + std::cout << "finished config" << std::endl; + j.run(); + assert(false); + } + catch (QPDFUsage& e) + { + std::cout << "usage: " << e.what() << std::endl; + } +} + void runtest(int n, char const* filename1, char const* arg2) { // Most tests here are crafted to work on specific files. Look at @@ -3206,7 +3283,7 @@ void runtest(int n, char const* filename1, char const* arg2) pdf.processMemoryFile((std::string(filename1) + ".pdf").c_str(), p, size); } - else if ((n == 61) || (n == 81)) + else if ((n == 61) || (n == 81) || (n == 83) || (n == 84)) { // Ignore filename argument entirely } @@ -3253,7 +3330,8 @@ void runtest(int n, char const* filename1, char const* arg2) {68, test_68}, {69, test_69}, {70, test_70}, {71, test_71}, {72, test_72}, {73, test_73}, {74, test_74}, {75, test_75}, {76, test_76}, {77, test_77}, {78, test_78}, {79, test_79}, - {80, test_80}, {81, test_81}, {82, test_82}, + {80, test_80}, {81, test_81}, {82, test_82}, {83, test_83}, + {84, test_84}, }; auto fn = test_functions.find(n);