
# Oracle-Tests

Jede Implementierungsentscheidung in Phasis hängt von einer Frage ab: **Erzeugt V8 dieselbe Ausgabe?**

JavaScript hat subtile Semantik – `NaN !== NaN`, `-0 === 0`, `[1] + 1 === "11"`, die genaue Reihenfolge der Property-Aufzählung und der Zeitpunkt von `Promise`-Microtasks. Diese durch Lesen der Spezifikation erneut herzuleiten, ist langsam und fehleranfällig. Phasis umgeht das, indem es Node.js (V8) als Oracle behandelt: Schreibe ein JS-Szenario, führe es in V8 aus und speichere die Ausgabe als Wahrheit; führe es anschließend über Phasis aus, speichere auch diese Ausgabe und vergleiche beide.

```
1. SETUP    → a JavaScript source file or snippet
2. ORACLE   → Node.js executes it, output captured as truth
3. ACTUAL   → Phasis executes it, output captured
4. COMPARE  → oracle vs actual, diff measures the gap
```

## Zwei Testebenen

### Ebene 1 — Eigene Szenarien

Jedes Szenario in `scenarios/` ist ein kleines JS-Programm mit bekannter Ausgabe. So führst du ein einzelnes Szenario aus:

```bash
./bin/test-scenario operators/arithmetic
```

Führe alle Szenarien, nur eine Kategorie oder mehrere parallel aus:

```bash
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions
```

Oracle aktualisieren (e.g. nach einem Versionsupdate von Node.js):

```bash
./bin/oracle --refresh operators/arithmetic
```

Die Szenarien sind nach ECMAScript-Kapiteln geordnet: Literale, Operatoren, Variablen, Kontrollfluss, Funktionen, Objekte, Arrays, Klassen, integrierte Funktionen, Fehler, Interoperabilität und Sonderfälle.

### Ebene 2 — test262

Die offizielle TC39-Konformitätssuite ist als git-Submodul unter `test262/` ausgecheckt. Jeder Test prüft sich selbst: Er besteht, wenn er keinen Fehler auslöst, und schlägt fehl, wenn er es tut (bei `negative`-Tests umgekehrt). Vor jedem Test lädt der Test-Harness `assert.js` und `sta.js`.

```bash
./bin/test262                                    # full suite
./bin/test262 --category built-ins/Array         # subset
./bin/test262 --jobs 4                           # parallel
./bin/test262 --failures                         # one line per failing test
./bin/compat-report                              # full COMPAT.md + compat.json
```

Der Snapshot der vollständigen Suite liegt in [`COMPAT.md`](https://github.com/inline0/phasis/blob/main/COMPAT.md) und wird von `bin/compat-report` neu erzeugt. In CI führt der `compat-matrix.yml`-Workflow die Suite in Shards aus und committet das Ergebnis. Dieser Workflow wird manuell gestartet, nicht bei jedem Push.

## Lokale Prüfung vor dem Push

`./bin/verify-all` führt die von CI erzwungene Qualitätsprüfung aus:

```
=== PHPStan ===                  level 6, zero errors
=== Code Standards ===           PHPCS, zero warnings
=== PHPUnit ===                  unit suite passes
=== Oracle Regression ===        scenarios under `scenarios/` pass
```

Das allein reicht **nicht** aus – bei jeder Änderung am Parser, Interpreter oder an integrierten Funktionen müssen auch betroffene test262-Tests stichprobenartig ausgeführt werden. Bei jedem Pull Request führt CI PHPStan, PHPCS, die Unit-Suite und die Oracle-Regression aus; die WPT- und Popular-Package-Suites laufen, wenn ein Pull Request `src/` oder deren Fixtures ändert. Die vollständige test262-Matrix gehört nicht zu den Pull-Request-Prüfungen in CI; prüfe die betroffenen Kategorien daher lokal stichprobenartig.

## Warum das funktioniert

V8 als Quelle der Wahrheit zu behandeln, erspart beim Entwickeln fast das gesamte Lesen der Spezifikation. Eine Abweichung von V8 weist immer auf einen Phasis-Fehler hin – niemals auf eine auslegbare Mehrdeutigkeit in der Spezifikation. Sobald eine Korrektur eingeht, werden die zugehörigen test262-Einträge zu dauerhaften Regressionstests.

Die Disziplin dahinter ermöglicht eine Erfolgsquote von 100 %: Jeder PR wird mit V8 verglichen, CI weist Regressionen in der Oracle-, WPT- und Popular-Package-Suite zurück, und die test262-Matrix bestätigt bei ihrer Ausführung das Ergebnis der vollständigen Suite.
