use assert_cmd::Command;
use std::process::Command as Sys;
use tempfile::TempDir;
fn repo_with(old_files: &[(&str, &str)]) -> TempDir {
let dir = tempfile::tempdir().unwrap();
sys(&dir, &["init", "-q"]);
sys(&dir, &["config", "user.email", "t@t"]);
sys(&dir, &["config", "user.name", "t"]);
for (p, c) in old_files {
let full = dir.path().join(p);
std::fs::create_dir_all(full.parent().unwrap()).unwrap();
std::fs::write(full, c).unwrap();
}
sys(&dir, &["add", "."]);
sys(&dir, &["commit", "-q", "-m", "init"]);
dir
}
fn sys(dir: &TempDir, args: &[&str]) {
let ok = Sys::new("git")
.args(args)
.current_dir(dir.path())
.status()
.unwrap()
.success();
assert!(ok, "git {args:?} failed");
}
fn diff_after(dir: &TempDir, new_files: &[(&str, &str)]) -> String {
for (p, c) in new_files {
std::fs::write(dir.path().join(p), c).unwrap();
}
let out = Sys::new("git")
.args(["diff"])
.current_dir(dir.path())
.output()
.unwrap();
String::from_utf8(out.stdout).unwrap()
}
fn revert(dir: &TempDir) {
sys(dir, &["checkout", "--", "."]);
}
#[test]
fn select_subset_applies_to_old_state() {
let dir = repo_with(&[("f", "a\nb\nc\nd\ne\n")]);
let diff = diff_after(&dir, &[("f", "a\nB\nc\nD\ne\n")]);
revert(&dir);
Command::cargo_bin("hunkpick")
.unwrap()
.args([
"select",
"1",
"--verify-result-diff-git",
"-C",
dir.path().to_str().unwrap(),
])
.write_stdin(diff.clone())
.assert()
.success();
Command::cargo_bin("hunkpick")
.unwrap()
.args([
"select",
"1-2",
"--verify-result-diff-git",
"-C",
dir.path().to_str().unwrap(),
])
.write_stdin(diff)
.assert()
.success();
}
#[test]
fn select_all_applies() {
let dir = repo_with(&[("f", "a\nb\nc\nd\ne\nf\ng\n")]);
let diff = diff_after(&dir, &[("f", "a\nB\nc\nD\ne\nF\ng\n")]);
revert(&dir);
Command::cargo_bin("hunkpick")
.unwrap()
.args([
"select",
"1-3",
"--verify-result-diff-git",
"-C",
dir.path().to_str().unwrap(),
])
.write_stdin(diff)
.assert()
.success();
}
#[test]
fn tampered_diff_fails_git_check() {
let dir = repo_with(&[("f", "a\nb\nc\nd\ne\n")]);
let diff = diff_after(&dir, &[("f", "a\nB\nc\nD\ne\n")]);
revert(&dir);
let tampered = diff.replace(" c\n", " X\n");
assert_ne!(diff, tampered, "tampering must change the diff");
Command::cargo_bin("hunkpick")
.unwrap()
.args([
"select",
"1",
"--verify-result-diff-git",
"-C",
dir.path().to_str().unwrap(),
])
.write_stdin(tampered)
.assert()
.failure()
.code(70);
}