use debtmap::analyzers::{rust::RustAnalyzer, Analyzer};
use debtmap::complexity::entropy::EntropyAnalyzer;
use std::path::PathBuf;
use syn::{parse_str, Block};
#[test]
fn test_entropy_reduces_pattern_complexity() {
let analyzer = RustAnalyzer::new();
let validation_code = r#"
fn validate_input(value: i32) -> Result<(), String> {
if value < 0 {
return Err("Value must be non-negative".to_string());
}
if value > 100 {
return Err("Value must be <= 100".to_string());
}
if value % 2 != 0 {
return Err("Value must be even".to_string());
}
if value % 5 != 0 {
return Err("Value must be divisible by 5".to_string());
}
Ok(())
}
"#;
let ast = analyzer
.parse(validation_code, PathBuf::from("test.rs"))
.unwrap();
let metrics = analyzer.analyze(&ast);
assert_eq!(metrics.complexity.functions.len(), 1);
let func = &metrics.complexity.functions[0];
assert!(func.cyclomatic >= 5);
}
#[test]
fn test_entropy_preserves_complex_logic() {
let analyzer = RustAnalyzer::new();
let complex_code = r#"
fn calculate_discount(customer_type: &str, purchase_amount: f64, loyalty_years: u32) -> f64 {
let base_discount = match customer_type {
"premium" => 0.15,
"regular" => 0.05,
_ => 0.0,
};
let loyalty_bonus = if loyalty_years > 5 {
0.10
} else if loyalty_years > 2 {
0.05
} else {
0.0
};
let volume_discount = if purchase_amount > 1000.0 {
0.08
} else if purchase_amount > 500.0 {
0.04
} else {
0.0
};
let total_discount = base_discount + loyalty_bonus + volume_discount;
total_discount.min(0.25)
}
"#;
let ast = analyzer
.parse(complex_code, PathBuf::from("test.rs"))
.unwrap();
let metrics = analyzer.analyze(&ast);
assert_eq!(metrics.complexity.functions.len(), 1);
let func = &metrics.complexity.functions[0];
assert!(func.cyclomatic >= 1); assert!(func.cognitive >= 1); }
#[test]
fn test_entropy_for_switch_like_patterns() {
let analyzer = RustAnalyzer::new();
let switch_code = r#"
fn process_command(cmd: &str) -> String {
match cmd {
"start" => execute_start(),
"stop" => execute_stop(),
"pause" => execute_pause(),
"resume" => execute_resume(),
"restart" => execute_restart(),
"status" => execute_status(),
_ => execute_unknown(),
}
}
fn execute_start() -> String { "Starting...".to_string() }
fn execute_stop() -> String { "Stopping...".to_string() }
fn execute_pause() -> String { "Pausing...".to_string() }
fn execute_resume() -> String { "Resuming...".to_string() }
fn execute_restart() -> String { "Restarting...".to_string() }
fn execute_status() -> String { "Status: OK".to_string() }
fn execute_unknown() -> String { "Unknown command".to_string() }
"#;
let ast = analyzer
.parse(switch_code, PathBuf::from("test.rs"))
.unwrap();
let metrics = analyzer.analyze(&ast);
let process_fn = metrics
.complexity
.functions
.iter()
.find(|f| f.name == "process_command")
.expect("process_command function not found");
assert_eq!(process_fn.cyclomatic, 7);
}
#[test]
fn test_entropy_analyzer_directly() {
use syn::parse_quote;
let mut analyzer = EntropyAnalyzer::new();
let repetitive_block: syn::Block = parse_quote! {{
if x > 0 { return Err("error"); }
if y > 0 { return Err("error"); }
if z > 0 { return Err("error"); }
}};
let entropy_score = analyzer.calculate_entropy(&repetitive_block);
assert!(entropy_score.pattern_repetition > 0.5);
assert!(entropy_score.effective_complexity < 1.0);
let complex_block: syn::Block = parse_quote! {{
let result = x * 2 + y;
if result > threshold {
process_high_value(result);
} else {
handle_low_value(result / 2);
}
update_cache(result);
}};
let complex_score = analyzer.calculate_entropy(&complex_block);
assert!(
complex_score.pattern_repetition < 0.6,
"Expected pattern_repetition < 0.6, got {}",
complex_score.pattern_repetition
);
assert!(complex_score.effective_complexity > 0.5); }
#[test]
fn test_get_cache_stats_empty_cache() {
let analyzer = EntropyAnalyzer::new();
let stats = analyzer.get_cache_stats();
assert_eq!(stats.entries, 0);
assert_eq!(stats.memory_usage, 0);
assert_eq!(stats.hit_rate, 0.0);
assert_eq!(stats.miss_rate, 0.0);
assert_eq!(stats.evictions, 0);
}
#[test]
fn test_get_cache_stats_with_hits_and_misses() {
let mut analyzer = EntropyAnalyzer::new();
let block_str = "{ let x = 1; let y = 2; x + y }";
let block: Block = parse_str(block_str).unwrap();
let _score1 = analyzer.calculate_entropy_cached(&block, "test_hash_1");
let stats = analyzer.get_cache_stats();
assert_eq!(stats.entries, 1);
assert_eq!(stats.hit_rate, 0.0); assert_eq!(stats.miss_rate, 1.0); assert_eq!(stats.evictions, 0);
let _score2 = analyzer.calculate_entropy_cached(&block, "test_hash_1");
let stats = analyzer.get_cache_stats();
assert_eq!(stats.entries, 1);
assert_eq!(stats.hit_rate, 0.5); assert_eq!(stats.miss_rate, 0.5); assert_eq!(stats.evictions, 0);
let _score3 = analyzer.calculate_entropy_cached(&block, "test_hash_2");
let stats = analyzer.get_cache_stats();
assert_eq!(stats.entries, 2);
assert!((stats.hit_rate - 0.333).abs() < 0.01); assert!((stats.miss_rate - 0.667).abs() < 0.01); assert_eq!(stats.evictions, 0);
}
#[test]
fn test_get_cache_stats_memory_estimation() {
let mut analyzer = EntropyAnalyzer::with_cache_size(10);
let block_str = "{ let x = 1; }";
let block: Block = parse_str(block_str).unwrap();
for i in 0..5 {
let hash = format!("test_hash_{}", i);
let _score = analyzer.calculate_entropy_cached(&block, &hash);
}
let stats = analyzer.get_cache_stats();
assert_eq!(stats.entries, 5);
assert_eq!(stats.memory_usage, 5 * 128);
}
#[test]
fn test_get_cache_stats_after_evictions() {
let mut analyzer = EntropyAnalyzer::with_cache_size(2);
let block_str = "{ let x = 1; }";
let block: Block = parse_str(block_str).unwrap();
for i in 0..3 {
let hash = format!("test_hash_{}", i);
let _score = analyzer.calculate_entropy_cached(&block, &hash);
}
let stats = analyzer.get_cache_stats();
assert_eq!(stats.entries, 2); assert_eq!(stats.evictions, 1); assert_eq!(stats.miss_rate, 1.0); assert_eq!(stats.hit_rate, 0.0);
}
#[test]
fn test_get_cache_stats_after_clear() {
let mut analyzer = EntropyAnalyzer::new();
let block_str = "{ let x = 1; }";
let block: Block = parse_str(block_str).unwrap();
let _score1 = analyzer.calculate_entropy_cached(&block, "test_hash_1");
let _score2 = analyzer.calculate_entropy_cached(&block, "test_hash_1"); let _score3 = analyzer.calculate_entropy_cached(&block, "test_hash_2");
analyzer.clear_cache();
let stats = analyzer.get_cache_stats();
assert_eq!(stats.entries, 0);
assert_eq!(stats.memory_usage, 0);
assert_eq!(stats.hit_rate, 0.0);
assert_eq!(stats.miss_rate, 0.0);
assert_eq!(stats.evictions, 0);
}
#[test]
fn test_get_cache_stats_high_hit_rate() {
let mut analyzer = EntropyAnalyzer::new();
let block_str = "{ let x = 1; }";
let block: Block = parse_str(block_str).unwrap();
let _score = analyzer.calculate_entropy_cached(&block, "test_hash");
for _ in 0..9 {
let _score = analyzer.calculate_entropy_cached(&block, "test_hash");
}
let stats = analyzer.get_cache_stats();
assert_eq!(stats.entries, 1);
assert_eq!(stats.hit_rate, 0.9); assert_eq!(stats.miss_rate, 0.1); }