
# Тестирование

Greph проверяется на трех уровнях:

1. **Модульные тесты** изолированных компонентов (парсеров, обходчиков, кодеков, параметров).
2. **Регрессионный корпус oracle**, сравнивающий вывод Greph с выводом канонических бинарных файлов `grep`, `ripgrep` и `ast-grep` на фиксированном наборе сценариев.
3. **Матрица функций на основе проверок**, подтверждающая проверенный набор возможностей оболочек `rg` и `sg`.

CI запускается при каждом отправлении изменений в `main` и при каждом запросе на слияние (`.github/workflows/ci.yml`). Выполняются проверки стандартов кодирования (`composer cs`), статический анализ (`composer analyse`), модульные и интеграционные наборы PHPUnit (`composer test`), а также `composer audit` на PHP 8.4. Корпус oracle (`composer test:oracle`) не входит в CI, а матрица функций обновляется вручную с помощью `php bin/feature-matrix`. В наборе PHPUnit есть тест, который создает матрицу, помечая вышестоящие `rg` и `sg` как недоступные, и проверяет структуру отчета, поэтому он не падает при сбое одной проверки.

## Работа с клоном репозитория

Для всего, что описано на этой странице, нужен клон репозитория. Поскольку пакет Composer содержит только `src/` и четыре исполняемых файла для работы, из него исключены 0.2.3, `tests/`, `scenarios/`, `benchmarks/` и скрипты разработки из `bin/`.

```bash
git clone https://github.com/inline0/greph
cd greph
composer install
```

## Запуск тестов

```bash
# PHPUnit unit and integration suites
composer test

# Oracle regression corpus
composer test:oracle

# Static analysis
composer analyse

# Coding standards
composer cs
composer cs:fix

# Full release-grade verification (analyse + cs + test + test:oracle)
composer verify
```

`composer verify` — обязательное условие выпуска. Если проверка не проходит, изменение не готово.

## Модель oracle

В Greph используется модель проверки на основе oracle. Для каждого сценария выполняются три команды:

1. **Oracle**: `grep`, `ripgrep` или `ast-grep`, вывод которых сохранен для корпуса сценариев.
2. **Фактический результат**: Greph, вывод которого сохранен для того же корпуса.
3. **Сравнение**: структурированное сопоставление для проверки построчной или семантической эквивалентности.

Если Greph расходится с oracle, значит, Greph работает неверно. Если `grep` и `rg` расходятся между собой, сценарий фиксирует расхождение в `oracle_disagreement`, указывает инструмент, за которым следует Greph в `greph_follows`, и задает значение `skip` для сравнения с другим инструментом. В корпусе встречаются оба варианта.

Текстовые сценарии сравниваются с `grep` и `rg`, сценарии AST и переписывания — с `sg`. Вывод oracle сохраняется один раз в каталоге `oracle/` каждого сценария и фиксируется в репозитории, поэтому для обычного запуска нужен только PHP; внешние инструменты требуются лишь для получения или обновления вывода oracle.

Реализация находится в `tests/Oracle/`, а сценарии — в `scenarios/text/`, `scenarios/ast/`, `scenarios/rewrite/` и `scenarios/edge/`.

## Структура сценариев

Каждый сценарий находится в отдельном каталоге:

```
scenarios/text/literal-simple/
├── scenario.json     # name, category, pattern, flags, path
├── setup/            # corpus to search through
├── oracle/           # captured oracle output (grep.txt, rg.txt, rg.json, ...)
├── actual/           # captured greph output (generated, git-ignored)
└── reports/          # comparison results (generated, git-ignored)
```

`scenario.json` задает шаблон, флаги и путь поиска. Необязательный объект `expectations` задает режим сравнения для каждого oracle (`exact`, `semantic` или `skip`). Если он не задан, в текстовых сценариях `grep` и `rg` сравниваются точно, а `rg` JSON — семантически; сценарии AST и переписывания сравниваются с `sg`.

## Запуск отдельного сценария

В репозитории есть небольшой набор CLI-инструментов для работы с отдельными сценариями. Это инструменты разработки, а не исполняемые файлы, которые запускаются во время работы: они находятся рядом с исполняемыми файлами в `bin/`, но не входят в пакет Composer. Каждый принимает имя сценария относительно `scenarios/`.

```bash
# Capture oracle output for a scenario (needs grep and rg, or sg)
./bin/oracle text/literal-simple

# Run greph against a scenario, capture its output
./bin/actual text/literal-simple

# Diff oracle vs actual
./bin/compare text/literal-simple

# Full pipeline: oracle (only if missing) -> actual -> compare
./bin/test-scenario text/literal-simple

# Recapture the oracle output first
./bin/test-scenario text/literal-simple --refresh
```

## Запуск полного набора регрессионных тестов

```bash
# All scenarios (the same as composer test:oracle)
./bin/test-regression

# Filter by category
./bin/test-regression --category text
./bin/test-regression --category ast
./bin/test-regression --category rewrite
./bin/test-regression --category edge

# Print only failures and the summary
./bin/test-regression --fast

# Recapture every oracle before comparing
./bin/test-regression --refresh
```

Сценарии всегда запускаются по одному. Параметр `--jobs N` принимается и отображается в строке сводки, но ничего не запускает параллельно ([#7](https://github.com/inline0/greph/issues/7)). В свежем клоне `text/no-ignore` и `text/explicit-file-input` завершаются с ошибкой, поскольку файлы фикстур в `setup/vendor/` не включены в репозиторий ([#6](https://github.com/inline0/greph/issues/6)).

Регрессионный набор служит проверкой для нового поведения. Для нового флага, граничного случая или исправления ошибки нужен сценарий, который фиксирует ожидаемое поведение относительно oracle.

## Отчет о соответствии требованиям

```bash
./bin/verify-compliance
```

`verify-compliance` ничего не запускает. Он читает файлы oracle, фактических результатов и отчетов, оставленные последним запуском сценариев, и выводит, какие сценарии прошли, какие завершились с ошибкой, а для каких отчет еще не создан. Сначала запустите `./bin/test-regression`. `--output report.json` также записывает отчет в формате JSON. Эту команду следует запускать, если нужно узнать, «готова ли текущая ветка к выпуску».

## Процесс разработки через тестирование

При добавлении функции:

1. Создайте каталог сценария с корпусом и флагами, которые проверяют новое поведение.
2. Запустите `./bin/oracle <scenario>`, чтобы сохранить вывод канонического инструмента.
3. Реализуйте функцию в `src/`.
4. Запустите `./bin/test-scenario <scenario>`, чтобы проверить, что Greph совпадает с oracle.
5. Запустите `./bin/test-regression --fast`, чтобы убедиться, что ничего другого не сломалось.
6. Запустите `composer verify` перед фиксацией изменений.

При исправлении ошибки:

1. Сохраните вызывающий ошибку ввод как сценарий.
2. Убедитесь, что oracle выдает ожидаемый результат.
3. Убедитесь, что Greph выдает другой результат.
4. Исправьте ошибку.
5. Убедитесь, что теперь Greph совпадает с oracle.
6. Запустите `composer verify`.

Сценарий навсегда остается в корпусе, поэтому ошибка не сможет повториться без сбоя `composer test:oracle` (и `composer verify`).
