test: constrain MP4 composition timing, MLP substream directory, and codec-private absence

Mutation testing over src/mux/. No production change — 49 survivors
killed, all proven red before green.

The MP4 composition-time chain was entirely unconstrained: VideoTiming::ctts,
build_ctts and parse_ctts could each return a constant and the suite
stayed green. Confirmed on HEAD: build_ctts -> vec![] passes all 1,220
mux tests. A demuxed B-frame title presenting in decode order would
have shipped.

The cause is a test whose name asserts coverage its body does not
deliver — stts_and_ctts_expand builds an stts box and never touches
ctts, and write_then_read_round_trip asserts sample sizes and keyframe
flags but not one PTS. Same shape as the set_speed forwarding finding,
different disguise.

mlp_num_substreams / mlp_substr_header_size: every TrueHD fixture in
the crate uses one substream and no extraword, so both could return a
constant and agree with all of them. These position mlp_parity_ok's
window over the AU header, so a constant mis-windows the parity check
on exactly the multi-substream AUs that carry 7.1 and Atmos.

CodecPrivate absent vs empty: mkv.rs writes Some(bytes) verbatim and
omits the element on None (RFC 9559 5.1.4.1.24), so a zero-length Some
emits a track header asserting the config IS empty. Four parsers could
return Some(vec![]) before any frame.

Also: mandatory ISO/IEC 14496-12 boxes (tkhd, vmhd, smhd, dinf, mdhd)
could each build empty; HEVC num_extra_slice_header_bits (H.265 7.3.2.3)
was never non-zero in any fixture, so the slice-type offset skip was
unexercised; chapter names from the disc go straight into
<ChapterString> and the & escape must run first; a stray 0x47 in a
payload must not latch a TS resync.

Documented as equivalent rather than killed: CodecParser::flush and the
three parser flush bodies that differ from the mutant only by a tracing
call, and DropTally::log_summary.
This commit is contained in:
Matthew Jackson
2026-07-30 13:39:02 -07:00
parent 55b97ac576
commit 170fd0c064
14 changed files with 1027 additions and 0 deletions
+25
View File
@@ -200,6 +200,31 @@ mod tests {
assert!(!t.is_poisoned());
}
/// The poison verdict is a RATIO — verified drops against every AU seen — so
/// the kept count is half of it. `does_not_poison_a_mostly_good_track` above
/// records its keeps AFTER the single drop, and `maybe_poison` only runs
/// inside `record_drop`, so the keeps are never in the denominator when the
/// verdict is actually computed: that test passes even with the kept count
/// never incremented. Interleaving them puts the kept count on the critical
/// path, where losing it turns the ratio into "verified drops vs verified
/// drops" — always >50% — and silently discards a healthy track.
#[test]
fn interleaved_keeps_are_in_the_poison_denominator() {
let mut t = DropTally::new("test");
// 2 kept per 1 dropped, well past the minimum-AU gate: a third of the
// track is undecodable, which is bad but nowhere near the >50% threshold.
for _ in 0..(TRACK_VERDICT_MIN_AUS * 3) {
t.record_kept();
t.record_kept();
t.record_drop(0, 1000, 512, "bad");
assert!(
!t.is_poisoned(),
"33% dropped must never poison, at any point in the run"
);
}
assert_eq!(t.dropped_frames(), TRACK_VERDICT_MIN_AUS * 3);
}
#[test]
fn collateral_drops_never_poison_the_track() {
// A TrueHD resync-forward run collaterally drops a long burst of AUs, but