"""Tests for the PCDB Table 172 (postcode weather) lookup module. The lookup parses pcdb10.dat at first use and caches it as a `{(area, district): PostcodeClimate}` dict. Callers invoke `postcode_climate(postcode_str)` to obtain the per-district monthly weather (temp, wind, solar) used by the demand-side cascade for EPC emissions / primary energy. Reference: BRE PCDB pcdb10.dat Table 172 (Postcodes). """ from __future__ import annotations from domain.sap10_calculator.tables.pcdb.postcode_weather import ( PostcodeClimate, postcode_climate, ) def test_postcode_climate_returns_bd3_record() -> None: """Bradford district 3 (BD3) is the postcode for Elmhurst fixture 000474. Verified against U985 Block 2 wind speed (5.2, 5.2, 5.0, ..., 4.9) which is the EPC demand-cascade climate.""" # Arrange # Act climate = postcode_climate("bd3 8aq") # Assert assert climate is not None assert climate.area == "BD" assert climate.district == 3 assert climate.region == 11 # East Pennines # Block 2 of U985-0001-000474.txt: Wind speed # 5.2 5.2 5.0 4.4 4.3 3.9 4.0 3.8 4.1 4.4 4.6 4.9 (22) assert climate.monthly_wind_speed_m_per_s == ( 5.2, 5.2, 5.0, 4.4, 4.3, 3.9, 4.0, 3.8, 4.1, 4.4, 4.6, 4.9, ) def test_postcode_climate_parses_mixed_case() -> None: """Postcode is normalised to upper-case so "bd3 8aq" and "BD3 8AQ" hit the same record.""" # Arrange lower = "bd4 7jr" upper = "BD4 7JR" # Act a = postcode_climate(lower) b = postcode_climate(upper) # Assert assert a is not None assert b is not None assert a == b def test_postcode_climate_handles_two_digit_district() -> None: """Two-digit district numbers ("BD19") parse correctly — the digit consumption walks past the alpha prefix and grabs all digits.""" # Arrange # Act climate = postcode_climate("bd19 3tf") # Assert assert climate is not None assert climate.area == "BD" assert climate.district == 19 def test_postcode_climate_returns_none_for_unknown_postcode() -> None: """Postcodes with no Table 172 entry (e.g. synthetic test data) yield None so callers can fall back to UK-average climate.""" # Arrange # Act result = postcode_climate("ZZ99 9ZZ") # Assert assert result is None def test_postcode_climate_returns_none_for_malformed() -> None: """Empty or letter-only postcodes return None rather than raising.""" # Arrange # Act # Assert assert postcode_climate("") is None assert postcode_climate(None) is None assert postcode_climate("XYZ") is None