Skip to content

fix(tests): migrate unit tests to Qt6 and fix DEADLYSIGNAL crash#479

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
pengfeixx:fix/unittest-build-and-crash
Jun 4, 2026
Merged

fix(tests): migrate unit tests to Qt6 and fix DEADLYSIGNAL crash#479
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
pengfeixx:fix/unittest-build-and-crash

Conversation

@pengfeixx
Copy link
Copy Markdown
Contributor

Migrate test build system from Qt5 to Qt6 (dtk6, Qt6 modules), fix cmake source path, test data paths in run script, and move UNITTEST guard before workspaceWindows() to prevent ASan crash caused by DForeignWindow::fromWinId() in worker thread.

将单元测试构建系统从 Qt5 迁移至 Qt6(dtk6、Qt6 模块),
修复运行脚本中 cmake 源码路径、测试数据路径问题,
并将 UNITTEST 保护移至 workspaceWindows() 之前,
防止工作线程中 DForeignWindow::fromWinId() 导致 ASan 崩溃。

Log: 修复单元测试构建和运行崩溃问题
Influence: 修复后全部 101 个单元测试用例可正常构建并通过,
覆盖 Qt5→Qt6 迁移、cmake 路径、脚本路径、线程安全等修复。

Migrate test build system from Qt5 to Qt6 (dtk6, Qt6 modules),
fix cmake source path, test data paths in run script, and move
UNITTEST guard before workspaceWindows() to prevent ASan crash
caused by DForeignWindow::fromWinId() in worker thread.

将单元测试构建系统从 Qt5 迁移至 Qt6(dtk6、Qt6 模块),
修复运行脚本中 cmake 源码路径、测试数据路径问题,
并将 UNITTEST 保护移至 workspaceWindows() 之前,
防止工作线程中 DForeignWindow::fromWinId() 导致 ASan 崩溃。

Log: 修复单元测试构建和运行崩溃问题
Influence: 修复后全部 101 个单元测试用例可正常构建并通过,
覆盖 Qt5→Qt6 迁移、cmake 路径、脚本路径、线程安全等修复。
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @pengfeixx, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

这是一次将项目从 Qt5 迁移到 Qt6/DTK6 并对单元测试进行适配的代码审查。整体来看,迁移方向正确,解决了很多 Qt6 中的 Breaking Changes(如 QCamera、QWheelEvent、高 DPI 属性等),并且对测试脚本的健壮性做了一定提升。

以下是针对语法逻辑、代码质量、代码性能和代码安全方面的详细审查意见和改进建议:

1. 语法与逻辑

1.1 CMake 版本与 Project 声明顺序

文件: tests/CMakeLists.txt
问题: cmake_minimum_required 被移到了 project() 之前,这在 CMake 语法上是允许的,但结合上下文,原代码是先 projectcmake_minimum_required。更重要的是,CMake 官方强烈建议 cmake_minimum_required 必须在 project() 之前调用,以确保策略设置正确。
建议: 保持当前顺序(先 cmake_minimum_requiredproject),但需确保这是有意为之的修改。

1.2 CMake 文件遍历与排除逻辑的脆弱性

文件: tests/CMakeLists.txt
问题: 使用 foreach 循环和字符串比较来排除 videosurface.cpp

file(GLOB_RECURSE SRC_CXXSOURCES ../src/src/*.cpp)
foreach(src_file ${SRC_CXXSOURCES})
    get_filename_component(src_name ${src_file} NAME)
    if(NOT src_name STREQUAL "videosurface.cpp")
        list(APPEND CXXSOURCES ${src_file})
    endif()
endforeach()

这种做法在逻辑上没问题,但如果未来需要排除更多文件(Qt6 中可能还有其他不兼容的文件),if 条件会变得冗长且难以维护。
建议: 使用 CMake 的 list(FILTER ...) 语法(需要 CMake 3.6+,你已要求 3.16,所以完全支持),更简洁高效:

file(GLOB_RECURSE SRC_CXXSOURCES ../src/src/*.cpp)
list(FILTER SRC_CXXSOURCES EXCLUDE REGEX "videosurface\\.cpp$")
list(APPEND CXXSOURCES ${SRC_CXXSOURCES})

1.3 DTK 头文件包含路径硬编码

文件: MainwindowTest.cpp, MainwindowTest.h, main.cpp
问题: DTK 的头文件包含方式改为了硬编码路径前缀,如:

#include <dtk6/DWidget/DApplication>
#include <dtk6/DCore/DLog>

这破坏了 DTK 原本设计的通过 pkg-config 或 CMake find_package 提供的透明包含路径。如果 DTK6 的目录结构发生变化,或者在不同发行版上安装路径不同,代码将编译失败。
建议: 应该通过 CMake 的 find_packagepkg_check_modules 正确导入 DTK6 的头文件路径,代码中依然使用原生的包含方式:

#include <DApplication>
#include <DLog>

如果是因为 DTK5 和 DTK6 头文件冲突被迫硬编码,建议在 CMake 中通过 target_include_directories 针对性配置,而不是在源码中写死 dtk6/

1.4 拼写错误修正

文件: VideoWidgetTest.cpp
问题: PRIVIEW_ENUM_STATE 被修改为 PREVIEW_ENUM_STATE。这是一个好的修改(修正了原有的拼写错误)。
建议: 确保源代码中 videowidget.h 的枚举定义也已同步修改为 PREVIEW_ENUM_STATE,否则编译会报错。

1.5 QWheelEvent 构造函数适配

文件: TakePhotoSettingTest.cpp
问题: Qt6 中 QWheelEvent 的构造函数签名发生了变化,修改后代码如下:

QWheelEvent wheelEvent(QPointF(p), QPointF(slider->mapToGlobal(p)), QPoint(0, 40), QPoint(0, 40), Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin, false);

建议: 逻辑正确,但注意 QPoint(0, 40) 代表 pixelDelta 和 angleDelta。通常鼠标滚轮的角度增量是 120 的倍数(即 8 度的倍数),这里用 40 测试虽然可以,但如果测试期望触发特定的滚动步长,需确认 40 是否符合业务逻辑预期。

2. 代码质量

2.1 宏定义控制单元测试逻辑(代码坏味道)

文件: windowstatethread.cpp
问题: 在生产代码中使用 #ifdef UNITTEST 来打断正常业务逻辑:

while (!isInterruptionRequested()) {
#ifdef UNITTEST
    break;
#endif
    auto list = workspaceWindows();
    // ...

这违反了“生产代码不应感知测试代码”的原则。如果 workspaceWindows() 在多线程中存在安全问题,应该通过设计来解决(如依赖注入、接口隔离),而不是用宏来跳过。
建议:

  1. 临时方案:既然 UNITTEST 宏已经定义,目前的修改把 break 移到循环最前面,比原来放在 sleep 之后要好,至少避免了无意义的休眠。
  2. 长期方案:重构 windowStateThread,将获取窗口的逻辑抽象为接口,在单测中 Mock 该接口,从而避免在生产代码中植入测试宏。

2.2 Qt 版本兼容宏的统一管理

文件: 多个测试文件
问题: 代码中大量出现 #if QT_VERSION_MAJOR <= 5#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0)
建议: 建议在项目公共头文件中统一定义项目级别的宏,例如 #ifdef USE_QT6,而不是在每个文件中重复写 Qt 版本判断。这样可以减少未来升级或回退时的修改量,提高代码可读性。

3. 代码性能

3.1 CMake 中链接库的重复与冗余

文件: tests/CMakeLists.txt
问题: 在链接库部分,代码显得冗长且重复:

target_link_libraries(${TARGET_NAME} PRIVATE
    ${3rd_lib_LIBRARIES}
    gtest pthread Qt6::Test dl va va-x11 imagevisualresult6
)

target_link_libraries(${TARGET_NAME} PRIVATE
    Qt6::Core Qt6::Gui Qt6::Widgets Qt6::DBus Qt6::Concurrent 
    Qt6::Multimedia Qt6::PrintSupport Qt6::Svg Qt6::SvgWidgets Qt6::OpenGLWidgets
)

target_link_libraries(${TARGET_NAME} PRIVATE
    dtk6core dtk6gui dtk6widget
)

建议:

  1. 合并这三个 target_link_libraries 调用为一个,减少 CMake 解析开销,也使依赖更清晰。
  2. 对于 Qt 模块,既然已经使用了 find_package(Qt6 REQUIRED ${QtModule}),可以直接使用 Qt 提供的 CMake Target(如 Qt6::Core),这比直接写 dtk6core 等更规范,能自动处理传递依赖和编译选项。

4. 代码安全

4.1 Shell 脚本中的命令执行安全

文件: tests/test-prj-running.sh
问题: 修改后的脚本增加了容错:

cp -r /data/source/deepin-camera/jpegtest/*.jpg ~/Pictures/相机/ 2>/dev/null || true

建议:

  1. 2>/dev/null || true 会吞掉所有错误(包括权限拒绝、磁盘满等严重问题)。虽然对于测试脚本来说可以避免中断,但可能导致测试在错误的环境下静默运行并产生误报。
  2. 更安全的做法是:检查目录是否存在,并在复制前确保目标目录存在:
if [ -d "/data/source/deepin-camera/jpegtest" ]; then
    mkdir -p ~/Pictures/相机/ ~/Pictures/Camera/
    cp -r /data/source/deepin-camera/jpegtest/*.jpg ~/Pictures/相机/ || echo "Warning: Failed to copy jpg to ~/Pictures/相机/"
fi

4.2 CMake 中的硬编码系统路径

文件: tests/CMakeLists.txt
问题:

set(PROJECT_INCLUDE
    ...
    /usr/include/libusb-1.0
    ...
)

硬编码 /usr/include/libusb-1.0 是不安全的。在多架构系统(如 Debian 的 /usr/include/x86_64-linux-gnu/libusb-1.0)或自定义安装路径下会找不到头文件。
建议: 应该使用 pkg_check_modules 来查找 libusb-1.0,并使用其变量:

pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
target_include_directories(${TARGET_NAME} PRIVATE ${LIBUSB_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} PRIVATE ${LIBUSB_LIBRARIES})

总结

本次 Diff 的核心目标(Qt6 迁移)已基本达成,对 Qt6 API 变更的修复是正确的。最需要关注的是 DTK 头文件硬编码引入的移植性风险CMake 中硬编码系统路径 的问题,建议优先修复。生产代码中的 #ifdef UNITTEST 属于技术债,建议在后续迭代中通过依赖注入重构。

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 4, 2026

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lzwind, pengfeixx

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@pengfeixx
Copy link
Copy Markdown
Contributor Author

/merge

@deepin-bot deepin-bot Bot merged commit 93320d4 into linuxdeepin:master Jun 4, 2026
22 checks passed
@pengfeixx pengfeixx deleted the fix/unittest-build-and-crash branch June 4, 2026 05:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants