#![deny(missing_docs)]
use std::collections::BTreeMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CaseResult {
AlwaysPass,
AlwaysFail,
Flaky,
}
#[derive(Debug, Clone)]
pub struct Report {
pub case: String,
pub status: CaseResult,
pub passes: u32,
pub fails: u32,
pub flip_rate: f64,
}
pub fn detect(runs: &[Vec<(&str, bool)>]) -> Vec<Report> {
let mut grouped: BTreeMap<String, Vec<bool>> = BTreeMap::new();
for run in runs {
for (case, pass) in run {
grouped.entry((*case).to_string()).or_default().push(*pass);
}
}
grouped
.into_iter()
.map(|(case, outcomes)| {
let passes = outcomes.iter().filter(|p| **p).count() as u32;
let fails = outcomes.iter().filter(|p| !**p).count() as u32;
let status = match (passes, fails) {
(0, _) => CaseResult::AlwaysFail,
(_, 0) => CaseResult::AlwaysPass,
_ => CaseResult::Flaky,
};
let flip_rate = if outcomes.len() < 2 {
0.0
} else {
let flips = outcomes
.windows(2)
.filter(|w| w[0] != w[1])
.count() as f64;
flips / (outcomes.len() - 1) as f64
};
Report {
case,
status,
passes,
fails,
flip_rate,
}
})
.collect()
}