use std::cmp::Ordering;
use dyniak::datatypes::{Itc, ItcEvent, ItcId};
use hegel::generators as gs;
use hegel::TestCase;
fn build_history(ops: &[u8]) -> Vec<Itc> {
let mut stamps = vec![Itc::seed()];
for &op in ops {
match op % 4 {
0 => {
if let Some(pos) = stamps.iter().position(Itc::has_authority) {
let s = stamps.remove(pos);
let (a, b) = s.fork();
stamps.push(a);
stamps.push(b);
}
}
1 => {
if let Some(s) = stamps.iter_mut().find(|s| s.has_authority()) {
s.event();
}
}
2 => {
if stamps.len() >= 2 {
let b = stamps.pop().unwrap();
let a = stamps.pop().unwrap();
stamps.push(a.join(b));
}
}
_ => {
if stamps.len() >= 2 {
let sender = stamps.remove(0);
let (sender, msg) = sender.send();
let receiver = stamps.remove(0);
stamps.insert(0, receiver.receive(msg));
stamps.push(sender);
}
}
}
if stamps.is_empty() {
stamps.push(Itc::seed());
}
}
stamps
}
fn arb_ops(tc: &TestCase) -> Vec<u8> {
let n = tc.draw(gs::integers::<usize>().min_value(0).max_value(24));
let mut out = Vec::with_capacity(n);
for _ in 0..n {
out.push(tc.draw(gs::integers::<u8>()));
}
out
}
#[test]
fn seed_has_authority_and_peek_drops_it() {
let s = Itc::seed();
assert!(s.has_authority());
let p = s.peek();
assert!(!p.has_authority());
assert_eq!(p.event_tree(), s.event_tree());
assert_eq!(p.id(), &ItcId::zero());
}
#[test]
fn event_advances_strictly() {
let mut s = Itc::seed();
let before = s.clone();
s.event();
assert_eq!(before.partial_cmp_event(&s), Some(Ordering::Less));
assert!(before.leq(&s));
assert!(!s.leq(&before));
}
#[test]
fn fork_then_join_recovers_causal_equality() {
let mut s = Itc::seed();
s.event();
let snapshot = s.clone();
let (a, b) = s.fork();
let rejoined = a.join(b);
assert_eq!(snapshot.partial_cmp_event(&rejoined), Some(Ordering::Equal));
}
#[test]
fn concurrent_forks_are_incomparable_after_independent_events() {
let (mut a, mut b) = Itc::seed().fork();
a.event();
b.event();
assert_eq!(a.partial_cmp_event(&b), None);
}
#[test]
fn send_receive_establishes_happens_before() {
let sender = Itc::seed();
let (sender_after, msg) = sender.send();
let (recv_half, _other) = Itc::seed().fork();
let merged = recv_half.receive(msg.clone());
assert!(msg.leq(&merged));
assert!(sender_after.leq(&sender_after));
}
#[test]
fn encode_decode_round_trip_seed_and_evolved() {
for stamp in [
Itc::seed(),
{
let mut s = Itc::seed();
s.event();
s.event();
s
},
{
let (a, b) = Itc::seed().fork();
let mut a = a;
a.event();
a.join(b)
},
] {
let bytes = stamp.encode();
let back = Itc::decode(&bytes).expect("decode");
assert_eq!(stamp.partial_cmp_event(&back), Some(Ordering::Equal));
assert_eq!(back.encode(), bytes, "re-encode is stable");
}
}
#[test]
fn decode_rejects_malformed_bytes() {
assert!(Itc::decode(&[]).is_none());
assert!(Itc::decode(&[0, 0, 0]).is_none());
assert!(Itc::decode(&[0, 0, 0, 200, 0x00]).is_none());
assert!(Itc::decode(&[0, 0, 0, 8, 0x00, 0x00]).is_none());
}
#[test]
fn display_is_non_empty_for_node_trees() {
let (a, b) = Itc::seed().fork();
let joined = a.join(b);
let shown = format!("{joined}");
assert!(!shown.is_empty());
assert!(!format!("{}", Itc::seed()).is_empty());
}
#[test]
fn from_parts_normalises() {
let s = Itc::from_parts(ItcId::one(), ItcEvent::zero());
assert_eq!(s.partial_cmp_event(&Itc::seed()), Some(Ordering::Equal));
}
#[hegel::test(test_cases = 256)]
fn encode_decode_round_trips_over_histories(tc: TestCase) {
let ops = arb_ops(&tc);
for stamp in build_history(&ops) {
let bytes = stamp.encode();
let back = Itc::decode(&bytes).expect("decode round-trips");
assert_eq!(stamp.partial_cmp_event(&back), Some(Ordering::Equal));
assert_eq!(back.encode(), bytes);
}
}
#[hegel::test(test_cases = 256)]
fn partial_cmp_consistent_with_leq(tc: TestCase) {
let ops = arb_ops(&tc);
let stamps = build_history(&ops);
if stamps.len() < 2 {
return;
}
let i = tc.draw(
gs::integers::<usize>()
.min_value(0)
.max_value(stamps.len() - 1),
);
let j = tc.draw(
gs::integers::<usize>()
.min_value(0)
.max_value(stamps.len() - 1),
);
let a = &stamps[i];
let b = &stamps[j];
let expected = match (a.leq(b), b.leq(a)) {
(true, true) => Some(Ordering::Equal),
(true, false) => Some(Ordering::Less),
(false, true) => Some(Ordering::Greater),
(false, false) => None,
};
assert_eq!(a.partial_cmp_event(b), expected);
}
#[hegel::test(test_cases = 256)]
fn event_never_regresses(tc: TestCase) {
let ops = arb_ops(&tc);
let stamps = build_history(&ops);
let idx = tc.draw(
gs::integers::<usize>()
.min_value(0)
.max_value(stamps.len() - 1),
);
let before = stamps[idx].clone();
let mut after = before.clone();
if !after.has_authority() {
return;
}
after.event();
assert!(before.leq(&after));
}