"""Tests for the unified-review HTML report tool.""" from __future__ import annotations import sys from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).parent.parent)) from code_review_graph.scoring import build_report_data # noqa: E402 from code_review_graph.tools.scoring_tools import ( # noqa: E402 _load_report_template, generate_report_func, ) def _review_data() -> dict: return { "scope": "change-level", "tier": "standard", "timestamp": "2026-08-05T00:00:00Z", "files": "app.py, main.py", "baseline": "generic", "verdict": "\u2705 PASS", "metrics": { "sql_risk": {"value": 0, "grade": "good", "note": "heuristic"}, "exception_coverage": {"value": 33.33, "grade": "warn", "note": "heuristic"}, }, "findings": [ { "severity": "MAJOR", "category": "Data", "message": "Possible N+1 query", "path": "src/app.py", "line": 42, "confidence": 7, "fix": "Add eager loading", }, ], "manual_review": ["Payment callback idempotency"], "llm_judged": ["requirement_coverage", "logic_alignment"], } class TestBuildReportData: def test_normalises_review_data(self): data = build_report_data(_review_data()) assert data["verdict"] == "\u2705 PASS" assert data["tier"] == "standard" assert data["scope"] == "change-level" assert data["metrics"]["sql_risk"]["grade"] == "good" assert len(data["issues"]) == 1 assert data["issues"][0]["location"] == "src/app.py:42" assert "requirement_coverage" in data["llm_judged"] def test_empty_findings(self): rd = _review_data() rd["findings"] = [] data = build_report_data(rd) assert data["issues"] == [] def test_defaults(self): data = build_report_data({}) assert data["scope"] == "change-level" assert data["tier"] == "standard" assert data["verdict"] == "\u274c FAIL" assert data["issues"] == [] class TestLoadTemplate: def test_loads_package_asset(self): template = _load_report_template() assert "{{REPORT_DATA}}" in template assert template.startswith("") class TestGenerateReport: def test_writes_self_contained_html(self, tmp_path): Path(tmp_path, ".code-review-graph").mkdir(exist_ok=True) out = tmp_path / "sub" / "report.html" result = generate_report_func( _review_data(), output_path=str(out), repo_root=str(tmp_path), ) assert result["status"] == "ok" assert Path(result["output_path"]).is_file() html = Path(result["output_path"]).read_text(encoding="utf-8") assert "{{REPORT_DATA}}" not in html assert "\u2705 PASS" in html assert "N+1" in html def test_default_output_path_is_repo_root(self, tmp_path): # repo_root must look like a project root: create .code-review-graph. Path(tmp_path, ".code-review-graph").mkdir(exist_ok=True) result = generate_report_func(_review_data(), repo_root=str(tmp_path)) assert result["status"] == "ok" assert result["output_path"].endswith("code-review-report.html") assert Path(result["output_path"]).is_file() def test_handles_missing_repo_root(self, tmp_path): with pytest.raises(ValueError): generate_report_func(_review_data(), repo_root=str(tmp_path / "missing"))