Перейти до вмісту

Тестування

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 містить тест, який генерує матрицю з позначеними як недоступні upstream-інструментами rg і sg та перевіряє структуру звіту, тому регресія однієї проби не призводить до помилки.

Робота з клоном

Для всього на цій сторінці потрібен клон репозиторію. Оскільки 0.2.3 пакет Composer містить лише src/ і чотири виконувані файли середовища виконання, 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 — обов'язкова умова для будь-якого випуску. Якщо він не проходить, зміна не готова.

Модель еталонної перевірки

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

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

Набір регресійних тестів є умовою для додавання нової поведінки. Для нового прапорця, граничного випадку або виправлення помилки потрібен сценарій, що фіксує очікувану поведінку за еталоном.

Звітування про відповідність

Командна оболонка
./bin/verify-compliance

verify-compliance самостійно нічого не запускає. Команда читає файли oracle, actual і report, залишені останнім запуском сценаріїв, і виводить, які сценарії пройшли, які завершилися помилкою, а для яких звіт ще відсутній. Спочатку запустіть ./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).