use super::super::{Governance, config_branches, governing_config};
use crate::git_tree::tests::fixture::Fixture;
use crate::git_tree::{GitTree, GitTreeError};
fn tip(fx: &Fixture, id: &str) -> String {
GitTree::from_repo(&fx.path)
.unwrap()
.agents
.into_iter()
.find(|a| a.agent_id == id)
.unwrap()
.tip_oid
}
fn branch_tip(fx: &Fixture, name: &str) -> String {
config_branches(&fx.path)
.unwrap()
.into_iter()
.find(|b| b.name == name)
.unwrap()
.tip_oid
}
#[test]
fn governing_config_is_the_fork_point_for_a_fresh_agent() {
let fx = Fixture::new();
fx.agent_off("r1", "config/default");
let gov = governing_config(&fx.path, &tip(&fx, "r1")).unwrap();
assert_eq!(gov.oid, branch_tip(&fx, "default"));
assert_eq!(gov.followed_lineage().as_deref(), Some("default"));
assert_eq!(gov.diverged_lineages(), 0);
assert!(gov.files.contains(&"version".to_string()));
}
#[test]
fn governing_config_follows_the_lineage_tip_after_the_branch_advances() {
let fx = Fixture::new();
fx.agent_off("r1", "config/default");
fx.commit_other("workflow.yaml", "events: {}\n");
let gov = governing_config(&fx.path, &tip(&fx, "r1")).unwrap();
assert_eq!(gov.oid, branch_tip(&fx, "default"));
assert_eq!(gov.governance, Governance::Follows("default".to_owned()));
assert!(gov.files.contains(&"version".to_string()));
assert!(gov.files.contains(&"workflow.yaml".to_string()));
assert_eq!(
gov.label(),
format!("policy follows config/default, now at {}", gov.short_oid)
);
}
#[test]
fn two_diverged_lineages_hold_the_conversation_on_its_fork_commit() {
let fx = Fixture::new();
fx.agent_off("r1", "config/default");
let fork_point = branch_tip(&fx, "default");
fx.config_off("strict", "config/default");
fx.commit_other("workflow.yaml", "events: {}\n");
let gov = governing_config(&fx.path, &tip(&fx, "r1")).unwrap();
assert_eq!(gov.oid, fork_point);
assert_eq!(
gov.governance,
Governance::Held {
diverged_lineages: 2
}
);
assert_eq!(gov.followed_lineage(), None);
assert_eq!(gov.diverged_lineages(), 2);
assert!(!gov.files.contains(&"workflow.yaml".to_string()));
assert_eq!(
gov.label(),
format!(
"policy held at {} — 2 diverged config lineages",
gov.short_oid
)
);
}
#[test]
fn governing_config_picks_the_nearer_ancestor_arriving_later() {
let fx = Fixture::new();
fx.config_off("strict", "config/default");
fx.agent_off("r1", "config/strict");
let gov = governing_config(&fx.path, &tip(&fx, "r1")).unwrap();
assert_eq!(gov.oid, branch_tip(&fx, "strict"));
assert_eq!(gov.followed_lineage().as_deref(), Some("strict"));
}
#[test]
fn governing_config_keeps_the_nearer_ancestor_arriving_first() {
let fx = Fixture::new();
fx.config_off("aaa", "config/default");
fx.agent_off("r1", "config/aaa");
let gov = governing_config(&fx.path, &tip(&fx, "r1")).unwrap();
assert_eq!(gov.oid, branch_tip(&fx, "aaa"));
}
#[test]
fn governing_config_folds_two_equal_candidates() {
let fx = Fixture::new();
fx.config_alias("twin", "config/default");
fx.agent_off("r1", "config/default");
let gov = governing_config(&fx.path, &tip(&fx, "r1")).unwrap();
assert_eq!(gov.oid, branch_tip(&fx, "default"));
assert_eq!(gov.governance, Governance::Follows("default".to_owned()));
}
#[test]
fn governing_config_skips_an_unrelated_orphan_config() {
let fx = Fixture::new();
fx.agent_off("r1", "config/default");
fx.orphan_config("island");
let gov = governing_config(&fx.path, &tip(&fx, "r1")).unwrap();
assert_eq!(gov.followed_lineage().as_deref(), Some("default"));
}
#[test]
fn governing_config_declines_an_agent_with_no_config_ancestor() {
let fx = Fixture::new();
fx.orphan_agent("x1");
let err = governing_config(&fx.path, &tip(&fx, "x1")).unwrap_err();
assert!(matches!(err, GitTreeError::Governing(_)), "{err}");
assert!(err.to_string().contains("no config/* ancestor"), "{err}");
}
#[test]
fn governing_config_declines_incomparable_candidates() {
let fx = Fixture::new();
fx.agent_off("r1", "config/default");
fx.orphan_config("island");
fx.cross_merge("r1", "island");
let err = governing_config(&fx.path, &tip(&fx, "r1")).unwrap_err();
assert!(matches!(err, GitTreeError::Governing(_)), "{err}");
assert!(err.to_string().contains("incomparable"), "{err}");
}