test: salvage the orphaned labels/disc triage, and extract build_labels

Thirteen agents triaging src/labels and src/disc died on a saturated
machine, leaving 5,836 insertions across 28 files uncommitted in a
worktree. Recovered by 3-way apply onto twelve commits of drift; zero
conflicts. The diff was archived to freemkv-private first, because a
worktree is not a backup and this one had already nearly been lost.

One production change, and it is the right one: mpls_universal::parse
read every playlist off the disc AND converted the entries to labels in
a single function, so the conversion — stream-type mapping, dedup key,
the dense global counters — could only be reached through a synthetic
UDF image. Extracted to build_labels(&[Playlist]), which unit tests can
drive from already-parsed values. Behaviour-preserving: same iteration
order, same skip-on-error.

Two collisions resolved by hand:

A second mod pass_progress_tests, written independently against the
same survivors as the one committed in c610285. Kept mine — it covers
the distinct-counters case and the Progress blanket impl, which theirs
does not — but theirs had three clamp tests mine lacked: good_pct,
bad_pct and pending_pct also clamp an overshoot, and I had only tested
that for work_pct. Merged those in as one test and proved each of the
three clamps load-bearing by removing them individually.

An unused_parens warning in a new fixture.

Method note, recorded because it cost real time: git apply --3way
STAGES its result, so `git diff` reads empty and the tree looks
untouched. I nearly concluded the patch had silently failed. Worse, the
first attempt piped through `head -20`, so `echo exit=$?` reported
head's status rather than git's — the same mistake this audit has
already documented once. Check the real exit status, and check
--cached, not just the working tree.
This commit is contained in:
Matthew Jackson
2026-07-30 16:36:13 -07:00
parent 8b8bcff106
commit 5360f8d309
28 changed files with 5717 additions and 75 deletions
+511
View File
@@ -963,6 +963,24 @@ mod tests {
sniff_video_codec(&[0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00]),
None
);
// Every byte of the `00 00 01` marker is load-bearing: a near-miss
// that gets ANY one of the three bytes wrong must not be recognized.
assert_eq!(
sniff_video_codec(&[0x05, 0x00, 0x01, 0xB3]),
None,
"leading byte must be 0x00, not just any byte"
);
assert_eq!(
sniff_video_codec(&[0x00, 0x05, 0x01, 0xB3]),
None,
"second byte must be 0x00, not just any byte"
);
assert_eq!(
sniff_video_codec(&[0x00, 0xFF, 0x01, 0xB3]),
None,
"the middle byte of the marker must actually be checked, not skipped"
);
}
#[test]
@@ -972,6 +990,13 @@ mod tests {
Some(Codec::Ac3Plus)
);
assert_eq!(sniff_audio_codec(&[0x00, 0x01, 0x02, 0x03]), None);
// Both syncword bytes are required together: a lone 0x0B with no 0x77
// partner anywhere must not be recognized.
assert_eq!(
sniff_audio_codec(&[0x0B, 0x00, 0x0B, 0x01]),
None,
"0x0B alone (no 0x77 partner) is not the E-AC-3 syncword"
);
}
// ── EVO head probe → streams ──────────────────────────────────────────
@@ -1394,4 +1419,490 @@ mod tests {
// Both feature halves are in ONE title's extents.
assert!(!mm.extents.is_empty());
}
// ── parse_vti_clip_order: bound / cap / termination edge cases ────────
/// The outer scan cap (`MAX_VTI_HITS`) must be exact, not off-by-one. Every
/// entry here is stride-aligned so they ALL land in one residue bucket —
/// unlike the scattered-token cap test above, the cap is directly visible
/// in the output length (the total scanned-hit count IS the bucket size).
#[test]
fn parse_vti_clip_order_caps_hits_at_exact_boundary_same_residue() {
let table_start = 0x200usize;
let n = MAX_VTI_HITS + 50;
let mut v = vec![0u8; table_start + n * VTI_CLIP_ENTRY_STRIDE];
v[..HDDVD_VTI_MAGIC.len()].copy_from_slice(HDDVD_VTI_MAGIC);
for i in 0..n {
let off = table_start + i * VTI_CLIP_ENTRY_STRIDE + 0x42;
v[off..off + b"X.EVO".len()].copy_from_slice(b"X.EVO");
}
let out = parse_vti_clip_order(&v);
assert_eq!(
out.len(),
MAX_VTI_HITS,
"the scan must stop at exactly MAX_VTI_HITS, not one past it"
);
}
/// A name-byte run that reaches the exact end of the buffer with NO NUL
/// terminator must not be read out of bounds — the inner scan (and the
/// nul-terminated check) must stop at the buffer boundary rather than
/// indexing one past it.
#[test]
fn parse_vti_clip_order_handles_unterminated_name_run_at_buffer_end() {
let mut v = HDDVD_VTI_MAGIC.to_vec();
v.extend_from_slice(b"TRAILING_JUNK_NO_TERMINATOR"); // all ascii-graphic, no NUL, ends at EOF
let out = parse_vti_clip_order(&v);
assert!(
out.is_empty(),
"unterminated trailing run yields no entries (and must not panic)"
);
}
/// A `.EVO`-suffixed name run followed by an in-bounds byte that is NOT a
/// NUL must not be treated as terminated — being merely in-bounds is not
/// the same as actually finding a NUL.
#[test]
fn parse_vti_clip_order_requires_actual_nul_terminator_not_just_in_bounds() {
let mut v = HDDVD_VTI_MAGIC.to_vec();
v.extend_from_slice(b"FEATURE.EVO");
v.push(0x01); // in-bounds terminator byte, but NOT a NUL
v.extend_from_slice(&[0u8; 16]);
let out = parse_vti_clip_order(&v);
assert!(
out.is_empty(),
"a non-NUL byte after .EVO must not count as terminated"
);
}
/// A NUL-terminated ascii run that does NOT end in ".EVO" must never be
/// collected, no matter how many repeat at a shared residue: nul-
/// termination and the `.EVO`-suffix check are independent gates, one must
/// not short-circuit the other away.
#[test]
fn parse_vti_clip_order_rejects_nul_terminated_names_without_evo_suffix() {
let mut v = HDDVD_VTI_MAGIC.to_vec();
for _ in 0..20 {
v.extend_from_slice(b"HELLO\0"); // nul-terminated, 5 bytes, not .EVO
}
let out = parse_vti_clip_order(&v);
assert!(
out.is_empty(),
"non-.EVO nul-terminated names must not be collected"
);
}
/// A short (<4-byte) nul-terminated name run must be rejected by the
/// length guard BEFORE the `.EVO`-suffix slice runs — slicing a name
/// shorter than 4 bytes at `name.len() - 4` would otherwise underflow.
/// Must not panic, and must not be collected.
#[test]
fn parse_vti_clip_order_short_circuits_length_check_before_slicing_short_names() {
let mut v = HDDVD_VTI_MAGIC.to_vec();
v.push(b' '); // non-name-byte separator: isolates "AB" from the magic run
v.extend_from_slice(b"AB\0"); // 2-byte name, under the 4-byte slice width
let out = parse_vti_clip_order(&v);
assert!(
out.is_empty(),
"short name is rejected without slicing/panicking"
);
}
// ── EVO_ES_SAMPLE_CAP / collect_es capping ─────────────────────────────
/// The documented sample cap is 128 KiB, i.e. `128 * 1024`.
#[test]
fn evo_es_sample_cap_is_128_kib() {
assert_eq!(EVO_ES_SAMPLE_CAP, 128 * 1024);
}
/// Plain-video-range (`0xE0..=0xEF`) samples stop growing once the buffer
/// has reached the cap — a subsequent packet must not push it past.
#[test]
fn collect_es_caps_video_sample_at_the_length_cap() {
use crate::consts::pes_stream_id::VIDEO;
let mut video = Vec::new();
let mut video_pid: Option<u16> = None;
let mut audio = BTreeMap::new();
collect_es(
&ps_pkt(VIDEO, None, vec![0xAA; EVO_ES_SAMPLE_CAP]),
&mut video,
&mut video_pid,
&mut audio,
);
assert_eq!(video.len(), EVO_ES_SAMPLE_CAP);
collect_es(
&ps_pkt(VIDEO, None, vec![0xBB; 16]),
&mut video,
&mut video_pid,
&mut audio,
);
assert_eq!(
video.len(),
EVO_ES_SAMPLE_CAP,
"no further growth once at the cap"
);
}
/// The VC-1 extended-stream-id (0xFD, ext 0x55) video branch has its own
/// cap check; it must behave identically to the plain-video branch.
#[test]
fn collect_es_caps_vc1_video_sample_at_the_length_cap() {
let mut video = Vec::new();
let mut video_pid: Option<u16> = None;
let mut audio = BTreeMap::new();
collect_es(
&ps_pkt(0xFD, Some(0x55), vec![0xAA; EVO_ES_SAMPLE_CAP]),
&mut video,
&mut video_pid,
&mut audio,
);
assert_eq!(video.len(), EVO_ES_SAMPLE_CAP);
collect_es(
&ps_pkt(0xFD, Some(0x55), vec![0xBB; 16]),
&mut video,
&mut video_pid,
&mut audio,
);
assert_eq!(
video.len(),
EVO_ES_SAMPLE_CAP,
"no further growth once at the cap (VC-1 0xFD branch)"
);
}
/// The per-sub-id audio branch has its own cap check; same requirement.
#[test]
fn collect_es_caps_audio_sample_at_the_length_cap() {
use crate::consts::pes_stream_id::PRIVATE_STREAM_1;
let mut video = Vec::new();
let mut video_pid: Option<u16> = None;
let mut audio = BTreeMap::new();
collect_es(
&ps_pkt(PRIVATE_STREAM_1, Some(0xC0), vec![0xAA; EVO_ES_SAMPLE_CAP]),
&mut video,
&mut video_pid,
&mut audio,
);
assert_eq!(audio[&0xC0].len(), EVO_ES_SAMPLE_CAP);
collect_es(
&ps_pkt(PRIVATE_STREAM_1, Some(0xC0), vec![0xBB; 16]),
&mut video,
&mut video_pid,
&mut audio,
);
assert_eq!(
audio[&0xC0].len(),
EVO_ES_SAMPLE_CAP,
"no further growth once at the cap (audio branch)"
);
}
// ── read_adv_obj_xpl: prefix AND suffix are both required ──────────────
/// A file matching the `vplst` prefix but NOT the `.xpl` suffix must not
/// be adopted as the playlist — both conditions are independently
/// required, one must not be short-circuited away by the other.
#[test]
fn read_adv_obj_xpl_requires_both_vplst_prefix_and_xpl_suffix() {
let mut disc = MemDisc::new();
let root = DirSpec {
name: String::new(),
icb_lba: 10,
dir_data_lba: 11,
files: Vec::new(),
subdirs: vec![DirSpec {
name: "ADV_OBJ".to_string(),
icb_lba: 30,
dir_data_lba: 31,
files: vec![file_with(
"VPLST_NOTES.TXT",
40,
4000,
b"not a playlist".to_vec(),
true,
)],
subdirs: vec![],
}],
};
build_udf_skeleton(&mut disc, 10);
lay_dir(&mut disc, &root);
let udf = crate::udf::read_filesystem(&mut disc).expect("fs");
assert!(
read_adv_obj_xpl(&mut disc, &udf).is_none(),
"prefix match alone (not ending .xpl) must not select a file"
);
}
// ── compose_xpl_titles: size/offset arithmetic ─────────────────────────
/// Direct unit test of the arithmetic composing a title from its XPL
/// clips: clip sizes are SUMMED (not multiplied), title-time in/out ticks
/// are `seconds * 45000` (not divided), and `duration_secs` is
/// `end - begin` (not `end + begin` or a division).
#[test]
fn compose_xpl_titles_sums_sizes_and_computes_in_out_times() {
let clip_extents: BTreeMap<String, (String, u64, Vec<Extent>)> = [
(
"a.evo".to_string(),
(
"A.EVO".to_string(),
1000u64,
vec![Extent {
start_lba: 1,
sector_count: 1,
}],
),
),
(
"b.evo".to_string(),
(
"B.EVO".to_string(),
2000u64,
vec![Extent {
start_lba: 2,
sector_count: 1,
}],
),
),
]
.into_iter()
.collect();
let xpl_titles = vec![XplTitle {
number: 1,
name: "T".to_string(),
duration_secs: 10.0,
clips: vec![
XplClip {
evo: "a.evo".to_string(),
begin_secs: 2.0,
end_secs: 5.0,
},
XplClip {
evo: "b.evo".to_string(),
begin_secs: 5.0,
end_secs: 9.0,
},
],
chapters: vec![],
}];
let mut disc = MemDisc::new();
let titles = compose_xpl_titles(&mut disc, &xpl_titles, &clip_extents);
assert_eq!(titles.len(), 1);
let t = &titles[0];
assert_eq!(t.size_bytes, 3000, "clip sizes summed, not multiplied");
assert_eq!(
t.clips[0].in_time,
(2.0f64 * 45000.0) as u32,
"in_time is begin_secs * 45000, not divided"
);
assert_eq!(
t.clips[0].out_time,
(5.0f64 * 45000.0) as u32,
"out_time is end_secs * 45000, not divided"
);
assert!(
(t.clips[0].duration_secs - 3.0).abs() < 1e-9,
"duration_secs is end_secs - begin_secs, not +/÷: got {}",
t.clips[0].duration_secs
);
assert!(
(t.clips[1].duration_secs - 4.0).abs() < 1e-9,
"second clip's duration is also end - begin: got {}",
t.clips[1].duration_secs
);
}
// ── Disc::scan_hddvd_titles: VTI-selection / extent-filter guards ──────
/// A file carrying the real `ADVANCED-VTS` magic but the WRONG extension
/// (not `.vti`) must never be adopted as the navigation file. Absent a
/// real `.vti` file, the scan must fall back to one title per clip (no
/// VTI-driven feature composition) rather than trusting a same-content
/// impostor by name-agnostic magic alone.
#[test]
fn scan_hddvd_titles_ignores_a_vti_look_alike_with_the_wrong_extension() {
let mut disc = MemDisc::new();
let vti_bytes = synthetic_vti(&["FEATURE_1.EVO", "FEATURE_2.EVO"]);
let files = vec![
file_with("IMPOSTER.DAT", 90, 20000, vti_bytes, true),
file("FEATURE_1.EVO", 100, 5000, 10 * 2048, true),
file("FEATURE_2.EVO", 101, 8000, 6 * 2048, true),
];
let root = DirSpec {
name: String::new(),
icb_lba: 10,
dir_data_lba: 11,
files: Vec::new(),
subdirs: vec![DirSpec {
name: "HVDVD_TS".to_string(),
icb_lba: 20,
dir_data_lba: 21,
files,
subdirs: vec![],
}],
};
build_udf_skeleton(&mut disc, 10);
lay_dir(&mut disc, &root);
let udf = crate::udf::read_filesystem(&mut disc).expect("fs");
let titles = Disc::scan_hddvd_titles(&mut disc, &udf);
assert_eq!(
titles.len(),
2,
"no real .vti present -> no VTI-driven composition, one title per clip"
);
}
/// A clip whose file has a zero-byte size (a degenerate/empty allocation:
/// its ICB's allocation descriptor has `data_len == 0`, the UDF AD-list
/// terminator, so `file_extents` yields no extent at all) must not
/// produce a title. NOTE: this exercises the *upstream* `data_len == 0`
/// terminator path in [`crate::udf::UdfFs::file_extents`], not the
/// `sectors > 0 && lba > 0` guard in `scan_hddvd_titles` itself — with
/// this fixture (`file_extents` never returns a `(lba, 0)` tuple, and
/// `PART_START` unconditionally makes every resolved `lba` positive)
/// that guard is unreachable in a divergent way; kept here as a
/// regression check on the zero-byte-file behavior in its own right.
#[test]
fn scan_hddvd_titles_excludes_a_clip_with_zero_sectors() {
let mut disc = MemDisc::new();
let files = vec![
file("REAL.EVO", 100, 5000, 4 * 2048, true), // ordinary, valid clip
file("BOGUS.EVO", 101, 9000, 0, true), // size 0 -> zero-sector extent
];
let root = DirSpec {
name: String::new(),
icb_lba: 10,
dir_data_lba: 11,
files: Vec::new(),
subdirs: vec![DirSpec {
name: "HVDVD_TS".to_string(),
icb_lba: 20,
dir_data_lba: 21,
files,
subdirs: vec![],
}],
};
build_udf_skeleton(&mut disc, 10);
lay_dir(&mut disc, &root);
let udf = crate::udf::read_filesystem(&mut disc).expect("fs");
let titles = Disc::scan_hddvd_titles(&mut disc, &udf);
assert_eq!(
titles.len(),
1,
"the zero-sector clip must not produce a title"
);
assert_eq!(titles[0].playlist, "REAL.EVO");
}
// ── probe_evo_streams: sector-cursor bookkeeping ───────────────────────
/// A zero-sector extent must be skipped outright, never entering the read
/// loop — `left` (an unsigned sector count) starting at 0 must gate the
/// loop closed. (A `left >= 0` tautology here would spin forever: `n`
/// would be pinned at 0, so neither `lba`, `left`, nor `remaining` would
/// ever change — a non-terminating loop reachable from a crafted extent
/// list.)
#[test]
fn probe_evo_streams_skips_a_zero_sector_extent_without_reading() {
let mut disc = MemDisc::new();
let extent = Extent {
start_lba: 500_000,
sector_count: 0,
};
let streams = probe_evo_streams(&mut disc, std::slice::from_ref(&extent));
assert!(streams.is_empty(), "a zero-sector extent yields no streams");
}
/// The read cursor must advance FORWARD by each chunk's sector count, not
/// backward — real content living only in the second 512-sector (1 MiB)
/// chunk must be reached.
#[test]
fn probe_evo_streams_advances_lba_forward_across_chunk_reads() {
let mut disc = MemDisc::new();
let start_lba = 100_000u32;
// First chunk (512 sectors): inert filler, no start codes.
disc.put_bytes(start_lba, &vec![0x55u8; 512 * 2048]);
// Second chunk: the real EVO content (H.264 video PES).
let evo = synthetic_evo();
disc.put_bytes(start_lba + 512, &evo);
let extent = Extent {
start_lba,
sector_count: 512 + (evo.len() as u32).div_ceil(2048),
};
let streams = probe_evo_streams(&mut disc, std::slice::from_ref(&extent));
let has_h264 = streams
.iter()
.any(|s| matches!(s, Stream::Video(v) if v.codec == Codec::H264));
assert!(
has_h264,
"the second 1 MiB chunk must be read from the correct (forward) LBA"
);
}
/// The read loop must stop at the extent's DECLARED `sector_count` — data
/// living just past it must never be read (a buffer over-read past the
/// caller-supplied extent bound, on untrusted disc-layout input).
#[test]
fn probe_evo_streams_stops_reading_at_the_extents_declared_sector_count() {
let mut disc = MemDisc::new();
let start_lba = 200_000u32;
let declared_sectors = 4u32;
disc.put_bytes(start_lba, &vec![0x55u8; declared_sectors as usize * 2048]);
// Real H.264 PES data placed just PAST the declared extent — must
// never be read.
let evo = synthetic_evo();
disc.put_bytes(start_lba + declared_sectors, &evo);
let extent = Extent {
start_lba,
sector_count: declared_sectors,
};
let streams = probe_evo_streams(&mut disc, std::slice::from_ref(&extent));
let has_h264 = streams
.iter()
.any(|s| matches!(s, Stream::Video(v) if v.codec == Codec::H264));
assert!(
!has_h264,
"must not read past the extent's declared sector_count"
);
}
/// The total read budget (`EVO_PROBE_SECTORS`) must be enforced ACROSS
/// extents, not just within one — once it is exhausted by an earlier
/// extent, a later extent in the same probe must not be read at all.
#[test]
fn probe_evo_streams_caps_total_reads_across_extents_at_evo_probe_sectors() {
let mut disc = MemDisc::new();
let first_lba = 300_000u32;
disc.put_bytes(first_lba, &vec![0x55u8; EVO_PROBE_SECTORS as usize * 2048]);
// A second extent, following the first in the extents list: once the
// whole EVO_PROBE_SECTORS budget is spent on the first, this must
// never be reached.
let second_lba = first_lba + EVO_PROBE_SECTORS;
let evo = synthetic_evo();
disc.put_bytes(second_lba, &evo);
let extents = vec![
Extent {
start_lba: first_lba,
sector_count: EVO_PROBE_SECTORS,
},
Extent {
start_lba: second_lba,
sector_count: 10,
},
];
let streams = probe_evo_streams(&mut disc, &extents);
let has_h264 = streams
.iter()
.any(|s| matches!(s, Stream::Video(v) if v.codec == Codec::H264));
assert!(
!has_h264,
"must not read past the total EVO_PROBE_SECTORS budget across extents"
);
}
}