use md5::{Digest, Md5};
use std::io::{Read, Seek, SeekFrom};
const DATA_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/data");
fn full_media_md5(reader: &mut ewf::EwfReader) -> String {
let mut hasher = Md5::new();
let mut buf = vec![0u8; 1024 * 1024];
reader.seek(SeekFrom::Start(0)).unwrap();
loop {
let n = reader.read(&mut buf).unwrap();
if n == 0 {
break;
}
hasher.update(&buf[..n]);
}
format!("{:x}", hasher.finalize())
}
#[test]
fn bogus_e01_open_returns_err() {
let path = format!("{DATA_DIR}/bogus.E01");
let result = ewf::EwfReader::open(&path);
assert!(
result.is_err(),
"0-byte bogus.E01 must be rejected with Err, not panic"
);
}
#[test]
fn bogus_e02_open_returns_err() {
let path = format!("{DATA_DIR}/bogus.E02");
let result = ewf::EwfReader::open(&path);
assert!(
result.is_err(),
"0-byte bogus.E02 must be rejected with Err, not panic"
);
}
#[test]
fn ctf_file6_opens_and_has_nonzero_size() {
let path = format!("{DATA_DIR}/ctf_file6.E01");
let reader = ewf::EwfReader::open(&path).expect("ctf_file6.E01 must open");
assert!(reader.total_size() > 0, "ctf_file6.E01 total_size must be > 0");
}
#[test]
fn ctf_file6_read_is_stable() {
let path = format!("{DATA_DIR}/ctf_file6.E01");
let mut reader = ewf::EwfReader::open(&path).expect("open");
let mut buf = [0u8; 512];
reader.seek(SeekFrom::Start(0)).unwrap();
reader.read_exact(&mut buf).expect("read sector 0 of ctf_file6.E01");
let mut buf2 = [0u8; 512];
reader.seek(SeekFrom::Start(0)).unwrap();
reader.read_exact(&mut buf2).unwrap();
assert_eq!(buf, buf2, "repeated reads at offset 0 must be identical");
}
#[test]
fn ewfacquire_clean_media_size() {
let path = format!("{DATA_DIR}/ewfacquire_clean.E01");
let reader = ewf::EwfReader::open(&path).expect("ewfacquire_clean.E01 must open");
assert_eq!(
reader.total_size(),
4_194_304,
"ewfacquire_clean: 4 MiB /dev/zero source → 4 MiB media"
);
}
#[test]
fn ewfacquire_clean_sector0_is_zeros() {
let path = format!("{DATA_DIR}/ewfacquire_clean.E01");
let mut reader = ewf::EwfReader::open(&path).expect("open");
let mut buf = [0xFFu8; 512];
reader.read_exact(&mut buf).expect("read sector 0");
assert_eq!(
buf,
[0u8; 512],
"ewfacquire_clean sourced from /dev/zero — sector 0 must be all zeros"
);
}
#[test]
fn gpt_130_partitions_opens_and_has_nonzero_size() {
let path = format!("{DATA_DIR}/gpt_130_partitions.E01");
let reader =
ewf::EwfReader::open(&path).expect("gpt_130_partitions.E01 must open");
assert!(
reader.total_size() > 0,
"gpt_130_partitions: total_size must be > 0"
);
}
#[test]
fn gpt_130_partitions_mbr_signature() {
let path = format!("{DATA_DIR}/gpt_130_partitions.E01");
let mut reader = ewf::EwfReader::open(&path).expect("open");
let mut mbr = [0u8; 512];
reader.read_exact(&mut mbr).expect("read sector 0 (MBR/GPT protective MBR)");
assert_eq!(mbr[510], 0x55, "GPT protective MBR byte 510 must be 0x55");
assert_eq!(mbr[511], 0xAA, "GPT protective MBR byte 511 must be 0xAA");
}
#[test]
fn multiseg_v1_total_size() {
let path = format!("{DATA_DIR}/multiseg_v1.E01");
let reader = ewf::EwfReader::open(&path).expect("multiseg_v1.E01 must open");
assert_eq!(
reader.total_size(),
10_485_760,
"multiseg_v1: 10 MiB source → 10 MiB media across 8 segments"
);
}
#[test]
fn multiseg_v1_full_media_md5() {
let path = format!("{DATA_DIR}/multiseg_v1.E01");
let mut reader = ewf::EwfReader::open(&path).expect("open");
assert_eq!(
full_media_md5(&mut reader),
"2692f3177a389e58906b5c9080aa1add",
"multiseg_v1 MD5 mismatch vs ewfverify ground truth"
);
}
#[test]
fn multiseg_v1_seek_across_segments() {
let path = format!("{DATA_DIR}/multiseg_v1.E01");
let mut reader = ewf::EwfReader::open(&path).expect("open");
let boundary_approx = 1_400_000u64;
reader.seek(SeekFrom::Start(boundary_approx)).expect("seek");
let mut buf = [0u8; 512];
reader
.read_exact(&mut buf)
.expect("cross-segment read must succeed");
}
#[test]
fn zeros_128s_ex01_media_size() {
let path = format!("{DATA_DIR}/zeros_128s.Ex01");
let reader = ewf::EwfReader::open(&path).expect("zeros_128s.Ex01 must open");
assert_eq!(
reader.total_size(),
65_536,
"zeros_128s: 128 sectors × 512 bytes = 65 536 bytes"
);
}
#[test]
fn zeros_128s_ex01_all_zeros() {
let path = format!("{DATA_DIR}/zeros_128s.Ex01");
let mut reader = ewf::EwfReader::open(&path).expect("open");
let mut buf = [0xFFu8; 512];
reader.read_exact(&mut buf).expect("read sector 0");
assert_eq!(
buf,
[0u8; 512],
"zeros_128s.Ex01 sourced from /dev/zero — all bytes must be zero"
);
}
#[test]
fn zeros_128s_compressed_ex01_media_size() {
let path = format!("{DATA_DIR}/zeros_128s_compressed.Ex01");
let reader =
ewf::EwfReader::open(&path).expect("zeros_128s_compressed.Ex01 must open");
assert_eq!(
reader.total_size(),
65_536,
"zeros_128s_compressed: same 64 KiB source, just stored compressed"
);
}
#[test]
fn zeros_128s_compressed_ex01_all_zeros() {
let path = format!("{DATA_DIR}/zeros_128s_compressed.Ex01");
let mut reader = ewf::EwfReader::open(&path).expect("open");
let mut buf = [0xFFu8; 512];
reader.read_exact(&mut buf).expect("read sector 0 from compressed EWF v2");
assert_eq!(
buf,
[0u8; 512],
"zeros_128s_compressed sourced from /dev/zero — all bytes must be zero"
);
}
#[test]
fn zeros_128s_compressed_matches_uncompressed_md5() {
let uncompressed_path = format!("{DATA_DIR}/zeros_128s.Ex01");
let compressed_path = format!("{DATA_DIR}/zeros_128s_compressed.Ex01");
let mut ur = ewf::EwfReader::open(&uncompressed_path).expect("open uncompressed");
let mut cr = ewf::EwfReader::open(&compressed_path).expect("open compressed");
assert_eq!(
full_media_md5(&mut ur),
full_media_md5(&mut cr),
"compressed and uncompressed Ex01 images must yield identical media MD5"
);
}