use proptest::prelude::*;
use rc_hashmap::RcHashMap;
proptest! {
#[test]
fn prop_rc_hashmap_liveness(keys in 1usize..=5, ops in proptest::collection::vec((0u8..=4u8, 0usize..100usize), 1..100)) {
let mut m: RcHashMap<String, i32> = RcHashMap::new();
let mut live: Vec<Vec<rc_hashmap::Ref<String, i32>>> = vec![Vec::new(); keys];
for (op, raw_k) in ops {
let k = raw_k % keys;
let key = format!("k{}", k);
match op {
0 => {
let res = m.insert(key.clone(), k as i32);
match res {
Ok(r) => live[k].push(r),
Err(rc_hashmap::InsertError::DuplicateKey) => {},
}
}
1 => {
if let Some(r) = m.find(&key) {
let v = r.value(&m).unwrap();
prop_assert_eq!(*v, k as i32);
live[k].push(r);
}
}
2 => {
if let Some(existing) = live[k].pop() {
let cloned = existing.clone();
live[k].push(existing);
live[k].push(cloned);
}
}
3 => {
if let Some(r) = live[k].pop() { drop(r); }
}
4 => {
while let Some(r) = live[k].pop() { drop(r); }
}
_ => unreachable!(),
}
let present = m.contains_key(&key);
prop_assert_eq!(present, !live[k].is_empty());
}
let expected_len = live.iter().filter(|v| !v.is_empty()).count();
prop_assert_eq!(m.len(), expected_len);
}
}
#[derive(Default)]
struct VNode {
children: Vec<rc_hashmap::Ref<String, VNode>>, }
fn key(i: usize) -> String {
format!("k{}", i)
}
proptest! {
#[test]
fn prop_dag_liveness(
n in 1usize..=6,
ops in proptest::collection::vec((0u8..=6u8, 0usize..64usize, 0usize..64usize), 1..128)
) {
let mut m: RcHashMap<String, VNode> = RcHashMap::new();
let mut live: Vec<Vec<rc_hashmap::Ref<String, VNode>>> = vec![Vec::new(); n];
let mut adj: Vec<Vec<usize>> = vec![Vec::new(); n];
fn closure(n: usize, roots: &[bool], adj: &[Vec<usize>]) -> Vec<bool> {
let mut alive = roots.to_vec();
let mut changed = true;
while changed {
changed = false;
for i in 0..n {
if alive[i] {
for &j in &adj[i] {
if !alive[j] { alive[j] = true; changed = true; }
}
}
}
}
alive
}
for (op, a, b) in ops.into_iter() {
let i = a % n;
let j_opt = if i + 1 < n { Some(i + 1 + (b % (n - i - 1))) } else { None };
let ki = key(i);
match op {
0 => {
match m.insert(ki.clone(), VNode { children: vec![] }) {
Ok(r) => live[i].push(r),
Err(rc_hashmap::InsertError::DuplicateKey) => {}
}
}
1 => { if let Some(r) = m.find(&ki) { live[i].push(r); } }
2 => { if let Some(r) = live[i].pop() { let c = r.clone(); live[i].push(r); live[i].push(c); } }
3 => { if let Some(r) = live[i].pop() { drop(r); } }
4 => { while let Some(r) = live[i].pop() { drop(r); } }
5 => {
if let Some(j) = j_opt {
let kj = key(j);
if let (Some(ri), Some(rj)) = (m.find(&ki), m.find(&kj)) {
if !adj[i].contains(&j) {
ri.value_mut(&mut m).unwrap().children.push(rj.clone());
adj[i].push(j);
}
}
}
}
6 => {
if let Some(ri) = m.find(&ki) {
if let Some(_child) = ri.value_mut(&mut m).unwrap().children.pop() {}
adj[i].pop();
}
}
_ => unreachable!()
}
let present: Vec<bool> = (0..n).map(|t| m.contains_key(&key(t))).collect();
for i in 0..n {
if !present[i] { adj[i].clear(); } else { adj[i].retain(|&child| present[child]); }
}
let roots: Vec<bool> = (0..n).map(|t| !live[t].is_empty()).collect();
let alive = closure(n, &roots, &adj);
let expected_len = alive.iter().filter(|&&b| b).count();
prop_assert_eq!(m.len(), expected_len);
for (t, alive_t) in alive.iter().enumerate() {
prop_assert_eq!(m.contains_key(&key(t)), *alive_t);
}
}
for v in &mut live { while let Some(r) = v.pop() { drop(r); } }
let roots: Vec<bool> = (0..n).map(|_t| false).collect();
let alive = closure(n, &roots, &adj);
let expected_len = alive.iter().filter(|&&b| b).count();
prop_assert_eq!(m.len(), expected_len);
}
}