From 539f66143018a3fa87b7dffe8979e068328384df Mon Sep 17 00:00:00 2001 From: Jun-te Kim Date: Tue, 23 Jun 2026 15:35:19 +0000 Subject: [PATCH] =?UTF-8?q?Skip=20a=20landlord=20override=20that=20targets?= =?UTF-8?q?=20a=20building=20part=20the=20EPC=20lacks=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../modelling/test_overlay_applicator.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) 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