Cobertura, sanitizadores e build reproduzível
-coverage para saber o que os testes executam, --sanitize=undefined para pegar índice fora da faixa e estouro, -reproducible para binário sem data.
O que é e por que existe#
Três opções de compilação para confiar mais no código sem mudar o código:
| Opção | O que faz |
|---|---|
-coverage | instrumenta o código do usuário e grava quais linhas executaram (<saída>.fxcov) |
--sanitize=undefined | liga de uma vez rangechecks, overflowchecks e divcheck (e um aviso de narrowing) no código do usuário |
-reproducible | PE sem data/hora (/Brepro): o mesmo fonte gera o mesmo binário |
No .config, os equivalentes são Config All Coverage on (ou atomic), Config All Sanitize undefined e Config All Reproducible on.
Cobertura#
fc Defer.fxp -coverage -o Defcov.exe # -coverage-atomic: contadores atômicos (threads)
Defcov.exe # ao terminar, grava Defcov.exe.fxcov
fc --cov-report Defcov.exe --text # relatórioO relatório do demo 40 (defer), conferido com o compilador:
Defer.fxp 22/22 100.00%
TOTAL: 22/22 linhas cobertas (100.00%)fc --cov-report também gera --html <pasta> (linhas coloridas), --lcov <arq>, --json <arq>, --cobertura <arq>, aceita --include/--exclude <glob>, --merge <outro.fxcov> (juntar execuções) e --fail-under <N> (sai com erro abaixo de N%, ótimo para CI).
Por dentro é uma instrumentação própria: cada comando do código do usuário (a RTL fica de fora) incrementa um contador por arquivo:linha; "linha coberta" é contador maior que zero. Desligada, o código gerado é idêntico ao de antes. Com -coverage toda rotina do usuário vira raiz da poda de código vivo, para que uma rotina nunca chamada apareça como não coberta.
Armadilhas da cobertura#
- Só em
.exeWindows com IR; em DLL/package, bytecode, nativo, Linux, Android e Wasm ofcavisa e ignora. Halt/ExitProcesse exceção fatal pulam o fim do@main: o.fxcovnão é gravado.- Granularidade por linha, não por ramo nem por
and/or. Sem-coverage-atomic, threads podem perder contagem. - O HTML lê o fonte pelo caminho que o
fcviu: rode do mesmo diretório.
Sanitizador#
Um programa que escreve fora de um vetor estático e deixa um inteiro estourar. Compilado normalmente, nada acontece (e a memória fica corrompida); com o sanitizador, vira exceção que o programa pode tratar:
var A: array[0..2] of Int32;
for I := 0 to N do A[I] := I; // N = 3: o último índice está fora
I := 2147483647;
I := I + N; // estouro de Int32Saída com --sanitize=undefined (verificada):
capturou: RangeError
capturou: Integer OverflowSem a opção, a primeira falha passa em silêncio e a segunda dá a volta (-2147483646). --sanitize=undefined vale só no código do usuário, e um {$config rangechecks off} escrito no fonte continua mandando sobre ele.
Build reproduzível#
fc prog.fxp -reproducible tira a data e a hora do executável. Duas compilações do mesmo fonte, com as mesmas opções, geram binários idênticos, o que permite verificar uma distribuição por hash. Não cobre -g: o .pdb guarda o caminho absoluto.
Veja também#
- Testes com Fenner.Testing, que a cobertura mede bem.
- Diagnósticos e depuração (rangechecks, overflowchecks, divcheck).