use super::types::{ExplainCoverageResult, StrategyAttempt};
pub fn format_header(result: &ExplainCoverageResult) -> String {
let mut output = String::new();
output.push_str("Coverage Detection Explanation\n");
output.push_str("==============================\n\n");
output.push_str(&format!("Function: {}\n", result.function_name));
if let Some(ref file) = result.file_path {
output.push_str(&format!("File: {}\n", file));
}
output.push('\n');
output
}
pub fn format_coverage_status(result: &ExplainCoverageResult) -> String {
if result.coverage_found {
format!(
"✓ Coverage Found!\n Strategy: {}\n Coverage: {:.1}%\n\n",
result.matched_by_strategy.as_ref().unwrap(),
result.coverage_percentage.unwrap() * 100.0
)
} else {
"✗ Coverage Not Found\n\n".to_string()
}
}
pub fn format_attempt(attempt: &StrategyAttempt) -> String {
let status = if attempt.success { "✓" } else { "✗" };
let mut output = format!(" {} {}\n", status, attempt.strategy);
if attempt.success {
if let Some(ref matched_file) = attempt.matched_file {
output.push_str(&format!(" File: {}\n", matched_file));
}
if let Some(ref matched_func) = attempt.matched_function {
output.push_str(&format!(" Function: {}\n", matched_func));
}
if let Some(coverage) = attempt.coverage_percentage {
output.push_str(&format!(" Coverage: {:.1}%\n", coverage * 100.0));
}
}
output
}
pub fn format_matching_attempts(attempts: &[StrategyAttempt]) -> String {
let mut output = String::from("Matching Attempts:\n------------------\n");
for attempt in attempts {
output.push_str(&format_attempt(attempt));
}
output.push('\n');
output
}
pub fn format_truncated_list<T: AsRef<str>>(items: &[T], limit: usize) -> String {
let mut output = String::new();
for (i, item) in items.iter().take(limit).enumerate() {
output.push_str(&format!(" {}. {}\n", i + 1, item.as_ref()));
}
if items.len() > limit {
output.push_str(&format!(" ... and {} more\n", items.len() - limit));
}
output
}
pub fn format_available_files(files: &[String]) -> String {
let mut output = format!("Available Files in LCOV ({} total):\n", files.len());
output.push_str("----------------------------------\n");
output.push_str(&format_truncated_list(files, 10));
output.push('\n');
output
}
pub fn find_matching_functions<'a>(
function_name: &str,
available_functions: &'a [String],
) -> Vec<&'a String> {
let query = function_name.to_lowercase();
available_functions
.iter()
.filter(|f| f.to_lowercase().contains(&query))
.collect()
}
pub fn format_function_matches(function_name: &str, matching: &[&String]) -> String {
let mut output = format!(" Functions containing '{}':\n", function_name);
for func in matching.iter().take(10) {
output.push_str(&format!(" - {}\n", func));
}
if matching.len() > 10 {
output.push_str(&format!(" ... and {} more\n", matching.len() - 10));
}
output
}
pub fn format_first_functions(available_functions: &[String]) -> String {
let mut output = String::from(" First 10 available functions:\n");
for func in available_functions.iter().take(10) {
output.push_str(&format!(" - {}\n", func));
}
if available_functions.len() > 10 {
output.push_str(&format!(
" ... and {} more\n",
available_functions.len() - 10
));
}
output
}
pub fn format_available_functions(result: &ExplainCoverageResult) -> String {
let mut output = format!(
"Available Functions in LCOV ({} total):\n",
result.available_functions.len()
);
output.push_str("--------------------------------------\n");
let matching = find_matching_functions(&result.function_name, &result.available_functions);
if !matching.is_empty() {
output.push_str(&format_function_matches(&result.function_name, &matching));
} else {
output.push_str(&format!(
" No functions found containing '{}'\n\n",
result.function_name
));
output.push_str(&format_first_functions(&result.available_functions));
}
output
}
pub fn format_text_report(result: &ExplainCoverageResult, verbose: bool) -> String {
let mut output = format_header(result);
output.push_str(&format_coverage_status(result));
if verbose || !result.coverage_found {
output.push_str(&format_matching_attempts(&result.attempts));
}
if !result.coverage_found {
output.push_str(&format_available_files(&result.available_files));
output.push_str(&format_available_functions(result));
}
output
}