#include #include #include "Outline.h" #include "PDFDoc.h" #include "PDFDocFactory.h" class TestInternalOutline : public QObject { Q_OBJECT public: explicit TestInternalOutline(QObject *parent = nullptr) : QObject(parent) { } private slots: void testCreateOutline(); void testSetOutline(); void testInsertChild(); void testRemoveChild(); void testSetTitleAndSetPageDest(); }; void TestInternalOutline::testCreateOutline() { QTemporaryFile tempFile; QVERIFY(tempFile.open()); tempFile.close(); const std::string tempFileName = tempFile.fileName().toStdString(); const GooString gooTempFileName { tempFileName }; std::unique_ptr doc = PDFDocFactory().createPDFDoc(GooString(TESTDATADIR "/unittestcases/truetype.pdf")); QVERIFY(doc.get()); // ensure the file has no existing outline Outline *outline = doc->getOutline(); QVERIFY(outline != nullptr); auto *outlineItems = outline->getItems(); QVERIFY(outlineItems == nullptr); // create an empty outline and save the file outline->setOutline({}); outlineItems = outline->getItems(); // no items will result in a nullptr rather than a 0 length list QVERIFY(outlineItems == nullptr); doc->saveAs(gooTempFileName); /******************************************************/ doc = PDFDocFactory().createPDFDoc(gooTempFileName); QVERIFY(doc.get()); // ensure the re-opened file has an outline with no items outline = doc->getOutline(); QVERIFY(outline != nullptr); outlineItems = outline->getItems(); QVERIFY(outlineItems == nullptr); } static std::string getTitle(const OutlineItem *item) { const std::vector &u = item->getTitle(); std::string s; for (const auto &c : u) { s.append(1, (char)(c)); } return s; } void TestInternalOutline::testSetOutline() { QTemporaryFile tempFile; QVERIFY(tempFile.open()); tempFile.close(); const std::string tempFileName = tempFile.fileName().toStdString(); const GooString gooTempFileName { tempFileName }; std::unique_ptr doc = PDFDocFactory().createPDFDoc(GooString(TESTDATADIR "/unittestcases/truetype.pdf")); QVERIFY(doc.get()); // ensure the file has no existing outline Outline *outline = doc->getOutline(); QVERIFY(outline != nullptr); auto *outlineItems = outline->getItems(); QVERIFY(outlineItems == nullptr); // create an outline and save the file outline->setOutline( { { "1", 1, { { "1.1", 1, {} }, { "1.2", 2, {} }, { "1.3", 3, { { "1.3.1", 1, {} }, { "1.3.2", 2, {} }, { "1.3.3", 3, {} }, { "1.3.4", 4, {} } } }, { "1.4", 4, {} } } }, { "2", 2, {} }, { "3", 3, {} }, { "4", 4, {} } }); outlineItems = outline->getItems(); QVERIFY(outlineItems != nullptr); doc->saveAs(gooTempFileName); outline = nullptr; /******************************************************/ doc = PDFDocFactory().createPDFDoc(gooTempFileName); QVERIFY(doc.get()); // ensure the re-opened file has an outline outline = doc->getOutline(); QVERIFY(outline != nullptr); outlineItems = outline->getItems(); QVERIFY(outlineItems != nullptr); QVERIFY(outlineItems->size() == 4); OutlineItem *item = outlineItems->at(0); QVERIFY(item != nullptr); // c_str() is used so QCOMPARE prints string correctly on disagree QCOMPARE(getTitle(item).c_str(), "1"); item = outlineItems->at(1); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "2"); item = outlineItems->at(2); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "3"); item = outlineItems->at(3); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "4"); outlineItems = outlineItems->at(0)->getKids(); QVERIFY(outlineItems != nullptr); item = outlineItems->at(0); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.1"); item = outlineItems->at(1); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.2"); item = outlineItems->at(2); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.3"); item = outlineItems->at(3); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.4"); outlineItems = outlineItems->at(2)->getKids(); QVERIFY(outlineItems != nullptr); item = outlineItems->at(0); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.3.1"); item = outlineItems->at(1); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.3.2"); item = outlineItems->at(2); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.3.3"); item = outlineItems->at(3); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.3.4"); } void TestInternalOutline::testInsertChild() { QTemporaryFile tempFile; QVERIFY(tempFile.open()); tempFile.close(); QTemporaryFile tempFile2; QVERIFY(tempFile2.open()); tempFile2.close(); const std::string tempFileName = tempFile.fileName().toStdString(); const GooString gooTempFileName { tempFileName }; const std::string tempFileName2 = tempFile2.fileName().toStdString(); const GooString gooTempFileName2 { tempFileName2 }; std::unique_ptr doc = PDFDocFactory().createPDFDoc(GooString(TESTDATADIR "/unittestcases/truetype.pdf")); QVERIFY(doc.get()); // ensure the file has no existing outline Outline *outline = doc->getOutline(); QVERIFY(outline != nullptr); auto *outlineItems = outline->getItems(); QVERIFY(outlineItems == nullptr); // create an outline and save the file outline->setOutline({}); doc->saveAs(gooTempFileName); outline = nullptr; /******************************************************/ doc = PDFDocFactory().createPDFDoc(gooTempFileName); QVERIFY(doc.get()); // ensure the re-opened file has an outline with no items outline = doc->getOutline(); QVERIFY(outline != nullptr); // nullptr for 0-length QVERIFY(outline->getItems() == nullptr); // insert first one to empty outline->insertChild("2", 1, 0); // insert at the end outline->insertChild("3", 1, 1); // insert at the start outline->insertChild("1", 1, 0); // add an item to "2" outlineItems = outline->getItems(); QVERIFY(outlineItems != nullptr); QVERIFY(outlineItems->at(1)); outlineItems->at(1)->insertChild("2.1", 2, 0); outlineItems->at(1)->insertChild("2.2", 2, 1); outlineItems->at(1)->insertChild("2.4", 2, 2); outlineItems->at(1)->insertChild("2.3", 2, 2); // save the file doc->saveAs(gooTempFileName2); outline = nullptr; /******************************************************/ doc = PDFDocFactory().createPDFDoc(gooTempFileName2); QVERIFY(doc.get()); // ensure the re-opened file has an outline outline = doc->getOutline(); QVERIFY(outline != nullptr); outlineItems = outline->getItems(); QVERIFY(outlineItems != nullptr); QVERIFY(outlineItems->size() == 3); OutlineItem *item = outlineItems->at(0); QVERIFY(item != nullptr); // c_str() is used so QCOMPARE prints string correctly on disagree QCOMPARE(getTitle(item).c_str(), "1"); item = outlineItems->at(1); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "2"); item = outlineItems->at(2); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "3"); outlineItems = outlineItems->at(1)->getKids(); item = outlineItems->at(0); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "2.1"); item = outlineItems->at(1); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "2.2"); item = outlineItems->at(2); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "2.3"); item = outlineItems->at(3); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "2.4"); } void TestInternalOutline::testRemoveChild() { QTemporaryFile tempFile; QVERIFY(tempFile.open()); tempFile.close(); QTemporaryFile tempFile2; QVERIFY(tempFile2.open()); tempFile2.close(); const std::string tempFileName = tempFile.fileName().toStdString(); const GooString gooTempFileName { tempFileName }; const std::string tempFileName2 = tempFile2.fileName().toStdString(); const GooString gooTempFileName2 { tempFileName2 }; std::unique_ptr doc = PDFDocFactory().createPDFDoc(GooString(TESTDATADIR "/unittestcases/truetype.pdf")); QVERIFY(doc.get()); // ensure the file has no existing outline Outline *outline = doc->getOutline(); QVERIFY(outline != nullptr); auto *outlineItems = outline->getItems(); QVERIFY(outlineItems == nullptr); // create an outline and save the file outline->setOutline({ { "1", 1, { { "1.1", 1, {} }, { "1.2", 2, {} }, { "1.3", 3, { { "1.3.1", 1, {} }, { "1.3.2", 2, {} }, { "1.3.3", 3, {} }, { "1.3.4", 4, {} } } }, { "1.4", 4, {} } } }, { "2", 2, { { "2.1", 1, {} } } }, { "3", 3, { { "3.1", 1, {} }, { "3.2", 2, { { "3.2.1", 1, {} } } } } }, { "4", 4, {} } }); outlineItems = outline->getItems(); QVERIFY(outlineItems != nullptr); doc->saveAs(gooTempFileName); outline = nullptr; /******************************************************/ doc = PDFDocFactory().createPDFDoc(gooTempFileName); QVERIFY(doc.get()); outline = doc->getOutline(); QVERIFY(outline != nullptr); // remove "3" outline->removeChild(2); // remove "1.3.1" outline->getItems()->at(0)->getKids()->at(2)->removeChild(0); // remove "1.3.4" outline->getItems()->at(0)->getKids()->at(2)->removeChild(2); // remove "2.1" outline->getItems()->at(1)->removeChild(0); // save the file doc->saveAs(gooTempFileName2); outline = nullptr; /******************************************************/ doc = PDFDocFactory().createPDFDoc(gooTempFileName2); QVERIFY(doc.get()); // ensure the re-opened file has an outline outline = doc->getOutline(); QVERIFY(outline != nullptr); outlineItems = outline->getItems(); QVERIFY(outlineItems != nullptr); QVERIFY(outlineItems->size() == 3); OutlineItem *item = outlineItems->at(0); QVERIFY(item != nullptr); // c_str() is used so QCOMPARE prints string correctly on disagree QCOMPARE(getTitle(item).c_str(), "1"); item = outlineItems->at(1); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "2"); item = outlineItems->at(2); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "4"); outlineItems = outlineItems->at(0)->getKids(); outlineItems = outlineItems->at(2)->getKids(); item = outlineItems->at(0); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.3.2"); item = outlineItems->at(1); QVERIFY(item != nullptr); QCOMPARE(getTitle(item).c_str(), "1.3.3"); // verify "2.1" is removed, lst length 0 is returned as a nullptr QVERIFY(outline->getItems()->at(1)->getKids() == nullptr); } void TestInternalOutline::testSetTitleAndSetPageDest() { QTemporaryFile tempFile; QVERIFY(tempFile.open()); tempFile.close(); QTemporaryFile tempFile2; QVERIFY(tempFile2.open()); tempFile2.close(); const std::string tempFileName = tempFile.fileName().toStdString(); const GooString gooTempFileName { tempFileName }; const std::string tempFileName2 = tempFile2.fileName().toStdString(); const GooString gooTempFileName2 { tempFileName2 }; std::unique_ptr doc = PDFDocFactory().createPDFDoc(GooString(TESTDATADIR "/unittestcases/truetype.pdf")); QVERIFY(doc.get()); // ensure the file has no existing outline Outline *outline = doc->getOutline(); QVERIFY(outline != nullptr); auto *outlineItems = outline->getItems(); QVERIFY(outlineItems == nullptr); // create an outline and save the file outline->setOutline({ { "1", 1, { { "1.1", 1, {} }, { "1.2", 2, {} }, { "1.3", 3, { { "1.3.1", 1, {} }, { "1.3.2", 2, {} }, { "1.3.3", 3, {} }, { "1.3.4", 4, {} } } }, { "1.4", 4, {} } } }, { "2", 2, { { "2.1", 1, {} } } }, { "3", 3, { { "3.1", 1, {} }, { "3.2", 2, { { "3.2.1", 1, {} } } } } }, { "4", 4, {} } }); outlineItems = outline->getItems(); QVERIFY(outlineItems != nullptr); doc->saveAs(gooTempFileName); outline = nullptr; /******************************************************/ doc = PDFDocFactory().createPDFDoc(gooTempFileName); QVERIFY(doc.get()); outline = doc->getOutline(); QVERIFY(outline != nullptr); // change "1.3.1" OutlineItem *item = outline->getItems()->at(0)->getKids()->at(2)->getKids()->at(0); QCOMPARE(getTitle(item).c_str(), "1.3.1"); item->setTitle("Changed to a different title"); item = outline->getItems()->at(2); { const LinkAction *action = item->getAction(); QVERIFY(action->getKind() == actionGoTo); const LinkGoTo *gotoAction = dynamic_cast(action); const LinkDest *dest = gotoAction->getDest(); QVERIFY(dest->isPageRef() == false); QCOMPARE(dest->getPageNum(), 3); item->setPageDest(1); } // save the file doc->saveAs(gooTempFileName2); outline = nullptr; item = nullptr; /******************************************************/ doc = PDFDocFactory().createPDFDoc(gooTempFileName2); QVERIFY(doc.get()); outline = doc->getOutline(); QVERIFY(outline != nullptr); item = outline->getItems()->at(0)->getKids()->at(2)->getKids()->at(0); QCOMPARE(getTitle(item).c_str(), "Changed to a different title"); { item = outline->getItems()->at(2); const LinkAction *action = item->getAction(); QVERIFY(action->getKind() == actionGoTo); const LinkGoTo *gotoAction = dynamic_cast(action); const LinkDest *dest = gotoAction->getDest(); QVERIFY(dest->isPageRef() == false); QCOMPARE(dest->getPageNum(), 1); } } QTEST_GUILESS_MAIN(TestInternalOutline) #include "check_internal_outline.moc"