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
14 changes: 10 additions & 4 deletions reader/browser/PageRenderThread.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
// Copyright (C) 2019 ~ 2026 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -873,9 +873,15 @@ void PageRenderThread::onDocPageThumbnailTask(DocPageThumbnailTask task, QPixmap
void PageRenderThread::onDocOpenTask(DocOpenTask task, deepin_reader::Document::Error error, deepin_reader::Document *document, QList<deepin_reader::Page *> pages)
{
// qCDebug(appLog) << "PageRenderThread::onDocOpenTask() - Starting on doc open task";
if (DocSheet::existSheet(task.sheet)) {
task.renderer->handleOpened(error, document, pages);
DocSheet *sheet = task.sheet;
if (nullptr == sheet || !DocSheet::existSheet(sheet) || sheet->uuid() != task.uuid) {
qCWarning(appLog) << "Sheet no longer alive (or address reused), drop doc open task";
qDeleteAll(pages);
delete document;
return;
}

sheet->renderer()->handleOpened(error, document, pages);
// qCDebug(appLog) << "PageRenderThread::onDocOpenTask() - On doc open task completed";
}

Expand Down
5 changes: 3 additions & 2 deletions reader/browser/PageRenderThread.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
// Copyright (C) 2019 ~ 2026 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -61,6 +61,7 @@ struct DocOpenTask {//打开文档
DocSheet *sheet = nullptr;
QString password;
SheetRenderer *renderer = nullptr;
QString uuid; //排队时的sheet唯一标识,防止地址复用误判存活
};

struct DocCloseTask {//关闭文档
Expand Down
4 changes: 3 additions & 1 deletion reader/uiframe/DocSheet.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd.
// Copyright (C) 2019 ~ 2026 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
Expand Down Expand Up @@ -670,7 +670,9 @@
*/
SheetRenderer *renderer();

QString uuid() const { return m_uuid; }

public slots:

Check warning on line 675 in reader/uiframe/DocSheet.h

View workflow job for this annotation

GitHub Actions / cppcheck

There is an unknown macro here somewhere. Configuration is required. If slots is a macro then please configure it.
/**
* @brief 阻塞打印
*/
Expand Down
3 changes: 3 additions & 0 deletions reader/uiframe/SheetRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ void SheetRenderer::openFileAsync(const QString &password)

task.renderer = this;

if (nullptr != m_sheet)
task.uuid = m_sheet->uuid();

PageRenderThread::appendTask(task);
qCDebug(appLog) << "SheetRenderer::openFileAsync end";
}
Expand Down
44 changes: 39 additions & 5 deletions tests/browser/ut_pagerenderthread.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
// Copyright (C) 2019 ~ 2026 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -85,6 +85,19 @@ static void handleOpened_stub(deepin_reader::Document::Error, deepin_reader::Doc
g_funcName = __FUNCTION__;
}

// DocSheet::uuid 档:返回固定uuid供任务校验比对
static QString uuid_stub()
{
return QStringLiteral("ut-sheet-uuid");
}

// DocSheet::renderer 档:占位渲染器(handleOpened已stub)。堆分配不释放,避免静态对象在 main 返回后析构
static SheetRenderer *renderer_stub()
{
static SheetRenderer *dummy = new SheetRenderer(nullptr);
return dummy;
}

// Makes DocSheet::existSheet() return true so the onDoc*Finished slots
// take the "sheet exists" branch without needing a real DocSheet (whose
// destructor would otherwise start the render thread and deadlock the test).
Expand Down Expand Up @@ -309,22 +322,43 @@ TEST_F(TestPageRenderThread, UT_PageRenderThread_onDocPageThumbnailTask_002)
EXPECT_TRUE(g_funcName == "handleRenderThumbnail_stub");
}

// Tests onDocOpenTask when sheet exists; forwards to
// SheetRenderer::handleOpened (stubbed).
// Tests onDocOpenTask when sheet exists; forwards to SheetRenderer::handleOpened (stubbed).
TEST_F(TestPageRenderThread, UT_PageRenderThread_onDocOpenTask_002)
{
Stub s;
s.set(ADDR(DocSheet, existSheet), existSheet_true_stub);
s.set(ADDR(DocSheet, uuid), uuid_stub);
s.set(ADDR(DocSheet, renderer), renderer_stub);
s.set(ADDR(SheetRenderer, handleOpened), handleOpened_stub);

DocOpenTask task;
task.sheet = nullptr;
task.sheet = reinterpret_cast<DocSheet *>(0x1); //成员调用均已被stub
task.renderer = nullptr;
task.uuid = "ut-sheet-uuid"; //与uuid_stub一致,校验通过
QList<deepin_reader::Page *> pages;
m_tester->onDocOpenTask(task, deepin_reader::Document::NoError, nullptr, pages);
EXPECT_TRUE(g_funcName == "handleOpened_stub");
}

// Tests onDocOpenTask when uuid mismatch: task must be dropped, document/pages released.
TEST_F(TestPageRenderThread, UT_PageRenderThread_onDocOpenTask_003)
{
g_funcName.clear();
Stub s;
s.set(ADDR(DocSheet, existSheet), existSheet_true_stub);
s.set(ADDR(DocSheet, uuid), uuid_stub);
s.set(ADDR(DocSheet, renderer), renderer_stub);
s.set(ADDR(SheetRenderer, handleOpened), handleOpened_stub);

DocOpenTask task;
task.sheet = reinterpret_cast<DocSheet *>(0x1);
task.renderer = reinterpret_cast<SheetRenderer *>(0x1); //悬空,不应被解引用
task.uuid = "stale-uuid"; //与uuid_stub不一致
QList<deepin_reader::Page *> pages;
m_tester->onDocOpenTask(task, deepin_reader::Document::NoError, nullptr, pages);
EXPECT_TRUE(g_funcName.isEmpty());
}

//======================================================================
// appendTask overloads (static). Thread start is stubbed to keep the
// queued tasks from running during the test.
Expand Down
25 changes: 25 additions & 0 deletions tests/test-prj-running.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ cmake -DCMAKE_SAFETYTEST_ARG="CMAKE_SAFETYTEST_ARG_ON" \
# Compile tests target
make -j"$(nproc)" test-deepin-reader

# DB 隔离: 重定向 Qt AppDataLocation,避免读写用户数据及跨运行状态残留
export XDG_DATA_HOME="${build_path}/ut-testdata"
rm -rf "${XDG_DATA_HOME}"
mkdir -p "${XDG_DATA_HOME}"

# Ensure report directory used by gtest exists inside the build tree
mkdir -p "${build_path}/report"

Expand All @@ -53,11 +58,31 @@ lcov --directory "${workdir}" --zerocounters || true
# Re-run tests so .gcda files reflect a clean run
# If the first run segfaulted, .gcda files won't exist (atexit not called on SIGSEGV).
# This re-run gives another chance; we also add a SIGSEGV handler as safety net.
rm -rf "${XDG_DATA_HOME}"
mkdir -p "${XDG_DATA_HOME}"
set +e
./tests/test-deepin-reader --gtest_output=xml:"${build_path}/report/report_deepin-reader.xml"
retest_exit_code=$?
set -e

# libdjvulibre21 全局析构 bug: 进程退出阶段 free() 非法指针 → SIGABRT(134),
# 此时所有测试已通过且 XML 已写出。若 exit=134 且 XML failures=0,则视为通过
is_djvu_exit_crash() {
[ "$1" -eq 134 ] || return 1
local xml="${build_path}/report/report_deepin-reader.xml"
[ -f "$xml" ] || return 1
grep -q 'failures="0"' "$xml" 2>/dev/null
}

if is_djvu_exit_crash "$test_exit_code"; then
echo "Note: first run exit 134 (djvulibre exit-time abort), but all tests passed — ignoring"
test_exit_code=0
fi
if is_djvu_exit_crash "$retest_exit_code"; then
echo "Note: re-run exit 134 (djvulibre exit-time abort), but all tests passed — ignoring"
retest_exit_code=0
fi

# Use the worst exit code between first and second run
test_exit_code=$((test_exit_code || retest_exit_code))

Expand Down
17 changes: 8 additions & 9 deletions tests/uiframe/ut_sheetrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
#include "dpdfpage.h"
#include "stub.h"

#include <DWidget>

Check warning on line 11 in tests/uiframe/ut_sheetrenderer.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 12 in tests/uiframe/ut_sheetrenderer.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.
#include <QMutex>

Check warning on line 13 in tests/uiframe/ut_sheetrenderer.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 14 in tests/uiframe/ut_sheetrenderer.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 15 in tests/uiframe/ut_sheetrenderer.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 <QPointF>

Check warning on line 16 in tests/uiframe/ut_sheetrenderer.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 17 in tests/uiframe/ut_sheetrenderer.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Expand Down Expand Up @@ -270,20 +271,18 @@

TEST_F(TestSheetRenderer, testOpenFileAsync)
{
// Call openFileAsync - it just appends a task to the render thread
// Must spin the event loop until the task is fully executed and delivered;
// otherwise a queued sigDocOpenTask referencing this renderer outlives the test
// and gets delivered to freed memory later.
QSignalSpy spy(m_tester, &SheetRenderer::sigOpened);
m_tester->openFileAsync("test");
// Wait briefly for the task to be processed
QTest::qWait(100);
QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 30000);
SUCCEED();
}

TEST_F(TestSheetRenderer, testOpenFileExec)
{
// Schedule sigOpened emission to break the event loop in openFileExec
QTimer::singleShot(50, m_tester, [this]() {
emit m_tester->sigOpened(deepin_reader::Document::NoError);
});
// Let openFileExec wait for the REAL sigOpened of the actual open task.
bool result = m_tester->openFileExec("test");
Q_UNUSED(result);
SUCCEED();
EXPECT_TRUE(result);
}
Loading