| """Tests for report.html — generate_html_report, _aggregate, _render_finding."""
|
| import pytest
|
|
|
| from report.html import generate_html_report
|
|
|
|
|
| def _finding(**kwargs) -> dict:
|
| defaults = dict(
|
| tool="bandit", rule="B101", severity="WARNING",
|
| confidence="likely", file="test.py", line=10,
|
| message="Shell injection risk",
|
| owasp=["A01:2021-Broken_Access_Control"],
|
| category="security",
|
| remediation="Use subprocess.run without shell=True",
|
| )
|
| defaults.update(kwargs)
|
| return defaults
|
|
|
|
|
| class TestGenerateHtmlReport:
|
| def test_returns_string(self):
|
| html = generate_html_report([], {})
|
| assert isinstance(html, str)
|
|
|
| def test_contains_html_tag(self):
|
| html = generate_html_report([], {})
|
| assert "<html" in html.lower() or "<!doctype" in html.lower()
|
|
|
| def test_empty_findings_produces_zero_count(self):
|
| html = generate_html_report([], {"title": "Empty Test"})
|
|
|
| assert "0" in html
|
|
|
| def test_finding_message_in_output(self):
|
| f = _finding(message="Hardcoded password detected")
|
| html = generate_html_report([f], {})
|
| assert "Hardcoded password detected" in html
|
|
|
| def test_owasp_badge_rendered(self):
|
| f = _finding(owasp=["A01:2021-Broken_Access_Control"])
|
| html = generate_html_report([f], {})
|
| assert "A01" in html
|
|
|
| def test_unmapped_owasp_excluded_from_badge(self):
|
| f = _finding(owasp=["UNMAPPED"])
|
| html = generate_html_report([f], {})
|
| assert "UNMAPPED" not in html
|
|
|
| def test_remediation_rendered(self):
|
| f = _finding(remediation="Upgrade the vulnerable dependency to >=2.0")
|
| html = generate_html_report([f], {})
|
| assert "Upgrade the vulnerable dependency" in html
|
|
|
| def test_finding_without_remediation(self):
|
| f = _finding(remediation="")
|
| html = generate_html_report([f], {})
|
| assert isinstance(html, str)
|
|
|
| def test_severity_high_preserved(self):
|
| f = _finding(severity="HIGH")
|
| html = generate_html_report([f], {})
|
| assert "HIGH" in html
|
|
|
| def test_severity_medium_preserved(self):
|
| f = _finding(severity="MEDIUM")
|
| html = generate_html_report([f], {})
|
| assert "MEDIUM" in html
|
|
|
| def test_severity_low_preserved(self):
|
| f = _finding(severity="LOW")
|
| html = generate_html_report([f], {})
|
| assert "LOW" in html
|
|
|
| def test_error_severity_class(self):
|
| f = _finding(severity="ERROR")
|
| html = generate_html_report([f], {})
|
| assert "error" in html
|
|
|
| def test_performance_finding_in_perf_section(self):
|
| f = _finding(category="performance", rule="PERF401", severity="WARNING")
|
| html = generate_html_report([f], {})
|
| assert "performance" in html.lower() or "PERF" in html
|
|
|
| def test_footer_text_in_output(self):
|
| html = generate_html_report([], {"footer": "MyCustomScanner v1.0"})
|
| assert "MyCustomScanner v1.0" in html
|
|
|
| def test_tool_and_rule_in_output(self):
|
| f = _finding(tool="myTool", rule="MY-RULE-001")
|
| html = generate_html_report([f], {})
|
| assert "myTool" in html
|
| assert "MY-RULE-001" in html
|
|
|
| def test_file_and_line_in_output(self):
|
| f = _finding(file="src/auth.py", line=42)
|
| html = generate_html_report([f], {})
|
| assert "src/auth.py" in html
|
| assert "42" in html
|
|
|
| def test_multiple_findings(self):
|
| findings = [
|
| _finding(severity="ERROR", message="Critical issue"),
|
| _finding(severity="WARNING", message="Medium issue"),
|
| _finding(severity="INFO", message="Low issue"),
|
| ]
|
| html = generate_html_report(findings, {})
|
| assert "Critical issue" in html
|
| assert "Medium issue" in html
|
| assert "Low issue" in html
|
|
|
| def test_owasp_summary_section_generated(self):
|
| findings = [_finding(owasp=["A01:2021-Broken_Access_Control"]) for _ in range(3)]
|
| html = generate_html_report(findings, {})
|
| assert "A01" in html
|
|
|
| def test_xss_in_message_escaped(self):
|
| f = _finding(message='<script>alert("xss")</script>')
|
| html = generate_html_report([f], {})
|
|
|
| assert "<script>" not in html
|
|
|
| def test_severity_counts_in_output(self):
|
| findings = [
|
| _finding(severity="ERROR"),
|
| _finding(severity="ERROR"),
|
| _finding(severity="WARNING"),
|
| ]
|
| html = generate_html_report(findings, {})
|
|
|
| assert "2" in html
|
| assert "1" in html
|
|
|