mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
711 lines
28 KiB
Python
711 lines
28 KiB
Python
import json
|
|
import os
|
|
from datetime import date
|
|
from typing import Any, Dict
|
|
|
|
import pytest
|
|
|
|
from domain.epc.epc_property_data import (
|
|
EpcPropertyData,
|
|
InstantaneousWwhrs,
|
|
MainHeatingDetail,
|
|
SapBuildingPart,
|
|
SapEnergySource,
|
|
SapFloorDimension,
|
|
SapHeating,
|
|
SapVentilation,
|
|
SapWindow,
|
|
ShowerOutlet,
|
|
ShowerOutlets,
|
|
)
|
|
from domain.epc.mapper import EpcPropertyDataMapper
|
|
from datatypes.epc.schema.tests.helpers import from_dict
|
|
from datatypes.epc.surveys.pashub_rdsap_site_notes import PasHubRdSapSiteNotes
|
|
|
|
FIXTURES = os.path.join(os.path.dirname(__file__), "fixtures")
|
|
|
|
|
|
def load(filename: str) -> Dict[str, Any]:
|
|
with open(os.path.join(FIXTURES, filename)) as f:
|
|
return json.load(f) # type: ignore[no-any-return]
|
|
|
|
|
|
class TestFromSiteNotesExample1:
|
|
"""
|
|
Fixture: pashub_rdsap_site_notes_example1.json
|
|
No extensions, regular boiler with cylinder, natural ventilation.
|
|
"""
|
|
|
|
@pytest.fixture
|
|
def survey(self) -> PasHubRdSapSiteNotes:
|
|
return from_dict(
|
|
PasHubRdSapSiteNotes, load("pashub_rdsap_site_notes_example1.json")
|
|
)
|
|
|
|
@pytest.fixture
|
|
def result(self, survey: PasHubRdSapSiteNotes) -> EpcPropertyData:
|
|
return EpcPropertyDataMapper.from_site_notes(survey)
|
|
|
|
# --- property details ---
|
|
|
|
def test_dwelling_type(self, result: EpcPropertyData) -> None:
|
|
# general.property_type + general.detachment_type → "Mid-terrace house"
|
|
assert result.dwelling_type == "Mid-terrace house"
|
|
|
|
def test_tenure(self, result: EpcPropertyData) -> None:
|
|
# general.tenure: "Rented Social"
|
|
assert result.tenure == "Rented Social"
|
|
|
|
def test_transaction_type(self, result: EpcPropertyData) -> None:
|
|
# general.transaction_type: "None of the Above"
|
|
assert result.transaction_type == "None of the Above"
|
|
|
|
def test_inspection_date(self, result: EpcPropertyData) -> None:
|
|
# general.inspection_date: "2026-03-31"
|
|
assert result.inspection_date == date(2026, 3, 31)
|
|
|
|
def test_built_form(self, result: EpcPropertyData) -> None:
|
|
# general.detachment_type: "Mid-terrace"
|
|
assert result.built_form == "Mid-terrace"
|
|
|
|
def test_property_type(self, result: EpcPropertyData) -> None:
|
|
# general.property_type: "House"
|
|
assert result.property_type == "House"
|
|
|
|
# --- energy elements are not available from site notes ---
|
|
|
|
def test_roofs_empty(self, result: EpcPropertyData) -> None:
|
|
assert result.roofs == []
|
|
|
|
def test_walls_empty(self, result: EpcPropertyData) -> None:
|
|
assert result.walls == []
|
|
|
|
def test_floors_empty(self, result: EpcPropertyData) -> None:
|
|
assert result.floors == []
|
|
|
|
def test_main_heating_elements_empty(self, result: EpcPropertyData) -> None:
|
|
assert result.main_heating == []
|
|
|
|
def test_window_element_absent(self, result: EpcPropertyData) -> None:
|
|
assert result.window is None
|
|
|
|
def test_lighting_element_absent(self, result: EpcPropertyData) -> None:
|
|
assert result.lighting is None
|
|
|
|
def test_hot_water_element_absent(self, result: EpcPropertyData) -> None:
|
|
assert result.hot_water is None
|
|
|
|
# --- energy source ---
|
|
|
|
def test_mains_gas_available(self, result: EpcPropertyData) -> None:
|
|
# general.mains_gas_available: true
|
|
assert result.sap_energy_source.mains_gas is True
|
|
|
|
def test_electricity_smart_meter(self, result: EpcPropertyData) -> None:
|
|
# general.electricity_smart_meter: true
|
|
assert result.sap_energy_source.electricity_smart_meter_present is True
|
|
|
|
def test_gas_smart_meter(self, result: EpcPropertyData) -> None:
|
|
# general.gas_smart_meter: true
|
|
assert result.sap_energy_source.gas_smart_meter_present is True
|
|
|
|
def test_meter_type(self, result: EpcPropertyData) -> None:
|
|
# general.electric_meter_type: "Single"
|
|
assert result.sap_energy_source.meter_type == "Single"
|
|
|
|
def test_dwelling_export_capable(self, result: EpcPropertyData) -> None:
|
|
# general.dwelling_export_capable: true
|
|
assert result.sap_energy_source.is_dwelling_export_capable is True
|
|
|
|
def test_wind_turbines_terrain_type(self, result: EpcPropertyData) -> None:
|
|
# general.terrain_type: "Suburban"
|
|
assert result.sap_energy_source.wind_turbines_terrain_type == "Suburban"
|
|
|
|
def test_no_wind_turbines(self, result: EpcPropertyData) -> None:
|
|
# renewables.wind_turbines: false → count 0
|
|
assert result.sap_energy_source.wind_turbines_count == 0
|
|
|
|
def test_no_pv_batteries(self, result: EpcPropertyData) -> None:
|
|
# renewables.number_of_pv_batteries: 0
|
|
assert result.sap_energy_source.pv_battery_count == 0
|
|
|
|
# --- renewables ---
|
|
|
|
def test_no_solar_hot_water(self, result: EpcPropertyData) -> None:
|
|
# renewables.solar_hot_water: false
|
|
assert result.solar_water_heating is False
|
|
|
|
# --- ventilation ---
|
|
|
|
def test_no_fixed_air_conditioning(self, result: EpcPropertyData) -> None:
|
|
# ventilation.has_fixed_air_conditioning: false
|
|
assert result.has_fixed_air_conditioning is False
|
|
|
|
# --- conservatory ---
|
|
|
|
def test_no_conservatory(self, result: EpcPropertyData) -> None:
|
|
# conservatories.has_conservatory: false
|
|
assert result.has_conservatory is False
|
|
|
|
# --- hot water / cylinder ---
|
|
|
|
def test_has_hot_water_cylinder(self, result: EpcPropertyData) -> None:
|
|
# water_heating.cylinder_size is present → cylinder exists
|
|
assert result.has_hot_water_cylinder is True
|
|
|
|
# --- main heating ---
|
|
|
|
def test_main_heating_fuel(self, result: EpcPropertyData) -> None:
|
|
# heating_and_hot_water.main_heating.fuel: "Mains gas"
|
|
assert result.sap_heating.main_heating_details[0].main_fuel_type == "Mains gas"
|
|
|
|
def test_main_heating_emitter(self, result: EpcPropertyData) -> None:
|
|
# heating_and_hot_water.main_heating.emitter: "Radiators"
|
|
assert (
|
|
result.sap_heating.main_heating_details[0].heat_emitter_type == "Radiators"
|
|
)
|
|
|
|
def test_main_heating_no_fghrs(self, result: EpcPropertyData) -> None:
|
|
# heating_and_hot_water.main_heating.flue_gas_heat_recovery_system: false
|
|
assert result.sap_heating.main_heating_details[0].has_fghrs is False
|
|
|
|
def test_main_heating_fan_flue_present(self, result: EpcPropertyData) -> None:
|
|
# heating_and_hot_water.main_heating.fan_assist: true
|
|
assert result.sap_heating.main_heating_details[0].fan_flue_present is True
|
|
|
|
def test_no_secondary_heating(self, result: EpcPropertyData) -> None:
|
|
# secondary_heating.secondary_fuel: "No Secondary Heating" → no secondary fuel type
|
|
assert result.sap_heating.secondary_fuel_type is None
|
|
|
|
# --- windows ---
|
|
|
|
def test_window_count(self, result: EpcPropertyData) -> None:
|
|
# 4 windows in fixture
|
|
assert len(result.sap_windows) == 4
|
|
|
|
def test_window_height(self, result: EpcPropertyData) -> None:
|
|
assert result.sap_windows[0].window_height == 1.36
|
|
|
|
def test_window_width(self, result: EpcPropertyData) -> None:
|
|
assert result.sap_windows[0].window_width == 1.0
|
|
|
|
def test_window_draught_proofed(self, result: EpcPropertyData) -> None:
|
|
# windows[0].draught_proofed: true
|
|
assert result.sap_windows[0].draught_proofed is True
|
|
|
|
def test_window_orientation(self, result: EpcPropertyData) -> None:
|
|
assert result.sap_windows[0].orientation == "South East"
|
|
|
|
def test_window_glazing_type(self, result: EpcPropertyData) -> None:
|
|
assert (
|
|
result.sap_windows[0].glazing_type == "Double glazing, Unknown install date"
|
|
)
|
|
|
|
# --- building parts ---
|
|
|
|
def test_building_parts_count(self, result: EpcPropertyData) -> None:
|
|
# no extensions → one building part for main building
|
|
assert len(result.sap_building_parts) == 1
|
|
|
|
def test_building_part_identifier(self, result: EpcPropertyData) -> None:
|
|
assert result.sap_building_parts[0].identifier == "main"
|
|
|
|
def test_construction_age_band(self, result: EpcPropertyData) -> None:
|
|
# main_building.age_range: "I: 1996 - 2002" → letter "I"
|
|
assert result.sap_building_parts[0].construction_age_band == "I"
|
|
|
|
def test_wall_construction(self, result: EpcPropertyData) -> None:
|
|
# main_building.walls_construction_type: "Cavity"
|
|
assert result.sap_building_parts[0].wall_construction == "Cavity"
|
|
|
|
def test_wall_insulation_type(self, result: EpcPropertyData) -> None:
|
|
# main_building.walls_insulation_type: "As built"
|
|
assert result.sap_building_parts[0].wall_insulation_type == "As built"
|
|
|
|
def test_wall_thickness_measured(self, result: EpcPropertyData) -> None:
|
|
# main_building.wall_thickness_mm: 280 → thickness was measured
|
|
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 == 280
|
|
|
|
# --- floor dimensions ---
|
|
|
|
def test_floor_count(self, result: EpcPropertyData) -> None:
|
|
# 2 floors in main building
|
|
assert len(result.sap_building_parts[0].sap_floor_dimensions) == 2
|
|
|
|
def test_floor_area(self, result: EpcPropertyData) -> None:
|
|
# building_measurements.main_building.floors[0].area_m2: 24.78
|
|
assert (
|
|
result.sap_building_parts[0].sap_floor_dimensions[0].total_floor_area_m2
|
|
== 24.78
|
|
)
|
|
|
|
def test_floor_height(self, result: EpcPropertyData) -> None:
|
|
# floors[0].height_m: 2.37
|
|
assert (
|
|
result.sap_building_parts[0].sap_floor_dimensions[0].room_height_m == 2.37
|
|
)
|
|
|
|
def test_heat_loss_perimeter(self, result: EpcPropertyData) -> None:
|
|
# floors[0].heat_loss_perimeter_m: 14.21
|
|
assert (
|
|
result.sap_building_parts[0].sap_floor_dimensions[0].heat_loss_perimeter_m
|
|
== 14.21
|
|
)
|
|
|
|
def test_party_wall_length(self, result: EpcPropertyData) -> None:
|
|
# floors[0].pwl_m: 6.15
|
|
assert (
|
|
result.sap_building_parts[0].sap_floor_dimensions[0].party_wall_length_m
|
|
== 6.15
|
|
)
|
|
|
|
def test_total_floor_area(self, result: EpcPropertyData) -> None:
|
|
# sum of all floor areas: 24.78 + 24.78 = 49.56
|
|
assert result.total_floor_area_m2 == 49.56
|
|
|
|
# --- room counts ---
|
|
|
|
def test_habitable_rooms(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_habitable_rooms: 2
|
|
assert result.habitable_rooms_count == 2
|
|
|
|
def test_external_doors(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_external_doors: 2
|
|
assert result.door_count == 2
|
|
|
|
def test_open_chimneys(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_open_chimneys: 0
|
|
assert result.open_chimneys_count == 0
|
|
|
|
def test_blocked_chimneys(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_blocked_chimneys: 0
|
|
assert result.blocked_chimneys_count == 0
|
|
|
|
def test_insulated_doors(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_insulated_external_doors: 0
|
|
assert result.insulated_door_count == 0
|
|
|
|
def test_draughtproofed_doors(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_draughtproofed_external_doors: 2
|
|
assert result.draughtproofed_door_count == 2
|
|
|
|
def test_extensions_count(self, result: EpcPropertyData) -> None:
|
|
# general.number_of_extensions: 0
|
|
assert result.extensions_count == 0
|
|
|
|
def test_heated_rooms_count(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_heated_rooms: 0
|
|
# no equivalent in site notes defaults to 0
|
|
assert result.heated_rooms_count == 0
|
|
|
|
def test_wet_rooms_count_defaults_to_zero(self, result: EpcPropertyData) -> None:
|
|
# no equivalent in site notes; mapper must default to 0
|
|
assert result.wet_rooms_count == 0
|
|
|
|
# --- lighting ---
|
|
|
|
def test_led_bulbs(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_fixed_led_bulbs: 5
|
|
assert result.led_fixed_lighting_bulbs_count == 5
|
|
|
|
def test_cfl_bulbs(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_fixed_cfl_bulbs: 4
|
|
assert result.cfl_fixed_lighting_bulbs_count == 4
|
|
|
|
def test_incandescent_bulbs(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.number_of_fixed_incandescent_bulbs: 0
|
|
assert result.incandescent_fixed_lighting_bulbs_count == 0
|
|
|
|
# --- api-only fields absent ---
|
|
|
|
def test_assessment_type_absent(self, result: EpcPropertyData) -> None:
|
|
assert result.assessment_type is None
|
|
|
|
def test_sap_version_absent(self, result: EpcPropertyData) -> None:
|
|
assert result.sap_version is None
|
|
|
|
def test_uprn_absent(self, result: EpcPropertyData) -> None:
|
|
assert result.uprn is None
|
|
|
|
def test_address_line_1(self, result: EpcPropertyData) -> None:
|
|
assert result.address_line_1 == "1, Test Street"
|
|
|
|
def test_postcode(self, result: EpcPropertyData) -> None:
|
|
assert result.postcode == "TE1 1ST"
|
|
|
|
def test_post_town(self, result: EpcPropertyData) -> None:
|
|
assert result.post_town == "Test Town"
|
|
|
|
def test_status_absent(self, result: EpcPropertyData) -> None:
|
|
assert result.status is None
|
|
|
|
# --- full object equality ---
|
|
|
|
def test_full_mapping(self, survey: PasHubRdSapSiteNotes) -> None:
|
|
result = EpcPropertyDataMapper.from_site_notes(survey)
|
|
expected = EpcPropertyData(
|
|
# General
|
|
assessment_type=None,
|
|
sap_version=None,
|
|
dwelling_type="Mid-terrace house",
|
|
uprn=None,
|
|
address_line_1="1, Test Street",
|
|
postcode="TE1 1ST",
|
|
post_town="Test Town",
|
|
inspection_date=date(2026, 3, 31),
|
|
status=None,
|
|
tenure="Rented Social",
|
|
transaction_type="None of the Above",
|
|
# Elements (not available from site notes)
|
|
roofs=[],
|
|
walls=[],
|
|
floors=[],
|
|
main_heating=[],
|
|
window=None,
|
|
lighting=None,
|
|
hot_water=None,
|
|
door_count=2,
|
|
# Heating
|
|
sap_heating=SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=False,
|
|
main_fuel_type="Mains gas",
|
|
heat_emitter_type="Radiators",
|
|
emitter_temperature="Unknown",
|
|
fan_flue_present=True,
|
|
main_heating_control="Programmer, room thermostat and TRVs",
|
|
condensing=True,
|
|
weather_compensator=False,
|
|
central_heating_pump_age_str="Unknown",
|
|
)
|
|
],
|
|
has_fixed_air_conditioning=False,
|
|
cylinder_size="Normal (90-130 litres)",
|
|
cylinder_insulation_type="Factory fitted",
|
|
cylinder_insulation_thickness_mm=12,
|
|
shower_outlets=ShowerOutlets(
|
|
shower_outlet=ShowerOutlet(shower_outlet_type="Non-Electric Shower"),
|
|
),
|
|
),
|
|
# Windows
|
|
sap_windows=[
|
|
SapWindow(
|
|
frame_material="Wooden or PVC",
|
|
glazing_gap="16 mm or more",
|
|
orientation="South East",
|
|
window_type="Window",
|
|
glazing_type="Double glazing, Unknown install date",
|
|
window_width=1.0,
|
|
window_height=1.36,
|
|
draught_proofed=True,
|
|
window_location="Main Building",
|
|
window_wall_type="External wall",
|
|
permanent_shutters_present=False,
|
|
),
|
|
SapWindow(
|
|
frame_material="Wooden or PVC",
|
|
glazing_gap="16 mm or more",
|
|
orientation="South East",
|
|
window_type="Window",
|
|
glazing_type="Double glazing, Unknown install date",
|
|
window_width=0.96,
|
|
window_height=1.33,
|
|
draught_proofed=True,
|
|
window_location="Main Building",
|
|
window_wall_type="External wall",
|
|
permanent_shutters_present=False,
|
|
),
|
|
SapWindow(
|
|
frame_material="Wooden or PVC",
|
|
glazing_gap="16 mm or more",
|
|
orientation="North West",
|
|
window_type="Window",
|
|
glazing_type="Double glazing, Unknown install date",
|
|
window_width=0.96,
|
|
window_height=1.04,
|
|
draught_proofed=True,
|
|
window_location="Main Building",
|
|
window_wall_type="External wall",
|
|
permanent_shutters_present=False,
|
|
),
|
|
SapWindow(
|
|
frame_material="Wooden or PVC",
|
|
glazing_gap="16 mm or more",
|
|
orientation="North West",
|
|
window_type="Window",
|
|
glazing_type="Double glazing, Unknown install date",
|
|
window_width=0.97,
|
|
window_height=1.02,
|
|
draught_proofed=True,
|
|
window_location="Main Building",
|
|
window_wall_type="External wall",
|
|
permanent_shutters_present=False,
|
|
),
|
|
],
|
|
# Energy source
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=True,
|
|
meter_type="Single",
|
|
pv_battery_count=0,
|
|
wind_turbines_count=0,
|
|
gas_smart_meter_present=True,
|
|
is_dwelling_export_capable=True,
|
|
wind_turbines_terrain_type="Suburban",
|
|
electricity_smart_meter_present=True,
|
|
),
|
|
# Building parts
|
|
sap_building_parts=[
|
|
SapBuildingPart(
|
|
identifier="main",
|
|
construction_age_band="I",
|
|
wall_construction="Cavity",
|
|
wall_insulation_type="As built",
|
|
wall_thickness_measured=True,
|
|
party_wall_construction="Cavity Masonry, Unfilled",
|
|
sap_floor_dimensions=[
|
|
SapFloorDimension(
|
|
room_height_m=2.37,
|
|
total_floor_area_m2=24.78,
|
|
party_wall_length_m=6.15,
|
|
heat_loss_perimeter_m=14.21,
|
|
floor=1,
|
|
),
|
|
SapFloorDimension(
|
|
room_height_m=2.35,
|
|
total_floor_area_m2=24.78,
|
|
party_wall_length_m=6.15,
|
|
heat_loss_perimeter_m=14.21,
|
|
floor=0,
|
|
),
|
|
],
|
|
wall_thickness_mm=280,
|
|
roof_insulation_location="Joists",
|
|
roof_insulation_thickness=100,
|
|
floor_type="Ground Floor",
|
|
floor_construction_type="Suspended, not timber",
|
|
floor_insulation_type_str="As Built",
|
|
floor_u_value_known=False,
|
|
)
|
|
],
|
|
solar_water_heating=False,
|
|
has_hot_water_cylinder=True,
|
|
has_fixed_air_conditioning=False,
|
|
# Counts
|
|
wet_rooms_count=0, # no equivalent in site notes
|
|
extensions_count=0,
|
|
heated_rooms_count=0,
|
|
open_chimneys_count=0,
|
|
habitable_rooms_count=2,
|
|
insulated_door_count=0,
|
|
cfl_fixed_lighting_bulbs_count=4,
|
|
led_fixed_lighting_bulbs_count=5,
|
|
incandescent_fixed_lighting_bulbs_count=0,
|
|
total_floor_area_m2=49.56,
|
|
# Optional fields populated from site notes
|
|
built_form="Mid-terrace",
|
|
property_type="House",
|
|
has_conservatory=False,
|
|
blocked_chimneys_count=0,
|
|
draughtproofed_door_count=2,
|
|
report_reference="49D422A9-0779-44DD-9665-464D35DFF1A8",
|
|
number_of_storeys=2,
|
|
any_unheated_rooms=True,
|
|
waste_water_heat_recovery="None",
|
|
hydro=False,
|
|
photovoltaic_array=False,
|
|
sap_ventilation=SapVentilation(
|
|
ventilation_type="Natural",
|
|
open_flues_count=0,
|
|
closed_flues_count=0,
|
|
boiler_flues_count=0,
|
|
other_flues_count=0,
|
|
extract_fans_count=2,
|
|
passive_vents_count=0,
|
|
flueless_gas_fires_count=0,
|
|
pressure_test="No test",
|
|
draught_lobby=False,
|
|
),
|
|
)
|
|
assert result == expected
|
|
|
|
|
|
class TestFromSiteNotesVentilation:
|
|
"""
|
|
Fixture: pashub_rdsap_site_notes_example1.json
|
|
Ventilation: Natural, 2 extract fans, no flues, no test, no draught lobby.
|
|
"""
|
|
|
|
@pytest.fixture
|
|
def survey(self) -> PasHubRdSapSiteNotes:
|
|
return from_dict(
|
|
PasHubRdSapSiteNotes, load("pashub_rdsap_site_notes_example1.json")
|
|
)
|
|
|
|
@pytest.fixture
|
|
def result(self, survey: PasHubRdSapSiteNotes) -> EpcPropertyData:
|
|
return EpcPropertyDataMapper.from_site_notes(survey)
|
|
|
|
def test_sap_ventilation_present(self, result: EpcPropertyData) -> None:
|
|
assert result.sap_ventilation is not None
|
|
|
|
def test_ventilation_type(self, result: EpcPropertyData) -> None:
|
|
# ventilation.ventilation_type: "Natural"
|
|
assert result.sap_ventilation.ventilation_type == "Natural"
|
|
|
|
def test_open_flues_count(self, result: EpcPropertyData) -> None:
|
|
# ventilation.number_of_open_flues: 0
|
|
assert result.sap_ventilation.open_flues_count == 0
|
|
|
|
def test_closed_flues_count(self, result: EpcPropertyData) -> None:
|
|
# ventilation.number_of_closed_flues: 0
|
|
assert result.sap_ventilation.closed_flues_count == 0
|
|
|
|
def test_boiler_flues_count(self, result: EpcPropertyData) -> None:
|
|
# ventilation.number_of_boiler_flues: 0
|
|
assert result.sap_ventilation.boiler_flues_count == 0
|
|
|
|
def test_other_flues_count(self, result: EpcPropertyData) -> None:
|
|
# ventilation.number_of_other_flues: 0
|
|
assert result.sap_ventilation.other_flues_count == 0
|
|
|
|
def test_extract_fans_count(self, result: EpcPropertyData) -> None:
|
|
# ventilation.number_of_extract_fans: 2
|
|
assert result.sap_ventilation.extract_fans_count == 2
|
|
|
|
def test_passive_vents_count(self, result: EpcPropertyData) -> None:
|
|
# ventilation.number_of_passive_vents: 0
|
|
assert result.sap_ventilation.passive_vents_count == 0
|
|
|
|
def test_flueless_gas_fires_count(self, result: EpcPropertyData) -> None:
|
|
# ventilation.number_of_flueless_gas_fires: 0
|
|
assert result.sap_ventilation.flueless_gas_fires_count == 0
|
|
|
|
def test_pressure_test(self, result: EpcPropertyData) -> None:
|
|
# ventilation.pressure_test: "No test"
|
|
assert result.sap_ventilation.pressure_test == "No test"
|
|
|
|
def test_draught_lobby(self, result: EpcPropertyData) -> None:
|
|
# ventilation.draught_lobby: false
|
|
assert result.sap_ventilation.draught_lobby is False
|
|
|
|
|
|
class TestFromSiteNotesFloorConstruction:
|
|
"""
|
|
Fixture: pashub_rdsap_site_notes_example1.json
|
|
Floor: Suspended not timber, As Built insulation, Ground Floor type.
|
|
"""
|
|
|
|
@pytest.fixture
|
|
def survey(self) -> PasHubRdSapSiteNotes:
|
|
return from_dict(
|
|
PasHubRdSapSiteNotes, load("pashub_rdsap_site_notes_example1.json")
|
|
)
|
|
|
|
@pytest.fixture
|
|
def result(self, survey: PasHubRdSapSiteNotes) -> EpcPropertyData:
|
|
return EpcPropertyDataMapper.from_site_notes(survey)
|
|
|
|
def test_floor_type(self, result: EpcPropertyData) -> None:
|
|
# building_construction.floor.floor_type: "Ground Floor"
|
|
assert result.sap_building_parts[0].floor_type == "Ground Floor"
|
|
|
|
def test_floor_construction_type(self, result: EpcPropertyData) -> None:
|
|
# building_construction.floor.floor_construction: "Suspended, not timber"
|
|
assert result.sap_building_parts[0].floor_construction_type == "Suspended, not timber"
|
|
|
|
def test_floor_insulation_type_str(self, result: EpcPropertyData) -> None:
|
|
# building_construction.floor.floor_insulation_type: "As Built"
|
|
assert result.sap_building_parts[0].floor_insulation_type_str == "As Built"
|
|
|
|
def test_floor_u_value_known(self, result: EpcPropertyData) -> None:
|
|
# building_construction.floor.floor_u_value_known: false
|
|
assert result.sap_building_parts[0].floor_u_value_known is False
|
|
|
|
|
|
class TestFromSiteNotesHeatingBoiler:
|
|
"""
|
|
Fixture: pashub_rdsap_site_notes_example1.json
|
|
Boiler: Vaillant ecoFIT sustain, condensing, no weather compensator, pump age unknown.
|
|
"""
|
|
|
|
@pytest.fixture
|
|
def survey(self) -> PasHubRdSapSiteNotes:
|
|
return from_dict(
|
|
PasHubRdSapSiteNotes, load("pashub_rdsap_site_notes_example1.json")
|
|
)
|
|
|
|
@pytest.fixture
|
|
def result(self, survey: PasHubRdSapSiteNotes) -> EpcPropertyData:
|
|
return EpcPropertyDataMapper.from_site_notes(survey)
|
|
|
|
def test_condensing(self, result: EpcPropertyData) -> None:
|
|
# heating_and_hot_water.main_heating.condensing: true
|
|
assert result.sap_heating.main_heating_details[0].condensing is True
|
|
|
|
def test_weather_compensator(self, result: EpcPropertyData) -> None:
|
|
# heating_and_hot_water.main_heating.weather_compensator: false
|
|
assert result.sap_heating.main_heating_details[0].weather_compensator is False
|
|
|
|
def test_central_heating_pump_age_str(self, result: EpcPropertyData) -> None:
|
|
# heating_and_hot_water.main_heating.central_heating_pump_age: "Unknown"
|
|
assert result.sap_heating.main_heating_details[0].central_heating_pump_age_str == "Unknown"
|
|
|
|
|
|
class TestFromSiteNotesMiscTopLevel:
|
|
"""
|
|
Fixture: pashub_rdsap_site_notes_example1.json
|
|
Misc fields: 2 storeys, unheated rooms present, no hydro, no PV array, no WWHR.
|
|
"""
|
|
|
|
@pytest.fixture
|
|
def survey(self) -> PasHubRdSapSiteNotes:
|
|
return from_dict(
|
|
PasHubRdSapSiteNotes, load("pashub_rdsap_site_notes_example1.json")
|
|
)
|
|
|
|
@pytest.fixture
|
|
def result(self, survey: PasHubRdSapSiteNotes) -> EpcPropertyData:
|
|
return EpcPropertyDataMapper.from_site_notes(survey)
|
|
|
|
def test_number_of_storeys(self, result: EpcPropertyData) -> None:
|
|
# general.number_of_storeys: 2
|
|
assert result.number_of_storeys == 2
|
|
|
|
def test_any_unheated_rooms(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.any_unheated_rooms: true
|
|
assert result.any_unheated_rooms is True
|
|
|
|
def test_waste_water_heat_recovery(self, result: EpcPropertyData) -> None:
|
|
# room_count_elements.waste_water_heat_recovery: "None"
|
|
assert result.waste_water_heat_recovery == "None"
|
|
|
|
def test_hydro(self, result: EpcPropertyData) -> None:
|
|
# renewables.hydro: false
|
|
assert result.hydro is False
|
|
|
|
def test_photovoltaic_array(self, result: EpcPropertyData) -> None:
|
|
# renewables.photovoltaic_array: false
|
|
assert result.photovoltaic_array is False
|
|
|
|
|
|
class TestUnmeasurableWallThickness:
|
|
"""wall_thickness_mm=None in site notes → wall_thickness_measured=False in domain."""
|
|
|
|
@pytest.fixture
|
|
def result(self) -> EpcPropertyData:
|
|
survey = from_dict(
|
|
PasHubRdSapSiteNotes,
|
|
load("pashub_rdsap_site_notes_example_unmeasurable_wall.json"),
|
|
)
|
|
return EpcPropertyDataMapper.from_site_notes(survey)
|
|
|
|
def test_wall_thickness_measured_is_false(self, result: EpcPropertyData) -> None:
|
|
assert result.sap_building_parts[0].wall_thickness_measured is False
|
|
|
|
def test_wall_thickness_mm_is_none(self, result: EpcPropertyData) -> None:
|
|
assert result.sap_building_parts[0].wall_thickness_mm is None
|