// ---------------------------------------------------------------------------
// Trace assertions — structured helpers that report the first differing index.
// ---------------------------------------------------------------------------
///|
/// Return the first structural trace mismatch. Kept pure so conformance tests
/// can prove missing, duplicate, and out-of-order detection without catching
/// an assertion panic.
pub fn event_trace_mismatch(
expected : Array[@types.TurnEvent],
actual : Array[@types.TurnEvent],
) -> String? {
let n = if expected.length() < actual.length() {
expected.length()
} else {
actual.length()
}
for i = 0; i < n; i = i + 1 {
if expected[i] != actual[i] {
return Some(
"event_trace_mismatch at index \{i}: expected \{expected[i].to_string()}, got \{actual[i].to_string()}",
)
}
}
if expected.length() != actual.length() {
let index = n
if expected.length() > actual.length() {
return Some(
"event_trace_mismatch at index \{index}: expected \{expected[index].to_string()}, got (expected \{expected.length()} events, actual \{actual.length()})",
)
} else {
return Some(
"event_trace_mismatch at index \{index}: expected , got \{actual[index].to_string()} (expected \{expected.length()} events, actual \{actual.length()})",
)
}
}
None
}
///|
/// Assert two event traces are equal, reporting the first differing index,
/// the expected and actual event, when they diverge.
pub fn assert_events_eq(
expected : Array[@types.TurnEvent],
actual : Array[@types.TurnEvent],
) -> Unit {
match event_trace_mismatch(expected, actual) {
Some(message) => abort(message)
None => ()
}
}
///|
/// Assert the recorded events contain a sub-sequence matching `needle`, in
/// order. Reports the first needle event that could not be matched.
pub fn assert_events_contain(
haystack : Array[@types.TurnEvent],
needle : Array[@types.TurnEvent],
) -> Unit {
if needle.is_empty() {
return
}
let mut hi = 0
for ni = 0; ni < needle.length(); ni = ni + 1 {
let mut found = false
while hi < haystack.length() {
if haystack[hi] == needle[ni] {
found = true
hi = hi + 1
break
}
hi = hi + 1
}
if !found {
abort(
"event_not_found_in_order: needle[\{ni}] = \{needle[ni].to_string()} not matched after haystack index \{hi}",
)
}
}
}