extern crate alloc;
use alloc::vec::Vec;
use core::num::{NonZeroU32, NonZeroU64};
use crate::kairos::{Clock, TickCounter};
use crate::metis::{Anchor, Dot, Locus};
use proptest::prelude::*;
use super::super::d;
use super::{Seq, arb_ops_with_paste, run};
use crate::metis::dot::RawDot;
proptest! {
#[test]
fn prop_weave_run_agrees_with_the_per_dot_weave(
ops in arb_ops_with_paste(),
len in 1u32..200,
anchor_pick in 0usize..11,
) {
let (live, _) = run(&ops);
let state = live.iter().fold(Seq::new(), |acc, r| acc.merge(r));
let station = 9u32;
let clock = Clock::with_default_config(TickCounter::new(), station).unwrap();
let reservation = clock.now_run(NonZeroU32::new(len).unwrap(), 0u16);
let first = state.next_dot(station);
let visible = state.store().order();
let anchor = if anchor_pick == 9 {
Anchor::After(RawDot { station: 7, counter: 1_000_000 })
} else if visible.is_empty() || anchor_pick == 8 {
Anchor::Origin
} else if anchor_pick == 10 {
Anchor::Before(visible[len as usize % visible.len()].into())
} else {
Anchor::After(visible[anchor_pick % visible.len()].into())
};
let members: Vec<_> = reservation.iter().collect();
let mut bulk = state.store().clone();
prop_assert!(bulk.weave_run(first, anchor, reservation));
let mut pointwise = state.store().clone();
let mut prev = first;
for k in 0..len {
let dot = d(station, first.counter() + u64::from(k));
let locus = Locus {
anchor: if k == 0 { anchor } else { Anchor::After(prev.into()) },
rank: members[k as usize],
};
prop_assert!(pointwise.weave(dot, locus));
prev = dot;
}
prop_assert_eq!(&bulk, &pointwise);
bulk.check_order_thread();
prop_assert_eq!(bulk.order(), pointwise.order());
prop_assert_eq!(bulk.order_len(), pointwise.order_len());
for offset in 0..bulk.order_len() {
prop_assert_eq!(bulk.order_at(offset), pointwise.order_at(offset));
}
for k in 0..len {
let dot = d(station, first.counter() + u64::from(k));
prop_assert_eq!(bulk.offset_of(dot), pointwise.offset_of(dot));
prop_assert_eq!(bulk.is_reachable(dot), pointwise.is_reachable(dot));
prop_assert!(bulk.is_visible(dot));
prop_assert_eq!(bulk.locus(dot), pointwise.locus(dot));
}
}
#[test]
fn prop_a_run_delta_absorbs_like_the_pure_merge(
ops in arb_ops_with_paste(),
len in 1u32..200,
) {
let (live, _) = run(&ops);
let state = live.iter().fold(Seq::new(), |acc, r| acc.merge(r));
let station = 9u32;
let clock = Clock::with_default_config(TickCounter::new(), station).unwrap();
let reservation = clock.now_run(NonZeroU32::new(len).unwrap(), 0u16);
let first = state.next_dot(station);
let anchor = state
.store()
.order()
.last()
.map_or(Anchor::Origin, |&tail| Anchor::After(tail.into()));
let mut fragment = crate::metis::Rhapsody::new();
prop_assert!(fragment.weave_run(first, anchor, reservation));
let delta = Seq::from_store(fragment);
let pure = state.merge(&delta);
let mut folded = state;
folded.merge_from(&delta);
prop_assert_eq!(&folded, &pure);
prop_assert_eq!(folded.store().order(), pure.store().order());
folded.store().check_order_thread();
folded.merge_from(&delta);
prop_assert_eq!(&folded, &pure);
}
}
#[test]
fn test_a_run_delta_lands_as_whole_fragments() {
let station = 2u32;
let clock = Clock::with_default_config(TickCounter::new(), station).unwrap();
let reservation = clock.now_run(NonZeroU32::new(300).unwrap(), 0u16);
let mut fragment = crate::metis::Rhapsody::new();
assert!(fragment.weave_run(d(station, 1), Anchor::Origin, reservation));
let delta = Seq::from_store(fragment);
let mut receiver = Seq::new();
receiver.merge_from(&delta);
assert_eq!(receiver.store().order().len(), 300);
receiver.store().check_order_thread();
assert_eq!(
receiver.store().order_thread_fragments(),
5,
"three hundred slots tile five fragments"
);
assert_eq!(
receiver.store().order_thread_region_segments(),
1,
"one chain run is one region segment"
);
}
#[test]
fn test_an_arriving_run_repairs_a_parked_waiter_per_dot() {
let mut receiver = Seq::new();
let waiter_rank = Clock::with_default_config(TickCounter::new(), 3)
.unwrap()
.now(0u16);
let mut waiter = crate::metis::Rhapsody::new();
assert!(waiter.weave(
d(3, 1),
Locus {
anchor: Anchor::After(RawDot {
station: 1,
counter: 40
}),
rank: waiter_rank,
}
));
receiver.merge_from(&Seq::from_store(waiter));
assert!(!receiver.store().is_reachable(d(3, 1)));
let clock = Clock::with_default_config(TickCounter::new(), 1).unwrap();
let run = clock.now_run(NonZeroU32::new(80).unwrap(), 0u16);
let mut fragment = crate::metis::Rhapsody::new();
assert!(fragment.weave_run(d(1, 1), Anchor::Origin, run));
let delta = Seq::from_store(fragment);
let pure = receiver.merge(&delta);
let mut folded = receiver;
folded.merge_from(&delta);
assert_eq!(&folded, &pure);
folded.store().check_order_thread();
assert!(
folded.store().is_reachable(d(3, 1)),
"the waiter was repaired"
);
assert_eq!(folded.store().order(), pure.store().order());
assert_eq!(folded.store().order_len(), 81);
}
#[test]
fn test_a_bulk_retract_settles_by_runs() {
let station = 1u32;
let clock = Clock::with_default_config(TickCounter::new(), station).unwrap();
let reservation = clock.now_run(NonZeroU32::new(256).unwrap(), 0u16);
let mut store = crate::metis::Rhapsody::new();
assert!(store.weave_run(d(station, 1), Anchor::Origin, reservation));
let state = Seq::from_store(store);
let mut superseded = crate::metis::DotSet::new();
superseded.insert_run(
station,
NonZeroU64::new(70).expect("a run starts at a dot"),
121,
);
let retract = Seq::from_context(superseded);
let pure = state.merge(&retract);
let mut folded = state;
folded.merge_from(&retract);
assert_eq!(&folded, &pure);
folded.store().check_order_thread();
assert_eq!(folded.store().order_len(), 135);
let visible: Vec<Dot> = folded.store().order();
assert_eq!(visible.first(), Some(&d(station, 1)));
assert_eq!(
visible.get(69),
Some(&d(station, 191)),
"the span reopens past the retract"
);
assert_eq!(visible.last(), Some(&d(station, 256)));
for (offset, &dot) in visible.iter().enumerate() {
assert_eq!(folded.store().order_at(offset), Some(dot));
assert_eq!(folded.store().offset_of(dot), Some(offset));
}
}