use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathResult {
pub success: bool,
pub iterations: u32,
pub diff: String,
pub diff_lines: u32,
pub duration: Duration,
pub error: Option<String>,
}
impl PathResult {
pub fn failure(error: String, duration: Duration) -> Self {
Self {
success: false,
iterations: 0,
diff: String::new(),
diff_lines: 0,
duration,
error: Some(error),
}
}
}
pub use crate::metrics::ComparisonResult;
pub struct Comparator;
impl Comparator {
pub fn compare(direct: &PathResult, bridge: &PathResult) -> ComparisonResult {
let both_succeeded = direct.success && bridge.success;
let both_failed = !direct.success && !bridge.success;
let diffs_match = if both_succeeded {
let d1: String = direct.diff.split_whitespace().collect();
let d2: String = bridge.diff.split_whitespace().collect();
d1 == d2
} else {
false
};
let iteration_delta = bridge.iterations as i32 - direct.iterations as i32;
let mut bridge_specific_errors = Vec::new();
if !bridge.success
&& direct.success
&& let Some(ref err) = bridge.error
{
bridge_specific_errors.push(format!("Bridge failed while direct succeeded: {err}"));
}
ComparisonResult {
both_succeeded,
both_failed,
diffs_match,
iteration_delta,
bridge_specific_errors,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compare_both_succeed() {
let direct = PathResult {
success: true,
iterations: 5,
diff: "some diff".to_string(),
diff_lines: 10,
duration: Duration::from_secs(30),
error: None,
};
let bridge = PathResult {
success: true,
iterations: 7,
diff: "some diff".to_string(),
diff_lines: 10,
duration: Duration::from_secs(45),
error: None,
};
let result = Comparator::compare(&direct, &bridge);
assert!(result.both_succeeded);
assert!(!result.both_failed);
assert!(result.diffs_match);
assert_eq!(result.iteration_delta, 2);
}
#[test]
fn test_compare_bridge_fails() {
let direct = PathResult {
success: true,
iterations: 5,
diff: "diff".to_string(),
diff_lines: 5,
duration: Duration::from_secs(30),
error: None,
};
let bridge = PathResult::failure("timeout".to_string(), Duration::from_secs(60));
let result = Comparator::compare(&direct, &bridge);
assert!(!result.both_succeeded);
assert!(!result.both_failed);
assert!(!result.diffs_match);
assert_eq!(result.bridge_specific_errors.len(), 1);
}
}