use proptest::collection::vec;
use proptest::prelude::*;
use triblespace_core::patch::{Entry, IdentitySchema, PATCH};
type TestPatch = PATCH<8, IdentitySchema, ()>;
fn arb_key() -> impl Strategy<Value = [u8; 8]> {
prop::array::uniform8(any::<u8>())
}
fn arb_patch(max: usize) -> impl Strategy<Value = TestPatch> {
vec(arb_key(), 0..max).prop_map(|keys| {
let mut patch = TestPatch::new();
for k in &keys {
patch.insert(&Entry::new(k));
}
patch
})
}
proptest! {
#[test]
fn insert_then_has_prefix(key in arb_key()) {
let mut patch = TestPatch::new();
patch.insert(&Entry::new(&key));
prop_assert!(patch.has_prefix(&key));
prop_assert_eq!(patch.len(), 1);
}
#[test]
fn insert_idempotent(key in arb_key()) {
let mut patch = TestPatch::new();
patch.insert(&Entry::new(&key));
patch.insert(&Entry::new(&key));
prop_assert_eq!(patch.len(), 1);
}
#[test]
fn remove_then_absent(key in arb_key()) {
let mut patch = TestPatch::new();
patch.insert(&Entry::new(&key));
patch.remove(&key);
prop_assert!(!patch.has_prefix(&key));
prop_assert_eq!(patch.len(), 0);
}
#[test]
fn union_commutative(a in arb_patch(15), b in arb_patch(15)) {
let mut ab = a.clone();
ab.union(b.clone());
let mut ba = b;
ba.union(a);
prop_assert_eq!(ab, ba);
}
#[test]
fn union_idempotent(a in arb_patch(15)) {
let mut aa = a.clone();
aa.union(a.clone());
prop_assert_eq!(a, aa);
}
#[test]
fn union_identity(a in arb_patch(15)) {
let mut result = a.clone();
result.union(TestPatch::new());
prop_assert_eq!(a, result);
}
#[test]
fn intersect_commutative(a in arb_patch(15), b in arb_patch(15)) {
let ab = a.intersect(&b);
let ba = b.intersect(&a);
prop_assert_eq!(ab, ba);
}
#[test]
fn intersect_idempotent(a in arb_patch(15)) {
let aa = a.intersect(&a);
prop_assert_eq!(a, aa);
}
#[test]
fn difference_self_is_empty(a in arb_patch(15)) {
let diff = a.difference(&a);
prop_assert!(diff.is_empty());
}
#[test]
fn difference_empty_is_self(a in arb_patch(15)) {
let empty = TestPatch::new();
let diff = a.difference(&empty);
prop_assert_eq!(a, diff);
}
#[test]
fn union_then_difference(a in arb_patch(10), b in arb_patch(10)) {
let mut union = a.clone();
union.union(b.clone());
let diff = union.difference(&b);
let expected = a.difference(&b);
prop_assert_eq!(expected, diff);
}
#[test]
fn intersect_subset_of_both(a in arb_patch(15), b in arb_patch(15)) {
let inter = a.intersect(&b);
for key in inter.iter() {
prop_assert!(a.has_prefix(key));
prop_assert!(b.has_prefix(key));
}
}
#[test]
fn iter_len_consistent(a in arb_patch(20)) {
prop_assert_eq!(a.len() as usize, a.iter().count());
}
#[test]
fn iter_ordered_is_sorted(a in arb_patch(20)) {
let keys: Vec<[u8; 8]> = a.iter_ordered().copied().collect();
for pair in keys.windows(2) {
prop_assert!(pair[0] <= pair[1],
"iter_ordered not sorted: {:?} > {:?}", pair[0], pair[1]);
}
}
#[test]
fn iter_and_iter_ordered_same_elements(a in arb_patch(20)) {
let mut unordered: Vec<[u8; 8]> = a.iter().copied().collect();
let mut ordered: Vec<[u8; 8]> = a.iter_ordered().copied().collect();
unordered.sort();
ordered.sort();
prop_assert_eq!(unordered, ordered);
}
#[test]
fn clone_is_equal(a in arb_patch(15)) {
let b = a.clone();
prop_assert_eq!(a, b);
}
#[test]
fn union_order_independent_equality(a in arb_patch(10), b in arb_patch(10)) {
let mut ab = a.clone();
ab.union(b.clone());
let mut ba = b;
ba.union(a);
prop_assert_eq!(ab, ba);
}
}