mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-08-03 05:18:22 +00:00
test(overlay): RED — band -> (winter,summer) slot on gas/oil boiler overlay
C-and-below reuse accredited Table 4b pairs; A/B pending Elmhurst (no slot yet, no invented numbers); non-banded boilers (solid/electric/CPSU) ignore the band. The base code is unchanged; only the efficiency slot is set (ADR-0068). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b41c25e756
commit
7a35d177b2
1 changed files with 124 additions and 0 deletions
124
tests/domain/epc/test_boiler_efficiency_band_overlay.py
Normal file
124
tests/domain/epc/test_boiler_efficiency_band_overlay.py
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
|
||||
from domain.epc.property_overrides.boiler_efficiency_band import BoilerEfficiencyBand
|
||||
from domain.epc.property_overlays.main_heating_system_overlay import (
|
||||
band_seasonal_efficiency_pct,
|
||||
main_heating_overlay_for,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("base_code", "band", "expected"),
|
||||
[
|
||||
# Gas regular (base 102) — C-and-below reuse the accredited Table 4b
|
||||
# (winter, summer) of the code the band maps to (ADR-0068).
|
||||
(102, BoilerEfficiencyBand.C, (84.0, 74.0)), # code 102
|
||||
(102, BoilerEfficiencyBand.D, (80.0, 70.0)), # code 106
|
||||
(102, BoilerEfficiencyBand.E, (74.0, 64.0)), # code 101
|
||||
(102, BoilerEfficiencyBand.F, (70.0, 60.0)), # code 105
|
||||
(102, BoilerEfficiencyBand.G, (66.0, 56.0)), # code 115
|
||||
# Gas combi (base 104).
|
||||
(104, BoilerEfficiencyBand.C, (84.0, 75.0)), # code 104
|
||||
(104, BoilerEfficiencyBand.D, (80.0, 71.0)), # code 108
|
||||
(104, BoilerEfficiencyBand.G, (66.0, 57.0)), # code 118
|
||||
# Oil regular (base 127) — E/F nearest-fit to code 125 (⚠ ADR-0068).
|
||||
(127, BoilerEfficiencyBand.C, (84.0, 72.0)), # code 127
|
||||
(127, BoilerEfficiencyBand.D, (80.0, 68.0)), # code 126
|
||||
(127, BoilerEfficiencyBand.E, (71.0, 59.0)), # code 125
|
||||
(127, BoilerEfficiencyBand.G, (66.0, 54.0)), # code 124
|
||||
# Oil combi (base 130) — D/E to code 129, F/G to code 128 (⚠ ADR-0068).
|
||||
(130, BoilerEfficiencyBand.C, (82.0, 73.0)), # code 130
|
||||
(130, BoilerEfficiencyBand.D, (77.0, 68.0)), # code 129
|
||||
(130, BoilerEfficiencyBand.F, (71.0, 62.0)), # code 128
|
||||
],
|
||||
)
|
||||
def test_c_and_below_bands_resolve_to_the_table_4b_pair(
|
||||
base_code: int, band: BoilerEfficiencyBand, expected: tuple[float, float]
|
||||
) -> None:
|
||||
assert band_seasonal_efficiency_pct(base_code, band) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("band", [BoilerEfficiencyBand.A, BoilerEfficiencyBand.B])
|
||||
@pytest.mark.parametrize("base_code", [102, 104, 127, 130])
|
||||
def test_a_and_b_bands_are_pending_elmhurst_validation(
|
||||
base_code: int, band: BoilerEfficiencyBand
|
||||
) -> None:
|
||||
# A/B exceed Table 4b's 84% ceiling — they are judgement values that MUST be
|
||||
# pinned against an accredited Elmhurst build before they are enabled
|
||||
# (ADR-0068 gated pre-req). Until then: no slot, so an A/B boiler keeps its
|
||||
# condensing code default (no invented numbers ship).
|
||||
assert band_seasonal_efficiency_pct(base_code, band) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"base_code",
|
||||
[
|
||||
151, # Solid fuel boiler — Table 4a 75%, intrinsic (SEDBUK doesn't rate it)
|
||||
191, # Electric boiler — Table 4a 100%, intrinsic
|
||||
192, # Electric CPSU — intrinsic electric
|
||||
120, # Gas CPSU — non-condensing, not SEDBUK-banded
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("band", list(BoilerEfficiencyBand))
|
||||
def test_non_banded_boilers_never_take_a_slot(
|
||||
base_code: int, band: BoilerEfficiencyBand
|
||||
) -> None:
|
||||
assert band_seasonal_efficiency_pct(base_code, band) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("archetype", "band", "expected"),
|
||||
[
|
||||
("Gas boiler, regular", BoilerEfficiencyBand.D, (80.0, 70.0)),
|
||||
("Gas boiler, combi", BoilerEfficiencyBand.G, (66.0, 57.0)),
|
||||
("Oil boiler, regular", BoilerEfficiencyBand.E, (71.0, 59.0)),
|
||||
("Oil boiler, combi", BoilerEfficiencyBand.D, (77.0, 68.0)),
|
||||
],
|
||||
)
|
||||
def test_overlay_sets_the_band_efficiency_slot_on_gas_and_oil_boilers(
|
||||
archetype: str, band: BoilerEfficiencyBand, expected: tuple[float, float]
|
||||
) -> None:
|
||||
simulation = main_heating_overlay_for(archetype, 0, band)
|
||||
|
||||
assert simulation is not None
|
||||
assert simulation.heating is not None
|
||||
# The base code is unchanged (it still drives combi/regular HW behaviour);
|
||||
# only the efficiency slot is set from the band.
|
||||
assert simulation.heating.seasonal_efficiency_override_pct == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("archetype", "band"),
|
||||
[
|
||||
# No band → no slot (today's behaviour: keep the condensing code default).
|
||||
("Gas boiler, combi", None),
|
||||
# A/B pending Elmhurst → no slot yet.
|
||||
("Gas boiler, combi", BoilerEfficiencyBand.A),
|
||||
# C on gas regular equals the code default — still set, but a no-op value.
|
||||
# Non-banded boilers ignore the band letter entirely.
|
||||
("Electric boiler", BoilerEfficiencyBand.D),
|
||||
("Solid fuel boiler", BoilerEfficiencyBand.G),
|
||||
("Gas CPSU", BoilerEfficiencyBand.D),
|
||||
],
|
||||
)
|
||||
def test_overlay_sets_no_slot_when_band_absent_or_not_applicable(
|
||||
archetype: str, band: Optional[BoilerEfficiencyBand]
|
||||
) -> None:
|
||||
simulation = main_heating_overlay_for(archetype, 0, band)
|
||||
|
||||
assert simulation is not None
|
||||
assert simulation.heating is not None
|
||||
assert simulation.heating.seasonal_efficiency_override_pct is None
|
||||
|
||||
|
||||
def test_overlay_defaults_to_no_band_when_not_supplied() -> None:
|
||||
# Back-compat: the band arg is optional; existing callers pass none.
|
||||
simulation = main_heating_overlay_for("Gas boiler, combi", 0)
|
||||
|
||||
assert simulation is not None
|
||||
assert simulation.heating is not None
|
||||
assert simulation.heating.seasonal_efficiency_override_pct is None
|
||||
Loading…
Add table
Reference in a new issue