#![cfg_attr(coverage_nightly, coverage(off))]
use super::handler::handle_analyze_defects;
use super::output::print_text_report;
use super::types::*;
use crate::services::defect_detector::Severity;
use tempfile::TempDir;
#[tokio::test]
async fn test_handle_analyze_defects_empty_dir() {
let temp_dir = TempDir::new().expect("temp dir");
let result =
handle_analyze_defects(Some(temp_dir.path()), None, None, OutputFormat::Text).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0); }
#[tokio::test]
async fn test_handle_analyze_defects_no_defects() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(
src_dir.join("main.rs"),
r#"
fn main() {
let x = Some(42);
if let Some(val) = x {
println!("Value: {}", val);
}
}
"#,
)
.expect("write");
let result =
handle_analyze_defects(Some(temp_dir.path()), None, None, OutputFormat::Json).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0);
}
#[tokio::test]
async fn test_handle_analyze_defects_with_critical_defects() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(
src_dir.join("main.rs"),
r#"
fn main() {
let x = Some(42).unwrap();
println!("Value: {}", x);
}
"#,
)
.expect("write");
let result =
handle_analyze_defects(Some(temp_dir.path()), None, None, OutputFormat::Text).await;
assert!(result.is_ok());
assert!(result.unwrap() >= 0);
}
#[tokio::test]
async fn test_handle_analyze_defects_specific_file() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(src_dir.join("clean.rs"), "fn clean() { let x = Some(42); }").expect("write");
std::fs::write(
src_dir.join("dirty.rs"),
"fn dirty() { let x = Some(42).unwrap(); }",
)
.expect("write");
let clean_file = src_dir.join("clean.rs");
let result = handle_analyze_defects(
Some(temp_dir.path()),
Some(clean_file.as_path()),
None,
OutputFormat::Json,
)
.await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0); }
#[tokio::test]
async fn test_handle_analyze_defects_severity_filter() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(
src_dir.join("main.rs"),
"fn main() { let x = Some(42).unwrap(); }",
)
.expect("write");
let result = handle_analyze_defects(
Some(temp_dir.path()),
None,
Some(Severity::High),
OutputFormat::Text,
)
.await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0);
}
#[tokio::test]
async fn test_handle_analyze_defects_default_path() {
let result = handle_analyze_defects(None, None, None, OutputFormat::Junit).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_analyze_defects_json_format() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(src_dir.join("main.rs"), "fn main() {}").expect("write");
let result =
handle_analyze_defects(Some(temp_dir.path()), None, None, OutputFormat::Json).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_analyze_defects_junit_format() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(src_dir.join("main.rs"), "fn main() {}").expect("write");
let result =
handle_analyze_defects(Some(temp_dir.path()), None, None, OutputFormat::Junit).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_analyze_defects_unreadable_file() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(src_dir.join("main.rs"), "fn main() {}").expect("write");
let result =
handle_analyze_defects(Some(temp_dir.path()), None, None, OutputFormat::Text).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_analyze_defects_filter_critical() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(
src_dir.join("main.rs"),
"fn main() { let x = Some(42).unwrap(); }",
)
.expect("write");
let result = handle_analyze_defects(
Some(temp_dir.path()),
None,
Some(Severity::Critical),
OutputFormat::Json,
)
.await;
assert!(result.is_ok());
assert!(result.unwrap() >= 0);
}
#[tokio::test]
async fn test_handle_analyze_defects_nested_directories() {
let temp_dir = TempDir::new().expect("temp dir");
let deep_dir = temp_dir.path().join("src").join("nested").join("deep");
std::fs::create_dir_all(&deep_dir).expect("create dir");
std::fs::write(
deep_dir.join("module.rs"),
"fn deep() { let x = Some(1).unwrap(); }",
)
.expect("write");
let result =
handle_analyze_defects(Some(temp_dir.path()), None, None, OutputFormat::Text).await;
assert!(result.is_ok());
assert!(result.unwrap() >= 0);
}
#[tokio::test]
async fn test_handle_analyze_defects_multiple_files_with_defects() {
let temp_dir = TempDir::new().expect("temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("create dir");
std::fs::write(src_dir.join("file1.rs"), "fn f1() { Some(1).unwrap(); }").expect("write");
std::fs::write(
src_dir.join("file2.rs"),
"fn f2() { Some(2).unwrap(); Some(3).unwrap(); }",
)
.expect("write");
std::fs::write(src_dir.join("file3.rs"), "fn f3() { let x = 1; }").expect("write");
let result =
handle_analyze_defects(Some(temp_dir.path()), None, None, OutputFormat::Json).await;
assert!(result.is_ok());
assert!(result.unwrap() >= 0);
}
#[test]
fn test_print_text_report_with_high_and_medium() {
use crate::services::defect_detector::{DefectInstance, DefectPattern, Severity};
let report = DefectReport {
summary: DefectSummary {
total_files_scanned: 10,
files_with_defects: 2,
total_defects: 2,
by_severity: SeverityCount {
critical: 0,
high: 1,
medium: 1,
low: 0,
},
},
defects: vec![
DefectPattern {
id: "HIGH-001".to_string(),
name: "High Issue".to_string(),
severity: Severity::High,
fix_recommendation: "Fix soon".to_string(),
bad_example: "bad()".to_string(),
good_example: "good()".to_string(),
evidence_description: "High evidence".to_string(),
evidence_url: None,
instances: vec![DefectInstance {
file: "src/lib.rs".to_string(),
line: 10,
column: 1,
code_snippet: "bad()".to_string(),
}],
},
DefectPattern {
id: "MED-001".to_string(),
name: "Medium Issue".to_string(),
severity: Severity::Medium,
fix_recommendation: "Fix when possible".to_string(),
bad_example: "meh()".to_string(),
good_example: "better()".to_string(),
evidence_description: "Medium evidence".to_string(),
evidence_url: None,
instances: vec![DefectInstance {
file: "src/util.rs".to_string(),
line: 20,
column: 5,
code_snippet: "meh()".to_string(),
}],
},
],
exit_code: 0,
has_critical_defects: false,
};
print_text_report(&report);
}
#[test]
fn test_print_text_report_many_instances() {
use crate::services::defect_detector::{DefectInstance, DefectPattern, Severity};
let instances: Vec<DefectInstance> = (0..15)
.map(|i| DefectInstance {
file: format!("src/file{}.rs", i),
line: i + 1,
column: 1,
code_snippet: "bad()".to_string(),
})
.collect();
let report = DefectReport {
summary: DefectSummary {
total_files_scanned: 15,
files_with_defects: 15,
total_defects: 15,
by_severity: SeverityCount {
critical: 15,
high: 0,
medium: 0,
low: 0,
},
},
defects: vec![DefectPattern {
id: "CRIT-001".to_string(),
name: "Many instances".to_string(),
severity: Severity::Critical,
fix_recommendation: "Fix all".to_string(),
bad_example: "bad()".to_string(),
good_example: "good()".to_string(),
evidence_description: "Evidence".to_string(),
evidence_url: None,
instances,
}],
exit_code: 1,
has_critical_defects: true,
};
print_text_report(&report);
}
#[test]
fn test_print_text_report_all_severity_levels() {
use crate::services::defect_detector::{DefectInstance, DefectPattern, Severity};
let report = DefectReport {
summary: DefectSummary {
total_files_scanned: 4,
files_with_defects: 4,
total_defects: 4,
by_severity: SeverityCount {
critical: 1,
high: 1,
medium: 1,
low: 1,
},
},
defects: vec![
DefectPattern {
id: "CRIT-001".to_string(),
name: "Critical".to_string(),
severity: Severity::Critical,
fix_recommendation: "Fix".to_string(),
bad_example: "bad".to_string(),
good_example: "good".to_string(),
evidence_description: "Evidence".to_string(),
evidence_url: None,
instances: vec![DefectInstance {
file: "c.rs".to_string(),
line: 1,
column: 1,
code_snippet: "bad".to_string(),
}],
},
DefectPattern {
id: "HIGH-001".to_string(),
name: "High".to_string(),
severity: Severity::High,
fix_recommendation: "Fix".to_string(),
bad_example: "bad".to_string(),
good_example: "good".to_string(),
evidence_description: "Evidence".to_string(),
evidence_url: None,
instances: vec![DefectInstance {
file: "h.rs".to_string(),
line: 1,
column: 1,
code_snippet: "bad".to_string(),
}],
},
DefectPattern {
id: "MED-001".to_string(),
name: "Medium".to_string(),
severity: Severity::Medium,
fix_recommendation: "Fix".to_string(),
bad_example: "bad".to_string(),
good_example: "good".to_string(),
evidence_description: "Evidence".to_string(),
evidence_url: None,
instances: vec![DefectInstance {
file: "m.rs".to_string(),
line: 1,
column: 1,
code_snippet: "bad".to_string(),
}],
},
DefectPattern {
id: "LOW-001".to_string(),
name: "Low".to_string(),
severity: Severity::Low,
fix_recommendation: "Fix".to_string(),
bad_example: "bad".to_string(),
good_example: "good".to_string(),
evidence_description: "Evidence".to_string(),
evidence_url: None,
instances: vec![DefectInstance {
file: "l.rs".to_string(),
line: 1,
column: 1,
code_snippet: "bad".to_string(),
}],
},
],
exit_code: 1,
has_critical_defects: true,
};
print_text_report(&report);
}