use debtmap::organization::boilerplate_detector::{
BoilerplateDetectionConfig, BoilerplateDetector,
};
use std::path::Path;
use std::time::Instant;
#[test]
fn test_boilerplate_detection_overhead() {
let test_code = generate_test_code_with_traits(25);
let syntax = syn::parse_file(&test_code).expect("Failed to parse test code");
println!("Running performance test on code with trait implementations");
let config_disabled = BoilerplateDetectionConfig {
enabled: false,
min_impl_blocks: 1000, ..Default::default()
};
let detector_disabled = BoilerplateDetector::from_config(&config_disabled);
let start_baseline = Instant::now();
for _ in 0..100 {
let _ = detector_disabled.detect(Path::new("test.rs"), &syntax);
}
let baseline_duration = start_baseline.elapsed();
let config_enabled = BoilerplateDetectionConfig::default();
let detector_enabled = BoilerplateDetector::from_config(&config_enabled);
let start_full = Instant::now();
for _ in 0..100 {
let _ = detector_enabled.detect(Path::new("test.rs"), &syntax);
}
let full_duration = start_full.elapsed();
let baseline_ms = baseline_duration.as_millis() as f64;
let full_ms = full_duration.as_millis() as f64;
let overhead_ms = full_ms - baseline_ms;
let overhead_percent = if baseline_ms > 0.0 {
(overhead_ms / baseline_ms) * 100.0
} else {
0.0
};
println!("\nPerformance Results:");
println!(" Baseline (disabled): {:.2}ms", baseline_ms);
println!(" Full (enabled): {:.2}ms", full_ms);
println!(
" Overhead: {:.2}ms ({:.2}%)",
overhead_ms, overhead_percent
);
if baseline_ms > 10.0 {
assert!(
overhead_percent < 10.0,
"Boilerplate detection overhead should be < 10%, but was {:.2}%",
overhead_percent
);
} else {
println!("Baseline too fast for accurate overhead measurement, skipping overhead check");
}
}
fn generate_test_code_with_traits(num_impls: usize) -> String {
let mut code = String::new();
code.push_str("pub struct Target { value: i32 }\n\n");
for i in 0..num_impls {
code.push_str(&format!(
"pub trait Trait{} {{ fn method_{}(&self) -> i32; }}\n",
i, i
));
code.push_str(&format!(
"impl Trait{} for Target {{ fn method_{}(&self) -> i32 {{ self.value + {} }} }}\n\n",
i, i, i
));
}
code
}
#[test]
fn test_boilerplate_detection_scalability() {
let test_sizes = vec![5, 10, 20, 30];
for size in test_sizes {
let test_code = generate_test_code_with_traits(size);
let syntax = syn::parse_file(&test_code).expect("Failed to parse test code");
let config = BoilerplateDetectionConfig::default();
let detector = BoilerplateDetector::from_config(&config);
let start = Instant::now();
for _ in 0..10 {
let _ = detector.detect(Path::new("test.rs"), &syntax);
}
let duration = start.elapsed();
let time_per_analysis = duration.as_micros() as f64 / 10.0;
println!(
"Size {}: analyzed 10 times in {:.2}ms ({:.2}µs/analysis)",
size,
duration.as_millis(),
time_per_analysis
);
assert!(
time_per_analysis < 10000.0,
"Analysis time should be < 10ms, but was {:.2}µs for size {}",
time_per_analysis,
size
);
}
}
#[test]
fn test_boilerplate_detection_consistency() {
let test_code = generate_test_code_with_traits(20);
let syntax = syn::parse_file(&test_code).expect("Failed to parse test code");
let config = BoilerplateDetectionConfig::default();
let detector = BoilerplateDetector::from_config(&config);
let result1 = detector.detect(Path::new("test.rs"), &syntax);
let result2 = detector.detect(Path::new("test.rs"), &syntax);
assert_eq!(
result1.is_boilerplate, result2.is_boilerplate,
"Detection should be consistent across runs"
);
assert!(
(result1.confidence - result2.confidence).abs() < 0.001,
"Confidence scores should be consistent"
);
println!("\nConsistency Results:");
println!(
" Run 1: is_boilerplate={}, confidence={:.2}%",
result1.is_boilerplate,
result1.confidence * 100.0
);
println!(
" Run 2: is_boilerplate={}, confidence={:.2}%",
result2.is_boilerplate,
result2.confidence * 100.0
);
}