
# Test con oracle

Ogni decisione di implementazione in Phasis dipende da una domanda: **V8 produce lo stesso output?**

JavaScript ha semantiche sottili: `NaN !== NaN`, `-0 === 0`, `[1] + 1 === "11"`, l’ordine esatto di enumerazione delle proprietà e il momento in cui vengono eseguite le microtask `Promise`. Ricavare questi dettagli leggendo la specifica è lento e soggetto a errori. Phasis aggira il problema usando Node.js (V8) come oracle: si scrive uno scenario JS, lo si esegue tramite V8 e si acquisisce l’output come verità; poi lo si esegue tramite Phasis, si acquisisce di nuovo l’output e lo si confronta.

```
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
```

## Due livelli di test

### Livello 1 — Scenari personalizzati

Ogni scenario in `scenarios/` è un piccolo programma JS con un output noto. Eseguite un singolo scenario:

```bash
./bin/test-scenario operators/arithmetic
```

Eseguiteli tutti, una sola categoria oppure in parallelo:

```bash
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions
```

Aggiornate l’oracle (e.g, ad esempio dopo un aggiornamento di versione di Node.js):

```bash
./bin/oracle --refresh operators/arithmetic
```

Gli scenari sono organizzati per capitolo ECMAScript: valori letterali, operatori, variabili, flusso di controllo, funzioni, oggetti, array, classi, funzioni integrate, errori, interoperabilità e casi limite.

### Livello 2 — test262

La suite ufficiale di conformità TC39 è presente come sottomodulo git in `test262/`. Ogni test si verifica da sé: ha esito positivo se non genera un’eccezione e negativo se la genera (o viceversa per i test `negative`). L’harness carica `assert.js` e `sta.js` prima di ogni test.

```bash
./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
```

Lo snapshot della suite completa si trova in [`COMPAT.md`](https://github.com/inline0/phasis/blob/main/COMPAT.md) ed è rigenerato da `bin/compat-report`. Nella CI il workflow `compat-matrix.yml` lo esegue suddividendolo in shard e salva il risultato; viene avviato manualmente, non a ogni push.

## Controllo locale prima del push

`./bin/verify-all` esegue i controlli di qualità imposti dalla CI:

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

Da solo **non** basta: occorre anche eseguire un campione di test262 per ogni modifica che tocca il parser, l’interprete o le funzioni integrate. A ogni pull request, la CI esegue PHPStan, PHPCS, la suite di unit test e la regressione oracle; le suite WPT e popular vengono eseguite quando la pull request modifica `src/` o i relativi fixture. La matrice test262 completa non fa parte della CI delle pull request, quindi eseguite localmente un campione delle categorie interessate.

## Perché funziona

Usare V8 come fonte di verità elimina quasi tutta la necessità di leggere la specifica durante lo sviluppo. Ogni divergenza da V8 indica un bug di Phasis, mai un’ambiguità della specifica su cui discutere. Una volta applicata una correzione, le relative voci test262 diventano test di regressione permanenti.

Il tasso di superamento del 100 % deriva da questa disciplina: ogni PR viene valutata rispetto a V8, la CI rifiuta le regressioni nelle suite oracle, WPT e popular e la matrice test262 conferma il risultato della suite completa quando viene eseguita.
