コンテンツへスキップ

テスト

Grephは、次の3層のテストで検証されます。

  1. ユニットテスト:パーサー、ウォーカー、コーデック、オプションなど、個別コンポーネントを対象にします。
  2. オラクル回帰コーパス:固定されたシナリオセットで、Grephの出力を正規のgrep、ripgrep、ast-grepバイナリと比較します。
  3. プローブ駆動の機能マトリクス:rgおよびsgラッパーの検証済み機能範囲を確認します。

CIはmainへのプッシュごと、および各プルリクエスト(.github/workflows/ci.yml)で実行されます。PHP 8.4上で、コーディング規約(composer cs)、静的解析(composer analyse)、PHPUnitのユニットテストと統合テスト(composer test)、およびcomposer auditを実行します。オラクルコーパス(composer test:oracle)はCIに含まれず、機能マトリクスはphp bin/feature-matrixで手動生成します。PHPUnitスイートには、上流のrgとsgを利用不可としてマトリクスを生成し、レポートの形式を確認するテストが含まれています。そのため、単一のプローブが失敗してもテストは失敗しません。

クローンから作業する

このページの内容を実行するには、リポジトリのクローンが必要です。0.2.3以降、Composerパッケージに含まれるのはsrc/と4つのランタイム実行ファイルのみです。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ではオラクル駆動の検証モデルを採用しています。各シナリオで、次の3つのコマンドを実行します。

  1. オラクル:grep、ripgrep、またはast-grepをシナリオコーパスに対して実行し、出力を取得します。
  2. 実際の出力:同じコーパスに対してGrephを実行し、出力を取得します。
  3. 比較ツール:行ごと、または意味上の等価性を確認する構造化差分を作成します。

Grephがオラクルと一致しない場合は、Grephに誤りがあります。grepとrgが互いに一致しない場合、シナリオにはoracle_disagreementの下で不一致が記録され、greph_followsでGrephがどちらのツールに従うかが示され、もう一方のツールとの比較結果は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を完全一致で比較し、rgJSONは意味上の等価性を比較します。ASTと書き換えのシナリオはsgと比較します。

単一シナリオの実行

個別のシナリオを扱うための小規模なCLI群があります。これらは開発ツールであり、ランタイムのエントリポイントではありません。bin/内のランタイムバイナリと同じ場所にありますが、Composerパッケージには含まれません。各CLIには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

シナリオは常に1つずつ実行されます。--jobs Nは受け付けられ、サマリー行にも表示されますが、並列実行は行いません(#7)。新しいクローンでは、text/no-ignoreとtext/explicit-file-inputは失敗します。setup/vendor/内のフィクスチャファイルがコミットされていないためです(#6)。

回帰テストスイートは、新しい動作を導入する際のゲートです。新しいフラグ、エッジケース、バグ修正には、オラクルに対する期待動作を記録したシナリオが必要です。

コンプライアンスレポート

シェル
./bin/verify-compliance

verify-compliance自体は何も実行しません。最後にシナリオを実行したときに残されたオラクル、実際の出力、レポートの各ファイルを読み込み、合格したシナリオ、失敗したシナリオ、まだレポートがないシナリオを表示します。先に./bin/test-regressionを実行してください。--output report.jsonはレポートをJSONとしても書き出します。「現在のブランチはリリース可能か」を確認する場合に実行するコマンドです。

テスト駆動開発のワークフロー

機能を追加する場合:

  1. 新しい動作を検証するコーパスとフラグを含むシナリオディレクトリを作成します。
  2. ./bin/oracle <scenario>を実行し、正規ツールの出力を取得します。
  3. src/に機能を実装します。
  4. ./bin/test-scenario <scenario>を実行し、Grephがオラクルと一致することを確認します。
  5. ./bin/test-regression --fastを実行し、ほかに回帰がないことを確認します。
  6. コミット前にcomposer verifyを実行します。

バグを修正する場合:

  1. 失敗する入力をシナリオとして記録します。
  2. オラクルが期待どおりの出力を返すことを確認します。
  3. Grephがその出力を返さないことを確認します。
  4. バグを修正します。
  5. Grephがオラクルと一致するようになったことを確認します。
  6. composer verifyを実行します。

シナリオはコーパスに永久に残るため、composer test:oracle(およびcomposer verify)が失敗しない限り、バグが再発することはありません。