use crate::observe::{Action, Observation, ObservationTrace, Reason};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Divergence {
pub index: usize,
pub expected: Option<Observation>,
pub actual: Option<Observation>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "comparison", rename_all = "snake_case")]
pub enum Comparison {
Equal,
Diverged(Divergence),
Incomparable {
reason: Reason,
},
}
pub fn compare(expected: &ObservationTrace, actual: &ObservationTrace) -> Comparison {
if !expected.is_complete() {
return Comparison::Incomparable {
reason: Reason::with_detail(
"incomplete_expected",
format!("the expected trace dropped {} facts", expected.dropped),
),
};
}
if !actual.is_complete() {
return Comparison::Incomparable {
reason: Reason::with_detail(
"incomplete_actual",
format!("the actual trace dropped {} facts", actual.dropped),
),
};
}
let semantic = |observation: &Observation| {
let mut observation = observation.clone();
observation.at = None;
if let Action::Adapter { observation } = &mut observation.action {
observation.analysis = None;
}
observation
};
let longest = expected.observations.len().max(actual.observations.len());
for index in 0..longest {
let left = expected.observations.get(index).map(semantic);
let right = actual.observations.get(index).map(semantic);
if left != right {
return Comparison::Diverged(Divergence {
index,
expected: left,
actual: right,
});
}
}
Comparison::Equal
}