aprender-ptx-debug 0.37.0

Pure Rust PTX debugging and static analysis tool
Documentation
//! HTML Report Generation

use super::AnalysisResult;
use crate::falsification::TestResult;

/// Generate HTML analysis report
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"));
    }
}