#![cfg_attr(coverage_nightly, coverage(off))]
use crate::cli::handlers::lint_hotspot_handlers::{
format_summary, EnforcementMetadata, FileSummary, LintHotspot, LintHotspotParams,
LintHotspotResult, QualityGateStatus, QualityViolation, RefactorChain, RefactorStep,
SeverityDistribution, ViolationDetail,
};
use crate::cli::LintHotspotOutputFormat;
use std::collections::HashMap;
use std::path::PathBuf;
use std::time::Duration;
fn create_violation(lint_name: &str, severity: &str, line: u32) -> ViolationDetail {
ViolationDetail {
file: PathBuf::from("src/main.rs"),
line,
column: 1,
end_line: line,
end_column: 50,
lint_name: lint_name.to_string(),
message: format!("violation: {lint_name}"),
severity: severity.to_string(),
suggestion: Some("fix it".to_string()),
machine_applicable: true,
}
}
fn create_test_hotspot(violations: usize, density: f64, sloc: usize) -> LintHotspot {
let detailed_violations: Vec<ViolationDetail> = (0..violations)
.map(|i| create_violation("clippy::test", "warning", i as u32 + 1))
.collect();
LintHotspot {
file: PathBuf::from("src/hotspot.rs"),
defect_density: density,
total_violations: violations,
sloc,
severity_distribution: SeverityDistribution {
error: violations / 4,
warning: violations / 2,
suggestion: violations / 4,
note: 0,
},
top_lints: vec![
("clippy::unwrap_used".to_string(), 5),
("clippy::needless_return".to_string(), 3),
("clippy::redundant_clone".to_string(), 2),
],
detailed_violations,
}
}
fn create_full_result() -> LintHotspotResult {
let mut summary_by_file = HashMap::new();
summary_by_file.insert(
PathBuf::from("src/main.rs"),
FileSummary {
total_violations: 10,
errors: 2,
warnings: 6,
sloc: 200,
defect_density: 0.05,
},
);
summary_by_file.insert(
PathBuf::from("src/lib.rs"),
FileSummary {
total_violations: 5,
errors: 1,
warnings: 3,
sloc: 500,
defect_density: 0.01,
},
);
let all_violations = vec![
create_violation("clippy::unwrap_used", "warning", 10),
create_violation("clippy::expect_used", "warning", 20),
create_violation("clippy::panic", "error", 30),
];
LintHotspotResult {
hotspot: create_test_hotspot(15, 0.075, 200),
all_violations,
summary_by_file,
total_project_violations: 15,
enforcement: None,
refactor_chain: None,
quality_gate: QualityGateStatus {
passed: true,
violations: vec![],
blocking: false,
},
}
}
#[test]
fn test_severity_distribution_with_all_values() {
let dist = SeverityDistribution {
error: 5,
warning: 10,
suggestion: 3,
note: 2,
};
assert_eq!(dist.error, 5);
assert_eq!(dist.warning, 10);
assert_eq!(dist.suggestion, 3);
assert_eq!(dist.note, 2);
}
#[test]
fn test_severity_distribution_serde_roundtrip() {
let dist = SeverityDistribution {
error: 1,
warning: 2,
suggestion: 3,
note: 4,
};
let json = serde_json::to_string(&dist).unwrap();
assert!(json.contains("\"error\":1"));
assert!(json.contains("\"warning\":2"));
let back: SeverityDistribution = serde_json::from_str(&json).unwrap();
assert_eq!(back.error, 1);
assert_eq!(back.warning, 2);
}
#[test]
fn test_severity_distribution_default_values() {
let dist = SeverityDistribution::default();
assert_eq!(dist.error + dist.warning + dist.suggestion + dist.note, 0);
}
#[test]
fn test_violation_detail_full_construction() {
let v = ViolationDetail {
file: PathBuf::from("src/complex.rs"),
line: 100,
column: 15,
end_line: 105,
end_column: 20,
lint_name: "clippy::cognitive_complexity".to_string(),
message: "function has high complexity".to_string(),
severity: "error".to_string(),
suggestion: Some("consider refactoring".to_string()),
machine_applicable: false,
};
assert_eq!(v.line, 100);
assert_eq!(v.end_line, 105);
assert!(!v.machine_applicable);
assert!(v.suggestion.is_some());
}
#[test]
fn test_violation_detail_without_suggestion() {
let v = ViolationDetail {
file: PathBuf::from("test.rs"),
line: 1,
column: 1,
end_line: 1,
end_column: 10,
lint_name: "clippy::test".to_string(),
message: "test message".to_string(),
severity: "warning".to_string(),
suggestion: None,
machine_applicable: true,
};
assert!(v.suggestion.is_none());
assert!(v.machine_applicable);
}
#[test]
fn test_violation_detail_serde_with_suggestion() {
let v = create_violation("clippy::test_lint", "error", 42);
let json = serde_json::to_string(&v).unwrap();
assert!(json.contains("test_lint"));
assert!(json.contains("42"));
let back: ViolationDetail = serde_json::from_str(&json).unwrap();
assert_eq!(back.line, 42);
}
#[test]
fn test_violation_detail_clone_preserves_all_fields() {
let original = ViolationDetail {
file: PathBuf::from("original.rs"),
line: 50,
column: 10,
end_line: 55,
end_column: 25,
lint_name: "clippy::clone_test".to_string(),
message: "clone message".to_string(),
severity: "warning".to_string(),
suggestion: Some("use clone".to_string()),
machine_applicable: true,
};
let cloned = original.clone();
assert_eq!(cloned.file, original.file);
assert_eq!(cloned.line, original.line);
assert_eq!(cloned.lint_name, original.lint_name);
assert_eq!(cloned.suggestion, original.suggestion);
}
#[test]
fn test_file_summary_construction() {
let summary = FileSummary {
total_violations: 25,
errors: 5,
warnings: 15,
sloc: 1000,
defect_density: 0.025,
};
assert_eq!(summary.total_violations, 25);
assert_eq!(summary.errors + summary.warnings, 20);
assert!((summary.defect_density - 0.025).abs() < f64::EPSILON);
}
#[test]
fn test_file_summary_zero_sloc() {
let summary = FileSummary {
total_violations: 0,
errors: 0,
warnings: 0,
sloc: 0,
defect_density: 0.0,
};
assert_eq!(summary.sloc, 0);
assert_eq!(summary.defect_density, 0.0);
}
#[test]
fn test_file_summary_serde() {
let summary = FileSummary {
total_violations: 10,
errors: 2,
warnings: 8,
sloc: 500,
defect_density: 0.02,
};
let json = serde_json::to_string(&summary).unwrap();
assert!(json.contains("total_violations"));
assert!(json.contains("500"));
let back: FileSummary = serde_json::from_str(&json).unwrap();
assert_eq!(back.sloc, 500);
}
#[test]
fn test_lint_hotspot_construction() {
let hotspot = create_test_hotspot(20, 0.1, 200);
assert_eq!(hotspot.total_violations, 20);
assert_eq!(hotspot.sloc, 200);
assert!((hotspot.defect_density - 0.1).abs() < f64::EPSILON);
}
#[test]
fn test_lint_hotspot_empty_violations() {
let hotspot = LintHotspot {
file: PathBuf::from("empty.rs"),
defect_density: 0.0,
total_violations: 0,
sloc: 100,
severity_distribution: SeverityDistribution::default(),
top_lints: vec![],
detailed_violations: vec![],
};
assert!(hotspot.detailed_violations.is_empty());
assert!(hotspot.top_lints.is_empty());
}
#[test]
fn test_lint_hotspot_serde() {
let hotspot = create_test_hotspot(5, 0.05, 100);
let json = serde_json::to_string(&hotspot).unwrap();
assert!(json.contains("hotspot.rs"));
let back: LintHotspot = serde_json::from_str(&json).unwrap();
assert_eq!(back.total_violations, 5);
}
#[test]
fn test_lint_hotspot_top_lints_ordering() {
let hotspot = create_test_hotspot(10, 0.1, 100);
assert_eq!(hotspot.top_lints[0].1, 5); assert_eq!(hotspot.top_lints[1].1, 3); assert_eq!(hotspot.top_lints[2].1, 2); }
#[test]
fn test_enforcement_metadata_construction() {
let meta = EnforcementMetadata {
enforcement_score: 8.5,
requires_enforcement: true,
estimated_fix_time: 3600,
automation_confidence: 0.85,
enforcement_priority: 2,
};
assert!(meta.requires_enforcement);
assert_eq!(meta.enforcement_priority, 2);
assert!((meta.automation_confidence - 0.85).abs() < f64::EPSILON);
}
#[test]
fn test_enforcement_metadata_low_score() {
let meta = EnforcementMetadata {
enforcement_score: 2.0,
requires_enforcement: false,
estimated_fix_time: 600,
automation_confidence: 0.5,
enforcement_priority: 5,
};
assert!(!meta.requires_enforcement);
assert_eq!(meta.enforcement_priority, 5);
}
#[test]
fn test_enforcement_metadata_serde() {
let meta = EnforcementMetadata {
enforcement_score: 7.0,
requires_enforcement: true,
estimated_fix_time: 1800,
automation_confidence: 0.9,
enforcement_priority: 1,
};
let json = serde_json::to_string(&meta).unwrap();
assert!(json.contains("enforcement_score"));
assert!(json.contains("7.0") || json.contains("7"));
let back: EnforcementMetadata = serde_json::from_str(&json).unwrap();
assert!(back.requires_enforcement);
}
#[test]
fn test_refactor_step_construction() {
let step = RefactorStep {
id: "step-001".to_string(),
lint: "clippy::unwrap_used".to_string(),
confidence: 0.95,
impact: 10,
description: "Replace unwrap with expect".to_string(),
};
assert_eq!(step.id, "step-001");
assert_eq!(step.impact, 10);
assert!((step.confidence - 0.95).abs() < f64::EPSILON);
}
#[test]
fn test_refactor_step_serde() {
let step = RefactorStep {
id: "fix-unused".to_string(),
lint: "clippy::unused".to_string(),
confidence: 0.99,
impact: 5,
description: "Remove unused code".to_string(),
};
let json = serde_json::to_string(&step).unwrap();
assert!(json.contains("fix-unused"));
let back: RefactorStep = serde_json::from_str(&json).unwrap();
assert_eq!(back.lint, "clippy::unused");
}
#[test]
fn test_refactor_chain_construction() {
let chain = RefactorChain {
id: "chain-20240101-120000".to_string(),
estimated_reduction: 25,
automation_confidence: 0.85,
steps: vec![
RefactorStep {
id: "step-1".to_string(),
lint: "unused".to_string(),
confidence: 0.95,
impact: 15,
description: "Remove unused".to_string(),
},
RefactorStep {
id: "step-2".to_string(),
lint: "redundant".to_string(),
confidence: 0.75,
impact: 10,
description: "Remove redundant".to_string(),
},
],
};
assert_eq!(chain.steps.len(), 2);
assert_eq!(chain.estimated_reduction, 25);
}
#[test]
fn test_refactor_chain_empty_steps() {
let chain = RefactorChain {
id: "empty-chain".to_string(),
estimated_reduction: 0,
automation_confidence: 0.0,
steps: vec![],
};
assert!(chain.steps.is_empty());
assert_eq!(chain.estimated_reduction, 0);
}
#[test]
fn test_refactor_chain_serde() {
let chain = RefactorChain {
id: "test-chain".to_string(),
estimated_reduction: 10,
automation_confidence: 0.8,
steps: vec![RefactorStep {
id: "s1".to_string(),
lint: "test".to_string(),
confidence: 0.8,
impact: 10,
description: "test step".to_string(),
}],
};
let json = serde_json::to_string(&chain).unwrap();
assert!(json.contains("test-chain"));
let back: RefactorChain = serde_json::from_str(&json).unwrap();
assert_eq!(back.steps.len(), 1);
}
#[test]
fn test_quality_violation_construction() {
let v = QualityViolation {
rule: "max_defect_density".to_string(),
threshold: 0.05,
actual: 0.15,
severity: "blocking".to_string(),
};
assert_eq!(v.rule, "max_defect_density");
assert!(v.actual > v.threshold);
}
#[test]
fn test_quality_violation_warning_severity() {
let v = QualityViolation {
rule: "max_single_file_violations".to_string(),
threshold: 50.0,
actual: 75.0,
severity: "warning".to_string(),
};
assert_eq!(v.severity, "warning");
}
#[test]
fn test_quality_violation_serde() {
let v = QualityViolation {
rule: "test_rule".to_string(),
threshold: 10.0,
actual: 20.0,
severity: "error".to_string(),
};
let json = serde_json::to_string(&v).unwrap();
assert!(json.contains("test_rule"));
let back: QualityViolation = serde_json::from_str(&json).unwrap();
assert_eq!(back.threshold, 10.0);
}
#[test]
fn test_quality_gate_status_passed() {
let status = QualityGateStatus {
passed: true,
violations: vec![],
blocking: false,
};
assert!(status.passed);
assert!(!status.blocking);
assert!(status.violations.is_empty());
}
#[test]
fn test_quality_gate_status_failed_blocking() {
let status = QualityGateStatus {
passed: false,
violations: vec![QualityViolation {
rule: "density".to_string(),
threshold: 0.05,
actual: 0.20,
severity: "blocking".to_string(),
}],
blocking: true,
};
assert!(!status.passed);
assert!(status.blocking);
assert_eq!(status.violations.len(), 1);
}
#[test]
fn test_quality_gate_status_failed_non_blocking() {
let status = QualityGateStatus {
passed: false,
violations: vec![QualityViolation {
rule: "violations".to_string(),
threshold: 50.0,
actual: 60.0,
severity: "warning".to_string(),
}],
blocking: false,
};
assert!(!status.passed);
assert!(!status.blocking);
}
#[test]
fn test_quality_gate_status_multiple_violations() {
let status = QualityGateStatus {
passed: false,
violations: vec![
QualityViolation {
rule: "rule1".to_string(),
threshold: 1.0,
actual: 2.0,
severity: "blocking".to_string(),
},
QualityViolation {
rule: "rule2".to_string(),
threshold: 10.0,
actual: 15.0,
severity: "warning".to_string(),
},
],
blocking: true,
};
assert_eq!(status.violations.len(), 2);
}
#[test]
fn test_quality_gate_status_serde() {
let status = QualityGateStatus {
passed: false,
violations: vec![],
blocking: false,
};
let json = serde_json::to_string(&status).unwrap();
assert!(json.contains("\"passed\":false"));
let back: QualityGateStatus = serde_json::from_str(&json).unwrap();
assert!(!back.passed);
}
#[test]
fn test_lint_hotspot_params_default_values() {
let params = LintHotspotParams {
project_path: PathBuf::from("."),
file: None,
format: LintHotspotOutputFormat::Summary,
max_density: 5.0,
min_confidence: 0.8,
enforce: false,
dry_run: false,
enforcement_metadata: false,
output: None,
perf: false,
clippy_flags: String::new(),
top_files: 10,
include: vec![],
exclude: vec![],
};
assert_eq!(params.max_density, 5.0);
assert!(!params.enforce);
assert!(params.include.is_empty());
}
#[test]
fn test_lint_hotspot_params_with_file_filter() {
let params = LintHotspotParams {
project_path: PathBuf::from("/project"),
file: Some(PathBuf::from("src/main.rs")),
format: LintHotspotOutputFormat::Detailed,
max_density: 2.5,
min_confidence: 0.9,
enforce: true,
dry_run: true,
enforcement_metadata: true,
output: Some(PathBuf::from("output.json")),
perf: true,
clippy_flags: "-D warnings".to_string(),
top_files: 5,
include: vec!["*.rs".to_string()],
exclude: vec!["tests/*".to_string()],
};
assert!(params.file.is_some());
assert!(params.enforce);
assert!(params.dry_run);
assert!(!params.include.is_empty());
}
#[test]
fn test_lint_hotspot_params_all_formats() {
let formats = vec![
LintHotspotOutputFormat::Summary,
LintHotspotOutputFormat::Detailed,
LintHotspotOutputFormat::Json,
LintHotspotOutputFormat::EnforcementJson,
LintHotspotOutputFormat::Sarif,
];
for format in formats {
let params = LintHotspotParams {
project_path: PathBuf::from("."),
file: None,
format,
max_density: 5.0,
min_confidence: 0.8,
enforce: false,
dry_run: false,
enforcement_metadata: false,
output: None,
perf: false,
clippy_flags: String::new(),
top_files: 10,
include: vec![],
exclude: vec![],
};
assert!(params.max_density > 0.0);
}
}
#[test]
fn test_lint_hotspot_result_construction() {
let result = create_full_result();
assert_eq!(result.total_project_violations, 15);
assert!(result.quality_gate.passed);
assert!(result.enforcement.is_none());
}
#[test]
fn test_lint_hotspot_result_with_enforcement() {
let mut result = create_full_result();
result.enforcement = Some(EnforcementMetadata {
enforcement_score: 8.0,
requires_enforcement: true,
estimated_fix_time: 2400,
automation_confidence: 0.88,
enforcement_priority: 1,
});
assert!(result.enforcement.is_some());
assert!(result.enforcement.as_ref().unwrap().requires_enforcement);
}
#[test]
fn test_lint_hotspot_result_with_refactor_chain() {
let mut result = create_full_result();
result.refactor_chain = Some(RefactorChain {
id: "chain-1".to_string(),
estimated_reduction: 10,
automation_confidence: 0.85,
steps: vec![],
});
assert!(result.refactor_chain.is_some());
}
#[test]
fn test_lint_hotspot_result_serde_full() {
let mut result = create_full_result();
result.enforcement = Some(EnforcementMetadata {
enforcement_score: 5.0,
requires_enforcement: false,
estimated_fix_time: 1200,
automation_confidence: 0.7,
enforcement_priority: 3,
});
result.refactor_chain = Some(RefactorChain {
id: "chain".to_string(),
estimated_reduction: 5,
automation_confidence: 0.7,
steps: vec![],
});
let json = serde_json::to_string(&result).unwrap();
assert!(json.contains("total_project_violations"));
let back: LintHotspotResult = serde_json::from_str(&json).unwrap();
assert_eq!(
back.total_project_violations,
result.total_project_violations
);
assert!(back.enforcement.is_some());
assert!(back.refactor_chain.is_some());
}
#[test]
fn test_format_summary_with_high_defect_density() {
let mut result = create_full_result();
result.hotspot.defect_density = 0.50; let output = format_summary(&result, false, Duration::from_secs(1), 10).unwrap();
assert!(output.contains("0.50"));
}
#[test]
fn test_format_summary_with_many_lints() {
let mut result = create_full_result();
result.hotspot.top_lints = (0..10)
.map(|i| (format!("clippy::lint_{i}"), 10 - i))
.collect();
let output = format_summary(&result, false, Duration::from_secs(1), 10).unwrap();
assert!(output.contains("lint_0"));
assert!(output.contains("lint_4"));
}
#[test]
fn test_format_summary_with_zero_violations() {
let mut result = create_full_result();
result.total_project_violations = 0;
result.hotspot.total_violations = 0;
result.hotspot.detailed_violations.clear();
let output = format_summary(&result, false, Duration::from_secs(1), 10).unwrap();
assert!(output.contains("**Total Project Violations**: 0"));
}
#[test]
fn test_format_summary_with_single_file() {
let mut result = create_full_result();
result.summary_by_file.clear();
result.summary_by_file.insert(
PathBuf::from("only_file.rs"),
FileSummary {
total_violations: 5,
errors: 1,
warnings: 4,
sloc: 100,
defect_density: 0.05,
},
);
let output = format_summary(&result, false, Duration::from_secs(1), 10).unwrap();
assert!(output.contains("only_file.rs"));
}
#[test]
fn test_format_summary_perf_timing_precision() {
let result = create_full_result();
let output = format_summary(&result, true, Duration::from_millis(1234), 10).unwrap();
assert!(output.contains("1.23") || output.contains("Analysis completed in"));
}
#[test]
fn test_format_summary_multiple_quality_violations() {
let mut result = create_full_result();
result.quality_gate = QualityGateStatus {
passed: false,
violations: vec![
QualityViolation {
rule: "max_defect_density".to_string(),
threshold: 0.05,
actual: 0.15,
severity: "blocking".to_string(),
},
QualityViolation {
rule: "max_single_file_violations".to_string(),
threshold: 50.0,
actual: 100.0,
severity: "warning".to_string(),
},
],
blocking: true,
};
let output = format_summary(&result, false, Duration::from_secs(1), 10).unwrap();
assert!(output.contains("max_defect_density exceeded"));
assert!(output.contains("max_single_file_violations exceeded"));
}
#[test]
fn test_severity_distribution_debug() {
let dist = SeverityDistribution {
error: 1,
warning: 2,
suggestion: 3,
note: 4,
};
let debug_str = format!("{:?}", dist);
assert!(debug_str.contains("SeverityDistribution"));
assert!(debug_str.contains("error: 1"));
}
#[test]
fn test_violation_detail_debug() {
let v = create_violation("test", "warning", 10);
let debug_str = format!("{:?}", v);
assert!(debug_str.contains("ViolationDetail"));
assert!(debug_str.contains("test"));
}
#[test]
fn test_file_summary_debug() {
let summary = FileSummary {
total_violations: 5,
errors: 1,
warnings: 4,
sloc: 100,
defect_density: 0.05,
};
let debug_str = format!("{:?}", summary);
assert!(debug_str.contains("FileSummary"));
}
#[test]
fn test_lint_hotspot_debug() {
let hotspot = create_test_hotspot(5, 0.05, 100);
let debug_str = format!("{:?}", hotspot);
assert!(debug_str.contains("LintHotspot"));
}
#[test]
fn test_enforcement_metadata_debug_full() {
let meta = EnforcementMetadata {
enforcement_score: 9.0,
requires_enforcement: true,
estimated_fix_time: 7200,
automation_confidence: 0.95,
enforcement_priority: 1,
};
let debug_str = format!("{:?}", meta);
assert!(debug_str.contains("EnforcementMetadata"));
assert!(debug_str.contains("9"));
}
#[test]
fn test_refactor_chain_debug_with_steps() {
let chain = RefactorChain {
id: "debug-chain".to_string(),
estimated_reduction: 20,
automation_confidence: 0.9,
steps: vec![RefactorStep {
id: "s1".to_string(),
lint: "test".to_string(),
confidence: 0.9,
impact: 20,
description: "test desc".to_string(),
}],
};
let debug_str = format!("{:?}", chain);
assert!(debug_str.contains("RefactorChain"));
assert!(debug_str.contains("debug-chain"));
}
#[test]
fn test_quality_gate_status_debug() {
let status = QualityGateStatus {
passed: false,
violations: vec![],
blocking: true,
};
let debug_str = format!("{:?}", status);
assert!(debug_str.contains("QualityGateStatus"));
assert!(debug_str.contains("passed: false"));
}
#[test]
fn test_quality_violation_debug() {
let v = QualityViolation {
rule: "test".to_string(),
threshold: 1.0,
actual: 2.0,
severity: "error".to_string(),
};
let debug_str = format!("{:?}", v);
assert!(debug_str.contains("QualityViolation"));
}
#[test]
fn test_refactor_step_debug() {
let step = RefactorStep {
id: "step".to_string(),
lint: "lint".to_string(),
confidence: 0.5,
impact: 5,
description: "desc".to_string(),
};
let debug_str = format!("{:?}", step);
assert!(debug_str.contains("RefactorStep"));
}
#[test]
fn test_lint_hotspot_result_debug() {
let result = create_full_result();
let debug_str = format!("{:?}", result);
assert!(debug_str.contains("LintHotspotResult"));
}
#[test]
fn test_violation_detail_max_values() {
let v = ViolationDetail {
file: PathBuf::from("max.rs"),
line: u32::MAX,
column: u32::MAX,
end_line: u32::MAX,
end_column: u32::MAX,
lint_name: "max_lint".to_string(),
message: "max message".to_string(),
severity: "error".to_string(),
suggestion: None,
machine_applicable: true,
};
assert_eq!(v.line, u32::MAX);
}
#[test]
fn test_empty_lint_name() {
let v = ViolationDetail {
file: PathBuf::from("test.rs"),
line: 1,
column: 1,
end_line: 1,
end_column: 1,
lint_name: String::new(),
message: "message".to_string(),
severity: "warning".to_string(),
suggestion: None,
machine_applicable: false,
};
assert!(v.lint_name.is_empty());
}
#[test]
fn test_enforcement_metadata_max_score() {
let meta = EnforcementMetadata {
enforcement_score: 10.0,
requires_enforcement: true,
estimated_fix_time: u32::MAX,
automation_confidence: 1.0,
enforcement_priority: u8::MAX,
};
assert_eq!(meta.enforcement_score, 10.0);
assert_eq!(meta.enforcement_priority, u8::MAX);
}
#[test]
fn test_quality_violation_zero_threshold() {
let v = QualityViolation {
rule: "zero_rule".to_string(),
threshold: 0.0,
actual: 0.001,
severity: "error".to_string(),
};
assert!(v.actual > v.threshold);
}
#[test]
fn test_file_summary_high_sloc() {
let summary = FileSummary {
total_violations: 100,
errors: 10,
warnings: 90,
sloc: 1_000_000,
defect_density: 0.0001,
};
assert_eq!(summary.sloc, 1_000_000);
}
#[test]
fn test_lint_hotspot_unicode_file_path() {
let hotspot = LintHotspot {
file: PathBuf::from("src/unicode_\u{1F600}.rs"),
defect_density: 0.1,
total_violations: 1,
sloc: 10,
severity_distribution: SeverityDistribution::default(),
top_lints: vec![],
detailed_violations: vec![],
};
assert!(hotspot.file.to_string_lossy().contains("unicode"));
}
#[test]
fn test_violation_detail_long_message() {
let long_message = "a".repeat(10000);
let v = ViolationDetail {
file: PathBuf::from("test.rs"),
line: 1,
column: 1,
end_line: 1,
end_column: 1,
lint_name: "test".to_string(),
message: long_message.clone(),
severity: "warning".to_string(),
suggestion: Some(long_message),
machine_applicable: false,
};
assert_eq!(v.message.len(), 10000);
}
#[test]
fn test_severity_distribution_json_field_names() {
let dist = SeverityDistribution {
error: 1,
warning: 2,
suggestion: 3,
note: 4,
};
let json = serde_json::to_string(&dist).unwrap();
assert!(json.contains("\"error\""));
assert!(json.contains("\"warning\""));
assert!(json.contains("\"suggestion\""));
assert!(json.contains("\"note\""));
}
#[test]
fn test_lint_hotspot_result_json_structure() {
let result = create_full_result();
let json = serde_json::to_string_pretty(&result).unwrap();
assert!(json.contains("\"hotspot\""));
assert!(json.contains("\"all_violations\""));
assert!(json.contains("\"summary_by_file\""));
assert!(json.contains("\"total_project_violations\""));
assert!(json.contains("\"quality_gate\""));
}
#[test]
fn test_violation_detail_deserialization_from_raw_json() {
let json = r#"{
"file": "test.rs",
"line": 42,
"column": 10,
"end_line": 42,
"end_column": 50,
"lint_name": "clippy::test",
"message": "test message",
"severity": "warning",
"suggestion": null,
"machine_applicable": true
}"#;
let v: ViolationDetail = serde_json::from_str(json).unwrap();
assert_eq!(v.line, 42);
assert!(v.suggestion.is_none());
}
#[test]
fn test_quality_gate_status_deserialization() {
let json = r#"{
"passed": true,
"violations": [],
"blocking": false
}"#;
let status: QualityGateStatus = serde_json::from_str(json).unwrap();
assert!(status.passed);
assert!(!status.blocking);
}
#[test]
fn test_enforcement_metadata_deserialization() {
let json = r#"{
"enforcement_score": 7.5,
"requires_enforcement": true,
"estimated_fix_time": 3600,
"automation_confidence": 0.85,
"enforcement_priority": 2
}"#;
let meta: EnforcementMetadata = serde_json::from_str(json).unwrap();
assert!(meta.requires_enforcement);
assert_eq!(meta.enforcement_priority, 2);
}
#[test]
fn test_violation_detail_clone_independence() {
let original = create_violation("test", "warning", 10);
let mut cloned = original.clone();
cloned.line = 999;
cloned.lint_name = "modified".to_string();
assert_eq!(original.line, 10);
assert_eq!(original.lint_name, "test");
}
#[test]
fn test_summary_by_file_pathbuf_key() {
let mut map: HashMap<PathBuf, FileSummary> = HashMap::new();
let path1 = PathBuf::from("src/main.rs");
let path2 = PathBuf::from("src/lib.rs");
let path1_duplicate = PathBuf::from("src/main.rs");
map.insert(
path1.clone(),
FileSummary {
total_violations: 5,
errors: 1,
warnings: 4,
sloc: 100,
defect_density: 0.05,
},
);
map.insert(
path2,
FileSummary {
total_violations: 3,
errors: 0,
warnings: 3,
sloc: 50,
defect_density: 0.06,
},
);
map.insert(
path1_duplicate,
FileSummary {
total_violations: 10,
errors: 2,
warnings: 8,
sloc: 100,
defect_density: 0.10,
},
);
assert_eq!(map.len(), 2);
assert_eq!(map.get(&path1).unwrap().total_violations, 10);
}
#[test]
fn test_format_summary_empty_summary_by_file() {
let mut result = create_full_result();
result.summary_by_file.clear();
let output = format_summary(&result, false, Duration::from_secs(1), 10).unwrap();
assert!(output.contains("**Files with Issues**: 0"));
}
#[test]
fn test_format_summary_long_file_path() {
let mut result = create_full_result();
result.hotspot.file = PathBuf::from(
"very/long/nested/directory/structure/with/many/levels/src/module/submodule/file.rs",
);
let output = format_summary(&result, false, Duration::from_secs(1), 10).unwrap();
assert!(output.contains("file.rs") || output.contains("very/long"));
}
#[test]
fn test_format_summary_top_files_limit() {
let mut result = create_full_result();
for i in 0..20 {
result.summary_by_file.insert(
PathBuf::from(format!("src/file_{i}.rs")),
FileSummary {
total_violations: 20 - i,
errors: 1,
warnings: 19 - i,
sloc: 100,
defect_density: (20 - i) as f64 / 100.0,
},
);
}
let output = format_summary(&result, false, Duration::from_secs(1), 5).unwrap();
assert!(output.contains("## Top Files with Lint Issues"));
}
#[test]
fn test_full_workflow_simulation() {
let mut result = create_full_result();
result.enforcement = Some(EnforcementMetadata {
enforcement_score: 8.5,
requires_enforcement: true,
estimated_fix_time: 1800,
automation_confidence: 0.88,
enforcement_priority: 1,
});
result.refactor_chain = Some(RefactorChain {
id: "workflow-chain".to_string(),
estimated_reduction: 12,
automation_confidence: 0.85,
steps: vec![
RefactorStep {
id: "step-1".to_string(),
lint: "clippy::unwrap_used".to_string(),
confidence: 0.95,
impact: 8,
description: "Replace unwrap with expect".to_string(),
},
RefactorStep {
id: "step-2".to_string(),
lint: "clippy::redundant_clone".to_string(),
confidence: 0.75,
impact: 4,
description: "Remove redundant clones".to_string(),
},
],
});
result.quality_gate = QualityGateStatus {
passed: false,
violations: vec![QualityViolation {
rule: "max_defect_density".to_string(),
threshold: 0.05,
actual: 0.075,
severity: "blocking".to_string(),
}],
blocking: true,
};
let json = serde_json::to_string_pretty(&result).unwrap();
let restored: LintHotspotResult = serde_json::from_str(&json).unwrap();
assert!(!restored.quality_gate.passed);
assert!(restored.enforcement.is_some());
assert!(restored.refactor_chain.is_some());
assert_eq!(restored.refactor_chain.as_ref().unwrap().steps.len(), 2);
let output = format_summary(&restored, true, Duration::from_millis(500), 10).unwrap();
assert!(output.contains("Enforcement Metadata"));
assert!(output.contains("Quality Gate Failed"));
assert!(output.contains("Analysis completed in"));
}
#[test]
fn test_minimal_result() {
let result = LintHotspotResult {
hotspot: LintHotspot {
file: PathBuf::from("empty.rs"),
defect_density: 0.0,
total_violations: 0,
sloc: 1,
severity_distribution: SeverityDistribution::default(),
top_lints: vec![],
detailed_violations: vec![],
},
all_violations: vec![],
summary_by_file: HashMap::new(),
total_project_violations: 0,
enforcement: None,
refactor_chain: None,
quality_gate: QualityGateStatus {
passed: true,
violations: vec![],
blocking: false,
},
};
let json = serde_json::to_string(&result).unwrap();
let back: LintHotspotResult = serde_json::from_str(&json).unwrap();
assert_eq!(back.total_project_violations, 0);
assert!(back.quality_gate.passed);
}