diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92e7f4c..91836f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,10 @@ jobs: # would always fail on a fresh runner because there's no committed # lockfile to lock against. The binary crates (freemkv, autorip, # bdemu) track Cargo.lock and DO use --locked. - - run: cargo clippy -- -D warnings + # --all-targets so TEST code is linted too. Without it this crate — the + # reference implementation for the other seven — was the only one whose + # tests had never been linted at all, and it was hiding 74 findings. + - run: cargo clippy --all-targets -- -D warnings working-directory: libfreemkv test: diff --git a/src/aacs/derive.rs b/src/aacs/derive.rs index c428dd9..22d8a43 100644 --- a/src/aacs/derive.rs +++ b/src/aacs/derive.rs @@ -1344,9 +1344,14 @@ mod position_recovery_tests { mkb } + /// `(dkey, mk, pk, cvalue, mk_dv)` — the five 16-byte AACS keys the + /// four-level fixture plants. Named so the return type says what it is + /// rather than repeating `[u8; 16]` five times. + type FourLevelParts = ([u8; 16], [u8; 16], [u8; 16], [u8; 16], [u8; 16]); + /// The planted slot-2 material from the four-level fixture, reusable for - /// the malformed-MKB shapes below: `(dkey, mk, pk, cvalue, mk_dv)`. - fn four_level_parts() -> ([u8; 16], [u8; 16], [u8; 16], [u8; 16], [u8; 16]) { + /// the malformed-MKB shapes below. + fn four_level_parts() -> FourLevelParts { let p = plant_four_level_mkb(); let cvalues = mkb_find_cvalues(&p.mkb).expect("cvalues"); let mut cv = [0u8; 16]; diff --git a/src/aacs/index_select.rs b/src/aacs/index_select.rs index 0b41e0d..d91b4c7 100644 --- a/src/aacs/index_select.rs +++ b/src/aacs/index_select.rs @@ -189,7 +189,7 @@ mod tests { let unit_packets = (ALIGNED_UNIT_LEN as u64 / SOURCE_PACKET_LEN) as u32; // 32 // Start so the unit covers [80, 80+31] = [80, 111]: overlaps at 100. let off = 80u64 * SOURCE_PACKET_LEN; - assert!(80 + unit_packets - 1 >= 100, "sanity: unit tails into seg"); + assert!(80 + unit_packets > 100, "sanity: unit tails into seg"); assert_eq!( unit_disposition(off, &segs, Some(5)), UnitDisposition::Index(5) diff --git a/src/aacs/variant.rs b/src/aacs/variant.rs index ec78425..d33ca40 100644 --- a/src/aacs/variant.rs +++ b/src/aacs/variant.rs @@ -1707,8 +1707,6 @@ mod tests { records: Vec, /// The device key that covers slot 1 with zero descent. dk: DeviceKey, - /// The Processing Key the walk must produce for it. - kp: [u8; 16], /// The Media Key the full chain must reach from that Processing Key. km: [u8; 16], /// The `0x0c` C block of slot 1 — the cvalue the walk must select. @@ -1833,7 +1831,6 @@ mod tests { uv: UV_REAL, u_mask_shift: U_MASK_SHIFT, }, - kp, km, c_block1, } diff --git a/src/decrypt.rs b/src/decrypt.rs index c509584..1a27d88 100644 --- a/src/decrypt.rs +++ b/src/decrypt.rs @@ -837,7 +837,7 @@ mod tests { // descramble-and-rekey lives in `css::descramble_region` (the recovery // seam calls it); the region change must re-crack region B's key. let mut ended = key_a; - css::descramble_region(&mut buf, &mut ended); + css::descramble_region(&mut buf, &mut ended).expect("descramble"); assert_eq!( &buf[0x80..2048], @@ -986,7 +986,7 @@ mod tests { let (mut sector, plaintext) = make_css_sector(&title_key, &seed, 0xA5); // CSS descramble lives in `css::descramble_region` (the recovery seam // calls it); `decrypt_sectors` only flags CSS sectors for recovery. - css::descramble_region(&mut sector, &mut title_key); + css::descramble_region(&mut sector, &mut title_key).expect("descramble"); assert_eq!( §or[0x80..2048], &plaintext[0x80..2048], @@ -1016,7 +1016,7 @@ mod tests { let mut buf = s0; buf.extend_from_slice(&s1); let mut title_key = title_key; - css::descramble_region(&mut buf, &mut title_key); + css::descramble_region(&mut buf, &mut title_key).expect("descramble"); assert_eq!( &buf[0x80..2048], &p0[0x80..2048], @@ -1095,7 +1095,7 @@ mod tests { // Cache primed to key_a only — exactly what the one-shot scan crack yields. let mut title_key = key_a; - css::descramble_region(&mut buf, &mut title_key); + css::descramble_region(&mut buf, &mut title_key).expect("descramble"); assert_eq!( &buf[0x80..2048], diff --git a/src/disc/hddvd.rs b/src/disc/hddvd.rs index 425c175..2f7d700 100644 --- a/src/disc/hddvd.rs +++ b/src/disc/hddvd.rs @@ -716,12 +716,15 @@ mod tests { /// Build a UDF with an `HVDVD_TS/` tree holding the listed `.evo` clips /// (name, sector count, data LBA). fn make_hddvd_fs(disc: &mut MemDisc, evos: &[(&str, u32, u32)]) -> crate::udf::UdfFs { - let mut files = Vec::new(); - let mut icb = 100u32; - for (name, sectors, data_lba) in evos { - files.push(file(name, icb, *data_lba, sectors * 2048, true)); - icb += 1; - } + // ICBs are handed out from 100 upward, one per EVO, so the index IS + // the offset from that base. + let files: Vec<_> = evos + .iter() + .enumerate() + .map(|(i, (name, sectors, data_lba))| { + file(name, 100 + i as u32, *data_lba, sectors * 2048, true) + }) + .collect(); let root = DirSpec { name: String::new(), icb_lba: 10, @@ -1337,12 +1340,15 @@ mod tests { evos: &[(&str, u32, u32)], xpl: &[u8], ) -> crate::udf::UdfFs { - let mut hv_files = Vec::new(); - let mut icb = 100u32; - for (name, sectors, data_lba) in evos { - hv_files.push(file(name, icb, *data_lba, sectors * 2048, true)); - icb += 1; - } + // ICBs are handed out from 100 upward, one per EVO, so the index IS + // the offset from that base. + let hv_files: Vec<_> = evos + .iter() + .enumerate() + .map(|(i, (name, sectors, data_lba))| { + file(name, 100 + i as u32, *data_lba, sectors * 2048, true) + }) + .collect(); let root = DirSpec { name: String::new(), icb_lba: 10, diff --git a/src/disc/mod.rs b/src/disc/mod.rs index 9f73662..aa2fe2e 100644 --- a/src/disc/mod.rs +++ b/src/disc/mod.rs @@ -3432,7 +3432,7 @@ mod tests { fn merged_extents_unions_sorts_and_merges() { // [300,310) ; [100,150) ; [150,200) adjacent→merges with prev ; // [120,160) overlaps [100,150)&[150,200) ; [500,505) disjoint. - let v = vec![ + let v = [ ext(300, 10), ext(100, 50), ext(150, 50), @@ -3450,7 +3450,7 @@ mod tests { /// to a single range — no double-counting of shared content. #[test] fn merged_extents_dedups_shared_clip() { - let v = vec![ext(100, 50), ext(100, 50)]; + let v = [ext(100, 50), ext(100, 50)]; assert_eq!(merged_extents(v.iter()), vec![(100, 50)]); } @@ -3666,7 +3666,7 @@ mod tests { #[test] fn canonical_order_pushes_oversize_play_all_behind_real_main() { const CAPACITY: u64 = 58_500_000_000; // 58.5 GB - let mut titles = vec![ + let mut titles = [ // Title 1 in the raw MPLS order — virtual play-all title_with( "00020.mpls", @@ -3694,7 +3694,7 @@ mod tests { #[test] fn canonical_order_preserves_natural_ranking_on_normal_disc() { const CAPACITY: u64 = 60_000_000_000; - let mut titles = vec![ + let mut titles = [ title_with("00100.mpls", 600.0, 500_000_000, 1), // 10 min menu (small) title_with("00800.mpls", 7320.0, 55_000_000_000, 1), // 2h02m main feature title_with("00200.mpls", 1800.0, 2_000_000_000, 1), // 30 min extra @@ -3717,7 +3717,7 @@ mod tests { #[test] fn title_index_0_is_main_feature_dvd_the_dash_t_1_contract() { const DVD9: u64 = 7_900_000_000; // dual-layer DVD - let mut titles = vec![ + let mut titles = [ title_with("VTS_01_menu", 120.0, 200_000_000, 1), // 2m menu/setup loop title_with("VTS_02_main", 6540.0, 6_300_000_000, 1), // 1h49m main feature title_with("VTS_03_extra", 900.0, 800_000_000, 1), // 15m extra @@ -3871,7 +3871,7 @@ mod tests { let feature = title_sized(57_000_000_000, 7860.0, 11); // 2h11m, 11 chapters let bonus = title_sized(1_200_000_000, 600.0, 1); // 10m, 1 clip let decoy = title_sized(400_000_000, 5460.0, 91); // 1h31m but tiny (reused) - let mut v = vec![bonus, decoy, feature]; + let mut v = [bonus, decoy, feature]; v.sort_by(|a, b| Disc::canonical_title_order(a, b, capacity)); assert_eq!( v[0].size_bytes, 57_000_000_000, @@ -4610,14 +4610,14 @@ mod tests { assert!(super::aligned_unit_keys_validate( &[(7, uk)], None, - &[enc.clone()], + std::slice::from_ref(&enc), ContentFormat::BdTs )); // Wrong key -> cannot de-scramble a scrambled sample -> reject. assert!(!super::aligned_unit_keys_validate( &[(7, [0x00u8; 16])], None, - &[enc.clone()], + std::slice::from_ref(&enc), ContentFormat::BdTs )); // Empty key set against a scrambled sample -> reject. diff --git a/src/ifo.rs b/src/ifo.rs index 6b3ad28..222ec9e 100644 --- a/src/ifo.rs +++ b/src/ifo.rs @@ -2201,6 +2201,11 @@ mod tests { /// `[padding, Y, Cb, Cr]`. Every byte of every entry is distinct here, so /// a wrong stride, a wrong base or a shifted component shows up. #[test] + // The loop variable is the DOMAIN VALUE being checked (a palette entry number), not a + // cursor into a collection: it is what the assertion message names and + // what the table is keyed by. `.iter().enumerate()` would rename the + // thing under test to `i` and read worse. + #[allow(clippy::needless_range_loop)] fn pgc_palette_entries_read_at_correct_stride() { let mut pal = [[0u8; 4]; 16]; for (i, c) in pal.iter_mut().enumerate() { diff --git a/src/keysource.rs b/src/keysource.rs index 34f0e8d..c609ee5 100644 --- a/src/keysource.rs +++ b/src/keysource.rs @@ -1306,7 +1306,7 @@ mod tests { break; } let abs = (lba - self.ext_start) / ALIGNED_UNIT_SECTORS + i as u32; - if abs % 2 == 0 { + if abs.is_multiple_of(2) { chunk.fill(0x11); // CPI-clear (0x11 & 0xC0 == 0), no TS sync } else { chunk.fill(0xAB); // scrambled body (no TS sync) diff --git a/src/labels/bdmt.rs b/src/labels/bdmt.rs index adbe37b..d305228 100644 --- a/src/labels/bdmt.rs +++ b/src/labels/bdmt.rs @@ -370,10 +370,10 @@ mod tests { if let Some(d) = desc { meta.descriptions.insert(lang.to_string(), d); } - if meta.disc_number.is_none() { - if let Some(d) = ds { - meta.disc_number = Some(d); - } + if meta.disc_number.is_none() + && let Some(d) = ds + { + meta.disc_number = Some(d); } } diff --git a/src/labels/mod.rs b/src/labels/mod.rs index 0836aec..9ce3eff 100644 --- a/src/labels/mod.rs +++ b/src/labels/mod.rs @@ -1333,7 +1333,7 @@ mod gap_fill_tests { // duplicate. Stream_number is computed from the EXISTING // labels' max(stream_number) per type so orphans (when they // do fire) sort cleanly at the tail. - let labels = vec![ + let labels = [ label(StreamLabelType::Audio, 1, "eng", "TrueHD"), label(StreamLabelType::Audio, 2, "fra", "AC-3"), ]; diff --git a/src/labels/text.rs b/src/labels/text.rs index c08a6d0..a9f1fa2 100644 --- a/src/labels/text.rs +++ b/src/labels/text.rs @@ -169,7 +169,7 @@ mod tests { /// Mutation: skip the final `if !current.is_empty()` emit → trailing run lost. #[test] fn large_buffer_trailing_run_emitted() { - let buf: Vec = (0..1000u32).map(|i| (0x41u8 + (i % 26) as u8)).collect(); + let buf: Vec = (0..1000u32).map(|i| 0x41u8 + (i % 26) as u8).collect(); let got = extract_ascii_strings(&buf, 1); // All printable, so one big run at the end. assert!(!got.is_empty()); diff --git a/src/mpls.rs b/src/mpls.rs index 503f7da..d52852c 100644 --- a/src/mpls.rs +++ b/src/mpls.rs @@ -1521,13 +1521,14 @@ mod tests { /// consumed to keep the cursor aligned but never retained. #[test] fn full_stn_table_block_alignment() { - let mut entries: Vec> = Vec::new(); - entries.push(build_stream_entry_video(0x1011, 0x1B, 6, 1, None)); - entries.push(build_stream_entry_audio(0x1100, 0x83, 6, 1, b"eng")); - entries.push(build_stream_entry_audio(0x1101, 0x86, 3, 1, b"fra")); - entries.push(build_stream_entry_pg(0x1200, 0x90, b"eng")); - entries.push(build_stream_entry_pg(0x1201, 0x90, b"fra")); - entries.push(build_stream_entry_pg(0x1202, 0x90, b"deu")); + let mut entries: Vec> = vec![ + build_stream_entry_video(0x1011, 0x1B, 6, 1, None), + build_stream_entry_audio(0x1100, 0x83, 6, 1, b"eng"), + build_stream_entry_audio(0x1101, 0x86, 3, 1, b"fra"), + build_stream_entry_pg(0x1200, 0x90, b"eng"), + build_stream_entry_pg(0x1201, 0x90, b"fra"), + build_stream_entry_pg(0x1202, 0x90, b"deu"), + ]; for i in 0..4u16 { entries.push(build_stream_entry_pg(0x1400 + i, 0x91, b"eng")); } diff --git a/src/mux/codec/ac3.rs b/src/mux/codec/ac3.rs index 4ac4da5..3a7378a 100644 --- a/src/mux/codec/ac3.rs +++ b/src/mux/codec/ac3.rs @@ -1738,7 +1738,7 @@ mod tests { /// byte 5 = bsid 16 so the E-AC-3 paths are taken. CRC finalized so the frame /// passes the decodability gate. fn make_eac3_frame(strmtyp: u8, substreamid: u8, size: usize) -> Vec { - assert!(size >= MIN_FRAME_BYTES && size % 2 == 0); + assert!(size >= MIN_FRAME_BYTES && size.is_multiple_of(2)); let frmsiz = size / 2 - 1; let mut f = vec![0u8; size]; f[0] = 0x0B; diff --git a/src/mux/codec/dts.rs b/src/mux/codec/dts.rs index b9540ef..f56f632 100644 --- a/src/mux/codec/dts.rs +++ b/src/mux/codec/dts.rs @@ -921,7 +921,7 @@ mod tests { let core = make_dts_core(512); let garbage = vec![0xE4, 0x3F, 0xE3, 0x90, 0xCC, 0x6C]; // real Bourne head bytes let mut garbage = garbage; - garbage.extend(std::iter::repeat(0xAB).take(300)); + garbage.extend(std::iter::repeat_n(0xAB, 300)); let next = make_dts_core(512); let mut buf = core.clone(); buf.extend_from_slice(&garbage); @@ -1931,6 +1931,11 @@ mod tests { } #[test] + // The loop variable is the DOMAIN VALUE being checked (a DTS SFREQ code), not a + // cursor into a collection: it is what the assertion message names and + // what the table is keyed by. `.iter().enumerate()` would rename the + // thing under test to `i` and read worse. + #[allow(clippy::needless_range_loop)] fn sr_validity_table_marks_reserved_codes() { // The core-header sample-rate validity table must have ZERO (reject) at // exactly the reserved SFREQ codes {0,4,5,9,10} and a real rate diff --git a/src/mux/codec/hevc.rs b/src/mux/codec/hevc.rs index 56381a6..3b8d45e 100644 --- a/src/mux/codec/hevc.rs +++ b/src/mux/codec/hevc.rs @@ -1456,6 +1456,11 @@ mod tests { /// offset on any real stream that sets it — mislabelling every picture's /// coding type. #[test] + // The underscores in these literals mark BITFIELD boundaries in the + // bitstream header being built (e.g. a 5-bit field then a 3-bit field), + // not thousands-style digit groups. Regrouping them uniformly would + // satisfy the lint by destroying the only thing they encode. + #[allow(clippy::unusual_byte_groupings)] fn nonzero_num_extra_slice_header_bits_shifts_the_slice_type_offset() { use super::super::coding::CodingType; @@ -2690,7 +2695,7 @@ mod tests { } } fn put_bit(&mut self, b: u32) { - if self.nbits % 8 == 0 { + if self.nbits.is_multiple_of(8) { self.bytes.push(0); } if b & 1 != 0 { diff --git a/src/mux/codec/mpegaudio.rs b/src/mux/codec/mpegaudio.rs index db48e45..dfe429b 100644 --- a/src/mux/codec/mpegaudio.rs +++ b/src/mux/codec/mpegaudio.rs @@ -154,7 +154,7 @@ mod tests { /// 0xFF 0xFB 0x90 0x00 — the canonical MP3 frame header. fn mp3_frame(payload: usize) -> Vec { let mut f = vec![0xFF, 0xFB, 0x90, 0x00]; - f.extend(std::iter::repeat(0xAA).take(payload)); + f.extend(std::iter::repeat_n(0xAA, payload)); f } diff --git a/src/mux/demux_thread.rs b/src/mux/demux_thread.rs index 557c3c2..0e99830 100644 --- a/src/mux/demux_thread.rs +++ b/src/mux/demux_thread.rs @@ -417,9 +417,7 @@ mod tests { let (_dt, rx) = DemuxThread::spawn_zero_copy(pf_rx, rc_tx, (), None, Some(ts), None).unwrap(); - pf_tx - .send(Err(std::io::Error::new(std::io::ErrorKind::Other, "boom"))) - .unwrap(); + pf_tx.send(Err(std::io::Error::other("boom"))).unwrap(); drop(pf_tx); let batches = collect_batches(&rx, Duration::from_secs(5)); diff --git a/src/mux/disc.rs b/src/mux/disc.rs index 450ce8d..4f5a1fb 100644 --- a/src/mux/disc.rs +++ b/src/mux/disc.rs @@ -1880,7 +1880,7 @@ mod tests { // would straddle AACS unit boundaries and decrypt under the wrong // alignment. assert!( - count as u32 % ALIGN == 0 || (count as u32) < ALIGN, + (count as u32).is_multiple_of(ALIGN) || (count as u32) < ALIGN, "read count {count} is neither a whole number of units nor a sub-unit tail" ); } @@ -2457,7 +2457,10 @@ mod tests { let h = halve_batch_size(size); assert!(h >= 1, "halve({size}) must never be 0"); assert!(h <= size, "halve({size}) = {h} must not grow"); - assert!(h < 6 || h % 3 == 0, "halve({size}) = {h} is unit-unaligned"); + assert!( + h < 6 || h.is_multiple_of(3), + "halve({size}) = {h} is unit-unaligned" + ); } } @@ -2483,7 +2486,7 @@ mod tests { let d = double_batch_size(size, 4096); assert!(d >= size, "double({size}) = {d} must not shrink"); assert!( - d < 6 || d % 3 == 0, + d < 6 || d.is_multiple_of(3), "double({size}) = {d} is unit-unaligned" ); } diff --git a/src/mux/driver.rs b/src/mux/driver.rs index b10209c..2e5d975 100644 --- a/src/mux/driver.rs +++ b/src/mux/driver.rs @@ -1043,15 +1043,15 @@ mod tests { impl Stream for FakeStream { fn read(&mut self) -> std::io::Result> { - if let Some((halt, after)) = &self.cancel_halt { - if self.reads >= *after { - halt.cancel(); - } + if let Some((halt, after)) = &self.cancel_halt + && self.reads >= *after + { + halt.cancel(); } - if let Some(after) = self.halt_err_at_read { - if self.reads >= after { - return Err(crate::error::Error::Halted.into()); - } + if let Some(after) = self.halt_err_at_read + && self.reads >= after + { + return Err(crate::error::Error::Halted.into()); } let f = self.frames.pop_front(); if f.is_some() { diff --git a/src/mux/ebml.rs b/src/mux/ebml.rs index 418da52..c469fbb 100644 --- a/src/mux/ebml.rs +++ b/src/mux/ebml.rs @@ -1479,6 +1479,11 @@ mod tests { /// end_master without a multi-terabyte buffer, which is why this is /// tested at the encoder. #[test] + // The underscores in these literals mark BITFIELD boundaries in the + // bitstream header being built (e.g. a 5-bit field then a 3-bit field), + // not thousands-style digit groups. Regrouping them uniformly would + // satisfy the lint by destroying the only thing they encode. + #[allow(clippy::unusual_byte_groupings)] fn fixed_width_vint8_is_big_endian_over_the_full_payload() { assert_eq!( fixed_width_vint8(0x00AA_BB_CC_DD_EE_FF_11), diff --git a/src/mux/m2ts_mux/mod.rs b/src/mux/m2ts_mux/mod.rs index b8d4a8f..d58379b 100644 --- a/src/mux/m2ts_mux/mod.rs +++ b/src/mux/m2ts_mux/mod.rs @@ -766,7 +766,7 @@ mod tests { // First two packets: PAT, PMT. At least one video packet after. assert_eq!(pids[0], PID_PAT); assert_eq!(pids[1], PID_PMT); - assert!(pids.iter().any(|p| *p == PID_VIDEO)); + assert!(pids.contains(&PID_VIDEO)); } #[test] @@ -810,8 +810,8 @@ mod tests { assert_ts_well_formed(&sink); let pids = extract_pids(&sink); - assert!(pids.iter().any(|p| *p == PID_VIDEO)); - assert!(pids.iter().any(|p| *p == PID_AUDIO)); + assert!(pids.contains(&PID_VIDEO)); + assert!(pids.contains(&PID_AUDIO)); } #[test] @@ -1129,10 +1129,11 @@ mod tests { continue; } total_video += 1; - if let Some(af) = af_body(pkt) { - if !af.is_empty() && (af[0] & 0x10) != 0 { - pcr_indices.push(video_idx); - } + if let Some(af) = af_body(pkt) + && !af.is_empty() + && (af[0] & 0x10) != 0 + { + pcr_indices.push(video_idx); } video_idx += 1; } @@ -1582,7 +1583,7 @@ mod tests { } let pids = extract_pids(&sink); assert!( - !pids.iter().any(|p| *p == PID_AUDIO), + !pids.contains(&PID_AUDIO), "no audio track configured → no audio PID emitted" ); } diff --git a/src/mux/mkv.rs b/src/mux/mkv.rs index 5e0a938..b28f8ad 100644 --- a/src/mux/mkv.rs +++ b/src/mux/mkv.rs @@ -2024,6 +2024,7 @@ mod tests { /// so a shipped DVD rip marked every P/B frame as a seek point; /// - the reader ignored ReferenceBlock and read the always-0 reserved bit, /// so EVERY BlockGroup frame read back as a non-keyframe. + /// /// Downstream that silently dropped all video on `mkv://`(MPEG-2)→`m2ts://` /// (TsMuxer drops non-key video until the first keyframe) and made /// `mkv://`→`mkv://` / `stdio://` fail E6008 (MkvMuxer opens a cluster only diff --git a/src/mux/mp4/audio.rs b/src/mux/mp4/audio.rs index 7a24a30..fc7efdd 100644 --- a/src/mux/mp4/audio.rs +++ b/src/mux/mp4/audio.rs @@ -522,6 +522,11 @@ mod tests { /// A synthetic legacy AC-3 header: syncword, crc, fscod=0 (48k), /// frmsizecod, bsid=8, bsmod=0, acmod=7 (3/2), lfeon=1 → 5.1. + // The underscores in these literals mark BITFIELD boundaries in the + // bitstream header being built (e.g. a 5-bit field then a 3-bit field), + // not thousands-style digit groups. Regrouping them uniformly would + // satisfy the lint by destroying the only thing they encode. + #[allow(clippy::unusual_byte_groupings)] fn ac3_frame_5_1() -> Vec { let mut f = vec![0x0B, 0x77, 0x00, 0x00]; // byte4: fscod(2)=0 | frmsizecod(6)=0b010110 (22) @@ -556,6 +561,11 @@ mod tests { /// A synthetic Annex-E (E-AC-3) syncframe: bsid=16, fscod=0 (48 kHz), /// numblkscod=3 (6 blocks), acmod=7 (3/2), lfeon=1 → 5.1, frmsiz=63 (128 B). + // The underscores in these literals mark BITFIELD boundaries in the + // bitstream header being built (e.g. a 5-bit field then a 3-bit field), + // not thousands-style digit groups. Regrouping them uniformly would + // satisfy the lint by destroying the only thing they encode. + #[allow(clippy::unusual_byte_groupings)] fn eac3_frame_5_1() -> Vec { // E-AC-3: syncword | strmtyp/substreamid/frmsiz | fscod/numblks/acmod/lfeon | bsid let mut f = vec![0x0B, 0x77]; @@ -840,6 +850,11 @@ mod tests { } #[test] + // The loop variable is the DOMAIN VALUE being checked (a DTS AMODE value), not a + // cursor into a collection: it is what the assertion message names and + // what the table is keyed by. `.iter().enumerate()` would rename the + // thing under test to `i` and read worse. + #[allow(clippy::needless_range_loop)] fn ddts_channel_layout_speaker_count_matches_declared_channels() { // The `ddts` box carries BOTH a channel count and a 16-bit speaker mask, // and a decoder may trust either. They must agree for all 16 AMODEs. diff --git a/src/mux/mp4/mod.rs b/src/mux/mp4/mod.rs index 139d518..83c5d87 100644 --- a/src/mux/mp4/mod.rs +++ b/src/mux/mp4/mod.rs @@ -1226,6 +1226,11 @@ mod tests { } // A minimal AC-3 5.1 frame the audio parser accepts. + // The underscores in these literals mark BITFIELD boundaries in the + // bitstream header being built (e.g. a 5-bit field then a 3-bit field), + // not thousands-style digit groups. Regrouping them uniformly would + // satisfy the lint by destroying the only thing they encode. + #[allow(clippy::unusual_byte_groupings)] fn ac3_frame() -> Vec { vec![ 0x0B, @@ -1503,11 +1508,11 @@ mod tests { t.duration_secs = 7200.0; let r = estimate_reserve(&t, &[0, 1]); assert!( - r % (4 << 20) == 0, + r.is_multiple_of(4 << 20), "reserve is 4 MiB-aligned + 4 MiB buffer" ); assert!( - r >= 12 << 20 && r <= 20 << 20, + (12 << 20..=20 << 20).contains(&r), "≈12-16 MB for a 2h feature, got {r}" ); diff --git a/src/mux/mp4/read.rs b/src/mux/mp4/read.rs index 34f41c2..1bc700c 100644 --- a/src/mux/mp4/read.rs +++ b/src/mux/mp4/read.rs @@ -1087,6 +1087,11 @@ mod tests { } #[test] + // The underscores in these literals mark BITFIELD boundaries in the + // bitstream header being built (e.g. a 5-bit field then a 3-bit field), + // not thousands-style digit groups. Regrouping them uniformly would + // satisfy the lint by destroying the only thing they encode. + #[allow(clippy::unusual_byte_groupings)] fn write_then_read_round_trip() { // Mux a small A/V title to an in-memory MP4, then demux it back and // check the streams, codec_private, and sample payloads survive. @@ -1453,6 +1458,11 @@ mod tests { /// one of any of them round-trips through this crate unnoticed while making /// the file unplayable elsewhere. #[test] + // The underscores in these literals mark BITFIELD boundaries in the + // bitstream header being built (e.g. a 5-bit field then a 3-bit field), + // not thousands-style digit groups. Regrouping them uniformly would + // satisfy the lint by destroying the only thing they encode. + #[allow(clippy::unusual_byte_groupings)] fn moov_tree_carries_the_mandatory_track_header_and_media_boxes() { use crate::disc::{ AudioChannels, AudioStream, Codec, DiscTitle, FrameRate, HdrFormat, LabelPurpose, @@ -2148,8 +2158,8 @@ mod tests { mdia.extend_from_slice(&mdhd); mdia.extend_from_slice(&hdlr); mdia.extend_from_slice(&minf); - let trak = mp4_box(b"trak", &mp4_box(b"mdia", &mdia)); - trak + + mp4_box(b"trak", &mp4_box(b"mdia", &mdia)) } #[test] @@ -2449,10 +2459,10 @@ mod tests { } /// A `VisualSampleEntry` body with DISTINCT width and height, plus optional - /// child boxes (ISO/IEC 14496-12 §12.1.3): 6 reserved + 2 data_reference_index - /// + 16 pre_defined/reserved, then width(2) at 24 and height(2) at 26, then 50 - /// more bytes of resolution / frame_count / compressorname / depth / pre_defined - /// to the 78-byte fixed part. + /// child boxes (ISO/IEC 14496-12 §12.1.3). The fixed part is 78 bytes: + /// 6 reserved, 2 data_reference_index, 16 pre_defined/reserved, width(2) at + /// offset 24, height(2) at 26, then 50 more bytes of resolution, + /// frame_count, compressorname, depth and pre_defined. fn visual_entry(width: u16, height: u16, children: &[u8]) -> Vec { let mut b = vec![0u8; 78]; b[24..26].copy_from_slice(&width.to_be_bytes()); @@ -2492,7 +2502,7 @@ mod tests { // And a VisualSampleEntry too short to hold the fixed part is refused // rather than read out of a shorter buffer. - let short = stsd_with(b"avc1", &vec![0u8; 40]); + let short = stsd_with(b"avc1", &[0u8; 40]); assert!( parse_stsd(&short).is_none(), "a truncated VisualSampleEntry has no dimensions to read" @@ -2519,7 +2529,7 @@ mod tests { assert_eq!(info.height, 0, "an audio entry declares no height"); // Too short for the 28-byte fixed part: fall back to stereo, not to 0. - let short = stsd_with(b"ac-3", &vec![0u8; 12]); + let short = stsd_with(b"ac-3", &[0u8; 12]); let info = parse_stsd(&short).expect("a short audio entry still names a codec"); assert_eq!( info.channels, 2, diff --git a/src/mux/resolve.rs b/src/mux/resolve.rs index 181ba11..518787a 100644 --- a/src/mux/resolve.rs +++ b/src/mux/resolve.rs @@ -4258,7 +4258,7 @@ mod tests { let sb = s.start_byte(); if unit_byte >= sb && unit_byte < sb + s.byte_len() { let n = (unit_byte - sb) / crate::aacs::content::ALIGNED_UNIT_LEN as u64; - let key = if n % 2 == 0 { + let key = if n.is_multiple_of(2) { FMTS_INDEX_KEYS[(s.index - 1) as usize] } else { FMTS_ALT_KEY @@ -4281,16 +4281,17 @@ mod tests { buf: &mut [u8], recovery: bool, ) -> crate::error::Result { - if let Some((a, b)) = self.fault_span { - if lba >= a && lba < b { - self.probe_reads += 1; - self.maybe_cancel(); - return Err(crate::error::Error::DiscRead { - sector: lba as u64, - status: None, - sense: None, - }); - } + if let Some((a, b)) = self.fault_span + && lba >= a + && lba < b + { + self.probe_reads += 1; + self.maybe_cancel(); + return Err(crate::error::Error::DiscRead { + sector: lba as u64, + status: None, + sense: None, + }); } if lba < FMTS_CONTENT_LBA { self.meta_reads += 1; diff --git a/src/mux/select.rs b/src/mux/select.rs index c23c670..c288b5f 100644 --- a/src/mux/select.rs +++ b/src/mux/select.rs @@ -232,10 +232,10 @@ mod tests { fn pids(t: &DiscTitle) -> Vec { t.streams .iter() - .filter_map(|s| match s { - Stream::Video(v) => Some(v.pid), - Stream::Audio(a) => Some(a.pid), - Stream::Subtitle(s) => Some(s.pid), + .map(|s| match s { + Stream::Video(v) => v.pid, + Stream::Audio(a) => a.pid, + Stream::Subtitle(s) => s.pid, }) .collect() } diff --git a/src/mux/ts.rs b/src/mux/ts.rs index ef2542a..3fd6085 100644 --- a/src/mux/ts.rs +++ b/src/mux/ts.rs @@ -1539,7 +1539,7 @@ mod tests { // 0xAA filler and the embedded 00 00 01 sequence must be absent — the // malformed PES header contributed ZERO bytes to the elementary stream. assert!( - !pes.data.iter().any(|&b| b == 0xAA), + !pes.data.contains(&0xAA), "garbage PES-header bytes must not appear in the elementary stream" ); assert!( @@ -2124,7 +2124,7 @@ mod tests { assert_eq!(out.len(), 1); // None of the 0xEE AF-only bytes may appear. assert!( - !out[0].data.iter().any(|&b| b == 0xEE), + !out[0].data.contains(&0xEE), "AF-only packet bytes must never be appended as ES" ); assert_eq!(out[0].data, vec![0x01, 0x02, 0x03, 0x04]); @@ -2165,7 +2165,7 @@ mod tests { assert_eq!(out.len(), 1); assert_eq!(out[0].data, vec![0x77, 0x88]); assert!( - !out[0].data.iter().any(|&b| b == 0xBB), + !out[0].data.contains(&0xBB), "adaptation-field stuffing must not appear in the ES" ); } diff --git a/src/udf.rs b/src/udf.rs index c3951bc..932943b 100644 --- a/src/udf.rs +++ b/src/udf.rs @@ -1946,7 +1946,7 @@ mod tests { let icb = build_entry_ads(266, 0, 16, &[(1, 2048, HOLE_LBA), (0, 2048, DATA_LBA)], &[]); disc.put_bytes(PART_START + 12, &icb); - let mut fs = super::read_filesystem(&mut disc).expect("volume mounts"); + let fs = super::read_filesystem(&mut disc).expect("volume mounts"); let lba = fs .file_start_lba(&mut disc, "/VIDEO_TS.IFO") .expect("a file whose first descriptor is a hole still has data");