use crate::priority::classification::Severity;
use crate::priority::UnifiedDebtItem;
#[derive(Debug, Clone)]
pub enum Filter {
Severity(SeverityFilter),
Coverage(CoverageFilter),
Complexity(u32),
}
impl Filter {
pub fn matches(&self, item: &UnifiedDebtItem) -> bool {
match self {
Filter::Severity(sev) => sev.matches(item),
Filter::Coverage(cov) => cov.matches(item),
Filter::Complexity(threshold) => item.cyclomatic_complexity >= *threshold,
}
}
pub fn display_name(&self) -> String {
match self {
Filter::Severity(sev) => format!("Severity: {}", sev.display_name()),
Filter::Coverage(cov) => format!("Coverage: {}", cov.display_name()),
Filter::Complexity(threshold) => format!("Complexity >= {}", threshold),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SeverityFilter {
Critical,
High,
Medium,
Low,
}
impl SeverityFilter {
pub fn matches(&self, item: &UnifiedDebtItem) -> bool {
let item_severity = Severity::from_score_100(item.unified_score.final_score)
.as_str()
.to_lowercase();
match self {
SeverityFilter::Critical => item_severity == "critical",
SeverityFilter::High => item_severity == "high",
SeverityFilter::Medium => item_severity == "medium",
SeverityFilter::Low => item_severity == "low",
}
}
pub fn display_name(&self) -> &'static str {
match self {
SeverityFilter::Critical => "Critical",
SeverityFilter::High => "High",
SeverityFilter::Medium => "Medium",
SeverityFilter::Low => "Low",
}
}
pub fn all() -> &'static [SeverityFilter] {
&[
SeverityFilter::Critical,
SeverityFilter::High,
SeverityFilter::Medium,
SeverityFilter::Low,
]
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CoverageFilter {
None,
Low,
Medium,
High,
}
impl CoverageFilter {
pub fn matches(&self, item: &UnifiedDebtItem) -> bool {
let coverage = item.transitive_coverage.as_ref().map(|c| c.direct);
match (self, coverage) {
(CoverageFilter::None, None) => true,
(CoverageFilter::None, Some(_)) => false,
(CoverageFilter::Low, Some(cov)) => cov < 30.0,
(CoverageFilter::Medium, Some(cov)) => (30.0..70.0).contains(&cov),
(CoverageFilter::High, Some(cov)) => cov >= 70.0,
_ => false,
}
}
pub fn display_name(&self) -> &'static str {
match self {
CoverageFilter::None => "No Coverage",
CoverageFilter::Low => "Low (0-30%)",
CoverageFilter::Medium => "Medium (30-70%)",
CoverageFilter::High => "High (70-100%)",
}
}
pub fn all() -> &'static [CoverageFilter] {
&[
CoverageFilter::None,
CoverageFilter::Low,
CoverageFilter::Medium,
CoverageFilter::High,
]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_severity_display() {
assert_eq!(SeverityFilter::Critical.display_name(), "Critical");
assert_eq!(SeverityFilter::High.display_name(), "High");
assert_eq!(SeverityFilter::Medium.display_name(), "Medium");
assert_eq!(SeverityFilter::Low.display_name(), "Low");
}
#[test]
fn test_coverage_display() {
assert_eq!(CoverageFilter::None.display_name(), "No Coverage");
assert_eq!(CoverageFilter::Low.display_name(), "Low (0-30%)");
assert_eq!(CoverageFilter::Medium.display_name(), "Medium (30-70%)");
assert_eq!(CoverageFilter::High.display_name(), "High (70-100%)");
}
#[test]
fn test_severity_classification() {
assert_eq!(
Severity::from_score_100(85.0).as_str().to_lowercase(),
"critical"
);
assert_eq!(
Severity::from_score_100(60.0).as_str().to_lowercase(),
"high"
);
assert_eq!(
Severity::from_score_100(40.0).as_str().to_lowercase(),
"medium"
);
assert_eq!(
Severity::from_score_100(15.0).as_str().to_lowercase(),
"low"
);
}
#[test]
fn test_all_filters() {
assert_eq!(SeverityFilter::all().len(), 4);
assert_eq!(CoverageFilter::all().len(), 4);
}
}