Тестване
Greph се проверява на три нива:
- Модулни тестове за изолирани компоненти (парсери, обхождащи инструменти, кодеци, опции).
- Набор за регресии спрямо еталон сравнява изхода на Greph с каноничните двоични файлове
grep,ripgrepиast-grepза фиксиран набор от сценарии. - Матрица с функции, задвижвана от проверки потвърждава проверената функционалност на обвивките
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 следва модел за проверка, основан на еталон. За всеки сценарий се изпълняват три команди:
- Еталон:
grep,ripgrepилиast-grep, заснети спрямо набора от сценарии. - Действителен резултат: Greph, заснет спрямо същия набор.
- Сравнител: структурирана разлика, която проверява еквивалентността ред по ред или семантично.
Ако 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. Използвайте тази команда, когато искате да разберете „готов ли е текущият клон за издание“.
Работен процес за разработка, водена от тестове
При добавяне на функция:
- Създайте директория на сценарий с набора от данни и флаговете, които упражняват новото поведение.
- Изпълнете
./bin/oracle <scenario>, за да заснемете изхода на каноничния инструмент. - Реализирайте функцията в
src/. - Изпълнете
./bin/test-scenario <scenario>, за да проверите дали Greph съвпада с еталона. - Изпълнете
./bin/test-regression --fast, за да се уверите, че нищо друго не е регресирало. - Изпълнете
composer verify, преди да направите комит.
При отстраняване на грешка:
- Запишете входа, който предизвиква грешката, като сценарий.
- Потвърдете, че еталонът генерира очаквания изход.
- Потвърдете, че Greph не го генерира.
- Поправете грешката.
- Потвърдете, че Greph вече съвпада с еталона.
- Изпълнете
composer verify.
Сценарият остава завинаги в набора, така че грешката не може да се появи отново, без да се провалят composer test:oracle (и composer verify).