测试
Greph 通过三层测试进行验证:
- 单元测试:针对独立组件(解析器、遍历器、编码器、选项)的测试。
- 预期结果回归语料:将 Greph 的输出与标准
grep、ripgrep和ast-grep二进制文件在固定场景集上的输出进行比较。 - 探测驱动的功能矩阵:验证
rg和sg包装器的已验证功能范围。
每次推送到 main 以及每个拉取请求(.github/workflows/ci.yml)都会触发 CI。CI 会运行代码规范检查(composer cs)、静态分析(composer analyse)、PHPUnit 单元和集成测试套件(composer test),并在 PHP 8.4 上运行 composer audit。预期结果语料(composer test:oracle)不属于 CI 流程;功能矩阵需要通过 php bin/feature-matrix 手动重新生成。PHPUnit 测试套件包含一项测试,会在上游 rg 和 sg 标记为不可用时生成矩阵并检查报告结构,因此单项探测回归不会导致测试失败。
从克隆目录开始
本页所有内容都需要在仓库克隆目录中操作。由于 0.2.3,Composer 包仅包含 src/ 和四个运行时可执行文件;tests/、scenarios/、benchmarks/ 以及 bin/ 中的开发脚本均未包含在其中。
git clone https://github.com/inline0/greph
cd greph
composer install
运行测试
# PHPUnit unit and integration suites
composer test
# Oracle regression corpus
composer test:oracle
# Static analysis
composer analyse
# Coding standards
composer cs
composer cs:fix
# Full release-grade verification (analyse + cs + test + test:oracle)
composer verify
composer verify 是每次发布的门槛。若未通过,变更就还没有完成。
预期结果模型
Greph 遵循由预期结果驱动的验证模型。每个场景都会运行三条命令:
- 预期结果:运行
grep、ripgrep或ast-grep,并针对场景语料捕获输出。 - 实际结果:运行 Greph,并针对相同语料捕获输出。
- 比较器:通过结构化差异检查逐行或语义等价性。
如果 Greph 与预期结果不一致,那么 Greph 就是错误的。如果 grep 和 rg 彼此不一致,场景会在 oracle_disagreement 中记录这一分歧,注明 Greph 在 greph_follows 中遵循的工具,并将与另一工具的比较设为 skip。语料中涵盖了这两种情况。
文本场景会与 grep 和 rg 比较,AST 和重写场景则与 sg 比较。预期结果输出只捕获一次,并提交到每个场景的 oracle/ 目录中,因此正常运行只需要 PHP;只有在捕获或刷新预期结果输出时才需要外部工具。
实现位于 tests/Oracle/ 中,场景位于 scenarios/text/、scenarios/ast/、scenarios/rewrite/ 和 scenarios/edge/ 中。
场景布局
每个场景都是一个独立的目录:
scenarios/text/literal-simple/
├── scenario.json # name, category, pattern, flags, path
├── setup/ # corpus to search through
├── oracle/ # captured oracle output (grep.txt, rg.txt, rg.json, ...)
├── actual/ # captured greph output (generated, git-ignored)
└── reports/ # comparison results (generated, git-ignored)
scenario.json 声明模式、标志和搜索路径。可选的 expectations 对象可为每个预期结果(exact、semantic 或 skip)设置比较模式;若未设置,文本场景会对 grep 和 rg 进行精确比较,并对 rg JSON 进行语义比较;AST 和重写场景则与 sg 比较。
运行单个场景
仓库提供了一组小型 CLI,用于处理单个场景。它们是开发工具,而非运行时入口:这些工具与运行时二进制文件一同位于 bin/ 中,但不属于 Composer 包。每个工具都接受一个相对于 scenarios/ 的场景名称。
# Capture oracle output for a scenario (needs grep and rg, or sg)
./bin/oracle text/literal-simple
# Run greph against a scenario, capture its output
./bin/actual text/literal-simple
# Diff oracle vs actual
./bin/compare text/literal-simple
# Full pipeline: oracle (only if missing) -> actual -> compare
./bin/test-scenario text/literal-simple
# Recapture the oracle output first
./bin/test-scenario text/literal-simple --refresh
运行完整回归测试套件
# All scenarios (the same as composer test:oracle)
./bin/test-regression
# Filter by category
./bin/test-regression --category text
./bin/test-regression --category ast
./bin/test-regression --category rewrite
./bin/test-regression --category edge
# Print only failures and the summary
./bin/test-regression --fast
# Recapture every oracle before comparing
./bin/test-regression --refresh
场景始终一次运行一个。--jobs N 会被接受并显示在摘要行中,但不会并行运行任何内容(#7)。在全新克隆中,text/no-ignore 和 text/explicit-file-input 会失败,因为它们位于 setup/vendor/ 下的测试夹具文件未提交(#6)。
回归测试套件是新行为的准入门槛。新增标志、新边缘情况或新错误修复,都需要一个场景来记录针对预期结果的行为。
合规性报告
./bin/verify-compliance
verify-compliance 本身不会运行任何内容。它会读取上一次场景运行留下的 oracle、实际结果和报告文件,并打印哪些场景通过、哪些失败,以及哪些尚无报告。请先运行 ./bin/test-regression。--output report.json 还会将报告写入 JSON。当你想知道“当前分支是否已准备好发布”时,应该运行此命令。
测试驱动开发工作流
添加功能时:
- 编写一个场景目录,其中包含用于测试新行为的语料库和标志。
- 运行
./bin/oracle <scenario>,捕获规范工具的输出。 - 在
src/中实现该功能。 - 运行
./bin/test-scenario <scenario>,验证 Greph 是否与 oracle 相符。 - 运行
./bin/test-regression --fast,确保其他内容没有发生回归。 - 在提交前运行
composer verify。
修复错误时:
- 将导致失败的输入记录为一个场景。
- 确认 oracle 产生预期输出。
- 确认 Greph 不会产生预期输出。
- 修复错误。
- 确认 Greph 现在与 oracle 相符。
- 运行
composer verify。
该场景会永久保留在语料库中,因此除非 composer test:oracle(以及 composer verify)失败,否则这个错误不会再次出现。