
# Testes com oráculo

Toda decisão de implementação em Phasis depende de uma pergunta: **V8 produz o mesmo resultado?**

JavaScript tem semânticas sutis — `NaN !== NaN`, `-0 === 0`, `[1] + 1 === "11"`, a ordem exata da enumeração de propriedades e o momento das microtarefas de `Promise`. Rededuzir esses comportamentos pela leitura da especificação é lento e propenso a erros. Phasis evita isso tratando Node.js (V8) como oráculo: escreva um cenário JS, execute-o em V8 e registre a saída como verdade; execute-o em Phasis, registre novamente a saída e compare.

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

## Dois níveis de testes

### Nível 1 — Cenários personalizados

Cada cenário em `scenarios/` é um pequeno programa JS com saída conhecida. Execute um único cenário:

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

Execute todos, apenas uma categoria ou em paralelo:

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

Atualize o oráculo (e.g, por exemplo, após uma atualização de versão do Node.js):

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

Os cenários são organizados por capítulo do ECMAScript: literais, operadores, variáveis, fluxo de controle, funções, objetos, arrays, classes, recursos integrados, erros, interoperabilidade e casos extremos.

### Nível 2 — test262

A suíte oficial de conformidade do TC39 é obtida como um submódulo git em `test262/`. Cada teste verifica a si próprio: é aprovado se não lançar uma exceção e reprovado se lançar (ou o contrário nos testes `negative`). O harness carrega `assert.js` e `sta.js` antes de cada teste.

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

O snapshot da suíte completa fica em [`COMPAT.md`](https://github.com/inline0/phasis/blob/main/COMPAT.md) e é regenerado por `bin/compat-report`. Na CI, o fluxo de trabalho `compat-matrix.yml` executa os testes em partes e registra o resultado; esse fluxo é iniciado manualmente, não a cada envio.

## Verificação local antes de enviar

`./bin/verify-all` executa a verificação de qualidade exigida pela CI:

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

Isso **não** basta por si só — test262 também deve ser testado para qualquer alteração no parser, interpretador ou nos recursos integrados. Em cada pull request, a CI executa PHPStan, PHPCS, a suíte unitária e a regressão do oráculo; as suítes WPT e de pacotes populares são executadas quando um pull request altera `src/` ou seus fixtures. A matriz test262 completa não faz parte da CI de pull requests, então teste localmente as categorias afetadas.

## Por que funciona

Tratar V8 como fonte de verdade elimina quase toda a leitura da especificação durante o ciclo de desenvolvimento. Uma divergência em relação a V8 sempre indica um bug Phasis — nunca uma ambiguidade na especificação que possa ser debatida. Depois que uma correção é integrada, as entradas correspondentes de test262 tornam-se testes de regressão permanentes.

A taxa de aprovação de 100 % é resultado dessa disciplina: cada PR é avaliado em relação a V8, a CI rejeita regressões nas suítes do oráculo, WPT e pacotes populares, e a matriz test262 confirma o resultado da suíte completa quando é executada.
