テスト
Grephは、次の3層のテストで検証されます。
- ユニットテスト:パーサー、ウォーカー、コーデック、オプションなど、個別コンポーネントを対象にします。
- オラクル回帰コーパス:固定されたシナリオセットで、Grephの出力を正規の
grep、ripgrep、ast-grepバイナリと比較します。 - プローブ駆動の機能マトリクス:
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つのコマンドを実行します。
- オラクル:
grep、ripgrep、またはast-grepをシナリオコーパスに対して実行し、出力を取得します。 - 実際の出力:同じコーパスに対してGrephを実行し、出力を取得します。
- 比較ツール:行ごと、または意味上の等価性を確認する構造化差分を作成します。
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としても書き出します。「現在のブランチはリリース可能か」を確認する場合に実行するコマンドです。
テスト駆動開発のワークフロー
機能を追加する場合:
- 新しい動作を検証するコーパスとフラグを含むシナリオディレクトリを作成します。
./bin/oracle <scenario>を実行し、正規ツールの出力を取得します。src/に機能を実装します。./bin/test-scenario <scenario>を実行し、Grephがオラクルと一致することを確認します。./bin/test-regression --fastを実行し、ほかに回帰がないことを確認します。- コミット前に
composer verifyを実行します。
バグを修正する場合:
- 失敗する入力をシナリオとして記録します。
- オラクルが期待どおりの出力を返すことを確認します。
- Grephがその出力を返さないことを確認します。
- バグを修正します。
- Grephがオラクルと一致するようになったことを確認します。
composer verifyを実行します。
シナリオはコーパスに永久に残るため、composer test:oracle(およびcomposer verify)が失敗しない限り、バグが再発することはありません。