Testovanie oracle
Každé rozhodnutie o implementácii v Phasis závisí od jednej otázky: vytvára V8 rovnaký výstup?
JavaScript má jemné sémantické nuansy — NaN !== NaN, -0 === 0, [1] + 1 === "11", presné poradie výpočtu vlastností a načasovanie mikrotaskov Promise. Odvodzovať ich nanovo čítaním špecifikácie je pomalé a náchylné na chyby. Phasis to obchádza tak, že za oracle považuje Node.js (V8): napíšete scenár JS, spustíte ho cez V8 a zaznamenáte výstup ako referenčný; potom ho spustíte cez Phasis, znova zaznamenáte výstup a porovnáte ich.
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
Dve úrovne testovania
Úroveň 1 — vlastné scenáre
Každý scenár v scenarios/ je malý program JS so známym výstupom. Spustenie jedného scenára:
./bin/test-scenario operators/arithmetic
Spustenie všetkých scenárov, iba jednej kategórie alebo paralelne:
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions
Obnovenie oracle (e.g po aktualizácii verzie Node.js):
./bin/oracle --refresh operators/arithmetic
Scenáre sú usporiadané podľa kapitol ECMAScriptu: literály, operátory, premenné, riadenie toku, funkcie, objekty, polia, triedy, vstavané funkcie, chyby, interoperabilita a okrajové prípady.
Úroveň 2 — test262
Oficiálna testovacia sada zhody TC39 je prevzatá ako podmodul git v test262/. Každý test sa overuje sám: prejde, ak nevyvolá výnimku, a zlyhá, ak ju vyvolá (pri testoch negative naopak). Pred každým testom načíta testovací rámec assert.js a sta.js.
./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
Snímka celej testovacej sady sa nachádza v COMPAT.md a obnovuje sa pomocou bin/compat-report. V CI ju workflow compat-matrix.yml spúšťa po častiach a ukladá výsledok; tento workflow sa spúšťa manuálne, nie pri každom odoslaní zmien.
Lokálna kontrola pred odoslaním zmien
./bin/verify-all spúšťa kontrolu kvality, ktorú vyžaduje CI:
=== PHPStan === level 6, zero errors
=== Code Standards === PHPCS, zero warnings
=== PHPUnit === unit suite passes
=== Oracle Regression === scenarios under `scenarios/` pass
Samo osebe to nestačí — pri každej zmene parsera, interpreta alebo vstavaných funkcií treba otestovať aj test262. Pri každej požiadavke na zlúčenie CI spúšťa PHPStan, PHPCS, unit testy a regresné testy oracle; sady WPT a popular sa spúšťajú pri zmenách v src/ alebo ich fixture. Úplná matica test262 nie je súčasťou CI pre požiadavky na zlúčenie, preto lokálne otestujte dotknuté kategórie.
Prečo to funguje
Ak považujete V8 za zdroj pravdy, pri vývoji takmer vôbec nemusíte čítať špecifikáciu. Každá nezhoda s V8 znamená chybu Phasis — nikdy nejde o nejednoznačnosť špecifikácie, o ktorej by sa dalo polemizovať. Po zapracovaní opravy sa príslušné položky test262 stanú trvalými regresnými testami.
Miera úspešnosti 100 % je výsledkom tejto disciplíny: každá požiadavka na zlúčenie sa vyhodnocuje voči V8, CI odmieta regresie v testovacích sadách oracle, WPT a popular a matica test262 potvrdzuje výsledok celej sady, keď sa spustí.