// SPDX-FileCopyrightText: 2020 Robin Krahl // SPDX-License-Identifier: Apache-2.0 or MIT #![cfg(feature = "derive")] use merge::Merge; fn test(expected: T, mut left: T, right: T) { left.merge(right); assert_eq!(expected, left); } #[test] fn test_one_option_field() { #[derive(Debug, Merge, PartialEq)] struct S { #[merge(strategy = merge::option::overwrite_none)] field1: Option, } impl S { pub fn new(field1: Option) -> S { S { field1 } } } test(S::new(Some(1)), S::new(Some(1)), S::new(Some(2))); test(S::new(Some(1)), S::new(Some(1)), S::new(None)); test(S::new(Some(2)), S::new(None), S::new(Some(2))); test(S::new(None), S::new(None), S::new(None)); } #[test] fn test_two_option_fields() { #[derive(Debug, Merge, PartialEq)] struct S { #[merge(strategy = merge::option::overwrite_none)] field1: Option, #[merge(strategy = merge::option::overwrite_none)] field2: Option, } impl S { pub fn new(field1: Option, field2: Option) -> S { S { field1, field2 } } } // left.field1 == Some(1) // right.field1 == Some(2) test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(Some(2), Some(2)), ); test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(Some(2), None), ); test( S::new(Some(1), Some(2)), S::new(Some(1), None), S::new(Some(2), Some(2)), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(Some(2), None), ); // left.field1 == Some(1) // right.field1 == None test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(None, Some(2)), ); test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(None, None), ); test( S::new(Some(1), Some(2)), S::new(Some(1), None), S::new(None, Some(2)), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(None, None), ); // left.field1 == None // right.field1 == Some(2) test( S::new(Some(2), Some(1)), S::new(None, Some(1)), S::new(Some(2), Some(2)), ); test( S::new(Some(2), Some(1)), S::new(None, Some(1)), S::new(Some(2), None), ); test( S::new(Some(2), Some(2)), S::new(None, None), S::new(Some(2), Some(2)), ); test( S::new(Some(2), None), S::new(None, None), S::new(Some(2), None), ); // left.field1 == None // right.field1 == None test( S::new(None, Some(1)), S::new(None, Some(1)), S::new(None, Some(2)), ); test( S::new(None, Some(1)), S::new(None, Some(1)), S::new(None, None), ); test( S::new(None, Some(2)), S::new(None, None), S::new(None, Some(2)), ); test(S::new(None, None), S::new(None, None), S::new(None, None)); } #[test] fn test_skip_valid() { #[derive(Debug, Merge, PartialEq)] struct S { #[merge(strategy = merge::option::overwrite_none)] field1: Option, #[merge(skip)] field2: Option, } impl S { pub fn new(field1: Option, field2: Option) -> S { S { field1, field2 } } } // left.field1 == Some(1) // right.field1 == Some(2) test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(Some(2), Some(2)), ); test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(Some(2), None), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(Some(2), Some(2)), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(Some(2), None), ); // left.field1 == Some(1) // right.field1 == None test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(None, Some(2)), ); test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(None, None), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(None, Some(2)), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(None, None), ); // left.field1 == None // right.field1 == Some(2) test( S::new(Some(2), Some(1)), S::new(None, Some(1)), S::new(Some(2), Some(2)), ); test( S::new(Some(2), Some(1)), S::new(None, Some(1)), S::new(Some(2), None), ); test( S::new(Some(2), None), S::new(None, None), S::new(Some(2), Some(2)), ); test( S::new(Some(2), None), S::new(None, None), S::new(Some(2), None), ); // left.field1 == None // right.field1 == None test( S::new(None, Some(1)), S::new(None, Some(1)), S::new(None, Some(2)), ); test( S::new(None, Some(1)), S::new(None, Some(1)), S::new(None, None), ); test( S::new(None, None), S::new(None, None), S::new(None, Some(2)), ); test(S::new(None, None), S::new(None, None), S::new(None, None)); } #[test] fn test_skip_invalid() { #[derive(Debug, Merge, PartialEq)] struct S { #[merge(strategy = merge::option::overwrite_none)] field1: Option, #[merge(skip)] field2: usize, } impl S { pub fn new(field1: Option, field2: usize) -> S { S { field1, field2 } } } // left.field1 == Some(1) // right.field1 == Some(2) test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(Some(2), 2)); test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(Some(2), 0)); test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(Some(2), 2)); test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(Some(2), 0)); // left.field1 == Some(1) // right.field1 == None test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(None, 2)); test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(None, 0)); test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(None, 2)); test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(None, 0)); // left.field1 == None // right.field1 == Some(2) test(S::new(Some(2), 1), S::new(None, 1), S::new(Some(2), 2)); test(S::new(Some(2), 1), S::new(None, 1), S::new(Some(2), 0)); test(S::new(Some(2), 0), S::new(None, 0), S::new(Some(2), 2)); test(S::new(Some(2), 0), S::new(None, 0), S::new(Some(2), 0)); // left.field1 == None // right.field1 == None test(S::new(None, 1), S::new(None, 1), S::new(None, 2)); test(S::new(None, 1), S::new(None, 1), S::new(None, 0)); test(S::new(None, 0), S::new(None, 0), S::new(None, 2)); test(S::new(None, 0), S::new(None, 0), S::new(None, 0)); } #[test] fn test_strategy_usize_add() { #[derive(Debug, Merge, PartialEq)] struct S { #[merge(strategy = add)] field1: usize, } impl S { pub fn new(field1: usize) -> S { S { field1 } } } fn add(left: &mut usize, right: usize) { *left = *left + right; } test(S::new(0), S::new(0), S::new(0)); test(S::new(1), S::new(1), S::new(0)); test(S::new(1), S::new(0), S::new(1)); test(S::new(2), S::new(1), S::new(1)); } #[test] fn test_strategy_vec_append() { #[derive(Debug, Merge, PartialEq)] struct S { #[merge(strategy = append)] field1: Vec, } impl S { pub fn new(field1: Vec) -> S { S { field1 } } } fn append(left: &mut Vec, mut right: Vec) { left.append(&mut right); } test( S::new(vec![0, 1, 2, 3]), S::new(vec![0, 1]), S::new(vec![2, 3]), ); test( S::new(vec![0, 1, 2, 3]), S::new(vec![0, 1, 2, 3]), S::new(vec![]), ); test( S::new(vec![0, 1, 2, 3]), S::new(vec![]), S::new(vec![0, 1, 2, 3]), ); } #[test] fn test_unnamed_fields() { #[derive(Debug, Merge, PartialEq)] struct S( #[merge(strategy = merge::option::overwrite_none)] Option, #[merge(strategy = merge::option::overwrite_none)] Option, ); impl S { pub fn new(field1: Option, field2: Option) -> S { S(field1, field2) } } // left.field1 == Some(1) // right.field1 == Some(2) test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(Some(2), Some(2)), ); test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(Some(2), None), ); test( S::new(Some(1), Some(2)), S::new(Some(1), None), S::new(Some(2), Some(2)), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(Some(2), None), ); // left.field1 == Some(1) // right.field1 == None test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(None, Some(2)), ); test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(None, None), ); test( S::new(Some(1), Some(2)), S::new(Some(1), None), S::new(None, Some(2)), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(None, None), ); // left.field1 == None // right.field1 == Some(2) test( S::new(Some(2), Some(1)), S::new(None, Some(1)), S::new(Some(2), Some(2)), ); test( S::new(Some(2), Some(1)), S::new(None, Some(1)), S::new(Some(2), None), ); test( S::new(Some(2), Some(2)), S::new(None, None), S::new(Some(2), Some(2)), ); test( S::new(Some(2), None), S::new(None, None), S::new(Some(2), None), ); // left.field1 == None // right.field1 == None test( S::new(None, Some(1)), S::new(None, Some(1)), S::new(None, Some(2)), ); test( S::new(None, Some(1)), S::new(None, Some(1)), S::new(None, None), ); test( S::new(None, Some(2)), S::new(None, None), S::new(None, Some(2)), ); test(S::new(None, None), S::new(None, None), S::new(None, None)); } #[test] fn test_unnamed_fields_skip() { #[derive(Debug, Merge, PartialEq)] struct S( #[merge(strategy = merge::option::overwrite_none)] Option, #[merge(skip)] Option, ); impl S { pub fn new(field1: Option, field2: Option) -> S { S(field1, field2) } } // left.field1 == Some(1) // right.field1 == Some(2) test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(Some(2), Some(2)), ); test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(Some(2), None), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(Some(2), Some(2)), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(Some(2), None), ); // left.field1 == Some(1) // right.field1 == None test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(None, Some(2)), ); test( S::new(Some(1), Some(1)), S::new(Some(1), Some(1)), S::new(None, None), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(None, Some(2)), ); test( S::new(Some(1), None), S::new(Some(1), None), S::new(None, None), ); // left.field1 == None // right.field1 == Some(2) test( S::new(Some(2), Some(1)), S::new(None, Some(1)), S::new(Some(2), Some(2)), ); test( S::new(Some(2), Some(1)), S::new(None, Some(1)), S::new(Some(2), None), ); test( S::new(Some(2), None), S::new(None, None), S::new(Some(2), Some(2)), ); test( S::new(Some(2), None), S::new(None, None), S::new(Some(2), None), ); // left.field1 == None // right.field1 == None test( S::new(None, Some(1)), S::new(None, Some(1)), S::new(None, Some(2)), ); test( S::new(None, Some(1)), S::new(None, Some(1)), S::new(None, None), ); test( S::new(None, None), S::new(None, None), S::new(None, Some(2)), ); test(S::new(None, None), S::new(None, None), S::new(None, None)); } #[test] fn test_default_strategy() { #[derive(Debug, Merge, PartialEq)] struct N(#[merge(strategy = merge::num::saturating_add)] u8); #[derive(Debug, Merge, PartialEq)] #[merge(strategy = merge::option::overwrite_none)] struct S( Option, Option, #[merge(strategy = merge::num::saturating_add)] u8, #[merge(strategy = Merge::merge)] N, ); }