#![cfg_attr(coverage_nightly, coverage(off))]
use super::*;
use std::path::Path;
#[test]
fn test_complexity_metrics_new() {
let metrics = ComplexityMetrics::new(5, 8, 3, 42);
assert_eq!(metrics.cyclomatic, 5);
assert_eq!(metrics.cognitive, 8);
assert_eq!(metrics.nesting_max, 3);
assert_eq!(metrics.lines, 42);
assert!(metrics.halstead.is_none());
}
#[test]
fn test_complexity_metrics_with_halstead() {
let halstead = HalsteadMetrics::new(10, 5, 20, 8);
let metrics = ComplexityMetrics::with_halstead(5, 8, 3, 42, halstead);
assert_eq!(metrics.cyclomatic, 5);
assert_eq!(metrics.cognitive, 8);
assert!(metrics.halstead.is_some());
assert_eq!(metrics.halstead.unwrap().operators_unique, 10);
}
#[test]
fn test_complexity_metrics_is_simple_true() {
let simple = ComplexityMetrics::new(2, 3, 1, 10);
assert!(simple.is_simple());
}
#[test]
fn test_complexity_metrics_is_simple_false_cyclomatic() {
let complex = ComplexityMetrics::new(6, 3, 1, 10);
assert!(!complex.is_simple());
}
#[test]
fn test_complexity_metrics_is_simple_false_cognitive() {
let complex = ComplexityMetrics::new(3, 8, 1, 10);
assert!(!complex.is_simple());
}
#[test]
fn test_complexity_metrics_is_simple_boundary() {
let boundary = ComplexityMetrics::new(5, 7, 2, 20);
assert!(boundary.is_simple());
}
#[test]
fn test_complexity_metrics_needs_refactoring_false() {
let simple = ComplexityMetrics::new(3, 4, 2, 15);
assert!(!simple.needs_refactoring());
}
#[test]
fn test_complexity_metrics_needs_refactoring_cyclomatic() {
let complex = ComplexityMetrics::new(15, 4, 2, 15);
assert!(complex.needs_refactoring());
}
#[test]
fn test_complexity_metrics_needs_refactoring_cognitive() {
let complex = ComplexityMetrics::new(5, 20, 2, 15);
assert!(complex.needs_refactoring());
}
#[test]
fn test_complexity_metrics_needs_refactoring_boundary() {
let boundary = ComplexityMetrics::new(10, 15, 3, 30);
assert!(!boundary.needs_refactoring());
}
#[test]
fn test_complexity_metrics_complexity_score() {
let simple = ComplexityMetrics::new(1, 1, 1, 5);
let complex = ComplexityMetrics::new(10, 15, 4, 80);
assert!(complex.complexity_score() > simple.complexity_score());
}
#[test]
fn test_complexity_metrics_complexity_score_calculation() {
let metrics = ComplexityMetrics::new(10, 20, 3, 100);
let expected = 50.0;
assert!((metrics.complexity_score() - expected).abs() < 0.001);
}
#[test]
fn test_complexity_metrics_default() {
let default = ComplexityMetrics::default();
assert_eq!(default.cyclomatic, 0);
assert_eq!(default.cognitive, 0);
assert_eq!(default.nesting_max, 0);
assert_eq!(default.lines, 0);
assert!(default.halstead.is_none());
}
#[test]
fn test_halstead_metrics_new() {
let metrics = HalsteadMetrics::new(8, 6, 20, 15);
assert_eq!(metrics.operators_unique, 8);
assert_eq!(metrics.operands_unique, 6);
assert_eq!(metrics.operators_total, 20);
assert_eq!(metrics.operands_total, 15);
assert_eq!(metrics.volume, 0.0);
assert_eq!(metrics.difficulty, 0.0);
}
#[test]
fn test_halstead_metrics_calculate_derived() {
let base = HalsteadMetrics::new(10, 8, 25, 20);
let calculated = base.calculate_derived();
assert!(calculated.volume > 0.0);
assert!(calculated.difficulty > 0.0);
assert!(calculated.effort > 0.0);
assert!(calculated.time > 0.0);
assert!(calculated.bugs >= 0.0);
}
#[test]
fn test_halstead_metrics_calculate_derived_zero_operators() {
let base = HalsteadMetrics::new(0, 5, 10, 8);
let calculated = base.calculate_derived();
assert_eq!(calculated.volume, 0.0);
assert_eq!(calculated.difficulty, 0.0);
}
#[test]
fn test_halstead_metrics_calculate_derived_zero_operands() {
let base = HalsteadMetrics::new(5, 0, 10, 8);
let calculated = base.calculate_derived();
assert_eq!(calculated.volume, 0.0);
}
#[test]
fn test_halstead_metrics_default() {
let default = HalsteadMetrics::default();
assert_eq!(default.operators_unique, 0);
assert_eq!(default.operands_unique, 0);
assert_eq!(default.volume, 0.0);
}
#[test]
fn test_complexity_thresholds_default() {
let thresholds = ComplexityThresholds::default();
assert_eq!(thresholds.cyclomatic_warn, 10);
assert_eq!(thresholds.cyclomatic_error, 20);
assert_eq!(thresholds.cognitive_warn, 15);
assert_eq!(thresholds.cognitive_error, 30);
assert_eq!(thresholds.nesting_max, 5);
assert_eq!(thresholds.method_length, 50);
}
#[test]
fn test_complexity_visitor_new() {
let mut metrics = ComplexityMetrics::default();
let visitor = ComplexityVisitor::new(&mut metrics);
assert_eq!(visitor.nesting_level, 0);
assert!(visitor.current_function.is_none());
assert!(visitor.functions.is_empty());
assert!(visitor.classes.is_empty());
}
#[test]
fn test_complexity_visitor_calculate_cognitive_increment_nesting() {
let mut metrics = ComplexityMetrics::default();
let mut visitor = ComplexityVisitor::new(&mut metrics);
assert_eq!(visitor.calculate_cognitive_increment(true), 1);
visitor.nesting_level = 1;
assert_eq!(visitor.calculate_cognitive_increment(true), 1);
visitor.nesting_level = 2;
assert_eq!(visitor.calculate_cognitive_increment(true), 2);
visitor.nesting_level = 3;
assert_eq!(visitor.calculate_cognitive_increment(true), 3);
}
#[test]
fn test_complexity_visitor_calculate_cognitive_increment_non_nesting() {
let mut metrics = ComplexityMetrics::default();
let mut visitor = ComplexityVisitor::new(&mut metrics);
visitor.nesting_level = 0;
assert_eq!(visitor.calculate_cognitive_increment(false), 1);
visitor.nesting_level = 5;
assert_eq!(visitor.calculate_cognitive_increment(false), 1);
}
#[test]
fn test_complexity_visitor_enter_exit_nesting() {
let mut metrics = ComplexityMetrics::default();
let mut visitor = ComplexityVisitor::new(&mut metrics);
assert_eq!(visitor.nesting_level, 0);
assert_eq!(visitor.complexity.nesting_max, 0);
visitor.enter_nesting();
assert_eq!(visitor.nesting_level, 1);
assert_eq!(visitor.complexity.nesting_max, 1);
visitor.enter_nesting();
assert_eq!(visitor.nesting_level, 2);
assert_eq!(visitor.complexity.nesting_max, 2);
visitor.exit_nesting();
assert_eq!(visitor.nesting_level, 1);
assert_eq!(visitor.complexity.nesting_max, 2);
visitor.exit_nesting();
assert_eq!(visitor.nesting_level, 0);
}
#[test]
fn test_complexity_visitor_exit_nesting_saturating() {
let mut metrics = ComplexityMetrics::default();
let mut visitor = ComplexityVisitor::new(&mut metrics);
visitor.exit_nesting();
assert_eq!(visitor.nesting_level, 0);
}
#[test]
fn test_complexity_visitor_enter_nesting_saturating() {
let mut metrics = ComplexityMetrics::default();
let mut visitor = ComplexityVisitor::new(&mut metrics);
visitor.nesting_level = u8::MAX;
visitor.enter_nesting();
assert_eq!(visitor.nesting_level, u8::MAX); }
#[test]
fn test_compute_complexity_cache_key() {
let path = Path::new("src/main.rs");
let content = b"fn main() { println!(\"Hello\"); }";
let key = compute_complexity_cache_key(path, content);
assert!(key.starts_with("cx:"));
assert!(key.len() > 3);
}
#[test]
fn test_compute_complexity_cache_key_different_content() {
let path = Path::new("src/main.rs");
let content1 = b"fn main() {}";
let content2 = b"fn main() { todo!(); }";
let key1 = compute_complexity_cache_key(path, content1);
let key2 = compute_complexity_cache_key(path, content2);
assert_ne!(key1, key2);
}
#[test]
fn test_compute_complexity_cache_key_different_path() {
let path1 = Path::new("src/main.rs");
let path2 = Path::new("src/lib.rs");
let content = b"fn test() {}";
let key1 = compute_complexity_cache_key(path1, content);
let key2 = compute_complexity_cache_key(path2, content);
assert_ne!(key1, key2);
}
#[test]
fn test_cyclomatic_complexity_rule_new() {
let thresholds = ComplexityThresholds::default();
let rule = CyclomaticComplexityRule::new(&thresholds);
assert_eq!(rule.warn_threshold, 10);
assert_eq!(rule.error_threshold, 20);
}
#[test]
fn test_cyclomatic_complexity_rule_evaluate_ok() {
let thresholds = ComplexityThresholds::default();
let rule = CyclomaticComplexityRule::new(&thresholds);
let metrics = ComplexityMetrics::new(5, 5, 2, 20);
let violation = rule.evaluate(&metrics, "test.rs", 1, Some("test_fn"));
assert!(violation.is_none());
}
#[test]
fn test_cyclomatic_complexity_rule_evaluate_warning() {
let thresholds = ComplexityThresholds::default();
let rule = CyclomaticComplexityRule::new(&thresholds);
let metrics = ComplexityMetrics::new(15, 5, 2, 20);
let violation = rule.evaluate(&metrics, "test.rs", 10, Some("complex_fn"));
assert!(violation.is_some());
if let Some(Violation::Warning {
rule: r,
value,
threshold,
..
}) = violation
{
assert_eq!(r, "cyclomatic-complexity");
assert_eq!(value, 15);
assert_eq!(threshold, 10);
} else {
panic!("Expected Warning violation");
}
}
#[test]
fn test_cyclomatic_complexity_rule_evaluate_error() {
let thresholds = ComplexityThresholds::default();
let rule = CyclomaticComplexityRule::new(&thresholds);
let metrics = ComplexityMetrics::new(25, 5, 2, 20);
let violation = rule.evaluate(&metrics, "test.rs", 10, None);
assert!(violation.is_some());
if let Some(Violation::Error {
rule: r,
value,
threshold,
function,
..
}) = violation
{
assert_eq!(r, "cyclomatic-complexity");
assert_eq!(value, 25);
assert_eq!(threshold, 20);
assert!(function.is_none());
} else {
panic!("Expected Error violation");
}
}
#[test]
fn test_cognitive_complexity_rule_new() {
let thresholds = ComplexityThresholds::default();
let rule = CognitiveComplexityRule::new(&thresholds);
assert_eq!(rule.warn_threshold, 15);
assert_eq!(rule.error_threshold, 30);
}
#[test]
fn test_cognitive_complexity_rule_evaluate_ok() {
let thresholds = ComplexityThresholds::default();
let rule = CognitiveComplexityRule::new(&thresholds);
let metrics = ComplexityMetrics::new(5, 10, 2, 20);
let violation = rule.evaluate(&metrics, "test.rs", 1, Some("simple_fn"));
assert!(violation.is_none());
}
#[test]
fn test_cognitive_complexity_rule_evaluate_warning() {
let thresholds = ComplexityThresholds::default();
let rule = CognitiveComplexityRule::new(&thresholds);
let metrics = ComplexityMetrics::new(5, 20, 2, 20);
let violation = rule.evaluate(&metrics, "test.rs", 10, Some("complex_fn"));
assert!(violation.is_some());
if let Some(Violation::Warning {
rule: r,
value,
threshold,
..
}) = violation
{
assert_eq!(r, "cognitive-complexity");
assert_eq!(value, 20);
assert_eq!(threshold, 15);
} else {
panic!("Expected Warning violation");
}
}
#[test]
fn test_cognitive_complexity_rule_evaluate_error() {
let thresholds = ComplexityThresholds::default();
let rule = CognitiveComplexityRule::new(&thresholds);
let metrics = ComplexityMetrics::new(5, 35, 2, 20);
let violation = rule.evaluate(&metrics, "test.rs", 10, None);
assert!(violation.is_some());
if let Some(Violation::Error {
rule: r,
value,
threshold,
..
}) = violation
{
assert_eq!(r, "cognitive-complexity");
assert_eq!(value, 35);
assert_eq!(threshold, 30);
} else {
panic!("Expected Error violation");
}
}
#[test]
fn test_function_complexity_struct() {
let fc = FunctionComplexity {
name: "test_fn".to_string(),
line_start: 10,
line_end: 25,
metrics: ComplexityMetrics::new(3, 4, 2, 15),
};
assert_eq!(fc.name, "test_fn");
assert_eq!(fc.line_start, 10);
assert_eq!(fc.line_end, 25);
assert_eq!(fc.metrics.cyclomatic, 3);
}
#[test]
fn test_class_complexity_struct() {
let cc = ClassComplexity {
name: "TestClass".to_string(),
line_start: 1,
line_end: 100,
metrics: ComplexityMetrics::new(10, 15, 4, 80),
methods: vec![],
};
assert_eq!(cc.name, "TestClass");
assert!(cc.methods.is_empty());
}
#[test]
fn test_file_complexity_metrics_struct() {
let fcm = FileComplexityMetrics {
path: "src/test.rs".to_string(),
total_complexity: ComplexityMetrics::new(5, 8, 3, 50),
functions: vec![],
classes: vec![],
};
assert_eq!(fcm.path, "src/test.rs");
assert_eq!(fcm.total_complexity.cyclomatic, 5);
}
#[test]
fn test_complexity_hotspot_struct() {
let hotspot = ComplexityHotspot {
file: "src/complex.rs".to_string(),
function: Some("complex_fn".to_string()),
line: 42,
complexity: 25,
complexity_type: "cyclomatic".to_string(),
};
assert_eq!(hotspot.file, "src/complex.rs");
assert_eq!(hotspot.complexity, 25);
}
#[test]
fn test_complexity_summary_default() {
let summary = ComplexitySummary::default();
assert_eq!(summary.total_files, 0);
assert_eq!(summary.total_functions, 0);
assert_eq!(summary.median_cyclomatic, 0.0);
}
#[test]
fn test_complexity_report_struct() {
let report = ComplexityReport {
summary: ComplexitySummary::default(),
violations: vec![],
hotspots: vec![],
files: vec![],
};
assert!(report.violations.is_empty());
assert!(report.hotspots.is_empty());
}
#[test]
fn test_format_as_sarif_empty_report() {
let report = ComplexityReport {
summary: ComplexitySummary::default(),
violations: vec![],
hotspots: vec![],
files: vec![],
};
let sarif = format_as_sarif(&report).unwrap();
assert!(sarif.contains("\"version\": \"2.1.0\""));
assert!(sarif.contains("pmat"));
}
#[test]
fn test_format_as_sarif_with_warning() {
let report = ComplexityReport {
summary: ComplexitySummary::default(),
violations: vec![Violation::Warning {
rule: "cyclomatic-complexity".to_string(),
message: "Too complex".to_string(),
value: 15,
threshold: 10,
file: "test.rs".to_string(),
line: 42,
function: Some("complex_fn".to_string()),
}],
hotspots: vec![],
files: vec![],
};
let sarif = format_as_sarif(&report).unwrap();
assert!(sarif.contains("cyclomatic-complexity"));
assert!(sarif.contains("warning"));
assert!(sarif.contains("test.rs"));
}
#[test]
fn test_format_as_sarif_with_error() {
let report = ComplexityReport {
summary: ComplexitySummary::default(),
violations: vec![Violation::Error {
rule: "cognitive-complexity".to_string(),
message: "Very complex".to_string(),
value: 35,
threshold: 30,
file: "complex.rs".to_string(),
line: 100,
function: None,
}],
hotspots: vec![],
files: vec![],
};
let sarif = format_as_sarif(&report).unwrap();
assert!(sarif.contains("cognitive-complexity"));
assert!(sarif.contains("error"));
assert!(sarif.contains("complex.rs"));
}