No description
Find a file
Jonatas Oliveira a6647ff61e fix(hooks): consertar onde o teste de mutação grava e onde ele compila
Duas correções no `mutacao()`, ambas descobertas rodando o hook nos quinze
repositórios.

`--output .`: o cargo-mutants grava o `mutants.out` na raiz do WORKSPACE,
não no diretório de onde foi chamado. Nos repositórios que também são
membros de um workspace maior o relatório ia parar um nível acima, fora do
repositório, e a checagem do teto não achava o arquivo -- reprovando um
crate que não tinha deixado nenhum mutante escapar (o battleship-common
foi reprovado assim, com 65 mutantes e 0 sobreviventes).

TMPDIR no disco: o cargo-mutants copia a árvore e compila a cópia no
TMPDIR, que aqui é /tmp em tmpfs -- memória. Uma árvore de build do `iced`
dentro dele esgotou a RAM da máquina. O scratch passa a ficar em
~/.cache/cargo-mutants, com CARGO_MUTANTS_TMPDIR para quem quiser outro
lugar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhdPjHUuVhXaitwT4mG53t
2026-09-05 13:00:35 +02:00
.cargo ci: run cargo-mutants from the workspace root 2026-09-02 11:30:22 +02:00
.githooks fix(hooks): consertar onde o teste de mutação grava e onde ele compila 2026-09-05 13:00:35 +02:00
.woodpecker ci: tirar a mutação do pipeline e rodar o CI inteiro no pre-commit 2026-09-05 07:41:17 +02:00
battleship-client@0581b3ece6 fix(hooks): consertar onde o teste de mutação grava e onde ele compila 2026-09-05 13:00:35 +02:00
battleship-common@238fc62088 fix(hooks): consertar onde o teste de mutação grava e onde ele compila 2026-09-05 13:00:35 +02:00
battleship-server@283d95256a fix(hooks): consertar onde o teste de mutação grava e onde ele compila 2026-09-05 13:00:35 +02:00
.gitignore build: turn the three crates into a workspace 2026-09-01 22:20:42 +02:00
.gitmodules refactor: split the three crates into their own repositories 2026-09-03 13:28:26 +02:00
Cargo.lock build: turn the three crates into a workspace 2026-09-01 22:20:42 +02:00
Cargo.toml refactor: split the three crates into their own repositories 2026-09-03 13:28:26 +02:00
LICENSE docs: add a README and the GPLv3 licence text 2026-09-01 22:20:42 +02:00
README.md ci: tirar a mutação do pipeline e rodar o CI inteiro no pre-commit 2026-09-05 07:41:17 +02:00

Batalha Naval

Batalha Naval multijogador com servidor em axum e cliente web em WebAssembly. Escrito como protótipo de curso de Rust.

Dois jogadores entram numa partida, posicionam a frota e alternam tiros até um deles afundar todos os navios do outro. A comunicação é por WebSocket.

Estrutura

Workspace com três crates, cada um em seu próprio submódulo git:

crate o que é repositório
battleship-common tipos, regras e protocolo — a biblioteca compartilhada battleship-common
battleship-server servidor axum com WebSocket, persistência em sled battleship-server
battleship-client cliente web em Yew, compilado para WebAssembly battleship-client
cargo run -p battleship-server        # sobe o servidor
cd battleship-client && trunk serve   # sobe o cliente

Como os crates são submódulos, depois de clonar:

git submodule update --init --recursive

Cada um tem o seu próprio pipeline, que responde a uma pergunta que esta build integrada não responde: o crate se sustenta sozinho? Por isso o servidor e o cliente declaram battleship-common pelo repositório dela, e não por caminho — sem isso um clone isolado nem compila. Dentro deste workspace o [patch] do Cargo.toml da raiz redireciona essa dependência de volta para o diretório ao lado, então a build integrada usa o código do submódulo, no SHA fixado aqui, e não a ponta de main.

Sobre o battleship-common

Vale um parágrafo, porque é o que este projeto ensina de mais caro.

Havia três cópias dos tipos do jogo: o servidor compilava contra uma cópia própria de 513 linhas, o cliente tinha outra em src/common.rs, e o battleship-common de verdade — 782 linhas, com testes — não era usado por ninguém. As cópias divergiram, e o jogo parou de funcionar ponta a ponta:

  • o envelope da mensagem (tag = "type" de um lado, com content = "data" do outro);
  • o nome da célula de água (Empty no servidor, Water no cliente);
  • o eixo em que um navio horizontal se estende.

Cada lado testava a sua própria cópia, e as duas suítes passavam. O defeito só aparecia com os dois processos no ar.

Hoje os três crates compartilham a biblioteca, e há testes cujo único propósito é impedir que a cópia volte: battleship-client/tests/spider compara byte a byte a serialização feita pelo caminho do cliente com a feita pela biblioteca.

Testes

cargo test --workspace                     # 265 testes
cargo test -p battleship-common --test spider
cargo mutants -p battleship-common         # índice de mutação: 0 sobreviventes

O cliente é wasm: os componentes Yew e o WebSocketService só rodam dentro de um navegador, e por isso ficam fora da conta de mutação (veja battleship-client/.cargo/mutants.toml). Para cobri-los é preciso teste de navegador:

cd battleship-client && wasm-pack test --headless --firefox

Verificações antes do commit

O .githooks/pre-commit roda aqui o que o Woodpecker roda no servidor. Ele é gerado a partir do .woodpecker/pipelines.yml deste repositório, então os comandos não podem divergir do CI. Ative uma vez por clone -- o hook é versionado, a configuração que aponta para ele não é:

git config core.hooksPath .githooks

Roda tudo a cada git commit, do mais barato ao mais caro, e para no primeiro que falhar: lint do pipeline, cargo fmt --check, clippy com -D warnings, build, testes, cobertura (piso 90%), auditoria de dependências e a perna MSRV 1.90.

O teste de mutação só existe aqui. Ele saiu do pipeline: mutação recompila o crate uma vez por mutante, e no runner isso eram dezenas de minutos por push, num passo que ninguém acompanha enquanto espera. O teto continua em .mutants-teto, versionado -- a regra não afrouxou, mudou de lugar. É de longe a etapa mais lenta; para pular só ela:

PRE_COMMIT_SEM_MUTACAO=1 git commit ...

Para pular tudo, git commit --no-verify. Um hook que não se pode pular é um hook que todo mundo desativa.

Licença

GPL-3.0-or-later. Veja LICENSE.