From 15ae46ec9230d7dc7a8c1280236a80295f52d15d Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Fri, 24 Apr 2026 13:37:21 +0000 Subject: [PATCH] =?UTF-8?q?Map=20Elmhurst=20site=20notes=20to=20EpcPropert?= =?UTF-8?q?yData=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/test_elmhurst_end_to_end.py | 297 ++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 backend/documents_parser/tests/test_elmhurst_end_to_end.py diff --git a/backend/documents_parser/tests/test_elmhurst_end_to_end.py b/backend/documents_parser/tests/test_elmhurst_end_to_end.py new file mode 100644 index 00000000..8e45e24d --- /dev/null +++ b/backend/documents_parser/tests/test_elmhurst_end_to_end.py @@ -0,0 +1,297 @@ +import json +import os +from datetime import date + +import pytest + +from backend.documents_parser.elmhurst_extractor import ElmhurstSiteNotesExtractor +from datatypes.epc.domain.epc_property_data import ( + EpcPropertyData, + MainHeatingDetail, + SapBuildingPart, + SapEnergySource, + SapFloorDimension, + SapHeating, + SapVentilation, + SapWindow, + ShowerOutlet, + ShowerOutlets, +) +from datatypes.epc.domain.mapper import EpcPropertyDataMapper + +FIXTURE_PATH = os.path.join( + os.path.dirname(__file__), "fixtures", "elmhurst_site_notes_1_text.json" +) + + +@pytest.fixture(scope="module") +def result() -> EpcPropertyData: + with open(FIXTURE_PATH) as f: + pages = json.load(f) + site_notes = ElmhurstSiteNotesExtractor(pages).extract() + return EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes) + + +class TestAddress: + def test_address_line_1(self, result: EpcPropertyData) -> None: + assert result.address_line_1 == "19, Queens Road" + + def test_post_town(self, result: EpcPropertyData) -> None: + assert result.post_town == "BURNLEY" + + def test_postcode(self, result: EpcPropertyData) -> None: + assert result.postcode == "BB10 1XX" + + +class TestInspectionInfo: + def test_inspection_date(self, result: EpcPropertyData) -> None: + assert result.inspection_date == date(2026, 3, 6) + + def test_tenure(self, result: EpcPropertyData) -> None: + assert result.tenure == "Rented (social)" + + def test_transaction_type(self, result: EpcPropertyData) -> None: + assert result.transaction_type == "Grant scheme" + + def test_report_reference(self, result: EpcPropertyData) -> None: + assert result.report_reference == "P960-0001-001573" + + +class TestPropertyDescription: + def test_property_type(self, result: EpcPropertyData) -> None: + assert result.property_type == "Bungalow" + + def test_built_form(self, result: EpcPropertyData) -> None: + assert result.built_form == "End-Terrace" + + def test_dwelling_type(self, result: EpcPropertyData) -> None: + assert result.dwelling_type == "End-Terrace bungalow" + + def test_number_of_storeys(self, result: EpcPropertyData) -> None: + assert result.number_of_storeys == 1 + + def test_has_conservatory(self, result: EpcPropertyData) -> None: + assert result.has_conservatory is False + + def test_total_floor_area(self, result: EpcPropertyData) -> None: + assert result.total_floor_area_m2 == 44.89 + + +class TestCounts: + def test_habitable_rooms_count(self, result: EpcPropertyData) -> None: + assert result.habitable_rooms_count == 2 + + def test_heated_rooms_count(self, result: EpcPropertyData) -> None: + assert result.heated_rooms_count == 2 + + def test_door_count(self, result: EpcPropertyData) -> None: + assert result.door_count == 0 + + def test_insulated_door_count(self, result: EpcPropertyData) -> None: + assert result.insulated_door_count == 0 + + def test_open_chimneys_count(self, result: EpcPropertyData) -> None: + assert result.open_chimneys_count == 0 + + def test_blocked_chimneys_count(self, result: EpcPropertyData) -> None: + assert result.blocked_chimneys_count == 0 + + +class TestLighting: + def test_led_count(self, result: EpcPropertyData) -> None: + assert result.led_fixed_lighting_bulbs_count == 4 + + def test_cfl_count(self, result: EpcPropertyData) -> None: + assert result.cfl_fixed_lighting_bulbs_count == 4 + + def test_incandescent_count(self, result: EpcPropertyData) -> None: + assert result.incandescent_fixed_lighting_bulbs_count == 0 + + +class TestFlags: + def test_solar_water_heating(self, result: EpcPropertyData) -> None: + assert result.solar_water_heating is False + + def test_has_hot_water_cylinder(self, result: EpcPropertyData) -> None: + assert result.has_hot_water_cylinder is False + + def test_has_fixed_air_conditioning(self, result: EpcPropertyData) -> None: + assert result.has_fixed_air_conditioning is False + + def test_hydro(self, result: EpcPropertyData) -> None: + assert result.hydro is False + + def test_photovoltaic_array(self, result: EpcPropertyData) -> None: + assert result.photovoltaic_array is False + + +class TestBuildingPart: + def test_single_building_part(self, result: EpcPropertyData) -> None: + assert len(result.sap_building_parts) == 1 + + def test_identifier(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].identifier == "main" + + def test_construction_age_band(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].construction_age_band == "1950-1966" + + def test_wall_construction(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].wall_construction == "Cavity" + + def test_wall_insulation_type(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].wall_insulation_type == "Filled Cavity" + + def test_wall_thickness_measured(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].wall_thickness_measured is True + + def test_wall_thickness_mm(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].wall_thickness_mm == 300 + + def test_roof_insulation_location(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].roof_insulation_location == "Joists" + + def test_roof_insulation_thickness(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].roof_insulation_thickness == 270 + + def test_floor_type(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].floor_type == "Ground floor" + + def test_floor_construction_type(self, result: EpcPropertyData) -> None: + assert ( + result.sap_building_parts[0].floor_construction_type + == "Suspended, not timber" + ) + + def test_floor_insulation_type_str(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].floor_insulation_type_str == "As built" + + def test_floor_u_value_known(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].floor_u_value_known is False + + def test_single_floor_dimension(self, result: EpcPropertyData) -> None: + assert len(result.sap_building_parts[0].sap_floor_dimensions) == 1 + + def test_floor_dimension_area(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].sap_floor_dimensions[0].total_floor_area_m2 == 44.89 + + def test_floor_dimension_room_height(self, result: EpcPropertyData) -> None: + assert result.sap_building_parts[0].sap_floor_dimensions[0].room_height_m == 2.24 + + def test_floor_dimension_heat_loss_perimeter(self, result: EpcPropertyData) -> None: + assert ( + result.sap_building_parts[0].sap_floor_dimensions[0].heat_loss_perimeter_m + == 20.10 + ) + + def test_floor_dimension_party_wall_length(self, result: EpcPropertyData) -> None: + assert ( + result.sap_building_parts[0].sap_floor_dimensions[0].party_wall_length_m + == 6.70 + ) + + +class TestWindows: + def test_window_count(self, result: EpcPropertyData) -> None: + assert len(result.sap_windows) == 4 + + def test_first_window_width(self, result: EpcPropertyData) -> None: + assert result.sap_windows[0].window_width == 1.30 + + def test_first_window_height(self, result: EpcPropertyData) -> None: + assert result.sap_windows[0].window_height == 1.10 + + def test_first_window_orientation(self, result: EpcPropertyData) -> None: + assert result.sap_windows[0].orientation == "North" + + def test_first_window_glazing_type(self, result: EpcPropertyData) -> None: + assert result.sap_windows[0].glazing_type == "Double post or during 2022" + + def test_first_window_draught_proofed(self, result: EpcPropertyData) -> None: + assert result.sap_windows[0].draught_proofed is True + + def test_third_window_orientation(self, result: EpcPropertyData) -> None: + assert result.sap_windows[2].orientation == "South" + + +class TestHeating: + def test_single_heating_detail(self, result: EpcPropertyData) -> None: + assert len(result.sap_heating.main_heating_details) == 1 + + def test_fuel_type(self, result: EpcPropertyData) -> None: + assert result.sap_heating.main_heating_details[0].main_fuel_type == "Mains gas" + + def test_heat_emitter_type(self, result: EpcPropertyData) -> None: + assert ( + result.sap_heating.main_heating_details[0].heat_emitter_type == "Radiators" + ) + + def test_emitter_temperature(self, result: EpcPropertyData) -> None: + assert ( + result.sap_heating.main_heating_details[0].emitter_temperature == "Unknown" + ) + + def test_fan_flue_present(self, result: EpcPropertyData) -> None: + assert result.sap_heating.main_heating_details[0].fan_flue_present is True + + def test_has_fghrs(self, result: EpcPropertyData) -> None: + assert result.sap_heating.main_heating_details[0].has_fghrs is False + + def test_main_heating_control(self, result: EpcPropertyData) -> None: + assert ( + result.sap_heating.main_heating_details[0].main_heating_control + == "Programmer, room thermostat and TRVs" + ) + + def test_shower_outlet_type(self, result: EpcPropertyData) -> None: + assert result.sap_heating.shower_outlets is not None + assert ( + result.sap_heating.shower_outlets.shower_outlet.shower_outlet_type + == "Electric shower" + ) + + def test_no_hot_water_cylinder_size(self, result: EpcPropertyData) -> None: + assert result.sap_heating.cylinder_size is None + + def test_has_fixed_air_conditioning(self, result: EpcPropertyData) -> None: + assert result.sap_heating.has_fixed_air_conditioning is False + + +class TestEnergySource: + def test_mains_gas(self, result: EpcPropertyData) -> None: + assert result.sap_energy_source.mains_gas is True + + def test_meter_type(self, result: EpcPropertyData) -> None: + assert result.sap_energy_source.meter_type == "Single" + + def test_electricity_smart_meter(self, result: EpcPropertyData) -> None: + assert result.sap_energy_source.electricity_smart_meter_present is False + + def test_gas_smart_meter(self, result: EpcPropertyData) -> None: + assert result.sap_energy_source.gas_smart_meter_present is False + + def test_wind_turbines_count(self, result: EpcPropertyData) -> None: + assert result.sap_energy_source.wind_turbines_count == 0 + + def test_wind_turbines_terrain_type(self, result: EpcPropertyData) -> None: + assert result.sap_energy_source.wind_turbines_terrain_type == "Suburban" + + def test_pv_battery_count(self, result: EpcPropertyData) -> None: + assert result.sap_energy_source.pv_battery_count == 0 + + +class TestVentilation: + def test_draught_lobby(self, result: EpcPropertyData) -> None: + assert result.sap_ventilation is not None + assert result.sap_ventilation.draught_lobby is False + + def test_pressure_test(self, result: EpcPropertyData) -> None: + assert result.sap_ventilation is not None + assert result.sap_ventilation.pressure_test == "Not available" + + def test_extract_fans_count(self, result: EpcPropertyData) -> None: + assert result.sap_ventilation is not None + assert result.sap_ventilation.extract_fans_count == 2 + + def test_open_flues_count(self, result: EpcPropertyData) -> None: + assert result.sap_ventilation is not None + assert result.sap_ventilation.open_flues_count == 0