"""Tests for models/build.py — BuildStatus and ApprovalRecord. Written FIRST (TDD RED phase). """ import pytest from dataclasses import FrozenInstanceError from release_agent.models.build import ApprovalRecord, BuildStatus # --------------------------------------------------------------------------- # BuildStatus tests # --------------------------------------------------------------------------- class TestBuildStatus: """Tests for BuildStatus frozen dataclass.""" def test_can_be_created_with_all_fields(self) -> None: bs = BuildStatus( status="completed", result="succeeded", build_url="https://dev.azure.com/org/proj/_build/results?buildId=42", ) assert bs.status == "completed" assert bs.result == "succeeded" assert bs.build_url == "https://dev.azure.com/org/proj/_build/results?buildId=42" def test_result_can_be_none(self) -> None: bs = BuildStatus( status="inProgress", result=None, build_url="https://dev.azure.com/org/proj/_build/results?buildId=99", ) assert bs.result is None def test_build_url_can_be_none(self) -> None: bs = BuildStatus(status="notStarted", result=None, build_url=None) assert bs.build_url is None def test_is_frozen_status(self) -> None: bs = BuildStatus(status="completed", result="succeeded", build_url=None) with pytest.raises((FrozenInstanceError, AttributeError)): bs.status = "inProgress" # type: ignore[misc] def test_is_frozen_result(self) -> None: bs = BuildStatus(status="completed", result="succeeded", build_url=None) with pytest.raises((FrozenInstanceError, AttributeError)): bs.result = "failed" # type: ignore[misc] def test_equality(self) -> None: a = BuildStatus(status="completed", result="succeeded", build_url="http://x") b = BuildStatus(status="completed", result="succeeded", build_url="http://x") assert a == b def test_inequality_on_status(self) -> None: a = BuildStatus(status="completed", result="succeeded", build_url=None) b = BuildStatus(status="inProgress", result="succeeded", build_url=None) assert a != b def test_inequality_on_result(self) -> None: a = BuildStatus(status="completed", result="succeeded", build_url=None) b = BuildStatus(status="completed", result="failed", build_url=None) assert a != b def test_repr_contains_status(self) -> None: bs = BuildStatus(status="completed", result="succeeded", build_url=None) assert "completed" in repr(bs) def test_status_values_typical(self) -> None: for s in ("notStarted", "inProgress", "completed", "cancelling"): bs = BuildStatus(status=s, result=None, build_url=None) assert bs.status == s def test_result_values_typical(self) -> None: for r in ("succeeded", "failed", "canceled", "partiallySucceeded"): bs = BuildStatus(status="completed", result=r, build_url=None) assert bs.result == r # --------------------------------------------------------------------------- # ApprovalRecord tests # --------------------------------------------------------------------------- class TestApprovalRecord: """Tests for ApprovalRecord frozen dataclass.""" def test_can_be_created_with_all_fields(self) -> None: ar = ApprovalRecord( approval_id="approval-abc-123", stage_name="Sandbox", status="pending", release_id=42, ) assert ar.approval_id == "approval-abc-123" assert ar.stage_name == "Sandbox" assert ar.status == "pending" assert ar.release_id == 42 def test_is_frozen_approval_id(self) -> None: ar = ApprovalRecord( approval_id="abc", stage_name="Sandbox", status="pending", release_id=1, ) with pytest.raises((FrozenInstanceError, AttributeError)): ar.approval_id = "xyz" # type: ignore[misc] def test_is_frozen_stage_name(self) -> None: ar = ApprovalRecord( approval_id="abc", stage_name="Sandbox", status="pending", release_id=1, ) with pytest.raises((FrozenInstanceError, AttributeError)): ar.stage_name = "Production" # type: ignore[misc] def test_equality(self) -> None: a = ApprovalRecord(approval_id="x", stage_name="S", status="pending", release_id=1) b = ApprovalRecord(approval_id="x", stage_name="S", status="pending", release_id=1) assert a == b def test_inequality_on_approval_id(self) -> None: a = ApprovalRecord(approval_id="x", stage_name="S", status="pending", release_id=1) b = ApprovalRecord(approval_id="y", stage_name="S", status="pending", release_id=1) assert a != b def test_status_pending(self) -> None: ar = ApprovalRecord(approval_id="a", stage_name="Stage", status="pending", release_id=10) assert ar.status == "pending" def test_status_approved(self) -> None: ar = ApprovalRecord(approval_id="a", stage_name="Stage", status="approved", release_id=10) assert ar.status == "approved" def test_status_rejected(self) -> None: ar = ApprovalRecord(approval_id="a", stage_name="Stage", status="rejected", release_id=10) assert ar.status == "rejected" def test_repr_contains_stage_name(self) -> None: ar = ApprovalRecord(approval_id="a", stage_name="Production", status="pending", release_id=5) assert "Production" in repr(ar) def test_release_id_is_int(self) -> None: ar = ApprovalRecord(approval_id="a", stage_name="S", status="pending", release_id=999) assert isinstance(ar.release_id, int)