Testowanie
Greph jest weryfikowany w trzech warstwach testów:
- Testy jednostkowe dla odizolowanych komponentów (parserów, walkerów, kodeków, opcji).
- Korpus regresyjny oracle, który porównuje wyjście Greph z kanonicznymi plikami binarnymi
grep,ripgrepiast-grepdla ustalonego zestawu scenariuszy. - Macierz funkcji oparta na sondach, która sprawdza zweryfikowany zakres funkcji opakowań
rgisg.
CI uruchamia się przy każdym wypchnięciu zmian do main i przy każdym żądaniu pull request (.github/workflows/ci.yml). Obejmuje standardy kodowania (composer cs), analizę statyczną (composer analyse), zestawy testów jednostkowych i integracyjnych PHPUnit (composer test) oraz composer audit na PHP 8.4. Korpus oracle (composer test:oracle) nie jest częścią CI, a macierz funkcji jest generowana ręcznie za pomocą php bin/feature-matrix. Zestaw PHPUnit zawiera test, który generuje macierz, gdy nadrzędne narzędzia rg i sg są oznaczone jako niedostępne, i sprawdza strukturę raportu, więc nie kończy się niepowodzeniem, gdy pojedyncza sonda ulegnie regresji.
Praca z klonem repozytorium
Wszystko na tej stronie wymaga klonu repozytorium. Ponieważ pakiet Composer zawiera tylko src/ i cztery pliki wykonywalne środowiska uruchomieniowego, 0.2.3 tests/, scenarios/, benchmarks/ i skrypty deweloperskie z bin/ są z niego wyłączone.
git clone https://github.com/inline0/greph
cd greph
composer install
Uruchamianie testów
# 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 to warunek każdego wydania. Jeśli nie przejdzie, zmiana nie jest gotowa.
Model oracle
Greph stosuje model weryfikacji oparty na oracle. Dla każdego scenariusza uruchamiane są trzy polecenia:
- Oracle:
grep,ripgreplubast-grep, zarejestrowane dla korpusu scenariuszy. - Wynik rzeczywisty: Greph, zarejestrowany dla tego samego korpusu.
- Porównywarka: ustrukturyzowane porównanie sprawdzające zgodność wiersz po wierszu lub semantyczną.
Jeśli Greph nie zgadza się z oracle, Greph jest błędne. Jeśli grep i rg nie zgadzają się ze sobą, scenariusz zapisuje rozbieżność w oracle_disagreement, wskazuje narzędzie, za którym podąża Greph w greph_follows, i ustawia porównanie z drugim narzędziem na skip. W korpusie występują oba kierunki rozbieżności.
Scenariusze tekstowe są porównywane z grep i rg, a scenariusze AST i przepisywania z sg. Wyjście oracle jest przechwytywane raz i zatwierdzane w katalogu oracle/ każdego scenariusza, więc zwykłe uruchomienie wymaga tylko PHP; narzędzia zewnętrzne są potrzebne wyłącznie do przechwycenia lub odświeżenia wyjścia oracle.
Implementacja znajduje się w tests/Oracle/, a scenariusze w scenarios/text/, scenarios/ast/, scenarios/rewrite/ i scenarios/edge/.
Układ scenariusza
Każdy scenariusz to samodzielny katalog:
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 deklaruje wzorzec, flagi i ścieżkę wyszukiwania. Opcjonalny obiekt expectations ustawia tryb porównania dla każdego oracle (exact, semantic lub skip); bez niego scenariusze tekstowe porównują dokładnie grep i rg, a rg JSON semantycznie, zaś scenariusze AST i przepisywania porównują z sg.
Uruchamianie pojedynczego scenariusza
Repozytorium zawiera niewielki zestaw interfejsów CLI do pracy z pojedynczymi scenariuszami. Są to narzędzia deweloperskie, a nie punkty wejścia środowiska uruchomieniowego: znajdują się obok plików binarnych środowiska uruchomieniowego w bin/, ale nie należą do pakietu Composer. Każde z nich przyjmuje nazwę scenariusza względem 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
Uruchamianie pełnego zestawu testów regresyjnych
# 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
Scenariusze zawsze są uruchamiane pojedynczo. --jobs N jest akceptowane i wyświetlane w wierszu podsumowania, ale nie uruchamia niczego równolegle (#7). W świeżym klonie text/no-ignore i text/explicit-file-input kończą się niepowodzeniem, ponieważ ich pliki fixture w setup/vendor/ nie są zatwierdzone (#6).
Zestaw testów regresyjnych jest bramką dla nowych funkcji. Nowa flaga, przypadek brzegowy lub poprawka błędu wymagają scenariusza rejestrującego oczekiwane działanie względem oracle.
Raportowanie zgodności
./bin/verify-compliance
verify-compliance sam niczego nie uruchamia. Odczytuje pliki oracle, wyników rzeczywistych i raportów pozostawione przez ostatnie uruchomienia scenariuszy, a następnie wyświetla, które scenariusze przechodzą, które kończą się niepowodzeniem i dla których nie ma jeszcze raportu. Najpierw uruchom ./bin/test-regression. --output report.json zapisuje również raport jako JSON. To właściwe polecenie, gdy chcesz sprawdzić, „czy bieżąca gałąź jest gotowa do wydania”.
Przepływ pracy oparty na testach
Dodając funkcję:
- Utwórz katalog scenariusza z korpusem i flagami sprawdzającymi nowe działanie.
- Uruchom
./bin/oracle <scenario>, aby przechwycić wyjście kanonicznego narzędzia. - Zaimplementuj funkcję w
src/. - Uruchom
./bin/test-scenario <scenario>, aby sprawdzić, czy Greph zgadza się z oracle. - Uruchom
./bin/test-regression --fast, aby upewnić się, że nic innego nie uległo regresji. - Uruchom
composer verifyprzed zatwierdzeniem zmian.
Naprawiając błąd:
- Zapisz błędne dane wejściowe jako scenariusz.
- Potwierdź, że oracle generuje oczekiwane wyjście.
- Potwierdź, że Greph go nie generuje.
- Napraw błąd.
- Potwierdź, że Greph zgadza się teraz z oracle.
- Uruchom
composer verify.
Scenariusz na stałe pozostaje w korpusie, więc błąd nie może powrócić niezauważony, ponieważ testy composer test:oracle (i composer verify) zakończą się niepowodzeniem.