"""Tests for the synthetic reference domain (D4).""" import pytest from portfolio_optimiser.reference_domain import CostItem, Project, load_reference_projects @pytest.fixture(scope="module") def projects() -> tuple[Project, ...]: return load_reference_projects() def test_loads_non_empty(projects: tuple[Project, ...]) -> None: assert len(projects) >= 1 def test_project_ids_unique(projects: tuple[Project, ...]) -> None: ids = [p.id for p in projects] assert len(ids) == len(set(ids)) def test_every_project_well_formed(projects: tuple[Project, ...]) -> None: for p in projects: assert p.id and p.name and p.description assert p.currency == "NOK" assert len(p.cost_items) >= 1 def test_every_project_has_docs_dir_and_verdict_input(projects: tuple[Project, ...]) -> None: """Step 2 (SC1 prep): docs_dir + verdict_input are config-driven per project. Each loaded Project exposes a docs_dir resolved to an existing bundled directory, and a verdict_input dict with exactly the decision + rationale keys. Removing the loader fields reddens this.""" import os for p in projects: assert p.docs_dir and os.path.isdir(p.docs_dir) assert set(p.verdict_input) == {"decision", "rationale"} assert p.verdict_input["decision"] and p.verdict_input["rationale"] def test_cost_item_total_is_quantity_times_unit_cost() -> None: item = CostItem(code="X", description="d", quantity=4.0, unit="m2", unit_cost=215.0) assert item.total_cost == pytest.approx(860.0) def test_project_total_is_sum_of_items(projects: tuple[Project, ...]) -> None: for p in projects: expected = sum(item.total_cost for item in p.cost_items) assert p.total_cost == pytest.approx(expected) assert p.total_cost > 0