
# Pruebas con oráculo

Cada decisión de implementación en Phasis depende de una pregunta: **¿V8 produce el mismo resultado?**

JavaScript tiene una semántica sutil: `NaN !== NaN`, `-0 === 0`, `[1] + 1 === "11"`, el orden exacto de enumeración de propiedades y el momento de las microtareas de `Promise`. Volver a deducirlo leyendo la especificación es lento y propenso a errores. Phasis lo evita al tratar Node.js (V8) como oráculo: se escribe un caso de prueba JS, se ejecuta con V8 y se guarda el resultado como referencia; luego se ejecuta con Phasis, se vuelve a guardar el resultado y se comparan ambos.

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

## Dos niveles de pruebas

### Nivel 1 — Casos personalizados

Cada caso de prueba en `scenarios/` es un pequeño programa JS con un resultado conocido. Ejecuta un solo caso:

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

Ejecútalos todos, una sola categoría o en paralelo:

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

Actualiza el oráculo (e.g, por ejemplo, después de actualizar la versión de Node.js):

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

Los casos están organizados por capítulo de ECMAScript: literales, operadores, variables, flujo de control, funciones, objetos, matrices, clases, funciones integradas, errores, interoperabilidad y casos límite.

### Nivel 2 — test262

La suite oficial de conformidad de TC39 está disponible como submódulo de git en `test262/`. Cada prueba se verifica por sí sola: pasa si no lanza una excepción y falla si la lanza (o lo contrario en las pruebas `negative`). El arnés carga `assert.js` y `sta.js` antes de cada prueba.

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

La instantánea completa se encuentra en [`COMPAT.md`](https://github.com/inline0/phasis/blob/main/COMPAT.md), generada de nuevo por `bin/compat-report`. En CI, el flujo de trabajo `compat-matrix.yml` la ejecuta en fragmentos y confirma el resultado; se inicia manualmente, no con cada envío.

## Comprobación local antes del envío

`./bin/verify-all` ejecuta el control de calidad que CI exige:

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

Por sí solo **no** es suficiente: también hay que muestrear test262 para cualquier cambio que afecte al analizador, al intérprete o a las funciones integradas. En cada solicitud de incorporación de cambios, CI ejecuta PHPStan, PHPCS, la batería de pruebas unitarias y la regresión del oráculo; las baterías de WPT y paquetes populares se ejecutan cuando una solicitud modifica `src/` o sus fixtures. La matriz completa de test262 no forma parte de CI para solicitudes de incorporación de cambios, así que pruebe localmente las categorías afectadas.

## Por qué funciona

Tratar V8 como fuente de verdad elimina casi toda lectura de especificaciones del ciclo de desarrollo. Cualquier discrepancia con V8 indica un error de Phasis, nunca una ambigüedad de la especificación que se pueda debatir. Cuando se incorpora una corrección, las entradas correspondientes de test262 se convierten en pruebas de regresión permanentes.

La tasa de aciertos del 100 % depende de esta disciplina: cada solicitud de incorporación de cambios se evalúa frente a V8, CI rechaza las regresiones en el oráculo y en las baterías de WPT y paquetes populares, y la matriz de test262 confirma el resultado de la batería completa cuando se ejecuta.
