Files
pdf/engine/tests/parser_test.cpp
T
2026-06-22 15:18:47 +05:30

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";
}