qpdf/qpdf/qtest/qpdf-json.test

363 lines
14 KiB
Perl

#!/usr/bin/env perl
require 5.008;
use warnings;
use strict;
unshift(@INC, '.');
require qpdf_test_helpers;
chdir("qpdf") or die "chdir testdir failed: $!\n";
require TestDriver;
cleanup();
my $td = new TestDriver('qpdf-json');
my $n_tests = 0;
my @badfiles = (
'no-qpdf-object',
'qpdf-not-array',
'qpdf-array-too-long',
'no-pdf-version',
'top-level-scalar',
'bad-pdf-version1',
'bad-pdf-version2',
'top-level-array',
'objects-not-dict',
'bad-object-key',
'object-not-dict',
'stream-not-dict',
'stream-dict-not-dict',
'trailer-not-dict',
'trailer-stream',
'missing-trailer',
'missing-objects',
'obj-key-errors',
'bad-data',
'bad-datafile',
);
$n_tests += scalar(@badfiles);
foreach my $f (@badfiles)
{
$td->runtest("bad: $f",
{$td->COMMAND =>
"qpdf --json-input qjson-$f.json a.pdf"},
{$td->FILE => "qjson-$f.out", $td->EXIT_STATUS => 2},
$td->NORMALIZE_NEWLINES);
}
my @goodfiles = (
'good1.pdf',
'good9.pdf',
'good13.pdf',
'good15.pdf',
'inline-images.pdf',
['20-pages.pdf', '--password=user'],
'outlines-with-actions.pdf',
'form-fields-and-annotations.pdf',
'need-appearances.pdf',
'fxo-blue.pdf',
'weird-tokens.pdf',
);
$n_tests += 6 * scalar(@goodfiles);
foreach my $i (@goodfiles)
{
my $f = $i;
my $xargs = "";
if (ref($i) eq 'ARRAY') {
($f, $xargs) = @$i;
}
# explicit "latest" as --json-output version
$td->runtest("good: $f -> JSON",
{$td->COMMAND => "qpdf $xargs" .
" --json-output=latest $f a.json"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
# default --json-output version
$td->runtest("good: $f JSON -> JSON",
{$td->COMMAND =>
"qpdf --json-input --json-output a.json b.json"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("good: $f JSON -> QDF",
{$td->COMMAND =>
"qpdf --qdf --json-input --stream-data=preserve" .
" --static-id a.json a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("good: $f compare JSON",
{$td->FILE => "a.json"},
{$td->FILE => "b.json"});
my $exp = "json-changed-$f";
if (! -f $exp)
{
$td->runtest("good: $f -> aqdf",
{$td->COMMAND =>
"qpdf $xargs --object-streams=disable --qdf" .
" --stream-data=preserve --static-id $f b.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$exp = "b.pdf";
}
else
{
# Sometimes passing through json may make semantically
# equivalent changes such as
#
# * adding leading 0 to a floating point (.1 -> 0.1)
# * changing the Unicode representation of a string
# * changing the representation of a name (/n#65st -> /nest)
$td->runtest("good: json changes $f",
{$td->STRING => ""},
{$td->STRING => ""});
}
$td->runtest("good: $f compare qdf",
{$td->FILE => "a.pdf"}, # from json
{$td->FILE => $exp}); # from original PDF
}
$n_tests += 6;
$td->runtest("manual JSON to PDF",
{$td->COMMAND => "qpdf --json-input --static-id --qdf" .
" manual-qpdf-json.json a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check manual JSON to PDF",
{$td->FILE => "a.pdf"},
{$td->FILE => "manual-qpdf-json.pdf"});
$td->runtest("check manual JSON to PDF to JSON",
{$td->COMMAND => "qpdf --json-output=2 a.pdf -"},
{$td->FILE => "manual-qpdf-json-pdf.json", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("manual JSON to JSON",
{$td->COMMAND => "qpdf --json-input --json-output=2" .
" manual-qpdf-json.json a.json"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check manual JSON to JSON",
{$td->FILE => "a.json"},
{$td->FILE => "manual-qpdf-json-out.json"},
$td->NORMALIZE_NEWLINES);
$td->runtest("check manual JSON to JSON to JSON",
{$td->COMMAND => "qpdf --json-output=2 --json-input a.json -"},
{$td->FILE => "a.json", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$n_tests += 6;
$td->runtest("json-output with file",
{$td->COMMAND => "qpdf --json-output=2" .
" --json-stream-prefix=auto-1 --json-stream-data=file" .
" minimal.pdf a.json"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check file mode",
{$td->FILE => "a.json"},
{$td->FILE => "minimal-json-file.out"},
$td->NORMALIZE_NEWLINES);
$td->runtest("JSON to JSON with file",
{$td->COMMAND => "qpdf --json-input --json-output=2" .
" --json-stream-prefix=auto-2 --json-stream-data=file" .
" a.json -"},
{$td->FILE => "minimal-json-file-2.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("JSON with file to qdf",
{$td->COMMAND => "qpdf --json-input --qdf --static-id" .
" a.json a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("PDF to qdf",
{$td->COMMAND => "qpdf --qdf --static-id minimal.pdf b.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check PDF",
{$td->FILE => "a.pdf"},
{$td->FILE => "b.pdf"});
# Replace mode tests
$n_tests += 1;
$td->runtest("create PDF for replace",
{$td->COMMAND => "qpdf good13.pdf a.pdf" .
" --update-from-json=qpdf-json-update-errors.json"},
{$td->FILE => "update-from-json-errors.out",
$td->EXIT_STATUS => 2},
$td->NORMALIZE_NEWLINES);
my @update_files = (
"update-stream-dict-only",
"update-stream-data",
"replace-with-stream",
"various-updates",
);
$n_tests += 2 * scalar(@update_files);
foreach my $f (@update_files) {
$td->runtest("update: $f",
{$td->COMMAND =>
"qpdf good13.pdf a.pdf --qdf --static-id" .
" --update-from-json=$f.json"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("$f: check updated",
{$td->FILE => "a.pdf"},
{$td->FILE => "$f-updated.pdf"});
}
# Exercise object description
$n_tests += 2;
$td->runtest("json-input object description",
{$td->COMMAND => "test_driver 89 manual-qpdf-json.json"},
{$td->FILE => "test-89.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("update-from-json object description",
{$td->COMMAND => "test_driver 90 good13.pdf various-updates.json"},
{$td->FILE => "test-90.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
# Exercise pushedinheritedpageresources and calledgetallpages
$n_tests += 12;
$td->runtest("call getAllPages",
{$td->COMMAND =>
"qpdf --json-output duplicate-page-inherited.pdf" .
" --json-key=pages a.json"},
{$td->FILE => "duplicate-page-inherited.out",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check json (1)",
{$td->FILE => "a.json"},
{$td->FILE => "duplicate-page-inherited-1.json"},
$td->NORMALIZE_NEWLINES);
$td->runtest("update (1)",
{$td->COMMAND =>
"qpdf" .
" --update-from-json=duplicate-page-inherited-update.json" .
" --json-output duplicate-page-inherited.pdf" .
" a.json"},
{$td->FILE => "duplicate-page-inherited.out",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check json (2)",
{$td->FILE => "a.json"},
{$td->FILE => "duplicate-page-inherited-1-fixed.json"},
$td->NORMALIZE_NEWLINES);
$td->runtest("create PDF (1)",
{$td->COMMAND =>
"qpdf --qdf --static-id --json-input a.json a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check PDF (1)",
{$td->FILE => "a.pdf"},
{$td->FILE => "duplicate-page-inherited-1-fixed.pdf"});
$td->runtest("call pushInheritedAttributesToPage",
{$td->COMMAND =>
"qpdf --json-output duplicate-page-inherited.pdf" .
" --json-key=pages --pages . -- a.json"},
{$td->FILE => "duplicate-page-inherited.out",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check json (2)",
{$td->FILE => "a.json"},
{$td->FILE => "duplicate-page-inherited-2.json"},
$td->NORMALIZE_NEWLINES);
$td->runtest("update (2)",
{$td->COMMAND =>
"qpdf" .
" --update-from-json=duplicate-page-inherited-update2.json" .
" --json-output duplicate-page-inherited.pdf" .
" a.json"},
{$td->FILE => "duplicate-page-inherited.out",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check json (3)",
{$td->FILE => "a.json"},
{$td->FILE => "duplicate-page-inherited-2-fixed.json"},
$td->NORMALIZE_NEWLINES);
$td->runtest("create PDF (2)",
{$td->COMMAND =>
"qpdf --qdf --static-id --json-input a.json a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check PDF (2)",
{$td->FILE => "a.pdf"},
{$td->FILE => "duplicate-page-inherited-2-fixed.pdf"});
$n_tests += 1;
$td->runtest("simple version of writeJSON",
{$td->COMMAND => "test_driver 91 minimal.pdf"},
{$td->FILE => "minimal-write-json.json", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$n_tests += 13;
$td->runtest("C API create from json file",
{$td->COMMAND => "qpdf-ctest 42 minimal.json '' a.pdf"},
{$td->STRING => "C test 42 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API create from file",
{$td->COMMAND => "qpdf-test-compare a.pdf qpdf-ctest-42-43.pdf"},
{$td->FILE => "qpdf-ctest-42-43.pdf", $td->EXIT_STATUS => 0});
$td->runtest("C API create from json buffer",
{$td->COMMAND => "qpdf-ctest 43 minimal.json '' a.pdf"},
{$td->STRING => "C test 43 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API create from buffer",
{$td->COMMAND => "qpdf-test-compare a.pdf qpdf-ctest-42-43.pdf"},
{$td->FILE => "qpdf-ctest-42-43.pdf", $td->EXIT_STATUS => 0});
$td->runtest("C API update from json file",
{$td->COMMAND =>
"qpdf-ctest 44 minimal.pdf '' a.pdf minimal-update.json"},
{$td->STRING => "C test 44 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API update from file",
{$td->COMMAND => "qpdf-test-compare a.pdf qpdf-ctest-44-45.pdf"},
{$td->FILE => "qpdf-ctest-44-45.pdf", $td->EXIT_STATUS => 0});
$td->runtest("C API update from json buffer",
{$td->COMMAND =>
"qpdf-ctest 45 minimal.pdf '' a.pdf minimal-update.json"},
{$td->STRING => "C test 45 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API update from buffer",
{$td->COMMAND => "qpdf-test-compare a.pdf qpdf-ctest-44-45.pdf"},
{$td->FILE => "qpdf-ctest-44-45.pdf", $td->EXIT_STATUS => 0});
$td->runtest("C API write to JSON 1",
{$td->COMMAND =>
"qpdf-ctest 46 minimal.pdf '' a.json"},
{$td->STRING => "C test 46 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API write to JSON 1",
{$td->FILE => "a.json"},
{$td->FILE => "qpdf-ctest-46.json"},
$td->NORMALIZE_NEWLINES);
$td->runtest("C API write to JSON 2",
{$td->COMMAND =>
"qpdf-ctest 47 minimal.pdf '' a.json auto"},
{$td->STRING => "C test 47 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API write to JSON 2",
{$td->FILE => "a.json"},
{$td->FILE => "qpdf-ctest-47.json"},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API write to JSON stream",
{$td->FILE => "auto-4"},
{$td->FILE => "qpdf-ctest-47-4"});
# Bugs #1072 and #1079 illustrate cases that qpdf-json got wrong. In
# #1072, it was noticed that name tokens containing binary characters
# (using #xx) would generate invalid JSON, even though qpdf's own JSON
# parser would accept it. Also, the JSON spec allows real numbers in
# scientific notation, but the PDF spec does not.
$n_tests += 2;
$td->runtest("handle binary names",
{$td->COMMAND =>
"qpdf --json-output weird-tokens.pdf a.json"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
# Round-trip is tested above.
$td->runtest("check json",
{$td->FILE => "a.json"},
{$td->FILE => "weird-tokens.json"},
$td->NORMALIZE_NEWLINES);
cleanup();
$td->report($n_tests);