use crate::stack::status::{commit_reachable, count_revs, git_ref_exists, patch_in_base};
use std::fs;
mod support;
use support::{commit_file, git, init_repo};
#[test]
fn git_ref_exists_true_for_existing_branch() {
let (_dir, path) = init_repo();
assert!(git_ref_exists(&path, "main"));
assert!(git_ref_exists(&path, "HEAD"));
}
#[test]
fn git_ref_exists_false_for_missing_branch() {
let (_dir, path) = init_repo();
assert!(!git_ref_exists(&path, "no-such-branch"));
assert!(!git_ref_exists(&path, "origin/never-fetched"));
}
#[test]
fn count_revs_zero_when_branches_at_same_commit() {
let (_dir, path) = init_repo();
git(&path, &["branch", "twin"]);
assert_eq!(count_revs(&path, "main", "twin"), Some(0));
assert_eq!(count_revs(&path, "twin", "main"), Some(0));
}
#[test]
fn count_revs_returns_ahead_count() {
let (dir, path) = init_repo();
git(&path, &["branch", "base"]);
commit_file(&dir, &path, "a.txt", "a\n", "a");
commit_file(&dir, &path, "b.txt", "b\n", "b");
commit_file(&dir, &path, "c.txt", "c\n", "c");
assert_eq!(count_revs(&path, "base", "main"), Some(3));
assert_eq!(count_revs(&path, "main", "base"), Some(0));
}
#[test]
fn count_revs_none_for_invalid_ref() {
let (_dir, path) = init_repo();
assert_eq!(count_revs(&path, "main", "nope"), None);
}
#[test]
fn commit_reachable_true_when_sha_in_branch_history() {
let (dir, path) = init_repo();
let sha = commit_file(&dir, &path, "a.txt", "a\n", "a");
assert_eq!(commit_reachable(&path, &sha, "main"), Some(true));
}
#[test]
fn commit_reachable_false_when_sha_on_different_branch() {
let (dir, path) = init_repo();
git(&path, &["checkout", "-q", "-b", "feature"]);
let sha = commit_file(&dir, &path, "a.txt", "a\n", "feature only");
git(&path, &["checkout", "-q", "main"]);
assert_eq!(commit_reachable(&path, &sha, "main"), Some(false));
assert_eq!(commit_reachable(&path, &sha, "feature"), Some(true));
}
#[test]
fn commit_reachable_none_for_unknown_sha() {
let (_dir, path) = init_repo();
let bogus = "0000000000000000000000000000000000000000";
assert!(commit_reachable(&path, bogus, "main").is_none());
}
#[test]
fn commit_reachable_none_for_empty_sha() {
let (_dir, path) = init_repo();
assert!(commit_reachable(&path, "", "main").is_none());
}
#[test]
fn patch_in_base_detects_squash_merged_content() {
let (dir, path) = init_repo();
git(&path, &["checkout", "-q", "-b", "pr-feature"]);
let pr_head_sha = commit_file(&dir, &path, "feature.txt", "feature\n", "PR feature commit");
git(&path, &["checkout", "-q", "main"]);
fs::write(dir.path().join("feature.txt"), "feature\n").unwrap();
git(&path, &["add", "."]);
git(&path, &["commit", "-q", "-m", "Squash-merge PR feature"]);
assert_eq!(
commit_reachable(&path, &pr_head_sha, "main"),
Some(false),
"head SHA must not be reachable from squash-merged main"
);
assert_eq!(
patch_in_base(&path, &pr_head_sha, "main"),
Some(true),
"patch-id should match the squash on main"
);
}
#[test]
fn patch_in_base_returns_false_when_patch_absent() {
let (dir, path) = init_repo();
git(&path, &["checkout", "-q", "-b", "pr-feature"]);
let pr_head_sha = commit_file(&dir, &path, "feature.txt", "feature\n", "PR feature commit");
git(&path, &["checkout", "-q", "main"]);
assert_eq!(
patch_in_base(&path, &pr_head_sha, "main"),
Some(false),
"patch should not be in base when no equivalent commit exists"
);
}
#[test]
fn patch_in_base_unknown_when_sha_not_local() {
let (_dir, path) = init_repo();
assert_eq!(
patch_in_base(&path, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "main"),
None,
"absent SHA must surface as None, not Some(false)"
);
assert_eq!(
patch_in_base(&path, "", "main"),
None,
"empty SHA must surface as None"
);
}