#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod unified_detection_integration_tests {
use super::super::{
duplicates::DuplicateDetector, polyglot::PolyglotDetector, satd::SATDDetector,
DetectionConfig, DetectionInput, DetectionOutput, Detector, UnifiedDetectionProcessor,
};
use std::fs;
use tempfile::TempDir;
type BoxedDetector = Box<
dyn Detector<Input = DetectionInput, Output = DetectionOutput, Config = DetectionConfig>,
>;
#[test]
fn test_all_detectors_creation() {
let _duplicate = DuplicateDetector::new();
let _satd = SATDDetector::new();
let _polyglot = PolyglotDetector::new();
let _processor = UnifiedDetectionProcessor::new();
}
#[test]
fn test_detector_capabilities() {
let detectors: Vec<(&str, BoxedDetector)> = vec![
("duplicates", Box::new(DuplicateDetector::new())),
("satd", Box::new(SATDDetector::new())),
("polyglot", Box::new(PolyglotDetector::new())),
];
for (expected_name, detector) in detectors {
assert_eq!(detector.name(), expected_name, "Detector name should match");
let caps = detector.capabilities();
let _ = caps.supports_batch;
let _ = caps.language_agnostic;
}
}
#[tokio::test]
async fn test_unified_processor_basic_operations() {
let processor = UnifiedDetectionProcessor::new();
let available = processor.available_detectors();
assert!(
available.contains(&"duplicates"),
"Should have duplicates detector"
);
assert!(available.contains(&"satd"), "Should have SATD detector");
assert!(
available.contains(&"polyglot"),
"Should have polyglot detector"
);
assert_eq!(available.len(), 3, "Should have exactly 3 detectors");
}
#[tokio::test]
async fn test_detection_with_real_files() {
let temp_dir = TempDir::new().unwrap();
let file1 = temp_dir.path().join("duplicate1.rs");
let file2 = temp_dir.path().join("duplicate2.rs");
let file3 = temp_dir.path().join("satd_example.rs");
let duplicate_content = r#"
fn calculate_sum(numbers: &[i32]) -> i32 {
let mut total = 0;
for num in numbers {
total += num;
}
total
}
"#;
fs::write(&file1, duplicate_content).unwrap();
fs::write(&file2, duplicate_content).unwrap();
fs::write(
&file3,
r#"
fn todo_function() {
// TODO: Implement this function properly
// FIXME: This is a hack, needs proper solution
unimplemented!()
}
"#,
)
.unwrap();
let processor = UnifiedDetectionProcessor::new();
let files_for_dup = vec![file1, file2];
let dup_result = processor.detect_duplicates(files_for_dup).await;
match dup_result {
Ok(report) => {
println!(
"✅ Duplicate detection completed: {} files analyzed",
report.summary.files_analyzed
);
assert!(
report.summary.files_analyzed > 0,
"Should analyze some files"
);
}
Err(e) => {
println!("⚠️ Duplicate detection failed gracefully: {}", e);
}
}
let satd_result = processor.detect_satd(temp_dir.path()).await;
match satd_result {
Ok(report) => {
println!(
"✅ SATD detection completed: {} files analyzed",
report.total_files_analyzed
);
}
Err(e) => {
println!("⚠️ SATD detection failed gracefully: {}", e);
}
}
let polyglot_result = processor.analyze_polyglot(temp_dir.path()).await;
match polyglot_result {
Ok(analysis) => {
println!(
"✅ Polyglot analysis completed: {} languages found",
analysis.languages.len()
);
assert!(
analysis.recommendation_score >= 0.0 && analysis.recommendation_score <= 1.0,
"Recommendation score should be between 0 and 1"
);
}
Err(e) => {
println!("⚠️ Polyglot analysis failed gracefully: {}", e);
}
}
}
#[tokio::test]
async fn test_error_handling() {
let processor = UnifiedDetectionProcessor::new();
let non_existent = std::path::PathBuf::from("/this/does/not/exist");
let result = processor.detect_satd(&non_existent).await;
match result {
Ok(report) => {
println!(
"Graceful handling of non-existent directory: {} files",
report.total_files_analyzed
);
assert_eq!(
report.total_files_analyzed, 0,
"Should analyze 0 files for non-existent directory"
);
}
Err(e) => {
println!("Graceful error for non-existent directory: {}", e);
assert!(!e.to_string().is_empty(), "Error should have description");
}
}
}
#[tokio::test]
async fn test_detection_consistency() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("consistency_test.rs");
fs::write(
&test_file,
r#"
fn consistent_function() -> i32 {
// TODO: Make this more efficient
let mut sum = 0;
for i in 0..100 {
sum += i;
}
sum
}
"#,
)
.unwrap();
let processor = UnifiedDetectionProcessor::new();
let result1 = processor.detect_satd(temp_dir.path()).await;
let result2 = processor.detect_satd(temp_dir.path()).await;
match (result1, result2) {
(Ok(r1), Ok(r2)) => {
assert_eq!(
r1.total_files_analyzed, r2.total_files_analyzed,
"File count should be consistent"
);
}
(Err(_), Err(_)) => {
}
_ => panic!("Inconsistent results between detection runs"),
}
}
#[test]
fn test_detector_capabilities_properties() {
let duplicate_detector = DuplicateDetector::new();
let satd_detector = SATDDetector::new();
let polyglot_detector = PolyglotDetector::new();
let caps_dup = duplicate_detector.capabilities();
let caps_satd = satd_detector.capabilities();
let caps_poly = polyglot_detector.capabilities();
assert!(
caps_dup.supports_batch,
"Duplicate detector should support batch processing"
);
assert!(
caps_dup.language_agnostic,
"Duplicate detector should be language agnostic"
);
assert!(
caps_satd.supports_streaming,
"SATD detector should support streaming"
);
assert!(
caps_satd.language_agnostic,
"SATD detector should be language agnostic"
);
assert!(
caps_poly.language_agnostic,
"Polyglot detector should be language agnostic"
);
assert!(
caps_poly.requires_ast,
"Polyglot detector should require AST"
);
println!("✅ All detector capabilities verified");
}
#[tokio::test]
async fn test_comprehensive_detection_integration() {
let temp_dir = TempDir::new().unwrap();
let rust_dir = temp_dir.path().join("src");
fs::create_dir_all(&rust_dir).unwrap();
let js_dir = temp_dir.path().join("web");
fs::create_dir_all(&js_dir).unwrap();
fs::write(
rust_dir.join("main.rs"),
r#"
// TODO: Optimize this function
fn duplicate_logic(data: &[i32]) -> i32 {
let mut sum = 0;
for item in data {
sum += item;
}
sum
}
// FIXME: This is duplicated code
fn another_sum(numbers: &[i32]) -> i32 {
let mut sum = 0;
for item in numbers {
sum += item;
}
sum
}
"#,
)
.unwrap();
fs::write(
js_dir.join("app.js"),
r#"
// TODO: Add error handling
function calculateSum(arr) {
let total = 0;
for (let i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
"#,
)
.unwrap();
let processor = UnifiedDetectionProcessor::new();
let mut successful_detections = 0;
let rust_files = vec![rust_dir.join("main.rs")];
if processor.detect_duplicates(rust_files).await.is_ok() {
successful_detections += 1;
println!("✅ Duplicate detection successful");
} else {
println!("⚠️ Duplicate detection failed gracefully");
}
if let Ok(satd_result) = processor.detect_satd(temp_dir.path()).await {
successful_detections += 1;
println!(
"✅ SATD detection successful: {} files",
satd_result.total_files_analyzed
);
} else {
println!("⚠️ SATD detection failed gracefully");
}
if let Ok(poly_result) = processor.analyze_polyglot(temp_dir.path()).await {
successful_detections += 1;
println!(
"✅ Polyglot analysis successful: {} languages",
poly_result.languages.len()
);
} else {
println!("⚠️ Polyglot analysis failed gracefully");
}
assert!(
successful_detections > 0,
"At least one detection should succeed"
);
println!(
"Comprehensive detection test: {}/3 detections successful",
successful_detections
);
}
#[tokio::test]
async fn test_detection_result_properties() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("property_test.rs");
fs::write(
&test_file,
r#"
// Multiple TODO comments for testing
fn function_with_todos() {
// TODO: Item 1
println!("Hello");
// FIXME: Item 2
println!("World");
}
"#,
)
.unwrap();
let processor = UnifiedDetectionProcessor::new();
if let Ok(satd_result) = processor.detect_satd(temp_dir.path()).await {
assert!(
satd_result.files_with_debt <= satd_result.total_files_analyzed,
"Files with debt should not exceed total files analyzed"
);
assert!(
satd_result.items.len() < 1000,
"SATD items should be reasonable in number"
);
println!("✅ SATD result properties verified");
}
if let Ok(poly_result) = processor.analyze_polyglot(temp_dir.path()).await {
assert!(
poly_result.recommendation_score >= 0.0 && poly_result.recommendation_score <= 1.0,
"Recommendation score should be between 0 and 1"
);
assert!(
poly_result.languages.len() < 100,
"Languages list should be reasonable"
);
println!("✅ Polyglot result properties verified");
}
}
}