use super::AnalysisResult;
use crate::falsification::TestResult;
pub fn generate_html_report(analysis: &AnalysisResult) -> String {
let test_rows = format_test_rows(&analysis.falsification_report);
let bug_list = format_bug_list(&analysis.bugs);
format!(
r#"<!DOCTYPE html>
<html>
<head>
<title>PTX Analysis Report - {module_name}</title>
<style>
body {{ font-family: system-ui, -apple-system, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; }}
h1 {{ color: #333; }}
.score {{ font-size: 3em; font-weight: bold; }}
.score-good {{ color: #28a745; }}
.score-warning {{ color: #ffc107; }}
.score-bad {{ color: #dc3545; }}
table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }}
th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
th {{ background-color: #f4f4f4; }}
.pass {{ background-color: #d4edda; }}
.fail {{ background-color: #f8d7da; }}
.na {{ background-color: #e2e3e5; }}
.critical {{ background-color: #f5c6cb; color: #721c24; }}
.high {{ background-color: #ffeeba; color: #856404; }}
.medium {{ background-color: #bee5eb; color: #0c5460; }}
.summary {{ display: flex; gap: 40px; align-items: center; }}
.metric {{ text-align: center; }}
.metric-value {{ font-size: 2em; font-weight: bold; }}
.metric-label {{ color: #666; }}
</style>
</head>
<body>
<h1>PTX Analysis Report</h1>
<h2>{module_name}</h2>
<div class="summary">
<div class="metric">
<div class="metric-value {score_class}">{score:.1}</div>
<div class="metric-label">Falsification Score</div>
</div>
<div class="metric">
<div class="metric-value">{confidence:.1}%</div>
<div class="metric-label">Confidence</div>
</div>
<div class="metric">
<div class="metric-value">{earned}/{total}</div>
<div class="metric-label">Points Earned</div>
</div>
</div>
<h2>Falsification Results</h2>
<table>
<tr>
<th>ID</th>
<th>Category</th>
<th>Test</th>
<th>Result</th>
<th>Evidence</th>
</tr>
{test_rows}
</table>
<h2>Detected Bugs</h2>
{bug_list}
<footer>
<p>Generated by trueno-ptx-debug v{version}</p>
<p>Based on Popperian Falsification Framework</p>
</footer>
</body>
</html>"#,
module_name = analysis.module_name,
score = analysis.falsification_score,
score_class = if analysis.falsification_score >= 90.0 {
"score-good"
} else if analysis.falsification_score >= 70.0 {
"score-warning"
} else {
"score-bad"
},
confidence = analysis.confidence * 100.0,
earned = analysis.falsification_report.earned_points,
total = analysis.falsification_report.total_points,
test_rows = test_rows,
bug_list = bug_list,
version = env!("CARGO_PKG_VERSION"),
)
}
fn format_test_rows(report: &crate::falsification::FalsificationReport) -> String {
report
.results
.iter()
.map(|(id, category, description, result)| {
let (class, result_text, evidence) = match result {
TestResult::Pass => ("pass", "PASS", String::new()),
TestResult::Fail { evidence, .. } => ("fail", "FAIL", evidence.clone()),
TestResult::NotApplicable => ("na", "N/A", String::new()),
};
format!(
"<tr class=\"{}\"><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>",
class, id, category, description, result_text, evidence
)
})
.collect::<Vec<_>>()
.join("\n ")
}
fn format_bug_list(bugs: &crate::bugs::BugRegistry) -> String {
if bugs.bugs().is_empty() {
return "<p>No bugs detected.</p>".to_string();
}
let items: Vec<_> = bugs
.bugs()
.iter()
.map(|bug| {
format!(
"<li class=\"{}\"><strong>{}:</strong> {} at {}</li>",
match bug.class.severity() {
crate::bugs::Severity::Critical => "critical",
crate::bugs::Severity::High => "high",
crate::bugs::Severity::Medium => "medium",
crate::bugs::Severity::Low => "",
},
bug.class,
bug.message,
bug.location
)
})
.collect();
format!("<ul>\n {}\n </ul>", items.join("\n "))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bugs::BugRegistry;
use crate::falsification::FalsificationRegistry;
use crate::parser::Parser;
#[test]
fn test_html_report_generation() {
let ptx = r#"
.version 8.0
.target sm_70
.address_size 64
.entry test() { ret; }
"#;
let mut parser = Parser::new(ptx).expect("parser creation should succeed");
let module = parser.parse().expect("parsing should succeed");
let registry = FalsificationRegistry::new();
let report = registry.evaluate(&module);
let result = AnalysisResult::new("test_kernel", report, BugRegistry::new());
let html = generate_html_report(&result);
assert!(html.contains("PTX Analysis Report"));
assert!(html.contains("test_kernel"));
assert!(html.contains("Falsification Score"));
}
}