from typing import Optional from scripts.audit.neighbour_divergence import Neighbour, find_divergences def _n( property_id: int, *, effective_sap: Optional[float], postcode: str = "AB1 2CD", property_type: str = "Flat", built_form: str = "Mid-Terrace", floor_area_m2: float = 60.0, ) -> Neighbour: return Neighbour( property_id=property_id, uprn=None, postcode=postcode, property_type=property_type, built_form=built_form, floor_area_m2=floor_area_m2, effective_sap=effective_sap, effective_band=None, ) class TestFindDivergences: def test_flags_the_outlier_neighbour(self) -> None: # Arrange — three identical-cohort flats, one sits a clear band below. cohort = [ _n(1, effective_sap=70.0), _n(2, effective_sap=72.0), _n(3, effective_sap=50.0), # Δ-20 vs median 70 ] # Act result = find_divergences(cohort, min_gap=12.0) # Assert — only the outlier is flagged. assert [d.property_id for d in result] == [3] def test_silent_when_cohort_agrees(self) -> None: # Arrange — neighbours within a few SAP points of each other. cohort = [_n(1, effective_sap=70.0), _n(2, effective_sap=68.0)] # Act result = find_divergences(cohort, min_gap=12.0) # Assert assert result == [] def test_singletons_never_flagged(self) -> None: # Arrange — one flat here, one house there: neither has a peer to diverge from. lonely = [ _n(1, effective_sap=30.0, property_type="Flat"), _n(2, effective_sap=90.0, property_type="House"), ] # Act result = find_divergences(lonely, min_gap=12.0) # Assert assert result == [] def test_different_postcode_is_a_different_cohort(self) -> None: # Arrange — same type/form but different postcodes: not neighbours. split = [ _n(1, effective_sap=40.0, postcode="AB1 2CD"), _n(2, effective_sap=80.0, postcode="ZZ9 9ZZ"), ] # Act result = find_divergences(split, min_gap=12.0) # Assert assert result == []