
# Тестування з оракулом

Кожне рішення щодо реалізації в Phasis залежить від одного запитання: **чи видає V8 такий самий результат?**

JavaScript має тонкощі семантики — `NaN !== NaN`, `-0 === 0`, `[1] + 1 === "11"`, точний порядок перелічення властивостей і час виконання мікрозадач `Promise`. Повторно виводити ці правила з тексту специфікації довго й легко помилитися. Phasis розв’язує це, використовуючи Node.js (V8) як оракул: напишіть сценарій JS, виконайте його в V8 і збережіть результат як еталон; виконайте його в Phasis, збережіть результат і порівняйте.

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

## Два рівні тестування

### Рівень 1 — користувацькі сценарії

Кожен сценарій у `scenarios/` — це невелика програма JS з відомим результатом. Запустити один сценарій:

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

Запустити їх усі, лише одну категорію або паралельно:

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

Оновити оракул (e.g, наприклад, після оновлення версії Node.js):

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

Сценарії згруповано за розділами ECMAScript: літерали, оператори, змінні, керування потоком виконання, функції, об’єкти, масиви, класи, вбудовані функції, помилки, взаємодія, крайові випадки.

### Рівень 2 — test262

Офіційний набір тестів відповідності TC39 підключено як підмодуль git у `test262/`. Кожен тест перевіряє себе сам: він проходить, якщо не виникає винятку, і не проходить, якщо виняток виникає (або навпаки для тестів `negative`). Перед кожним тестом тестове середовище завантажує `assert.js` і `sta.js`.

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

Знімок повного набору тестів зберігається в [`COMPAT.md`](https://github.com/inline0/phasis/blob/main/COMPAT.md); його повторно створює `bin/compat-report`. У CI робочий процес `compat-matrix.yml` запускає тести частинами й фіксує результат; його запускають вручну, а не під час кожного надсилання змін.

## Локальна перевірка перед відправленням змін

`./bin/verify-all` запускає перевірки якості, обов’язкові в CI:

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

Самого цього **недостатньо** — test262 також потрібно вибірково запускати для будь-яких змін у парсері, інтерпретаторі чи вбудованих функціях. Для кожного pull request CI запускає PHPStan, PHPCS, модульний набір тестів і регресійний тест оракула; набори WPT і popular запускаються, якщо pull request змінює `src/` або відповідні тестові приклади. Повна матриця test262 не входить до CI для pull request, тож локально вибірково запускайте тести для відповідних категорій.

## Чому це працює

Якщо вважати V8 еталоном, під час розробки майже не доводиться читати специфікацію. Будь-яка розбіжність із V8 означає помилку Phasis, а не неоднозначність специфікації, яку можна оскаржувати. Після внесення виправлення відповідні записи test262 стають постійними регресійними тестами.

Показник проходження тестів 100 % є результатом цієї дисципліни: кожен PR перевіряється за V8, CI відхиляє регресії в наборах oracle, WPT і popular-package, а матриця test262 підтверджує результат повного набору, коли її запускають.
