use quickcheck::quickcheck;
use radix_immutable::StringTrie;
use std::collections::HashMap;
fn prop_insert_then_get(entries: Vec<(String, u32)>) -> bool {
let mut trie = StringTrie::<String, u32>::new();
let mut reference = HashMap::new();
for (k, v) in &entries {
trie = trie.insert(k.clone(), *v);
reference.insert(k.clone(), *v);
}
if trie.len() != reference.len() {
return false;
}
for (k, v) in &reference {
if trie.get(k) != Some(v) {
return false;
}
}
true
}
fn prop_insert_remove_all(keys: Vec<String>) -> bool {
let mut trie = StringTrie::<String, u32>::new();
for (i, k) in keys.iter().enumerate() {
trie = trie.insert(k.clone(), i as u32);
}
let unique: Vec<_> = keys.iter().collect::<std::collections::HashSet<_>>()
.into_iter().collect();
for k in &unique {
let (new_trie, removed) = trie.remove(k);
if removed.is_none() {
return false;
}
trie = new_trie;
}
trie.is_empty() && trie.len() == 0
}
fn prop_insertion_order_independent(entries: Vec<(String, u32)>) -> bool {
let mut deduped = HashMap::new();
for (k, v) in &entries {
deduped.insert(k.clone(), *v);
}
let mut trie_forward = StringTrie::<String, u32>::new();
for (k, v) in &deduped {
trie_forward = trie_forward.insert(k.clone(), *v);
}
let mut sorted: Vec<_> = deduped.iter().collect();
sorted.sort_by(|a, b| b.0.cmp(a.0));
let mut trie_reverse = StringTrie::<String, u32>::new();
for (k, v) in sorted {
trie_reverse = trie_reverse.insert(k.clone(), *v);
}
trie_forward == trie_reverse
}
fn prop_iter_matches_entries(entries: Vec<(String, u32)>) -> bool {
let mut reference = HashMap::new();
let mut trie = StringTrie::<String, u32>::new();
for (k, v) in &entries {
trie = trie.insert(k.clone(), *v);
reference.insert(k.clone(), *v);
}
let iter_entries: HashMap<String, u32> = trie.iter().collect();
iter_entries == reference
}
fn prop_subtree_size_consistent(entries: Vec<(String, u32)>) -> bool {
let mut trie = StringTrie::<String, u32>::new();
let mut reference = HashMap::new();
for (k, v) in &entries {
trie = trie.insert(k.clone(), *v);
reference.insert(k.clone(), *v);
}
let len = trie.len();
let iter_count = trie.iter().count();
len == reference.len() && iter_count == len
}
fn prop_remove_returns_value(entries: Vec<(String, u32)>) -> bool {
if entries.is_empty() {
return true;
}
let mut trie = StringTrie::<String, u32>::new();
let mut reference = HashMap::new();
for (k, v) in &entries {
trie = trie.insert(k.clone(), *v);
reference.insert(k.clone(), *v);
}
let key_to_remove = reference.keys().next().unwrap().clone();
let expected_value = reference[&key_to_remove];
let (new_trie, removed) = trie.remove(&key_to_remove);
removed == Some(expected_value)
&& new_trie.get(&key_to_remove).is_none()
&& new_trie.len() == trie.len() - 1
}
fn prop_canonical_after_remove(entries: Vec<(String, u32)>) -> bool {
if entries.len() < 2 {
return true;
}
let mut reference = HashMap::new();
for (k, v) in &entries {
reference.insert(k.clone(), *v);
}
if reference.len() < 2 {
return true;
}
let mut trie_full = StringTrie::<String, u32>::new();
for (k, v) in &reference {
trie_full = trie_full.insert(k.clone(), *v);
}
let key_to_remove = reference.keys().next().unwrap().clone();
let (trie_after_remove, _) = trie_full.remove(&key_to_remove);
let mut trie_direct = StringTrie::<String, u32>::new();
for (k, v) in &reference {
if *k != key_to_remove {
trie_direct = trie_direct.insert(k.clone(), *v);
}
}
trie_after_remove == trie_direct
}
quickcheck! {
fn qc_insert_then_get(entries: Vec<(String, u32)>) -> bool {
prop_insert_then_get(entries)
}
fn qc_insert_remove_all(keys: Vec<String>) -> bool {
prop_insert_remove_all(keys)
}
fn qc_insertion_order_independent(entries: Vec<(String, u32)>) -> bool {
prop_insertion_order_independent(entries)
}
fn qc_iter_matches_entries(entries: Vec<(String, u32)>) -> bool {
prop_iter_matches_entries(entries)
}
fn qc_subtree_size_consistent(entries: Vec<(String, u32)>) -> bool {
prop_subtree_size_consistent(entries)
}
fn qc_remove_returns_value(entries: Vec<(String, u32)>) -> bool {
prop_remove_returns_value(entries)
}
fn qc_canonical_after_remove(entries: Vec<(String, u32)>) -> bool {
prop_canonical_after_remove(entries)
}
}