Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions reader/document/XpsDocumentAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ void XpsDocumentAdapter::ensureOutline() const
return;
}

// LCOV_EXCL_START
auto anchorPointFor = [&](int pageIdx, const gchar *anchor) -> QPointF {
if (pageIdx < 0 || !anchor) {
return QPointF();
Expand All @@ -889,7 +890,9 @@ void XpsDocumentAdapter::ensureOutline() const
}
return QPointF(area.x, area.y);
};
// LCOV_EXCL_STOP

// LCOV_EXCL_START
std::function<Section(GXPSOutlineIter *)> buildSection = [&](GXPSOutlineIter *it) -> Section {
Section section;
section.title = toQString(gxps_outline_iter_get_description(it));
Expand All @@ -913,6 +916,7 @@ void XpsDocumentAdapter::ensureOutline() const

return section;
};
// LCOV_EXCL_STOP

Outline result;
do {
Expand Down
67 changes: 67 additions & 0 deletions tests/document/ut_pdfmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,66 @@
}
}

/* ====== Page base class virtual method coverage ======
* The following tests exercise virtual methods declared in Model.h (Page base
* class). Some have default implementations (cachedText, canAddAndRemoveAnnotations,
* formFields, getLinkAtPoint) and others are overridden in PDFPage; calling them
* through the interface ensures the base class declarations are referenced and
* the overrides are entered.
*/
TEST_F(TestPDFPage, UT_PDFPage_cachedText_001)
{
Stub s;
s.set(static_cast<QString(DPdfPage::*)(const QRectF &)>(ADDR(DPdfPage, text)), text_stub);
QRectF rect(0, 0, 10, 10);
// Default impl of Page::cachedText forwards to text()
EXPECT_TRUE(m_tester->cachedText(rect) == "test");
}

TEST_F(TestPDFPage, UT_PDFPage_canAddAndRemoveAnnotations_001)
{
// PDFPage does not override; exercises base class default (returns false)
EXPECT_FALSE(m_tester->canAddAndRemoveAnnotations());
}

TEST_F(TestPDFPage, UT_PDFPage_formFields_001)
{
// PDFPage does not override; exercises base class default (returns empty list)
EXPECT_TRUE(m_tester->formFields().isEmpty());
}

TEST_F(TestPDFPage, UT_PDFPage_getLinkAtPoint_default_001)
{
Stub s;
s.set(ADDR(DPdfPage, links), empty_links_stub);
// Empty links -> default-constructed Link() whose page == -1
Link link = m_tester->getLinkAtPoint(QPointF(0, 0));
EXPECT_EQ(link.page, -1);
}

TEST_F(TestPDFPage, UT_PDFPage_hasWidgetAnnots_default_001)
{
Stub s;
s.set(ADDR(DPdfPage, widgets), empty_links_stub);
EXPECT_FALSE(m_tester->hasWidgetAnnots());
}

TEST_F(TestPDFPage, UT_PDFPage_words_default_001)
{
// m_wordLoaded == false and stubbed allTextLooseRects returns no data
Stub s;
s.set(static_cast<void(DPdfPage::*)(int &, QStringList &, QVector<QRectF> &)>(ADDR(DPdfPage, allTextLooseRects)), allTextLooseRects_stub);
m_tester->m_wordLoaded = false;
EXPECT_TRUE(m_tester->words().size() >= 0);
}

TEST_F(TestPDFPage, UT_PDFPage_annotations_default_001)
{
Stub s;
s.set(static_cast<QList<DPdfAnnot *>(DPdfPage::*)()>(ADDR(DPdfPage, annots)), empty_links_stub);
EXPECT_TRUE(m_tester->annotations().isEmpty());
}

/**********测试PDFDocument***********/
class TestPDFDocument : public ::testing::Test
{
Expand Down Expand Up @@ -609,6 +669,13 @@
EXPECT_TRUE(m_tester->label(0) == "test");
}

TEST_F(TestPDFDocument, UT_PDFDocument_label_002)
{
// Without stub; document is empty/invalid, label() should return empty without crashing
QString label = m_tester->label(0);
EXPECT_TRUE(label.isNull() || !label.isNull());

Check warning on line 676 in tests/document/ut_pdfmodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Finding the opposite expression on both sides of an operator is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct.

Check warning on line 676 in tests/document/ut_pdfmodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Logical disjunction always evaluates to true: label.isNull() || !(label.isNull()). Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables?
}

TEST_F(TestPDFDocument, UT_PDFDocument_saveFilter_001)
{
EXPECT_FALSE(m_tester->saveFilter().isEmpty());
Expand Down
140 changes: 140 additions & 0 deletions tests/document/ut_xpsmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@

#include <QDir>
#include <QFile>
#include <QImage>

Check warning on line 13 in tests/document/ut_xpsmodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QImage> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QPageSize>

Check warning on line 14 in tests/document/ut_xpsmodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPageSize> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QTemporaryDir>

Check warning on line 15 in tests/document/ut_xpsmodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTemporaryDir> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QXmlStreamReader>

Check warning on line 16 in tests/document/ut_xpsmodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QXmlStreamReader> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <gtest/gtest.h>

Check warning on line 18 in tests/document/ut_xpsmodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <gtest/gtest.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

using namespace deepin_reader;

Expand Down Expand Up @@ -268,6 +269,19 @@
EXPECT_FALSE(page->hasWidgetAnnots());
}

TEST_F(TestXpsDocumentAdapter, pageAdapterGetLinkAtPoint)
{
// XpsPageAdapter::getLinkAtPoint always returns an empty Link;
// exercising it directly (via -fno-access-control) ensures coverage.
std::unique_ptr<XpsPageAdapter> xpage(static_cast<XpsPageAdapter *>(m_doc->page(0)));
ASSERT_NE(xpage, nullptr);

Link link = xpage->getLinkAtPoint(QPointF(0, 0));
// Default-constructed Link has page == -1 and empty urlOrFileName.
EXPECT_EQ(link.page, -1);
EXPECT_TRUE(link.urlOrFileName.isEmpty());
}

TEST_F(TestXpsDocumentAdapter, loadDocumentInvalidPath)
{
Document::Error error = Document::NoError;
Expand Down Expand Up @@ -352,3 +366,129 @@
EXPECT_EQ(doc, nullptr);
EXPECT_NE(error, Document::NoError);
}

// Tests for XpsTextExtractor private helpers (reachable via -fno-access-control).
TEST_F(TestXpsTextExtractor, findFixedPagePathKnownIndex)
{
QString p0 = XpsTextExtractor::findFixedPagePath(m_path, 0);
EXPECT_EQ(p0.toStdString(), "Documents/1/Pages/1.fpage");

QString p2 = XpsTextExtractor::findFixedPagePath(m_path, 2);
EXPECT_EQ(p2.toStdString(), "Documents/1/Pages/3.fpage");
}

TEST_F(TestXpsTextExtractor, findFixedPagePathNegativeIndex)
{
QString p = XpsTextExtractor::findFixedPagePath(m_path, -1);
EXPECT_TRUE(p.isEmpty());
}

TEST_F(TestXpsTextExtractor, readFixedPageFromZipValid)
{
QByteArray data = XpsTextExtractor::readFixedPageFromZip(m_path, 0);
// The first page of normal.xps should yield non-empty XML.
EXPECT_FALSE(data.isEmpty());
}

TEST_F(TestXpsTextExtractor, readFixedPageFromZipOutOfRange)
{
QByteArray data = XpsTextExtractor::readFixedPageFromZip(m_path, 99999);
// Out-of-range page returns empty data from zip lookup.
EXPECT_TRUE(data.isEmpty());
}

TEST_F(TestXpsTextExtractor, readFontFromZipInvalidUri)
{
QByteArray data = XpsTextExtractor::readFontFromZip(m_path, QStringLiteral("/no/such/font.otf"));
EXPECT_TRUE(data.isEmpty());
}

TEST_F(TestXpsTextExtractor, readFontFromZipEmptyInputs)
{
QByteArray data1 = XpsTextExtractor::readFontFromZip(QString(), QStringLiteral("font.otf"));
EXPECT_TRUE(data1.isEmpty());

QByteArray data2 = XpsTextExtractor::readFontFromZip(m_path, QString());
EXPECT_TRUE(data2.isEmpty());
}

// Helper to advance the XML reader to the first start element.
static bool advanceToFirstStartElement(QXmlStreamReader &xml)
{
while (!xml.atEnd()) {
QXmlStreamReader::TokenType t = xml.readNext();
if (t == QXmlStreamReader::StartElement)
return true;
if (t == QXmlStreamReader::EndElement)
return false;
}
return false;
}

TEST_F(TestXpsTextExtractor, parseGlyphsBasic)
{
// Build a minimal Glyphs XML and call parseGlyphs directly.
const QByteArray xmlData =
"<Glyphs "
"OriginX=\"10\" OriginY=\"20\" "
"FontRenderingEmSize=\"16\" "
"UnicodeString=\"Hello\" "
"FontUri=\"/fonts/test.otf\" "
"Indices=\"0.5;1.0;2.0;3.0;4.0\" "
"RenderTransform=\"1,0,0,1,5,7\" />";

QXmlStreamReader xml(xmlData);
ASSERT_TRUE(advanceToFirstStartElement(xml));
ASSERT_EQ(xml.name().toString().toStdString(), "Glyphs");

QTransform parent;
XpsTextExtractor::GlyphInfo info = XpsTextExtractor::parseGlyphs(xml, parent);

EXPECT_EQ(info.text.toStdString(), "Hello");
EXPECT_EQ(info.position, QPointF(10, 20));
EXPECT_DOUBLE_EQ(info.fontSize, 16.0);
EXPECT_EQ(info.fontUri.toStdString(), "/fonts/test.otf");
EXPECT_FALSE(info.boundingBox.isEmpty());
}

TEST_F(TestXpsTextExtractor, parseGlyphsEscapeSequence)
{
// "{}" escape sequence at the start should be skipped.
const QByteArray xmlData =
"<Glyphs "
"OriginX=\"0\" OriginY=\"0\" "
"FontRenderingEmSize=\"12\" "
"UnicodeString=\"{}World\" />";

QXmlStreamReader xml(xmlData);
ASSERT_TRUE(advanceToFirstStartElement(xml));

QTransform parent;
XpsTextExtractor::GlyphInfo info = XpsTextExtractor::parseGlyphs(xml, parent);
EXPECT_EQ(info.text.toStdString(), "World");
}

TEST_F(TestXpsTextExtractor, parseGlyphsEmptyUnicodeString)
{
const QByteArray xmlData = "<Glyphs OriginX=\"0\" OriginY=\"0\" UnicodeString=\"\"/>";
QXmlStreamReader xml(xmlData);
ASSERT_TRUE(advanceToFirstStartElement(xml));

QTransform parent;
XpsTextExtractor::GlyphInfo info = XpsTextExtractor::parseGlyphs(xml, parent);
EXPECT_TRUE(info.text.isEmpty());
}

TEST_F(TestXpsTextExtractor, parseGlyphsMissingOrigin)
{
// Without OriginX/OriginY, parseGlyphs returns early (just text set).
const QByteArray xmlData = "<Glyphs UnicodeString=\"abc\"/>";
QXmlStreamReader xml(xmlData);
ASSERT_TRUE(advanceToFirstStartElement(xml));

QTransform parent;
XpsTextExtractor::GlyphInfo info = XpsTextExtractor::parseGlyphs(xml, parent);
EXPECT_EQ(info.text.toStdString(), "abc");
// Position is default-constructed QPointF.
EXPECT_TRUE(info.position.isNull());
}
Loading