跳转到正文

测试

Greph 通过三层测试进行验证:

  1. 单元测试:针对独立组件(解析器、遍历器、编码器、选项)的测试。
  2. 预期结果回归语料:将 Greph 的输出与标准 grep、ripgrep 和 ast-grep 二进制文件在固定场景集上的输出进行比较。
  3. 探测驱动的功能矩阵:验证 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 遵循由预期结果驱动的验证模型。每个场景都会运行三条命令:

  1. 预期结果:运行 grep、ripgrep 或 ast-grep,并针对场景语料捕获输出。
  2. 实际结果:运行 Greph,并针对相同语料捕获输出。
  3. 比较器:通过结构化差异检查逐行或语义等价性。

如果 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。当你想知道“当前分支是否已准备好发布”时,应该运行此命令。

测试驱动开发工作流

添加功能时:

  1. 编写一个场景目录,其中包含用于测试新行为的语料库和标志。
  2. 运行 ./bin/oracle <scenario>,捕获规范工具的输出。
  3. 在 src/ 中实现该功能。
  4. 运行 ./bin/test-scenario <scenario>,验证 Greph 是否与 oracle 相符。
  5. 运行 ./bin/test-regression --fast,确保其他内容没有发生回归。
  6. 在提交前运行 composer verify。

修复错误时:

  1. 将导致失败的输入记录为一个场景。
  2. 确认 oracle 产生预期输出。
  3. 确认 Greph 不会产生预期输出。
  4. 修复错误。
  5. 确认 Greph 现在与 oracle 相符。
  6. 运行 composer verify。

该场景会永久保留在语料库中,因此除非 composer test:oracle(以及 composer verify)失败,否则这个错误不会再次出现。