use super::ValidationRule;
use crate::config::ComplexityConfig;
use crate::validator::{ValidationSeverity, Violation};
use smelt_core::{IntentRecord, SemanticDelta};
pub struct ComplexityChecker {
config: ComplexityConfig,
}
impl ComplexityChecker {
pub fn new(config: ComplexityConfig) -> Self {
Self { config }
}
}
impl ValidationRule for ComplexityChecker {
fn name(&self) -> &'static str {
"complexity"
}
fn validate(&self, delta: &SemanticDelta, _intent: Option<&IntentRecord>) -> Vec<Violation> {
let mut violations = Vec::new();
let complexity_delta = delta.impact_summary.complexity_delta;
if complexity_delta > self.config.max_complexity_increase {
violations.push(Violation {
rule: "complexity-increase".to_string(),
severity: if self.config.complexity_error {
ValidationSeverity::Error
} else {
ValidationSeverity::Warning
},
message: format!(
"Complexity increased by {} (threshold: {})",
complexity_delta, self.config.max_complexity_increase
),
location: None,
suggestion: Some(
"Consider refactoring to reduce complexity or splitting into smaller functions"
.to_string(),
),
});
}
for change in &delta.changes {
if let smelt_core::SemanticChange::BodyModified {
name,
file,
complexity_delta: func_delta,
} = change
{
if *func_delta > self.config.max_complexity_increase {
violations.push(Violation {
rule: "function-complexity".to_string(),
severity: if self.config.complexity_error {
ValidationSeverity::Error
} else {
ValidationSeverity::Warning
},
message: format!(
"Function '{}' complexity increased by {}",
name, func_delta
),
location: Some(file.clone()),
suggestion: Some(
"Extract helper functions or simplify control flow".to_string(),
),
});
}
}
}
violations
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
use smelt_core::{ImpactSummary, SemanticChange};
use uuid::Uuid;
fn make_delta_with_complexity(complexity_delta: i32) -> SemanticDelta {
SemanticDelta {
id: Uuid::new_v4(),
intent_id: Uuid::new_v4(),
timestamp: Utc::now(),
from_snapshot: Uuid::new_v4(),
to_snapshot: Uuid::new_v4(),
changes: Vec::new(),
impact_summary: ImpactSummary {
complexity_delta,
..Default::default()
},
}
}
#[test]
fn test_complexity_under_threshold() {
let checker = ComplexityChecker::new(ComplexityConfig::default());
let delta = make_delta_with_complexity(5);
let violations = checker.validate(&delta, None);
assert!(violations.is_empty());
}
#[test]
fn test_complexity_over_threshold() {
let checker = ComplexityChecker::new(ComplexityConfig::default());
let delta = make_delta_with_complexity(15);
let violations = checker.validate(&delta, None);
assert_eq!(violations.len(), 1);
assert_eq!(violations[0].rule, "complexity-increase");
}
#[test]
fn test_function_complexity_change() {
let checker = ComplexityChecker::new(ComplexityConfig::default());
let delta = SemanticDelta {
id: Uuid::new_v4(),
intent_id: Uuid::new_v4(),
timestamp: Utc::now(),
from_snapshot: Uuid::new_v4(),
to_snapshot: Uuid::new_v4(),
changes: vec![SemanticChange::BodyModified {
name: "complex_function".to_string(),
file: "lib.rs".to_string(),
complexity_delta: 15,
}],
impact_summary: ImpactSummary::default(),
};
let violations = checker.validate(&delta, None);
assert_eq!(violations.len(), 1);
assert_eq!(violations[0].rule, "function-complexity");
}
}