"""In-memory fakes for orchestrator unit tests (no DB, no network). A `FakeUnitOfWork` exposes dict-backed fake repos and records commits, so a test can drive an orchestrator and then assert what was persisted and that the batch committed exactly once (ADR-0012).""" from __future__ import annotations from types import TracebackType from typing import Any, Optional from datatypes.epc.domain.epc_property_data import EpcPropertyData from domain.property_baseline.property_baseline_performance import PropertyBaselinePerformance from domain.property.properties import Properties from domain.property.property import Property from repositories.property_baseline.property_baseline_repository import PropertyBaselineRepository from repositories.epc.epc_repository import EpcRepository from repositories.property.property_repository import PropertyRepository from repositories.solar.solar_repository import SolarRepository from repositories.unit_of_work import UnitOfWork class FakePropertyRepo(PropertyRepository): def __init__(self, by_id: dict[int, Property]) -> None: self._by_id = by_id def get(self, property_id: int) -> Property: return self._by_id[property_id] def get_many(self, property_ids: list[int]) -> Properties: return Properties([self._by_id[property_id] for property_id in property_ids]) class FakeEpcRepo(EpcRepository): def __init__(self, by_property: Optional[dict[int, EpcPropertyData]] = None) -> None: self.saved: list[tuple[EpcPropertyData, Optional[int]]] = [] self._by_property = by_property or {} def save( self, data: EpcPropertyData, property_id: Optional[int] = None, portfolio_id: Optional[int] = None, ) -> int: self.saved.append((data, property_id)) if property_id is not None: self._by_property[property_id] = data return len(self.saved) def get(self, epc_property_id: int) -> EpcPropertyData: # pragma: no cover raise NotImplementedError def get_for_property(self, property_id: int) -> Optional[EpcPropertyData]: return self._by_property.get(property_id) def get_for_properties( self, property_ids: list[int] ) -> dict[int, EpcPropertyData]: return { property_id: self._by_property[property_id] for property_id in property_ids if property_id in self._by_property } class FakeSolarRepo(SolarRepository): def __init__(self) -> None: self.saved: list[tuple[int, dict[str, Any]]] = [] def save(self, property_id: int, insights: dict[str, Any]) -> None: self.saved.append((property_id, insights)) def get(self, property_id: int) -> Optional[dict[str, Any]]: # pragma: no cover raise NotImplementedError class FakePropertyBaselineRepo(PropertyBaselineRepository): def __init__(self) -> None: self.saved: list[tuple[PropertyBaselinePerformance, int]] = [] def save(self, baseline: PropertyBaselinePerformance, property_id: int) -> int: self.saved.append((baseline, property_id)) return len(self.saved) def get_for_property( self, property_id: int ) -> Optional[PropertyBaselinePerformance]: # pragma: no cover raise NotImplementedError class FakeUnitOfWork(UnitOfWork): """A unit that holds in-memory repos and counts commits.""" def __init__( self, *, property: FakePropertyRepo, epc: Optional[FakeEpcRepo] = None, solar: Optional[FakeSolarRepo] = None, property_baseline: Optional[FakePropertyBaselineRepo] = None, ) -> None: self.property = property self.epc = epc or FakeEpcRepo() self.solar = solar or FakeSolarRepo() self.property_baseline = property_baseline or FakePropertyBaselineRepo() self.commits = 0 def __enter__(self) -> "FakeUnitOfWork": return self def __exit__( self, exc_type: Optional[type[BaseException]], exc: Optional[BaseException], tb: Optional[TracebackType], ) -> None: return None def commit(self) -> None: self.commits += 1 def rollback(self) -> None: return None