mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
Exercise object description in tests
This commit is contained in:
parent
6c2fb5b8f0
commit
9b2eb01e25
3
TODO
3
TODO
@ -58,9 +58,6 @@ Some of this documentation has drifted from the actual implementation.
|
||||
|
||||
Make sure pages tree repair generates warnings.
|
||||
|
||||
* Have a test case if possible that exercises the object description
|
||||
which means we need some kind of semantic error that gets caught
|
||||
after creation.
|
||||
* Document that /Length is ignored in stream dictionary replacements
|
||||
|
||||
Try to never flatten pages tree. Make sure we do something reasonable
|
||||
|
@ -1041,12 +1041,15 @@ class QPDF
|
||||
|
||||
void containerStart();
|
||||
void nestedState(std::string const& key, JSON const& value, state_e);
|
||||
void setObjectDescription(QPDFObjectHandle& oh, JSON const& value);
|
||||
QPDFObjectHandle makeObject(JSON const& value);
|
||||
void error(size_t offset, std::string const& message);
|
||||
QPDFObjectHandle
|
||||
reserveObject(std::string const& obj, std::string const& gen);
|
||||
void replaceObject(
|
||||
QPDFObjectHandle to_replace, QPDFObjectHandle replacement);
|
||||
QPDFObjectHandle to_replace,
|
||||
QPDFObjectHandle replacement,
|
||||
JSON const& value);
|
||||
|
||||
QPDF& pdf;
|
||||
std::shared_ptr<InputSource> is;
|
||||
|
@ -249,11 +249,15 @@ QPDF::JSONReactor::reserveObject(std::string const& obj, std::string const& gen)
|
||||
|
||||
void
|
||||
QPDF::JSONReactor::replaceObject(
|
||||
QPDFObjectHandle to_replace, QPDFObjectHandle replacement)
|
||||
QPDFObjectHandle to_replace,
|
||||
QPDFObjectHandle replacement,
|
||||
JSON const& value)
|
||||
{
|
||||
auto og = to_replace.getObjGen();
|
||||
this->reserved.erase(og);
|
||||
this->pdf.replaceObject(og, replacement);
|
||||
auto oh = pdf.getObjectByObjGen(og);
|
||||
setObjectDescription(oh, value);
|
||||
}
|
||||
|
||||
void
|
||||
@ -326,9 +330,10 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
nestedState(key, value, st_trailer);
|
||||
this->cur_object = "trailer";
|
||||
} else if (std::regex_match(key, m, OBJ_KEY_RE)) {
|
||||
object_stack.push_back(reserveObject(m[1].str(), m[2].str()));
|
||||
nestedState(key, value, st_object_top);
|
||||
this->cur_object = key;
|
||||
auto oh = reserveObject(m[1].str(), m[2].str());
|
||||
object_stack.push_back(oh);
|
||||
nestedState(key, value, st_object_top);
|
||||
} else {
|
||||
QTC::TC("qpdf", "QPDF_json bad object key");
|
||||
error(
|
||||
@ -348,7 +353,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
this->saw_value = true;
|
||||
next_state = st_object;
|
||||
replacement = makeObject(value);
|
||||
replaceObject(tos, replacement);
|
||||
replaceObject(tos, replacement, value);
|
||||
} else if (key == "stream") {
|
||||
this->saw_stream = true;
|
||||
nestedState(key, value, st_stream);
|
||||
@ -359,7 +364,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
this->this_stream_needs_data = true;
|
||||
replacement =
|
||||
pdf.reserveStream(tos.getObjectID(), tos.getGeneration());
|
||||
replaceObject(tos, replacement);
|
||||
replaceObject(tos, replacement, value);
|
||||
}
|
||||
} else {
|
||||
// Ignore unknown keys for forward compatibility
|
||||
@ -376,6 +381,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
// The trailer must be a dictionary, so we can use nestedState.
|
||||
nestedState("trailer.value", value, st_object);
|
||||
this->pdf.m->trailer = makeObject(value);
|
||||
setObjectDescription(this->pdf.m->trailer, value);
|
||||
} else if (key == "stream") {
|
||||
// Don't need to set saw_stream here since there's already
|
||||
// an error.
|
||||
@ -471,6 +477,17 @@ QPDF::JSONReactor::arrayItem(JSON const& value)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::JSONReactor::setObjectDescription(QPDFObjectHandle& oh, JSON const& value)
|
||||
{
|
||||
std::string description = this->is->getName();
|
||||
if (!this->cur_object.empty()) {
|
||||
description += ", " + this->cur_object;
|
||||
}
|
||||
description += " at offset " + QUtil::uint_to_string(value.getStart());
|
||||
oh.setObjectDescription(&this->pdf, description);
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
QPDF::JSONReactor::makeObject(JSON const& value)
|
||||
{
|
||||
@ -515,12 +532,9 @@ QPDF::JSONReactor::makeObject(JSON const& value)
|
||||
"JSONReactor::makeObject didn't initialize the object");
|
||||
}
|
||||
|
||||
std::string description = this->is->getName();
|
||||
if (!this->cur_object.empty()) {
|
||||
description += " " + this->cur_object + ",";
|
||||
if (!result.hasObjectDescription()) {
|
||||
setObjectDescription(result, value);
|
||||
}
|
||||
description += " offset " + QUtil::uint_to_string(value.getStart());
|
||||
result.setObjectDescription(&this->pdf, description);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -202,6 +202,16 @@ foreach my $f (@update_files) {
|
||||
{$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);
|
||||
|
||||
cleanup();
|
||||
$td->report($n_tests);
|
||||
|
@ -1,2 +1,2 @@
|
||||
WARNING: qjson-object-not-dict.json (offset 100): "obj:1 0 R" must be a dictionary
|
||||
WARNING: qjson-object-not-dict.json (obj:1 0 R, offset 100): "obj:1 0 R" must be a dictionary
|
||||
qpdf: qjson-object-not-dict.json: errors found in JSON
|
||||
|
5
qpdf/qtest/qpdf/test-89.out
Normal file
5
qpdf/qtest/qpdf/test-89.out
Normal file
@ -0,0 +1,5 @@
|
||||
WARNING: manual-qpdf-json.json, trailer at offset 1761: operation for array attempted on object of type dictionary: ignoring attempt to append item
|
||||
WARNING: manual-qpdf-json.json, obj:1 0 R at offset 1079: operation for array attempted on object of type dictionary: ignoring attempt to append item
|
||||
WARNING: manual-qpdf-json.json, obj:5 0 R at offset 1404: operation for dictionary attempted on object of type array: ignoring key replacement request
|
||||
WARNING: manual-qpdf-json.json, obj:5 0 R at offset 1416: operation for dictionary attempted on object of type name: ignoring key replacement request
|
||||
test 89 done
|
5
qpdf/qtest/qpdf/test-90.out
Normal file
5
qpdf/qtest/qpdf/test-90.out
Normal file
@ -0,0 +1,5 @@
|
||||
WARNING: various-updates.json, trailer at offset 580: operation for array attempted on object of type dictionary: ignoring attempt to append item
|
||||
WARNING: various-updates.json, obj:7 0 R at offset 171: operation for array attempted on object of type dictionary: ignoring attempt to append item
|
||||
WARNING: various-updates.json, obj:7 0 R at offset 283: operation for integer attempted on object of type array: returning 0
|
||||
WARNING: good13.pdf, object 1 0 at offset 19: operation for array attempted on object of type dictionary: ignoring attempt to append item
|
||||
test 90 done
|
@ -3172,6 +3172,31 @@ test_88(QPDF& pdf, char const* arg2)
|
||||
assert(arr2.eraseItemAndGet(50).isNull());
|
||||
}
|
||||
|
||||
static void
|
||||
test_89(QPDF& pdf, char const* arg2)
|
||||
{
|
||||
// Generate object warning with json-input. Crafted to work with
|
||||
// manual-qpdf-json.json.
|
||||
auto null = QPDFObjectHandle::newNull();
|
||||
pdf.getTrailer().appendItem(null);
|
||||
pdf.getRoot().appendItem(null);
|
||||
pdf.getObjectByID(5, 0).replaceKey("/X", null);
|
||||
pdf.getObjectByID(5, 0).getArrayItem(0).replaceKey("/X", null);
|
||||
}
|
||||
|
||||
static void
|
||||
test_90(QPDF& pdf, char const* arg2)
|
||||
{
|
||||
// Generate object warning with update-from-json. Crafted to work
|
||||
// with good13.pdf and various-updates.json. JSON file is arg2.
|
||||
pdf.updateFromJSON(arg2);
|
||||
pdf.getTrailer().appendItem(QPDFObjectHandle::newNull());
|
||||
pdf.getTrailer().getKey("/QTest").appendItem(QPDFObjectHandle::newNull());
|
||||
pdf.getTrailer().getKey("/QTest").getKey("/strings").getIntValue();
|
||||
// not from json
|
||||
pdf.getRoot().appendItem(QPDFObjectHandle::newNull());
|
||||
}
|
||||
|
||||
void
|
||||
runtest(int n, char const* filename1, char const* arg2)
|
||||
{
|
||||
@ -3235,6 +3260,8 @@ runtest(int n, char const* filename1, char const* arg2)
|
||||
(std::string(filename1) + ".pdf").c_str(), p, size);
|
||||
} else if (ignore_filename.count(n)) {
|
||||
// Ignore filename argument entirely
|
||||
} else if (n == 89) {
|
||||
pdf.createFromJSON(filename1);
|
||||
} else if (n % 2 == 0) {
|
||||
if (n % 4 == 0) {
|
||||
QTC::TC("qpdf", "exercise processFile(name)");
|
||||
@ -3274,7 +3301,7 @@ runtest(int n, char const* filename1, char const* arg2)
|
||||
{76, test_76}, {77, test_77}, {78, test_78}, {79, test_79},
|
||||
{80, test_80}, {81, test_81}, {82, test_82}, {83, test_83},
|
||||
{84, test_84}, {85, test_85}, {86, test_86}, {87, test_87},
|
||||
{88, test_88}};
|
||||
{88, test_88}, {89, test_89}, {90, test_90}};
|
||||
|
||||
auto fn = test_functions.find(n);
|
||||
if (fn == test_functions.end()) {
|
||||
|
Loading…
Reference in New Issue
Block a user