fn pct_or_unmeasured(value: Option<f64>) -> String {
value.map_or_else(|| "not measured".to_string(), |v| format!("{v:.1}%"))
}
fn delta_or_unmeasured(value: Option<f64>) -> String {
value.map_or_else(|| "not measured".to_string(), |v| format!("{v:+.1}%"))
}
fn format_summary(result: &IncrementalCoverageResult, top_files: usize) -> String {
let mut output = String::new();
output.push_str("# Incremental Coverage Summary\n\n");
output.push_str(&result.summary);
output.push_str("\n\n## Top Changed Files\n");
for (i, file) in result.changed_files.iter().take(top_files).enumerate() {
output.push_str(&format!(
"{}. {} - {} → {} (Δ{})\n",
i + 1,
file.file_path,
pct_or_unmeasured(file.coverage_before),
pct_or_unmeasured(file.coverage_after),
delta_or_unmeasured(file.coverage_delta)
));
}
output
}
fn format_detailed(result: &IncrementalCoverageResult, top_files: usize) -> String {
let mut output = String::new();
output.push_str("# Incremental Coverage Detailed Report\n\n");
output.push_str(&format!("Total files analyzed: {}\n", result.total_files));
output.push_str(&format!("Files with coverage: {}\n", result.covered_files));
output.push_str(&format!(
"Overall coverage: {}\n",
pct_or_unmeasured(result.coverage_percentage)
));
output.push_str(&format!(
"Files above threshold: {}\n",
result.files_above_threshold
));
output.push_str(&format!(
"Files below threshold: {}\n",
result.files_below_threshold
));
output.push_str(&format!(
"Files not measured: {}\n\n",
result.files_not_measured
));
output.push_str(&format!("## Changed Files (Top {top_files})\n"));
for file in result.changed_files.iter().take(top_files) {
output.push_str(&format!("\n### {}\n", file.file_path));
output.push_str(&format!("- Status: {:?}\n", file.status));
output.push_str(&format!(
"- Coverage: {} → {}\n",
pct_or_unmeasured(file.coverage_before),
pct_or_unmeasured(file.coverage_after)
));
output.push_str(&format!(
"- Delta: {}\n",
delta_or_unmeasured(file.coverage_delta)
));
output.push_str(&format!(
"- Lines: {}/{}\n",
file.lines_covered, file.lines_total
));
}
output
}
fn format_markdown(result: &IncrementalCoverageResult, top_files: usize) -> String {
let mut output = String::new();
output.push_str("# Incremental Coverage Report\n\n");
output.push_str(&format!("**Summary:** {}\n\n", result.summary));
output.push_str("## Metrics\n\n");
output.push_str("| Metric | Value |\n");
output.push_str("|--------|-------|\n");
output.push_str(&format!("| Total Files | {} |\n", result.total_files));
output.push_str(&format!("| Covered Files | {} |\n", result.covered_files));
output.push_str(&format!(
"| Coverage | {} |\n",
pct_or_unmeasured(result.coverage_percentage)
));
output.push_str(&format!(
"| Above Threshold | {} |\n",
result.files_above_threshold
));
output.push_str(&format!(
"| Below Threshold | {} |\n",
result.files_below_threshold
));
output.push_str(&format!(
"| Not Measured | {} |\n\n",
result.files_not_measured
));
output.push_str("## Top Changed Files\n\n");
output.push_str("| File | Before | After | Delta | Status |\n");
output.push_str("|------|--------|-------|-------|--------|\n");
for file in result.changed_files.iter().take(top_files) {
output.push_str(&format!(
"| {} | {} | {} | {} | {:?} |\n",
file.file_path,
pct_or_unmeasured(file.coverage_before),
pct_or_unmeasured(file.coverage_after),
delta_or_unmeasured(file.coverage_delta),
file.status
));
}
output
}
fn format_lcov(result: &IncrementalCoverageResult) -> String {
let mut output = String::new();
for file in result
.changed_files
.iter()
.filter(|f| f.coverage_after.is_some())
{
output.push_str(&format!("SF:{}\n", file.file_path));
output.push_str(&format!("LH:{}\n", file.lines_covered));
output.push_str(&format!("LF:{}\n", file.lines_total));
output.push_str("end_of_record\n");
}
output
}
fn format_delta(result: &IncrementalCoverageResult, top_files: usize) -> String {
let mut output = String::new();
output.push_str("Coverage Delta Report\n");
output.push_str("====================\n\n");
let improved: Vec<_> = result
.changed_files
.iter()
.filter(|f| f.coverage_delta.is_some_and(|d| d > 0.0))
.take(top_files)
.collect();
let degraded: Vec<_> = result
.changed_files
.iter()
.filter(|f| f.coverage_delta.is_some_and(|d| d < 0.0))
.take(top_files)
.collect();
let unmeasured = result
.changed_files
.iter()
.filter(|f| f.coverage_delta.is_none())
.count();
if !improved.is_empty() {
output.push_str("✅ Improved Coverage:\n");
for file in improved {
output.push_str(&format!(
" {} {}\n",
file.file_path,
delta_or_unmeasured(file.coverage_delta)
));
}
output.push('\n');
}
if !degraded.is_empty() {
output.push_str("⚠️ Degraded Coverage:\n");
for file in degraded {
output.push_str(&format!(
" {} {}\n",
file.file_path,
delta_or_unmeasured(file.coverage_delta)
));
}
output.push('\n');
}
if unmeasured > 0 {
output.push_str(&format!(
"ℹ️ {unmeasured} changed file(s) had no coverage data; delta not measured.\n"
));
}
output
}
fn format_sarif(result: &IncrementalCoverageResult) -> String {
serde_json::json!({
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [{
"tool": {
"driver": {
"name": "pmat-incremental-coverage",
"version": env!("CARGO_PKG_VERSION"),
"informationUri": "https://github.com/paiml/paiml-mcp-agent-toolkit"
}
},
"results": result.changed_files.iter().filter_map(|file| {
let delta = file.coverage_delta?;
if delta >= 0.0 {
return None;
}
Some(serde_json::json!({
"ruleId": "coverage-degradation",
"level": "warning",
"message": {
"text": format!(
"Coverage degraded by {:.1}% (from {} to {})",
delta.abs(),
pct_or_unmeasured(file.coverage_before),
pct_or_unmeasured(file.coverage_after)
)
},
"locations": [{
"physicalLocation": {
"artifactLocation": {
"uri": file.file_path.clone()
}
}
}]
}))
}).collect::<Vec<_>>()
}]
})
.to_string()
}