Skip to content

Mutation testing: fragmentation encode path and frame conversion survivors #596

Description

@leynos

Context

From the first complete full mutation-testing run (ADR-007 shared workflow, run 29074771985, 2026-07-10, main @ 94a5d44). The fragmentation encode path has untested boundaries, two unused public helpers, and an undispatched trait impl; the shared frame-length decoder misses a length-mismatch case.

Surviving mutants

  • src/fragment/series.rs:37replace FragmentSeries::is_complete -> bool with true
  • src/fragment/fragmenter.rs:146replace > with >= in Fragmenter::build_fragments_from
  • src/fragment/fragmenter.rs:155replace < with <= in Fragmenter::build_fragments_from
  • src/fragment/fragmenter.rs:262replace FragmentBatch::into_fragments -> Vec<FragmentFrame> with vec![]
  • src/fragment/config.rs:58replace encoded_fragment_ceiling -> usize with 0 / 1, replace + with * / -
  • src/fragment/adapter.rs:133replace <impl FragmentAdapter for DefaultFragmentAdapter>::purge_expired -> Vec<MessageId> with vec![]
  • src/frame/conversion.rs:83replace < with > in bytes_to_u64

Analysis

is_complete() is only ever asserted true (and accept() reads the field directly, not the method). The fragmenter's offset == total boundary is untested: the original returns Ok(vec![]), the >= mutant errors with SliceBounds, and the <= mutant emits a spurious empty is_last fragment. into_fragments and encoded_fragment_ceiling are public helpers with zero callers in the crate or tests. The FragmentAdapter trait impl of purge_expired is never dispatched — FragmentationState aliases the concrete type, so all calls bind the inherent method. In bytes_to_u64, every passing test uses bytes.len() == size and the short cases still error under the mutant via bytes.get(..size); only bytes.len() > size distinguishes it.

Suggested tests / deletions

  1. Assert !FragmentSeries::new(id).is_complete() (and after a non-final fragment).
  2. Fragment with a cursor positioned at offset == total; assert Ok with an empty fragment vector (kills both fragmenter boundary mutants).
  3. Either test into_fragments (fragment a known payload; assert length and contents) or delete it in favour of the tested IntoIterator path.
  4. Either assert encoded_fragment_ceiling() == fragment_payload_cap + fragment_overhead() with values where sum, product, and difference all differ, or delete the unused helper.
  5. Either delete the undispatched FragmentAdapter trait impl (and the trait, if dynamic dispatch is not intended API) or add a test calling through &mut dyn FragmentAdapter and asserting the evicted identifiers.
  6. Add a bytes_to_u64 case with trailing bytes, e.g. bytes_to_u64(&[0x12, 0x34, 0xFF, 0xFF], 2, Endianness::Big) == 0x1234.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmediumCould be disruptive, but might not happentesting

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions