Перейти к содержимому

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

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/.

Командная оболочка
git clone https://github.com/inline0/greph
cd greph
composer install

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

Командная оболочка
# 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/.

Командная оболочка
# 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

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

Командная оболочка
# 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). В свежем клоне text/no-ignore и text/explicit-file-input завершаются с ошибкой, поскольку файлы фикстур в setup/vendor/ не включены в репозиторий (#6).

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

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

Командная оболочка
./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).