use super::*;
fn base_with_worktrees(root: &Path, name: &str, count: usize) -> (PathBuf, Vec<PathBuf>) {
let base = root.join(name);
let common = base.join(".git");
std::fs::create_dir_all(common.join("objects")).unwrap();
std::fs::write(common.join("HEAD"), "ref: refs/heads/main\n").unwrap();
let mut workspaces = Vec::new();
for i in 0..count {
let id = format!("wt-{i}");
let admin = common.join("worktrees").join(&id);
std::fs::create_dir_all(&admin).unwrap();
std::fs::write(admin.join("HEAD"), "ref: refs/heads/main\n").unwrap();
let workspace = root.join(&id);
std::fs::create_dir_all(&workspace).unwrap();
std::fs::write(
workspace.join(".git"),
format!("gitdir: {}\n", admin.display()),
)
.unwrap();
workspaces.push(workspace);
}
(base, workspaces)
}
#[test]
fn base_clone_ok_with_no_live_workspaces() {
let check = check_base_clones(&[]);
assert_eq!(check.status, CheckStatus::Ok);
}
#[test]
fn base_clone_ok_for_a_healthy_worktree() {
let dir = tempfile::tempdir().unwrap();
let (_base, workspaces) = base_with_worktrees(dir.path(), "proj", 2);
let check = check_base_clones(&workspaces);
assert_eq!(check.status, CheckStatus::Ok, "{}", check.message);
assert!(
check.message.contains("2 live worktree(s)"),
"{}",
check.message
);
}
#[test]
fn base_clone_ignores_a_plain_checkout() {
let dir = tempfile::tempdir().unwrap();
let plain = dir.path().join("plain");
std::fs::create_dir_all(plain.join(".git").join("objects")).unwrap();
let check = check_base_clones(&[plain]);
assert_eq!(check.status, CheckStatus::Ok);
assert!(
check.message.contains("0 live worktree(s)"),
"{}",
check.message
);
}
#[test]
fn base_clone_fails_when_the_admin_dir_is_gone() {
let dir = tempfile::tempdir().unwrap();
let (base, workspaces) = base_with_worktrees(dir.path(), "proj", 1);
std::fs::remove_dir_all(base.join(".git").join("worktrees")).unwrap();
let check = check_base_clones(&workspaces);
assert_eq!(check.status, CheckStatus::Fail, "{}", check.message);
assert!(
check.message.contains(&base.display().to_string()),
"the failing base must be named: {}",
check.message
);
assert!(
check.message.contains("1 live worktree(s)"),
"the blast radius must be reported: {}",
check.message
);
assert!(
check.message.contains("Do NOT recursively delete"),
"remediation must preserve the quarantine discipline: {}",
check.message
);
}
#[test]
fn base_clone_fails_when_the_object_database_is_gone() {
let dir = tempfile::tempdir().unwrap();
let (base, workspaces) = base_with_worktrees(dir.path(), "proj", 1);
std::fs::remove_dir_all(base.join(".git").join("objects")).unwrap();
let check = check_base_clones(&workspaces);
assert_eq!(check.status, CheckStatus::Fail, "{}", check.message);
assert!(
check.message.contains("no object database"),
"{}",
check.message
);
}
#[test]
fn base_clone_counts_every_worktree_behind_one_base() {
let dir = tempfile::tempdir().unwrap();
let (base, workspaces) = base_with_worktrees(dir.path(), "proj", 5);
std::fs::remove_dir_all(base.join(".git")).unwrap();
let check = check_base_clones(&workspaces);
assert_eq!(check.status, CheckStatus::Fail);
assert!(
check.message.contains("5 live worktree(s)"),
"{}",
check.message
);
}
#[test]
fn base_clone_reports_the_legacy_bare_layout_too() {
let dir = tempfile::tempdir().unwrap();
let base = dir.path().join(".base");
let admin = base.join("worktrees").join("wt-0");
std::fs::create_dir_all(&admin).unwrap();
std::fs::create_dir_all(base.join("objects")).unwrap();
std::fs::write(base.join("HEAD"), "ref: refs/heads/main\n").unwrap();
let workspace = dir.path().join("wt-0");
std::fs::create_dir_all(&workspace).unwrap();
std::fs::write(
workspace.join(".git"),
format!("gitdir: {}\n", admin.display()),
)
.unwrap();
assert_eq!(
check_base_clones(std::slice::from_ref(&workspace)).status,
CheckStatus::Ok
);
std::fs::remove_dir_all(base.join("worktrees")).unwrap();
std::fs::remove_dir_all(base.join("objects")).unwrap();
std::fs::remove_file(base.join("HEAD")).unwrap();
let check = check_base_clones(&[workspace]);
assert_eq!(check.status, CheckStatus::Fail, "{}", check.message);
assert!(
check.message.contains(&base.display().to_string()),
"{}",
check.message
);
}