Testes e benchmarks
Um programa que você não consegue testar é um programa que você não consegue mudar com confiança. O Glide integra testes à própria cadeia de ferramentas — sem framework para instalar, sem configuração. Você escreve funções prefixadas com test_ em arquivos *_test.glide e executa glide test.
Seu primeiro teste
Os testes ficam ao lado do seu código (normalmente em um diretório tests/) em arquivos terminados em _test.glide. Um teste é uma função cujo nome começa com test_, retorna i32 e retorna 0 para indicar aprovação:
import stdlib::testing::*;
import stdlib::math::*;
fn test_ipow_basic() -> i32 {
assert_eq!(ipow(2, 10), 1024);
return 0;
}
fn test_gcd() -> i32 {
assert_eq!(gcd(48, 36), 12);
return 0;
}
Execute-os:
glide test tests/math_test.glide
# running tests/math_test.glide ( 2 tests )
#
# 2 passed, 0 failed
Cada arquivo de teste é compilado em seu próprio binário e executado de forma independente, portanto o estado global nunca vaza entre arquivos. Uma asserção que falha marca o teste como reprovado e imprime o local da falha; o executor sai com código diferente de zero se algo falhar — exatamente o que a CI espera.
Os macros de asserção
stdlib::testing oferece cinco macros. Escolha o mais específico — eles produzem mensagens de falha muito mais claras:
assert!(cond); // cond deve ser verdadeiro
assert_not!(cond); // cond deve ser falso
assert_eq!(a, b); // igualdade para i32, bool, char
assert_str_eq!(a, b); // igualdade para strings — use para texto
assert_msg!(cond, "context"); // verificação booleana com mensagem personalizada
Um teste com várias asserções falha na primeira que quebrar:
import stdlib::testing::*;
fn slug(s: string) -> string {
return s.trim().to_lower().replace(" ", "-");
}
fn test_slug() -> i32 {
assert_str_eq!(slug(" Hello World "), "hello-world");
assert_not!(slug("A B").contains(" "));
return 0;
}
Executando a suíte
glide test recebe um caminho, ou executa tudo no diretório atual:
glide test # todo *_test.glide abaixo do diretório atual
glide test tests/ # todo arquivo de teste em um diretório
glide test tests/math_test.glide # um único arquivo
As três camadas
O executor suporta testes em três granularidades — o mesmo glide test, escopos diferentes:
- Unitário — uma única função ou método de struct isolado: lógica pura, validação, uma regra de parser. O
test_ipow_basicacima é um teste unitário. - Integração — vários módulos juntos:
fs+os, ou sua biblioteca usando outra. Mesma estrutura, mas exercitando mais partes de uma vez. - Golden — um programa completo cuja
stdouté comparada com um arquivo.expectedgravado. O executor compila o programa, executa-o e compara a saída com o diff.
Os testes golden são executados com uma flag:
glide test --golden tests/golden
Cada programa em tests/golden/ é pareado com um arquivo .expected contendo a saída que ele deve produzir. O executor normaliza CRLF para LF, portanto um .expected escrito com terminações de linha Unix funciona no Windows também. Testes golden são perfeitos para CLIs e geradores de código onde o contrato é a saída.
Benchmarks
Correção é um eixo; velocidade é outro. glide bench executa microbenchmarks declarados como funções prefixadas com bench_ que recebem um *Bencher:
import stdlib::bench::*;
pub fn bench_sum(b: *Bencher) {
let mut total: i32 = 0;
for let i: i32 = 0; i < b.n; i++ {
total = total + i;
}
b.consume(&total); // mantém `total` vivo para que o loop não seja otimizado pelo compilador
}
Execute-o:
glide bench sum_bench.glide
Dois aspectos tornam um benchmark honesto:
- `b.n` é a contagem de iterações, e o executor ajusta automaticamente esse valor — ele escala
npara cima até que o benchmark rode por tempo suficiente para ser cronometrado com confiança, depois reporta nanossegundos por operação. Seu loop deve executar exatamenteb.nvezes. - `b.consume(&x)` informa ao otimizador que o resultado é observado. Sem isso, uma build
-O2perceberia quetotalnunca é usado e deletaria o loop inteiro — você estaria cronometrando nada. Passe&xpara primitivos, ou o valor diretamente para tipos no formato de ponteiro (b.consume(my_vector)).
Recapitulando
O que vem a seguir
Você já sabe compilar, testar e medir programas Glide. O capítulo final — FFI e saídas de emergência — vai na direção oposta: chamando C, incorporando C puro, assembly inline e código específico por plataforma para quando você precisar ir além dos limites da linguagem.