Repository navigation
feat(verification): recognize CTest and GoogleTest suites - #3
RyanZhangK wants to merge 6 commits into
Conversation
C/C++ projects gate on ctest, and each suite binary prints GoogleTest summaries, but testEvidence() only knew npm/pytest/go/cargo/maven. A green C++ receipt therefore carried test_summary.count = null and the stage gate rejected it as "no visible test result". Read both ctest summary forms -- "N% tests passed, M tests failed out of T" and the collapsed clean-run form "100% tests passed out of T" -- plus the GoogleTest "[==========] N tests from K test suites ran." / "[ PASSED ] N tests" lines. Failed, skipped or empty runs still count as zero so they cannot cross the gate. Verified with the real receipts of a CMake project: 192/192 passed now yields count 192 for both ctest and the gtest binary, while a failing summary stays 0.
godv61
left a comment
There was a problem hiding this comment.
感谢贡献!CTest / GoogleTest 的结果识别对 C/C++ 项目很有价值,目前 0.40.0 仍有这个支持缺口。
近期 main 已有较多流程和验证逻辑调整,这个分支目前存在冲突。建议直接更新本 PR,无需为同一功能重新提 Issue。合并前请先处理以下事项:
- 同步最新 main 并解决冲突,保留当前 Go JSON、unittest 等运行器的证据要求。
- CTest 不能只取汇总中的总测试数。请补充全部跳过、部分跳过和空套件的用例,保证“全部跳过”不会成为非零通过证据。我用包含
Skipped的解析样本复核时,当前实现仍返回了count: 1。 - GoogleTest 目前仅凭输出标记识别,不限制实际命令。解析样本中,普通
echo打印相同标记也会返回count: 1。请约束非测试命令,并补充完整汇总、失败和跳过的边界测试。 - 请覆盖 Windows 带空格且带引号的路径,例如
"C:\Program Files\CMake\bin\ctest.exe" --test-dir build,当前匹配方式无法识别。 - 补充真实 CTest / GoogleTest 运行的冒烟验证,并运行当前完整回归及 Git hook 一致性检查;同时更新生成的 hook(如构建产生变化)。
以上结论来自补丁阅读和解析样本复核,尚未复跑描述中的完整 192 用例工程。修订并通过 CI 后再评估合并。本 PR 先保持开放,欢迎继续更新。
Resolve the conflicts in the verification tests, README and development docs against 0.40.0, keeping the Go JSON, unittest and Gradle evidence requirements from main, then rework the CTest/GoogleTest evidence as requested in review: - CTest counts only cases that actually passed. A failed run reports 0, skips are subtracted from the summary and an all-skipped or empty suite reports 0, so "N% tests passed" alone is never passing evidence. - GoogleTest needs a real runner invocation and a complete summary. echo, cat, sh -c, python -c style printers and other known runners (npm, pytest, go, maven, ...) can no longer forge a passing count. - Quoted Windows paths such as "C:\Program Files\CMake\bin\ctest.exe" are recognized as ctest. - Add table-driven boundary cases, real CTest and GoogleTest smoke runs, and refresh the generated commit-msg hook.
|
已按上轮五点意见重做,分支已 rebase 到最新 main 之上(merge commit),冲突文件全部按 main 版本重写后重新实现:
细节与实测数据见 PR 描述。麻烦复审,谢谢! |
godv61
left a comment
There was a problem hiding this comment.
感谢更新,这次已经复核到提交 160cba7d3e660cfd443fac3e3088c197b5b1f0e6。CTest / GoogleTest 支持的方向认可;同步 main、保留现有运行器判定和更新生成的 hook 都已核对,真实 CTest 的全部跳过、全部禁用、部分跳过计数也符合预期。
本次实际验证:
npm run typecheck、npm run build、hook 一致性检查通过,重建后的 hook 与提交内容一致。- 完整
npm test为 426 通过、0 失败、9 跳过。跳过项包含新增 CTest / GoogleTest 真实冒烟,因此这个结果不能单独证明新增运行器已实机验证通过。 - 明确提供本机已安装的 CMake/CTest 路径后,Windows 下的 CTest 冒烟失败;临时副本仅添加
-C Debug后通过。 - 实际运行
cmd /d /c type old-results.txt和 PowerShellGet-Content,只读取旧 GoogleTest 日志、未执行测试,却都得到count=5,且回执门禁接受;相同输入在 main 基线上为count=null。
仍有两项需要修正,具体复现和位置见行内评论:
- P1:外壳读取旧日志仍被认作本次 GoogleTest 证据。 这会新增零测试误放行路径,需修复并补充回执门禁级回归。
- P2:CTest 冒烟未处理多配置生成器。 Windows 默认 Visual Studio 生成器下缺少
-C,导致测试全部 Not Run。
验证方面,还请至少在一个 CI job 中明确准备 CMake/GTest 并强制执行新增真实冒烟;GoogleTest 测试不要把所有 configure 失败都解释成缺少依赖而 skip,应区分依赖缺失和实际配置错误。本次未实际运行 GoogleTest C++ 二进制,不把解析样本通过写成实机通过。
本 PR 继续保持开放,当前先请求修改。请在修订提交上重新跑完整回归、Windows CTest 冒烟及 hook 一致性检查,提供实际执行、非 skip 的结果后再复审。如果暂时难以明确 GoogleTest 的命令边界,也可以先缩小为 CTest 支持,修复跨平台测试后单独评估。
| const name = commandProgramName(command) | ||
| if (!name) return null | ||
| if (name === 'ctest') return ctestEvidence(output) | ||
| if (outputOnlyCommands.has(name) || runnerCommands.has(name) || skillReceiptProblem(command)) return null |
There was a problem hiding this comment.
[P1] 对外壳内的实际命令执行相同的证据限制。
这里的两个集合只检查顶层程序名。cmd / powershell 不在集合中,skillReceiptProblem 也不拒绝外壳里的 type / Get-Content,所以普通读取旧日志的命令会进入 gtestEvidence。
Windows 上实际复现:创建 old-results.txt,内容如下,然后运行下面任意一条命令:
[==========] 5 tests from 2 test suites ran. (1 ms total)
[ PASSED ] 5 tests.
cmd /d /c type old-results.txt
powershell -NoProfile -Command "Get-Content old-results.txt"两条命令都只读取文件,退出码均为 0;当前 PR 的 testEvidence 为 {count: 5}、receiptHasRequiredTests 为 true、receiptProblems 为 [],verificationPlanProblem 也未拒绝。main 基线 0040b31 对相同命令及真实输出返回 {count: null}。复现范围是共享回执门禁函数,并未在业务任务中执行提交。
若支持外壳包装,应先识别实际执行程序并应用一致的限制;无法明确判断的包装不应获得通过证据。也可先限定为直接执行测试二进制并明确支持范围。请补充 cmd /c type、PowerShell Get-Content、sh -c 'cat ...' 等回归,断言回执门禁也拒绝。这里要求拒绝常见读日志命令,不是要求识别任意恶意二进制。
There was a problem hiding this comment.
已修。ctestOrGtestEvidence 不再取自顶层的第一个词:command-words.ts 的 invokedProgram 会跳过 NAME=value 和 env/nice/timeout 等透明前缀,递归拆开 cmd /c、sh -c、powershell -Command 并记下 shellDepth。GoogleTest 证据改为正向判定(深度 0 + 路径形态 + 不在读取类命令集合 + 不是运行器 + 不是脚本),所以 cmd /d /c type old-results.txt、powershell -NoProfile -Command "Get-Content old-results.txt"、sh -c "cat old-results.txt" 现在都是 null,回执门禁也拒收;外壳命令在 verificationPlanProblem 阶段就被拒绝。这四个形态和 cmd /c ctest …、sh -c "ctest …" 都进了 .verification-test.mjs 的负例表。
CI 双环境回执在下面的总评论里:run 42359142410,两个 cpp-evidence job 都 14 pass / 0 skipped。
| return dir | ||
| } | ||
| const run = dir => { | ||
| const result = spawnSync(ctest, ['--test-dir', dir, '--output-on-failure'], { encoding: 'utf8' }) |
There was a problem hiding this comment.
[P2] 为 CTest fixture 明确生成器或构建配置。
上面的 cmake -S ... -B ... 未固定生成器,Windows 默认使用 Visual Studio 时会生成多配置项目;此处未传 -C,测试不能运行。
用本机 Visual Studio Build Tools 随附的 CTest 3.31.6-msvc6,通过 CMAKE_BINARY / CTEST_BINARY 指向实际工具后运行本测试,得到:
***Not Run
Test not available without configuration. (Missing "-C <config>"?)
0% tests passed, 2 tests failed out of 2
CTest 退出码为 8,随后第 164 行失败。在临时副本中仅把参数改为 ['--test-dir', dir, '-C', 'Debug', '--output-on-failure'],整个真实 CTest 冒烟即通过,覆盖混合、全跳过和失败场景。
请显式选择可用的单配置生成器,或指定构建配置,并在 Windows CI 上实际执行这条冒烟。默认 PATH 找不到 CMake 而 skip 的绿色结果无法覆盖该问题。
There was a problem hiding this comment.
已修。fixture 现在从 CMakeCache.txt 里的 CMAKE_CONFIGURATION_TYPES 判断多配置:多配置时 ctest -C Debug、cmake --build --config Debug,二进制按 build/Debug/*.exe 定位;生成器/工具链可用 CMAKE_GENERATOR、CMAKE_TOOLCHAIN_FILE 注入,不固定生成器。同时 REQUIRE_CPP_EVIDENCE=1 时工具缺失直接失败,configure 失败只有确实缺 GTest/编译器才 skip,Windows 的无条件 skip 已删。
CI 新增 cpp-evidence 矩阵:ubuntu-latest 用 Ninja(单配置),windows-latest 故意走默认 Visual Studio 生成器(多配置),两边都带 REQUIRE_CPP_EVIDENCE=1 真跑,run 42359142410 全绿。
CTest and GoogleTest evidence was attached to any command whose text merely contained the markers, and to shell wrappers that only read an old log: cmd /d /c type old-results.txt -> count 5 powershell -Command "Get-Content old" -> count 5 sh -c "cat old-results.txt" -> count 5 node fake.mjs npm test -> count 5 main returned null for all four, so the branch accepted receipts the base branch rejected. - command-words.ts: add `invokedProgram`, which resolves the program that actually runs, skipping NAME=value assignments and the transparent prefixes env/nice/timeout/nohup/command/exec/stdbuf, and recursing into cmd /c, sh -c and powershell -Command bodies with a shell depth. - verification-tests.ts: GoogleTest evidence now needs a positive signal -- depth 0, a path-like program, not a reader (type, cat, Get-Content, ...), not a runner, and not a script file. Maven, Gradle, npm/yarn/pnpm, pytest and cargo evidence is anchored the same way instead of substring-matching the whole command line. Shell wrappers are rejected while the plan is checked, so the failure surfaces before the command runs. - .verification-test.mjs: cover the four wrappers, the reader commands, wrapper-wrapped ctest and the forged summaries from a real execution.
The previous smoke test skipped whenever a tool was missing and pinned no generator, so it proved nothing and failed on a multi-config default: - REQUIRE_CPP_EVIDENCE=1 turns a missing toolchain into a failure. - The generator and toolchain file come from CMAKE_GENERATOR and CMAKE_TOOLCHAIN_FILE, and the smoke test asks for `-C Debug` / `--config Debug` only when the cache lists CMAKE_CONFIGURATION_TYPES. - A configure failure is only skipped when GTest or a C++ compiler is really missing; anything else fails. The unconditional Windows skip is gone. New cpp-evidence job: ubuntu-latest with Ninja and libgtest-dev, and windows-latest with the default Visual Studio generator plus vcpkg GTest, which is exactly the multi-config case that used to report every test as "***Not Run".
The GitHub runners ship CMake without libgtest-dev, so configure stops in CMake's FindGTest module with "Could NOT find GTest (missing: ...)" instead of the package-configuration message. Only that wording skipped, so the whole verify job failed on an environment that legitimately lacks the package.
|
两条行内问题都已在 P1 外壳里的命令绕过了限制根因是 改法是换成正向识别: P2 CTest fixture 在 Windows 多配置下必挂根因是 fixture 既不固定生成器也不用 另外按你说的把 skip 收紧: CI 回执(真实 Windows + Linux)新增 job
Run:https://github.com/RyanZhangK/dsh-task-engine/actions/runs/42359142410(head
两个 cpp-evidence job 都输出 中间还有一次失败值得记一笔: 本地回执
文档同步在 如果还想把范围先缩到只支持 CTest,我可以把 GoogleTest 那条正向识别拆成独立 commit 再删掉——现在两条都在同一支上,分开也好回退。 |
问题
testEvidence()只识别 npm/pytest/go/cargo/maven 等运行器。C/C++ 项目(CMake 工程)的两种常见回执——ctest摘要和 GoogleTest 二进制输出——都解析不出来,test_summary.count恒为null,dev_task verify会以「没有可见的测试结果」拒绝,即使退出码为 0、全部用例通过。真实复现(未打补丁的 0.34.0,CMake 工程 192 个用例):
调用方只能退回
verify: ["true"]之类毫无意义的命令,测试门禁形同虚设。改动(已合并 main,按 review 重做)
分支已 merge
main(0.40.0),src/verification-tests.ts、.verification-test.mjs、README.md、docs/development.md的冲突按 main 版本重写,再在 main 的代码结构上重新实现 CTest/GoogleTest,Go JSON、unittest、Gradle 等既有证据要求完整保留。针对上轮 review 的五点:
testEvidence()为基底,新增分支插在 unittest 之后;Go-json、unittest 完整摘要、Gradle JUnit XML 的判定逻辑未改动。M tests failed非零记 0;逐行***Skipped的用例从总数中扣除(真实 ctest 在有跳过时仍打印100% tests passed out of T);全部跳过、out of 0、No tests were found!!!一律记 0。复核样本中的count: 1来自旧实现只取T,现已修正为0。echo/printf/cat/sh -c/python -c等打印器与已知其它运行器(npm、pytest、go、maven、cargo…)直接返回null;输出侧要求完整汇总[==========] N tests from M test suites ran.、[ PASSED ] N tests,出现[ FAILED ]或整个套件全部跳过记 0,空套件记 0。commandWords()+commandName()已能把"C:\Program Files\CMake\bin\ctest.exe" --test-dir build解析为ctest,并有用例覆盖。hooks/commit-msg并同步.hook-consistency.mjs。验证
npm run typecheck(server + client)通过;npm run build通过。npm test:426 通过、0 失败(含.verification-test.mjs12 个用例:23 条表驱动边界 + 真实 CTest/GoogleTest 冒烟)。真实输出冒烟(本机 CTest 3.x / GoogleTest 1.18):
count100% tests passed out of 2+***Skipped100% tests passed out of 1+***Skipped0% tests passed, 1 tests failed out of 1GTEST_SKIP3 tests … ran./[ PASSED ] 2 tests.[ PASSED ] 0 tests.+[ SKIPPED ]实测确认 GoogleTest 的
[ PASSED ]计数已排除 skipped 用例,因此不再二次扣减。hooks/commit-msg已按新源码重建,.hook-consistency.mjs通过。