use super::*;
const MATCH_DISPATCH: &str = r#"
fn call_a() {}
fn call_b() {}
fn dispatch(x: i32) {
match x {
0 => call_a(),
_ => call_b(),
}
}
"#;
#[test]
fn test_trivial_self_getter_not_violation() {
let code = r#"
struct Counter { count: usize }
impl Counter {
fn symbol_count(&self) -> usize { self.count }
fn next_symbol(&self) -> usize {
if self.symbol_count() > 0 {
self.symbol_count() + 1
} else {
0
}
}
}
"#;
let results = parse_and_analyze(code);
let next = results.iter().find(|r| r.name == "next_symbol").unwrap();
assert_eq!(
next.classification,
Classification::Operation,
"Trivial getter should not make next_symbol a Violation, got {:?}",
next.classification
);
}
#[test]
fn test_leaf_constructor_call_is_operation() {
let code = r#"
struct Adx { period: usize }
impl Adx {
fn new(period: usize) -> Self { Adx { period } }
}
fn compute(data: &[f64]) -> f64 {
let indicator = Adx::new(14);
if data.is_empty() { 0.0 } else { data[0] }
}
"#;
let results = parse_and_analyze(code);
let f = results.iter().find(|r| r.name == "compute").unwrap();
assert!(
matches!(f.classification, Classification::Operation),
"Adx::new() is leaf → calling it + logic = Operation, got {:?}",
f.classification
);
}
#[test]
fn test_trivial_getter_get_not_violation() {
let code = r#"
struct Browser { results: Vec<String>, selected: usize }
impl Browser {
fn current(&self) -> Option<&String> { self.results.get(self.selected) }
fn process(&self) -> String {
if let Some(item) = self.current() {
item.clone()
} else {
String::new()
}
}
}
"#;
let results = parse_and_analyze(code);
let f = results.iter().find(|r| r.name == "process").unwrap();
assert_eq!(
f.classification,
Classification::Operation,
"Trivial .get() getter should not make process a Violation, got {:?}",
f.classification
);
}
#[test]
fn test_for_loop_delegation_not_violation() {
let code = r#"
fn process(_x: i32) {}
fn f(items: Vec<i32>) {
for x in items {
process(x);
}
}
"#;
let results = parse_and_analyze(code);
let f = results.iter().find(|r| r.name == "f").unwrap();
assert_eq!(
f.classification,
Classification::Integration,
"For-loop delegation should be Integration, got {:?}",
f.classification
);
}
#[test]
fn test_match_dispatch_is_integration() {
let results = parse_and_analyze(MATCH_DISPATCH);
let f = results.iter().find(|r| r.name == "dispatch").unwrap();
assert_eq!(
f.classification,
Classification::Integration,
"Match dispatch should be Integration, got {:?}",
f.classification
);
}
#[test]
fn test_match_dispatch_method_is_integration() {
let code = r#"
struct S;
impl S {
fn run_a(&self) {}
fn run_b(&self) {}
fn dispatch(&self, x: i32) {
match x {
0 => self.run_a(),
_ => self.run_b(),
}
}
}
"#;
let results = parse_and_analyze(code);
let f = results.iter().find(|r| r.name == "dispatch").unwrap();
assert_eq!(
f.classification,
Classification::Integration,
"Match method dispatch should be Integration, got {:?}",
f.classification
);
}
#[test]
fn test_match_with_logic_in_arm_is_violation() {
let code = r#"
fn call_a(_x: i32) { if _x > 0 { dispatch(_x - 1); } }
fn call_b() { dispatch(0); }
fn dispatch(x: i32) {
match x {
0 => call_a(x + 1),
_ => call_b(),
}
}
"#;
let results = parse_and_analyze(code);
let f = results.iter().find(|r| r.name == "dispatch").unwrap();
assert!(
matches!(f.classification, Classification::Violation { .. }),
"Match with logic in arm should be Violation, got {:?}",
f.classification
);
}
#[test]
fn test_match_with_guard_is_violation() {
let code = r#"
fn call_a() { if true { dispatch(0); } }
fn call_b() { dispatch(1); }
fn dispatch(x: i32) {
match x {
n if n > 0 => call_a(),
_ => call_b(),
}
}
"#;
let results = parse_and_analyze(code);
let f = results.iter().find(|r| r.name == "dispatch").unwrap();
assert!(
matches!(f.classification, Classification::Violation { .. }),
"Match with guard should be Violation, got {:?}",
f.classification
);
}
#[test]
fn test_match_dispatch_complexity_still_tracked() {
let results = parse_and_analyze(MATCH_DISPATCH);
let f = results.iter().find(|r| r.name == "dispatch").unwrap();
assert!(
f.complexity.as_ref().unwrap().cognitive_complexity >= 1,
"Complexity should still be tracked for dispatch match"
);
}