#![allow(clippy::unwrap_used, clippy::expect_used)]
mod helpers;
use std::collections::BTreeSet;
use git_meta_lib::*;
use helpers::*;
#[test]
fn merge_string_conflict_local_wins() {
let (dir_a, dir_c, _base_oid) = setup_three_way_base(|s| {
s.target(&Target::project()).set("status", "draft").unwrap();
});
let session_a = reopen_session(dir_a.path(), 2000);
session_a
.target(&Target::project())
.set("status", "published")
.unwrap();
let _ = session_a.serialize().unwrap();
let session_c = reopen_session(dir_c.path(), 2500);
session_c
.target(&Target::project())
.set("status", "archived")
.unwrap();
let _ = session_c.serialize().unwrap();
let repo_a = gix::open_opts(
dir_a.path(),
gix::open::Options::isolated()
.config_overrides(["user.name=Test User", "user.email=test@example.com"]),
)
.unwrap();
let a_new_oid = repo_a
.find_reference("refs/meta/local/main")
.unwrap()
.into_fully_peeled_id()
.unwrap()
.detach();
let src_objects = dir_a.path().join(".git").join("objects");
inject_remote_ref(&src_objects, dir_c.path(), a_new_oid);
let session_c2 = reopen_session(dir_c.path(), 3000);
let mat_output = session_c2.materialize(None).unwrap();
assert!(
!mat_output.results.is_empty(),
"materialize should process at least one ref"
);
assert_eq!(
mat_output.results[0].strategy,
MaterializeStrategy::ThreeWayMerge,
);
let val = session_c2
.target(&Target::project())
.get_value("status")
.unwrap();
assert_eq!(val, Some(MetaValue::String("archived".to_string())));
}
#[test]
fn merge_list_union() {
let (dir_a, dir_c, _base_oid) = setup_three_way_base(|s| {
s.target(&Target::project())
.list_push("comments", "base-entry")
.unwrap();
});
let session_a = reopen_session(dir_a.path(), 2000);
session_a
.target(&Target::project())
.list_push("comments", "from-a")
.unwrap();
let _ = session_a.serialize().unwrap();
let session_c = reopen_session(dir_c.path(), 2500);
session_c
.target(&Target::project())
.list_push("comments", "from-c")
.unwrap();
let _ = session_c.serialize().unwrap();
let repo_a = gix::open_opts(
dir_a.path(),
gix::open::Options::isolated()
.config_overrides(["user.name=Test User", "user.email=test@example.com"]),
)
.unwrap();
let a_new_oid = repo_a
.find_reference("refs/meta/local/main")
.unwrap()
.into_fully_peeled_id()
.unwrap()
.detach();
let src_objects = dir_a.path().join(".git").join("objects");
inject_remote_ref(&src_objects, dir_c.path(), a_new_oid);
let session_c2 = reopen_session(dir_c.path(), 3000);
let mat_output = session_c2.materialize(None).unwrap();
assert!(
!mat_output.results.is_empty(),
"materialize should process at least one ref"
);
assert_eq!(
mat_output.results[0].strategy,
MaterializeStrategy::ThreeWayMerge,
);
let entries = session_c2
.target(&Target::project())
.list_entries("comments")
.unwrap();
let values: Vec<&str> = entries.iter().map(|e| e.value.as_str()).collect();
assert!(
values.contains(&"base-entry"),
"should still have base entry, got: {values:?}"
);
assert!(
values.contains(&"from-a"),
"should have A's entry, got: {values:?}"
);
assert!(
values.contains(&"from-c"),
"should have C's entry, got: {values:?}"
);
}
#[test]
fn merge_set_union() {
let (dir_a, dir_c, _base_oid) = setup_three_way_base(|s| {
s.target(&Target::project())
.set_add("owners", "shared")
.unwrap();
});
let session_a = reopen_session(dir_a.path(), 2000);
let mut owners_a = BTreeSet::new();
owners_a.insert("shared".to_string());
owners_a.insert("alice".to_string());
session_a
.target(&Target::project())
.set("owners", MetaValue::Set(owners_a))
.unwrap();
let _ = session_a.serialize().unwrap();
let session_c = reopen_session(dir_c.path(), 2500);
let mut owners_c = BTreeSet::new();
owners_c.insert("shared".to_string());
owners_c.insert("bob".to_string());
session_c
.target(&Target::project())
.set("owners", MetaValue::Set(owners_c))
.unwrap();
let _ = session_c.serialize().unwrap();
let repo_a = gix::open_opts(
dir_a.path(),
gix::open::Options::isolated()
.config_overrides(["user.name=Test User", "user.email=test@example.com"]),
)
.unwrap();
let a_new_oid = repo_a
.find_reference("refs/meta/local/main")
.unwrap()
.into_fully_peeled_id()
.unwrap()
.detach();
let src_objects = dir_a.path().join(".git").join("objects");
inject_remote_ref(&src_objects, dir_c.path(), a_new_oid);
let session_c2 = reopen_session(dir_c.path(), 3000);
let mat_output = session_c2.materialize(None).unwrap();
assert!(
!mat_output.results.is_empty(),
"materialize should process at least one ref"
);
assert_eq!(
mat_output.results[0].strategy,
MaterializeStrategy::ThreeWayMerge,
);
let val = session_c2
.target(&Target::project())
.get_value("owners")
.unwrap();
assert!(val.is_some(), "owners should exist");
if let Some(MetaValue::Set(members)) = val {
assert!(
members.contains("shared"),
"should still have shared, got: {members:?}"
);
assert!(
members.contains("alice"),
"should have alice from A, got: {members:?}"
);
assert!(
members.contains("bob"),
"should have bob from C, got: {members:?}"
);
} else {
panic!("expected MetaValue::Set, got: {val:?}");
}
}