Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .cargo/mutants.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# cargo-mutants configuration (issue #33, full-crate pass 2026-07-17:
# 1555 mutants, 89 missed -> tests added for all killable ones).
#
# Excluded below: provably-equivalent `|`->`^` mutants. In every listed
# function the `|` operands have disjoint set bits (nibble/bit-field
# packs or shifted whole bytes), where OR and XOR are the same function
# — the #5-precedent equivalence class. Reviewed per function, not
# blanket: every `|` in each listed function is a disjoint-operand pack.
#
# Known-equivalent but NOT excluded (kept visible on purpose, expect
# them as "missed"): five `+ with -` mutants in validate.rs (party,
# boxes, level_exp_coherence x2, text_terminators) that add the layout
# constant COUNT == 0, where +0 == -0. A function-scoped exclude would
# also hide future real span-arithmetic regressions in those functions.
exclude_re = [
'replace \| with \^ in encode', # bcd: (hi<<4) | lo, lo < 16
'replace \| with \^ in SaveFile::set_current_box_number', # (byte & 0x80) | n, n < 12
'replace \| with \^ in MonView::exp', # b0<<16 | b1<<8 | b2
'replace \| with \^ in Dvs::pack', # (x&0xF)<<4 | (y&0xF)
'replace \| with \^ in Dvs::hp_dv', # four distinct single bits
'replace \| with \^ in compose_pp', # (ups&3)<<6 | (pp&0x3F)
'replace \| with \^ in SaveFile::set_text_speed', # (byte & 0xF0) | speed, speed < 8
]
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ e2e/fixtures/
e2e/.venv/
__pycache__/
.DS_Store
# cargo-mutants output (issue #33 runs)
mutants*.out/
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[workspace]
resolver = "2"
members = ["crates/pksave", "crates/pksave-app", "crates/xtask"]
# The fuzz crate (nightly + libFuzzer only) builds as its own workspace.
exclude = ["crates/pksave/fuzz"]

[workspace.package]
edition = "2021"
Expand Down
4 changes: 4 additions & 0 deletions crates/pksave/fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
target
corpus
artifacts
coverage
152 changes: 152 additions & 0 deletions crates/pksave/fuzz/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions crates/pksave/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "pksave-fuzz"
version = "0.0.0"
publish = false
edition = "2021"

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.4"

[dependencies.pksave]
path = ".."

[[bin]]
name = "save_walk"
path = "fuzz_targets/save_walk.rs"
test = false
doc = false
bench = false

# Its own workspace: the fuzz crate needs nightly + libFuzzer and must
# stay out of the stable-toolchain root workspace builds.
[workspace]
members = ["."]

[profile.release]
debug = 1
11 changes: 11 additions & 0 deletions crates/pksave/fuzz/fuzz_targets/save_walk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Coverage-guided sweep of the no-panic-from-file-contents guarantee:
//! parse arbitrary bytes and walk every view, accessor, diagnostic and
//! file-value-driven mutating path. The walk itself lives in
//! `pksave::fuzz_support` so it always compiles against the current API.
#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
pksave::fuzz_support::exercise(data);
});
Loading
Loading