blob: 695111e6e71bbbc7ee1c68742ab6b674678e4c1e [file] [log] [blame]
#![allow(clippy::unit_arg)]
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::panic::{catch_unwind, AssertUnwindSafe};
use proptest::{arbitrary::any, collection::vec, prelude::*, proptest};
use proptest_derive::Arbitrary;
use crate::sparse_chunk::SparseChunk;
#[derive(Arbitrary, Debug)]
enum Construct<A> {
Empty,
Single((usize, A)),
Pair((usize, A, usize, A)),
}
#[derive(Arbitrary, Debug)]
enum Action<A> {
Insert(usize, A),
Remove(usize),
Pop,
}
impl<A> Construct<A>
where
A: Arbitrary + Clone + Debug + Eq,
<A as Arbitrary>::Strategy: 'static,
{
fn make(self) -> SparseChunk<A> {
match self {
Construct::Empty => {
let out = SparseChunk::new();
assert!(out.is_empty());
out
}
Construct::Single((index, value)) => {
let index = index % SparseChunk::<A>::CAPACITY;
let out = SparseChunk::unit(index, value.clone());
let mut guide = BTreeMap::new();
guide.insert(index, value);
assert_eq!(out, guide);
out
}
Construct::Pair((left_index, left, right_index, right)) => {
let left_index = left_index % SparseChunk::<A>::CAPACITY;
let right_index = right_index % SparseChunk::<A>::CAPACITY;
let out = SparseChunk::pair(left_index, left.clone(), right_index, right.clone());
let mut guide = BTreeMap::new();
guide.insert(left_index, left);
guide.insert(right_index, right);
assert_eq!(out, guide);
out
}
}
}
}
proptest! {
#[test]
fn test_constructors(cons: Construct<u32>) {
cons.make();
}
#[test]
fn test_actions(cons: Construct<u32>, actions in vec(any::<Action<u32>>(), 0..super::action_count())) {
let capacity = SparseChunk::<u32>::CAPACITY;
let mut chunk = cons.make();
let mut guide: BTreeMap<_, _> = chunk.entries().map(|(i, v)| (i, *v)).collect();
for action in actions {
match action {
Action::Insert(index, value) => {
if index >= capacity {
assert!(catch_unwind(AssertUnwindSafe(|| chunk.insert(index, value))).is_err());
} else {
assert_eq!(chunk.insert(index, value), guide.insert(index, value));
}
}
Action::Remove(index) => {
if index >= capacity {
assert!(catch_unwind(AssertUnwindSafe(|| chunk.remove(index))).is_err());
} else {
assert_eq!(chunk.remove(index), guide.remove(&index));
}
}
Action::Pop => {
if let Some(index) = chunk.first_index() {
assert_eq!(chunk.pop(), guide.remove(&index));
} else {
assert_eq!(chunk.pop(), None);
}
}
}
assert_eq!(chunk, guide);
assert!(guide.len() <= SparseChunk::<u32>::CAPACITY);
}
}
}