#![allow(clippy::unwrap_used)]
use std::fs;
use std::process::Command;
fn mkit_bin() -> &'static str {
env!("CARGO_BIN_EXE_mkit")
}
fn run_in(cwd: &std::path::Path, args: &[&str]) -> std::process::Output {
let xdg = tempfile::tempdir().expect("xdg tempdir");
let out = Command::new(mkit_bin())
.args(args)
.current_dir(cwd)
.env("XDG_CONFIG_HOME", xdg.path())
.output()
.expect("spawn mkit");
drop(xdg);
out
}
fn big_payload() -> Vec<u8> {
let n = 1024 * 1024 + 256 * 1024; let mut buf = Vec::with_capacity(n);
let mut state: u64 = 0x00C0_FFEE;
for _ in 0..n {
state = state.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^= z >> 31;
buf.push((z & 0xFF) as u8);
}
buf
}
#[test]
fn large_file_roundtrips_and_reports_clean() {
let td = tempfile::tempdir().unwrap();
let p = td.path();
assert!(run_in(p, &["init"]).status.success(), "init failed");
assert!(run_in(p, &["keygen"]).status.success(), "keygen failed");
let payload = big_payload();
fs::write(p.join("big.bin"), &payload).unwrap();
let out = run_in(p, &["add", "big.bin"]);
assert!(out.status.success(), "add failed: {out:?}");
let out = run_in(p, &["commit", "-m", "big"]);
assert!(
out.status.success(),
"commit of >1 MiB file must succeed (no non-blob error): {}",
String::from_utf8_lossy(&out.stderr)
);
let out = run_in(p, &["status", "--porcelain"]);
assert!(out.status.success(), "status failed: {out:?}");
assert!(
out.stdout.is_empty(),
"clean >1 MiB file must report unmodified, got: {:?}",
String::from_utf8_lossy(&out.stdout)
);
let out = run_in(p, &["diff"]);
assert!(out.status.success(), "diff failed: {out:?}");
assert!(
out.stdout.is_empty(),
"clean >1 MiB file must produce no diff, got: {:?}",
String::from_utf8_lossy(&out.stdout)
);
}
fn cat(cwd: &std::path::Path, hex: &str) -> Vec<u8> {
let out = run_in(cwd, &["cat", hex]);
assert!(
out.status.success(),
"cat {hex} failed: {}",
String::from_utf8_lossy(&out.stderr)
);
out.stdout
}
#[test]
fn cat_reassembles_chunked_blob() {
let td = tempfile::tempdir().unwrap();
let p = td.path();
assert!(run_in(p, &["init"]).status.success());
assert!(run_in(p, &["keygen"]).status.success());
let payload = big_payload();
fs::write(p.join("big.bin"), &payload).unwrap();
assert!(run_in(p, &["add", "big.bin"]).status.success());
assert!(
run_in(p, &["commit", "-m", "big"]).status.success(),
"commit failed"
);
let log = run_in(p, &["log", "--format=json"]);
assert!(log.status.success(), "log failed: {log:?}");
let log_out = String::from_utf8(log.stdout).unwrap();
let first = log_out.lines().next().expect("at least one commit");
let needle = "\"tree\":\"";
let start = first.find(needle).expect("json has a tree field") + needle.len();
let tree_hex = first[start..start + 64].to_owned();
assert_eq!(tree_hex.len(), 64, "tree hex must be full 64 chars");
let tree_dump = String::from_utf8(cat(p, &tree_hex)).unwrap();
let entry_hex = tree_dump
.lines()
.find(|l| l.ends_with(" big.bin"))
.and_then(|l| l.split_whitespace().nth(1))
.expect("tree has a big.bin entry")
.to_owned();
let dumped = cat(p, &entry_hex);
assert_eq!(
dumped, payload,
"cat must reassemble the chunked blob byte-identically"
);
}
#[test]
fn rm_dirty_guard_does_not_false_positive_clean_large_file() {
let td = tempfile::tempdir().unwrap();
let p = td.path();
assert!(run_in(p, &["init"]).status.success());
assert!(run_in(p, &["keygen"]).status.success());
let payload = big_payload();
fs::write(p.join("big.bin"), &payload).unwrap();
assert!(run_in(p, &["add", "big.bin"]).status.success());
assert!(
run_in(p, &["commit", "-m", "big"]).status.success(),
"commit failed"
);
let out = run_in(p, &["rm", "big.bin"]);
assert!(
out.status.success(),
"rm of a clean >1 MiB file must not trip the dirty-guard: {}",
String::from_utf8_lossy(&out.stderr)
);
assert!(
!p.join("big.bin").exists(),
"rm should have deleted the worktree file"
);
}
#[test]
fn checkout_restores_chunked_file_byte_identically() {
let td = tempfile::tempdir().unwrap();
let p = td.path();
assert!(run_in(p, &["init"]).status.success());
assert!(run_in(p, &["keygen"]).status.success());
let payload = big_payload();
fs::write(p.join("big.bin"), &payload).unwrap();
assert!(run_in(p, &["add", "big.bin"]).status.success());
assert!(
run_in(p, &["commit", "-m", "big"]).status.success(),
"commit failed"
);
assert!(run_in(p, &["branch", "without"]).status.success());
assert!(run_in(p, &["checkout", "without"]).status.success());
assert!(
run_in(p, &["rm", "big.bin"]).status.success(),
"rm on the side branch failed"
);
assert!(
run_in(p, &["commit", "-m", "drop big"]).status.success(),
"commit of removal failed"
);
assert!(
!p.join("big.bin").exists(),
"big.bin should be gone on the side branch"
);
let out = run_in(p, &["checkout", "main"]);
assert!(
out.status.success(),
"checkout main failed: {}",
String::from_utf8_lossy(&out.stderr)
);
let restored = fs::read(p.join("big.bin")).unwrap();
assert_eq!(
restored, payload,
"checkout must restore the >1 MiB file byte-identically"
);
}