← back to Unclaimed Property Platform
tests/test_cycle7_recall.py
70 lines
"""Cycle 6 test — apostrophe/hyphen search RECALL fix.
Run: python -m tests.test_cycle7_recall
Before: normalize_text collapsed "O'Neil" -> "O NEIL", so masked_search("Oneil") missed it.
After: a fully-collapsed alphanumeric key on both sides matches regardless of internal
apostrophes/hyphens/spaces. Matching (phonetic) was always fine; this restores SEARCH recall.
"""
from __future__ import annotations
import sys
import tempfile
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from services.common.normalize import normalize_search
from services.common.sqlite_repo import FileObjectStore, SqliteRepository
from services.ingestion.ingest import FeedDefinition, ingest_authorized_feed
SAMPLE = Path(__file__).resolve().parents[1] / "data" / "sample" / "sample_state_feed.csv"
def ok(msg: str) -> None:
print(f" ✓ {msg}")
def main() -> int:
tmp = Path(tempfile.mkdtemp(prefix="upp-cycle7-"))
store = FileObjectStore(tmp / "obj")
(tmp / "obj").mkdir(parents=True, exist_ok=True)
store.write_bytes("incoming/s.csv", SAMPLE.read_bytes())
repo = SqliteRepository(str(tmp / "p.db"))
ingest_authorized_feed(FeedDefinition("SAMPLE", "incoming/s.csv"), store, repo)
print("0) normalize_search collapses punctuation + spaces")
assert normalize_search("Catherine O'Neil") == "CATHERINEONEIL", normalize_search("Catherine O'Neil")
assert normalize_search("Smith-Jones") == "SMITHJONES"
ok("O'Neil -> CATHERINEONEIL, Smith-Jones -> SMITHJONES")
print("1) 'Oneil' now finds \"O'Neil\" (the recall fix)")
hits = repo.masked_search("Oneil")
assert hits, "expected 'Oneil' to match \"O'Neil\" after the fix"
assert all("owner_name_raw" not in h for h in hits)
ok(f"'Oneil' -> {len(hits)} hit(s), e.g. {hits[0]['owner_name_masked']}")
print("2) space/punct-free query still matches")
assert repo.masked_search("catherineoneil"), "collapsed query should match"
ok("'catherineoneil' matches")
print("3) ordinary token still works")
assert repo.masked_search("Testcase"), "expected Maria Testcase"
ok("'Testcase' matches")
print("4) empty/punctuation still rejected (m2 preserved)")
for bad in ("", " ", "'-.'"):
try:
repo.masked_search(bad)
raise AssertionError(f"{bad!r} should raise")
except ValueError:
pass
ok("empty/punctuation-only queries rejected")
print("\nALL CYCLE-6 RECALL ASSERTIONS PASSED ✅")
return 0
if __name__ == "__main__":
raise SystemExit(main())