← 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())