"""Behaviour of the ventilation Recommendation Generator: detecting a dwelling that lacks adequate mechanical ventilation and emitting a priced MEV Recommendation. Like wall/roof/floor it does detection + pricing; unlike them it is consumed by the Measure Dependency path, not the free candidate pool (it is a forced dependency of fabric insulation — ADR-0016). See CONTEXT.md. """ from datatypes.epc.domain.epc_property_data import EpcPropertyData from domain.modelling.generators.ventilation_recommendation import ( recommend_ventilation, ) from domain.modelling.product import Product from domain.modelling.recommendation import Recommendation from domain.modelling.simulation import VentilationOverlay from repositories.product.product_repository import ProductRepository from tests.domain.sap10_calculator.worksheet._elmhurst_worksheet_000490 import ( build_epc, ) class _StubProducts(ProductRepository): """In-memory ProductRepository returning a fixed per-unit ventilation cost.""" def get(self, measure_type: str) -> Product: # unit_cost_per_m2 carries the catalogue row's fully-loaded total cost; # for ventilation that total is per installed unit. return Product( measure_type=measure_type, unit_cost_per_m2=450.0, contingency_rate=0.26 ) def test_naturally_ventilated_dwelling_yields_a_mev_recommendation() -> None: # Arrange — 000490 lodges no mechanical ventilation kind. baseline: EpcPropertyData = build_epc() # Act recommendation: Recommendation | None = recommend_ventilation( baseline, _StubProducts() ) # Assert — one MEV Option targeting the whole-dwelling ventilation system. assert recommendation is not None assert recommendation.surface == "Ventilation" assert len(recommendation.options) == 1 option = recommendation.options[0] assert option.measure_type == "mechanical_ventilation" assert option.overlay.ventilation == VentilationOverlay( mechanical_ventilation_kind="EXTRACT_OR_PIV_OUTSIDE" ) def test_recommendation_prices_two_installed_units_with_contingency() -> None: # Arrange baseline: EpcPropertyData = build_epc() # Act recommendation: Recommendation | None = recommend_ventilation( baseline, _StubProducts() ) # Assert — two MEV units at £450 each, carrying the product's contingency. assert recommendation is not None cost = recommendation.options[0].cost assert cost is not None assert abs(cost.total - 900.0) <= 1e-9 assert abs(cost.contingency_rate - 0.26) <= 1e-9 def test_already_mechanically_ventilated_yields_no_recommendation() -> None: # Arrange — a dwelling that already lodges a mechanical ventilation kind # must not be told to install MEV (legacy has_ventilation guard). baseline: EpcPropertyData = build_epc() assert baseline.sap_ventilation is not None baseline.sap_ventilation.mechanical_ventilation_kind = "EXTRACT_OR_PIV_OUTSIDE" # Act recommendation: Recommendation | None = recommend_ventilation( baseline, _StubProducts() ) # Assert assert recommendation is None def test_dwelling_with_no_sap_ventilation_yields_a_recommendation() -> None: # Arrange — no SapVentilation at all counts as not mechanically ventilated. baseline: EpcPropertyData = build_epc() baseline.sap_ventilation = None # Act recommendation: Recommendation | None = recommend_ventilation( baseline, _StubProducts() ) # Assert assert recommendation is not None