
# 测试与 git Oracle

Pitmaster 将标准 `git` 二进制程序作为 Oracle：如果 `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`：所有 Oracle 场景 | 是 |
| `composer test` | PHPUnit（两个套件）以及 Oracle 回归测试 | 是 |
| `./bin/verify-all` | `composer verify`：支持证据、上游偏差、证明产物、变异冒烟测试、`composer audit`、PHPStan、编码规范和 `composer test` | 是 |

CI 会在多个 PHP 版本上运行单元测试套件、集成测试套件、Oracle 回归测试（`PITMASTER_TEST_JOBS=4`），以及支持证据和上游偏差检查。

## Oracle 场景

每个场景都是 `scenarios/<category>/` 下的一个目录（总计 761 个，其中 Pitmaster 和 605 编写了 156 个，其余来自其他 Git 实现）：

```
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` 构建的仓库，分别在独立副本上运行 Oracle 和 Pitmaster 命令，并比较输出、对象、引用和日志。`fsck_clean` 还要求 `git fsck` 接受 Pitmaster 写入的仓库。若 Oracle 输出缺失或需要刷新，则从 `git` 捕获；否则使用已提交的 `oracle/` 文件。

一个场景仅覆盖其设置所构建的案例。例如，diff 场景比较的是已修改文件，因此不会捕获 [Diff](https://pitmaster.inline0.dev/zh/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` | 已实现，并在声明的兼容范围内通过 Oracle 验证 |
| `PART` | 部分实现 |
| `TODO` | 在范围内，尚未实现 |
| `DEFER` | 暂无计划 |
| `N/A` | 不在范围内 |

该文件由 `bin/support-matrix` 根据 `config/support-matrix.json` 生成。`config/support-evidence.json` 会将每一行 `DONE` 和 `PART` 与具体测试及 Oracle 场景关联起来；如果某行没有证据，`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 会根据已提交的阈值验证冒烟测试报告。
