use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationResult {
pub passed: bool,
pub baseline: f64,
pub current: f64,
pub strategy: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub failure_reason: Option<String>,
pub sample_count: usize,
}
impl ValidationResult {
pub fn pass(baseline: f64, current: f64, strategy: &str, sample_count: usize) -> Self {
Self {
passed: true,
baseline,
current,
strategy: strategy.to_string(),
failure_reason: None,
sample_count,
}
}
pub fn fail(
baseline: f64,
current: f64,
strategy: &str,
reason: impl Into<String>,
sample_count: usize,
) -> Self {
Self {
passed: false,
baseline,
current,
strategy: strategy.to_string(),
failure_reason: Some(reason.into()),
sample_count,
}
}
pub fn improvement(&self) -> f64 {
if self.baseline > 0.0 {
(self.current / self.baseline - 1.0) * 100.0
} else {
0.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pass_result() {
let result = ValidationResult::pass(0.7, 0.85, "no_regression", 100);
assert!(result.passed);
assert!(result.failure_reason.is_none());
assert!((result.improvement() - 21.43).abs() < 0.1);
}
#[test]
fn test_fail_result() {
let result = ValidationResult::fail(0.7, 0.65, "no_regression", "regression detected", 100);
assert!(!result.passed);
assert!(result.failure_reason.is_some());
}
#[test]
fn test_serialization() {
let result = ValidationResult::pass(0.7, 0.8, "improvement", 50);
let json = serde_json::to_string(&result).unwrap();
let restored: ValidationResult = serde_json::from_str(&json).unwrap();
assert_eq!(restored.passed, result.passed);
assert_eq!(restored.strategy, result.strategy);
}
}