Model/tests/backend/address2UPRN/test_resolve_group_ambiguity.py
Jun-te Kim 269aade481 test(address2uprn): cover ambiguity withholding + override dedup; add ADR-0057
- unit tests for resolve_group_ambiguity (distinct addresses withheld,
  same-address re-listing kept, order preserved)
- Postgres integration tests for upsert_all's backstop dedup
- ADR-0057 recording the "confirm UPRNs before finalise" decision

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 15:21:04 +00:00

70 lines
2.4 KiB
Python

"""Unit tests for ``resolve_group_ambiguity`` (ADR-0057).
Each address is matched independently, so one UPRN can be the best match for
two *different* addresses (a coarse EPC record absorbing several real
addresses). Withholding that UPRN is a pure function of a postcode group's
``(uprn, normalised_address)`` pairs — no S3, EPC API, or scoring needed — so
it is unit-tested directly here.
"""
from __future__ import annotations
from backend.address2UPRN.scoring import resolve_group_ambiguity
def test_distinct_addresses_sharing_one_uprn_are_withheld() -> None:
# Flat 1 and Flat 2 both matched the same coarse EPC UPRN — distinct
# addresses, so both are withheld rather than silently merged.
result = resolve_group_ambiguity(
[
("100", "flat 1 42 moreton road"),
("100", "flat 2 42 moreton road"),
]
)
assert result == [(None, "ambiguous_duplicate"), (None, "ambiguous_duplicate")]
def test_same_address_listed_twice_keeps_the_uprn() -> None:
# A genuine re-listing of one property (identical normalised address) is a
# real duplicate, not an ambiguous match — the UPRN is kept on both.
result = resolve_group_ambiguity(
[
("100", "42 moreton road"),
("100", "42 moreton road"),
]
)
assert result == [("100", "matched"), ("100", "matched")]
def test_distinct_uprns_are_each_matched() -> None:
result = resolve_group_ambiguity(
[
("100", "42 moreton road"),
("101", "44 moreton road"),
]
)
assert result == [("100", "matched"), ("101", "matched")]
def test_none_uprn_is_unmatched() -> None:
result = resolve_group_ambiguity([(None, "99 nowhere lane")])
assert result == [(None, "unmatched")]
def test_order_is_preserved_across_mixed_group() -> None:
# A withheld pair, an unmatched row, and a clean match — all in one group;
# the output aligns positionally with the input.
result = resolve_group_ambiguity(
[
("100", "flat 1 42 moreton road"), # ambiguous (with row 3)
(None, "no epc candidate"), # unmatched
("100", "flat 2 42 moreton road"), # ambiguous (with row 0)
("200", "sole match road"), # matched
]
)
assert result == [
(None, "ambiguous_duplicate"),
(None, "unmatched"),
(None, "ambiguous_duplicate"),
("200", "matched"),
]