
# Testen

Greph wird mit drei Testebenen validiert:

1. **Unit-Tests** für isolierte Komponenten (Parser, Walker, Codecs, Optionen).
2. **Oracle-Regressionskorpus**, das die Ausgabe von Greph mit den kanonischen Binärdateien `grep`, `ripgrep` und `ast-grep` anhand eines festen Szenariosatzes vergleicht.
3. **Probe-gesteuerte Funktionsmatrix**, die die verifizierte Oberfläche der Wrapper `rg` und `sg` prüft.

CI läuft bei jedem Push nach `main` und bei jedem Pull Request (`.github/workflows/ci.yml`). Dabei werden Codierungsstandards (`composer cs`), statische Analyse (`composer analyse`), die PHPUnit-Unit- und Integrationssuiten (`composer test`) sowie `composer audit` unter PHP 8.4 ausgeführt. Das Oracle-Korpus (`composer test:oracle`) ist nicht Teil von CI, und die Funktionsmatrix wird manuell mit `php bin/feature-matrix` neu erstellt. Die PHPUnit-Suite enthält einen Test, der die Matrix mit dem vorgelagerten `rg` generiert, wobei `sg` als nicht verfügbar markiert ist, und die Struktur des Berichts überprüft. So schlägt der Test nicht fehl, wenn eine einzelne Prüfung regressiert.

## Mit einem Klon arbeiten

Für alles auf dieser Seite brauchst du einen Klon des Repositorys. Seit Version 0.2.3 enthält das Composer-Paket nur `src/` und die vier Laufzeitprogramme; `tests/`, `scenarios/`, `benchmarks/` und die Entwicklungsskripte in `bin/` sind nicht enthalten.

```bash
git clone https://github.com/inline0/greph
cd greph
composer install
```

## Tests ausführen

```bash
# 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` ist die Mindestanforderung für jede Veröffentlichung. Wenn sie nicht besteht, ist die Änderung nicht abgeschlossen.

## Das Oracle-Modell

Greph folgt einem Oracle-gesteuerten Verifikationsmodell. Für jedes Szenario werden drei Befehle ausgeführt:

1. **Oracle**: `grep`, `ripgrep` oder `ast-grep`, ausgeführt anhand des Szenariokorpus.
2. **Tatsächliche Ausgabe**: Greph, ausgeführt anhand desselben Korpus.
3. **Vergleich**: ein strukturierter Diff, der die zeilenweise oder semantische Gleichwertigkeit prüft.

Wenn Greph vom Oracle abweicht, ist Greph falsch. Wenn `grep` und `rg` voneinander abweichen, hält das Szenario die Abweichung unter `oracle_disagreement` fest, nennt das Werkzeug, dem Greph in `greph_follows` folgt, und setzt den Vergleich mit dem anderen Werkzeug auf `skip`. Im Korpus kommen beide Richtungen vor.

Text-Szenarien werden mit `grep` und `rg` verglichen, AST- und Rewrite-Szenarien mit `sg`. Die Oracle-Ausgabe wird einmal erfasst und im Verzeichnis `oracle/` jedes Szenarios eingecheckt. Für einen normalen Durchlauf brauchst du daher nur PHP; die externen Werkzeuge werden nur zum Erfassen oder Aktualisieren der Oracle-Ausgabe benötigt.

Die Implementierung liegt unter `tests/Oracle/`, die Szenarien unter `scenarios/text/`, `scenarios/ast/`, `scenarios/rewrite/` und `scenarios/edge/`.

## Szenarioaufbau

Jedes Szenario ist ein eigenständiges Verzeichnis:

```
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` definiert das Muster, die Flags und den Suchpfad. Ein optionales Objekt `expectations` legt den Vergleichsmodus für jedes Oracle fest (`exact`, `semantic` oder `skip`). Ohne dieses Objekt werden Textszenarien mit `grep` und `rg` exakt und das `rg` JSON semantisch verglichen; AST- und Rewrite-Szenarien werden mit `sg` verglichen.

## Ein einzelnes Szenario ausführen

Das Repository enthält einige CLIs, um mit einzelnen Szenarien zu arbeiten. Sie sind Entwicklungswerkzeuge und keine Laufzeiteinstiegspunkte: Sie liegen neben den Laufzeit-Binärdateien in `bin/`, gehören aber nicht zum Composer-Paket. Jedes Tool erwartet den Szenarionamen relativ zu `scenarios/`.

```bash
# 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
```

## Die gesamte Regressionssuite ausführen

```bash
# 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
```

Szenarien werden immer nacheinander ausgeführt. `--jobs N` wird akzeptiert und in der Zusammenfassungszeile ausgegeben, führt aber nichts parallel aus ([#7](https://github.com/inline0/greph/issues/7)). In einem frisch geklonten Repository schlagen `text/no-ignore` und `text/explicit-file-input` fehl, weil ihre Fixture-Dateien unter `setup/vendor/` nicht eingecheckt sind ([#6](https://github.com/inline0/greph/issues/6)).

Die Regressionssuite ist die Freigabeinstanz für neues Verhalten. Für ein neues Flag, einen neuen Sonderfall oder eine Fehlerbehebung brauchst du ein Szenario, das das erwartete Verhalten anhand eines Oracle festhält.

## Compliance-Berichte

```bash
./bin/verify-compliance
```

`verify-compliance` führt selbst nichts aus. Es liest die Oracle-, Ist- und Berichtsdateien, die der letzte Szenariolauf hinterlassen hat, und gibt aus, welche Szenarien bestanden haben, welche fehlgeschlagen sind und für welche noch kein Bericht vorliegt. Führe zuerst `./bin/test-regression` aus. `--output report.json` schreibt den Bericht außerdem als JSON. Dieser Befehl eignet sich, wenn du wissen möchtest: „Ist der aktuelle Branch veröffentlichungsbereit?“

## Testgetriebener Entwicklungsablauf

Beim Hinzufügen einer Funktion:

1. Erstelle ein Szenarioverzeichnis mit Korpus und Flags, das das neue Verhalten abdeckt.
2. Führe `./bin/oracle <scenario>` aus, um die Ausgabe des kanonischen Werkzeugs zu erfassen.
3. Implementiere die Funktion in `src/`.
4. Führe `./bin/test-scenario <scenario>` aus, um zu prüfen, ob Greph mit dem Oracle übereinstimmt.
5. Führe `./bin/test-regression --fast` aus, um sicherzustellen, dass nichts anderes regressiert ist.
6. Führe `composer verify` vor dem Commit aus.

Beim Beheben eines Fehlers:

1. Erfasse die fehlerhafte Eingabe als Szenario.
2. Prüfe, ob das Oracle die erwartete Ausgabe erzeugt.
3. Prüfe, ob Greph das nicht tut.
4. Behebe den Fehler.
5. Prüfe, ob Greph jetzt mit dem Oracle übereinstimmt.
6. Führe `composer verify` aus.

Das Szenario bleibt dauerhaft im Korpus, sodass der Fehler nicht wieder auftreten kann, ohne dass `composer test:oracle` (und `composer verify`) fehlschlägt.
