use super::*;
#[test]
fn test_anchor_support_matrix_exposes_the_annex_boundary() {
let cases = [
(false, BoundarySupport::PositionOnly, false),
(false, BoundarySupport::TombstoneAnnex, true),
(true, BoundarySupport::PositionOnly, true),
(true, BoundarySupport::TombstoneAnnex, true),
];
for (anchor_is_live, support, expected) in cases {
let (state, movements) = anchor_case(anchor_is_live, [2, 1]);
let result = cross_boundary(&state, &movements, support);
let applied = [
Decision {
testimony: Testimony(2),
verdict: Verdict::Applied,
},
Decision {
testimony: Testimony(1),
verdict: Verdict::Applied,
},
];
assert_eq!(result.old_decisions, applied);
assert_eq!(result.translated_decisions, applied);
if anchor_is_live {
assert_eq!(result.fold_then_refound, ['a', 't', 'x', 'y', 'b']);
assert_eq!(result.refound_then_fold, ['a', 't', 'x', 'y', 'b']);
} else if support == BoundarySupport::TombstoneAnnex {
assert_eq!(result.fold_then_refound, ['a', 'x', 'y', 'b']);
assert_eq!(result.refound_then_fold, ['a', 'x', 'y', 'b']);
} else {
assert_eq!(result.fold_then_refound, ['a', 'x', 'y', 'b']);
assert_eq!(result.refound_then_fold, ['a', 'y', 'x', 'b']);
}
assert_eq!(
result.commutes(),
expected,
"{anchor_is_live:?} {support:?}"
);
}
}
#[test]
fn test_equal_rank_rechaining_changes_live_anchor_context() {
for support in [
BoundarySupport::PositionOnly,
BoundarySupport::TombstoneAnnex,
] {
let (state, movements) = anchor_case(true, [0, 0]);
let result = cross_boundary(&state, &movements, support);
assert_eq!(result.fold_then_refound, ['a', 't', 'x', 'y', 'b']);
assert_eq!(result.refound_then_fold, ['a', 't', 'b', 'x', 'y']);
assert!(!result.commutes(), "{support:?}");
}
}
#[test]
fn test_rechaining_changes_a_move_refusal_even_with_the_annex() {
let mut state = State::new();
let a = Dot::old(1);
let b = Dot::old(2);
state.insert(
a,
Node {
label: 'a',
locus: Locus {
anchor: Anchor::Origin,
rank: 2,
},
visible: true,
},
);
state.insert(
b,
Node {
label: 'b',
locus: Locus {
anchor: Anchor::Origin,
rank: 1,
},
visible: true,
},
);
let movement = Movement {
testimony: Testimony(1),
target: a,
to: Locus {
anchor: Anchor::After(b),
rank: 1,
},
};
for support in [
BoundarySupport::PositionOnly,
BoundarySupport::TombstoneAnnex,
] {
let result = cross_boundary(&state, &[movement], support);
assert_eq!(
result.old_decisions,
[Decision {
testimony: Testimony(1),
verdict: Verdict::Applied,
}]
);
assert_eq!(
result.translated_decisions,
[Decision {
testimony: Testimony(1),
verdict: Verdict::RefusedCycle,
}]
);
assert_eq!(result.fold_then_refound, ['b', 'a']);
assert_eq!(result.refound_then_fold, ['a', 'b']);
assert!(!result.commutes());
}
}
#[test]
fn test_replay_order_decides_which_cycle_former_is_refused() {
let mut state = State::new();
let a = Dot::old(1);
let b = Dot::old(2);
let c = Dot::old(3);
for (dot, label, rank) in [(a, 'a', 3), (b, 'b', 2), (c, 'c', 1)] {
state.insert(
dot,
Node {
label,
locus: Locus {
anchor: Anchor::Origin,
rank,
},
visible: true,
},
);
}
let mut movements = [
Movement {
testimony: Testimony(3),
target: a,
to: Locus {
anchor: Anchor::After(c),
rank: 3,
},
},
Movement {
testimony: Testimony(2),
target: c,
to: Locus {
anchor: Anchor::After(b),
rank: 2,
},
},
Movement {
testimony: Testimony(1),
target: b,
to: Locus {
anchor: Anchor::After(a),
rank: 1,
},
},
];
let expected = [
Decision {
testimony: Testimony(1),
verdict: Verdict::Applied,
},
Decision {
testimony: Testimony(2),
verdict: Verdict::Applied,
},
Decision {
testimony: Testimony(3),
verdict: Verdict::RefusedCycle,
},
];
let mut rank_ordered = state.clone();
assert_eq!(replay(&mut rank_ordered, &movements), expected);
assert_eq!(rank_ordered.reading(), ['a', 'b', 'c']);
for movement in &mut movements {
movement.to.rank = 1;
}
assert_eq!(replay(&mut state, &movements), expected);
assert_eq!(state.reading(), ['a', 'b', 'c']);
}