extern crate alloc;
use alloc::vec::Vec;
use super::super::super::support::arb_vv;
use super::arb_roster;
use crate::metis::VersionVector;
use proptest::prelude::*;
proptest! {
#[test]
fn prop_restrict_is_functorial(
a in arb_vv(), r in arb_roster(), s in arb_roster(),
) {
prop_assert_eq!(&a.restrict(0u32..8), &a);
prop_assert_eq!(a.restrict(core::iter::empty::<u32>()), VersionVector::new());
let ra = a.restrict(r.iter().copied());
prop_assert_eq!(&ra.restrict(r.iter().copied()), &ra);
let intersection: Vec<u32> =
r.iter().copied().filter(|station| s.contains(station)).collect();
prop_assert_eq!(
a.restrict(r.iter().copied()).restrict(s.iter().copied()),
a.restrict(intersection)
);
}
#[test]
fn prop_restrict_is_a_lattice_homomorphism_and_reflects_concurrency(
a in arb_vv(), b in arb_vv(), r in arb_roster(),
) {
let ra = a.restrict(r.iter().copied());
let rb = b.restrict(r.iter().copied());
prop_assert_eq!(a.merge(&b).restrict(r.iter().copied()), ra.merge(&rb));
prop_assert_eq!(a.meet(&b).restrict(r.iter().copied()), ra.meet(&rb));
if a <= b {
prop_assert!(ra <= rb);
}
if ra.concurrent(&rb) {
prop_assert!(a.concurrent(&b));
}
}
#[test]
fn prop_sections_of_one_vector_glue_back(
v in arb_vv(), r in arb_roster(), s in arb_roster(),
) {
let vr = v.restrict(r.iter().copied());
let vs = v.restrict(s.iter().copied());
let overlap: Vec<u32> =
r.iter().copied().filter(|station| s.contains(station)).collect();
let glued = v_glued(&vr, &vs, &overlap)?;
let union = r.iter().copied().chain(s.iter().copied());
prop_assert_eq!(glued, v.restrict(union));
}
#[test]
fn prop_glue_refuses_disagreement_with_the_first_witness(
a in arb_vv(), b in arb_vv(),
) {
prop_assert_eq!(
a.try_glue(&b, core::iter::empty::<u32>()),
Ok(a.merge(&b))
);
match a.try_glue(&b, 0u32..8) {
Ok(glued) => {
prop_assert_eq!(&glued, &a.merge(&b));
for station in 0u32..8 {
prop_assert_eq!(a.get(station), b.get(station));
}
}
Err(witness) => {
prop_assert_eq!(witness.left, a.get(witness.station));
prop_assert_eq!(witness.right, b.get(witness.station));
prop_assert_ne!(witness.left, witness.right);
for station in 0..witness.station {
prop_assert_eq!(a.get(station), b.get(station));
}
let mirrored = b.try_glue(&a, 0u32..8).unwrap_err();
prop_assert_eq!(mirrored.station, witness.station);
prop_assert_eq!(mirrored.left, witness.right);
prop_assert_eq!(mirrored.right, witness.left);
}
}
}
}
fn v_glued(
left: &VersionVector,
right: &VersionVector,
overlap: &[u32],
) -> Result<VersionVector, TestCaseError> {
left.try_glue(right, overlap.iter().copied())
.map_err(|witness| {
TestCaseError::fail(alloc::format!(
"sections of one vector must glue, got {witness:?}"
))
})
}