diff --git a/tests/domain/modelling/test_overlay_applicator.py b/tests/domain/modelling/test_overlay_applicator.py index 64a237d7..2e7059ec 100644 --- a/tests/domain/modelling/test_overlay_applicator.py +++ b/tests/domain/modelling/test_overlay_applicator.py @@ -55,6 +55,33 @@ def test_apply_writes_targeted_building_part_and_leaves_others_untouched() -> No ) +def test_override_targeting_a_part_absent_from_the_epc_is_skipped() -> None: + # A Landlord Override can reference a building part the lodged (or predicted) + # EPC never carried — e.g. an `extension_1` override on a property whose EPC + # has only `main`. The orphaned part is skipped, not crashed on, so the rest + # of the overlay still folds and the property still models. + # Arrange — build_epc() has MAIN + EXTENSION_1 but no EXTENSION_2. + baseline: EpcPropertyData = build_epc() + simulation = EpcSimulation( + building_parts={ + BuildingPartIdentifier.MAIN: BuildingPartOverlay(wall_insulation_type=1), + BuildingPartIdentifier.EXTENSION_2: BuildingPartOverlay( + wall_insulation_type=1 + ), + } + ) + + # Act + result: EpcPropertyData = apply_simulations(baseline, [simulation]) + + # Assert — the present part got its overlay; the absent one was not added. + assert _part(result, BuildingPartIdentifier.MAIN).wall_insulation_type == 1 + assert all( + part.identifier is not BuildingPartIdentifier.EXTENSION_2 + for part in result.sap_building_parts + ) + + def test_flat_roof_construction_type_folds_onto_the_part() -> None: # ADR-0033: a flat-roof landlord override sets `roof_construction_type` so the # calculator's flat path (`"flat" in roof_construction_type`) fires the