Skip to content

test: add autotests Google Test framework + core/common-module unit tests - #512

Open
add-uos wants to merge 2 commits into
linuxdeepin:masterfrom
add-uos:agent/p2/58cd18e4
Open

test: add autotests Google Test framework + core/common-module unit tests#512
add-uos wants to merge 2 commits into
linuxdeepin:masterfrom
add-uos:agent/p2/58cd18e4

Conversation

@add-uos

@add-uos add-uos commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

deepin-editor 单元测试(autotests/)—— 自动生成首轮

为 deepin-editor 新增独立的 autotests/ Google Test 测试套件(lcov 覆盖率),首轮覆盖核心模块。

框架

  • autotests/CMakeLists.txt:独立 CMake 项目;deepin-editor 无库目标,故将应用源码直接编译进单个 deepin-editor-autotest 可执行文件,按类组织 autotests/<module>/test_<class>.cpp
  • 3rdparty/stub/:内置 stub-ext(不从网络下载)。
  • run-ut.sh:配置 + 编译 + 运行 + lcov + 报告,自动加载可选的 ~/ut-deps 用户级 -dev 前缀以支持无头/CI 复现。
  • report_generator/:HTML/CSV 报告生成器。

首轮覆盖类(全部通过,0 失败 / 0 跳过)

common:UtilsConfigPerformanceMonitorEventlogutilsTextFileSaverFileLoadThreadCSyntaxHighlighterUrlInfo
editor:DeleteTextUndoCommand2MidButtonInsertTextUndoCommandDragInsertTextUndoCommand

结果

  • Google Test 用例:72 个,全部通过(QT_QPA_PLATFORM=offscreen
  • 函数覆盖率(lcov,*/src/*):7.1%(85/1199)——首轮基线
  • 全量 src:1199 函数 / 17338 行,100% 覆盖为多轮持续工程,框架已就绪可增量扩展

复现

./autotests/run-ut.sh
# 报告:build-autotests/test-reports/test_report.html、build-autotests/coverage/html/index.html

说明

  • 仅新增测试代码与 CMake 脚手架,未修改任何用户源码。
  • 基线 commit:eba9ef7c(test: fix 11 failing unit tests ...)。

Summary by Sourcery

Add a standalone Google Test-based autotest framework, including build scripts, stubbing infrastructure, and HTML/CSV reporting, to cover core/common deepin-editor modules and establish a coverage-measured testing baseline.

New Features:

  • Introduce a standalone Google Test-based autotest suite for deepin-editor with lcov coverage integration
  • Add an HTML/CSV report generator and parser pipeline for test and coverage results, including module-level navigation

Build:

  • Add a dedicated autotests CMake project with coverage-friendly build flags and GTest/Qt/DTK/KF6 integration

Tests:

  • Add unit tests for common utilities (Utils, Config, PerformanceMonitor, Eventlogutils, TextFileSaver, FileLoadThread, CSyntaxHighlighter, UrlInfo) and editor undo command classes
  • Integrate a Qt-based test main that configures an offscreen QApplication for headless/CI execution

Chores:

  • Vendor stub-ext and ELFIO-based helper libraries to support function stubbing and symbol lookup in tests

add-uos added 2 commits August 7, 2026 18:03
Introduce a standalone autotests/ test suite (Google Test + gmock, lcov
coverage) for deepin-editor and cover the common module's core classes.

Batch 1 classes (all done, 0 failed, 0 skipped):
- Utils, Config, PerformanceMonitor, Eventlogutils, TextFileSaver,
  FileLoadThread, CSyntaxHighlighter, UrlInfo

Batch statistics:
- Total target classes: 8
- Passed: 8
- Failed: 0
- Skipped: 0
- Google Test cases: 68 (all passing, QT_QPA_PLATFORM=offscreen)
- Function coverage (lcov, */src/*): 6.3% (76/1199) -- baseline

Framework:
- autotests/CMakeLists.txt: standalone project; compiles app sources into
  a single deepin-editor-autotest executable (deepin-editor has no lib
  target), per-class test files under autotests/<module>/test_*.cpp.
- 3rdparty/stub/: built-in stub-ext (no network download).
- run-ut.sh: configure + build + run + lcov + report, sources an optional
  ~/ut-deps user-local -dev prefix for headless/CI reproducibility.
- report_generator/: HTML/CSV report emitter.

Baseline commit:
- eba9ef7
- test: fix 11 failing unit tests for deepin-editor (Qt6/TextFileSaver refactor)
- 2026-08-07
Cover the QPlainTextEdit-based editor undo/redo command classes with
round-trip redo/undo tests, and switch the test harness main() to
QApplication so QWidget-based tests (QPlainTextEdit) run headless.

Batch 2 classes (all done, 0 failed, 0 skipped):
- DeleteTextUndoCommand2, MidButtonInsertTextUndoCommand,
  DragInsertTextUndoCommand

Batch statistics:
- Total target classes: 3
- Passed: 3
- Failed: 0
- Skipped: 0
- Google Test cases added: 4 (72 total, all passing)
- Function coverage (lcov, */src/*): 7.1% (85/1199)

Baseline commit:
- eba9ef7
- test: fix 11 failing unit tests for deepin-editor (Qt6/TextFileSaver refactor)
- 2026-08-07

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @add-uos, your pull request is larger than the review limit of 150000 diff characters

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: add-uos

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

@sourcery-ai

sourcery-ai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a standalone Google Test-based autotest framework for deepin-editor, including build scaffolding, a local stub library, a rich HTML/CSV report generator pipeline, and an initial batch of unit tests for core common/editor modules, all without modifying production source code.

Flow diagram for the new run-ut.sh unit test pipeline

flowchart TD
    A[run-ut.sh] --> B{from_step <= 1?}
    B -->|yes| C[step_1_prepare_build_env]
    C --> D[step_2_configure_cmake]
    D --> E[step_3_compile_tests]
    E --> F[step_4_run_tests<br/>ctest, test_output.log, test_results.xml]
    F --> G[step_5_generate_coverage<br/>lcov, genhtml]
    G --> H[step_6_generate_test_report<br/>python3 generate-report.py]

    B -->|no, from_step=4| F
    B -->|no, from_step=5| G
    B -->|no, from_step=6| H

    H --> I[test_report.html]
    H --> J[test_data.json]
    G --> K[coverage/html/index.html]

    subgraph BuildDir[build-autotests]
        C
        D
        E
        F
        G
    end

    subgraph Reports[test-reports]
        F
        G
        H
        I
        J
    end
Loading

File-Level Changes

Change Details Files
Introduce standalone CMake-based Google Test harness and wiring for deepin-editor autotests, including coverage flags and Qt/DTK/KF dependencies.
  • Create autotests CMake project that compiles application sources plus test sources into a single deepin-editor-autotest executable.
  • Configure Qt/DTK/KF/ICU/chardet/uchardet dependencies mirroring the main project, with coverage instrumentation and -fno-access-control for private-member testing.
  • Wire gtest_discover_tests with headless Qt environment and add a shared Google Test main that bootstraps QApplication in offscreen mode.
autotests/CMakeLists.txt
autotests/test_main.cpp
autotests/cmake/UnitTestUtils.cmake
Vendor and integrate a stub framework (stub-ext and ELFIO) to support function/method interception in tests.
  • Inline ELFIO headers to a single elfio.hpp/elfio_dump.hpp bundle used by the stub implementation.
  • Add generic stub.h implementation that patches function prologues for multiple architectures, plus addr_any/addr_pri helpers for symbol lookup and private access.
  • Add C++ wrapper layer (stub-shadow.* and stubext.h) to bind lambdas to shadow functions and manage wrapper lifetimes for tests.
autotests/3rdparty/stub/elfio.hpp
autotests/3rdparty/stub/stub.h
autotests/3rdparty/stub/addr_any.h
autotests/3rdparty/stub/addr_pri.h
autotests/3rdparty/stub/stub-shadow.h
autotests/3rdparty/stub/stub-shadow.cpp
autotests/3rdparty/stub/stubext.h
Add a Python-based report generation pipeline that parses ctest/gtest and lcov output into HTML and CSV reports with module-level navigation.
  • Implement a main TestReportGenerator that orchestrates parsing test output, coverage info, and build metadata, then emits HTML and JSON (and CSV coverage).
  • Add TestOutputParser and CoverageParser to read ctest logs, gtest XML results, and lcov .info files, and to aggregate coverage per module/file.
  • Add HtmlReportGenerator and CsvReportGenerator with UI helpers to render a Bootstrap-based HTML dashboard, module navigation, and coverage CSV, plus shared file/UI utilities.
  • Wire run-ut.sh to call the Python report generator with detected test/coverage status and support resumable steps via --from-step.
autotests/report_generator/__init__.py
autotests/report_generator/main.py
autotests/report_generator/parsers/__init__.py
autotests/report_generator/parsers/test_parser.py
autotests/report_generator/parsers/coverage_parser.py
autotests/report_generator/generators/__init__.py
autotests/report_generator/generators/html_generator.py
autotests/report_generator/generators/csv_generator.py
autotests/report_generator/utils/__init__.py
autotests/report_generator/utils/file_utils.py
autotests/report_generator/utils/ui_utils.py
autotests/run-ut.sh
Add initial Google Test unit coverage for core common utilities and editor undo commands.
  • Create tests for Utils covering easing functions, region intersection, MD5 hashing, filesystem helpers, encoding detection, system memory info, and key shortcut translation.
  • Add tests for Config, PerformanceMonitor, Eventlogutils, TextFileSaver, FileLoadThread, CSyntaxHighlighter, and UrlInfo to validate constructors, key side-effectful methods, and non-crashing behavior.
  • Add tests for editor undo commands (DeleteTextUndoCommand2, MidButtonInsertTextUndoCommand, DragInsertTextUndoCommand) verifying redo/undo round-trips on QPlainTextEdit content.
autotests/common/test_utils.cpp
autotests/common/test_config.cpp
autotests/common/test_performancemonitor.cpp
autotests/common/test_eventlogutils.cpp
autotests/common/test_textfilesaver.cpp
autotests/common/test_fileloadthread.cpp
autotests/common/test_csyntaxhighlighter.cpp
autotests/common/test_urlinfo.cpp
autotests/editor/test_editor_commands.cpp
autotests/README.md
Extend .gitignore to skip autotest build artifacts and reports (not fully shown in diff).
  • Update .gitignore to exclude build-autotests outputs and coverage/report artifacts to keep the repo clean.
  • Aligns with run-ut.sh output locations for reproducible test runs.
.gitignore

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:60分

■ 【总体评价】

代码为deepin-editor引入了结构完整的Google Test自动化测试框架,但存在跨站脚本注入安全漏洞
逻辑正确且结构清晰,但因HTML报告生成器未转义动态内容导致XSS漏洞,强制限制最高分为60分

■ 【详细分析】

  • 1.语法逻辑(基本正确)✓

测试主入口正确设置了offscreen平台以支持无头CI环境;CMakeLists.txt准确排除了主程序的main.cpp以避免符号冲突;stub库通过mprotect修改内存权限并写入跳转指令实现Hook,底层汇编逻辑正确;测试用例中FileLoadThread使用Qt::DirectConnection避免了跨线程信号槽的死锁问题
潜在问题:addr_any.h中调用regcomp未检查返回值,若传入非法正则表达式可能引发未定义行为
建议:在regcomp调用后增加返回值校验,若编译失败则进行错误处理或直接返回

  • 2.代码质量(良好)✓

代码模块划分清晰,3rdparty、common、editor等目录职责明确;所有文件均包含规范的SPDX版权头;Python报告生成器采用了良好的面向对象设计,解析器与生成器解耦
潜在问题:CMakeLists.txt末尾输出了未定义的变量TEST_SOURCES_COUNT,会打印空字符串;部分Python文件末尾缺少换行符
建议:在CMakeLists.txt中通过list(LENGTH TEST_SRC TEST_SOURCES_COUNT)定义该变量;使用代码格式化工具统一补全Python文件末尾换行符

  • 3.代码性能(无性能问题)✓

ELF符号解析与/proc/self/maps读取仅在Stub初始化时执行一次,无热点路径;Shell脚本通过$(nproc)实现并行编译,最大化利用CI资源;Python报告生成针对小体量XML和文本数据,处理速度极快
建议:无需优化

  • 4.代码安全(存在 2 个安全漏洞(中危1个,低危1个))✕

漏洞对比统计:新增漏洞 2 个,减少漏洞 0 个,持平 0 个
报告生成器在拼接HTML时直接将测试输出、文件路径等外部不可信数据嵌入HTML上下文,未进行实体转义,导致跨站脚本漏洞;底层正则编译缺乏校验可能导致异常

  • 安全漏洞1(【中危】):跨站脚本攻击(XSS)在 autotests/report_generator/generators/html_generator.py 中,_generate_failed_tests_html函数将fail_detail.get("formatted")直接插入

    标签,_generate_coverage_modules_html函数将module["name"]和file_info["name"]直接插入HTML。若被测项目包含恶意命名的文件(如.cpp)或测试失败信息包含HTML标签,查看报告时将在浏览器中执行恶意脚本 ——非常重要

  • 安全漏洞2(【低危】):正则表达式拒绝服务/崩溃在 autotests/3rdparty/stub/addr_any.h 中,get_lib_pathname_and_baseaddr函数调用regcomp(&pathname_regex, pathname_regex_str.c_str(), 0)后未检查其返回值,若传入语法错误的正则表达式,后续regexec将产生未定义行为导致程序崩溃 ——非常重要

  • 建议:在html_generator.py中引入html模块,对所有动态拼接的变量(如formatted_msg、module["name"]等)使用html.escape()进行转义后再插入HTML模板;在addr_any.h的regcomp调用后增加if(ret != 0) return false;的错误处理逻辑

■ 【改进建议代码示例】

# autotests/report_generator/generators/html_generator.py
import html  # 新增导入

# 在 _generate_failed_tests_html 函数中修复 XSS
# 修改前:
# <pre class="text-danger mb-0" style="font-size: 0.85em; white-space: pre-wrap;">{formatted_msg}</pre>
# 修改后:
                        formatted_msg = fail_detail.get("formatted", "断言失败")
                        escaped_msg = html.escape(formatted_msg) # 转义HTML实体
                        failed_tests_html += f"""
                        <div class="mb-2">
                            <div class="alert alert-light p-2">
                                <small class="text-muted">{fail_detail['type'].replace('_', ' ').title()}</small>
                                <pre class="text-danger mb-0" style="font-size: 0.85em; white-space: pre-wrap;">{escaped_msg}</pre>
                            </div>
                        </div>
                        """

# 在 _generate_coverage_modules_html 函数中修复 XSS
# 修改前:
# <h6 class="mb-0 module-name">{module["name"]}</h6>
# <span class="file-name">{file_name_html}</span>
# 修改后:
            html += f"""
            <div class="module-card card mb-3" id="module-{module_id}">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <div class="d-flex align-items-center">
                        <span class="module-icon me-2">{module_icon}</span>
                        <h6 class="mb-0 module-name">{html.escape(module["name"])}</h6>
                        <span class="badge ms-2 text-muted">{len(module["files"])} 文件</span>
                    </div>
...
                file_name_html = html.escape(file_info['name']) # 确保基础文件名被转义
                
                if file_info.get('coverage_html_path') and os.path.exists(file_info['coverage_html_path']):
                    file_name_html = f'<a href="file://{file_info["coverage_html_path"]}" target="_blank" class="file-link coverage-primary">{html.escape(file_info["name"])}</a>'
// autotests/3rdparty/stub/addr_any.h
// 在 get_lib_pathname_and_baseaddr 函数中修复正则编译未校验问题
    bool get_lib_pathname_and_baseaddr(std::string pathname_regex_str, std::string& name, unsigned long& addr)
    {
        // ... 前置代码 ...
        regex_t   pathname_regex;

        // 修复:增加 regcomp 返回值检查
        int ret = regcomp(&pathname_regex, pathname_regex_str.c_str(), 0);
        if (ret != 0) {
            return false;
        }

        if(NULL == (fp = fopen("/proc/self/maps", "r")))
        {
            regfree(&pathname_regex); // 修复:出错时释放正则对象
            return false;
        }
        // ... 后续代码 ...
        // 注意:在所有 return false 之前需要调用 regfree(&pathname_regex) 防止内存泄漏
    }

@deepin-ci-robot

Copy link
Copy Markdown

@add-uos: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
github-pr-review-ci fbb9cfe link true /test github-pr-review-ci

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

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.

2 participants