blob: b04b753357f44bdc708a16de8adfefdecd522d53 [file] [log] [blame] [edit]
// SPDX-FileCopyrightText: 2020 Robin Krahl <[email protected]>
// SPDX-License-Identifier: Apache-2.0 or MIT
#![cfg(feature = "derive")]
use merge::Merge;
fn test<T: std::fmt::Debug + Merge + PartialEq>(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<usize>,
}
impl S {
pub fn new(field1: Option<usize>) -> 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<usize>,
#[merge(strategy = merge::option::overwrite_none)]
field2: Option<usize>,
}
impl S {
pub fn new(field1: Option<usize>, field2: Option<usize>) -> 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<usize>,
#[merge(skip)]
field2: Option<usize>,
}
impl S {
pub fn new(field1: Option<usize>, field2: Option<usize>) -> 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<usize>,
#[merge(skip)]
field2: usize,
}
impl S {
pub fn new(field1: Option<usize>, 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 += 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<usize>,
}
impl S {
pub fn new(field1: Vec<usize>) -> S {
S { field1 }
}
}
fn append(left: &mut Vec<usize>, mut right: Vec<usize>) {
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<usize>,
#[merge(strategy = merge::option::overwrite_none)] Option<usize>,
);
impl S {
pub fn new(field1: Option<usize>, field2: Option<usize>) -> 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<usize>,
#[merge(skip)] Option<usize>,
);
impl S {
pub fn new(field1: Option<usize>, field2: Option<usize>) -> 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<usize>,
Option<usize>,
#[merge(strategy = merge::num::saturating_add)] u8,
#[merge(strategy = Merge::merge)] N,
);
test(
S(Some(0), Some(1), 5, N(u8::MAX)),
S(Some(0), None, 2, N(u8::MAX)),
S(Some(2), Some(1), 3, N(1)),
);
}