"""Behaviour of the wall Recommendation Generator: detecting a treatable wall and emitting a Recommendation whose Measure Option carries the Simulation Overlay for the intervention. See CONTEXT.md / ADR-0016. """ from datatypes.epc.domain.epc_property_data import ( BuildingPartIdentifier, EpcPropertyData, SapBuildingPart, ) from domain.modelling.scoring.overlay_applicator import apply_simulations from domain.modelling.product import Product from domain.modelling.recommendation import Recommendation from domain.modelling.generators.wall_recommendation import recommend_cavity_wall from domain.modelling.generators.solid_wall_recommendation import recommend_solid_wall 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 cavity Product.""" def get(self, measure_type: str) -> Product: return Product( measure_type=measure_type, unit_cost_per_m2=18.5, contingency_rate=0.10 ) def _part(epc: EpcPropertyData, identifier: BuildingPartIdentifier) -> SapBuildingPart: return next(p for p in epc.sap_building_parts if p.identifier is identifier) def test_uninsulated_main_cavity_wall_yields_a_cavity_fill_recommendation() -> None: # Arrange baseline: EpcPropertyData = build_epc() # MAIN: cavity (4), uninsulated (4) # Act recommendation: Recommendation | None = recommend_cavity_wall(baseline, _StubProducts()) # Assert assert recommendation is not None assert recommendation.surface == "Main wall" assert len(recommendation.options) == 1 option = recommendation.options[0] assert option.measure_type == "cavity_wall_insulation" simulated: EpcPropertyData = apply_simulations(baseline, [option.overlay]) assert _part(simulated, BuildingPartIdentifier.MAIN).wall_insulation_type == 2 def test_already_insulated_main_wall_yields_no_recommendation() -> None: # Arrange baseline: EpcPropertyData = build_epc() _part(baseline, BuildingPartIdentifier.MAIN).wall_insulation_type = 2 # filled # Act recommendation: Recommendation | None = recommend_cavity_wall(baseline, _StubProducts()) # Assert assert recommendation is None def test_cavity_option_carries_fully_loaded_cost_from_area_and_product() -> None: # Arrange baseline: EpcPropertyData = build_epc() # MAIN gross heat-loss area 45.93 m^2 products = _StubProducts() # cavity 18.5 GBP/m^2, contingency 0.10 # Act recommendation: Recommendation | None = recommend_cavity_wall(baseline, products) # Assert assert recommendation is not None cost = recommendation.options[0].cost assert cost is not None assert abs(cost.total - 45.93 * 18.5) <= 0.01 assert abs(cost.contingency_rate - 0.10) <= 1e-9 def test_non_cavity_main_wall_yields_no_recommendation() -> None: # Arrange baseline: EpcPropertyData = build_epc() main: SapBuildingPart = _part(baseline, BuildingPartIdentifier.MAIN) main.wall_construction = 2 # solid (not cavity); still uninsulated # Act recommendation: Recommendation | None = recommend_cavity_wall(baseline, _StubProducts()) # Assert assert recommendation is None def test_park_home_wall_yields_no_solid_wall_recommendation() -> None: # Arrange — a park home (wall_construction code 8) with an uninsulated # as-built wall. Code 8 is NOT system-built (ADR-0019); a park home's # proprietary panel is never EWI/IWI-suitable, so the generator excludes it. baseline: EpcPropertyData = build_epc() main: SapBuildingPart = _part(baseline, BuildingPartIdentifier.MAIN) main.wall_construction = 8 main.wall_insulation_type = 4 # as-built / uninsulated — the trigger # Act recommendation: Recommendation | None = recommend_solid_wall( baseline, _StubProducts() ) # Assert assert recommendation is None