mirror of
https://github.com/freemkv/libfreemkv.git
synced 2026-10-07 18:13:10 +00:00
tests: UDF not-filesystem verdicts, codec id round-trip, exact URL error codes, scsi timeout bound
This commit is contained in:
+2
-2
@@ -50,8 +50,8 @@ fn scan_image_empty_reader() {
|
||||
let opts = ScanOptions::default();
|
||||
let result = Disc::scan_image(&mut reader, 0, &opts);
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"scan_image should fail with empty reader (no AVDP)"
|
||||
matches!(result, Err(libfreemkv::error::Error::UdfNotFilesystem)),
|
||||
"empty reader (no AVDP) must surface the not-UDF verdict"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -188,8 +188,11 @@ fn scan_iso_propagates_scan_error() {
|
||||
.suffix(".iso")
|
||||
.tempfile()
|
||||
.expect("tempfile create");
|
||||
tmp.write_all(&vec![0u8; 8 * SECTOR_SIZE]).expect("write");
|
||||
tmp.write_all(&vec![0u8; 300 * SECTOR_SIZE]).expect("write");
|
||||
tmp.flush().expect("flush");
|
||||
let result = libfreemkv::scan_iso(tmp.path(), ScanOptions::default());
|
||||
assert!(result.is_err(), "non-UDF image must error");
|
||||
assert!(
|
||||
matches!(result, Err(libfreemkv::error::Error::UdfNotFilesystem)),
|
||||
"non-UDF image must surface the not-UDF verdict"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ fn test_drive_read_per_cdb_timeout_bounds_call() {
|
||||
let path = Path::new(&device);
|
||||
|
||||
let mut drive = libfreemkv::Drive::open(path).expect("open drive");
|
||||
let timeout_ms: u32 = 5_000;
|
||||
// Mirrors the crate-private scsi::READ_TIMEOUT_MS used by Drive::read.
|
||||
let timeout_ms: u32 = 10_000;
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
let _ = drive.read(0, 1, &mut [0u8; 2048], false);
|
||||
|
||||
+20
-30
@@ -126,11 +126,7 @@ fn open_input_bare_path_errors() {
|
||||
Err(e) => e.to_string(),
|
||||
Ok(_) => panic!("expected error"),
|
||||
};
|
||||
assert!(
|
||||
msg.contains("not a valid stream URL") || msg.contains("E9002"),
|
||||
"got: {}",
|
||||
msg
|
||||
);
|
||||
assert!(msg.contains("E9002"), "got: {}", msg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -142,11 +138,7 @@ fn open_output_bare_path_errors() {
|
||||
Err(e) => e.to_string(),
|
||||
Ok(_) => panic!("expected error"),
|
||||
};
|
||||
assert!(
|
||||
msg.contains("not a valid stream URL") || msg.contains("E9002"),
|
||||
"got: {}",
|
||||
msg
|
||||
);
|
||||
assert!(msg.contains("E9002"), "got: {}", msg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -157,11 +149,7 @@ fn open_input_m2ts_empty_path_errors() {
|
||||
Err(e) => e.to_string(),
|
||||
Ok(_) => panic!("expected error"),
|
||||
};
|
||||
assert!(
|
||||
msg.contains("requires a file path") || msg.contains("E9003"),
|
||||
"got: {}",
|
||||
msg
|
||||
);
|
||||
assert!(msg.contains("E9003"), "got: {}", msg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -172,11 +160,7 @@ fn open_output_null_input_errors() {
|
||||
Err(e) => e.to_string(),
|
||||
Ok(_) => panic!("expected error"),
|
||||
};
|
||||
assert!(
|
||||
msg.contains("write-only") || msg.contains("E9001"),
|
||||
"got: {}",
|
||||
msg
|
||||
);
|
||||
assert!(msg.contains("E9001"), "got: {}", msg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -188,11 +172,7 @@ fn open_output_disc_errors() {
|
||||
Err(e) => e.to_string(),
|
||||
Ok(_) => panic!("expected error"),
|
||||
};
|
||||
assert!(
|
||||
msg.contains("read-only") || msg.contains("E9000"),
|
||||
"got: {}",
|
||||
msg
|
||||
);
|
||||
assert!(msg.contains("E9000"), "got: {}", msg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -203,11 +183,7 @@ fn open_input_network_no_port_errors() {
|
||||
Err(e) => e.to_string(),
|
||||
Ok(_) => panic!("expected error"),
|
||||
};
|
||||
assert!(
|
||||
msg.contains("PES pipeline") || msg.contains("missing port") || msg.contains("E9004"),
|
||||
"got: {}",
|
||||
msg
|
||||
);
|
||||
assert!(msg.contains("E9004"), "got: {}", msg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -379,6 +355,20 @@ fn disc_title_empty() {
|
||||
assert!(dt.playlist.is_empty());
|
||||
}
|
||||
|
||||
// Every named codec must round-trip through its serialized id (FMKV meta headers).
|
||||
#[test]
|
||||
fn codec_id_roundtrips_for_every_named_codec() {
|
||||
use Codec::*;
|
||||
let all = [
|
||||
Hevc, H264, Vc1, Mpeg2, Mpeg1, Av1, TrueHd, DtsHdMa, DtsHdHr, Dts, Ac3, Ac3Plus, Lpcm, Aac,
|
||||
Mp2, Mp3, Flac, Opus, Pgs, DvdSub, Srt, Ssa,
|
||||
];
|
||||
for c in all {
|
||||
assert_ne!(c.id(), "unknown", "{c:?} missing from the codec table");
|
||||
assert_eq!(c.id().parse::<Codec>(), Ok(c), "{c:?} id must parse back");
|
||||
}
|
||||
}
|
||||
|
||||
// ── Meta codec roundtrip ─────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
|
||||
+15
-65
@@ -1,5 +1,6 @@
|
||||
//! UDF parser tests using a MockSectorReader.
|
||||
|
||||
use libfreemkv::error::Error;
|
||||
use libfreemkv::error::Result;
|
||||
use libfreemkv::{SectorSource, read_filesystem};
|
||||
use std::collections::HashMap;
|
||||
@@ -208,59 +209,15 @@ fn make_file_icb(data_lba: u32, data_len: u32, file_size: u64) -> Vec<u8> {
|
||||
|
||||
// ── Tests ──────────────────────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn mock_sector_reader_roundtrip() {
|
||||
let mut reader = MockSectorReader::new();
|
||||
|
||||
// Write a recognizable pattern to sector 100
|
||||
let mut data = vec![0u8; SECTOR_SIZE];
|
||||
data[0] = 0xAB;
|
||||
data[1] = 0xCD;
|
||||
data[2047] = 0xFF;
|
||||
reader.set_sector(100, data.clone());
|
||||
|
||||
// Read it back
|
||||
let mut buf = vec![0u8; SECTOR_SIZE];
|
||||
let n = reader.read_sectors(100, 1, &mut buf, true).unwrap();
|
||||
assert_eq!(n, SECTOR_SIZE);
|
||||
assert_eq!(buf[0], 0xAB);
|
||||
assert_eq!(buf[1], 0xCD);
|
||||
assert_eq!(buf[2047], 0xFF);
|
||||
|
||||
// Reading an unmapped sector returns zeros
|
||||
let mut buf2 = vec![0xFFu8; SECTOR_SIZE];
|
||||
let n2 = reader.read_sectors(999, 1, &mut buf2, true).unwrap();
|
||||
assert_eq!(n2, SECTOR_SIZE);
|
||||
assert_eq!(buf2[0], 0);
|
||||
assert_eq!(buf2[2047], 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mock_sector_reader_multi_sector() {
|
||||
let mut reader = MockSectorReader::new();
|
||||
|
||||
let mut s10 = vec![0u8; SECTOR_SIZE];
|
||||
s10[0] = 10;
|
||||
reader.set_sector(10, s10);
|
||||
|
||||
let mut s11 = vec![0u8; SECTOR_SIZE];
|
||||
s11[0] = 11;
|
||||
reader.set_sector(11, s11);
|
||||
|
||||
// Read 2 consecutive sectors
|
||||
let mut buf = vec![0u8; SECTOR_SIZE * 2];
|
||||
let n = reader.read_sectors(10, 2, &mut buf, true).unwrap();
|
||||
assert_eq!(n, SECTOR_SIZE * 2);
|
||||
assert_eq!(buf[0], 10);
|
||||
assert_eq!(buf[SECTOR_SIZE], 11);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_filesystem_no_avdp() {
|
||||
// Empty reader — sector 256 is all zeros, tag_id=0 != 2
|
||||
let mut reader = MockSectorReader::new();
|
||||
let result = read_filesystem(&mut reader);
|
||||
assert!(result.is_err(), "should fail when no AVDP at sector 256");
|
||||
assert!(
|
||||
matches!(result, Err(Error::UdfNotFilesystem)),
|
||||
"no AVDP at sector 256 is the deterministic not-UDF verdict"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -272,7 +229,10 @@ fn read_filesystem_bad_avdp_tag() {
|
||||
reader.set_sector(256, bad);
|
||||
|
||||
let result = read_filesystem(&mut reader);
|
||||
assert!(result.is_err(), "should fail when AVDP tag_id is not 2");
|
||||
assert!(
|
||||
matches!(result, Err(Error::UdfNotFilesystem)),
|
||||
"AVDP tag_id != 2 is the not-UDF verdict"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -285,8 +245,8 @@ fn read_filesystem_no_partition_descriptor() {
|
||||
|
||||
let result = read_filesystem(&mut reader);
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"should fail when no partition descriptor in VDS"
|
||||
matches!(result, Err(Error::UdfNotFilesystem)),
|
||||
"no partition descriptor is the not-UDF verdict"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -305,7 +265,10 @@ fn read_filesystem_bad_fsd_tag() {
|
||||
// FSD should be at sector partition_start but we leave it as zeros (tag_id=0 != 256).
|
||||
|
||||
let result = read_filesystem(&mut reader);
|
||||
assert!(result.is_err(), "should fail when FSD tag_id is not 256");
|
||||
assert!(
|
||||
matches!(result, Err(Error::UdfNotFilesystem)),
|
||||
"FSD tag_id != 256 is the not-UDF verdict"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -455,16 +418,3 @@ fn find_dir_case_insensitive() {
|
||||
assert!(fs.find_dir("BDMV/STREAM").is_none());
|
||||
assert!(fs.find_dir("NONEXISTENT").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sector_reader_is_object_safe() {
|
||||
// Verify SectorSource can be used as a trait object
|
||||
let mut reader = MockSectorReader::new();
|
||||
reader.set_sector(0, vec![42u8; SECTOR_SIZE]);
|
||||
|
||||
let dyn_reader: &mut dyn SectorSource = &mut reader;
|
||||
let mut buf = vec![0u8; SECTOR_SIZE];
|
||||
let n = dyn_reader.read_sectors(0, 1, &mut buf, true).unwrap();
|
||||
assert_eq!(n, SECTOR_SIZE);
|
||||
assert_eq!(buf[0], 42);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user