#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use crate::services::facades::satd_facade::{SatdSeverity as FacadeSeverity, SatdViolation};
fn strip_ansi(s: &str) -> String {
let re = regex::Regex::new(r"\x1b\[[0-9;]*m").unwrap();
re.replace_all(s, "").to_string()
}
#[test]
fn test_format_summary() {
let result = SatdAnalysisResult {
total_files: 10,
violations: vec![SatdViolation {
file_path: "test.rs".to_string(),
line_number: 42,
violation_type: "TODO".to_string(),
message: "Implement feature".to_string(),
severity: FacadeSeverity::Medium,
}],
summary: "Test summary".to_string(),
};
let output = strip_ansi(&format_summary(&result));
assert!(output.contains("Test summary"));
assert!(output.contains("Total violations:"));
assert!(output.contains("1"));
}
fn make_violation(severity: FacadeSeverity, vtype: &str) -> SatdViolation {
SatdViolation {
file_path: format!("src/{vtype}.rs"),
line_number: 1,
violation_type: vtype.to_string(),
message: format!("{vtype} message"),
severity,
}
}
fn result_with_all_severities() -> SatdAnalysisResult {
SatdAnalysisResult {
total_files: 4,
violations: vec![
make_violation(FacadeSeverity::Critical, "FIXME"),
make_violation(FacadeSeverity::High, "TODO"),
make_violation(FacadeSeverity::Medium, "HACK"),
make_violation(FacadeSeverity::Low, "XXX"),
],
summary: "All severities".to_string(),
}
}
fn empty_result() -> SatdAnalysisResult {
SatdAnalysisResult {
total_files: 0,
violations: vec![],
summary: "Empty".to_string(),
}
}
#[test]
fn test_format_output_summary_arm() {
let r = format_output(
&result_with_all_severities(),
SatdOutputFormat::Summary,
false,
0,
false,
);
let s = strip_ansi(&r);
assert!(s.contains("SATD Analysis Summary"));
}
#[test]
fn test_format_output_json_arm() {
let r = format_output(
&result_with_all_severities(),
SatdOutputFormat::Json,
false,
0,
false,
);
assert!(r.contains("\"total_violations\": 4"));
}
#[test]
fn test_format_output_sarif_arm() {
let r = format_output(
&result_with_all_severities(),
SatdOutputFormat::Sarif,
false,
0,
false,
);
assert!(r.contains("\"version\":\"2.1.0\""));
assert!(r.contains("satd-violation"));
}
#[test]
fn test_format_output_markdown_arm() {
let r = format_output(
&result_with_all_severities(),
SatdOutputFormat::Markdown,
false,
0,
false,
);
assert!(r.contains("# SATD Analysis Report"));
}
#[test]
fn test_format_summary_with_all_severities_lists_each_count() {
let r = strip_ansi(&format_summary(&result_with_all_severities()));
assert!(r.contains("Critical:"));
assert!(r.contains("High:"));
assert!(r.contains("Medium:"));
assert!(r.contains("Low:"));
assert!(r.contains("Top Violations"));
}
#[test]
fn test_format_summary_empty_skips_top_violations() {
let r = strip_ansi(&format_summary(&empty_result()));
assert!(!r.contains("Top Violations"));
}
#[test]
fn test_format_summary_top_violations_caps_at_10() {
let mut res = result_with_all_severities();
for i in 0..12 {
res.violations
.push(make_violation(FacadeSeverity::Low, &format!("V{i}")));
}
let r = strip_ansi(&format_summary(&res));
assert!(!r.contains("V11"));
}
#[test]
fn test_format_json_metrics_flag_adds_metrics_block() {
let r = format_json(&result_with_all_severities(), true, false);
assert!(r.contains("\"metrics\""));
assert!(r.contains("\"critical_count\": 1"));
assert!(r.contains("\"high_count\": 1"));
}
#[test]
fn test_format_json_no_metrics_flag_omits_metrics() {
let r = format_json(&result_with_all_severities(), false, false);
assert!(!r.contains("\"metrics\""));
}
#[test]
fn test_format_json_evolution_flag_adds_evolution_block() {
let r = format_json(&result_with_all_severities(), false, true);
assert!(r.contains("\"evolution\""));
assert!(r.contains("Evolution tracking"));
}
#[test]
fn test_format_sarif_maps_each_severity_to_correct_level() {
let r = format_sarif(&result_with_all_severities());
assert!(r.contains("\"error\""));
assert!(r.contains("\"warning\""));
assert!(r.contains("\"note\""));
}
#[test]
fn test_format_sarif_empty_violations_emits_empty_results() {
let r = format_sarif(&empty_result());
assert!(r.contains("\"results\":[]"));
}
#[test]
fn test_format_markdown_with_evolution_emits_section() {
let r = format_markdown(&result_with_all_severities(), true, 30);
assert!(r.contains("## Evolution (Last 30 Days)"));
}
#[test]
fn test_format_markdown_without_evolution_skips_section() {
let r = format_markdown(&result_with_all_severities(), false, 0);
assert!(!r.contains("## Evolution"));
}
#[test]
fn test_format_markdown_violations_table_emitted_only_when_non_empty() {
let with = format_markdown(&result_with_all_severities(), false, 0);
assert!(with.contains("## Violations"));
let without = format_markdown(&empty_result(), false, 0);
assert!(!without.contains("## Violations"));
}
#[test]
fn test_format_markdown_metrics_table_includes_critical_high_counts() {
let r = format_markdown(&result_with_all_severities(), false, 0);
assert!(r.contains("Critical Violations | 1"));
assert!(r.contains("High Violations | 1"));
}
#[test]
fn test_print_metrics_with_violations_no_panic() {
print_metrics(&result_with_all_severities());
}
#[test]
fn test_print_metrics_empty_no_panic() {
print_metrics(&empty_result());
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
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);
}
}
}