use super::*;
use crate::tracker::fixtures::{
binding, checkout, commit, default_binding, empty_remote, env, env_at, landing_repo,
legacy_remote, local_unpushed, remote_with_branch, remote_with_config, store_clone, tip,
tracked, unpushable_remote, BRANCH,
};
use std::fs;
use tempfile::TempDir;
#[test]
fn a_no_remote_prime_is_silent_and_persists_nothing() {
let tmp = TempDir::new().unwrap();
let env = env(&tmp.path().join("home"), &tmp.path().join("state"));
let b = binding(None, &tmp.path().join("landing"));
prime(&b, &env).unwrap();
assert!(!env.xdg.clone_dir(Path::new(&b.invocation_path)).root().exists());
}
#[test]
fn prime_pre_clones_an_established_remote_store_into_a_local_ref() {
let tmp = TempDir::new().unwrap();
let remote = remote_with_branch(tmp.path());
let landing = landing_repo(tmp.path()); let env = env(&tmp.path().join("home"), &tmp.path().join("state"));
prime(&tracked(&remote, &landing, &landing), &env).unwrap();
assert_eq!(tip(&landing, BRANCH), tip(&remote, BRANCH));
}
#[test]
fn prime_pre_skips_clone_in_when_the_local_branch_is_already_present() {
let tmp = TempDir::new().unwrap();
let remote = remote_with_branch(tmp.path());
let landing = store_clone(tmp.path(), &remote); let before = tip(&landing, BRANCH);
let other = checkout(tmp.path(), &remote, "other");
commit(&other, "next.txt", "next");
git(&other, &["push", "-q", "origin", BRANCH]).unwrap();
let env = env(&tmp.path().join("home"), &tmp.path().join("state"));
prime(&tracked(&remote, &landing, &landing), &env).unwrap();
assert_eq!(tip(&landing, BRANCH), before); }
#[test]
fn prime_pre_quarantines_a_legacy_remote_store_instead_of_adopting_it() {
let tmp = TempDir::new().unwrap();
let remote = legacy_remote(tmp.path());
let landing = landing_repo(tmp.path());
let env = env(&tmp.path().join("home"), &tmp.path().join("state"));
prime(&tracked(&remote, &landing, &landing), &env).unwrap();
assert!(!local_branch(&landing, BRANCH)); }
#[test]
fn prime_post_over_a_legacy_remote_converges_without_touching_it() {
let tmp = TempDir::new().unwrap();
let remote = legacy_remote(tmp.path());
let store = local_unpushed(tmp.path()); let before = tip(&remote, BRANCH);
prime_post(&binding(Some(&remote), &store), &env_at(1)).unwrap();
assert_eq!(tip(&remote, BRANCH), before); }
#[test]
fn prime_pre_in_a_bootstrap_clones_nothing() {
let tmp = TempDir::new().unwrap();
let remote = empty_remote(tmp.path()); let landing = landing_repo(tmp.path());
let env = env(&tmp.path().join("home"), &tmp.path().join("state"));
prime(&tracked(&remote, &landing, &landing), &env).unwrap();
assert!(!local_branch(&landing, BRANCH));
}
#[test]
fn prime_post_founds_an_absent_remote_by_pushing() {
let tmp = TempDir::new().unwrap();
let remote = empty_remote(tmp.path());
let store = local_unpushed(tmp.path());
prime_post(&binding(Some(&remote), &store), &env_at(1)).unwrap();
assert_eq!(tip(&remote, BRANCH), tip(&store, "HEAD")); }
#[test]
fn prime_post_brings_current_then_publishes_to_an_established_remote() {
let tmp = TempDir::new().unwrap();
let remote = remote_with_branch(tmp.path());
let store = store_clone(tmp.path(), &remote);
let landed = commit(&store, "landed.txt", "landed"); prime_post(&binding(Some(&remote), &store), &env_at(1)).unwrap();
assert_eq!(tip(&remote, BRANCH), landed); }
#[test]
fn prime_post_founding_reject_degrades_silently_and_persists_nothing() {
let tmp = TempDir::new().unwrap();
let remote = unpushable_remote(tmp.path());
let store = local_unpushed(tmp.path());
prime_post(&binding(Some(&remote), &store), &env_at(1)).unwrap(); assert!(git(&remote, &["rev-parse", BRANCH]).is_err()); }
#[test]
fn prime_post_established_push_reject_errors_never_degrades() {
let tmp = TempDir::new().unwrap();
let remote = remote_with_branch(tmp.path());
let store = store_clone(tmp.path(), &remote);
let other = checkout(tmp.path(), &remote, "other");
commit(&other, "remote.txt", "remote");
git(&other, &["push", "-q", "origin", BRANCH]).unwrap();
commit(&store, "local.txt", "local");
assert!(prime_post(&binding(Some(&remote), &store), &env_at(1)).is_err());
}
#[test]
fn prime_post_in_stealth_is_a_no_op() {
let tmp = TempDir::new().unwrap();
let store = local_unpushed(tmp.path());
prime_post(&binding(None, &store), &env_at(1)).unwrap(); }
#[test]
fn the_ephemeral_gap_compares_the_acting_remote_to_the_durable_ladder() {
let tmp = TempDir::new().unwrap();
let env = env(&tmp.path().join("home"), &tmp.path().join("state"));
let repo = landing_repo(tmp.path()); let b = binding(None, &repo); assert_eq!(
ephemeral_gap(&b, &env, "git@hub:r").as_deref(),
Some("nothing (plain commands run stealth)")
);
git(&repo, &["remote", "add", "origin", "git@hub:r"]).unwrap();
assert_eq!(ephemeral_gap(&b, &env, "git@hub:r"), None);
let cfg = env.xdg.user_config();
fs::create_dir_all(cfg.parent().unwrap()).unwrap();
fs::write(&cfg, "remote = \"git@hub:durable\"\n").unwrap();
assert_eq!(ephemeral_gap(&b, &env, "git@hub:r").as_deref(), Some("`git@hub:durable`"));
assert_eq!(ephemeral_gap(&b, &env, "git@hub:durable"), None);
let binding_path = env.xdg.clone_dir(std::path::Path::new(&b.invocation_path)).binding();
fs::create_dir_all(binding_path.parent().unwrap()).unwrap();
fs::write(&binding_path, "remote = \"git@hub:bind\"\n").unwrap();
assert_eq!(ephemeral_gap(&b, &env, "git@hub:r").as_deref(), Some("`git@hub:bind`"));
assert_eq!(ephemeral_gap(&b, &env, "git@hub:bind"), None);
let stealth_landing = tmp.path().join("stealth-landing");
fs::create_dir_all(stealth_landing.join("config")).unwrap();
fs::write(stealth_landing.join("config").join("balls.toml"), "task_remote = \"none\"\n").unwrap();
let declared = Binding { landing: stealth_landing.to_string_lossy().into_owned(), ..b };
assert_eq!(
ephemeral_gap(&declared, &env, "git@hub:r").as_deref(),
Some("declared stealth (the landing `task_remote` sentinel)")
);
}
#[test]
fn store_elsewhere_reports_a_differently_configured_origin() {
let tmp = TempDir::new().unwrap();
let remote = remote_with_config(tmp.path(), "balls/work");
let landing = local_unpushed(tmp.path());
let b = default_binding(Some(&remote), &landing);
assert_eq!(
store_elsewhere(&b, &landing, b.remote.as_deref().unwrap()),
Some("balls/work".to_string())
);
}
#[test]
fn store_elsewhere_is_silent_when_origin_agrees_or_is_unreadable() {
let tmp = TempDir::new().unwrap();
let landing = local_unpushed(tmp.path());
let agree = remote_with_config(tmp.path(), crate::DEFAULT_TASKS_BRANCH);
let b = default_binding(Some(&agree), &landing);
assert_eq!(store_elsewhere(&b, &landing, b.remote.as_deref().unwrap()), None);
let bare = empty_remote(tmp.path());
let b = default_binding(Some(&bare), &landing);
assert_eq!(store_elsewhere(&b, &landing, b.remote.as_deref().unwrap()), None);
}
#[test]
fn prime_warns_about_a_relocated_store_but_does_not_abort() {
let tmp = TempDir::new().unwrap();
let remote = remote_with_config(tmp.path(), "balls/work");
let landing = local_unpushed(tmp.path());
let env = env(&tmp.path().join("home"), &tmp.path().join("state"));
let b = Binding { landing: landing.to_string_lossy().into_owned(), ..default_binding(Some(&remote), &landing) };
prime(&b, &env).unwrap();
}