Testes
Greph é validado com três camadas de testes:
- Testes unitários para componentes isolados (analisadores, percorredores, codecs, opções).
- Corpus de regressão do oráculo que compara a saída de Greph com os binários canônicos
grep,ripgrepeast-grepem um conjunto fixo de cenários. - Matriz de recursos orientada por sondagens que verifica a superfície confirmada dos wrappers
rgesg.
O CI é executado a cada push para main e a cada pull request (.github/workflows/ci.yml). Ele executa verificações de padrões de código (composer cs), análise estática (composer analyse), os conjuntos de testes unitários e de integração de PHPUnit (composer test) e composer audit em PHP 8.4. O corpus do oráculo (composer test:oracle) não faz parte do CI, e a matriz de recursos é gerada manualmente com php bin/feature-matrix. O conjunto PHPUnit inclui um teste que gera a matriz com rg e sg upstream marcados como indisponíveis e verifica o formato do relatório, para que o teste não falhe quando uma única sondagem apresenta regressão.
Trabalhar a partir de um clone
Tudo nesta página exige um clone do repositório. Como desde 0.2.3 o pacote Composer contém apenas src/ e os quatro executáveis de runtime, tests/, scenarios/, benchmarks/ e os scripts de desenvolvimento em bin/ não são incluídos nele.
git clone https://github.com/inline0/greph
cd greph
composer install
Executar os testes
# 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 é o requisito para qualquer lançamento. Se não passar, a alteração não está concluída.
O modelo do oráculo
Greph segue um modelo de verificação orientado por oráculo. Para cada cenário, três comandos são executados:
- Oráculo:
grep,ripgrepouast-grep, capturado para o corpus de cenários. - Resultado real: Greph, capturado para o mesmo corpus.
- Comparador: uma comparação estruturada que verifica a equivalência linha a linha ou semântica.
Se Greph divergir do oráculo, Greph está errado. Se grep e rg divergirem entre si, o cenário registra a divergência em oracle_disagreement, identifica a ferramenta que Greph segue em greph_follows e define a comparação com a outra ferramenta como skip. As duas direções ocorrem no corpus.
Os cenários de texto são comparados com grep e rg; os cenários de AST e reescrita, com sg. A saída do oráculo é capturada uma vez e enviada ao diretório oracle/ de cada cenário, então uma execução normal precisa apenas de PHP; as ferramentas externas só são necessárias para capturar ou atualizar a saída do oráculo.
A implementação fica em tests/Oracle/ e os cenários ficam em scenarios/text/, scenarios/ast/, scenarios/rewrite/ e scenarios/edge/.
Estrutura dos cenários
Cada cenário é um diretório independente:
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 declara o padrão, as flags e o caminho de pesquisa. Um objeto expectations opcional define o modo de comparação por oráculo (exact, semantic ou skip); sem ele, os cenários de texto comparam grep e rg exatamente e o rg JSON semanticamente, enquanto os cenários de AST e reescrita comparam com sg.
Executar um único cenário
O repositório tem um pequeno conjunto de CLIs para trabalhar com cenários individuais. São ferramentas de desenvolvimento, não pontos de entrada do runtime: ficam junto aos binários de runtime em bin/, mas não fazem parte do pacote Composer. Cada uma recebe o nome do cenário relativo a 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
Executar o conjunto completo de regressão
# 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
Os cenários são sempre executados um de cada vez. --jobs N é aceito e exibido na linha de resumo, mas não executa nada em paralelo (#7). Em um clone novo, text/no-ignore e text/explicit-file-input falham, porque os arquivos de fixture em setup/vendor/ não estão incluídos no repositório (#6).
O conjunto de regressão é o critério para novos comportamentos. Uma nova flag, um novo caso-limite ou uma correção de bug exige um cenário que registre o comportamento esperado em relação a um oráculo.
Relatórios de conformidade
./bin/verify-compliance
verify-compliance não executa nada por conta própria. Ele lê os arquivos do oráculo, de resultados reais e de relatórios deixados pelas últimas execuções de cenários e informa quais cenários passaram, quais falharam e quais ainda não têm relatório. Execute ./bin/test-regression primeiro. --output report.json também grava o relatório como JSON. É o comando certo para saber "a ramificação atual está pronta para lançamento?".
Fluxo de trabalho de desenvolvimento orientado por testes
Ao adicionar um recurso:
- Escreva um diretório de cenário com o corpus e as flags que exercitam o novo comportamento.
- Execute
./bin/oracle <scenario>para capturar a saída da ferramenta canônica. - Implemente o recurso em
src/. - Execute
./bin/test-scenario <scenario>para verificar se Greph corresponde ao oráculo. - Execute
./bin/test-regression --fastpara garantir que nada mais regrediu. - Execute
composer verifyantes de fazer o commit.
Ao corrigir um bug:
- Registre a entrada que falha como um cenário.
- Confirme que o oráculo produz a saída esperada.
- Confirme que Greph não produz essa saída.
- Corrija o bug.
- Confirme que Greph agora corresponde ao oráculo.
- Execute
composer verify.
O cenário permanece no corpus permanentemente, para que o bug não volte sem que composer test:oracle (e composer verify) falhe.