use std::{
cmp::Ordering,
hash::{DefaultHasher, Hash},
};
use itertools::Itertools;
use total_maps::{Commonality, TotalBTreeMap, TotalHashMap};
macro_rules! common {
(mod $mod:ident, $Map:ident, $BaseMap:ident, $as_inner_mut:ident, $iter_eq:expr $(,)?) => {
mod $mod {
#[cfg(feature = "serde")]
use std::collections::$BaseMap;
use super::*;
#[test]
fn populate_basic() {
let mut m = $Map::<_, _>::new();
assert_eq!(m.insert("foo", "v_foo"), "");
assert_eq!(m.insert("baz", ""), "");
assert_eq!(m.insert("bar", "v_bar"), "");
assert_eq!(m.insert("foo", "v_foo_2"), "v_foo");
assert!(!m.is_empty());
assert_eq!(m.len(), 2);
assert_iter_eq(m.keys(), [&"bar", &"foo"], $iter_eq);
assert_iter_eq(m.values(), [&"v_bar", &"v_foo_2"], $iter_eq);
assert_iter_eq(m.iter(), [(&"bar", &"v_bar"), (&"foo", &"v_foo_2")], $iter_eq);
assert_iter_eq(&m, [(&"bar", &"v_bar"), (&"foo", &"v_foo_2")], $iter_eq);
assert_iter_eq(m.clone().into_keys(), ["bar", "foo"], $iter_eq);
assert_iter_eq(m.clone().into_values(), ["v_bar", "v_foo_2"], $iter_eq);
assert_iter_eq(m, [("bar", "v_bar"), ("foo", "v_foo_2")], $iter_eq);
}
#[test]
fn populate_common_only() {
let mut m = $Map::<_, _>::new();
assert_eq!(m.insert("foo", ""), "");
assert_eq!(m.insert("bar", ""), "");
assert!(m.is_empty());
assert_eq!(m.len(), 0);
assert!(m.into_iter().next().is_none());
}
#[test]
fn removal() {
let mut m = $Map::<_, _>::new();
assert_eq!(m.insert("foo", "bar"), "");
assert_eq!(m.insert("baz", "quux"), "");
assert_eq!(m.len(), 2);
assert_iter_eq(m.iter(), [(&"baz", &"quux"), (&"foo", &"bar")], $iter_eq);
assert_eq!(m.remove(&"foo"), "bar");
assert_eq!(m.remove(&"xyzzy"), "");
assert_eq!(m.len(), 1);
assert_iter_eq(m.iter(), [(&"baz", &"quux")], $iter_eq);
m.clear();
assert_eq!(m.len(), 0);
assert!(m.into_iter().next().is_none());
}
#[test]
fn access() {
let mut m = $Map::<_, _>::new();
assert_eq!(m.insert("foo", "bar"), "");
assert_eq!(m.insert("baz", ""), "");
assert!(m.contains_key(&"foo"));
assert_eq!(m.get(&"foo"), &"bar");
assert_eq!(m[&"foo"], "bar");
assert!(!m.contains_key(&"baz"));
assert_eq!(m.get(&"baz"), &"");
assert_eq!(m[&"baz"], "");
assert!(!m.contains_key(&"quux"));
assert_eq!(m.get(&"quux"), &"");
assert_eq!(m[&"quux"], "");
}
#[test]
fn entry_mut() {
let mut m = $Map::<_, _>::new();
let entry = m.entry("foo");
assert_eq!(*entry, "");
drop(entry);
assert!(!m.contains_key(&"foo"));
let mut entry = m.entry("foo");
assert_eq!(*entry, "");
*entry = "bar";
drop(entry);
assert_eq!(m.get(&"foo"), &"bar");
let mut entry = m.entry("foo");
assert_eq!(*entry, "bar");
*entry = "baz";
drop(entry);
assert_eq!(m.get(&"foo"), &"baz");
let mut entry = m.entry("foo");
assert_eq!(*entry, "baz");
*entry = "";
drop(entry);
assert!(!m.contains_key(&"foo"));
}
#[test]
fn as_inner_mut() {
let mut m = $Map::<_, _>::new();
assert_eq!(m.insert("foo", "bar"), "");
assert_eq!(m.insert("baz", "quux"), "");
let mut view = m.$as_inner_mut();
let it = view.values_mut();
let mut values = it.collect::<Vec<_>>();
values.sort();
assert_eq!(values.len(), 2);
assert_eq!(values[0], &mut "bar");
*values[0] = "bar2";
assert_eq!(values[1], &mut "quux");
*values[1] = "";
drop(view);
assert_eq!(m.len(), 1);
assert_iter_eq(m.iter(), [(&"foo", &"bar2")], $iter_eq);
}
#[test]
fn from_iter() {
let elems =
[("foo", "bar"), ("baz", "quux"), ("xyzzy", ""), ("foo", "bar2"), ("baz", "")];
let m = elems.into_iter().collect::<$Map<_, _>>();
assert_eq!(m.len(), 1);
assert_iter_eq(m.iter(), [(&"foo", &"bar2")], $iter_eq);
let mut m = $Map::<_, _>::new();
m.insert("xyzzy", "plugh");
m.insert("monkey", "banana");
m.extend(elems);
assert_eq!(m.len(), 2);
assert_iter_eq(m.iter(), [(&"foo", &"bar2"), (&"monkey", &"banana")], $iter_eq);
}
#[test]
fn map_eq() {
assert_eq!(
[("foo", "bar"), ("baz", "quux")].into_iter().collect::<$Map<_, _>>(),
[("baz", "quux"), ("foo", "bar")].into_iter().collect::<$Map<_, _>>()
);
let nan_map = $Map::<&str, (), NaNCommonality>::new();
assert_eq!(nan_map, nan_map);
}
#[test]
fn uncommon_entry() {
let mut m = $Map::<_, _>::new();
assert_eq!(m.insert("foo", "bar"), "");
assert!(m.uncommon_entry("nope").is_none());
{
let mut entry = m.uncommon_entry("foo").unwrap();
*entry = "baz";
}
assert_eq!(m.get("foo"), &"baz");
{
let mut entry = m.uncommon_entry("foo").unwrap();
*entry = "";
}
assert!(!m.contains_key("foo"));
}
#[test]
fn recursive_data_structure() {
#[derive(Debug, PartialEq, Default)]
struct Recursive($Map<(), Box<Recursive>>);
let rec = Recursive::default();
assert_eq!(rec, rec);
}
#[cfg(feature = "serde")]
#[test]
fn serde_serialize() {
let entries = [("foo", "bar"), ("baz", "quux")];
let total = entries.into_iter().collect::<$Map<_, _>>();
let json = serde_json::to_string(&total).unwrap();
let actual = serde_json::from_str::<$BaseMap<_, _>>(&json).unwrap();
let expected = entries.into_iter().collect();
assert_eq!(actual, expected);
}
#[cfg(feature = "serde")]
#[test]
fn serde_deserialize() {
let entries = [("foo", "bar"), ("baz", "quux")];
let base = entries.into_iter().collect::<$BaseMap<_, _>>();
let json = serde_json::to_string(&base).unwrap();
let actual = serde_json::from_str::<$Map<_, _>>(&json).unwrap();
let expected = entries.into_iter().collect();
assert_eq!(actual, expected);
}
#[cfg(feature = "serde")]
#[test]
fn serde_deserialize_with_common_entries() {
let entries = [("foo", "bar"), ("baz", "quux")];
let mut base = entries.into_iter().collect::<$BaseMap<_, _>>();
base.insert("this entry should not be present in the total map", "");
let json = serde_json::to_string(&base).unwrap();
let actual = serde_json::from_str::<$Map<_, _>>(&json).unwrap();
let expected = entries.into_iter().collect();
assert_eq!(actual, expected);
}
}
};
}
common!(mod btree_map, TotalBTreeMap, BTreeMap, as_btree_map_mut, Iterator::eq);
common!(mod hash_map, TotalHashMap, HashMap, as_hash_map_mut, unordered_iter_eq);
#[test]
fn hash_drain() {
let mut m = TotalHashMap::<_, _>::new();
assert_eq!(m.insert("foo", "bar"), "");
assert_eq!(m.insert("baz", "quux"), "");
assert_iter_eq(m.drain(), [("baz", "quux"), ("foo", "bar")], unordered_iter_eq);
assert!(m.is_empty());
}
#[test]
fn btree_recursive_cmp_hash() {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
struct Recursive(TotalBTreeMap<(), Box<Recursive>>);
let rec = Recursive::default();
assert_eq!(rec.partial_cmp(&rec), Some(Ordering::Equal));
assert_eq!(rec.cmp(&rec), Ordering::Equal);
rec.hash(&mut DefaultHasher::new());
}
fn assert_iter_eq<I, J>(lhs: I, rhs: J, iter_eq: impl FnOnce(I::IntoIter, J::IntoIter) -> bool)
where
I: IntoIterator,
I::IntoIter: ExactSizeIterator,
J: IntoIterator<Item = I::Item>,
J::IntoIter: ExactSizeIterator,
{
let lhs = lhs.into_iter();
let rhs = rhs.into_iter();
assert_eq!(lhs.len(), rhs.len());
assert!(iter_eq(lhs, rhs));
}
fn unordered_iter_eq<I, J>(lhs: I, rhs: J) -> bool
where
I: IntoIterator,
J: IntoIterator<Item = I::Item>,
I::Item: Ord,
{
lhs.into_iter().sorted().eq(rhs)
}
struct NaNCommonality;
impl Commonality<f64> for NaNCommonality {
fn common() -> f64 {
f64::NAN
}
fn is_common(value: &f64) -> bool {
value.is_nan()
}
}