120 lines
3.9 KiB
C++
120 lines
3.9 KiB
C++
#include <gtest/gtest.h>
|
|
#include <pdfengine/token.hpp>
|
|
#include <pdfengine/ast.hpp>
|
|
#include <pdfengine/content_object.hpp>
|
|
#include "../src/parser/lexer.hpp"
|
|
#include "../src/parser/parser.hpp"
|
|
#include "../src/parser/content_builder.hpp"
|
|
#include "../src/qpdf/qpdf_extractor.hpp"
|
|
#include <filesystem>
|
|
|
|
#ifndef TEST_CORPUS_DIR
|
|
#define TEST_CORPUS_DIR "../../corpus"
|
|
#endif
|
|
|
|
using namespace pdfengine;
|
|
|
|
TEST(ContentBuilderTest, SimpleTextState) {
|
|
Lexer lexer("10 20 Td /F1 12 Tf (Hello) Tj");
|
|
auto tokens = lexer.tokenize();
|
|
ContentParser parser(tokens);
|
|
ContentBuilder builder;
|
|
|
|
auto ops = parser.parse();
|
|
auto objects = builder.build(ops);
|
|
ASSERT_EQ(objects.size(), 1);
|
|
|
|
EXPECT_EQ(objects[0]->getType(), ContentObjectType::Text);
|
|
auto* textObj = static_cast<TextObject*>(objects[0].get());
|
|
|
|
EXPECT_EQ(textObj->text, "Hello");
|
|
EXPECT_EQ(textObj->fontName, "F1");
|
|
EXPECT_DOUBLE_EQ(textObj->fontSize, 12.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[4], 10.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[5], 20.0);
|
|
}
|
|
|
|
TEST(ContentBuilderTest, KerningArrayTJ) {
|
|
Lexer lexer("[ (He) 120 (llo) -600 (World) ] TJ");
|
|
auto tokens = lexer.tokenize();
|
|
ContentParser parser(tokens);
|
|
ContentBuilder builder;
|
|
|
|
auto ops = parser.parse();
|
|
auto objects = builder.build(ops);
|
|
ASSERT_EQ(objects.size(), 1);
|
|
|
|
EXPECT_EQ(objects[0]->getType(), ContentObjectType::Text);
|
|
auto* textObj = static_cast<TextObject*>(objects[0].get());
|
|
|
|
// -600 is less than -500, so it inserts a space
|
|
EXPECT_EQ(textObj->text, "Hello World");
|
|
}
|
|
|
|
TEST(ContentBuilderTest, RotatedTextMatrix) {
|
|
Lexer lexer("0 1 -1 0 100 200 Tm (Rotated) Tj");
|
|
auto tokens = lexer.tokenize();
|
|
ContentParser parser(tokens);
|
|
ContentBuilder builder;
|
|
|
|
auto ops = parser.parse();
|
|
auto objects = builder.build(ops);
|
|
ASSERT_EQ(objects.size(), 1);
|
|
|
|
EXPECT_EQ(objects[0]->getType(), ContentObjectType::Text);
|
|
auto* textObj = static_cast<TextObject*>(objects[0].get());
|
|
|
|
EXPECT_EQ(textObj->text, "Rotated");
|
|
EXPECT_DOUBLE_EQ(textObj->tm[0], 0.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[1], 1.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[2], -1.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[3], 0.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[4], 100.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[5], 200.0);
|
|
}
|
|
|
|
TEST(ContentBuilderTest, 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);
|
|
ContentBuilder builder;
|
|
|
|
auto ops = parser.parse();
|
|
auto objects = builder.build(ops);
|
|
|
|
// hello_world.pdf has two text lines: "Hello, world!" and "Goodbye, world!"
|
|
int textObjectCount = 0;
|
|
bool foundHello = false;
|
|
bool foundGoodbye = false;
|
|
|
|
for (const auto& obj : objects) {
|
|
if (obj->getType() == ContentObjectType::Text) {
|
|
textObjectCount++;
|
|
auto* textObj = static_cast<TextObject*>(obj.get());
|
|
if (textObj->text == "Hello, world!") {
|
|
foundHello = true;
|
|
EXPECT_EQ(textObj->fontName, "F1");
|
|
EXPECT_DOUBLE_EQ(textObj->fontSize, 12.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[4], 20.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[5], 50.0);
|
|
} else if (textObj->text == "Goodbye, world!") {
|
|
foundGoodbye = true;
|
|
EXPECT_EQ(textObj->fontName, "F2");
|
|
EXPECT_DOUBLE_EQ(textObj->fontSize, 16.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[4], 20.0);
|
|
EXPECT_DOUBLE_EQ(textObj->tm[5], 100.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
EXPECT_GE(textObjectCount, 2);
|
|
EXPECT_TRUE(foundHello);
|
|
EXPECT_TRUE(foundGoodbye);
|
|
}
|