extern crate alloc;
use alloc::collections::BTreeSet;
use alloc::vec::Vec;
use crate::metis::{Dot, Rhapsody};
use proptest::prelude::*;
use super::super::super::d;
use super::super::{Record, Seq, arb_ops_with_paste, reference_order, run};
use super::walk::enrich_with_sided_edits;
fn assert_positional_laws(store: &Rhapsody) -> Result<(), TestCaseError> {
store.check_order_thread();
let order = store.order();
prop_assert_eq!(store.order_len(), order.len());
prop_assert!(store.visible_len() >= store.order_len());
for (offset, &dot) in order.iter().enumerate() {
prop_assert_eq!(store.order_at(offset), Some(dot));
prop_assert_eq!(store.offset_of(dot), Some(offset));
}
prop_assert_eq!(store.order_at(order.len()), None);
prop_assert_eq!(store.order_at(usize::MAX), None);
for dot in unplaced_dots(store) {
prop_assert_eq!(store.offset_of(dot), None);
prop_assert!(store.order_walk_rev_before(dot).is_none());
}
prop_assert_eq!(store.offset_of(d(u32::MAX, u64::MAX)), None);
prop_assert!(Dot::from_parts(1, 0).is_err());
let rev: Vec<Dot> = store.order_walk_rev().collect();
let mut expected = order.clone();
expected.reverse();
prop_assert_eq!(&rev, &expected);
prop_assert_eq!(store.order_walk_rev().len(), order.len());
for dot in store.woven().dots() {
let placed = store.is_reachable(dot);
let walk = store.order_walk_rev_before(dot);
prop_assert_eq!(placed, walk.is_some());
if let Some(walk) = walk {
let boundary = store.offset_of(dot).expect("a placed dot has an offset");
let mut prefix: Vec<Dot> = order[..boundary].to_vec();
prefix.reverse();
let got: Vec<Dot> = walk.collect();
prop_assert_eq!(got, prefix, "reversed prefix at {:?}", dot);
}
}
Ok(())
}
proptest! {
#[test]
fn prop_positional_reads_agree_with_the_order(
ops in arb_ops_with_paste(),
edits in prop::collection::vec((0usize..16, any::<bool>()), 0..6),
) {
let (live, mut record) = run(&ops);
let seq = enrich_with_sided_edits(&live, &mut record, &edits);
assert_positional_laws(seq.store())?;
let slots = reference_order(&Record {
woven: record.woven.clone(),
expelled: BTreeSet::new(),
});
let mut visible_before = 0usize;
for &dot in &slots {
prop_assert_eq!(
seq.store().offset_of(dot),
Some(visible_before),
"slot offsets agree with the oracle at {:?}",
dot
);
if seq.store().is_visible(dot) {
visible_before += 1;
}
}
let mut incremental = live.first().cloned().unwrap_or_default();
incremental.merge_from(&seq);
assert_positional_laws(incremental.store())?;
prop_assert_eq!(incremental.store().order_len(), seq.store().order_len());
prop_assert_eq!(incremental.store().order(), seq.store().order());
let mut fresh = Seq::new();
fresh.merge_from(&seq);
assert_positional_laws(fresh.store())?;
prop_assert_eq!(fresh.store().order_len(), seq.store().order_len());
let mut bare = Rhapsody::new();
for &dot in &slots {
let locus = seq
.store()
.locus(dot)
.expect("a walked slot has a locus");
prop_assert!(bare.weave(dot, locus));
}
bare.check_order_thread();
prop_assert_eq!(bare.order_len(), slots.len());
for (offset, &dot) in slots.iter().enumerate() {
prop_assert_eq!(bare.order_at(offset), Some(dot));
prop_assert_eq!(bare.offset_of(dot), Some(offset));
}
assert_positional_laws(&bare)?;
let mut condensed = seq.store().clone();
let mut retired = crate::metis::DotSet::new();
for &dot in &record.expelled {
let _ = retired.insert(dot);
}
let _ = condensed.condense(&crate::metis::Retired::trust(retired));
assert_positional_laws(&condensed)?;
prop_assert_eq!(condensed.order(), seq.store().order());
}
}
fn unplaced_dots(store: &Rhapsody) -> Vec<Dot> {
store
.woven()
.dots()
.filter(|&dot| !store.is_reachable(dot))
.collect()
}