use super::*;
mod tests {
use super::*;
fn create_test_hotspot_result() -> LintHotspotResult {
LintHotspotResult {
hotspot: LintHotspot {
file: PathBuf::from("src/main.rs"),
defect_density: 0.05,
total_violations: 5,
sloc: 100,
severity_distribution: SeverityDistribution {
error: 2,
warning: 3,
suggestion: 0,
note: 0,
},
top_lints: vec![
("clippy::too_many_arguments".to_string(), 2),
("unused_variable".to_string(), 3),
],
detailed_violations: vec![],
},
all_violations: vec![],
summary_by_file: std::collections::HashMap::new(),
total_project_violations: 5,
enforcement: None,
refactor_chain: None,
quality_gate: QualityGateStatus {
passed: true,
violations: vec![],
blocking: false,
},
}
}
pub fn should_exit_with_error(
quality_gate_passed: bool,
enforce: bool,
total_violations: usize,
) -> bool {
!quality_gate_passed || (enforce && total_violations > 0)
}
#[test]
fn test_enforce_flag_behavior() {
assert!(should_exit_with_error(true, true, 5));
assert!(!should_exit_with_error(true, true, 0));
assert!(!should_exit_with_error(true, false, 5));
assert!(should_exit_with_error(false, false, 0));
assert!(should_exit_with_error(false, true, 5));
}
#[test]
fn test_format_summary_with_violations() {
let result = create_test_hotspot_result();
let output = format_summary(&result, false, std::time::Duration::from_secs(1), 10).unwrap();
assert!(output.contains("# Lint Hotspot Analysis"));
assert!(output.contains("**Total Project Violations**: 5"));
assert!(output.contains("## Top Files with Lint Issues"));
assert!(output.contains("## Hottest File Details"));
assert!(output.contains("**File**: src/main.rs"));
}
#[test]
fn test_quality_gate_enforcement_scenario() {
let mut result = create_test_hotspot_result();
result.quality_gate.passed = true;
result.total_project_violations = 10;
let should_exit = should_exit_with_error(
result.quality_gate.passed,
true, result.total_project_violations,
);
assert!(
should_exit,
"Should exit with error when enforce flag is set and violations exist"
);
result.total_project_violations = 0;
let should_exit = should_exit_with_error(
result.quality_gate.passed,
true, result.total_project_violations,
);
assert!(
!should_exit,
"Should not exit with error when enforce flag is set but no violations"
);
}
#[test]
fn test_multiple_enforcement_scenarios() {
assert!(should_exit_with_error(false, false, 0));
assert!(should_exit_with_error(true, true, 1));
assert!(!should_exit_with_error(true, true, 0));
assert!(!should_exit_with_error(true, false, 10));
assert!(should_exit_with_error(false, true, 5));
}
}
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}
mod coverage_tests {
use super::*;
use std::collections::HashMap;
use std::path::PathBuf;
use std::time::Duration;
fn create_test_violation(
file: &str,
line: u32,
lint_name: &str,
severity: &str,
) -> ViolationDetail {
ViolationDetail {
file: PathBuf::from(file),
line,
column: 1,
end_line: line,
end_column: 10,
lint_name: lint_name.to_string(),
message: format!("Test violation for {lint_name}"),
severity: severity.to_string(),
suggestion: None,
machine_applicable: false,
}
}
fn create_test_violation_with_suggestion(
file: &str,
line: u32,
lint_name: &str,
severity: &str,
suggestion: &str,
) -> ViolationDetail {
ViolationDetail {
file: PathBuf::from(file),
line,
column: 1,
end_line: line,
end_column: 10,
lint_name: lint_name.to_string(),
message: format!("Test violation for {lint_name}"),
severity: severity.to_string(),
suggestion: Some(suggestion.to_string()),
machine_applicable: true,
}
}
fn create_test_hotspot(
file: &str,
violations: usize,
sloc: usize,
errors: usize,
warnings: usize,
) -> LintHotspot {
let defect_density = if sloc > 0 {
violations as f64 / sloc as f64
} else {
0.0
};
LintHotspot {
file: PathBuf::from(file),
defect_density,
total_violations: violations,
sloc,
severity_distribution: SeverityDistribution {
error: errors,
warning: warnings,
suggestion: 0,
note: 0,
},
top_lints: vec![
("clippy::unused_variable".to_string(), 3),
("clippy::needless_return".to_string(), 2),
],
detailed_violations: vec![],
}
}
fn create_full_test_result() -> LintHotspotResult {
let mut summary_by_file = HashMap::new();
summary_by_file.insert(
PathBuf::from("src/main.rs"),
FileSummary {
total_violations: 5,
errors: 2,
warnings: 3,
sloc: 100,
defect_density: 0.05,
},
);
summary_by_file.insert(
PathBuf::from("src/lib.rs"),
FileSummary {
total_violations: 3,
errors: 1,
warnings: 2,
sloc: 50,
defect_density: 0.06,
},
);
LintHotspotResult {
hotspot: create_test_hotspot("src/main.rs", 5, 100, 2, 3),
all_violations: vec![
create_test_violation("src/main.rs", 10, "unused_variable", "warning"),
create_test_violation("src/main.rs", 20, "clippy::needless_return", "warning"),
create_test_violation("src/lib.rs", 5, "clippy::too_many_arguments", "warning"),
],
summary_by_file,
total_project_violations: 8,
enforcement: None,
refactor_chain: None,
quality_gate: QualityGateStatus {
passed: true,
violations: vec![],
blocking: false,
},
}
}
#[test]
fn test_lint_hotspot_params_creation() {
let params = LintHotspotParams {
project_path: PathBuf::from("/test/project"),
file: None,
format: LintHotspotOutputFormat::Summary,
max_density: 5.0,
min_confidence: 0.7,
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.project_path, PathBuf::from("/test/project"));
assert!(params.file.is_none());
assert!(!params.enforce);
assert_eq!(params.max_density, 5.0);
assert_eq!(params.min_confidence, 0.7);
}
#[test]
fn test_lint_hotspot_params_with_file() {
let params = LintHotspotParams {
project_path: PathBuf::from("/test/project"),
file: Some(PathBuf::from("src/main.rs")),
format: LintHotspotOutputFormat::Json,
max_density: 10.0,
min_confidence: 0.8,
enforce: true,
dry_run: true,
enforcement_metadata: true,
output: Some(PathBuf::from("/tmp/output.json")),
perf: true,
clippy_flags: "-W clippy::pedantic".to_string(),
top_files: 5,
include: vec!["src/**/*.rs".to_string()],
exclude: vec!["**/tests/**".to_string()],
};
assert_eq!(params.file, Some(PathBuf::from("src/main.rs")));
assert!(params.enforce);
assert!(params.dry_run);
assert!(params.enforcement_metadata);
assert!(params.perf);
assert!(!params.include.is_empty());
assert!(!params.exclude.is_empty());
}
#[test]
fn test_violation_detail_clone() {
let original = create_test_violation("src/main.rs", 10, "unused_variable", "warning");
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.severity, original.severity);
}
#[test]
fn test_violation_detail_with_suggestion() {
let violation = create_test_violation_with_suggestion(
"src/main.rs",
10,
"unused_variable",
"warning",
"Remove the unused variable",
);
assert!(violation.suggestion.is_some());
assert!(violation.machine_applicable);
assert_eq!(
violation.suggestion.unwrap(),
"Remove the unused variable"
);
}
#[test]
fn test_violation_detail_serialization() {
let violation = create_test_violation("src/main.rs", 10, "unused_variable", "warning");
let json = serde_json::to_string(&violation).unwrap();
assert!(json.contains("src/main.rs"));
assert!(json.contains("unused_variable"));
assert!(json.contains("warning"));
}
#[test]
fn test_severity_distribution_default() {
let dist = SeverityDistribution::default();
assert_eq!(dist.error, 0);
assert_eq!(dist.warning, 0);
assert_eq!(dist.suggestion, 0);
assert_eq!(dist.note, 0);
}
#[test]
fn test_severity_distribution_custom() {
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_serialization() {
let dist = SeverityDistribution {
error: 5,
warning: 10,
suggestion: 3,
note: 2,
};
let json = serde_json::to_string(&dist).unwrap();
let deserialized: SeverityDistribution = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.error, dist.error);
assert_eq!(deserialized.warning, dist.warning);
assert_eq!(deserialized.suggestion, dist.suggestion);
assert_eq!(deserialized.note, dist.note);
}
#[test]
fn test_file_summary_creation() {
let summary = FileSummary {
total_violations: 10,
errors: 3,
warnings: 7,
sloc: 200,
defect_density: 0.05,
};
assert_eq!(summary.total_violations, 10);
assert_eq!(summary.errors, 3);
assert_eq!(summary.warnings, 7);
assert_eq!(summary.sloc, 200);
assert!((summary.defect_density - 0.05).abs() < f64::EPSILON);
}
#[test]
fn test_file_summary_serialization() {
let summary = FileSummary {
total_violations: 10,
errors: 3,
warnings: 7,
sloc: 200,
defect_density: 0.05,
};
let json = serde_json::to_string(&summary).unwrap();
let deserialized: FileSummary = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.total_violations, summary.total_violations);
assert_eq!(deserialized.errors, summary.errors);
assert_eq!(deserialized.warnings, summary.warnings);
}
#[test]
fn test_lint_hotspot_creation() {
let hotspot = create_test_hotspot("src/main.rs", 10, 200, 3, 7);
assert_eq!(hotspot.file, PathBuf::from("src/main.rs"));
assert_eq!(hotspot.total_violations, 10);
assert_eq!(hotspot.sloc, 200);
assert_eq!(hotspot.severity_distribution.error, 3);
assert_eq!(hotspot.severity_distribution.warning, 7);
assert!((hotspot.defect_density - 0.05).abs() < f64::EPSILON);
}
#[test]
fn test_lint_hotspot_with_zero_sloc() {
let hotspot = create_test_hotspot("src/empty.rs", 5, 0, 1, 4);
assert_eq!(hotspot.sloc, 0);
assert!((hotspot.defect_density - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_lint_hotspot_serialization() {
let hotspot = create_test_hotspot("src/main.rs", 10, 200, 3, 7);
let json = serde_json::to_string(&hotspot).unwrap();
let deserialized: LintHotspot = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.file, hotspot.file);
assert_eq!(deserialized.total_violations, hotspot.total_violations);
assert_eq!(deserialized.sloc, hotspot.sloc);
}
}