use serde_json::Value;
use crate::merge::conflict::{Conflict, MergeResult};
pub fn merge_atomic(path: &str, base: &Value, current: &Value, proposed: &Value) -> MergeResult {
if current == base && proposed == base {
return MergeResult::Merged(base.clone());
}
if current != base && proposed == base {
return MergeResult::Merged(current.clone());
}
if current == base && proposed != base {
return MergeResult::Merged(proposed.clone());
}
if current == proposed {
return MergeResult::Merged(current.clone());
}
MergeResult::Conflicts(vec![Conflict::value_mismatch(
path,
base.clone(),
current.clone(),
proposed.clone(),
)])
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_atomic_same_change_accepted() {
let result = merge_atomic("version", &json!(1), &json!(2), &json!(2));
assert!(result.is_merged());
assert_eq!(result.unwrap_merged(), json!(2));
}
#[test]
fn test_atomic_current_change_only() {
let result = merge_atomic("version", &json!(1), &json!(2), &json!(1));
assert!(result.is_merged());
assert_eq!(result.unwrap_merged(), json!(2));
}
#[test]
fn test_atomic_proposed_change_only() {
let result = merge_atomic("version", &json!(1), &json!(1), &json!(3));
assert!(result.is_merged());
assert_eq!(result.unwrap_merged(), json!(3));
}
#[test]
fn test_atomic_divergent_changes_conflict() {
let result = merge_atomic("version", &json!(1), &json!(2), &json!(3));
assert!(result.is_conflict());
}
#[test]
fn test_atomic_object_divergent_conflict() {
let result = merge_atomic(
"config",
&json!({"a": 1}),
&json!({"a": 1, "b": 2}),
&json!({"a": 1, "c": 3}),
);
assert!(result.is_conflict());
}
#[test]
fn test_atomic_all_equal() {
let result = merge_atomic("version", &json!(5), &json!(5), &json!(5));
assert!(result.is_merged());
assert_eq!(result.unwrap_merged(), json!(5));
}
#[test]
fn test_atomic_null_values() {
let result = merge_atomic(
"field",
&json!("value"),
&json!(Value::Null),
&json!("value"),
);
assert!(result.is_merged());
assert_eq!(result.unwrap_merged(), Value::Null);
}
}