use serde_json::Value;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
use tempfile::TempDir;
fn debtmap_command() -> Command {
Command::new(env!("CARGO_BIN_EXE_debtmap"))
}
#[test]
#[ignore = "environment: requires target/coverage/lcov.info and full-repository analysis"]
fn test_coverage_matching_integration() {
let coverage_file = PathBuf::from("target/coverage/lcov.info");
if !coverage_file.exists() {
println!(
"Skipping test: coverage file not found at {}",
coverage_file.display()
);
return;
}
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.path().join("analysis_output.json");
let output = debtmap_command()
.args([
"analyze",
".",
"--format",
"json",
"--coverage-file",
coverage_file.to_str().unwrap(),
"--output",
output_path.to_str().unwrap(),
])
.output()
.expect("Failed to execute debtmap command");
if !output.status.success() {
eprintln!("stdout: {}", String::from_utf8_lossy(&output.stdout));
eprintln!("stderr: {}", String::from_utf8_lossy(&output.stderr));
panic!("debtmap analyze command failed");
}
let output_content = fs::read_to_string(&output_path).expect("Failed to read output file");
let json: Value = serde_json::from_str(&output_content).expect("Output is not valid JSON");
let items = json
.get("items")
.expect("Missing items section")
.as_array()
.expect("items should be an array");
let trait_method_item = items.iter().find(|item| {
let location = item.get("location");
if let Some(loc) = location {
let function = loc.get("function").and_then(|f| f.as_str()).unwrap_or("");
if !function.contains("::") {
return false;
}
if let Some(metrics) = item.get("metrics")
&& let Some(coverage) = metrics.get("coverage")
{
return !coverage.is_null();
}
false
} else {
false
}
});
if let Some(item) = trait_method_item {
let metrics = item
.get("metrics")
.expect("Debt item missing 'metrics' field");
let function_name = item
.get("location")
.and_then(|l| l.get("function"))
.and_then(|f| f.as_str())
.unwrap_or("unknown");
let coverage = metrics.get("coverage").expect("Coverage should exist");
assert!(
!coverage.is_null(),
"Coverage is null for trait method {} - \
should show actual coverage via name variant matching",
function_name
);
if let Some(cov_pct) = coverage.as_f64() {
assert!(
(0.0..=1.0).contains(&cov_pct),
"Coverage should be between 0 and 1 for {}, got {}",
function_name,
cov_pct
);
}
if let Some(recommendation) = item.get("recommendation") {
let rec_text = recommendation
.get("description")
.and_then(|d| d.as_str())
.unwrap_or("");
assert!(
!rec_text.contains("no coverage data"),
"Recommendation should not claim 'no coverage data' for trait method with coverage"
);
}
} else {
println!(
"Note: no trait method implementations with coverage data found in analysis output. \
This is expected if all trait methods are below complexity thresholds or not covered."
);
}
let functions_with_coverage = items
.iter()
.filter(|item| {
item.get("type")
.and_then(|t| t.as_str())
.map(|t| t == "Function")
.unwrap_or(false)
})
.filter(|item| {
item.get("metrics")
.and_then(|m| m.get("coverage"))
.map(|c| !c.is_null())
.unwrap_or(false)
})
.count();
assert!(
functions_with_coverage > 10,
"Should find coverage for many functions (found {}), \
variant matching may have broken regular coverage lookup",
functions_with_coverage
);
}
#[test]
#[ignore = "environment: requires target/coverage/lcov.info and full-repository analysis"]
fn test_explain_coverage_finds_trait_method() {
let coverage_file = PathBuf::from("target/coverage/lcov.info");
if !coverage_file.exists() {
println!(
"Skipping test: coverage file not found at {}",
coverage_file.display()
);
return;
}
let output = debtmap_command()
.args([
"explain-coverage",
".",
"--coverage-file",
coverage_file.to_str().unwrap(),
"--function",
"visit_expr",
"--file",
"src/complexity/recursive_detector.rs",
])
.output()
.expect("Failed to execute debtmap explain-coverage command");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
if !output.status.success() {
eprintln!("stdout: {}", stdout);
eprintln!("stderr: {}", stderr);
panic!("debtmap explain-coverage command failed");
}
assert!(
stdout.contains("Coverage Found") || stdout.contains("✓"),
"explain-coverage should find coverage for visit_expr method, got:\n{}",
stdout
);
assert!(
stdout.contains("Coverage:") || stdout.contains("%"),
"explain-coverage should report coverage percentage, got:\n{}",
stdout
);
assert!(
!stdout.contains("No coverage found") && !stderr.contains("No coverage found"),
"Should not report 'No coverage found' for visit_expr"
);
}