use std::fmt;
use crate::ScenarioReceiptEvent;
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct ReceiptDifference<'a> {
pub index: usize,
pub expected: Option<&'a ScenarioReceiptEvent>,
pub actual: Option<&'a ScenarioReceiptEvent>,
}
pub fn first_receipt_difference<'a>(
expected: &'a [ScenarioReceiptEvent],
actual: &'a [ScenarioReceiptEvent],
) -> Option<ReceiptDifference<'a>> {
let index = expected
.iter()
.zip(actual)
.position(|(expected, actual)| expected != actual)
.or_else(|| (expected.len() != actual.len()).then_some(expected.len().min(actual.len())))?;
Some(ReceiptDifference {
index,
expected: expected.get(index),
actual: actual.get(index),
})
}
impl fmt::Display for ReceiptDifference<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"receipt differs at event {}\nexpected: ",
self.index
)?;
write_event(formatter, self.expected)?;
formatter.write_str("\nactual: ")?;
write_event(formatter, self.actual)
}
}
impl fmt::Debug for ReceiptDifference<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, formatter)
}
}
fn write_event(
formatter: &mut fmt::Formatter<'_>,
event: Option<&ScenarioReceiptEvent>,
) -> fmt::Result {
let Some(event) = event else {
return formatter.write_str("<end of receipt>");
};
write!(
formatter,
"time_ns={} generation=",
event.virtual_time.as_nanos()
)?;
write_identifier(formatter, &event.generation_id)?;
formatter.write_str(" operation=")?;
write_identifier(formatter, &event.operation_id)?;
write!(
formatter,
" transition={:?} fault={:?} terminal={:?}",
event.transition, event.fault, event.terminal,
)
}
fn write_identifier(formatter: &mut fmt::Formatter<'_>, identifier: &str) -> fmt::Result {
let mut remaining = 128;
formatter.write_str("\"")?;
for character in identifier.chars() {
let escaped_size = character.escape_default().count();
if escaped_size > remaining {
formatter.write_str("...")?;
break;
}
write!(formatter, "{}", character.escape_default())?;
remaining -= escaped_size;
}
formatter.write_str("\"")
}