"""Search tests.""" from coastwise.data import UNKNOWN_CARD, get_rule_card from coastwise.search import alias_resolution_rate, search_source_candidates, search_species from coastwise.source_cache import DEFAULT_SEED_CACHE_DIR, load_seed_cache def test_search_returns_supported_aliases_and_groups(): mussel = search_species("mussel")[0] assert mussel.rule_card_key == "mussels" assert mussel.reason in {"exact", "alias"} crab = search_species("Dungeness crabs")[0] assert crab.rule_card_key == "dungeness_crab" flatfish = search_species("sanddab")[0] assert flatfish.rule_card_key == "flatfish" def test_search_returns_stricter_exception_cards_before_group_cards(): yelloweye = search_species("yelloweye rockfish")[0] assert yelloweye.rule_card_key == "yelloweye_rockfish" abalone = search_species("red abalone")[0] assert abalone.rule_card_key == "red_abalone" assert get_rule_card(yelloweye.rule_card_key).default_status.value == "do_not_harvest" def test_search_unknown_or_empty_uses_safe_fallback_path(): assert search_species("") == [] assert search_species("mystery tidepool creature") == [] assert UNKNOWN_CARD.default_status.value == "observe_only" def test_source_backed_alias_fixture_resolves_at_least_95_percent(): cache = load_seed_cache(DEFAULT_SEED_CACHE_DIR) aliases = { "lingcod": "lingcod", "ling cod": "lingcod", "dungeness crab": "dungeness_crab", "dungeness crabs": "dungeness_crab", "crab": "dungeness_crab", "mussels": "mussels", "mussel": "mussels", "shellfish": "shellfish", } rate = alias_resolution_rate(aliases, cache) assert rate >= 0.95 assert search_source_candidates("mystery tidepool creature", cache) == [] def test_source_backed_search_handles_public_typos_and_aliases(): cache = load_seed_cache(DEFAULT_SEED_CACHE_DIR) expected = { "dugenese crab": "dungeness_crab", "dungenese crab": "dungeness_crab", "dugeness crabs": "dungeness_crab", "cabezon": "cabezon", "cabezone": "cabezon", "cabazon": "cabezon", "shell fish": "shellfish", "rock crab": "rock_crab", } for query, key in expected.items(): matches = search_source_candidates(query, cache) assert matches, query assert matches[0].rule_card_key == key def test_source_backed_typos_are_fallback_not_primary_interpretation_contract(): cache = load_seed_cache(DEFAULT_SEED_CACHE_DIR) matches = search_source_candidates("dugenese crab", cache) assert matches assert matches[0].rule_card_key == "dungeness_crab" assert matches[0].reason == "source_alias"