|
| 1 | +"""Tests for compose_mappings: strategy chaining and priority ordering. |
| 2 | +
|
| 3 | +These tests focus on compose_mappings behavior in isolation and in |
| 4 | +combination. Interaction with individual strategies (regex, manual, |
| 5 | +embedding, LLM) is covered in the dedicated per-strategy test files. |
| 6 | +""" |
| 7 | +from __future__ import annotations |
| 8 | + |
| 9 | +from pm_rag.mapping import compose_mappings, manual_mapping, regex_mapping |
| 10 | + |
| 11 | + |
| 12 | +def test_zero_strategies_returns_empty_for_all_events() -> None: |
| 13 | + composed = compose_mappings() |
| 14 | + m = composed(["ev"], ["a", "b"]) |
| 15 | + assert m == {"ev": []} |
| 16 | + |
| 17 | + |
| 18 | +def test_single_strategy_matches_direct_call() -> None: |
| 19 | + symbols = ["foo_handler", "bar_handler"] |
| 20 | + composed = compose_mappings(regex_mapping) |
| 21 | + direct = regex_mapping(["foo", "bar"], symbols) |
| 22 | + result = composed(["foo", "bar"], symbols) |
| 23 | + assert result == direct |
| 24 | + |
| 25 | + |
| 26 | +def test_all_strategies_miss_returns_empty_list_per_event() -> None: |
| 27 | + composed = compose_mappings(regex_mapping) |
| 28 | + m = composed(["totally_unknown"], ["a", "b"]) |
| 29 | + assert m == {"totally_unknown": []} |
| 30 | + |
| 31 | + |
| 32 | +def test_second_fills_gap_third_result_not_used() -> None: |
| 33 | + symbols = ["a_handler", "b_handler", "c_handler"] |
| 34 | + manual1 = manual_mapping({"ev": ["b_handler"]}) |
| 35 | + manual2 = manual_mapping({"ev": ["c_handler"]}) |
| 36 | + composed = compose_mappings(regex_mapping, manual1, manual2) |
| 37 | + m = composed(["ev"], symbols) |
| 38 | + assert m["ev"] == [1] |
| 39 | + |
| 40 | + |
| 41 | +def test_different_events_resolved_by_different_strategies() -> None: |
| 42 | + symbols = ["pay_handler", "legacy.old"] |
| 43 | + overrides = {"obscure": ["legacy.old"]} |
| 44 | + composed = compose_mappings(regex_mapping, manual_mapping(overrides)) |
| 45 | + m = composed(["pay", "obscure", "no_match"], symbols) |
| 46 | + assert m["pay"] == [0] |
| 47 | + assert m["obscure"] == [1] |
| 48 | + assert m["no_match"] == [] |
| 49 | + |
| 50 | + |
| 51 | +def test_duplicate_events_collapsed_in_result() -> None: |
| 52 | + composed = compose_mappings(regex_mapping) |
| 53 | + m = composed(["x", "x", "x"], ["x_handler"]) |
| 54 | + assert list(m.keys()) == ["x"] |
| 55 | + assert m["x"] == [0] |
| 56 | + |
| 57 | + |
| 58 | +def test_empty_events_returns_empty_dict() -> None: |
| 59 | + composed = compose_mappings(regex_mapping) |
| 60 | + assert composed([], ["a", "b"]) == {} |
| 61 | + |
| 62 | + |
| 63 | +def test_empty_symbols_all_strategies_miss() -> None: |
| 64 | + composed = compose_mappings(regex_mapping) |
| 65 | + m = composed(["ev"], []) |
| 66 | + assert m == {"ev": []} |
| 67 | + |
| 68 | + |
| 69 | +def test_event_order_preserved_in_result_keys() -> None: |
| 70 | + symbols = ["c_fn", "a_fn", "b_fn"] |
| 71 | + overrides = {"alpha": ["a_fn"], "beta": ["b_fn"], "gamma": ["c_fn"]} |
| 72 | + composed = compose_mappings(manual_mapping(overrides)) |
| 73 | + events = ["gamma", "alpha", "beta"] |
| 74 | + m = composed(events, symbols) |
| 75 | + assert list(m.keys()) == events |
| 76 | + assert m["gamma"] == [0] |
| 77 | + assert m["alpha"] == [1] |
| 78 | + assert m["beta"] == [2] |
0 commit comments