use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use tempfile::TempDir;
use super::{check, gate_fingerprint, read, record, verdict_path, worktree_oid, write, Verdict};
fn repo() -> (TempDir, PathBuf) {
let tmp = TempDir::new().unwrap();
let root = tmp.path().join("repo");
fs::create_dir_all(root.join("scripts")).unwrap();
fs::write(root.join("scripts/pre-commit"), "#!/bin/sh\ncargo test\n").unwrap();
fs::write(root.join("code.rs"), "fn main() {}\n").unwrap();
assert!(Command::new("git").arg("-C").arg(&root).arg("init").arg("-q").status().unwrap().success());
(tmp, root)
}
fn scratch(tmp: &TempDir) -> PathBuf {
tmp.path().join("scratch")
}
#[test]
fn worktree_oid_is_stable_and_content_sensitive() {
let (tmp, root) = repo();
let a = worktree_oid(&root, &scratch(&tmp)).unwrap();
let b = worktree_oid(&root, &scratch(&tmp)).unwrap();
assert_eq!(a, b, "same worktree, same tree");
assert_eq!(a.len(), 40, "a full object id, not a truncation");
fs::write(root.join("code.rs"), "fn main() { let _ = 1; }\n").unwrap();
let c = worktree_oid(&root, &scratch(&tmp)).unwrap();
assert_ne!(a, c, "an edited worktree is a different tree");
}
#[test]
fn worktree_oid_outside_a_repo_reports_gits_voice() {
let tmp = TempDir::new().unwrap();
let err = worktree_oid(tmp.path(), &scratch(&tmp)).unwrap_err();
assert!(err.to_string().contains("git add -A"), "names the failing act: {err}");
}
#[test]
fn fingerprint_is_the_toolchain_alone() {
let (tmp, root) = repo();
let a = gate_fingerprint(&root, &scratch(&tmp), "rustc 1.0").unwrap();
assert_eq!(a, gate_fingerprint(&root, &scratch(&tmp), "rustc 1.0").unwrap());
assert_eq!(a.len(), 40, "a git object id, importable as a verdict key");
let b = gate_fingerprint(&root, &scratch(&tmp), "rustc 2.0").unwrap();
assert_ne!(a, b, "a toolchain bump is a different gate");
fs::write(root.join("scripts/pre-commit"), "#!/bin/sh\ncargo test && leak-scan\n").unwrap();
let c = gate_fingerprint(&root, &scratch(&tmp), "rustc 1.0").unwrap();
assert_eq!(a, c, "the gate scripts are the tree's business, not the fingerprint's");
}
#[test]
fn store_roundtrip_absence_and_corruption() {
let tmp = TempDir::new().unwrap();
let territory = tmp.path().join("territory");
assert_eq!(read(&territory, "t", "g").unwrap(), None, "absence is a miss, not an error");
let v = Verdict { pass: true, builder: "Gushed".into() };
write(&territory, "t", "g", &v).unwrap();
assert_eq!(read(&territory, "t", "g").unwrap(), Some(v));
fs::write(verdict_path(&territory, "t", "g"), "not = [toml").unwrap();
assert!(read(&territory, "t", "g").is_err(), "a corrupt record must not half-work");
fs::create_dir_all(verdict_path(&territory, "dir", "key")).unwrap();
assert!(read(&territory, "dir", "key").is_err(), "a non-NotFound IO failure surfaces");
}
#[test]
fn check_sees_only_a_pass_on_the_exact_tree() {
let (tmp, root) = repo();
let territory = tmp.path().join("territory");
let s = scratch(&tmp);
assert!(!check(&root, &s, &territory, "rustc 1.0").unwrap(), "empty store misses");
record(&root, &s, &territory, "rustc 1.0", false, "Gushed").unwrap();
assert!(!check(&root, &s, &territory, "rustc 1.0").unwrap(), "a recorded FAIL is not a pass");
record(&root, &s, &territory, "rustc 1.0", true, "Gushed").unwrap();
assert!(check(&root, &s, &territory, "rustc 1.0").unwrap(), "recorded pass hits");
assert!(!check(&root, &s, &territory, "rustc 2.0").unwrap(), "another gate misses");
fs::write(root.join("code.rs"), "fn main() { let _ = 2; }\n").unwrap();
assert!(!check(&root, &s, &territory, "rustc 1.0").unwrap(), "another tree misses");
record(&root, &s, &territory, "rustc 1.0", true, "Gushed").unwrap();
fs::write(root.join("scripts/pre-commit"), "#!/bin/sh\ncargo test && leak-scan\n").unwrap();
assert!(!check(&root, &s, &territory, "rustc 1.0").unwrap(), "an edited gate script misses");
}
#[test]
fn scratch_holds_no_leftovers_after_any_call() {
let (tmp, root) = repo();
let s = scratch(&tmp);
let territory = tmp.path().join("territory");
record(&root, &s, &territory, "rustc 1.0", true, "Gushed").unwrap();
check(&root, &s, &territory, "rustc 1.0").unwrap();
let leftovers: Vec<_> = fs::read_dir(&s).unwrap().collect();
assert!(leftovers.is_empty(), "scratch must be swept: {leftovers:?}");
}
#[test]
fn fingerprint_failure_still_sweeps_scratch() {
let (tmp, root) = repo();
let s = scratch(&tmp);
fs::remove_dir_all(root.join(".git")).unwrap();
fs::write(root.join(".git"), "gitdir: /nonexistent\n").unwrap();
assert!(gate_fingerprint(&root, &s, "rustc 1.0").is_err());
assert!(!s.join("gate-blob").exists());
}
#[test]
fn verdict_path_is_the_key() {
let p = verdict_path(Path::new("/t"), "abc", "def");
assert_eq!(p, Path::new("/t/verdicts/abc-def.toml"));
}
#[test]
fn import_adopts_a_foreign_store_file_and_refuses_malformation() {
let tmp = TempDir::new().unwrap();
let remote = tmp.path().join("remote");
let local = tmp.path().join("local");
let tree = "a".repeat(40);
let gate = "b".repeat(40);
let v = Verdict { pass: true, builder: "github-actions".into() };
write(&remote, &tree, &gate, &v).unwrap();
let file = verdict_path(&remote, &tree, &gate);
let key = super::import(&local, &file).unwrap();
assert_eq!(key, (tree.clone(), gate.clone()));
assert_eq!(read(&local, &tree, &gate).unwrap(), Some(v), "the record crossed whole");
for bad in ["short-name.toml", "nosuffix", &format!("{tree}-{gate}.json")] {
let p = tmp.path().join(bad);
fs::write(&p, "pass = true\nbuilder = \"x\"\n").unwrap();
assert!(super::import(&local, &p).is_err(), "{bad} must be refused");
}
let corrupt = tmp.path().join(format!("{tree}-{gate}.toml"));
fs::write(&corrupt, "not a verdict").unwrap();
assert!(super::import(&local, &corrupt).is_err(), "a malformed body is refused");
assert!(super::import(&local, Path::new("/")).is_err(), "no filename at all");
}