extern crate alloc;
use super::super::support::dot;
use crate::metis::{DotSet, Retired, Retirement, UnknownStation};
fn dots(pairs: &[(u32, u64)]) -> DotSet {
let mut set = DotSet::new();
for &(station, counter) in pairs {
let _ = set.insert(dot(station, counter));
}
set
}
fn retired_eq(retired: &Retired, expected: &DotSet) -> bool {
*retired == Retired::trust(expected.clone())
}
#[test]
fn test_retired_is_the_meet_across_the_roster() {
let mut tracker = Retirement::new([1, 2, 3]);
tracker.acknowledge(1, &dots(&[(1, 1), (2, 1)])).unwrap();
tracker
.acknowledge(2, &dots(&[(1, 1), (2, 1), (3, 1)]))
.unwrap();
tracker
.acknowledge(3, &dots(&[(1, 1), (2, 1), (2, 2)]))
.unwrap();
assert!(retired_eq(&tracker.retired(), &dots(&[(1, 1), (2, 1)])));
}
#[test]
fn test_retired_requires_every_member() {
let mut tracker = Retirement::new([1, 2]);
tracker.acknowledge(1, &dots(&[(1, 9), (2, 9)])).unwrap();
assert!(retired_eq(&tracker.retired(), &DotSet::new()));
}
#[test]
fn test_unknown_station_is_refused_unchanged() {
let mut tracker = Retirement::new([1, 2]);
tracker.acknowledge(1, &dots(&[(1, 1)])).unwrap();
let before = tracker.clone();
let refused = tracker.acknowledge(7, &dots(&[(1, 5)]));
assert_eq!(refused, Err(UnknownStation { station: 7 }));
assert_eq!(tracker, before);
}
#[test]
fn test_acknowledge_is_order_invariant() {
let mut forward = Retirement::new([1, 2]);
forward.acknowledge(1, &dots(&[(1, 1)])).unwrap();
forward.acknowledge(2, &dots(&[(1, 1), (2, 2)])).unwrap();
forward.acknowledge(1, &dots(&[(1, 4)])).unwrap();
let mut backward = Retirement::new([1, 2]);
backward.acknowledge(1, &dots(&[(1, 4)])).unwrap();
backward.acknowledge(2, &dots(&[(1, 1), (2, 2)])).unwrap();
backward.acknowledge(1, &dots(&[(1, 1)])).unwrap();
assert_eq!(forward, backward);
}
#[test]
fn test_stale_acknowledgement_is_absorbed() {
let mut tracker = Retirement::new([1, 2]);
tracker.acknowledge(1, &dots(&[(1, 4)])).unwrap();
tracker.acknowledge(2, &dots(&[(1, 4)])).unwrap();
let high = tracker.retired();
assert!(retired_eq(&high, &dots(&[(1, 4)])));
tracker.acknowledge(1, &dots(&[(1, 4)])).unwrap();
assert_eq!(tracker.retired(), high);
}
#[test]
fn test_retired_is_monotone_non_decreasing() {
let mut tracker = Retirement::new([1, 2]);
tracker.acknowledge(1, &dots(&[(1, 3)])).unwrap();
tracker.acknowledge(2, &dots(&[(1, 3)])).unwrap();
let first = tracker.retired();
tracker.acknowledge(1, &dots(&[(1, 3), (2, 1)])).unwrap();
tracker.acknowledge(2, &dots(&[(1, 3), (2, 1)])).unwrap();
let second = tracker.retired();
assert!(retired_eq(&first, &dots(&[(1, 3)])));
assert!(retired_eq(&second, &dots(&[(1, 3), (2, 1)])));
}
#[test]
fn test_empty_roster_retired_is_bottom() {
let tracker = Retirement::new(core::iter::empty::<u32>());
assert!(retired_eq(&tracker.retired(), &DotSet::new()));
}
#[test]
fn test_acknowledged_reader_exposes_the_laggard() {
let mut tracker = Retirement::new([2, 1]);
tracker.acknowledge(1, &dots(&[(1, 6)])).unwrap();
let slots: alloc::vec::Vec<_> = tracker.acknowledged().collect();
assert_eq!(slots.len(), 2);
assert_eq!(slots[0], (1, &dots(&[(1, 6)])));
assert_eq!(slots[1], (2, &DotSet::new()));
}
#[test]
fn test_trust_is_the_audited_escape() {
let mut tracker = Retirement::new([1]);
tracker.acknowledge(1, &dots(&[(1, 2), (1, 3)])).unwrap();
assert_eq!(tracker.retired(), Retired::trust(dots(&[(1, 2), (1, 3)])));
}