ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

V 语言测试体系全解:从 `v test-all` 到编译器各阶段测试运行器的实现剖析

V 语言测试体系全解:从 `v test-all` 到编译器各阶段测试运行器的实现剖析 V 语言测试体系全解从v test-all到编译器各阶段测试运行器的实现剖析【免费下载链接】vSimple, fast, safe, compiled language for developing maintainable software. Compiles itself in 1s with zero library dependencies. Supports automatic C V translation. https://vlang.io项目地址: https://gitcode.com/GitHub_Trending/v/v本文以 V 语言仓库根目录的 TESTS.md 为主体系统讲解 V 的自动化测试体系v test-all的完整检查链、_test.v单元测试的批量执行与并发控制、inout 输出比对、C 代码生成断言、REPL 脚本回放、known_errors 负向测试等运行器的工作原理。读完后你可以在本地以与 CI 相同的方式验证改动并能用VAUTOFIX、VTEST_ONLY、VJOBS等环境变量精准地定位和修复各类测试。提交前第一件事v test-allTESTS.md 开篇的 TLDR 只有一句话在完成改动之后、提交 PR 之前在本地运行v test-all。这是验证CI 大概率会通过的最可靠方式——它最慢但也最全面。文档同时给出一条提速建议编译测试时使用v -cc tcc因为 TCC 比 clang/gcc/msvc 等大多数 C 编译器快得多。原因在于大多数测试命令会调用 V 编译器和 V 工具很多次动辄数百甚至上千次C 编译器的速度差异会被成倍放大。v test-all实际执行的检查链v test-all按顺序运行以下命令v test-cleancodev test-selfv test-fmtv build-toolsv build-examplesv check-md -hide-warnings .v install nedpals.args从源码结构看该命令由 cmd/tools/vtest-all.v 实现。get_all_commands() 函数返回一个Command列表除了上述 7 条核心命令外还包含一批编译器自验证检查例如编译 examples/hello_world.v含-W -Wimpure-v严格模式、-profile模式、JS 后端-b js、-o -输出生成源码等变体v -o vtmp cmd/v系列以默认、-cstrict、-autofree、-prealloc、-new-transformer等多种模式编译 V 自身-shared编译 examples/dynamic_library_loader 下的共享库并在 Linux 上交叉编译 Windows.dllLinux/macOS 下将cmd/v输出为v.c后用cc -Werror -stdc99重新编译断言生成的 C 代码无警告运行 examples/veb/todo/main.v 等真实项目验证 Web 框架路径Linux 上用prlimit限制虚拟内存验证 STBI 加载图片 1000 次不泄漏GC 开启时占用 10MB。每条Command支持expect输出全等、starts_with/ends_with/contains输出匹配、before_cb/after_cb前置/后置回调、rmfile测试后清理产物等字段失败时会打印期望值与实际输出的对比。main() 逐条执行后汇总OK/Failed列表只要有失败项就以退出码 1 结束。此外该实现支持-new-compiler严格 V3 模式标记为v3_compatible: false的检查会被跳过部分命令还会替换为v3_line变体——这说明测试链本身也在跟随编译器演进做条件化裁剪。test-all同样是 Makefile 流程的一部分Makefile 中存在./v test-all调用供 CI 构建流程复用。_test.vV 的标准测试文件所有test_前缀的函数都会由 V 的测试框架自动运行。单文件执行与批量执行方式如下# 逐个运行执行 file_test.v 中的所有 test_ 函数 # 全部断言通过时退出码为 0 v file_test.v # 附带每个 test_ 函数的耗时统计 v -stats file_test.v# 递归运行 folder 下所有 _test.v 文件并行度取决于核心数 v test folder # 同上但输出每个 test_ 函数的计时报告 v -stats test folder并发工作数的自动预算TESTS.md 说明默认v test最多使用 4 个并行 worker且每个 worker 预算 8 GiB 内存在 Linux 上取物理内存与活动 cgroup 内存限制中的较小者。可用VJOBS环境变量显式覆盖 worker 数。这一点在 cmd/tools/modules/testing/common.v 中有精确实现// 常量定义common.v 第 81-84 行 // 每个 worker 编译一个独立测试程序因此用保守的内存预算来约束自动并行度 // VJOBS 仍是显式覆盖手段 const test_job_memory_budget u64(8) * 1024 * 1024 * 1024 // 8 GiB / worker const max_automatic_test_jobs 4automatic_test_jobs() 的决策逻辑是若VJOBS设为正数则直接采用否则取CPU 核数与总内存 ÷ 8 GiB下限 1的较小值再与上限 4 取小。Linux 下 cgroup 限制的读取通过 cgroup_memory_limit_from_contents() 完成它解析/sys/fs/cgroup/cgroup与/proc/self/mountinfo同时支持 cgroup v1 的memory.limit_in_bytes和 cgroup v2 的memory.max保证在容器环境中不会因宿主机内存大而开过多的 worker。该文件还集中定义了测试框架的一组环境变量可作为官方支持的调试开关环境变量作用VJOBS显式指定并行 worker 数正整数生效VTEST_HIDE_OK设为1时只打印汇总统计与失败项CI 环境默认开启VTEST_HIDE_OK0可关闭VTEST_ONLY逗号分隔的路径过滤器只运行匹配的用例VTEST_ONLY_FN按test_函数名过滤VTEST_FAIL_FAST设为1时失败立即停止VTEST_MAX_COMPILATION_RETRIES编译失败时的最大重试次数默认 3VAUTOFIX设为1时让输出比对类测试录制新期望值而非失败编译器功能测试v test vlib/v/tests该目录下的_test.v文件针对 V 编译器本身的不同功能编写。每个文件都会被编译其中的功能行为由断言验证——即编译器必须能正确产出并执行这些代码。inout 测试运行器v vlib/v/slow_tests/inout/compiler_test.v这是一个输出比对运行器检查运行某 V 程序的输出是否与期望的.out文件一致。它同样支持期望 panic的场景——把panic()输出的开头部分粘贴到对应的.out文件即可。约定在vlib/v/slow_tests/inout目录下.vv与.out成对出现。运行器逐个编译执行.vv文件并校验其输出与同名.out文件内容一致。这对检查错误和 panic 是否正确打印尤其有用因为编译器错误信息本身也是被测对象。C 代码生成断言v vlib/v/gen/c/coutput_test.vcoutput_test.v是另一个运行器检查生成的 C 源码是否满足vlib/v/gen/c/testdata/目录下所有*.c.must_have文件中的期望每个.c.must_have文件必须有对应的.vv文件.c.must_have的每一行应当至少出现一次在.vv文件以-o -编译时的输出中。这意味着它可以精确断言cgen 必须生成某个函数调用 / 宏 / 结构体字段是 V 作为V → C 转译器架构下验证代码生成正确性的关键手段。REPL 测试.repl脚本回放运行器为vlib/v/slow_tests/repl/repl_test.v测试用例是vlib/v/slow_tests/repl/下的.repl文件。每个.repl文件包含若干行输入到 V REPL 的内容后跟一行output分隔符再接 REPL 正常应显示的输出行——本质上是对 REPL 会话的输入/输出录制回放。如果你修改了编译器或 REPL 源码导致这些文件断掉可以运行VAUTOFIX1 ./vlib/v/slow_tests/repl/repl_test.v多次用VAUTOFIX1模式替换文件中的当前输出直到全部修复且测试通过为止。整项目文件夹测试v vlib/v/slow_tests/run_project_folders_test.v该运行器检查完整的项目文件夹能否编译并运行。约束每个项目必须以退出码 0 结束且其 stdout 的最后一行必须是OK。负向测试v vlib/v/tests/known_errors/known_errors_test.v这个运行器验证已知会失败的程序是否仍然失败负向程序收集在vlib/v/tests/known_errors/testdata/目录下每个程序都应当因为某个已知/已确认的编译器 bug 或限制checker、parser 或 cgen而编译失败。其设计意图值得注意这些样本记录的是当前不能编译、但未来编译器改进后能编译的程序用来自我追踪是否被某个不相关的改动顺手修复了。例如一段会触发非法 C 代码生成的代码可以放在这里日后 bug 修复时把它移出vlib/v/tests/known_errors/testdata/目录转成正规的_test.v或.vv/.out配对即可。构建类检查tools、examples 与 V 自身v build-tools—— 编译cmd/tools下所有工具v build-examples—— 编译 examples/ 下的所有示例项目v build-vbinaries—— 编译 V 的各个二进制变体。这三者对应test-all链条中的真实 V 程序构建层语言特性测试证明功能对构建测试证明生态里的真实代码还能被编译。格式化测试vlib/v/fmt 与v fmt在vlib/v/fmt/下v vlib/v/fmt/fmt_test.v—— 检查.out格式比对测试v vlib/v/fmt/fmt_keep_test.v—— 验证vlib/v/fmt/tests/下所有_keep.vv文件经v fmt -w处理后保持不变即格式化器输出是幂等稳定的格式化过一次后再次格式化不应再产生变化v vlib/v/fmt/fmt_vlib_test.v—— 检查所有 V 源文件是否已格式化并打印汇总非必需项v test-cleancode—— 检查绝大多数.v文件对v fmt不变v test-fmt—— 测试当前目录下所有.v文件是否已格式化适合加入 CI保证后续贡献不破坏既有代码风格。Markdown 文档检查v check-md -hide-warnings .确保项目内所有.md文件格式正确且其中的 V 代码块示例也能被编译/格式化。若发现格式错误可用以下方式修复VAUTOFIX1 ./v check-md file.md # 或 v check-md -fix file.mdv test-self与编译器阶段测试v test-self运行vlib模块测试包括编译器测试是test-all中最重的环节。其中v vlib/v/compiler_errors_test.v专门驱动三个编译器阶段的错误用例vlib/v/scanner/tests/*.vvvlib/v/checker/tests/*.vvvlib/v/parser/tests/*.vv特殊目录会带特定选项编译vlib/v/checker/tests/globals_run/用-enable-globals run运行结果存到与.vv同名的.run.out文件。实用技巧均可直接复制使用批量更新.out期望文件连续运行两次VAUTOFIX1 ./v vlib/v/compiler_errors_test.v。第一次会失败但会为每个.vv录制新输出并写入对应.out第二次应当成功此时你可以检查差异并提交新的.out文件几乎不需要手工编辑。只跑部分用例VTEST_ONLYmismatch ./v vlib/v/compiler_errors_test.v只检查路径匹配过滤条件的.vv文件。静默成功输出VTEST_HIDE_OK1 ./v test vlib/math/只打印汇总统计和失败项适合成百上千个_test.v文件时避免刷屏见上文 common.v 中的实现CI 环境默认开启该行为可用VTEST_HIDE_OK0关闭。只显示当前运行的测试./v -progress test vlib/math/。该模式下无论有多少_test.v文件输出行数都保持有限且仍包含汇总统计和失败测试的输出。CI 集成TESTS.md 说明主仓库的 CI 使用 GitHub Actions 配置文件.github/workflows/ci.yml运行各类检查例如v vet vlib/v—— 风格检查器v test-self在多种编译模式下执行自测试。本仓库同时维护着一套平台化的 CI 脚本目录 ci/linux_ci.vsh、macos_ci.vsh、freebsd_ci.vsh、openbsd_ci.vsh及qemu_linux_tests.sh供各平台的本地/CI 流程调用与根目录Makefile中的./v test-all调用共同构成完整的持续验证入口。此外文档特别提醒VDOC 测试vdoc_file_test.v也支持VAUTOFIX。当你修改了 cmd/tools/vdoc 内部或它依赖的模块如 markdown后把下面命令运行2 次并连同cmd/tools/vdoc/testdata里的变化一起提交VAUTOFIX1 ./v cmd/tools/vdoc/vdoc_file_test.v小结一套分层、可回放的测试体系V 的测试体系可以概括为四个层次且每一层都有对应的期望值文件 VAUTOFIX 回放机制来应对编译器演进语言特性层——_test.v断言测试v test/v test-self并发度由 common.v 的内存预算算法自动决定输出/生成层——inout.vv/.out比对、coutput_test.v的.c.must_have断言、compiler_errors_test.v的阶段错误用例验证错误信息和生成的 C 代码本身交互层——.repl会话回放与整项目文件夹运行工程层——build-tools/build-examples/v vet/check-md/test-fmt保证生态示例、工具链与代码风格不腐化而known_errors则把已知的坏也纳入回归管理。对贡献者而言日常工作流就是本地改完代码跑v test-all配合v -cc tcc提速定位问题用VTEST_ONLY过滤 -progress收敛输出期望值漂移用VAUTOFIX1双次运行录制后再人工审查 diff。【免费下载链接】vSimple, fast, safe, compiled language for developing maintainable software. Compiles itself in 1s with zero library dependencies. Supports automatic C V translation. https://vlang.io项目地址: https://gitcode.com/GitHub_Trending/v/v创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进