#[cfg(test)]
mod tests {
use crate::policy::*;
use crate::{merged, deep_merge_ref, deep_merge_reporting, deep_merge_from, deep_merge_from_with_policy, deep_merge_from_reporting};
#[cfg(feature = "std")]
use std::string::{String, ToString};
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::string::{String, ToString};
#[derive(Debug, Clone, PartialEq)]
struct TestStruct {
name: String,
value: i32,
}
impl DeepMerge<DefaultPolicy> for TestStruct {
fn merge_with_policy(&mut self, other: Self, policy: &DefaultPolicy) {
self.name.merge_with_policy(other.name, policy);
self.value.merge_with_policy(other.value, policy);
}
fn merge_ref(&mut self, src: &Self, policy: &DefaultPolicy)
where
Self: Clone,
{
DeepMerge::merge_ref(&mut self.name, &src.name, policy);
DeepMerge::merge_ref(&mut self.value, &src.value, policy);
}
fn merge_with_policy_reporting(&mut self, other: Self, policy: &DefaultPolicy) -> MergeOutcome {
let old_name = self.name.clone();
let old_value = self.value;
self.merge_with_policy(other, policy);
if self.name == old_name && self.value == old_value {
MergeOutcome::Unchanged
} else {
MergeOutcome::Changed
}
}
}
#[test]
fn test_merge_ref_string() {
let mut dst = String::from("hello");
let src = String::from("world");
DeepMerge::merge_ref(&mut dst, &src, &DefaultPolicy);
assert_eq!(dst, "world");
assert_eq!(src, "world"); }
#[test]
fn test_merge_ref_reporting_string() {
let mut dst = String::from("hello");
let src = String::from("world");
let outcome = DeepMerge::merge_ref_reporting(&mut dst, &src, &DefaultPolicy);
assert_eq!(outcome, MergeOutcome::Changed);
assert_eq!(dst, "world");
let src2 = String::from("world");
let outcome2 = DeepMerge::merge_ref_reporting(&mut dst, &src2, &DefaultPolicy);
assert_eq!(outcome2, MergeOutcome::Unchanged);
assert_eq!(dst, "world");
}
#[test]
fn test_merged_convenience_functions() {
let dst = String::from("hello");
let src = String::from("world");
let result = merged(dst.clone(), src.clone());
assert_eq!(result, "world");
assert_eq!(dst, "hello");
assert_eq!(src, "world");
}
#[test]
fn test_deep_merge_ref_functions() {
let mut dst = String::from("hello");
let src = String::from("world");
deep_merge_ref(&mut dst, &src);
assert_eq!(dst, "world");
assert_eq!(src, "world"); }
#[test]
fn test_deep_merge_reporting_functions() {
let mut dst = String::from("hello");
let src = String::from("world");
let outcome = deep_merge_reporting(&mut dst, src);
assert_eq!(outcome, MergeOutcome::Changed);
assert_eq!(dst, "world");
let src2 = String::from("world");
let outcome2 = deep_merge_reporting(&mut dst, src2);
assert_eq!(outcome2, MergeOutcome::Unchanged);
}
#[test]
fn test_custom_struct_merge_ref() {
let mut dst = TestStruct {
name: "original".to_string(),
value: 42,
};
let src = TestStruct {
name: "updated".to_string(),
value: 100,
};
DeepMerge::merge_ref(&mut dst, &src, &DefaultPolicy);
assert_eq!(dst.name, "updated");
assert_eq!(dst.value, 100);
assert_eq!(src.name, "updated");
assert_eq!(src.value, 100);
}
#[test]
fn test_merge_outcome_methods() {
assert!(MergeOutcome::Changed.is_changed());
assert!(!MergeOutcome::Changed.is_unchanged());
assert!(!MergeOutcome::Unchanged.is_changed());
assert!(MergeOutcome::Unchanged.is_unchanged());
}
#[test]
fn test_merge_ref_avoids_unnecessary_clones() {
let mut dst = String::from("hello");
let src = String::from("");
let policy = ComposedPolicy::new(DefaultPolicy).with_when_condition(Condition::NonEmpty);
DeepMerge::merge_ref(&mut dst, &src, &policy);
assert_eq!(dst, "hello"); }
#[test]
fn test_efficient_change_detection() {
let mut dst = String::from("test");
let src = String::from("test");
let outcome = DeepMerge::merge_ref_reporting(&mut dst, &src, &DefaultPolicy);
assert_eq!(outcome, MergeOutcome::Unchanged);
assert_eq!(dst, "test");
}
#[test]
fn test_string_merge_replace() {
let mut dst = String::from("hello");
let src = String::from("world");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Replace);
DeepMerge::merge_ref(&mut dst, &src, &policy);
assert_eq!(dst, "world");
}
#[test]
fn test_string_merge_keep() {
let mut dst = String::from("hello");
let src = String::from("world");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Keep);
DeepMerge::merge_ref(&mut dst, &src, &policy);
assert_eq!(dst, "hello");
}
#[test]
fn test_string_merge_concat() {
let mut dst = String::from("hello");
let src = String::from("world");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Concat);
DeepMerge::merge_ref(&mut dst, &src, &policy);
assert_eq!(dst, "helloworld");
}
#[test]
fn test_string_merge_concat_with_sep() {
let mut dst = String::from("hello");
let src = String::from("world");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::ConcatWithSep(" "));
DeepMerge::merge_ref(&mut dst, &src, &policy);
assert_eq!(dst, "hello world");
}
#[test]
fn test_string_merge_concat_with_sep_empty_dst() {
let mut dst = String::from("");
let src = String::from("world");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::ConcatWithSep(" "));
DeepMerge::merge_ref(&mut dst, &src, &policy);
assert_eq!(dst, "world"); }
#[test]
fn test_string_merge_concat_with_sep_empty_src() {
let mut dst = String::from("hello");
let src = String::from("");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::ConcatWithSep(" "));
DeepMerge::merge_ref(&mut dst, &src, &policy);
assert_eq!(dst, "hello"); }
#[test]
fn test_string_merge_concat_with_sep_both_empty() {
let mut dst = String::from("");
let src = String::from("");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::ConcatWithSep(" "));
DeepMerge::merge_ref(&mut dst, &src, &policy);
assert_eq!(dst, ""); }
#[test]
fn test_string_merge_change_reporting_concat() {
let mut dst = String::from("hello");
let src = String::from("world");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Concat);
let outcome = DeepMerge::merge_ref_reporting(&mut dst, &src, &policy);
assert_eq!(outcome, MergeOutcome::Changed);
assert_eq!(dst, "helloworld");
}
#[test]
fn test_string_merge_change_reporting_concat_empty_src() {
let mut dst = String::from("hello");
let src = String::from("");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Concat);
let outcome = DeepMerge::merge_ref_reporting(&mut dst, &src, &policy);
assert_eq!(outcome, MergeOutcome::Unchanged); assert_eq!(dst, "hello");
}
#[test]
fn test_string_merge_change_reporting_keep() {
let mut dst = String::from("hello");
let src = String::from("world");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Keep);
let outcome = DeepMerge::merge_ref_reporting(&mut dst, &src, &policy);
assert_eq!(outcome, MergeOutcome::Unchanged);
assert_eq!(dst, "hello");
}
#[test]
fn test_string_merge_with_composed_policy() {
let mut config = TestStruct {
name: "prefix".to_string(),
value: 42,
};
let update = TestStruct {
name: "suffix".to_string(),
value: 100,
};
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Concat);
DeepMerge::merge_ref(&mut config.name, &update.name, &policy);
assert_eq!(config.name, "prefixsuffix");
config.name = "prefix".to_string();
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::ConcatWithSep("-"));
DeepMerge::merge_ref(&mut config.name, &update.name, &policy);
assert_eq!(config.name, "prefix-suffix");
}
#[test]
fn test_deep_merge_from_string_str() {
let mut dst = String::from("hello");
let src = "world";
dst.merge_from(src);
assert_eq!(dst, "world");
}
#[test]
fn test_deep_merge_from_string_str_concat() {
let mut dst = String::from("hello");
let src = "world";
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Concat);
dst.merge_from_with_policy(src, &policy);
assert_eq!(dst, "helloworld");
}
#[test]
fn test_deep_merge_from_string_str_with_separator() {
let mut dst = String::from("hello");
let src = "world";
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::ConcatWithSep(" "));
dst.merge_from_with_policy(src, &policy);
assert_eq!(dst, "hello world");
}
#[test]
fn test_deep_merge_from_string_string_ref() {
let mut dst = String::from("hello");
let src = String::from("world");
dst.merge_from(&src);
assert_eq!(dst, "world");
assert_eq!(src, "world");
}
#[test]
fn test_deep_merge_from_change_reporting() {
let mut dst = String::from("hello");
let src = "world";
let outcome = dst.merge_from_reporting(src);
assert_eq!(outcome, MergeOutcome::Changed);
assert_eq!(dst, "world");
let src2 = "world";
let outcome2 = dst.merge_from_reporting(src2);
assert_eq!(outcome2, MergeOutcome::Unchanged);
}
#[test]
fn test_deep_merge_from_concat_empty_src() {
let mut dst = String::from("hello");
let src = "";
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Concat);
let outcome = dst.merge_from_with_policy_reporting(src, &policy);
assert_eq!(outcome, MergeOutcome::Unchanged);
assert_eq!(dst, "hello");
}
#[test]
fn test_deep_merge_from_bridge_implementation() {
let mut dst = String::from("hello");
let src_owned = String::from("world");
let src_ref = String::from("test");
dst.merge_from_with_policy(src_owned, &DefaultPolicy);
assert_eq!(dst, "world");
dst.merge_from_with_policy(&src_ref, &DefaultPolicy);
assert_eq!(dst, "test");
assert_eq!(src_ref, "test"); }
#[test]
fn test_top_level_deep_merge_from_functions() {
let mut dst = String::from("hello");
let src = "world";
deep_merge_from(&mut dst, src);
assert_eq!(dst, "world");
dst = String::from("hello");
let policy = ComposedPolicy::new(DefaultPolicy).with_string_merge(StringMerge::Concat);
deep_merge_from_with_policy(&mut dst, src, &policy);
assert_eq!(dst, "helloworld");
dst = String::from("hello");
let outcome = deep_merge_from_reporting(&mut dst, "different");
assert_eq!(outcome, MergeOutcome::Changed);
assert_eq!(dst, "different");
}
#[test]
fn test_deep_merge_from_no_clone_required() {
struct NoCopyStruct {
data: String,
}
impl DeepMergeFrom<&str, DefaultPolicy> for NoCopyStruct {
fn merge_from_with_policy(&mut self, other: &str, _policy: &DefaultPolicy) {
self.data = other.to_string();
}
}
let mut dst = NoCopyStruct {
data: "original".to_string(),
};
let src = "updated"; dst.merge_from_with_policy(src, &DefaultPolicy);
assert_eq!(dst.data, "updated");
}
}