Pular para o conteúdo

Testes

Greph é validado com três camadas de testes:

  1. Testes unitários para componentes isolados (analisadores, percorredores, codecs, opções).
  2. Corpus de regressão do oráculo que compara a saída de Greph com os binários canônicos grep, ripgrep e ast-grep em um conjunto fixo de cenários.
  3. Matriz de recursos orientada por sondagens que verifica a superfície confirmada dos wrappers rg e sg.

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.

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

Executar os testes

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 é 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:

  1. Oráculo: grep, ripgrep ou ast-grep, capturado para o corpus de cenários.
  2. Resultado real: Greph, capturado para o mesmo corpus.
  3. 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:

Código
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/.

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

Executar o conjunto completo de regressão

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

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

Shell
./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:

  1. Escreva um diretório de cenário com o corpus e as flags que exercitam o novo comportamento.
  2. Execute ./bin/oracle <scenario> para capturar a saída da ferramenta canônica.
  3. Implemente o recurso em src/.
  4. Execute ./bin/test-scenario <scenario> para verificar se Greph corresponde ao oráculo.
  5. Execute ./bin/test-regression --fast para garantir que nada mais regrediu.
  6. Execute composer verify antes de fazer o commit.

Ao corrigir um bug:

  1. Registre a entrada que falha como um cenário.
  2. Confirme que o oráculo produz a saída esperada.
  3. Confirme que Greph não produz essa saída.
  4. Corrija o bug.
  5. Confirme que Greph agora corresponde ao oráculo.
  6. 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.