#![cfg_attr(coverage_nightly, coverage(off))]
use super::markdown_format::{
calculate_component_score, write_component_breakdown, write_hotspot_basic_info,
write_single_hotspot, write_tdg_header, write_tdg_hotspots, write_tdg_summary,
};
use super::sarif_format::generate_tdg_rules;
use super::*;
use crate::models::tdg::{TDGHotspot, TDGSummary};
use std::path::PathBuf;
fn create_test_hotspot(path: &str, score: f64, factor: &str, hours: f64) -> TDGHotspot {
TDGHotspot {
path: path.to_string(),
tdg_score: score,
primary_factor: factor.to_string(),
estimated_hours: hours,
}
}
fn create_test_summary() -> TDGSummary {
TDGSummary {
total_files: 100,
critical_files: 5,
warning_files: 15,
average_tdg: 1.5,
p95_tdg: 2.8,
p99_tdg: 3.5,
estimated_debt_hours: 80.0,
hotspots: vec![],
}
}
fn create_test_hotspots() -> Vec<TDGHotspot> {
vec![
create_test_hotspot("src/complex.rs", 3.5, "complexity", 12.0),
create_test_hotspot("src/churn.rs", 2.8, "churn", 8.0),
create_test_hotspot("src/coupling.rs", 2.0, "coupling", 5.0),
create_test_hotspot("src/normal.rs", 1.2, "none", 2.0),
create_test_hotspot("src/low.rs", 0.5, "none", 0.5),
]
}
mod filter_tests {
use super::*;
#[test]
fn test_filter_no_filters() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots.clone(), 0.0, 0, false);
assert_eq!(result.len(), 5);
}
#[test]
fn test_filter_by_threshold() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, 2.0, 0, false);
assert_eq!(result.len(), 3);
assert!(result.iter().all(|h| h.tdg_score >= 2.0));
}
#[test]
fn test_filter_by_threshold_high() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, 3.0, 0, false);
assert_eq!(result.len(), 1);
assert_eq!(result[0].path, "src/complex.rs");
}
#[test]
fn test_filter_critical_only() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, 0.0, 0, true);
assert_eq!(result.len(), 2);
assert!(result.iter().all(|h| h.tdg_score > 2.5));
}
#[test]
fn test_filter_top_limit() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, 0.0, 3, false);
assert_eq!(result.len(), 3);
}
#[test]
fn test_filter_top_limit_larger_than_list() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, 0.0, 100, false);
assert_eq!(result.len(), 5);
}
#[test]
fn test_filter_combined_threshold_and_critical() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, 1.0, 0, true);
assert_eq!(result.len(), 2);
}
#[test]
fn test_filter_combined_all_filters() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, 1.0, 1, true);
assert_eq!(result.len(), 1);
assert!(result[0].tdg_score > 2.5);
}
#[test]
fn test_filter_empty_hotspots() {
let hotspots: Vec<TDGHotspot> = vec![];
let result = filter_tdg_hotspots(hotspots, 1.0, 10, true);
assert!(result.is_empty());
}
#[test]
fn test_filter_zero_threshold() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, 0.0, 0, false);
assert_eq!(result.len(), 5);
}
#[test]
fn test_filter_negative_threshold_treated_as_no_filter() {
let hotspots = create_test_hotspots();
let result = filter_tdg_hotspots(hotspots, -1.0, 0, false);
assert_eq!(result.len(), 5);
}
}
mod json_format_tests {
use super::*;
#[test]
fn test_format_json_basic() {
let summary = create_test_summary();
let hotspots = create_test_hotspots();
let result = format_tdg_json(&summary, &hotspots, false);
assert!(result.is_ok());
let json_str = result.unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap();
assert_eq!(parsed["summary"]["total_files"], 100);
assert_eq!(parsed["hotspots"].as_array().unwrap().len(), 5);
}
#[test]
fn test_format_json_with_components() {
let summary = create_test_summary();
let hotspots = create_test_hotspots();
let result = format_tdg_json(&summary, &hotspots, true).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert!(parsed["components"].is_object());
assert_eq!(parsed["components"]["complexity_weight"], 0.4);
}
#[test]
fn test_format_json_without_components() {
let summary = create_test_summary();
let hotspots = create_test_hotspots();
let result = format_tdg_json(&summary, &hotspots, false).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert!(parsed["components"].is_null());
}
#[test]
fn test_format_json_empty_hotspots() {
let summary = create_test_summary();
let result = format_tdg_json(&summary, &[], false).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert!(parsed["hotspots"].as_array().unwrap().is_empty());
}
#[test]
fn test_format_json_is_valid_json() {
let summary = create_test_summary();
let hotspots = vec![create_test_hotspot(
"path/with spaces/file.rs",
2.5,
"special\"chars",
5.0,
)];
let result = format_tdg_json(&summary, &hotspots, true).unwrap();
assert!(serde_json::from_str::<serde_json::Value>(&result).is_ok());
}
}
mod table_format_tests {
use super::*;
#[test]
fn test_format_table_basic() {
let hotspots = create_test_hotspots();
let result = format_tdg_table(&hotspots, false);
assert!(result.is_ok());
let table = result.unwrap();
assert!(table.contains("| File | TDG Score |"));
assert!(table.contains("|------|-----------|"));
}
#[test]
fn test_format_table_contains_hotspot_data() {
let hotspots = vec![create_test_hotspot("src/test.rs", 2.5, "complexity", 5.0)];
let result = format_tdg_table(&hotspots, false).unwrap();
assert!(result.contains("test.rs"));
assert!(result.contains("2.50"));
assert!(result.contains("complexity"));
assert!(result.contains("5.0"));
}
#[test]
fn test_format_table_verbose_mode() {
let hotspots = vec![create_test_hotspot("src/test.rs", 2.5, "complexity", 5.0)];
let result = format_tdg_table(&hotspots, true).unwrap();
assert!(result.contains("Components:"));
assert!(result.contains("complexity="));
assert!(result.contains("churn="));
}
#[test]
fn test_format_table_non_verbose_no_components() {
let hotspots = vec![create_test_hotspot("src/test.rs", 2.5, "complexity", 5.0)];
let result = format_tdg_table(&hotspots, false).unwrap();
assert!(!result.contains("Components:"));
}
#[test]
fn test_format_table_empty_hotspots() {
let result = format_tdg_table(&[], false).unwrap();
assert!(result.contains("| File | TDG Score |"));
let lines: Vec<&str> = result.lines().collect();
assert_eq!(lines.len(), 2); }
#[test]
fn test_format_table_multiple_hotspots() {
let hotspots = create_test_hotspots();
let result = format_tdg_table(&hotspots, false).unwrap();
let data_lines = result.lines().count() - 2; assert_eq!(data_lines, 5);
}
#[test]
fn test_format_table_extracts_filename_from_path() {
let hotspots = vec![create_test_hotspot(
"very/deep/path/to/file.rs",
1.0,
"none",
1.0,
)];
let result = format_tdg_table(&hotspots, false).unwrap();
assert!(result.contains("file.rs"));
assert!(!result.contains("very/deep/path/to/file.rs"));
}
}
mod markdown_format_tests {
use super::*;
#[test]
fn test_format_markdown_basic() {
let summary = create_test_summary();
let hotspots = create_test_hotspots();
let result = format_tdg_markdown(&summary, &hotspots, false);
assert!(result.is_ok());
let md = result.unwrap();
assert!(md.contains("# Technical Debt Gradient Analysis"));
}
#[test]
fn test_format_markdown_summary_content() {
let summary = create_test_summary();
let result = format_tdg_markdown(&summary, &[], false).unwrap();
assert!(result.contains("**Total Files**: 100"));
assert!(result.contains("**Critical Files**: 5"));
assert!(result.contains("**Warning Files**: 15"));
assert!(result.contains("**Average TDG**: 1.500"));
assert!(result.contains("**95th Percentile**: 2.800"));
}
#[test]
fn test_format_markdown_with_hotspots() {
let summary = create_test_summary();
let hotspots = vec![create_test_hotspot("src/test.rs", 2.5, "complexity", 5.0)];
let result = format_tdg_markdown(&summary, &hotspots, false).unwrap();
assert!(result.contains("## Top Hotspots"));
assert!(result.contains("### 1. src/test.rs"));
assert!(result.contains("**TDG Score**: 2.500"));
assert!(result.contains("**Primary Factor**: complexity"));
assert!(result.contains("**Estimated Hours**: 5.0"));
}
#[test]
fn test_format_markdown_with_components() {
let summary = create_test_summary();
let hotspots = vec![create_test_hotspot("src/test.rs", 2.0, "complexity", 5.0)];
let result = format_tdg_markdown(&summary, &hotspots, true).unwrap();
assert!(result.contains("#### Component Breakdown:"));
assert!(result.contains("Complexity: 0.800"));
assert!(result.contains("Churn: 0.600"));
assert!(result.contains("Duplication: 0.400"));
assert!(result.contains("Coupling: 0.200"));
}
#[test]
fn test_format_markdown_without_components() {
let summary = create_test_summary();
let hotspots = vec![create_test_hotspot("src/test.rs", 2.0, "complexity", 5.0)];
let result = format_tdg_markdown(&summary, &hotspots, false).unwrap();
assert!(!result.contains("Component Breakdown"));
}
#[test]
fn test_format_markdown_empty_hotspots_no_section() {
let summary = create_test_summary();
let result = format_tdg_markdown(&summary, &[], false).unwrap();
assert!(!result.contains("## Top Hotspots"));
}
#[test]
fn test_format_markdown_multiple_hotspots_indexed() {
let summary = create_test_summary();
let hotspots = vec![
create_test_hotspot("src/a.rs", 3.0, "complexity", 10.0),
create_test_hotspot("src/b.rs", 2.0, "churn", 5.0),
create_test_hotspot("src/c.rs", 1.0, "coupling", 2.0),
];
let result = format_tdg_markdown(&summary, &hotspots, false).unwrap();
assert!(result.contains("### 1. src/a.rs"));
assert!(result.contains("### 2. src/b.rs"));
assert!(result.contains("### 3. src/c.rs"));
}
}
mod sarif_format_tests {
use super::*;
#[test]
fn test_format_sarif_basic_structure() {
let hotspots = create_test_hotspots();
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/test"));
assert!(result.is_ok());
let sarif_str = result.unwrap();
let sarif: serde_json::Value = serde_json::from_str(&sarif_str).unwrap();
assert_eq!(sarif["version"], "2.1.0");
}
#[test]
fn test_format_sarif_tool_info() {
let hotspots = create_test_hotspots();
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/test")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let tool = &sarif["runs"][0]["tool"]["driver"];
assert_eq!(tool["name"], "paiml-tdg-analyzer");
assert!(!tool["version"].as_str().unwrap().is_empty());
assert!(tool["informationUri"]
.as_str()
.unwrap()
.contains("github.com"));
}
#[test]
fn test_format_sarif_rules_present() {
let hotspots = create_test_hotspots();
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/test")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let rules = sarif["runs"][0]["tool"]["driver"]["rules"]
.as_array()
.unwrap();
assert_eq!(rules.len(), 3);
let rule_ids: Vec<&str> = rules.iter().map(|r| r["id"].as_str().unwrap()).collect();
assert!(rule_ids.contains(&"critical-tdg"));
assert!(rule_ids.contains(&"high-tdg"));
assert!(rule_ids.contains(&"moderate-tdg"));
}
#[test]
fn test_format_sarif_critical_hotspot() {
let hotspots = vec![create_test_hotspot("src/test.rs", 3.0, "complexity", 10.0)];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let results = sarif["runs"][0]["results"].as_array().unwrap();
assert_eq!(results[0]["level"], "error");
assert_eq!(results[0]["ruleId"], "critical-tdg");
}
#[test]
fn test_format_sarif_warning_hotspot() {
let hotspots = vec![create_test_hotspot("src/test.rs", 2.0, "churn", 5.0)];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let results = sarif["runs"][0]["results"].as_array().unwrap();
assert_eq!(results[0]["level"], "warning");
assert_eq!(results[0]["ruleId"], "high-tdg");
}
#[test]
fn test_format_sarif_note_hotspot() {
let hotspots = vec![create_test_hotspot("src/test.rs", 1.0, "none", 2.0)];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let results = sarif["runs"][0]["results"].as_array().unwrap();
assert_eq!(results[0]["level"], "note");
assert_eq!(results[0]["ruleId"], "moderate-tdg");
}
#[test]
fn test_format_sarif_message_format() {
let hotspots = vec![create_test_hotspot("src/test.rs", 2.5, "complexity", 5.0)];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let msg = sarif["runs"][0]["results"][0]["message"]["text"]
.as_str()
.unwrap();
assert!(msg.contains("2.50"));
assert!(msg.contains("complexity"));
assert!(msg.contains("5.0 hours"));
}
#[test]
fn test_format_sarif_location() {
let hotspots = vec![create_test_hotspot("/test/src/file.rs", 2.0, "churn", 5.0)];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/test")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let uri = sarif["runs"][0]["results"][0]["locations"][0]["physicalLocation"]
["artifactLocation"]["uri"]
.as_str()
.unwrap();
assert_eq!(uri, "src/file.rs");
}
#[test]
fn test_format_sarif_location_no_strip() {
let hotspots = vec![create_test_hotspot("other/path/file.rs", 2.0, "churn", 5.0)];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/test")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let uri = sarif["runs"][0]["results"][0]["locations"][0]["physicalLocation"]
["artifactLocation"]["uri"]
.as_str()
.unwrap();
assert_eq!(uri, "other/path/file.rs");
}
#[test]
fn test_format_sarif_empty_hotspots() {
let result = format_tdg_sarif(&[], &PathBuf::from("/test")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let results = sarif["runs"][0]["results"].as_array().unwrap();
assert!(results.is_empty());
let rules = sarif["runs"][0]["tool"]["driver"]["rules"]
.as_array()
.unwrap();
assert_eq!(rules.len(), 3);
}
#[test]
fn test_format_sarif_multiple_severity_levels() {
let hotspots = vec![
create_test_hotspot("src/critical.rs", 3.0, "complexity", 10.0),
create_test_hotspot("src/warning.rs", 2.0, "churn", 5.0),
create_test_hotspot("src/note.rs", 1.0, "none", 2.0),
];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let results = sarif["runs"][0]["results"].as_array().unwrap();
assert_eq!(results[0]["level"], "error");
assert_eq!(results[1]["level"], "warning");
assert_eq!(results[2]["level"], "note");
}
#[test]
fn test_format_sarif_boundary_values() {
let hotspots = vec![
create_test_hotspot("src/exactly_2.5.rs", 2.5, "boundary", 5.0),
create_test_hotspot("src/exactly_1.5.rs", 1.5, "boundary", 3.0),
];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/")).unwrap();
let sarif: serde_json::Value = serde_json::from_str(&result).unwrap();
let results = sarif["runs"][0]["results"].as_array().unwrap();
assert_eq!(results[0]["level"], "warning");
assert_eq!(results[0]["ruleId"], "high-tdg");
assert_eq!(results[1]["level"], "note");
assert_eq!(results[1]["ruleId"], "moderate-tdg");
}
}
mod internal_helpers_tests {
use super::*;
#[test]
fn test_calculate_component_score() {
assert!((calculate_component_score(10.0, 0.4) - 4.0).abs() < f64::EPSILON);
assert!((calculate_component_score(10.0, 0.3) - 3.0).abs() < f64::EPSILON);
assert!((calculate_component_score(10.0, 0.2) - 2.0).abs() < f64::EPSILON);
assert!((calculate_component_score(10.0, 0.1) - 1.0).abs() < f64::EPSILON);
}
#[test]
fn test_calculate_component_score_zero() {
assert!((calculate_component_score(0.0, 0.5)).abs() < f64::EPSILON);
assert!((calculate_component_score(5.0, 0.0)).abs() < f64::EPSILON);
}
#[test]
fn test_write_tdg_header() {
let mut output = String::new();
write_tdg_header(&mut output).unwrap();
assert!(output.contains("# Technical Debt Gradient Analysis"));
}
#[test]
fn test_write_tdg_summary() {
let mut output = String::new();
let summary = create_test_summary();
write_tdg_summary(&mut output, &summary).unwrap();
assert!(output.contains("## Summary"));
assert!(output.contains("**Total Files**: 100"));
}
#[test]
fn test_write_hotspot_basic_info() {
let mut output = String::new();
let hotspot = create_test_hotspot("src/test.rs", 2.5, "complexity", 5.0);
write_hotspot_basic_info(&mut output, &hotspot).unwrap();
assert!(output.contains("**TDG Score**: 2.500"));
assert!(output.contains("**Primary Factor**: complexity"));
}
#[test]
fn test_write_component_breakdown() {
let mut output = String::new();
let hotspot = create_test_hotspot("src/test.rs", 2.0, "complexity", 5.0);
write_component_breakdown(&mut output, &hotspot).unwrap();
assert!(output.contains("#### Component Breakdown:"));
assert!(output.contains("Complexity: 0.800"));
}
#[test]
fn test_write_single_hotspot_with_components() {
let mut output = String::new();
let hotspot = create_test_hotspot("src/test.rs", 2.0, "complexity", 5.0);
write_single_hotspot(&mut output, 1, &hotspot, true).unwrap();
assert!(output.contains("### 1. src/test.rs"));
assert!(output.contains("Component Breakdown"));
}
#[test]
fn test_write_single_hotspot_without_components() {
let mut output = String::new();
let hotspot = create_test_hotspot("src/test.rs", 2.0, "complexity", 5.0);
write_single_hotspot(&mut output, 1, &hotspot, false).unwrap();
assert!(output.contains("### 1. src/test.rs"));
assert!(!output.contains("Component Breakdown"));
}
#[test]
fn test_write_tdg_hotspots() {
let mut output = String::new();
let hotspots = vec![
create_test_hotspot("src/a.rs", 3.0, "complexity", 10.0),
create_test_hotspot("src/b.rs", 2.0, "churn", 5.0),
];
write_tdg_hotspots(&mut output, &hotspots, false).unwrap();
assert!(output.contains("## Top Hotspots"));
assert!(output.contains("### 1. src/a.rs"));
assert!(output.contains("### 2. src/b.rs"));
}
#[test]
fn test_generate_tdg_rules() {
let rules = generate_tdg_rules();
assert_eq!(rules.len(), 3);
let rule_ids: Vec<&str> = rules.iter().map(|r| r["id"].as_str().unwrap()).collect();
assert!(rule_ids.contains(&"critical-tdg"));
assert!(rule_ids.contains(&"high-tdg"));
assert!(rule_ids.contains(&"moderate-tdg"));
assert_eq!(
rules[0]["defaultConfiguration"]["level"].as_str().unwrap(),
"error"
);
assert_eq!(
rules[1]["defaultConfiguration"]["level"].as_str().unwrap(),
"warning"
);
assert_eq!(
rules[2]["defaultConfiguration"]["level"].as_str().unwrap(),
"note"
);
}
}
mod edge_case_tests {
use super::*;
#[test]
fn test_hotspot_with_empty_path() {
let hotspots = vec![create_test_hotspot("", 2.0, "complexity", 5.0)];
let result = format_tdg_table(&hotspots, false);
assert!(result.is_ok());
}
#[test]
fn test_hotspot_with_special_characters_in_path() {
let hotspots = vec![create_test_hotspot(
"src/my file (1).rs",
2.0,
"complexity",
5.0,
)];
let result = format_tdg_json(&create_test_summary(), &hotspots, false);
assert!(result.is_ok());
}
#[test]
fn test_hotspot_with_unicode_path() {
let hotspots = vec![create_test_hotspot("src/日本語.rs", 2.0, "complexity", 5.0)];
let result = format_tdg_table(&hotspots, false);
assert!(result.is_ok());
}
#[test]
fn test_summary_with_zero_values() {
let summary = TDGSummary {
total_files: 0,
critical_files: 0,
warning_files: 0,
average_tdg: 0.0,
p95_tdg: 0.0,
p99_tdg: 0.0,
estimated_debt_hours: 0.0,
hotspots: vec![],
};
let result = format_tdg_markdown(&summary, &[], false);
assert!(result.is_ok());
}
#[test]
fn test_hotspot_with_very_high_score() {
let hotspots = vec![create_test_hotspot(
"src/test.rs",
999.99,
"complexity",
1000.0,
)];
let result = format_tdg_sarif(&hotspots, &PathBuf::from("/"));
assert!(result.is_ok());
let sarif_str = result.unwrap();
let sarif: serde_json::Value = serde_json::from_str(&sarif_str).unwrap();
assert_eq!(sarif["runs"][0]["results"][0]["level"], "error");
}
#[test]
fn test_hotspot_with_zero_score() {
let hotspots = vec![create_test_hotspot("src/test.rs", 0.0, "none", 0.0)];
let result = format_tdg_table(&hotspots, true).unwrap();
assert!(result.contains("0.00"));
}
#[test]
fn test_hotspot_with_negative_score() {
let hotspots = vec![create_test_hotspot("src/test.rs", -1.0, "none", 0.0)];
let result = format_tdg_table(&hotspots, false).unwrap();
assert!(result.contains("-1.00"));
}
#[test]
fn test_very_long_primary_factor() {
let long_factor = "a".repeat(1000);
let hotspots = vec![create_test_hotspot("src/test.rs", 2.0, &long_factor, 5.0)];
let result = format_tdg_table(&hotspots, false);
assert!(result.is_ok());
}
#[test]
fn test_special_chars_in_factor() {
let hotspots = vec![create_test_hotspot("src/test.rs", 2.0, "factor<>\"'&", 5.0)];
let result = format_tdg_json(&create_test_summary(), &hotspots, false);
assert!(result.is_ok());
let json_str = result.unwrap();
assert!(serde_json::from_str::<serde_json::Value>(&json_str).is_ok());
}
}
mod integration_tests {
use super::*;
#[test]
fn test_full_workflow_json() {
let summary = create_test_summary();
let hotspots = create_test_hotspots();
let filtered = filter_tdg_hotspots(hotspots, 2.0, 3, false);
assert_eq!(filtered.len(), 3);
let json = format_tdg_json(&summary, &filtered, true).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["hotspots"].as_array().unwrap().len(), 3);
assert!(parsed["components"].is_object());
}
#[test]
fn test_full_workflow_markdown() {
let summary = create_test_summary();
let hotspots = create_test_hotspots();
let filtered = filter_tdg_hotspots(hotspots, 1.0, 0, false);
let md = format_tdg_markdown(&summary, &filtered, true).unwrap();
assert!(md.contains("# Technical Debt Gradient Analysis"));
assert!(md.contains("## Summary"));
assert!(md.contains("## Top Hotspots"));
assert!(md.contains("Component Breakdown"));
}
#[test]
fn test_full_workflow_sarif() {
let hotspots = create_test_hotspots();
let filtered = filter_tdg_hotspots(hotspots, 0.0, 0, false);
let sarif = format_tdg_sarif(&filtered, &PathBuf::from("/project")).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&sarif).unwrap();
assert_eq!(parsed["runs"][0]["results"].as_array().unwrap().len(), 5);
}
#[test]
fn test_all_formats_produce_valid_output() {
let summary = create_test_summary();
let hotspots = create_test_hotspots();
assert!(format_tdg_json(&summary, &hotspots, false).is_ok());
assert!(format_tdg_json(&summary, &hotspots, true).is_ok());
assert!(format_tdg_table(&hotspots, false).is_ok());
assert!(format_tdg_table(&hotspots, true).is_ok());
assert!(format_tdg_markdown(&summary, &hotspots, false).is_ok());
assert!(format_tdg_markdown(&summary, &hotspots, true).is_ok());
assert!(format_tdg_sarif(&hotspots, &PathBuf::from("/")).is_ok());
let json = format_tdg_json(&summary, &hotspots, true).unwrap();
assert!(serde_json::from_str::<serde_json::Value>(&json).is_ok());
let sarif = format_tdg_sarif(&hotspots, &PathBuf::from("/")).unwrap();
assert!(serde_json::from_str::<serde_json::Value>(&sarif).is_ok());
}
}