"""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