Към съдържанието

Тестване

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/ не са включени в него.

Обвивка
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 не изпълнява нищо самостоятелно. Той чете файловете с еталон, действителен резултат и отчет, оставени от последното изпълнение на сценарий, и показва кои сценарии са преминали, кои са се провалили и за кои все още няма отчет. Първо изпълнете ./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).