From c1e754057bd04ac75592e18cfcf27e20871179ae Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 25 Jun 2026 14:14:03 +0000 Subject: [PATCH] =?UTF-8?q?Mapper=20synthesises=20SapFloorDimension=20for?= =?UTF-8?q?=20SAP-16.0=20flats=20with=20empty=20floor=20dims=20?= =?UTF-8?q?=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../epc/domain/tests/test_from_sap_schema.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/datatypes/epc/domain/tests/test_from_sap_schema.py b/datatypes/epc/domain/tests/test_from_sap_schema.py index 25acf566..42bb1867 100644 --- a/datatypes/epc/domain/tests/test_from_sap_schema.py +++ b/datatypes/epc/domain/tests/test_from_sap_schema.py @@ -751,3 +751,52 @@ class TestFullSapSchema16xRouting: # Assert assert not any("broken schema_type" in r.message for r in caplog.records) + + +class TestFullSapSchema16xNoFloorDimensions: + """SAP-Schema-16.0 certs with assessment_type=SAP that lodge no + sap_floor_dimensions inside sap_building_parts (uprn 10090783001, + cert lodged 88). The API only carries total_floor_area at the top level; + the building part has sap_walls but no per-storey dimension data. + + This is the root cause of the `max() arg is an empty sequence` crash in + building_geometry.roof_area() — documented in + scripts/handover_max_empty_sequence_design_question.md. + """ + + @pytest.fixture + def epc(self) -> EpcPropertyData: + return EpcPropertyDataMapper.from_api_response( + load("sap_16_0_full_no_floor_dims.json") + ) + + def test_maps_successfully(self, epc: EpcPropertyData) -> None: + assert isinstance(epc, EpcPropertyData) + + def test_uprn_and_total_floor_area(self, epc: EpcPropertyData) -> None: + assert epc.uprn == 10090783001 + assert epc.total_floor_area_m2 == 72.0 + + def test_building_part_has_empty_floor_dimensions( + self, epc: EpcPropertyData + ) -> None: + # The API lodges no sap_floor_dimensions for this cert family. + # The mapper faithfully produces an empty list — the data gap that + # causes roof_area() / gross_heat_loss_wall_area() to crash downstream. + main_part = epc.sap_building_parts[0] + assert main_part.sap_floor_dimensions == [] + + def test_total_floor_area_available_at_cert_level( + self, epc: EpcPropertyData + ) -> None: + # total_floor_area_m2 IS present at the EpcPropertyData level (72 m²). + # This is the candidate fallback value for roof_area() — accurate for + # single-storey single-part certs, an overestimate for multi-storey. + assert epc.total_floor_area_m2 == 72.0 + + def test_synthesises_single_floor_dimension(self, epc: EpcPropertyData) -> None: + # Arrange + main_part = epc.sap_building_parts[0] + + # Act / Assert + assert len(main_part.sap_floor_dimensions) == 1