Oracle-testning
Varje implementeringsbeslut i Phasis avgörs av en fråga: ger V8 samma resultat?
JavaScript har subtil semantik — NaN !== NaN, -0 === 0, [1] + 1 === "11", den exakta ordningen för uppräkning av egenskaper och tidpunkten för Promise-mikrotasks. Att härleda detta på nytt genom att läsa specifikationen är långsamt och felbenäget. Phasis undviker det genom att behandla Node.js (V8) som ett oracle: skriv ett JS-scenario, kör det genom V8 och spara resultatet som facit; kör det genom Phasis, spara resultatet igen och jämför.
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
Två testnivåer
Nivå 1 — Anpassade scenarier
Varje scenario i scenarios/ är ett litet JS-program med känt resultat. Kör ett enskilt scenario:
./bin/test-scenario operators/arithmetic
Kör alla, en enda kategori eller parallellt:
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions
Uppdatera oracle (e.g. efter en versionsuppdatering av Node.js):
./bin/oracle --refresh operators/arithmetic
Scenarierna är organiserade efter ECMAScript-kapitel: literaler, operatorer, variabler, kontrollflöde, funktioner, objekt, arrayer, klasser, inbyggda funktioner, fel, interoperabilitet och specialfall.
Nivå 2 — test262
Den officiella TC39-konformitetssviten är utcheckad som en git-submodul under test262/. Varje test verifierar sig självt: det godkänns om det inte kastar ett undantag och misslyckas om det gör det (eller tvärtom för negative-tester). Testriggen laddar assert.js och sta.js före varje test.
./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
Ögonblicksbilden av hela sviten finns i COMPAT.md och återskapas av bin/compat-report. I CI kör compat-matrix.yml-arbetsflödet den i delar och checkar in resultatet. Arbetsflödet startas manuellt, inte vid varje push.
Lokal kontroll före push
./bin/verify-all kör kvalitetskontrollen som CI tillämpar:
=== PHPStan === level 6, zero errors
=== Code Standards === PHPCS, zero warnings
=== PHPUnit === unit suite passes
=== Oracle Regression === scenarios under `scenarios/` pass
Det räcker inte på egen hand — test262 måste också testas för alla ändringar som berör parsern, tolken eller inbyggda funktioner. Vid varje pull request kör CI PHPStan, PHPCS, unit-sviten och oracle-regressionstestet. WPT- och popular-paketsviterna körs när en pull request ändrar src/ eller deras fixtures. Den fullständiga test262-matrisen ingår inte i CI för pull requests, så testa berörda kategorier lokalt.
Varför det här fungerar
När V8 behandlas som facit behöver utvecklingsflödet nästan inte alls läsa specifikationen. Om resultatet skiljer sig från V8 finns alltid ett Phasis-fel — det är aldrig en tvetydighet i specifikationen att diskutera. När en korrigering har landat blir motsvarande test262-poster permanenta regressionstester.
100 % godkända tester är resultatet av den här disciplinen: varje PR bedöms mot V8, CI avvisar regressioner i oracle-, WPT- och popular-paketsviterna, och test262-matrisen bekräftar resultatet för hela sviten när den körs.