Vai al contenuto

Test

Greph viene convalidato con tre livelli di test:

  1. Test unitari per componenti isolati (parser, walker, codec, opzioni).
  2. Corpus di regressione dell’oracolo, che confronta l’output di Greph con i binari canonici di grep, ripgrep e ast-grep su un insieme fisso di scenari.
  3. Matrice delle funzionalità basata su probe, che verifica le funzionalità disponibili nei wrapper rg e sg.

CI viene eseguita a ogni push su main e a ogni pull request (.github/workflows/ci.yml). Esegue gli standard di codifica (composer cs), l’analisi statica (composer analyse), le suite di test unitari e di integrazione di PHPUnit (composer test) e composer audit su PHP 8.4. Il corpus dell’oracolo (composer test:oracle) non fa parte di CI e la matrice delle funzionalità viene rigenerata manualmente con php bin/feature-matrix. La suite PHPUnit contiene un test che genera la matrice indicando come non disponibili rg e sg a monte, quindi verifica la struttura del report; in questo modo il test non fallisce se un singolo probe presenta una regressione.

Lavorare da un clone

Per tutto ciò che è descritto in questa pagina serve un clone del repository. Poiché 0.2.3 il pacchetto Composer contiene solo src/ e i quattro eseguibili runtime, ne sono esclusi tests/, scenarios/, benchmarks/ e gli script di sviluppo in bin/.

Shell
git clone https://github.com/inline0/greph
cd greph
composer install

Eseguire i test

Shell
# 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 è un requisito per ogni release. Se non viene superato, la modifica non è completa.

Il modello dell’oracolo

Greph segue un modello di verifica basato sull’oracolo. Per ogni scenario vengono eseguiti tre comandi:

  1. Oracolo: grep, ripgrep o ast-grep, eseguito sul corpus di scenari per acquisirne l’output.
  2. Risultato effettivo: Greph, eseguito sullo stesso corpus per acquisirne l’output.
  3. Comparatore: un confronto strutturato che verifica l’equivalenza riga per riga o semantica.

Se Greph non concorda con l’oracolo, Greph è errato. Se grep e rg non concordano tra loro, lo scenario registra la discrepanza in oracle_disagreement, indica quale strumento Greph segue in greph_follows e imposta su skip il confronto con l’altro strumento. Nel corpus sono presenti entrambe le situazioni.

Gli scenari testuali vengono confrontati con grep e rg, mentre gli scenari AST e di riscrittura con sg. L’output dell’oracolo viene acquisito una volta e salvato nel repository nella directory oracle/ di ciascuno scenario, quindi per una normale esecuzione basta PHP; gli strumenti esterni servono solo per acquisire o aggiornare l’output dell’oracolo.

L’implementazione si trova in tests/Oracle/ e gli scenari in scenarios/text/, scenarios/ast/, scenarios/rewrite/ e scenarios/edge/.

Struttura degli scenari

Ogni scenario è una directory autonoma:

Codice
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 dichiara il pattern, i flag e il percorso di ricerca. Un oggetto expectations facoltativo imposta la modalità di confronto per ciascun oracolo (exact, semantic o skip); in sua assenza, gli scenari testuali confrontano grep e rg esattamente e rg JSON in modo semantico, mentre gli scenari AST e di riscrittura vengono confrontati con sg.

Eseguire un singolo scenario

Il repository include un piccolo insieme di CLI per lavorare con singoli scenari. Sono strumenti di sviluppo, non entry point runtime: si trovano accanto ai binari runtime in bin/, ma non fanno parte del pacchetto Composer. Ognuna accetta il nome dello scenario relativo a scenarios/.

Shell
# 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

Eseguire l’intera suite di regressione

Shell
# 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

Gli scenari vengono sempre eseguiti uno alla volta. --jobs N viene accettato e riportato nella riga di riepilogo, ma non esegue nulla in parallelo (#7). In un clone nuovo text/no-ignore e text/explicit-file-input falliscono, perché i relativi file fixture in setup/vendor/ non sono inclusi nel repository (#6).

La suite di regressione è il criterio di accesso per i nuovi comportamenti. Un nuovo flag, un nuovo caso limite o la correzione di un bug richiedono uno scenario che acquisisca il comportamento previsto rispetto a un oracolo.

Report di conformità

Shell
./bin/verify-compliance

verify-compliance non esegue nulla direttamente. Legge i file dell’oracolo, dei risultati effettivi e dei report lasciati dall’ultima esecuzione degli scenari, quindi indica quali scenari sono superati, quali falliscono e per quali non è ancora disponibile un report. Eseguite prima ./bin/test-regression. Anche --output report.json scrive il report in JSON. È il comando giusto per sapere «il branch corrente è pronto per il rilascio?».

Flusso di lavoro con sviluppo guidato dai test

Quando aggiungete una funzionalità:

  1. Scrivete una directory di scenario con il corpus e i flag necessari a verificare il nuovo comportamento.
  2. Eseguite ./bin/oracle <scenario> per acquisire l’output dello strumento canonico.
  3. Implementate la funzionalità in src/.
  4. Eseguite ./bin/test-scenario <scenario> per verificare che Greph corrisponda all’oracolo.
  5. Eseguite ./bin/test-regression --fast per assicurarvi che non ci siano altre regressioni.
  6. Eseguite composer verify prima di creare il commit.

Quando correggete un bug:

  1. Acquisite l’input che causa il malfunzionamento in uno scenario.
  2. Verificate che l’oracolo produca l’output previsto.
  3. Verificate che Greph non lo produca.
  4. Correggete il bug.
  5. Verificate che ora Greph corrisponda all’oracolo.
  6. Eseguite composer verify.

Lo scenario resta per sempre nel corpus, così il bug non può ripresentarsi senza far fallire composer test:oracle (e composer verify).