84 lines
3.0 KiB
Python
84 lines
3.0 KiB
Python
|
|
from app.discovery.enums import MatchStatus
|
||
|
|
from app.discovery.identity import IdentitySignals, decide_identity, spec_fingerprint
|
||
|
|
|
||
|
|
|
||
|
|
def _sig(**overrides) -> IdentitySignals:
|
||
|
|
base = IdentitySignals(
|
||
|
|
source_external_id="gh-1",
|
||
|
|
gtin_ean="4000000000001",
|
||
|
|
manufacturer_sku="EM13-32",
|
||
|
|
source_url="https://geizhals.de/a.html",
|
||
|
|
title="Example Mobile 13",
|
||
|
|
manufacturer="Example",
|
||
|
|
model="Mobile 13",
|
||
|
|
fingerprint=spec_fingerprint({"manufacturer": "Example", "model": "Mobile 13", "ram": 32}),
|
||
|
|
)
|
||
|
|
return IdentitySignals(**{**base.__dict__, **overrides})
|
||
|
|
|
||
|
|
|
||
|
|
def test_sku_and_ean_and_url_match():
|
||
|
|
known = [("a", _sig())]
|
||
|
|
assert decide_identity(_sig(), known).reason == "source_external_id"
|
||
|
|
assert decide_identity(_sig(source_external_id="other"), known).reason == "gtin_ean"
|
||
|
|
assert decide_identity(_sig(source_external_id="other", gtin_ean="x"), known).reason == "manufacturer_sku"
|
||
|
|
assert decide_identity(
|
||
|
|
_sig(source_external_id="other", gtin_ean="x", manufacturer_sku="y"),
|
||
|
|
known,
|
||
|
|
).reason == "source_url"
|
||
|
|
|
||
|
|
|
||
|
|
def test_title_plus_fingerprint_matches_stable_specs():
|
||
|
|
known = [("a", _sig(source_external_id=None, gtin_ean=None, manufacturer_sku=None, source_url=None))]
|
||
|
|
incoming = _sig(
|
||
|
|
source_external_id=None,
|
||
|
|
gtin_ean=None,
|
||
|
|
manufacturer_sku=None,
|
||
|
|
source_url=None,
|
||
|
|
title="Example Mobile 13",
|
||
|
|
)
|
||
|
|
decision = decide_identity(incoming, known)
|
||
|
|
assert decision.match_status == MatchStatus.MATCHED
|
||
|
|
assert decision.reason == "title+fingerprint"
|
||
|
|
|
||
|
|
|
||
|
|
def test_title_only_is_uncertain_and_never_merges():
|
||
|
|
known = [("a", _sig(source_external_id=None, gtin_ean=None, manufacturer_sku=None, source_url=None))]
|
||
|
|
incoming = _sig(
|
||
|
|
source_external_id=None,
|
||
|
|
gtin_ean=None,
|
||
|
|
manufacturer_sku=None,
|
||
|
|
source_url=None,
|
||
|
|
fingerprint="different",
|
||
|
|
manufacturer="Other",
|
||
|
|
model="Other",
|
||
|
|
)
|
||
|
|
decision = decide_identity(incoming, known)
|
||
|
|
assert decision.match_status == MatchStatus.MATCH_UNCERTAIN
|
||
|
|
assert decision.existing_id is None
|
||
|
|
assert decision.reason == "title only"
|
||
|
|
|
||
|
|
|
||
|
|
def test_fingerprint_uses_observed_keys_only():
|
||
|
|
left = spec_fingerprint({"capacity_l": 2, "color": "black"})
|
||
|
|
right = spec_fingerprint({"capacity_l": 5, "color": "black"})
|
||
|
|
assert left != right
|
||
|
|
assert "capacity_l=2" in left
|
||
|
|
assert "ram_gb" not in left
|
||
|
|
assert spec_fingerprint({"title": "ignored", "html": "<b>", "noise": 1}) == "noise=1"
|
||
|
|
|
||
|
|
|
||
|
|
def test_similar_names_do_not_merge():
|
||
|
|
known = [("a", _sig(source_external_id=None, gtin_ean=None, manufacturer_sku=None, source_url=None))]
|
||
|
|
incoming = _sig(
|
||
|
|
source_external_id=None,
|
||
|
|
gtin_ean=None,
|
||
|
|
manufacturer_sku=None,
|
||
|
|
source_url=None,
|
||
|
|
title="Example Mobile 14",
|
||
|
|
fingerprint="other",
|
||
|
|
manufacturer="Example",
|
||
|
|
model="Mobile 14",
|
||
|
|
)
|
||
|
|
decision = decide_identity(incoming, known)
|
||
|
|
assert decision.match_status == MatchStatus.NEW_REFERENCE
|