diff --git a/tests/domain/sap10_calculator/worksheet/test_rating.py b/tests/domain/sap10_calculator/worksheet/test_rating.py index 8eccda886..3867abe9f 100644 --- a/tests/domain/sap10_calculator/worksheet/test_rating.py +++ b/tests/domain/sap10_calculator/worksheet/test_rating.py @@ -109,6 +109,29 @@ def test_sap_rating_integer_rounds_to_nearest_and_clamps_to_minimum_one() -> Non assert catastrophic == 1 +def test_sap_rating_integer_rounds_a_half_point_up_not_to_even() -> None: + # Arrange — §13 "rounded to the nearest integer" is half-UP under SAP, the + # convention the mapper already follows (`_round_half_up_2dp`). Python's + # built-in `round` is half-to-EVEN, so it drops an exact x.5 to x whenever x + # is even. That bites hardest at the band floors, where one point is a whole + # band: a continuous 68.5 must publish as SAP 69 (band C), not 68 (band D). + # The linear branch (9) inverts exactly, so these ECFs land on a true .5: + # ECF = (100 − 68.5) / 13.95 → SAP 68.5 (band C floor) + # ECF = (100 − 54.5) / 13.95 → SAP 54.5 (band D floor) + ecf_at_band_c_floor = (100.0 - 68.5) / 13.95 + ecf_at_band_d_floor = (100.0 - 54.5) / 13.95 + assert sap_rating(ecf=ecf_at_band_c_floor) == 68.5 + assert sap_rating(ecf=ecf_at_band_d_floor) == 54.5 + + # Act + at_band_c_floor = sap_rating_integer(ecf=ecf_at_band_c_floor) + at_band_d_floor = sap_rating_integer(ecf=ecf_at_band_d_floor) + + # Assert — the half point rounds up into the band above. + assert at_band_c_floor == 69 + assert at_band_d_floor == 55 + + def test_environmental_impact_rating_linear_branch_below_threshold() -> None: # Arrange — Equations (10)/(12): CF = CO2/(TFA+45); when CF < 28.3, # EI = 100 − 1.34 × CF. For a 100 m² home emitting 1500 kg CO2/yr: