libfreemkv 0.31.2: comprehensive spec-grounded test suite (~950 tests)
Test-hardening release, no runtime changes. Adds spec-grounded unit tests across the silent-corruption surfaces — UDF/MPLS/CLPI/IFO parsing, BD/DVD title + extent assembly, AACS/CSS key handling, TS/PS demux + codec parsers, MKV/EBML container output, the mux pipeline, sector prefetch + decrypt decorator, drive/SCSI sense decoding, label extraction, and core I/O. Each test is grounded in the format spec or real on-disc behavior and verified to fail under a targeted source mutation. No behavior changed.
This commit is contained in:
@@ -318,4 +318,156 @@ mod tests {
|
||||
assert_eq!(m, 1);
|
||||
assert_eq!(d, 1);
|
||||
}
|
||||
|
||||
// ── Additional hardening tests ─────────────────────────────────────────
|
||||
|
||||
/// Spec: coding_type mismatch with matching language → Divergent (not Match).
|
||||
/// The spec doc says both coding_type AND language must agree for Match.
|
||||
/// Mutation: only check language for match → coding_type mismatch silently classified as Match.
|
||||
#[test]
|
||||
fn class_divergent_on_coding_type_mismatch_same_lang() {
|
||||
let r = ClpiVsMplsRow {
|
||||
pid: 0x1100,
|
||||
clpi_coding_type: Some(0x83), // TrueHD
|
||||
clpi_language: Some("eng".into()),
|
||||
mpls_coding_type: Some(0x86), // DTS-HD MA
|
||||
mpls_language: Some("eng".into()),
|
||||
};
|
||||
assert_eq!(r.class(), ClpiVsMplsClass::Divergent);
|
||||
}
|
||||
|
||||
/// Spec: empty rows → class_counts returns (0,0,0,0). Never panics on empty audit.
|
||||
/// Mutation: access rows[0] unconditionally → panic on empty audit.
|
||||
#[test]
|
||||
fn class_counts_empty_audit() {
|
||||
let audit = ClpiVsMplsAudit { rows: Vec::new() };
|
||||
let (co, mo, m, d) = audit.class_counts();
|
||||
assert_eq!((co, mo, m, d), (0, 0, 0, 0));
|
||||
}
|
||||
|
||||
/// Spec: (false, false) branch — both coding_types absent, equal language → Match.
|
||||
/// The spec comment says "compare language fields; Divergent if they differ, else Match".
|
||||
/// Mutation: return Divergent for any (false, false) case → this test goes red.
|
||||
#[test]
|
||||
fn class_both_coding_absent_equal_none_lang_is_match() {
|
||||
let r = ClpiVsMplsRow {
|
||||
pid: 0x1100,
|
||||
clpi_coding_type: None,
|
||||
clpi_language: None,
|
||||
mpls_coding_type: None,
|
||||
mpls_language: None,
|
||||
};
|
||||
// Both languages are None == None → Match.
|
||||
assert_eq!(r.class(), ClpiVsMplsClass::Match);
|
||||
}
|
||||
|
||||
/// Spec: all four classes form an exhaustive disjoint cover.
|
||||
/// This test verifies the discriminant logic using boundary coding_type values.
|
||||
/// Mutation: swap the ClpiOnly/MplsOnly branches → wrong classification.
|
||||
#[test]
|
||||
fn class_boundary_coding_types_all_four_classes_reachable() {
|
||||
let clpi_only = ClpiVsMplsRow {
|
||||
pid: 1,
|
||||
clpi_coding_type: Some(1),
|
||||
clpi_language: None,
|
||||
mpls_coding_type: None,
|
||||
mpls_language: None,
|
||||
};
|
||||
let mpls_only = ClpiVsMplsRow {
|
||||
pid: 2,
|
||||
clpi_coding_type: None,
|
||||
clpi_language: None,
|
||||
mpls_coding_type: Some(1),
|
||||
mpls_language: None,
|
||||
};
|
||||
let match_ = ClpiVsMplsRow {
|
||||
pid: 3,
|
||||
clpi_coding_type: Some(0x83),
|
||||
clpi_language: Some("eng".into()),
|
||||
mpls_coding_type: Some(0x83),
|
||||
mpls_language: Some("eng".into()),
|
||||
};
|
||||
let divergent = ClpiVsMplsRow {
|
||||
pid: 4,
|
||||
clpi_coding_type: Some(0x83),
|
||||
clpi_language: Some("eng".into()),
|
||||
mpls_coding_type: Some(0x83),
|
||||
mpls_language: Some("fra".into()),
|
||||
};
|
||||
assert_eq!(clpi_only.class(), ClpiVsMplsClass::ClpiOnly);
|
||||
assert_eq!(mpls_only.class(), ClpiVsMplsClass::MplsOnly);
|
||||
assert_eq!(match_.class(), ClpiVsMplsClass::Match);
|
||||
assert_eq!(divergent.class(), ClpiVsMplsClass::Divergent);
|
||||
}
|
||||
|
||||
/// Spec: class_counts tuple order is (clpi_only, mpls_only, matches, divergent).
|
||||
/// Verifies each counter increments the RIGHT slot.
|
||||
/// Mutation: swap any two counters → wrong slot increments.
|
||||
#[test]
|
||||
fn class_counts_each_counter_in_correct_slot() {
|
||||
// One of each class — verify tuple slots separately.
|
||||
let audit = ClpiVsMplsAudit {
|
||||
rows: vec![
|
||||
// 2 ClpiOnly
|
||||
ClpiVsMplsRow {
|
||||
pid: 1,
|
||||
clpi_coding_type: Some(0x83),
|
||||
clpi_language: None,
|
||||
mpls_coding_type: None,
|
||||
mpls_language: None,
|
||||
},
|
||||
ClpiVsMplsRow {
|
||||
pid: 2,
|
||||
clpi_coding_type: Some(0x82),
|
||||
clpi_language: None,
|
||||
mpls_coding_type: None,
|
||||
mpls_language: None,
|
||||
},
|
||||
// 1 MplsOnly
|
||||
ClpiVsMplsRow {
|
||||
pid: 3,
|
||||
clpi_coding_type: None,
|
||||
clpi_language: None,
|
||||
mpls_coding_type: Some(0x90),
|
||||
mpls_language: None,
|
||||
},
|
||||
// 3 Match
|
||||
ClpiVsMplsRow {
|
||||
pid: 4,
|
||||
clpi_coding_type: Some(0x83),
|
||||
clpi_language: Some("eng".into()),
|
||||
mpls_coding_type: Some(0x83),
|
||||
mpls_language: Some("eng".into()),
|
||||
},
|
||||
ClpiVsMplsRow {
|
||||
pid: 5,
|
||||
clpi_coding_type: Some(0x82),
|
||||
clpi_language: Some("fra".into()),
|
||||
mpls_coding_type: Some(0x82),
|
||||
mpls_language: Some("fra".into()),
|
||||
},
|
||||
ClpiVsMplsRow {
|
||||
pid: 6,
|
||||
clpi_coding_type: Some(0x86),
|
||||
clpi_language: Some("deu".into()),
|
||||
mpls_coding_type: Some(0x86),
|
||||
mpls_language: Some("deu".into()),
|
||||
},
|
||||
// 1 Divergent
|
||||
ClpiVsMplsRow {
|
||||
pid: 7,
|
||||
clpi_coding_type: Some(0x83),
|
||||
clpi_language: Some("eng".into()),
|
||||
mpls_coding_type: Some(0x83),
|
||||
mpls_language: Some("spa".into()),
|
||||
},
|
||||
],
|
||||
};
|
||||
let (co, mo, m, d) = audit.class_counts();
|
||||
assert_eq!(co, 2, "clpi_only slot");
|
||||
assert_eq!(mo, 1, "mpls_only slot");
|
||||
assert_eq!(m, 3, "matches slot");
|
||||
assert_eq!(d, 1, "divergent slot");
|
||||
assert_eq!(co + mo + m + d, audit.rows.len(), "all rows accounted for");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user