use super::*;
use crate::test_support::{fixture, git, remove};
fn repository(name: &str) -> (PathBuf, PathBuf) {
let root = fixture(name);
let remote = root.join("remote.git");
let repo = root.join("repo");
git(&root, &["init", "--bare", "--quiet", "--initial-branch=main", "remote.git"]);
git(&root, &["init", "--quiet", "--initial-branch=main", "repo"]);
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=base"]);
git(&repo, &["remote", "add", "origin", remote.to_str().expect("utf-8")]);
git(&repo, &["push", "--quiet", "--set-upstream", "origin", "main"]);
return (root, repo);
}
fn oid(repo: &Path, revision: &str) -> String {
return String::from_utf8_lossy(&git(repo, &["rev-parse", revision]).stdout).trim().to_owned();
}
fn git_says_ancestor(repo: &Path, ancestor: &str, descendant: &str) -> bool {
return crate::test_support::git_output(repo, &["merge-base", "--is-ancestor", ancestor, descendant]).status.success();
}
fn watch(repo: &Path) -> TipWatch {
let overlay: Vec<(OsString, OsString)> = crate::test_support::isolated_overlay();
return watch_tip(repo, Path::new("/usr/bin/git"), overlay.as_slice(), &[]).expect("a branch with a tip");
}
#[test]
fn the_walk_agrees_with_git_about_ancestry() {
let (root, repo) = repository("atr-walk");
let base = oid(&repo, "HEAD");
git(&repo, &["switch", "--quiet", "--create", "side"]);
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=side"]);
let side = oid(&repo, "HEAD");
git(&repo, &["switch", "--quiet", "main"]);
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=main"]);
git(&repo, &["merge", "--quiet", "--no-ff", "--no-edit", "side"]);
let merged = oid(&repo, "HEAD");
let layout = read_layout_in(&repo, crate::test_support::isolated_overlay().as_slice()).expect("layout");
let database = ObjectDatabase::open(layout.common_dir.as_path(), None, layout.object_format).expect("database");
for (from, target) in [(&merged, &base), (&merged, &side), (&side, &base), (&base, &side), (&side, &merged), (&base, &base)] {
assert_eq!(
reaches(&database, &layout, from, target, WALK_BUDGET),
Some(git_says_ancestor(&repo, target, from)),
"{target} from {from}"
);
}
assert_eq!(reaches(&database, &layout, &merged, &base, 0), None, "a walk past its budget does not guess");
remove(&root);
}
#[test]
fn a_branch_that_grew_ahead_of_its_upstream_is_handed_over() {
let (root, repo) = repository("atr-grew");
let watched = watch(&repo);
assert_eq!(tip_to_push(&watched), None, "nothing moved");
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=more"]);
assert_eq!(tip_to_push(&watched), Some(oid(&repo, "HEAD")));
remove(&root);
}
#[test]
fn a_branch_that_moved_backwards_is_not_handed_over() {
let (root, repo) = repository("atr-back");
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=more"]);
git(&repo, &["push", "--quiet", "origin", "main"]);
let watched = watch(&repo);
git(&repo, &["reset", "--quiet", "--hard", "HEAD~1"]);
assert_eq!(tip_to_push(&watched), None);
remove(&root);
}
#[test]
fn a_rewritten_branch_is_not_handed_over() {
let (root, repo) = repository("atr-rewrite");
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=local"]);
let watched = watch(&repo);
git(&repo, &["commit", "--quiet", "--amend", "--allow-empty", "--message=local, rewritten"]);
assert_eq!(tip_to_push(&watched), None);
remove(&root);
}
#[test]
fn a_diverged_branch_and_a_branch_without_an_upstream_are_not_handed_over() {
let (root, repo) = repository("atr-diverged");
git(&repo, &["switch", "--quiet", "--create", "loose"]);
let loose = watch(&repo);
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=more"]);
assert_eq!(tip_to_push(&loose), None, "no upstream");
git(&repo, &["switch", "--quiet", "main"]);
let watched = watch(&repo);
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=mine"]);
git(&repo, &["switch", "--quiet", "--detach", "HEAD~1"]);
git(&repo, &["commit", "--quiet", "--allow-empty", "--message=theirs"]);
let theirs = oid(&repo, "HEAD");
git(&repo, &["update-ref", "refs/remotes/origin/main", &theirs]);
git(&repo, &["switch", "--quiet", "main"]);
assert_eq!(tip_to_push(&watched), None);
remove(&root);
}