mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-27 23:35:01 +00:00
Lodge explicit zero roof insulation for a surveyed "Insulation At: None" 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
178af2f044
commit
66e0adf619
1 changed files with 69 additions and 0 deletions
|
|
@ -74,6 +74,75 @@ class TestRoofConstructionTypeCoding:
|
|||
assert extension_part.roof_construction_type == "Flat"
|
||||
|
||||
|
||||
class TestRoofInsulationNoneCoding:
|
||||
"""A surveyed roof-space "Insulation At: None" is the assessor explicitly
|
||||
recording ZERO loft insulation — `from_site_notes` must lodge an explicit
|
||||
`roof_insulation_thickness=0`, not leave it `None` ("unknown"). With `None`
|
||||
the calculator's `u_roof` falls through to the age-band "assumed insulated"
|
||||
default (e.g. 0.16 W/m²K at band J/K) instead of the Table 16 uninsulated
|
||||
row (2.30) — a ~14x understatement of roof heat loss (issue #1590 bug 2;
|
||||
fixtures 507665533138 / 507670893756 over-rate by ~7 SAP each).
|
||||
"""
|
||||
|
||||
def test_insulation_at_none_lodges_explicit_zero_thickness(self) -> None:
|
||||
# Arrange — the surveyor recorded "Insulation At: None" (no thickness
|
||||
# line follows; there is no insulation to measure).
|
||||
data = load("pashub_rdsap_site_notes_example1.json")
|
||||
data["roof_space"]["main_building"]["insulation_at"] = "None"
|
||||
data["roof_space"]["main_building"]["insulation_thickness_mm"] = None
|
||||
survey = from_dict(PasHubRdSapSiteNotes, data)
|
||||
|
||||
# Act
|
||||
result = EpcPropertyDataMapper.from_site_notes(survey)
|
||||
|
||||
# Assert — explicit zero, so u_roof takes the uninsulated branch.
|
||||
assert result.sap_building_parts[0].roof_insulation_thickness == 0
|
||||
|
||||
def test_surveyed_thickness_still_passes_through(self) -> None:
|
||||
# Arrange — the fixture's as-lodged "Joists" + 100mm.
|
||||
survey = from_dict(
|
||||
PasHubRdSapSiteNotes, load("pashub_rdsap_site_notes_example1.json")
|
||||
)
|
||||
|
||||
# Act
|
||||
result = EpcPropertyDataMapper.from_site_notes(survey)
|
||||
|
||||
# Assert
|
||||
assert result.sap_building_parts[0].roof_insulation_thickness == 100
|
||||
|
||||
def test_blank_insulation_at_stays_unknown(self) -> None:
|
||||
# Arrange — a blank lodging is "not surveyed", NOT "no insulation";
|
||||
# it must stay None so the age-band default still applies.
|
||||
data = load("pashub_rdsap_site_notes_example1.json")
|
||||
data["roof_space"]["main_building"]["insulation_at"] = ""
|
||||
data["roof_space"]["main_building"]["insulation_thickness_mm"] = None
|
||||
survey = from_dict(PasHubRdSapSiteNotes, data)
|
||||
|
||||
# Act
|
||||
result = EpcPropertyDataMapper.from_site_notes(survey)
|
||||
|
||||
# Assert
|
||||
assert result.sap_building_parts[0].roof_insulation_thickness is None
|
||||
|
||||
def test_extension_insulation_at_none_lodges_explicit_zero(self) -> None:
|
||||
# Arrange — same behaviour on the extension building part.
|
||||
data = load("pashub_rdsap_site_notes_example2.json")
|
||||
data["roof_space"]["extensions"][0]["insulation_at"] = "None"
|
||||
data["roof_space"]["extensions"][0]["insulation_thickness_mm"] = None
|
||||
survey = from_dict(PasHubRdSapSiteNotes, data)
|
||||
|
||||
# Act
|
||||
result = EpcPropertyDataMapper.from_site_notes(survey)
|
||||
|
||||
# Assert
|
||||
extension_part = next(
|
||||
bp
|
||||
for bp in result.sap_building_parts
|
||||
if bp.identifier != BuildingPartIdentifier.MAIN
|
||||
)
|
||||
assert extension_part.roof_insulation_thickness == 0
|
||||
|
||||
|
||||
class TestCountryCode:
|
||||
"""`from_site_notes` must set `country_code` so the cascade's England /
|
||||
Wales / Scotland / NI U-value tables (`u_floor`, `u_basement_floor`,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue