Testarea oracle
Fiecare decizie de implementare din Phasis depinde de un singur răspuns: produce V8 același rezultat?
JavaScript are semantică subtilă — NaN !== NaN, -0 === 0, [1] + 1 === "11", ordinea exactă de enumerare a proprietăților și momentul executării microtask-urilor Promise. Rededucerea acestor detalii prin citirea specificației este lentă și predispusă la erori. Phasis evită această problemă folosind Node.js (V8) drept oracle: scrieți un scenariu JS, rulați-l prin V8 și înregistrați rezultatul drept adevăr; rulați-l prin Phasis, înregistrați din nou rezultatul și comparați-le.
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
Două niveluri de testare
Nivelul 1 — Scenarii personalizate
Fiecare scenariu din scenarios/ este un mic program JS cu rezultat cunoscut. Rulați un singur scenariu:
./bin/test-scenario operators/arithmetic
Rulați-le pe toate, doar o categorie sau în paralel:
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions
Reîmprospătați oracle-ul (e.g după o actualizare a versiunii Node.js):
./bin/oracle --refresh operators/arithmetic
Scenariile sunt organizate după capitolele ECMAScript: literali, operatori, variabile, flux de control, funcții, obiecte, tablouri, clase, funcționalități încorporate, erori, interoperabilitate și cazuri-limită.
Nivelul 2 — test262
Suita oficială de conformitate TC39 este preluată ca submodul git în test262/. Fiecare test își verifică singur rezultatul: trece dacă nu aruncă o excepție și eșuează dacă o aruncă (sau invers, pentru testele negative). Harness-ul încarcă assert.js și sta.js înaintea fiecărui 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
Instantaneul suitei complete se află în COMPAT.md și este regenerat de bin/compat-report. În CI, fluxul de lucru compat-matrix.yml îl rulează în fragmente și înregistrează rezultatul; fluxul este pornit manual, nu la fiecare trimitere.
Verificare locală înainte de trimitere
./bin/verify-all rulează verificările de calitate impuse de CI:
=== PHPStan === level 6, zero errors
=== Code Standards === PHPCS, zero warnings
=== PHPUnit === unit suite passes
=== Oracle Regression === scenarios under `scenarios/` pass
Acest lucru nu este suficient de unul singur — trebuie testat și test262 pentru orice modificare care atinge parserul, interpretorul sau funcționalitățile încorporate. La fiecare pull request, CI rulează PHPStan, PHPCS, suita unitară și testul de regresie oracle; suitele WPT și popular rulează când pull request-ul modifică src/ sau fixture-urile acestora. Matricea completă test262 nu face parte din CI pentru pull request-uri, așa că testați local categoriile afectate.
De ce funcționează
Folosirea V8 ca sursă de adevăr elimină aproape complet citirea specificației din ciclul de dezvoltare. Orice dezacord cu V8 indică întotdeauna o eroare Phasis — niciodată o ambiguitate a specificației care poate fi dezbătută. După ce o remediere este integrată, intrările test262 corespunzătoare devin teste de regresie permanente.
Rata de promovare de 100% este rezultatul acestei discipline: fiecare PR este evaluat în raport cu V8, CI respinge regresiile din oracle și suitele WPT și popular, iar matricea test262 confirmă rezultatul suitei complete când este rulată.