use secfinding::*;
use secfinding::filter::*;
use super::*;
use crate::Finding;
#[test]
fn filter_applies_severity_scanner_and_tags() {
let findings = vec![
Finding::builder("nmap", "https://example.com", Severity::Critical)
.title("RCE")
.tag("critical")
.build()
.unwrap(),
Finding::builder("burp", "https://example.com", Severity::High)
.title("SQLi")
.tag("sqli")
.build()
.unwrap(),
Finding::builder("trivy", "https://example.org", Severity::Low)
.title("Info")
.tag("auth")
.build()
.unwrap(),
];
let config = FindingFilter {
min_severity: Some(Severity::High),
exclude_scanners: vec!["nmap".to_string()],
include_tags: vec!["sqli".to_string()],
};
let filtered = filter(&findings, &config);
assert_eq!(filtered.len(), 1);
assert_eq!(filtered[0].scanner, "burp");
}
#[test]
fn filter_with_no_includes_keeps_matching_scanners() {
let findings = vec![
Finding::builder("a", "target", Severity::High)
.title("t")
.tag("x")
.build()
.unwrap(),
Finding::builder("b", "target", Severity::Medium)
.title("t")
.tag("x")
.build()
.unwrap(),
];
let config = FindingFilter {
min_severity: Some(Severity::Medium),
exclude_scanners: vec!["b".to_string()],
include_tags: Vec::new(),
};
let filtered = filter(&findings, &config);
assert_eq!(filtered.len(), 1);
assert_eq!(filtered[0].scanner, "a");
}
#[test]
fn filter_all_excluded() {
let findings = vec![Finding::builder("a", "target", Severity::High)
.title("t")
.build()
.unwrap()];
let config = FindingFilter {
min_severity: None,
exclude_scanners: vec!["a".to_string()],
include_tags: Vec::new(),
};
let filtered = filter(&findings, &config);
assert!(filtered.is_empty());
}
#[test]
fn filter_by_min_severity_only() {
let findings = vec![
Finding::builder("a", "target", Severity::Info)
.title("t")
.build()
.unwrap(),
Finding::builder("b", "target", Severity::Low)
.title("t")
.build()
.unwrap(),
Finding::builder("c", "target", Severity::Critical)
.title("t")
.build()
.unwrap(),
];
let config = FindingFilter {
min_severity: Some(Severity::Low),
exclude_scanners: Vec::new(),
include_tags: Vec::new(),
};
let filtered = filter(&findings, &config);
assert_eq!(filtered.len(), 2);
}
#[test]
fn filter_no_tags_match() {
let findings = vec![Finding::builder("a", "target", Severity::High)
.title("t")
.tag("t1")
.build()
.unwrap()];
let config = FindingFilter {
min_severity: None,
exclude_scanners: Vec::new(),
include_tags: vec!["t2".to_string()],
};
let filtered = filter(&findings, &config);
assert!(filtered.is_empty());
}
#[test]
fn parse_toml_filter_config() {
let toml_str = r#"
min_severity = "high"
exclude_scanners = ["test"]
include_tags = ["t1", "t2"]
"#;
let config = FindingFilter::from_toml(toml_str).unwrap();
assert_eq!(config.min_severity, Some(Severity::High));
assert_eq!(config.exclude_scanners.len(), 1);
assert_eq!(config.include_tags.len(), 2);
}
#[test]
fn parse_empty_toml_filter_config() {
let config = FindingFilter::from_toml("").unwrap();
assert_eq!(config.min_severity, None);
assert!(config.exclude_scanners.is_empty());
assert!(config.include_tags.is_empty());
}
#[test]
fn filter_multiple_conditions() {
let findings = vec![
Finding::builder("nmap", "target", Severity::High)
.title("t")
.tag("web")
.build()
.unwrap(),
Finding::builder("burp", "target", Severity::Low)
.title("t")
.tag("web")
.build()
.unwrap(),
Finding::builder("burp", "target", Severity::Critical)
.title("t")
.tag("api")
.build()
.unwrap(),
];
let config = FindingFilter {
min_severity: Some(Severity::High),
exclude_scanners: vec!["nmap".to_string()],
include_tags: vec!["api".to_string(), "web".to_string()],
};
let filtered = filter(&findings, &config);
assert_eq!(filtered.len(), 1);
assert_eq!(filtered[0].scanner, "burp");
assert_eq!(filtered[0].severity, Severity::Critical);
}