Ugrás a tartalomhoz

Oracle-tesztelés

A Phasis minden megvalósítási döntését egy kérdés határozza meg: ugyanazt a kimenetet adja a V8?

A JavaScript szemantikája finom részleteket tartalmaz — NaN !== NaN, -0 === 0, [1] + 1 === "11", a tulajdonságok felsorolásának pontos sorrendje és a Promise mikrofeladatok időzítése. Ezek újbóli levezetése a specifikáció olvasásával lassú és hibalehetőségekkel teli. A Phasis ezt úgy kerüli meg, hogy a Node.js elemet (V8) orákulumként kezeli: írjon egy JS forgatókönyvet, futtassa le a V8 rendszeren, és mentse el a kimenetet igazságként; majd futtassa le a Phasis rendszeren is, mentse el ismét a kimenetet, végül hasonlítsa össze őket.

Kód
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

Két tesztelési szint

1. szint — Egyéni forgatókönyvek

A scenarios/ minden forgatókönyve egy ismert kimenetű kis JS program. Egyetlen forgatókönyv futtatása:

Shell
./bin/test-scenario operators/arithmetic

Futtassa le mindet, csak egy kategóriát, vagy párhuzamosan:

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

Az oracle frissítése (e.g, például a Node.js verziófrissítése után):

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

A forgatókönyvek az ECMAScript fejezetei szerint vannak rendezve: literálok, operátorok, változók, vezérlésfolyamat, függvények, objektumok, tömbök, osztályok, beépített elemek, hibák, együttműködés és szélső esetek.

2. szint — test262

A hivatalos TC39 megfelelőségi tesztcsomag git almodulként van kicheckolva a test262/ alatt. Minden teszt önellenőrző: sikeres, ha nem dob hibát, sikertelen, ha igen (vagy fordítva az negative tesztek esetén). A tesztfuttató minden teszt előtt betölti a assert.js és a sta.js elemet.

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

A teljes tesztcsomag pillanatképe itt található: COMPAT.md; az bin/compat-report generálja újra. CI-ben a compat-matrix.yml munkafolyamat részekre bontva futtatja, majd beküldi az eredményt; ezt a munkafolyamatot kézzel indítják, nem minden beküldéskor.

Beküldés előtti helyi ellenőrzés

A ./bin/verify-all lefuttatja a CI által megkövetelt minőségellenőrzést:

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

Ez önmagában nem elegendő — minden olyan módosításnál az test262 tesztjeit is le kell futtatni, amely érinti a parsert, az értelmezőt vagy a beépített elemeket. Minden pull request esetén a CI futtatja a PHPStan, a PHPCS, az egységteszteket és az oracle-regressziót; a WPT- és népszerűcsomag-tesztcsomagok akkor futnak, ha a pull request módosítja a src/ fájljait vagy azok tesztfixture-jeit. A teljes test262 mátrix nem része a pull requestek CI-folyamatának, ezért helyben futtassa az érintett kategóriákat.

Miért működik

Ha a V8 elemet tekintjük az igazság forrásának, a fejlesztési folyamatban szinte teljesen elhagyható a specifikáció olvasása. Ha eltérés van a V8 eredményétől, az mindig Phasis hibát jelez — soha nem a specifikáció olyan kétértelműségét, amelyről vitatkozni lehet. A javítás bekerülésével a megfelelő test262 bejegyzések állandó regressziós tesztekké válnak.

A 100%-os átmenési arány ennek a fegyelmezett folyamatnak az eredménye: minden PR-t a V8 alapján bírálunk el, a CI elutasítja az oracle-, WPT- és népszerűcsomag-tesztcsomagokban fellépő regressziókat, a test262 mátrix pedig megerősíti a teljes tesztcsomag eredményét, amikor lefuttatják.