
# テストと git オラクル

Pitmasterは正式な`git`バイナリをオラクルとして扱います。`git`がPitmasterの書き込み内容を受け入れ、Pitmasterが`git`の書き込み内容を読み取れれば、動作は正しいと判断できます。テスト基盤はPitmasterリポジトリにあります。Composer パッケージに含まれるのは`src/`と`bin/pitmaster`のみです。以下のすべてを実行するには、`composer install`の後にクローンから実行してください。

## テストスイート

| コマンド | 実行内容 | `git`が必要 |
|---------|--------------|-------------|
| `composer test:unit` | PHPUnit `unit`スイート：独立したコンポーネントテスト | いいえ |
| `composer test:integration` | PHPUnit `integration`スイート：同じリポジトリでPitmasterと`git`を動作させる | はい |
| `composer test:oracle` | `bin/test-regression`：すべてのオラクルシナリオ | はい |
| `composer test` | PHPUnit（両スイート）とオラクル回帰テスト | はい |
| `./bin/verify-all` | `composer verify`：サポートの根拠、上流との差分、証明アーティファクト、ミューテーションのスモークテスト、`composer audit`、PHPStan、コーディング規約、`composer test` | はい |

CI では複数のPHPバージョンでユニットテストを実行し、統合テスト、オラクル回帰テスト（`PITMASTER_TEST_JOBS=4`）、サポート根拠と上流との差分のチェックも行います。

## オラクルシナリオ

各シナリオは`scenarios/<category>/`配下のディレクトリです（合計761件。Pitmaster用に作成したものが156件、他の Git 実装から取り込んだものが605件）。

```
scenarios/diff/diff-add-lines/
  scenario.json   # commands and expectations
  setup.sh        # builds the starting repository
  oracle/         # outputs captured from git
```

`scenario.json`には、`git`と同等のPitmasterで実行するコマンドと、一致すべき内容が記載されています。

```json
{
    "name": "diff-add-lines",
    "category": "diff",
    "operations": ["diff"],
    "oracle_commands": { "diff": "git -c color.ui=never diff" },
    "actual_commands": { "diff": "php \"{{ROOT}}/bin/pitmaster\" diff | perl -pe 's/\\e\\[[0-9;]*m//g'" },
    "expectations": { "exact_match": ["diff"], "fsck_clean": true }
}
```

実行時には、`setup.sh`が構築したリポジトリをコピーし、別々のコピーでオラクルとPitmasterコマンドを実行して、出力、オブジェクト、参照、ログを比較します。さらに`fsck_clean`では、Pitmasterが書き込んだリポジトリを`git fsck`が受け入れることも確認します。オラクルの出力がない場合や更新する場合は`git`から取得し、それ以外の場合はコミット済みの`oracle/`ファイルを使います。

各シナリオが対象とするのは、セットアップで構築されたケースだけです。たとえば diff シナリオでは変更済みファイルを比較するため、[Diff](https://pitmaster.inline0.dev/ja/docs/operations/diff)に記載された新規、削除済み、バイナリファイルの diff 出力の違いは検出されません。

### シナリオの操作

```bash
./bin/test-scenario <name>                 # oracle, actual, compare for one scenario
./bin/test-regression                      # all scenarios
./bin/test-regression --jobs 4             # in parallel (or PITMASTER_TEST_JOBS=4)
./bin/test-regression --category diff      # one category
./bin/test-regression --fast               # pass/fail only, no reports

./bin/oracle <name>                        # capture git output for a scenario
./bin/oracle --refresh <name>              # re-capture, for example after a git upgrade
./bin/actual <name>                        # run Pitmaster and capture its output
./bin/compare <name>                       # compare oracle and actual output
```

複数の git バージョンを確認するには、`PITMASTER_TEST_GIT_BINARIES`に一覧を記載してスモークテストを実行します。

```bash
PITMASTER_TEST_GIT_BINARIES=/path/to/git-2.45:/path/to/git-2.46 \
  vendor/bin/phpunit --filter MultiGitVersionSmokeTest
```

## 上流テストコーパス

`scenarios/upstream/`配下のシナリオは、他の実装のテストスイートから取り込んだものです。内訳は git 独自のテストスイートが412件、isomorphic-git が71件、libgit2 が63件、go-git が46件、JGit が7件、dulwich が6件です。必要なフィクスチャツリーは`fixtures/upstream/`に同梱されているため、ネットワーク接続やマシン固有のパスがなくても、新規チェックアウトからコーパス全体を実行できます。セットアップスクリプトは`PITMASTER_ROOT`環境変数を通じてフィクスチャを見つけます。

`composer verify:drift`（`bin/audit-upstream-drift`）は、同梱された上流ケースすべてがシナリオに対応していることを確認します。

## サポートマトリクス

リポジトリ内の`SUPPORT_MATRIX.md`には、対象範囲内の git 機能とそのステータスがすべて記載されています。

| ステータス | 意味 |
|--------|---------|
| `DONE` | 宣言された互換性の範囲内で実装され、オラクルで検証済み |
| `PART` | 一部実装済み |
| `TODO` | 対象範囲内だが、未実装 |
| `DEFER` | 現時点では予定なし |
| `N/A` | 対象範囲外 |

ファイルは`config/support-matrix.json`をもとに`bin/support-matrix`が生成します。`config/support-evidence.json`は`DONE`と`PART`の各項目を具体的なテストとオラクルシナリオに紐付け、根拠のない項目があると`composer verify:evidence`が失敗します。CI はマトリクスを再生成し、コミット済みファイルと異なる場合は失敗します。

`DONE`の項目は、記録されたシナリオで git と一致することを意味します。これらのシナリオ以外では動作が異なる場合があり、既知の差異は[課題トラッカー](https://github.com/inline0/pitmaster/issues)で管理されています。

## ベンチマーク

パフォーマンス改善には、`bench/`配下のハーネスを使います。

```bash
composer bench -- --suite=smoke --runs=1 --warmups=0   # quick check
composer bench:baseline                                # full report
composer bench:compare -- <before.json> <after.json>   # compare two reports
composer bench:verify -- <report.json> bench/reports/smoke-thresholds.json
```

CI はスモークレポートをコミット済みのしきい値と照合します。
