]> git.openstreetmap.org Git - nominatim.git/blob - test/python/test_tokenizer_icu_rule_loader.py
use yaml tag syntax to mark include files
[nominatim.git] / test / python / test_tokenizer_icu_rule_loader.py
1 """
2 Tests for converting a config file to ICU rules.
3 """
4 import pytest
5 from textwrap import dedent
6
7 from nominatim.tokenizer.icu_rule_loader import ICURuleLoader
8 from nominatim.errors import UsageError
9
10 from icu import Transliterator
11
12 @pytest.fixture
13 def cfgfile(tmp_path, suffix='.yaml'):
14     def _create_config(suffixes, abbr):
15         content = dedent("""\
16         normalization:
17             - ":: NFD ()"
18             - "[[:Nonspacing Mark:] [:Cf:]] >"
19             - ":: lower ()"
20             - "[[:Punctuation:][:Space:]]+ > ' '"
21             - ":: NFC ()"
22         transliteration:
23             - "::  Latin ()"
24             - "[[:Punctuation:][:Space:]]+ > ' '"
25         """)
26         content += "compound_suffixes:\n"
27         content += '\n'.join(("    - " + s for s in suffixes)) + '\n'
28         content += "abbreviations:\n"
29         content += '\n'.join(("    - " + s for s in abbr)) + '\n'
30         fpath = tmp_path / ('test_config' + suffix)
31         fpath.write_text(dedent(content))
32         return fpath
33
34     return _create_config
35
36
37 def test_empty_rule_file(tmp_path):
38     fpath = tmp_path / ('test_config.yaml')
39     fpath.write_text(dedent("""\
40         normalization:
41         transliteration:
42         compound_suffixes:
43         abbreviations:
44         """))
45
46     rules = ICURuleLoader(fpath)
47     assert rules.get_search_rules() == ''
48     assert rules.get_normalization_rules() == ''
49     assert rules.get_transliteration_rules() == ''
50     assert rules.get_replacement_pairs() == []
51
52 CONFIG_SECTIONS = ('normalization', 'transliteration',
53                    'compound_suffixes', 'abbreviations')
54
55 @pytest.mark.parametrize("section", CONFIG_SECTIONS)
56 def test_missing_normalization(tmp_path, section):
57     fpath = tmp_path / ('test_config.yaml')
58     with fpath.open('w') as fd:
59         for name in CONFIG_SECTIONS:
60             if name != section:
61                 fd.write(name + ':\n')
62
63     with pytest.raises(UsageError):
64         ICURuleLoader(fpath)
65
66 @pytest.mark.parametrize("abbr", ["simple",
67                                   "double => arrow => bad",
68                                   "bad = > arrow"])
69 def test_bad_abbreviation_syntax(tmp_path, abbr):
70     fpath = tmp_path / ('test_config.yaml')
71     fpath.write_text(dedent("""\
72         normalization:
73         transliteration:
74         compound_suffixes:
75         abbreviations:
76          - {}
77         """.format(abbr)))
78
79     with pytest.raises(UsageError):
80         rules = ICURuleLoader(fpath)
81
82
83 def test_get_search_rules(cfgfile):
84     fpath = cfgfile(['strasse', 'straße', 'weg'],
85                     ['strasse,straße => str',
86                      'prospekt => pr'])
87
88     loader = ICURuleLoader(fpath)
89
90     rules = loader.get_search_rules()
91     trans = Transliterator.createFromRules("test", rules)
92
93     assert trans.transliterate(" Baum straße ") == " baum straße "
94     assert trans.transliterate(" Baumstraße ") == " baumstraße "
95     assert trans.transliterate(" Baumstrasse ") == " baumstrasse "
96     assert trans.transliterate(" Baumstr ") == " baumstr "
97     assert trans.transliterate(" Baumwegstr ") == " baumwegstr "
98     assert trans.transliterate(" Αθήνα ") == " athēna "
99     assert trans.transliterate(" проспект ") == " prospekt "
100
101
102 def test_get_normalization_rules(cfgfile):
103     fpath = cfgfile(['strasse', 'straße', 'weg'],
104                     ['strasse,straße => str'])
105
106     loader = ICURuleLoader(fpath)
107     rules = loader.get_normalization_rules()
108     trans = Transliterator.createFromRules("test", rules)
109
110     assert trans.transliterate(" проспект-Prospekt ") == " проспект prospekt "
111
112
113 def test_get_transliteration_rules(cfgfile):
114     fpath = cfgfile(['strasse', 'straße', 'weg'],
115                     ['strasse,straße => str'])
116
117     loader = ICURuleLoader(fpath)
118     rules = loader.get_transliteration_rules()
119     trans = Transliterator.createFromRules("test", rules)
120
121     assert trans.transliterate(" проспект-Prospekt ") == " prospekt Prospekt "
122
123
124 def test_transliteration_rules_from_file(tmp_path):
125     cfgpath = tmp_path / ('test_config.yaml')
126     cfgpath.write_text(dedent("""\
127         normalization:
128         transliteration:
129             - "'ax' > 'b'"
130             - !include transliteration.yaml
131         compound_suffixes:
132         abbreviations:
133         """))
134     transpath = tmp_path / ('transliteration.yaml')
135     transpath.write_text('- "x > y"')
136
137     loader = ICURuleLoader(cfgpath)
138     rules = loader.get_transliteration_rules()
139     trans = Transliterator.createFromRules("test", rules)
140
141     assert trans.transliterate(" axxt ") == " byt "
142
143
144 def test_get_replacement_pairs_multi_to(cfgfile):
145     fpath = cfgfile(['Pfad', 'Strasse'],
146                     ['Strasse => str,st'])
147
148     repl = ICURuleLoader(fpath).get_replacement_pairs()
149
150     assert [(a, sorted(b)) for a, b in repl] == \
151              [(' strasse ', [' st ', ' str ', ' strasse ', 'st ', 'str ', 'strasse ']),
152               ('strasse ', [' st ', ' str ', ' strasse ', 'st ', 'str ', 'strasse ']),
153               (' pfad ', [' pfad ', 'pfad ']),
154               ('pfad ', [' pfad ', 'pfad '])]
155
156
157 def test_get_replacement_pairs_multi_from(cfgfile):
158     fpath = cfgfile([], ['saint,Sainte => st'])
159
160     repl = ICURuleLoader(fpath).get_replacement_pairs()
161
162     assert [(a, sorted(b)) for a, b in repl] == \
163              [(' sainte ', [' sainte ', ' st ']),
164               (' saint ', [' saint ', ' st '])]
165
166
167 def test_get_replacement_pairs_cross_abbreviations(cfgfile):
168     fpath = cfgfile([], ['saint,Sainte => st',
169                          'sainte => ste'])
170
171     repl = ICURuleLoader(fpath).get_replacement_pairs()
172
173     assert [(a, sorted(b)) for a, b in repl] == \
174              [(' sainte ', [' sainte ', ' st ', ' ste ']),
175               (' saint ', [' saint ', ' st '])]
176
177
178 @pytest.mark.parametrize("abbr", ["missing to =>",
179                                   "  => missing from",
180                                   "=>"])
181 def test_bad_abbreviation_syntax(tmp_path, abbr):
182     fpath = tmp_path / ('test_config.yaml')
183     fpath.write_text(dedent("""\
184         normalization:
185         transliteration:
186         compound_suffixes:
187         abbreviations:
188          - {}
189         """.format(abbr)))
190
191     repl = ICURuleLoader(fpath).get_replacement_pairs()
192
193     assert repl == []