swarm_engine_core/validation/
result.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ValidationResult {
10 pub passed: bool,
12 pub baseline: f64,
14 pub current: f64,
16 pub strategy: String,
18 #[serde(default, skip_serializing_if = "Option::is_none")]
20 pub failure_reason: Option<String>,
21 pub sample_count: usize,
23}
24
25impl ValidationResult {
26 pub fn pass(baseline: f64, current: f64, strategy: &str, sample_count: usize) -> Self {
28 Self {
29 passed: true,
30 baseline,
31 current,
32 strategy: strategy.to_string(),
33 failure_reason: None,
34 sample_count,
35 }
36 }
37
38 pub fn fail(
40 baseline: f64,
41 current: f64,
42 strategy: &str,
43 reason: impl Into<String>,
44 sample_count: usize,
45 ) -> Self {
46 Self {
47 passed: false,
48 baseline,
49 current,
50 strategy: strategy.to_string(),
51 failure_reason: Some(reason.into()),
52 sample_count,
53 }
54 }
55
56 pub fn improvement(&self) -> f64 {
58 if self.baseline > 0.0 {
59 (self.current / self.baseline - 1.0) * 100.0
60 } else {
61 0.0
62 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn test_pass_result() {
72 let result = ValidationResult::pass(0.7, 0.85, "no_regression", 100);
73 assert!(result.passed);
74 assert!(result.failure_reason.is_none());
75 assert!((result.improvement() - 21.43).abs() < 0.1);
76 }
77
78 #[test]
79 fn test_fail_result() {
80 let result = ValidationResult::fail(0.7, 0.65, "no_regression", "regression detected", 100);
81 assert!(!result.passed);
82 assert!(result.failure_reason.is_some());
83 }
84
85 #[test]
86 fn test_serialization() {
87 let result = ValidationResult::pass(0.7, 0.8, "improvement", 50);
88 let json = serde_json::to_string(&result).unwrap();
89 let restored: ValidationResult = serde_json::from_str(&json).unwrap();
90 assert_eq!(restored.passed, result.passed);
91 assert_eq!(restored.strategy, result.strategy);
92 }
93}