diff --git a/tests/domain/modelling/test_roof_recommendation.py b/tests/domain/modelling/test_roof_recommendation.py index 3acdbb86f..77e9c0124 100644 --- a/tests/domain/modelling/test_roof_recommendation.py +++ b/tests/domain/modelling/test_roof_recommendation.py @@ -167,6 +167,30 @@ def test_vaulted_ceiling_with_measured_thickness_yields_no_recommendation() -> N assert recommendation is None +def test_loft_roof_with_nd_thickness_on_pre_1950_dwelling_yields_loft_insulation() -> None: + # Arrange — the loft fallback shares the sentinel semantics (ADR-0047): + # "ND" on an age-band-C pitched loft resolves to as-built uninsulated, so + # the joist measure fires just as it does for an explicit 0. + baseline: EpcPropertyData = build_epc() + main: SapBuildingPart = _part(baseline, BuildingPartIdentifier.MAIN) + main.roof_insulation_thickness = "ND" + main.construction_age_band = "C" + + # Act + recommendation: Recommendation | None = recommend_roof_insulation( + baseline, _StubProducts() + ) + + # Assert + assert recommendation is not None + option = recommendation.options[0] + assert option.measure_type == "loft_insulation" + simulated: EpcPropertyData = apply_simulations(baseline, [option.overlay]) + assert ( + _part(simulated, BuildingPartIdentifier.MAIN).roof_insulation_thickness == 300 + ) + + def test_loft_option_carries_cost_from_roof_area_and_product() -> None: # Arrange baseline: EpcPropertyData = build_epc() # MAIN roof area 14.85 m^2