Gå til indhold

Oracle-testning

Hver implementeringsbeslutning i Phasis afhænger af ét spørgsmål: giver V8 det samme resultat?

JavaScript har subtil semantik — NaN !== NaN, -0 === 0, [1] + 1 === "11", den nøjagtige rækkefølge for egenskabsopregning og tidspunktet for Promise-mikrotasks. Det er langsomt og fejlbehæftet at udlede dette ved at læse specifikationen. Phasis undgår det ved at behandle Node.js (V8) som et oracle: Skriv et JS-scenarie, kør det gennem V8, og gem resultatet som facit; kør det gennem Phasis, gem resultatet igen, og sammenlign dem.

Kode
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

To testniveauer

Niveau 1 — Tilpassede scenarier

Hvert scenarie i scenarios/ er et lille JS-program med kendt resultat. Kør et enkelt scenarie:

Shell
./bin/test-scenario operators/arithmetic

Kør dem alle, en enkelt kategori eller flere parallelt:

Shell
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions

Opdater oracle (e.g, efter en versionsopdatering af Node.js):

Shell
./bin/oracle --refresh operators/arithmetic

Scenarierne er organiseret efter ECMAScript-kapitler: literaler, operatorer, variabler, kontrolflow, funktioner, objekter, arrays, klasser, indbyggede funktioner, fejl, interop og kanttilfælde.

Niveau 2 — test262

Den officielle TC39-overensstemmelsessuite er hentet som et git-submodul under test262/. Hver test kontrollerer selv sit resultat: Den består, hvis den ikke udløser en fejl, og fejler, hvis den gør det (eller omvendt for negative-tests). Testrammen indlæser assert.js og sta.js før hver test.

Shell
./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

Øjebliksbilledet af den fulde suite ligger i COMPAT.md og gendannes af bin/compat-report. I CI kører workflowen compat-matrix.yml den i shards og gemmer resultatet; workflowen startes manuelt, ikke ved hver push.

Lokal kontrol før push

./bin/verify-all kører den kvalitetskontrol, som CI håndhæver:

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

Det er ikke tilstrækkeligt i sig selv — test262 skal også køres i udvalg for enhver ændring, der berører parseren, fortolkeren eller indbyggede funktioner. Ved hver pull request kører CI PHPStan, PHPCS, unit-suiten og oracle-regressionstesten; WPT- og populærpakke-suiterne køres, når en pull request ændrer src/ eller deres fixtures. Den fulde test262-matrix er ikke en del af CI for pull requests, så kør lokalt de berørte kategorier.

Hvorfor det virker

Når V8 behandles som facit, fjernes næsten al læsning af specifikationen fra udviklingsforløbet. Uenighed med V8 betyder altid en fejl i Phasis — aldrig en tvetydighed i specifikationen, der kan diskuteres. Når en rettelse er landet, bliver de tilsvarende test262-elementer permanente regressionstests.

100 % beståelsesgrad er resultatet af denne praksis: Hver PR vurderes mod V8, CI afviser regressioner i oracle-, WPT- og populærpakke-suiterne, og test262-matricen bekræfter resultatet for hele suiten, når den køres.