diff --git a/datatypes/epc/domain/tests/test_from_site_notes.py b/datatypes/epc/domain/tests/test_from_site_notes.py index 0fbab02fa..77e99403c 100644 --- a/datatypes/epc/domain/tests/test_from_site_notes.py +++ b/datatypes/epc/domain/tests/test_from_site_notes.py @@ -122,6 +122,62 @@ class TestPhotovoltaicArrayMapping: assert result.sap_energy_source.photovoltaic_arrays is None +class TestCylinderSizeCoding: + """The surveyed §Water-Heating "Cylinder Size" label must resolve to the + SAP10 cylinder-size enum (`_cylinder_volume_l_from_code` int-or-nones a raw + string, silently skipping the Table 28 volume convention — issue #1590 + bug 6). "No Access" routes per RdSAP 10 Table 28 p.55: solid-fuel boiler → + Medium/160L, off-peak dual electric immersion → Large/210L, otherwise → + Normal/110L (the cohort's case: cylinder fed from a gas main). + """ + + @staticmethod + def _with_cylinder(label: str) -> Dict[str, Any]: + data = load("pashub_rdsap_site_notes_example1.json") + data["heating_and_hot_water"]["water_heating"]["cylinder_size"] = label + return data + + @pytest.mark.parametrize( + "label, expected_code", + [ + ("Normal (90-130 litres)", 2), + ("Large (>170 litres)", 4), + ("No Access", 2), # fed from the (gas) main → Table 28 "otherwise" + ], + ) + def test_label_maps_to_sap_code(self, label: str, expected_code: int) -> None: + # Arrange + survey = from_dict(PasHubRdSapSiteNotes, self._with_cylinder(label)) + + # Act + result = EpcPropertyDataMapper.from_site_notes(survey) + + # Assert + assert result.sap_heating.cylinder_size == expected_code + + def test_no_cylinder_stays_absent(self) -> None: + # Arrange — a combi dwelling: no cylinder lodged. + survey = from_dict( + PasHubRdSapSiteNotes, self._with_cylinder("No Cylinder") + ) + + # Act + result = EpcPropertyDataMapper.from_site_notes(survey) + + # Assert + assert result.sap_heating.cylinder_size is None + + def test_unknown_label_strict_raises(self) -> None: + # Arrange + survey = from_dict( + PasHubRdSapSiteNotes, self._with_cylinder("Some novel size") + ) + + # Act / Assert + with pytest.raises(UnmappedPasHubLabel, match="cylinder size"): + EpcPropertyDataMapper.from_site_notes(survey) + + class TestMechanicalVentilationKindCoding: """The surveyed "Ventilation type" label must resolve to the `MechanicalVentilationKind` enum name the §2 cascade dispatches on —