112 lines
3.4 KiB
C++
112 lines
3.4 KiB
C++
#include <gtest/gtest.h>
|
|
#include <pdfengine/token.hpp>
|
|
#include <pdfengine/ast.hpp>
|
|
#include "../src/parser/parser.hpp"
|
|
#include "../src/parser/lexer.hpp"
|
|
#include "../src/qpdf/qpdf_extractor.hpp"
|
|
#include <filesystem>
|
|
|
|
#ifndef TEST_CORPUS_DIR
|
|
#define TEST_CORPUS_DIR "../../corpus"
|
|
#endif
|
|
|
|
using namespace pdfengine;
|
|
|
|
TEST(ParserTest, SimpleOperation) {
|
|
Lexer lexer("10 20 Td");
|
|
auto tokens = lexer.tokenize();
|
|
|
|
ContentParser parser(tokens);
|
|
auto ops = parser.parse();
|
|
|
|
ASSERT_EQ(ops.size(), 1);
|
|
EXPECT_EQ(ops[0].op, "Td");
|
|
ASSERT_EQ(ops[0].operands.size(), 2);
|
|
|
|
EXPECT_EQ(ops[0].operands[0]->type, AstNodeType::Number);
|
|
EXPECT_DOUBLE_EQ(ops[0].operands[0]->numberValue, 10.0);
|
|
|
|
EXPECT_EQ(ops[0].operands[1]->type, AstNodeType::Number);
|
|
EXPECT_DOUBLE_EQ(ops[0].operands[1]->numberValue, 20.0);
|
|
}
|
|
|
|
TEST(ParserTest, ArraysAndDicts) {
|
|
Lexer lexer("<< /Type /Page >> [ 1 2 ] (Text) Tj");
|
|
auto tokens = lexer.tokenize();
|
|
|
|
ContentParser parser(tokens);
|
|
auto ops = parser.parse();
|
|
|
|
ASSERT_EQ(ops.size(), 1);
|
|
EXPECT_EQ(ops[0].op, "Tj");
|
|
ASSERT_EQ(ops[0].operands.size(), 3);
|
|
|
|
auto dictNode = ops[0].operands[0];
|
|
EXPECT_EQ(dictNode->type, AstNodeType::Dictionary);
|
|
ASSERT_TRUE(dictNode->dictItems.find("Type") != dictNode->dictItems.end());
|
|
EXPECT_EQ(dictNode->dictItems["Type"]->stringValue, "Page");
|
|
|
|
auto arrayNode = ops[0].operands[1];
|
|
EXPECT_EQ(arrayNode->type, AstNodeType::Array);
|
|
ASSERT_EQ(arrayNode->arrayItems.size(), 2);
|
|
EXPECT_DOUBLE_EQ(arrayNode->arrayItems[0]->numberValue, 1.0);
|
|
EXPECT_DOUBLE_EQ(arrayNode->arrayItems[1]->numberValue, 2.0);
|
|
|
|
auto strNode = ops[0].operands[2];
|
|
EXPECT_EQ(strNode->type, AstNodeType::String);
|
|
EXPECT_EQ(strNode->stringValue, "Text");
|
|
}
|
|
|
|
TEST(ParserTest, MultipleOperations) {
|
|
Lexer lexer("BT /F1 12 Tf (Hello) Tj ET");
|
|
auto tokens = lexer.tokenize();
|
|
|
|
ContentParser parser(tokens);
|
|
auto ops = parser.parse();
|
|
|
|
ASSERT_EQ(ops.size(), 4);
|
|
|
|
EXPECT_EQ(ops[0].op, "BT");
|
|
EXPECT_TRUE(ops[0].operands.empty());
|
|
|
|
EXPECT_EQ(ops[1].op, "Tf");
|
|
ASSERT_EQ(ops[1].operands.size(), 2);
|
|
EXPECT_EQ(ops[1].operands[0]->stringValue, "F1");
|
|
EXPECT_DOUBLE_EQ(ops[1].operands[1]->numberValue, 12.0);
|
|
|
|
EXPECT_EQ(ops[2].op, "Tj");
|
|
ASSERT_EQ(ops[2].operands.size(), 1);
|
|
EXPECT_EQ(ops[2].operands[0]->stringValue, "Hello");
|
|
|
|
EXPECT_EQ(ops[3].op, "ET");
|
|
EXPECT_TRUE(ops[3].operands.empty());
|
|
}
|
|
|
|
TEST(ParserTest, IntegrationHelloWorld) {
|
|
pdfengine::qpdf_layer::QpdfExtractor extractor;
|
|
std::filesystem::path path = std::filesystem::path(TEST_CORPUS_DIR) / "basic" / "hello_world.pdf";
|
|
|
|
auto stream = extractor.extractPageStream(path.string(), 0);
|
|
ASSERT_TRUE(stream.has_value());
|
|
|
|
Lexer lexer(stream->decodedContent);
|
|
auto tokens = lexer.tokenize();
|
|
|
|
ContentParser parser(tokens);
|
|
auto ops = parser.parse();
|
|
|
|
bool foundTj = false;
|
|
for (const auto& op : ops) {
|
|
if (op.op == "Tj" || op.op == "TJ") {
|
|
ASSERT_EQ(op.operands.size(), 1);
|
|
if (op.operands[0]->type == AstNodeType::String &&
|
|
op.operands[0]->stringValue == "Hello, world!") {
|
|
foundTj = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXPECT_TRUE(foundTj) << "Failed to parse (Hello, world!) Tj operation from hello_world.pdf stream";
|
|
}
|