use std::{fs, path::PathBuf};
use hdiff_update_core::{
apply_patch, create_patch, sha256_file, ApplyPatchOptions, CreatePatchOptions,
};
use tempfile::tempdir;
#[test]
fn hdiff_tools_roundtrip_small_binary() {
let workspace = workspace_root();
let hdiffz = workspace.join("hdiffz.exe");
let hpatchz = workspace.join("hpatchz.exe");
if !hdiffz.is_file() || !hpatchz.is_file() {
eprintln!("skipping HDiffPatch roundtrip because hdiffz.exe or hpatchz.exe is missing");
return;
}
let dir = tempdir().expect("tempdir");
let old = dir.path().join("old.bin");
let new = dir.path().join("new.bin");
let patch = dir.path().join("delta.hpatch");
let output = dir.path().join("output.bin");
let mut old_bytes = vec![0_u8; 1024 * 1024];
let mut new_bytes = vec![0_u8; 1024 * 1024];
for index in 0..old_bytes.len() {
old_bytes[index] = (index % 251) as u8;
new_bytes[index] = old_bytes[index];
}
for index in 100_000..105_000 {
new_bytes[index] = ((index * 7) % 251) as u8;
}
fs::write(&old, old_bytes).expect("old");
fs::write(&new, new_bytes).expect("new");
let created = create_patch(&CreatePatchOptions {
old_path: old.clone(),
new_path: new.clone(),
patch_path: patch.clone(),
hdiffz_path: Some(hdiffz),
force: true,
step_size: Some("64k".to_string()),
old_window_size: Some("512k".to_string()),
compression: Some("zstd-20".to_string()),
checksum: Some("xxh128".to_string()),
parallel_threads: Some(2),
})
.expect("create patch");
assert!(created.patch.size > 0);
let expected = sha256_file(&new).expect("hash new").sha256;
let applied = apply_patch(&ApplyPatchOptions {
old_path: old,
patch_path: patch,
output_path: output,
hpatchz_path: Some(hpatchz),
force: true,
expected_sha256: Some(expected.clone()),
cache_size: Some("8m".to_string()),
parallel_threads: Some(2),
verify_checksums: true,
})
.expect("apply patch");
assert_eq!(applied.output.sha256, expected);
assert_eq!(
fs::read(new).expect("read new"),
fs::read(applied.output.path).expect("read out")
);
}
fn workspace_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.and_then(|path| path.parent())
.expect("workspace root")
.to_path_buf()
}