72 lines
2.7 KiB
Python
72 lines
2.7 KiB
Python
"""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_repo_local_mini_bundle_loads_as_ir_projection() -> None:
|
|
"""Step 1 (S2.0 fixture): the repo-local mini OKF-bundle under the package ``data/`` root loads
|
|
as a valid IR projection via ``okf.load_ir_projection`` (fail-fast), exposing its ``project_id``,
|
|
and lives under ``data/`` — NEVER under ``shared/`` (the subtree is PULL-ONLY). It is also a
|
|
navigable OKF bundle (readable ``index.md``), so the Step-3 bundle-context navigation works."""
|
|
import os
|
|
from importlib.resources import files
|
|
|
|
from portfolio_optimiser import okf
|
|
|
|
bundle_dir = str(files("portfolio_optimiser").joinpath("data/bundles/bygg-energi-mikro-a"))
|
|
assert os.path.isdir(bundle_dir)
|
|
assert f"{os.sep}data{os.sep}bundles{os.sep}" in bundle_dir
|
|
assert f"{os.sep}shared{os.sep}" not in bundle_dir
|
|
|
|
ir = okf.load_ir_projection(bundle_dir)
|
|
assert ir["project_id"] == "BYGG-ENERGI-MIKRO-A"
|
|
|
|
bundle = okf.navigate_bundle(bundle_dir)
|
|
assert bundle.index_summary.strip()
|
|
|
|
|
|
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
|