
# Тестване

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

1. **Модулни тестове** за изолирани компоненти (парсери, обхождащи инструменти, кодеци, опции).
2. **Набор за регресии спрямо еталон** сравнява изхода на 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. Наборът за регресии спрямо еталон (`composer test:oracle`) не е част от CI, а матрицата с функции се генерира ръчно с `php bin/feature-matrix`. Наборът PHPUnit съдържа тест, който генерира матрицата, като инструментите нагоре по веригата `rg` и `sg` са отбелязани като недостъпни, и проверява структурата на отчета, така че тестът да не се проваля при регресия в отделна проверка.

## Работа с клонирано хранилище

За всичко на тази страница е необходимо клонирано хранилище. Тъй като 0.2.3 пакетът Composer съдържа само `src/` и четирите изпълними файла за работа, `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` е задължително условие за всяко издание. Ако не премине, промяната не е готова.

## Моделът с еталон

Greph следва модел за проверка, основан на еталон. За всеки сценарий се изпълняват три команди:

1. **Еталон:** `grep`, `ripgrep` или `ast-grep`, заснети спрямо набора от сценарии.
2. **Действителен резултат:** Greph, заснет спрямо същия набор.
3. **Сравнител:** структурирана разлика, която проверява еквивалентността ред по ред или семантично.

Ако Greph не съвпада с еталона, Greph е грешен. Ако `grep` и `rg` не съвпадат помежду си, сценарият записва несъответствието в `oracle_disagreement`, посочва инструмента, който Greph следва в `greph_follows`, и задава сравнението с другия инструмент на `skip`. В набора има случаи и в двете посоки.

Текстовите сценарии се сравняват с `grep` и `rg`, а сценариите за AST и пренаписване — с `sg`. Изходът на еталона се заснема веднъж и се записва в директорията `oracle/` на всеки сценарий, така че при обичайно изпълнение е нужен само PHP; външните инструменти са нужни само за заснемане или обновяване на изхода на еталона.

Реализацията е в `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` задава режима на сравнение за всеки еталон (`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)).

Наборът за регресии е задължителен за въвеждане на ново поведение. За нов флаг, нов граничен случай или корекция на грешка е необходим сценарий, който записва очакваното поведение спрямо еталон.

## Отчитане на съответствието

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

`verify-compliance` не изпълнява нищо самостоятелно. Той чете файловете с еталон, действителен резултат и отчет, оставени от последното изпълнение на сценарий, и показва кои сценарии са преминали, кои са се провалили и за кои все още няма отчет. Първо изпълнете `./bin/test-regression`. `--output report.json` записва отчета и като JSON. Използвайте тази команда, когато искате да разберете „готов ли е текущият клон за издание“.

## Работен процес за разработка, водена от тестове

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

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

При отстраняване на грешка:

1. Запишете входа, който предизвиква грешката, като сценарий.
2. Потвърдете, че еталонът генерира очаквания изход.
3. Потвърдете, че Greph не го генерира.
4. Поправете грешката.
5. Потвърдете, че Greph вече съвпада с еталона.
6. Изпълнете `composer verify`.

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