mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
109 lines
3.5 KiB
Python
109 lines
3.5 KiB
Python
"""The Landlord-Override construction-age-band → fabric Simulation Overlay.
|
|
|
|
An age-band value resolves to the RdSAP letter code the calculator's U-value
|
|
cascades read from `SapBuildingPart.construction_age_band`; the overlay targets
|
|
the override's building part.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from datatypes.epc.domain.epc_property_data import (
|
|
BuildingPartIdentifier,
|
|
EpcPropertyData,
|
|
SapBuildingPart,
|
|
)
|
|
from domain.epc.property_overrides.construction_age_band import ConstructionAgeBand
|
|
from domain.epc.property_overlays.construction_age_band_overlay import (
|
|
age_band_overlay_for,
|
|
)
|
|
from domain.modelling.scoring.overlay_applicator import apply_simulations
|
|
from tests.domain.sap10_calculator.worksheet._elmhurst_worksheet_000490 import (
|
|
build_epc,
|
|
)
|
|
|
|
|
|
def _part(
|
|
epc: EpcPropertyData, identifier: BuildingPartIdentifier
|
|
) -> SapBuildingPart:
|
|
return next(p for p in epc.sap_building_parts if p.identifier is identifier)
|
|
|
|
|
|
def test_age_band_overlays_the_main_building_part() -> None:
|
|
# Act — band B (1900-1929) on the main building part.
|
|
simulation = age_band_overlay_for("B", 0)
|
|
|
|
# Assert
|
|
assert simulation is not None
|
|
overlay = simulation.building_parts[BuildingPartIdentifier.MAIN]
|
|
assert overlay.construction_age_band == "B"
|
|
|
|
|
|
def test_age_band_overlay_targets_the_extension_building_part() -> None:
|
|
# Act — building_part 1 is the first extension.
|
|
simulation = age_band_overlay_for("L", 1)
|
|
|
|
# Assert
|
|
assert simulation is not None
|
|
assert BuildingPartIdentifier.EXTENSION_1 in simulation.building_parts
|
|
assert (
|
|
simulation.building_parts[BuildingPartIdentifier.EXTENSION_1]
|
|
.construction_age_band
|
|
== "L"
|
|
)
|
|
|
|
|
|
def test_lowercase_age_band_is_normalised_to_its_letter_code() -> None:
|
|
# Act
|
|
simulation = age_band_overlay_for("d", 0)
|
|
|
|
# Assert — the calculator upper-cases the band; the overlay stores it upper.
|
|
assert simulation is not None
|
|
assert (
|
|
simulation.building_parts[BuildingPartIdentifier.MAIN].construction_age_band
|
|
== "D"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("age_band_value", ["Z", "", "1900-1929", "Unknown"])
|
|
def test_unrecognised_age_band_produces_no_overlay(age_band_value: str) -> None:
|
|
# Act
|
|
simulation = age_band_overlay_for(age_band_value, 0)
|
|
|
|
# Assert
|
|
assert simulation is None
|
|
|
|
|
|
def test_age_band_override_re_dates_the_main_part_only() -> None:
|
|
# Arrange — baseline main + extension are both band B; the landlord corrects
|
|
# the main building's age band to F (1976-1982).
|
|
baseline = build_epc()
|
|
overlay = age_band_overlay_for("F", 0)
|
|
assert overlay is not None
|
|
|
|
# Act
|
|
result = apply_simulations(baseline, [overlay])
|
|
|
|
# Assert — the main part is re-dated (its U-value cascade now keys on F); the
|
|
# extension is left untouched.
|
|
assert _part(result, BuildingPartIdentifier.MAIN).construction_age_band == "F"
|
|
assert (
|
|
_part(result, BuildingPartIdentifier.EXTENSION_1).construction_age_band == "B"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"member", [m for m in ConstructionAgeBand if m is not ConstructionAgeBand.UNKNOWN]
|
|
)
|
|
def test_every_resolvable_age_band_value_decodes_to_an_overlay(
|
|
member: ConstructionAgeBand,
|
|
) -> None:
|
|
# A classifier emits a ConstructionAgeBand value; if the overlay can't decode
|
|
# it the override silently no-ops. Every non-UNKNOWN member must resolve.
|
|
|
|
# Act
|
|
simulation = age_band_overlay_for(member.value, 0)
|
|
|
|
# Assert
|
|
assert simulation is not None
|