diff --git a/.cargo/mutants.toml b/.cargo/mutants.toml index df3ba13..2a30685 100644 --- a/.cargo/mutants.toml +++ b/.cargo/mutants.toml @@ -5,18 +5,13 @@ test_tool = "nextest" # are sufficient to catch mutants. Full proptests run separately via just test-unit. additional_cargo_test_args = ["-E", "not test(proptests)"] -# Excluded mutants (false positives only): +# False positives excluded: # -# - legacy-msrv const_copy: dead code under default features, only compiled -# with --features legacy-msrv. Tested separately. +# - `> 0` → `>= 0` or `< 0` on usize: tautological (usize always >= 0) +# - `< 254` → `<= 254` in max_run: both branches yield 254 at the boundary # -# - usize `> 0` → `>= 0` or `< 0`: tautological on usize (always >= 0). -# -# - `< 254` → `<= 254` in max_run: both branches yield 254 when remaining -# is exactly 254, so the mutation is a semantic no-op. +# The legacy-msrv const_copy is excluded via #[mutants::skip] in source. exclude_re = [ - "in const_copy", - "replace const_copy with \\(\\)", "replace > with < in encode", "replace > with >= in encode", "replace < with <= in encode", diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ef24eb..d012007 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,15 @@ # Changelog -## 0.3.2 — 2026-03-31 +## 0.3.2 — 2026-04-01 ### Testing -- **Mutation testing passes clean** — 88 mutants tested, 59 caught, 0 missed. - Added targeted tests for 254-byte block boundary encoding and exact-fit - decode buffer sizing that close gaps found by `cargo-mutants`. -- **111 tests** (was 106): added block-boundary interop, exact-fit decode zeros, - and too-small decode zeros tests. +- **Mutation testing: 100% kill rate** — 89 mutants tested, 59 caught, 30 + unviable (type system rejects them), 0 missed. Uses `cargo-mutants` v27 + with nextest. Added `mutants` crate for `#[mutants::skip]` annotations. +- **111 tests** (was 106): added block-boundary interop verification against + corncobs, exact-fit and too-small decode buffer sizing for the batch zero + path. ## 0.3.1 — 2026-03-31 diff --git a/Cargo.toml b/Cargo.toml index 42b767c..f2c1a37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ all-features = true cobs = "0.5" corncobs = "0.1" iai-callgrind = "0.16" +mutants = "0.0.4" proptest = "1" rand = "0.10" diff --git a/README.md b/README.md index c11acca..b3707ee 100644 --- a/README.md +++ b/README.md @@ -295,8 +295,8 @@ affected — it uses a byte loop instead of `copy_from_slice`/memcpy. structural/algebraic properties, and boundary-region behavior - **Fuzz targets** — 3 `cargo-fuzz` harnesses (decode, round-trip, small-dest) for continuous coverage of edge cases -- **Mutation testing** — `cargo-mutants` verifies that the test suite catches - injected bugs in every reachable code path +- **Mutation testing** — `cargo-mutants` with 100% kill rate (59/59 viable + mutants caught; 30 more rejected by the type system) - **Boundary tests** — exhaustive coverage of 254/255-byte block boundaries, multi-block splits, buffer-exact fits, and off-by-one dest sizes - **Compile-time verification** — `const` assertions that validate encode diff --git a/src/lib.rs b/src/lib.rs index 2802097..334e0ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,6 +167,7 @@ const fn const_copy(dest: &mut [u8], di: usize, src: &[u8], n: usize) { } /// Fallback const copy for toolchains older than Rust 1.93. +#[mutants::skip] // dead code under default features; tested via --features legacy-msrv #[inline(always)] #[cfg(feature = "legacy-msrv")] const fn const_copy(dest: &mut [u8], di: usize, src: &[u8], n: usize) { @@ -842,7 +843,7 @@ mod tests { let encoded = enc(&input).unwrap(); assert_eq!(encoded[0], 0xFF); // code byte for full 254-byte block assert_eq!(encoded.len(), 255); // 1 code byte + 254 data bytes - // Verify it round-trips + // Verify it round-trips let mut dec = vec![0u8; 256]; let n = decode(&encoded, &mut dec).unwrap(); assert_eq!(&dec[..n], &input[..]);