use std::collections::BTreeMap;
use blitz_control_protocol::SemanticNode;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Verdict {
Drawn,
Blank,
NoBox,
Hidden,
Offscreen,
}
impl Verdict {
pub fn label(self) -> &'static str {
match self {
Verdict::Drawn => "drawn",
Verdict::Blank => "BLANK",
Verdict::NoBox => "NO BOX",
Verdict::Hidden => "hidden",
Verdict::Offscreen => "offscreen",
}
}
pub fn is_fault(self) -> bool {
matches!(self, Verdict::Blank | Verdict::NoBox)
}
}
#[derive(Debug, Clone)]
pub struct Audited {
pub name: String,
pub family: &'static str,
pub width: f64,
pub height: f64,
pub verdict: Verdict,
}
pub fn family_of(name: &str) -> &'static str {
let lower = name.to_lowercase();
const FAMILIES: &[(&str, &str)] = &[
("close", "close"),
("delete", "delete"),
("remove", "delete"),
("retire", "delete"),
("add", "add"),
("new ", "add"),
("create", "add"),
("edit", "edit"),
("rename", "edit"),
("collapse", "disclosure"),
("expand", "disclosure"),
("show", "disclosure"),
("hide", "disclosure"),
("copy", "copy"),
("move ", "reorder"),
("sort", "reorder"),
("run ", "run"),
("stop", "run"),
("cancel", "run"),
("change the status", "status"),
("fork", "fork"),
("reply", "reply"),
("attach", "attach"),
("clear", "clear"),
];
for (needle, family) in FAMILIES {
if lower.contains(needle) {
return family;
}
}
"other"
}
pub fn buttons(nodes: &[SemanticNode]) -> Vec<&SemanticNode> {
nodes
.iter()
.filter(|node| node.role == "button" && !node.name.trim().is_empty())
.collect()
}
pub fn by_family(rows: &[Audited]) -> BTreeMap<&'static str, (usize, usize)> {
let mut totals: BTreeMap<&'static str, (usize, usize)> = BTreeMap::new();
for row in rows {
let entry = totals.entry(row.family).or_insert((0, 0));
entry.1 += 1;
if !row.verdict.is_fault() {
entry.0 += 1;
}
}
totals
}