use debtmap::priority::formatter::format_priorities_with_verbosity;
use debtmap::priority::{
CallGraph, DebtType, FunctionRole, ImpactMetrics, Location, OutputFormat, UnifiedAnalysis,
UnifiedAnalysisUtils, UnifiedDebtItem, UnifiedScore,
};
use std::path::PathBuf;
fn create_untested_item() -> UnifiedDebtItem {
UnifiedDebtItem {
location: Location {
file: PathBuf::from("src/main.rs"),
function: "untested_function".to_string(),
line: 100,
},
debt_type: DebtType::TestingGap {
coverage: 0.0,
cyclomatic: 15,
cognitive: 20,
},
unified_score: UnifiedScore {
complexity_factor: 7.5,
coverage_factor: 10.0, dependency_factor: 4.0,
role_multiplier: 1.0,
final_score: 85.0,
base_score: None,
exponential_factor: None,
risk_boost: None,
pre_adjustment_score: None,
adjustment_applied: None,
purity_factor: None,
refactorability_factor: None,
pattern_factor: None,
debt_adjustment: None,
pre_normalization_score: None,
structural_multiplier: Some(1.0),
has_coverage_data: false,
contextual_risk_multiplier: None,
pre_contextual_score: None,
debt_type_multiplier: None,
},
function_role: FunctionRole::PureLogic,
recommendation: debtmap::priority::ActionableRecommendation {
primary_action: "Add unit tests".to_string(),
rationale: "Function is untested".to_string(),
implementation_steps: vec![],
related_items: vec![],
steps: None,
estimated_effort_hours: None,
},
expected_impact: ImpactMetrics {
coverage_improvement: 100.0,
lines_reduction: 0,
complexity_reduction: 0.0,
risk_reduction: 50.0,
},
transitive_coverage: None, file_context: None,
upstream_dependencies: 2,
downstream_dependencies: 3,
upstream_callers: vec![],
downstream_callees: vec![],
upstream_production_callers: vec![],
upstream_test_callers: vec![],
production_blast_radius: 0,
nesting_depth: 3,
function_length: 50,
cyclomatic_complexity: 15,
cognitive_complexity: 20,
is_pure: None,
purity_confidence: None,
purity_level: None,
god_object_indicators: None,
tier: None,
function_context: None,
context_confidence: None,
contextual_recommendation: None,
pattern_analysis: None,
context_multiplier: None,
context_type: None,
language_specific: None, detected_pattern: None,
contextual_risk: None, file_line_count: None,
responsibility_category: None,
error_swallowing_count: None,
error_swallowing_patterns: None,
entropy_analysis: None,
context_suggestion: None,
}
}
#[test]
fn test_untested_labels_hidden_when_no_coverage_data() {
let call_graph = CallGraph::new();
let mut analysis = UnifiedAnalysis::new(call_graph);
analysis.has_coverage_data = false;
let item = create_untested_item();
analysis.add_item(item);
analysis.sort_by_priority();
let output = format_priorities_with_verbosity(&analysis, OutputFormat::Top(1), 0);
assert!(
!output.contains("UNTESTED"),
"Output should not contain UNTESTED label when has_coverage_data=false. Output:\n{}",
output
);
assert!(
!output.contains("🔴"),
"Output should not contain red circle emoji when has_coverage_data=false. Output:\n{}",
output
);
assert!(
!output.contains("LOW COVERAGE"),
"Output should not contain LOW COVERAGE label when has_coverage_data=false. Output:\n{}",
output
);
assert!(
!output.contains("PARTIAL COVERAGE"),
"Output should not contain PARTIAL COVERAGE label when has_coverage_data=false. Output:\n{}",
output
);
}
#[test]
fn test_untested_labels_shown_when_coverage_data_available() {
let call_graph = CallGraph::new();
let mut analysis = UnifiedAnalysis::new(call_graph);
analysis.has_coverage_data = true;
let item = create_untested_item();
analysis.add_item(item);
analysis.sort_by_priority();
let output = format_priorities_with_verbosity(&analysis, OutputFormat::Top(1), 0);
assert!(
output.contains("COVERAGE"),
"Output should contain COVERAGE line when has_coverage_data=true. Output:\n{}",
output
);
assert!(
output.contains("no coverage data"),
"Output should show 'no coverage data' when function not found in LCOV. Output:\n{}",
output
);
}
#[test]
fn test_coverage_indicator_hidden_in_unified_analysis_without_coverage() {
let call_graph = CallGraph::new();
let mut analysis = UnifiedAnalysis::new(call_graph);
analysis.has_coverage_data = false;
let item = create_untested_item();
analysis.add_item(item);
analysis.sort_by_priority();
let output = format_priorities_with_verbosity(&analysis, OutputFormat::Top(1), 0);
assert!(
!output.contains("UNTESTED"),
"UnifiedAnalysis with has_coverage_data=false should not show UNTESTED. Output:\n{}",
output
);
assert!(
!output.contains("🔴"),
"UnifiedAnalysis with has_coverage_data=false should not show coverage emoji. Output:\n{}",
output
);
}
#[test]
fn test_coverage_scoring_factors_hidden_without_coverage_data() {
let call_graph = CallGraph::new();
let mut analysis = UnifiedAnalysis::new(call_graph);
analysis.has_coverage_data = false;
let item = create_untested_item();
analysis.add_item(item);
analysis.sort_by_priority();
let output = format_priorities_with_verbosity(&analysis, OutputFormat::Top(1), 1);
let lines: Vec<&str> = output.lines().collect();
let factors_line = lines
.iter()
.find(|line| line.contains("Main factors:"))
.unwrap_or(&"");
assert!(
!factors_line.contains("UNTESTED"),
"Main factors should not mention UNTESTED when has_coverage_data=false. Factors line: {}",
factors_line
);
assert!(
!factors_line.contains("coverage"),
"Main factors should not mention coverage when has_coverage_data=false. Factors line: {}",
factors_line
);
}
#[test]
fn test_detailed_score_calculation_respects_coverage_flag() {
let call_graph_with = CallGraph::new();
let mut analysis_with = UnifiedAnalysis::new(call_graph_with);
analysis_with.has_coverage_data = true;
let item1 = create_untested_item();
analysis_with.add_item(item1);
analysis_with.sort_by_priority();
let call_graph_without = CallGraph::new();
let mut analysis_without = UnifiedAnalysis::new(call_graph_without);
analysis_without.has_coverage_data = false;
let item2 = create_untested_item();
analysis_without.add_item(item2);
analysis_without.sort_by_priority();
let output_with_coverage =
format_priorities_with_verbosity(&analysis_with, OutputFormat::Top(1), 2);
let output_without_coverage =
format_priorities_with_verbosity(&analysis_without, OutputFormat::Top(1), 2);
assert!(output_with_coverage.contains("SCORE CALCULATION:"));
assert!(output_without_coverage.contains("SCORE CALCULATION:"));
assert!(
output_with_coverage.contains("UNTESTED") || output_with_coverage.contains("coverage"),
"With coverage data, should mention coverage"
);
assert!(
!output_without_coverage.contains("[UNTESTED]"),
"Without coverage data, should not show [UNTESTED] label"
);
}