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
+81
View File
@@ -638,6 +638,87 @@ mod tests {
assert!(audio.is_empty() || audio.iter().all(|l| l.stream_number <= 512));
}
/// Spec: the FPL section also ends on an `SF_` marker (not just
/// `SEG_`/`FPL_`). Only `assign_labels_fpl_section_ends_on_seg_boundary`
/// existed before, which cannot distinguish a mutated `||` chain from
/// the correct one (any single true operand already ends the section).
/// This test isolates the `SF_` alternative specifically.
/// Mutation: `||` -> `&&` in the end-of-section check would require
/// ALL THREE prefixes to match simultaneously (impossible for a real
/// single token), so the section would never end on `SF_` alone.
#[test]
fn assign_labels_fpl_section_ends_on_sf_boundary() {
let mut flag = false;
let tokens = strs(&[
"FPL_MainFeature",
"eng_MLP_",
"SF_Something", // must end the FPL section
"fra_AC3_", // must NOT be parsed
]);
let labels = assign_labels(&tokens, &mut flag);
assert_eq!(labels.len(), 1, "only eng from FPL section");
assert_eq!(labels[0].language, "eng");
}
/// Spec: the two per-type caps are independent — the loop only stops
/// early once BOTH audio and subtitle counters have reached
/// `MAX_STREAMS_PER_TYPE`. Reaching the audio cap alone must not cut
/// off subtitle processing.
/// Mutation: `&&` -> `||` in the outer stop-condition would break the
/// loop as soon as EITHER counter reaches the cap, silently dropping
/// a legitimate subtitle stream that comes after audio saturates.
#[test]
fn assign_labels_audio_cap_alone_does_not_stop_subtitle_processing() {
let mut flag = false;
let mut tokens = vec!["FPL_MainFeature".to_string()];
for i in 1..=(MAX_STREAMS_PER_TYPE as usize) {
tokens.push(format!("Audio Stream {}", i));
}
// Subtitle counter is still 0 here — well under the cap.
tokens.push("eng_SDH_".to_string());
let labels = assign_labels(&tokens, &mut flag);
let subs: Vec<_> = labels
.iter()
.filter(|l| l.stream_type == StreamLabelType::Subtitle)
.collect();
assert_eq!(
subs.len(),
1,
"a subtitle stream after the audio cap (but under the subtitle \
cap) must still be labeled"
);
}
/// Companion to the above: with the subtitle counter saturated but
/// audio still under its cap, a subsequent audio token must still be
/// processed. Isolates the first `>=` operand (`audio_num >=
/// MAX_STREAMS_PER_TYPE`) from the second.
/// Mutation: `audio_num >= MAX_STREAMS_PER_TYPE` -> `audio_num <
/// MAX_STREAMS_PER_TYPE` would flip the stop-condition to trigger
/// whenever audio is UNDER cap and subtitle is AT/over cap — exactly
/// this scenario — dropping the trailing audio token.
#[test]
fn assign_labels_subtitle_cap_alone_does_not_stop_audio_processing() {
let mut flag = false;
let mut tokens = vec!["FPL_MainFeature".to_string()];
for _ in 1..=(MAX_STREAMS_PER_TYPE as usize) {
tokens.push("eng_SDH_".to_string());
}
// Audio counter is still 0 here — well under the cap.
tokens.push("fra_MLP_".to_string());
let labels = assign_labels(&tokens, &mut flag);
let audio: Vec<_> = labels
.iter()
.filter(|l| l.stream_type == StreamLabelType::Audio)
.collect();
assert_eq!(
audio.len(),
1,
"an audio stream after the subtitle cap (but under the audio \
cap) must still be labeled"
);
}
/// Spec: subtitle placeholders (PG Stream N) do NOT advance the subtitle counter.
/// Only audio placeholders (`Audio Stream N`) do.
/// Mutation: also advance sub counter on PG placeholder → subtitle labels misnumbered.