Map to domain from site notes 🟥

This commit is contained in:
Daniel Roth 2026-04-14 09:55:16 +00:00
parent 419892410b
commit e634933768
2 changed files with 518 additions and 137 deletions

View file

@ -113,7 +113,31 @@ class EpcPropertyDataMapper:
) )
@staticmethod @staticmethod
def from_rdsap_schema(_schema: AnyRdSapSchema) -> EpcPropertyData: def from_rdsap_schema_17_0(_schema: RdSapSchema17_0) -> EpcPropertyData:
raise NotImplementedError
@staticmethod
def from_rdsap_schema_17_1(_schema: RdSapSchema17_1) -> EpcPropertyData:
raise NotImplementedError
@staticmethod
def from_rdsap_schema_18_0(_schema: RdSapSchema18_0) -> EpcPropertyData:
raise NotImplementedError
@staticmethod
def from_rdsap_schema_19_0(_schema: RdSapSchema19_0) -> EpcPropertyData:
raise NotImplementedError
@staticmethod
def from_rdsap_schema_20_0_0(_schema: RdSapSchema20_0_0) -> EpcPropertyData:
raise NotImplementedError
@staticmethod
def from_rdsap_schema_21_0_0(_schema: RdSapSchema21_0_0) -> EpcPropertyData:
raise NotImplementedError
@staticmethod
def from_rdsap_schema_21_0_1(_schema: RdSapSchema21_0_1) -> EpcPropertyData:
raise NotImplementedError raise NotImplementedError

View file

@ -1,18 +1,22 @@
import json import json
import os import os
from datetime import date
from typing import Any, Dict from typing import Any, Dict
import pytest import pytest
from datatypes.epc.domain import Dwelling from datatypes.epc.domain.epc_property_data import EpcPropertyData
from datatypes.epc.domain.mapper import EpcPropertyDataMapper from datatypes.epc.domain.mapper import EpcPropertyDataMapper
from datatypes.epc.schema.rdsap_schema_17_0 import RdSapSchema17_0
from datatypes.epc.schema.rdsap_schema_17_1 import RdSapSchema17_1
from datatypes.epc.schema.rdsap_schema_18_0 import RdSapSchema18_0
from datatypes.epc.schema.rdsap_schema_19_0 import RdSapSchema19_0
from datatypes.epc.schema.rdsap_schema_20_0_0 import RdSapSchema20_0_0
from datatypes.epc.schema.rdsap_schema_21_0_0 import RdSapSchema21_0_0
from datatypes.epc.schema.rdsap_schema_21_0_1 import RdSapSchema21_0_1 from datatypes.epc.schema.rdsap_schema_21_0_1 import RdSapSchema21_0_1
from datatypes.epc.schema.tests.helpers import from_dict from datatypes.epc.schema.tests.helpers import from_dict
FIXTURES = os.path.join( FIXTURES = os.path.join(os.path.dirname(__file__), "../../schema/tests/fixtures")
os.path.dirname(__file__),
"../../schema/tests/fixtures",
)
def load(filename: str) -> Dict[str, Any]: def load(filename: str) -> Dict[str, Any]:
@ -20,168 +24,521 @@ def load(filename: str) -> Dict[str, Any]:
return json.load(f) # type: ignore[no-any-return] return json.load(f) # type: ignore[no-any-return]
# ---------------------------------------------------------------------------
# Schema 17.0
# ---------------------------------------------------------------------------
class TestFromRdSapSchema17_0:
@pytest.fixture
def result(self) -> EpcPropertyData:
schema = from_dict(RdSapSchema17_0, load("17_0.json"))
return EpcPropertyDataMapper.from_rdsap_schema_17_0(schema)
def test_uprn(self, result: EpcPropertyData) -> None:
assert result.uprn == 12457
def test_assessment_type(self, result: EpcPropertyData) -> None:
assert result.assessment_type == "RdSAP"
def test_sap_version(self, result: EpcPropertyData) -> None:
assert result.sap_version == 9.92
def test_dwelling_type(self, result: EpcPropertyData) -> None:
# dwelling_type is a localised object in 17.0; mapper extracts the string value
assert result.dwelling_type == "Mid-floor flat"
def test_tenure(self, result: EpcPropertyData) -> None:
# tenure: 2 — stored as stringified int
assert result.tenure == "2"
def test_door_count(self, result: EpcPropertyData) -> None:
assert result.door_count == 2
def test_built_form(self, result: EpcPropertyData) -> None:
# built_form: 2 → "Semi-detached"
assert result.built_form == "Semi-detached"
def test_property_type(self, result: EpcPropertyData) -> None:
# property_type: 2 → "Flat"
assert result.property_type == "Flat"
# ---------------------------------------------------------------------------
# Schema 17.1
# ---------------------------------------------------------------------------
class TestFromRdSapSchema17_1:
@pytest.fixture
def result(self) -> EpcPropertyData:
schema = from_dict(RdSapSchema17_1, load("17_1.json"))
return EpcPropertyDataMapper.from_rdsap_schema_17_1(schema)
def test_uprn(self, result: EpcPropertyData) -> None:
assert result.uprn == 12457
def test_assessment_type(self, result: EpcPropertyData) -> None:
assert result.assessment_type == "RdSAP"
def test_sap_version(self, result: EpcPropertyData) -> None:
assert result.sap_version == 9.92
def test_dwelling_type(self, result: EpcPropertyData) -> None:
# dwelling_type is a localised object in 17.1; mapper extracts the string value
assert result.dwelling_type == "Detached house"
def test_tenure(self, result: EpcPropertyData) -> None:
# tenure: 1
assert result.tenure == "1"
def test_door_count(self, result: EpcPropertyData) -> None:
assert result.door_count == 4
def test_built_form(self, result: EpcPropertyData) -> None:
# built_form: 1 → "Detached"
assert result.built_form == "Detached"
def test_property_type(self, result: EpcPropertyData) -> None:
# property_type: 0 → "House"
assert result.property_type == "House"
# ---------------------------------------------------------------------------
# Schema 18.0
# ---------------------------------------------------------------------------
class TestFromRdSapSchema18_0:
@pytest.fixture
def result(self) -> EpcPropertyData:
schema = from_dict(RdSapSchema18_0, load("18_0.json"))
return EpcPropertyDataMapper.from_rdsap_schema_18_0(schema)
def test_uprn(self, result: EpcPropertyData) -> None:
assert result.uprn == 12457
def test_assessment_type(self, result: EpcPropertyData) -> None:
assert result.assessment_type == "RdSAP"
def test_sap_version(self, result: EpcPropertyData) -> None:
assert result.sap_version == 9.92
def test_dwelling_type(self, result: EpcPropertyData) -> None:
# dwelling_type is a localised object in 18.0; mapper extracts the string value
assert result.dwelling_type == "Mid-terrace house"
def test_tenure(self, result: EpcPropertyData) -> None:
assert result.tenure == "1"
def test_door_count(self, result: EpcPropertyData) -> None:
assert result.door_count == 2
def test_built_form(self, result: EpcPropertyData) -> None:
# built_form: 4 → "Mid-terrace"
assert result.built_form == "Mid-terrace"
def test_property_type(self, result: EpcPropertyData) -> None:
# property_type: 0 → "House"
assert result.property_type == "House"
# ---------------------------------------------------------------------------
# Schema 19.0
# ---------------------------------------------------------------------------
class TestFromRdSapSchema19_0:
@pytest.fixture
def result(self) -> EpcPropertyData:
schema = from_dict(RdSapSchema19_0, load("19_0.json"))
return EpcPropertyDataMapper.from_rdsap_schema_19_0(schema)
def test_uprn(self, result: EpcPropertyData) -> None:
assert result.uprn == 12457
def test_assessment_type(self, result: EpcPropertyData) -> None:
assert result.assessment_type == "RdSAP"
def test_sap_version(self, result: EpcPropertyData) -> None:
assert result.sap_version == 9.94
def test_dwelling_type(self, result: EpcPropertyData) -> None:
# dwelling_type is a localised object in 19.0; mapper extracts the string value
assert result.dwelling_type == "Semi-detached house"
def test_tenure(self, result: EpcPropertyData) -> None:
# tenure: 3
assert result.tenure == "3"
def test_door_count(self, result: EpcPropertyData) -> None:
assert result.door_count == 1
def test_built_form(self, result: EpcPropertyData) -> None:
# built_form: 2 → "Semi-detached"
assert result.built_form == "Semi-detached"
def test_property_type(self, result: EpcPropertyData) -> None:
# property_type: 0 → "House"
assert result.property_type == "House"
# ---------------------------------------------------------------------------
# Schema 20.0.0
# ---------------------------------------------------------------------------
class TestFromRdSapSchema20_0_0:
@pytest.fixture
def result(self) -> EpcPropertyData:
schema = from_dict(RdSapSchema20_0_0, load("20_0_0.json"))
return EpcPropertyDataMapper.from_rdsap_schema_20_0_0(schema)
def test_uprn(self, result: EpcPropertyData) -> None:
assert result.uprn == 12457
def test_assessment_type(self, result: EpcPropertyData) -> None:
assert result.assessment_type == "RdSAP"
def test_sap_version(self, result: EpcPropertyData) -> None:
assert result.sap_version == 9.8
def test_dwelling_type(self, result: EpcPropertyData) -> None:
# dwelling_type is a plain string from 20.0.0 onwards
assert result.dwelling_type == "Mid-terrace house"
def test_tenure(self, result: EpcPropertyData) -> None:
assert result.tenure == "1"
def test_door_count(self, result: EpcPropertyData) -> None:
assert result.door_count == 2
def test_built_form(self, result: EpcPropertyData) -> None:
# built_form: 2 → "Semi-detached"
assert result.built_form == "Semi-detached"
def test_property_type(self, result: EpcPropertyData) -> None:
# property_type: 0 → "House"
assert result.property_type == "House"
# ---------------------------------------------------------------------------
# Schema 21.0.0
# ---------------------------------------------------------------------------
class TestFromRdSapSchema21_0_0:
@pytest.fixture
def result(self) -> EpcPropertyData:
schema = from_dict(RdSapSchema21_0_0, load("21_0_0.json"))
return EpcPropertyDataMapper.from_rdsap_schema_21_0_0(schema)
def test_uprn(self, result: EpcPropertyData) -> None:
assert result.uprn == 12457
def test_assessment_type(self, result: EpcPropertyData) -> None:
assert result.assessment_type == "RdSAP"
def test_sap_version(self, result: EpcPropertyData) -> None:
assert result.sap_version == 10.2
def test_dwelling_type(self, result: EpcPropertyData) -> None:
assert result.dwelling_type == "Mid-terrace house"
def test_tenure(self, result: EpcPropertyData) -> None:
assert result.tenure == "1"
def test_door_count(self, result: EpcPropertyData) -> None:
assert result.door_count == 3
def test_built_form(self, result: EpcPropertyData) -> None:
# built_form: 2 → "Semi-detached"
assert result.built_form == "Semi-detached"
def test_property_type(self, result: EpcPropertyData) -> None:
# property_type: 0 → "House"
assert result.property_type == "House"
# ---------------------------------------------------------------------------
# Schema 21.0.1 (most comprehensive — full field coverage)
# ---------------------------------------------------------------------------
class TestFromRdSapSchema21_0_1: class TestFromRdSapSchema21_0_1:
@pytest.fixture @pytest.fixture
def dwelling(self) -> Dwelling: def schema(self) -> RdSapSchema21_0_1:
schema = from_dict(RdSapSchema21_0_1, load("21_0_1.json")) return from_dict(RdSapSchema21_0_1, load("21_0_1.json"))
return EpcPropertyDataMapper.from_rdsap_schema(schema)
# --- property_details --- @pytest.fixture
def result(self, schema: RdSapSchema21_0_1) -> EpcPropertyData:
return EpcPropertyDataMapper.from_rdsap_schema_21_0_1(schema)
def test_property_type(self, dwelling: Dwelling) -> None: # --- general ---
# property_type: 0 → House
assert dwelling.property_details.property_type == "House"
def test_built_form(self, dwelling: Dwelling) -> None: def test_uprn(self, result: EpcPropertyData) -> None:
# built_form: 2 → Semi-detached assert result.uprn == 12457
assert dwelling.property_details.built_form == "Semi-detached"
def test_tenure(self, dwelling: Dwelling) -> None: def test_assessment_type(self, result: EpcPropertyData) -> None:
# tenure: 1 → Owner-occupied assert result.assessment_type == "RdSAP"
assert dwelling.property_details.tenure == "Owner-occupied"
def test_construction_age_band(self, dwelling: Dwelling) -> None: def test_sap_version(self, result: EpcPropertyData) -> None:
# taken directly from sap_building_parts[0].construction_age_band assert result.sap_version == 10.2
assert dwelling.property_details.construction_age_band == "M"
def test_mains_gas_available(self, dwelling: Dwelling) -> None: def test_dwelling_type(self, result: EpcPropertyData) -> None:
# sap_energy_source.mains_gas: "Y" assert result.dwelling_type == "Mid-terrace house"
assert dwelling.property_details.mains_gas_available is True
def test_electricity_smart_meter(self, dwelling: Dwelling) -> None: def test_property_type(self, result: EpcPropertyData) -> None:
# sap_energy_source.electricity_smart_meter_present: "true" # property_type: 0 → "House"
assert dwelling.property_details.electricity_smart_meter is True assert result.property_type == "House"
def test_gas_smart_meter(self, dwelling: Dwelling) -> None: def test_built_form(self, result: EpcPropertyData) -> None:
# sap_energy_source.gas_smart_meter_present: "false" # built_form: 2 → "Semi-detached"
assert dwelling.property_details.gas_smart_meter is False assert result.built_form == "Semi-detached"
# --- floor_dimensions --- def test_address_line_1(self, result: EpcPropertyData) -> None:
assert result.address_line_1 == "1 Some Street"
def test_floor_count(self, dwelling: Dwelling) -> None: def test_postcode(self, result: EpcPropertyData) -> None:
# one SapFloorDimension in the fixture assert result.postcode == "A0 0AA"
assert len(dwelling.floor_dimensions) == 1
def test_floor_area(self, dwelling: Dwelling) -> None: def test_post_town(self, result: EpcPropertyData) -> None:
# total_floor_area.value: 45.82 assert result.post_town == "Whitbury"
assert dwelling.floor_dimensions[0].total_floor_area_m2 == 45.82
def test_floor_height(self, dwelling: Dwelling) -> None: def test_status(self, result: EpcPropertyData) -> None:
# room_height.value: 2.45 assert result.status == "entered"
assert dwelling.floor_dimensions[0].height_m == 2.45
def test_heat_loss_perimeter(self, dwelling: Dwelling) -> None: def test_tenure(self, result: EpcPropertyData) -> None:
# heat_loss_perimeter.value: 19.5 # tenure: 1 — stored as stringified int
assert dwelling.floor_dimensions[0].heat_loss_perimeter_m == 19.5 assert result.tenure == "1"
def test_party_wall_length(self, dwelling: Dwelling) -> None: def test_transaction_type(self, result: EpcPropertyData) -> None:
# party_wall_length.value: 7.9 # transaction_type: 16 — stored as stringified int
assert dwelling.floor_dimensions[0].party_wall_length_m == 7.9 assert result.transaction_type == "16"
# --- walls --- def test_inspection_date(self, result: EpcPropertyData) -> None:
assert result.inspection_date == date(2025, 4, 4)
def test_wall_construction_type(self, dwelling: Dwelling) -> None: def test_total_floor_area(self, result: EpcPropertyData) -> None:
# wall_construction: 4 → Cavity wall assert result.total_floor_area_m2 == 55.0
assert dwelling.walls.construction_type == "Cavity wall"
def test_wall_insulation_type(self, dwelling: Dwelling) -> None: # --- property flags ---
# wall_insulation_type: 2 → As built, insulated (assumed)
assert dwelling.walls.insulation_type == "As built, insulated (assumed)"
def test_wall_thickness(self, dwelling: Dwelling) -> None: def test_solar_water_heating(self, result: EpcPropertyData) -> None:
# wall_thickness_measured: "N" → thickness unknown
assert dwelling.walls.thickness_mm is None
# --- roof ---
def test_roof_insulation_thickness(self, dwelling: Dwelling) -> None:
# roof_insulation_thickness: "200mm"
assert dwelling.roof.insulation_thickness_mm == 200
def test_roof_has_rooms_in_roof(self, dwelling: Dwelling) -> None:
# sap_room_in_roof is present in the fixture
assert dwelling.roof.has_rooms_in_roof is True
# --- windows ---
def test_window_count(self, dwelling: Dwelling) -> None:
assert len(dwelling.windows) == 1
def test_window_height(self, dwelling: Dwelling) -> None:
assert dwelling.windows[0].height_m == 2.0
def test_window_width(self, dwelling: Dwelling) -> None:
assert dwelling.windows[0].width_m == 1.2
def test_window_draught_proofed(self, dwelling: Dwelling) -> None:
# draught_proofed: "true"
assert dwelling.windows[0].draught_proofed is True
# --- main_heating ---
def test_main_heating_fuel(self, dwelling: Dwelling) -> None:
# main_fuel_type: 26 → Mains gas
assert dwelling.main_heating.fuel == "Mains gas"
def test_main_heating_flue_gas_heat_recovery(self, dwelling: Dwelling) -> None:
# has_fghrs: "N"
assert dwelling.main_heating.flue_gas_heat_recovery is False
# --- hot_water ---
def test_hot_water_cylinder_present(self, dwelling: Dwelling) -> None:
# has_hot_water_cylinder: "true"
assert dwelling.hot_water.cylinder_size is not None
# --- secondary_heating ---
def test_secondary_heating_present(self, dwelling: Dwelling) -> None:
# secondary_fuel_type: 25 → electricity
assert dwelling.secondary_heating is not None
# --- ventilation ---
def test_no_fixed_air_conditioning(self, dwelling: Dwelling) -> None:
# has_fixed_air_conditioning: "false"
assert dwelling.ventilation.has_fixed_air_conditioning is False
# --- renewables ---
def test_no_solar_hot_water(self, dwelling: Dwelling) -> None:
# solar_water_heating: "N" # solar_water_heating: "N"
assert dwelling.renewables.has_solar_hot_water is False assert result.solar_water_heating is False
def test_no_wind_turbines(self, dwelling: Dwelling) -> None: def test_has_hot_water_cylinder(self, result: EpcPropertyData) -> None:
# wind_turbines_count: 0 # has_hot_water_cylinder: "true"
assert dwelling.renewables.has_wind_turbines is False assert result.has_hot_water_cylinder is True
def test_pv_battery_count(self, dwelling: Dwelling) -> None: def test_has_fixed_air_conditioning(self, result: EpcPropertyData) -> None:
# pv_battery_count: 1 # has_fixed_air_conditioning: "false"
assert dwelling.renewables.number_of_pv_batteries == 1 assert result.has_fixed_air_conditioning is False
def test_no_conservatory(self, result: EpcPropertyData) -> None:
# conservatory_type: 1 → no conservatory
assert result.has_conservatory is False
# --- counts ---
def test_door_count(self, result: EpcPropertyData) -> None:
assert result.door_count == 3
def test_habitable_rooms(self, result: EpcPropertyData) -> None:
assert result.habitable_rooms_count == 5
def test_heated_rooms(self, result: EpcPropertyData) -> None:
assert result.heated_rooms_count == 5
def test_wet_rooms(self, result: EpcPropertyData) -> None:
assert result.wet_rooms_count == 0
def test_extensions_count(self, result: EpcPropertyData) -> None:
assert result.extensions_count == 0
def test_open_chimneys(self, result: EpcPropertyData) -> None:
assert result.open_chimneys_count == 1
def test_insulated_doors(self, result: EpcPropertyData) -> None:
assert result.insulated_door_count == 2
def test_draughtproofed_doors(self, result: EpcPropertyData) -> None:
assert result.draughtproofed_door_count == 1
# --- lighting --- # --- lighting ---
def test_led_bulbs(self, dwelling: Dwelling) -> None: def test_led_bulbs(self, result: EpcPropertyData) -> None:
assert dwelling.lighting.number_of_led_bulbs == 10 assert result.led_fixed_lighting_bulbs_count == 10
def test_cfl_bulbs(self, dwelling: Dwelling) -> None: def test_cfl_bulbs(self, result: EpcPropertyData) -> None:
assert dwelling.lighting.number_of_cfl_bulbs == 5 assert result.cfl_fixed_lighting_bulbs_count == 5
def test_incandescent_bulbs(self, dwelling: Dwelling) -> None: def test_incandescent_bulbs(self, result: EpcPropertyData) -> None:
assert dwelling.lighting.number_of_incandescent_bulbs == 0 assert result.incandescent_fixed_lighting_bulbs_count == 0
# --- dwelling-level counts --- # --- energy elements ---
def test_habitable_rooms(self, dwelling: Dwelling) -> None: def test_roof_count(self, result: EpcPropertyData) -> None:
assert dwelling.number_of_habitable_rooms == 5 assert len(result.roofs) == 2
def test_external_doors(self, dwelling: Dwelling) -> None: def test_roof_description(self, result: EpcPropertyData) -> None:
assert dwelling.number_of_external_doors == 3 assert result.roofs[0].description == "Pitched, 25 mm loft insulation"
def test_open_chimneys(self, dwelling: Dwelling) -> None: def test_roof_energy_efficiency_rating(self, result: EpcPropertyData) -> None:
assert dwelling.number_of_open_chimneys == 1 assert result.roofs[0].energy_efficiency_rating == 2
def test_no_conservatory(self, dwelling: Dwelling) -> None: def test_wall_count(self, result: EpcPropertyData) -> None:
# conservatory_type: 1 → no conservatory assert len(result.walls) == 2
assert dwelling.has_conservatory is False
def test_window_element_description(self, result: EpcPropertyData) -> None:
assert result.window is not None
assert result.window.description == "Fully double glazed"
def test_window_element_rating(self, result: EpcPropertyData) -> None:
assert result.window is not None
assert result.window.energy_efficiency_rating == 3
def test_lighting_element_description(self, result: EpcPropertyData) -> None:
assert result.lighting is not None
assert result.lighting.description == "Low energy lighting in 50% of fixed outlets"
def test_hot_water_element_description(self, result: EpcPropertyData) -> None:
assert result.hot_water is not None
assert result.hot_water.description == "From main system"
def test_secondary_heating_element(self, result: EpcPropertyData) -> None:
assert result.secondary_heating is not None
assert result.secondary_heating.description == "Room heaters, electric"
def test_main_heating_element_count(self, result: EpcPropertyData) -> None:
assert len(result.main_heating) == 2
def test_main_heating_element_description(self, result: EpcPropertyData) -> None:
assert result.main_heating[0].description == "Boiler and radiators, anthracite"
# --- sap energy source ---
def test_mains_gas(self, result: EpcPropertyData) -> None:
# mains_gas: "Y"
assert result.sap_energy_source.mains_gas is True
def test_electricity_smart_meter(self, result: EpcPropertyData) -> None:
# electricity_smart_meter_present: "true"
assert result.sap_energy_source.electricity_smart_meter_present is True
def test_gas_smart_meter(self, result: EpcPropertyData) -> None:
# gas_smart_meter_present: "false"
assert result.sap_energy_source.gas_smart_meter_present is False
def test_pv_battery_count(self, result: EpcPropertyData) -> None:
assert result.sap_energy_source.pv_battery_count == 1
def test_wind_turbines_count(self, result: EpcPropertyData) -> None:
assert result.sap_energy_source.wind_turbines_count == 0
# --- sap heating ---
def test_cylinder_size(self, result: EpcPropertyData) -> None:
assert result.sap_heating.cylinder_size == 1
def test_water_heating_code(self, result: EpcPropertyData) -> None:
assert result.sap_heating.water_heating_code == 901
def test_water_heating_fuel(self, result: EpcPropertyData) -> None:
assert result.sap_heating.water_heating_fuel == 26
def test_secondary_fuel_type(self, result: EpcPropertyData) -> None:
# secondary_fuel_type: 25
assert result.sap_heating.secondary_fuel_type == 25
def test_main_heating_no_fghrs(self, result: EpcPropertyData) -> None:
# has_fghrs: "N"
assert result.sap_heating.main_heating_details[0].has_fghrs is False
def test_main_heating_fuel_type(self, result: EpcPropertyData) -> None:
# main_fuel_type: 26
assert result.sap_heating.main_heating_details[0].main_fuel_type == 26
def test_main_heating_fan_flue(self, result: EpcPropertyData) -> None:
# fan_flue_present: "N"
assert result.sap_heating.main_heating_details[0].fan_flue_present is False
def test_main_heating_control(self, result: EpcPropertyData) -> None:
assert result.sap_heating.main_heating_details[0].main_heating_control == 2106
def test_main_heating_category(self, result: EpcPropertyData) -> None:
assert result.sap_heating.main_heating_details[0].main_heating_category == 2
def test_main_heating_number(self, result: EpcPropertyData) -> None:
assert result.sap_heating.main_heating_details[0].main_heating_number == 1
# --- sap windows ---
def test_window_count(self, result: EpcPropertyData) -> None:
assert len(result.sap_windows) == 1
def test_window_height(self, result: EpcPropertyData) -> None:
assert result.sap_windows[0].window_height == 2.0
def test_window_width(self, result: EpcPropertyData) -> None:
assert result.sap_windows[0].window_width == 1.2
def test_window_draught_proofed(self, result: EpcPropertyData) -> None:
# draught_proofed: "true"
assert result.sap_windows[0].draught_proofed is True
# --- sap building parts ---
def test_building_part_count(self, result: EpcPropertyData) -> None:
assert len(result.sap_building_parts) == 1
def test_construction_age_band(self, result: EpcPropertyData) -> None:
assert result.sap_building_parts[0].construction_age_band == "M"
def test_wall_construction(self, result: EpcPropertyData) -> None:
# wall_construction: 4 (int preserved from API)
assert result.sap_building_parts[0].wall_construction == 4
def test_wall_insulation_type(self, result: EpcPropertyData) -> None:
# wall_insulation_type: 2 (int preserved from API)
assert result.sap_building_parts[0].wall_insulation_type == 2
def test_wall_thickness_not_measured(self, result: EpcPropertyData) -> None:
# wall_thickness_measured: "N"
assert result.sap_building_parts[0].wall_thickness_measured is False
def test_wall_thickness_mm_absent(self, result: EpcPropertyData) -> None:
assert result.sap_building_parts[0].wall_thickness_mm is None
def test_roof_insulation_thickness(self, result: EpcPropertyData) -> None:
# roof_insulation_thickness: "200mm" — preserved as-is from schema
assert result.sap_building_parts[0].roof_insulation_thickness == "200mm"
def test_room_in_roof_present(self, result: EpcPropertyData) -> None:
# sap_room_in_roof is present in the fixture
assert result.sap_building_parts[0].sap_room_in_roof is not None
# --- floor dimensions ---
def test_floor_count(self, result: EpcPropertyData) -> None:
assert len(result.sap_building_parts[0].sap_floor_dimensions) == 1
def test_floor_area(self, result: EpcPropertyData) -> None:
assert result.sap_building_parts[0].sap_floor_dimensions[0].total_floor_area_m2 == 45.82
def test_floor_height(self, result: EpcPropertyData) -> None:
assert result.sap_building_parts[0].sap_floor_dimensions[0].room_height_m == 2.45
def test_heat_loss_perimeter(self, result: EpcPropertyData) -> None:
assert result.sap_building_parts[0].sap_floor_dimensions[0].heat_loss_perimeter_m == 19.5
def test_party_wall_length(self, result: EpcPropertyData) -> None:
assert result.sap_building_parts[0].sap_floor_dimensions[0].party_wall_length_m == 7.9