extern crate alloc;
use super::super::support::arb_vv;
use crate::metis::{Cut, Dot, DotSet, Stability, VersionVector};
use alloc::vec::Vec;
use proptest::prelude::*;
fn arb_reports() -> impl Strategy<Value = Vec<(u32, VersionVector)>> {
prop::collection::vec((0u32..4, arb_vv()), 0..12)
}
fn arb_dots() -> impl Strategy<Value = Vec<(u32, u64)>> {
prop::collection::vec((0u32..4, 0u64..8), 0..16)
}
fn cut_of(dots: &[(u32, u64)]) -> Cut {
let mut have = DotSet::new();
for &pair in dots {
if let Ok(dot) = Dot::try_from(pair) {
let _ = have.insert(dot);
}
}
Cut::floor_of(&have)
}
proptest! {
#[test]
fn prop_watermark_is_the_meet_of_vouched_cuts(reports in arb_reports()) {
let mut tracker = Stability::new(0..4);
let mut vouched: Vec<VersionVector> =
(0..4).map(|_| VersionVector::new()).collect();
for (station, cut) in &reports {
tracker.report(*station, cut).unwrap();
let slot = &mut vouched[usize::try_from(*station).unwrap()];
*slot = slot.merge(cut);
}
let watermark = tracker.watermark();
for cut in &vouched {
prop_assert!(&watermark <= cut);
}
let expected = vouched[1..]
.iter()
.fold(vouched[0].clone(), |acc, cut| acc.meet(cut));
prop_assert_eq!(watermark, expected);
}
#[test]
fn prop_watermark_never_regresses(reports in arb_reports()) {
let mut tracker = Stability::new(0..4);
let mut last = tracker.watermark();
for (station, cut) in &reports {
tracker.report(*station, cut).unwrap();
let next = tracker.watermark();
prop_assert!(last <= next);
last = next;
}
}
#[test]
fn prop_report_cut_agrees_with_report(streams in prop::collection::vec((0u32..4, arb_dots()), 0..12)) {
let mut witnessed = Stability::new(0..4);
let mut bare = Stability::new(0..4);
for (station, dots) in &streams {
let cut = cut_of(dots);
witnessed.report_cut(*station, &cut).unwrap();
bare.report(*station, cut.as_vector()).unwrap();
}
prop_assert_eq!(witnessed.watermark(), bare.watermark());
let branded = witnessed.watermark_cut().expect("all reports witnessed");
prop_assert_eq!(branded.as_vector(), &witnessed.watermark());
if !streams.is_empty() {
prop_assert!(bare.watermark_cut().is_none());
}
}
#[test]
fn prop_watermark_cut_tracks_the_witnessed_gate(
streams in prop::collection::vec((0u32..4, arb_dots(), any::<bool>()), 0..12),
) {
let mut tracker = Stability::new(0..4);
let mut all_witnessed = true;
for (station, dots, witnessed) in &streams {
let cut = cut_of(dots);
if *witnessed {
tracker.report_cut(*station, &cut).unwrap();
} else {
tracker.report(*station, cut.as_vector()).unwrap();
all_witnessed = false;
}
}
match tracker.watermark_cut() {
Some(branded) => {
prop_assert!(all_witnessed);
prop_assert_eq!(branded.as_vector(), &tracker.watermark());
}
None => prop_assert!(!all_witnessed),
}
}
#[test]
fn prop_reports_are_order_invariant(
(reports, permuted) in arb_reports()
.prop_flat_map(|r| (Just(r.clone()), Just(r).prop_shuffle())),
) {
let mut a = Stability::new(0..4);
for (station, cut) in &reports {
a.report(*station, cut).unwrap();
}
let mut b = Stability::new(0..4);
for (station, cut) in &permuted {
b.report(*station, cut).unwrap();
}
prop_assert_eq!(&a, &b);
prop_assert_eq!(a.watermark(), b.watermark());
}
}