use crate::model::{AttemptRow, TestStatus};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FailureClass {
DeterministicPass,
DeterministicFail,
Flaky, Unstable, Error, Skipped,
}
pub fn classify_attempts(attempts: &[AttemptRow]) -> FailureClass {
use TestStatus::*;
if attempts.is_empty() {
return FailureClass::Error;
}
if attempts.len() == 1 {
if let Skipped = attempts[0].status {
return FailureClass::Skipped;
}
}
let has_error = attempts.iter().any(|a| matches!(a.status, Error));
if has_error {
return FailureClass::Error;
}
let statuses: Vec<TestStatus> = attempts.iter().map(|a| a.status.clone()).collect();
let any_fail = statuses.iter().any(|s| matches!(s, Fail));
let any_pass = statuses.iter().any(|s| matches!(s, Pass | Warn | Flaky));
if any_fail && any_pass {
let first_fail_idx = statuses.iter().position(|s| matches!(s, Fail));
let first_pass_idx = statuses.iter().position(|s| matches!(s, Pass));
if let (Some(fail_i), Some(pass_i)) = (first_fail_idx, first_pass_idx) {
if fail_i < pass_i {
let last = statuses.last().unwrap();
if matches!(last, Pass) {
return FailureClass::Flaky;
}
}
}
return FailureClass::Unstable;
}
if any_fail {
return FailureClass::DeterministicFail;
}
FailureClass::DeterministicPass
}