|
| 1 | +"""Pins the pipeline's hand-duplicated regex/table copies to their |
| 2 | +nameparser.config.regexes source of truth. |
| 3 | +
|
| 4 | +The 2.0 layering rule forbids nameparser._pipeline/_render importing |
| 5 | +nameparser.config directly, so several patterns and tables are copied |
| 6 | +by hand into the modules that need them, each with a "keep in sync by |
| 7 | +hand" comment. Nothing previously enforced that promise: if |
| 8 | +config/regexes.py changed, the copies would silently diverge with no |
| 9 | +CI signal. Tests may legally import both sides (test_layering.py's own |
| 10 | +convention), so this module is where the promise gets checked. |
| 11 | +""" |
| 12 | +from nameparser.config import regexes as _config |
| 13 | +from nameparser._pipeline import _assign, _post_rules, _tokenize, _vocab |
| 14 | +from nameparser import _render |
| 15 | + |
| 16 | + |
| 17 | +def test_emoji_ranges_match_config() -> None: |
| 18 | + assert _tokenize._EMOJI_RANGES == _config._EMOJI_RANGES |
| 19 | + |
| 20 | + |
| 21 | +def test_bidi_pattern_matches_config() -> None: |
| 22 | + assert _tokenize._BIDI.pattern == _config.re_bidi.pattern |
| 23 | + assert _tokenize._BIDI.flags == _config.re_bidi.flags |
| 24 | + |
| 25 | + |
| 26 | +def test_period_not_at_end_matches_config() -> None: |
| 27 | + source = _config.REGEXES["period_not_at_end"] |
| 28 | + assert _vocab._PERIOD_NOT_AT_END.pattern == source.pattern |
| 29 | + assert _vocab._PERIOD_NOT_AT_END.flags == source.flags |
| 30 | + |
| 31 | + |
| 32 | +def test_period_abbreviation_matches_config() -> None: |
| 33 | + source = _config.REGEXES["period_abbreviation"] |
| 34 | + assert _assign._PERIOD_ABBREV.pattern == source.pattern |
| 35 | + assert _assign._PERIOD_ABBREV.flags == source.flags |
| 36 | + |
| 37 | + |
| 38 | +def test_roman_numeral_matches_config() -> None: |
| 39 | + source = _config.REGEXES["roman_numeral"] |
| 40 | + assert _assign._ROMAN.pattern == source.pattern |
| 41 | + assert _assign._ROMAN.flags == source.flags |
| 42 | + |
| 43 | + |
| 44 | +def test_patronymic_patterns_match_config() -> None: |
| 45 | + pairs = ( |
| 46 | + (_post_rules._EAST_SLAVIC, "east_slavic_patronymic"), |
| 47 | + (_post_rules._EAST_SLAVIC_CYR, "east_slavic_patronymic_cyrillic"), |
| 48 | + (_post_rules._TURKIC, "turkic_patronymic_marker"), |
| 49 | + (_post_rules._TURKIC_CYR, "turkic_patronymic_marker_cyrillic"), |
| 50 | + ) |
| 51 | + for copy, key in pairs: |
| 52 | + source = _config.REGEXES[key] |
| 53 | + assert copy.pattern == source.pattern, key |
| 54 | + assert copy.flags == source.flags, key |
| 55 | + |
| 56 | + |
| 57 | +def test_initial_copies_agree_with_each_other_and_config() -> None: |
| 58 | + # _vocab._INITIAL and _render._INITIAL are both v1's "initial" |
| 59 | + # pattern minus its trailing "?" (documented at _render.py's |
| 60 | + # _INITIAL definition: the two call sites always fullmatch a |
| 61 | + # non-empty token, so the empty-string alternative is dropped on |
| 62 | + # purpose). Assert both the internal-copy agreement and the exact, |
| 63 | + # documented relationship to the config source, so a future edit to |
| 64 | + # either side that breaks the relationship fails loudly here |
| 65 | + # instead of silently drifting. |
| 66 | + assert _vocab._INITIAL.pattern == _render._INITIAL.pattern |
| 67 | + source = _config.REGEXES["initial"] |
| 68 | + # config's pattern is the pipeline copy with an extra "?" spliced in |
| 69 | + # just before the trailing "$", making the whole group optional. |
| 70 | + trimmed = _vocab._INITIAL.pattern |
| 71 | + reconstructed = trimmed[:-1] + "?" + trimmed[-1:] |
| 72 | + assert source.pattern == reconstructed |
| 73 | + assert source.flags == _vocab._INITIAL.flags |
0 commit comments