extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use core::num::NonZeroUsize;
use crate::metis::{
Anchor, Cut, EpochPreparation, EpochPreparationFold, EpochPreparationMiss, EpochStratum,
Epochs, Stability, Vouched,
};
use super::{Moves, Text, d, move_delta, rank, text_delta, vector};
use crate::metis::dot::RawDot;
#[test]
fn the_lag_lemma_crossing_is_executable_and_the_shipped_door_detects_it() {
let mut tracker_n = Stability::new([2, 3]);
tracker_n
.report_cut(2, &Cut::from_witnessed(vector(&[(1, 5), (2, 9)])))
.unwrap();
tracker_n
.report_cut(3, &Cut::from_witnessed(vector(&[(1, 9), (2, 9)])))
.unwrap();
let mut tracker_d = Stability::new([2, 3]);
tracker_d
.report_cut(2, &Cut::from_witnessed(vector(&[(1, 8), (2, 9)])))
.unwrap();
tracker_d
.report_cut(3, &Cut::from_witnessed(vector(&[(1, 9), (2, 6)])))
.unwrap();
let watermark_n = tracker_n.watermark();
let watermark_d = tracker_d.watermark();
assert_eq!(watermark_n, vector(&[(1, 5), (2, 9)]));
assert_eq!(watermark_d, vector(&[(1, 8), (2, 6)]));
assert!(
watermark_n.concurrent(&watermark_d),
"the two local meets cross: neither member's estimate bounds the other's"
);
let mut epochs_d = Epochs::new([2, 3], NonZeroUsize::new(1).unwrap());
let declaration_d = epochs_d
.declare(d(2, 7), rank(7), &tracker_d, &Cut::bottom())
.unwrap();
let trailing_n = Text::from_context(tracker_n.watermark_cut().unwrap().to_have_set());
assert_eq!(
EpochPreparation::begin(&declaration_d, trailing_n, Moves::new()).unwrap_err(),
EpochPreparationMiss::UnpinnedBase {
dot: RawDot::new(2, 9)
}
);
let mut epochs_n = Epochs::new([2, 3], NonZeroUsize::new(1).unwrap());
let declaration_n = epochs_n
.declare(d(3, 1), rank(1), &tracker_n, &Cut::bottom())
.unwrap();
let trailing_d = Text::from_context(tracker_d.watermark_cut().unwrap().to_have_set());
assert_eq!(
EpochPreparation::begin(&declaration_n, trailing_d, Moves::new()).unwrap_err(),
EpochPreparationMiss::UnpinnedBase {
dot: RawDot::new(1, 8)
}
);
}
type LogEntries<S> = Vec<((u32, u64), S)>;
fn generation_log() -> (LogEntries<Text>, LogEntries<Moves>, Text, Moves) {
let text_entries = vec![
((1, 1), text_delta(d(1, 1), Anchor::Origin, rank(3))),
(
(1, 2),
text_delta(
d(1, 2),
Anchor::After(RawDot {
station: 1,
counter: 1,
}),
rank(5),
),
),
(
(2, 1),
text_delta(
d(2, 1),
Anchor::After(RawDot {
station: 1,
counter: 1,
}),
rank(4),
),
),
];
let move_entries = vec![((2, 2), move_delta(d(2, 2), (1, 2), rank(9)))];
let mut text = Text::new();
for (_, delta) in &text_entries {
text.merge_from(delta);
}
let mut moves = Moves::new();
for (_, delta) in &move_entries {
moves.merge_from(delta);
}
(text_entries, move_entries, text, moves)
}
#[test]
fn a_trailing_base_at_the_oath_meet_serves_every_candidate_of_a_contested_window() {
let (text_entries, move_entries, text, moves) = generation_log();
let coverage = text.context().merge(moves.context());
let boundary = Cut::floor_of(&coverage);
assert_eq!(boundary.as_vector(), &vector(&[(1, 2), (2, 2)]));
let advertised_one = vector(&[(1, 1), (2, 1)]);
let advertised_two = vector(&[(1, 2), (2, 1)]);
let oath_meet = advertised_one.meet(&advertised_two);
assert_eq!(oath_meet, vector(&[(1, 1), (2, 1)]));
let mut trailing_text = Text::new();
let mut trailing_moves = Moves::new();
for (dot, delta) in &text_entries {
if dot.1 <= oath_meet.get(dot.0) {
trailing_text.merge_from(delta);
}
}
for (dot, delta) in &move_entries {
if dot.1 <= oath_meet.get(dot.0) {
trailing_moves.merge_from(delta);
}
}
let mut stability = Stability::new([1, 2]);
stability.report_cut(1, &boundary).unwrap();
stability.report_cut(2, &boundary).unwrap();
let mut epochs = Epochs::new([1, 2], NonZeroUsize::new(1).unwrap());
let losing = epochs
.declare(d(1, 3), rank(1), &stability, &Cut::bottom())
.unwrap();
let mut rival = Epochs::new([1, 2], NonZeroUsize::new(1).unwrap());
let winning = rival
.declare(d(2, 3), rank(9), &stability, &Cut::bottom())
.unwrap();
epochs
.deliver(winning.clone(), &stability, &Cut::bottom())
.unwrap();
assert!(&oath_meet <= losing.cut().as_vector());
assert!(&oath_meet <= winning.cut().as_vector());
let mut stage_losing =
EpochPreparation::begin(&losing, trailing_text.clone(), trailing_moves.clone())
.expect("the oath meet sits below the losing candidate's cut");
let mut stage_winning = EpochPreparation::begin(&winning, trailing_text, trailing_moves)
.expect("the oath meet sits below the winning candidate's cut");
for (dot, delta) in &text_entries {
assert_eq!(
stage_losing.absorb_text(&[(*dot).into()], delta),
EpochPreparationFold::Staged
);
assert_eq!(
stage_winning.absorb_text(&[(*dot).into()], delta),
EpochPreparationFold::Staged
);
}
for (dot, delta) in &move_entries {
assert_eq!(
stage_losing.absorb_moves(&[(*dot).into()], delta),
EpochPreparationFold::Staged
);
assert_eq!(
stage_winning.absorb_moves(&[(*dot).into()], delta),
EpochPreparationFold::Staged
);
}
let mut delivered = boundary.as_vector().clone();
delivered.observe(1, 3);
delivered.observe(2, 3);
let delivered = Cut::from_witnessed(delivered);
stability.report_cut(1, &delivered).unwrap();
stability.report_cut(2, &delivered).unwrap();
epochs
.confirm(losing.address(), &Vouched::trust(1, delivered.clone()))
.unwrap();
epochs
.confirm(losing.address(), &Vouched::trust(2, delivered.clone()))
.unwrap();
let adopted = epochs
.adopt(1, delivered.as_vector().get(1), &stability)
.unwrap();
assert_eq!(adopted.address(), winning.address());
let staged = stage_winning
.finish(&adopted)
.expect("the staged winner is the adopted winner");
let control = EpochStratum::new(&adopted, text, moves).unwrap();
assert_eq!(staged.pristine(), control.pristine());
assert_eq!(
stage_losing.finish(&adopted).unwrap_err(),
EpochPreparationMiss::DifferentWinner {
staged: losing.address(),
adopted: adopted.address(),
}
);
}
#[test]
fn a_reordered_advertisement_overshoots_and_the_counter_fence_names_it() {
let advertised_early = vector(&[(1, 1), (2, 1)]);
let advertised_late = vector(&[(1, 4), (2, 4)]);
let late_counter: u64 = 4;
let advertised_other = vector(&[(1, 9), (2, 9)]);
let mut stability = Stability::new([1, 2]);
let declared = Cut::from_witnessed(vector(&[(1, 2), (2, 2)]));
stability.report_cut(1, &declared).unwrap();
stability.report_cut(2, &declared).unwrap();
let mut epochs = Epochs::new([1, 2], NonZeroUsize::new(1).unwrap());
let declaration = epochs
.declare(d(2, 3), rank(3), &stability, &Cut::bottom())
.unwrap();
let fenced_meet = advertised_early.meet(&advertised_other);
assert!(&fenced_meet <= declaration.cut().as_vector());
let broken_meet = advertised_early
.merge(&advertised_late)
.meet(&advertised_other);
assert!(declaration.cut().as_vector().happens_before(&broken_meet));
let trailing = Text::from_context(Cut::from_witnessed(broken_meet).to_have_set());
assert_eq!(
EpochPreparation::begin(&declaration, trailing, Moves::new()).unwrap_err(),
EpochPreparationMiss::UnpinnedBase {
dot: RawDot::new(1, 4)
}
);
assert!(late_counter >= declaration.dot().counter());
}
#[test]
fn a_stale_generation_advertisement_is_excluded_before_it_can_overshoot() {
let stale_advertised = vector(&[(1, 9), (2, 9)]);
let stale_counter: u64 = 1;
let mut stability = Stability::new([1, 2]);
let reborn = Cut::from_witnessed(vector(&[(1, 1), (2, 1)]));
stability.report_cut(1, &reborn).unwrap();
stability.report_cut(2, &reborn).unwrap();
let mut epochs = Epochs::new([1, 2], NonZeroUsize::new(1).unwrap());
let declaration = epochs
.declare(d(2, 2), rank(2), &stability, &Cut::bottom())
.unwrap();
assert!(stale_counter < declaration.dot().counter());
let poisoned_meet = stale_advertised.meet(&stale_advertised);
assert!(declaration.cut().as_vector().happens_before(&poisoned_meet));
let trailing = Text::from_context(Cut::from_witnessed(poisoned_meet).to_have_set());
assert_eq!(
EpochPreparation::begin(&declaration, trailing, Moves::new()).unwrap_err(),
EpochPreparationMiss::UnpinnedBase {
dot: RawDot::new(1, 9)
}
);
let fresh_one = vector(&[(1, 1), (2, 0)]);
let fresh_two = vector(&[(1, 0), (2, 1)]);
let fresh_meet = fresh_one.meet(&fresh_two);
assert!(&fresh_meet <= declaration.cut().as_vector());
let trailing = Text::from_context(Cut::from_witnessed(fresh_meet).to_have_set());
let staging = EpochPreparation::begin(&declaration, trailing, Moves::new());
assert!(staging.is_ok());
}