# #region Test.CleanRelease.ReportBuilder [C:3] [TYPE Module] [SEMANTICS test,clean-release,report,builder,compliance] # @BRIEF Tests for report_builder.py — ComplianceReportBuilder.build_report_payload, persist_report. # @RELATION BINDS_TO -> [ReportBuilder] from pathlib import Path import sys sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / "src")) from datetime import UTC, datetime from unittest.mock import MagicMock import pytest # #region TestBuildReportPayload [C:2] [TYPE Module] class TestBuildReportPayload: @pytest.fixture def repo(self): return MagicMock() @pytest.fixture def builder(self, repo): from src.services.clean_release.report_builder import ComplianceReportBuilder return ComplianceReportBuilder(repo) def test_raises_for_running_run(self, builder): """Non-terminal (RUNNING) run raises ValueError (line 37).""" from src.services.clean_release.enums import RunStatus run = MagicMock() run.status = RunStatus.RUNNING with pytest.raises(ValueError, match="non-terminal"): builder.build_report_payload(run, []) def test_raises_for_blocked_with_no_violations(self, builder): """BLOCKED final_status with zero blocking violations raises ValueError.""" from src.services.clean_release.enums import ComplianceDecision, RunStatus run = MagicMock() run.status = RunStatus.SUCCEEDED run.final_status = ComplianceDecision.BLOCKED violations = [] with pytest.raises(ValueError, match="blocking violation"): builder.build_report_payload(run, violations) def test_raises_for_blocked_with_non_blocking_violations(self, builder): """BLOCKED run with violations but none blocking raises ValueError.""" from src.services.clean_release.enums import ComplianceDecision, RunStatus from src.models.clean_release import ComplianceViolation run = MagicMock() run.status = RunStatus.SUCCEEDED run.final_status = ComplianceDecision.BLOCKED violations = [ ComplianceViolation( id="v1", run_id="run-1", stage_name="DATA_PURITY", code="WARN001", message="warning", severity="MINOR", evidence_json={"blocked_release": False}, ) ] with pytest.raises(ValueError, match="blocking violation"): builder.build_report_payload(run, violations) def test_returns_report_for_passed_run(self, builder): """PASSED run returns ComplianceReport with correct summary.""" from src.services.clean_release.enums import ComplianceDecision, RunStatus from src.models.clean_release import ComplianceViolation run = MagicMock() run.id = "check-run-1" run.candidate_id = "cand-1" run.status = RunStatus.SUCCEEDED run.final_status = ComplianceDecision.PASSED report = builder.build_report_payload(run, []) assert report is not None assert report.run_id == "check-run-1" assert report.final_status == ComplianceDecision.PASSED assert report.immutable is True assert "no blocking violations" in report.summary_json["operator_summary"] def test_returns_report_for_blocked_run(self, builder): """BLOCKED run with blocking violations returns report.""" from src.services.clean_release.enums import ComplianceDecision, RunStatus from src.models.clean_release import ComplianceViolation run = MagicMock() run.id = "check-run-2" run.candidate_id = "cand-2" run.status = RunStatus.SUCCEEDED run.final_status = ComplianceDecision.BLOCKED violations = [ ComplianceViolation( id="v1", run_id="run-1", stage_name="DATA_PURITY", code="POL001", message="prohibited artifact", severity="CRITICAL", evidence_json={"blocked_release": True}, ) ] report = builder.build_report_payload(run, violations) assert report is not None assert report.summary_json["violations_count"] == 1 assert report.summary_json["blocking_violations_count"] == 1 assert "Blocked" in report.summary_json["operator_summary"] # #endregion TestBuildReportPayload # #region TestPersistReport [C:2] [TYPE Module] class TestPersistReport: def test_persist_report(self): """persist_report delegates to repository.""" repo = MagicMock() repo.save_report.return_value = "saved_report" from src.services.clean_release.report_builder import ComplianceReportBuilder builder = ComplianceReportBuilder(repo) mock_report = MagicMock() result = builder.persist_report(mock_report) assert result == "saved_report" repo.save_report.assert_called_once_with(mock_report) # #endregion TestPersistReport # #endregion Test.CleanRelease.ReportBuilder