/************************************************************************* ** PDFParserTest.cpp ** ** ** ** This file is part of dvisvgm -- a fast DVI to SVG converter ** ** Copyright (C) 2005-2024 Martin Gieseking ** ** ** ** This program is free software; you can redistribute it and/or ** ** modify it under the terms of the GNU General Public License as ** ** published by the Free Software Foundation; either version 3 of ** ** the License, or (at your option) any later version. ** ** ** ** This program is distributed in the hope that it will be useful, but ** ** WITHOUT ANY WARRANTY; without even the implied warranty of ** ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** ** GNU General Public License for more details. ** ** ** ** You should have received a copy of the GNU General Public License ** ** along with this program; if not, see . ** *************************************************************************/ #include #include "PDFParser.hpp" using namespace std; TEST(PDFParserTest, empty) { PDFParser parser; vector objects = parser.parse(""); EXPECT_TRUE(objects.empty()); objects = parser.parse(" \n \r %comment 1 2 3 "); EXPECT_TRUE(objects.empty()); } TEST(PDFParserTest, numbers) { PDFParser parser; vector objects = parser.parse("5 1 +2 -3 1.1 9. .1 -7.2"); ASSERT_EQ(objects.size(), 8u); size_t count=0; for (int n : {5, 1, 2, -3}) { ASSERT_NE(objects[count].get(), nullptr); EXPECT_EQ(*objects[count++].get(), n); } for (double n : {1.1, 9.0, 0.1, -7.2}) { ASSERT_NE(objects[count].get(), nullptr); EXPECT_DOUBLE_EQ(*objects[count++].get(), n); } } TEST(PDFParserTest, literal_strings) { PDFParser parser; vector objects = parser.parse("()"); ASSERT_EQ(objects.size(), 1u); ASSERT_NE(objects[0].get(), nullptr); EXPECT_TRUE(objects[0].get()->empty()); objects = parser.parse("(literal string) (balanced (bra(ck)ets) inside)(a\\n\\(b\\c)"); ASSERT_EQ(objects.size(), 3u); size_t count=0; for (string str : {"literal string", "balanced (bra(ck)ets) inside", "a\n(bc"}) { ASSERT_NE(objects[count].get(), nullptr); ASSERT_EQ(*objects[count++].get(), str); } objects = parser.parse(R"*( ( octal \1\12\123\1234 ))*"); ASSERT_EQ(objects.size(), 1u); ASSERT_NE(objects[0].get(), nullptr); EXPECT_EQ(objects[0].get()->size(), 13u); EXPECT_EQ(*objects[0].get(), " octal \001\012\123\1234 "); objects = parser.parse("(split \\\nline)"); ASSERT_EQ(objects.size(), 1u); ASSERT_NE(objects[0].get(), nullptr); EXPECT_EQ(*objects[0].get(), "split line"); EXPECT_THROW(parser.parse("(missing parentheses"), PDFException); } TEST(PDFParserTest, hex_strings) { PDFParser parser; vector objects = parser.parse("<>< ><\n\r\f>"); ASSERT_EQ(objects.size(), 3u); for (size_t i=0; i < objects.size(); i++) { ASSERT_NE(objects[i].get(), nullptr); EXPECT_TRUE(objects[i].get()->empty()); } objects = parser.parse("<202>"); ASSERT_EQ(objects.size(), 1u); ASSERT_NE(objects[0].get(), nullptr); EXPECT_EQ(*objects[0].get(), " "); objects = parser.parse("<616263646566 6768\n696A6b6c6D6E6F 7>"); ASSERT_EQ(objects.size(), 1u); ASSERT_NE(objects[0].get(), nullptr); EXPECT_EQ(*objects[0].get(), "abcdefghijklmnop"); EXPECT_THROW(parser.parse(""), PDFException); EXPECT_THROW(parser.parse(" objects = parser.parse("[1 2.0/name(string) [5] <6162>]"); ASSERT_EQ(objects.size(), 1u); const PDFArray *arr = objects[0].get(); ASSERT_NE(arr, nullptr); ASSERT_EQ(arr->size(), 6u); // integer number ASSERT_NE((*arr)[0].get(), nullptr); ASSERT_EQ(*(*arr)[0].get(), 1); // real number ASSERT_NE((*arr)[1].get(), nullptr); ASSERT_DOUBLE_EQ(*(*arr)[1].get(), 2.0); // name ASSERT_NE((*arr)[2].get(), nullptr); ASSERT_EQ(*(*arr)[2].get(), PDFName("name")); // literal string ASSERT_NE((*arr)[3].get(), nullptr); ASSERT_EQ(*(*arr)[3].get(), "string"); // inner array ASSERT_NE((*arr)[4].get(), nullptr); ASSERT_EQ((*arr)[4].get()->size(), 1u); ASSERT_NE((*arr)[4].get()->at(0).get(), nullptr); ASSERT_EQ(*(*arr)[4].get()->at(0).get(), 5); // hex string ASSERT_NE((*arr)[5].get(), nullptr); ASSERT_EQ(*(*arr)[5].get(), "ab"); } TEST(PDFParserTest, dictionary) { PDFParser parser; vector objects = parser.parse("<< >>"); ASSERT_EQ(objects.size(), 1u); const PDFDict *dict = objects[0].get(); ASSERT_NE(dict, nullptr); ASSERT_TRUE(dict->empty()); objects = parser.parse("<>"); ASSERT_EQ(objects.size(), 1u); dict = objects[0].get(); ASSERT_NE(dict, nullptr); ASSERT_EQ(dict->size(), 4u); // integer number ASSERT_NE(dict->find("int"), dict->end()); ASSERT_NE(dict->find("int")->second.get(), nullptr); EXPECT_EQ(*dict->find("int")->second.get(), 4); ASSERT_NE(dict->find("real"), dict->end()); ASSERT_NE(dict->find("real")->second.get(), nullptr); EXPECT_DOUBLE_EQ(*dict->find("real")->second.get(), 5.5); ASSERT_NE(dict->find("str"), dict->end()); ASSERT_NE(dict->find("str")->second.get(), nullptr); EXPECT_EQ(*dict->find("str")->second.get(), "string value"); ASSERT_NE(dict->find("color"), dict->end()); ASSERT_NE(dict->find("color")->second.get(), nullptr); const PDFArray &arr = *dict->find("color")->second.get(); ASSERT_EQ(arr.size(), 3u); EXPECT_EQ(*arr[0].get(), 0); EXPECT_EQ(*arr[1].get(), 1); EXPECT_EQ(*arr[2].get(), 1); EXPECT_EQ(dict->find("nokey"), dict->end()); EXPECT_THROW(parser.parse("<>"), PDFException); // missing value EXPECT_THROW(parser.parse("<"), PDFException); // missing ">" EXPECT_THROW(parser.parse("<>" } TEST(PDFParserTest, indirect_objects) { PDFParser parser; vector objects = parser.parse("1 0 obj\n1 2 3 4 5endobj 2 5 R"); ASSERT_EQ(objects.size(), 2u); ASSERT_NE(objects[0].get(), nullptr); EXPECT_EQ(objects[0].get()->objnum, 1); EXPECT_EQ(objects[0].get()->gennum, 0); ASSERT_NE(objects[1].get(), nullptr); EXPECT_EQ(objects[1].get()->objnum, 2); EXPECT_EQ(objects[1].get()->gennum, 5); EXPECT_THROW(parser.parse("1 obj\n1 2 3 4 5endobj"), PDFException); EXPECT_THROW(parser.parse("1 (string)obj\n1 2 3 4 5endobj"), PDFException); EXPECT_THROW(parser.parse("1 R"), PDFException); EXPECT_THROW(parser.parse("1 (string)R"), PDFException); } TEST(PDFParserTest, stream) { PDFParser parser; vector objects = parser.parse("stream\n1 2 3 4 endstream"); ASSERT_EQ(objects.size(), 1u); ASSERT_NE(objects[0].get(), nullptr); } TEST(PDFParserTest, ops1) { PDFParser parser; vector objects = parser.parse("@xpos 1op op2 1..2"); ASSERT_EQ(objects.size(), 4u); size_t count=0; for (string str : {"@xpos", "1op", "op2", "1..2"}) { ASSERT_NE(objects[count].get(), nullptr); ASSERT_EQ(objects[count++].get()->opname, str); } } TEST(PDFParserTest, ops2) { PDFParser parser; vector objects = parser.parse("@xpos 1op op2 @ypos", [](const string &str, vector &objects) { if (str == "@xpos" || str == "@ypos") objects.emplace_back(PDFObject(str == "@xpos" ? 1.23 : 3.21)); else objects.emplace_back(PDFOperator(str)); }); ASSERT_EQ(objects.size(), 4u); size_t count=0; for (string str : {"1.23", "1op", "op2", "3.21"}) { ASSERT_EQ(string(objects[count++]), str); } }