use zipatch_rs::IndexError;
use zipatch_rs::index::{FilePatchSource, PatchSource};
use zipatch_rs::test_utils::MemoryPatchSource;
#[test]
fn memory_patch_source_new_wraps_single_buffer() {
let bytes: Vec<u8> = (0..16u8).collect();
let mut src = MemoryPatchSource::new(bytes.clone());
assert_eq!(src.patch_count(), 1);
let mut buf = [0u8; 8];
src.read(zipatch_rs::newtypes::PatchIndex::new(0), 0, &mut buf)
.unwrap();
assert_eq!(&buf, &bytes[..8]);
}
#[test]
fn memory_patch_source_from_slice_copies_data() {
let bytes: Vec<u8> = (0..16u8).collect();
let mut src = MemoryPatchSource::from_slice(&bytes);
assert_eq!(src.patch_count(), 1);
let mut buf = [0u8; 16];
src.read(zipatch_rs::newtypes::PatchIndex::new(0), 0, &mut buf)
.unwrap();
assert_eq!(&buf, bytes.as_slice());
}
#[test]
fn memory_patch_source_new_chain_patch_count() {
let p0 = vec![0xAAu8; 8];
let p1 = vec![0xBBu8; 8];
let src = MemoryPatchSource::new_chain(vec![p0, p1]);
assert_eq!(src.patch_count(), 2);
}
#[test]
fn memory_patch_source_offset_overflow_returns_too_short() {
let mut src = MemoryPatchSource::new(vec![0u8; 16]);
let mut buf = [0u8; 4];
let err = src
.read(zipatch_rs::newtypes::PatchIndex::new(0), u64::MAX, &mut buf)
.expect_err("u64::MAX offset must error");
assert!(
matches!(err, IndexError::PatchSourceTooShort { .. }),
"expected TooShort, got {err:?}"
);
}
#[test]
fn file_patch_source_from_file_wraps_open_handle() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("patch.bin");
std::fs::write(&path, b"ABCDEFGH").unwrap();
let f = std::fs::File::open(&path).unwrap();
let mut src = FilePatchSource::from_file(f);
assert_eq!(src.patch_count(), 1);
let mut buf = [0u8; 4];
src.read(zipatch_rs::newtypes::PatchIndex::new(0), 0, &mut buf)
.unwrap();
assert_eq!(&buf, b"ABCD");
}
#[test]
fn file_patch_source_patch_count_multi() {
let tmp = tempfile::tempdir().unwrap();
let p0 = tmp.path().join("p0.bin");
let p1 = tmp.path().join("p1.bin");
let p2 = tmp.path().join("p2.bin");
std::fs::write(&p0, b"P0").unwrap();
std::fs::write(&p1, b"P1").unwrap();
std::fs::write(&p2, b"P2").unwrap();
let src = FilePatchSource::open_chain([&p0, &p1, &p2]).unwrap();
assert_eq!(src.patch_count(), 3);
}
#[test]
fn file_patch_source_open_chain_empty_iterator_yields_empty_source() {
let paths: Vec<std::path::PathBuf> = Vec::new();
let mut src = FilePatchSource::open_chain(paths).expect("empty open_chain must succeed");
assert_eq!(src.patch_count(), 0);
let mut buf = [0u8; 0];
let err = src
.read(zipatch_rs::newtypes::PatchIndex::new(0), 0, &mut buf)
.expect_err("read against empty chain must surface PatchIndexOutOfRange");
match err {
IndexError::PatchIndexOutOfRange { patch, count } => {
assert_eq!(patch, zipatch_rs::newtypes::PatchIndex::new(0));
assert_eq!(count, 0);
}
other => panic!("expected PatchIndexOutOfRange, got {other:?}"),
}
}