]> git.openstreetmap.org Git - nominatim.git/blob - test/python/test_tools_postcodes.py
d5c8ff747fdb9aa6afbc151cd92fe63a62892976
[nominatim.git] / test / python / test_tools_postcodes.py
1 """
2 Tests for functions to maintain the artificial postcode table.
3 """
4 import subprocess
5
6 import pytest
7
8 from nominatim.tools import postcodes
9 import dummy_tokenizer
10
11 class MockPostcodeTable:
12     """ A location_postcode table for testing.
13     """
14     def __init__(self, conn):
15         self.conn = conn
16         with conn.cursor() as cur:
17             cur.execute("""CREATE TABLE location_postcode (
18                                place_id BIGINT,
19                                parent_place_id BIGINT,
20                                rank_search SMALLINT,
21                                rank_address SMALLINT,
22                                indexed_status SMALLINT,
23                                indexed_date TIMESTAMP,
24                                country_code varchar(2),
25                                postcode TEXT,
26                                geometry GEOMETRY(Geometry, 4326))""")
27             cur.execute("""CREATE OR REPLACE FUNCTION token_normalized_postcode(postcode TEXT)
28                            RETURNS TEXT AS $$ BEGIN RETURN postcode; END; $$ LANGUAGE plpgsql;
29
30                            CREATE OR REPLACE FUNCTION get_country_code(place geometry)
31                            RETURNS TEXT AS $$ BEGIN 
32                            RETURN (SELECT country_code FROM placex WHERE geometry = place LIMIT 1);
33                            END; $$ LANGUAGE plpgsql;
34                         """)
35         conn.commit()
36
37     def add(self, country, postcode, x, y):
38         with self.conn.cursor() as cur:
39             cur.execute("""INSERT INTO location_postcode (place_id, indexed_status,
40                                                           country_code, postcode,
41                                                           geometry)
42                            VALUES (nextval('seq_place'), 1, %s, %s,
43                                    'SRID=4326;POINT(%s %s)')""",
44                         (country, postcode, x, y))
45         self.conn.commit()
46
47
48     @property
49     def row_set(self):
50         with self.conn.cursor() as cur:
51             cur.execute("""SELECT country_code, postcode,
52                                   ST_X(geometry), ST_Y(geometry)
53                            FROM location_postcode""")
54             return set((tuple(row) for row in cur))
55
56
57 @pytest.fixture
58 def tokenizer():
59     return dummy_tokenizer.DummyTokenizer(None, None)
60
61 @pytest.fixture
62 def postcode_table(temp_db_conn, placex_table, word_table):
63     return MockPostcodeTable(temp_db_conn)
64
65
66 def test_postcodes_empty(dsn, postcode_table, place_table,
67                          tmp_path, tokenizer):
68     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
69
70     assert not postcode_table.row_set
71
72
73 def test_postcodes_add_new(dsn, postcode_table, placex_table, place_row,
74                            tmp_path, tokenizer):
75     placex_table.add(country='xx', geom='POINT(10 12)')
76     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='9486'))
77     postcode_table.add('yy', '9486', 99, 34)
78
79     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
80
81     assert postcode_table.row_set == {('xx', '9486', 10, 12), }
82
83
84 def test_postcodes_replace_coordinates(dsn, placex_table, postcode_table,
85                                        place_row, tmp_path, tokenizer):
86     placex_table.add(country='xx', geom='POINT(10 12)')
87     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='AB 4511'))
88     postcode_table.add('xx', 'AB 4511', 99, 34)
89
90     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
91
92     assert postcode_table.row_set == {('xx', 'AB 4511', 10, 12)}
93
94
95 def test_postcodes_replace_coordinates_close(dsn, placex_table, postcode_table,
96                                              place_row, tmp_path, tokenizer):
97     placex_table.add(country='xx', geom='POINT(10 12)')
98     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='AB 4511'))
99     postcode_table.add('xx', 'AB 4511', 10, 11.99999)
100
101     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
102
103     assert postcode_table.row_set == {('xx', 'AB 4511', 10, 11.99999)}
104
105
106 def test_postcodes_remove(dsn, placex_table, postcode_table, 
107                           place_row, tmp_path, tokenizer):
108     placex_table.add(country='xx', geom='POINT(10 12)')
109     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='AB 4511'))
110     postcode_table.add('xx', 'badname', 10, 12)
111
112     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
113
114     assert postcode_table.row_set == {('xx', 'AB 4511', 10, 12)}
115
116
117 def test_postcodes_ignore_empty_country(dsn, placex_table, postcode_table, 
118                                         place_row, tmp_path, tokenizer):
119     placex_table.add(country=None, geom='POINT(10 12)')
120     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='AB 4511'))
121     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
122
123     assert not postcode_table.row_set
124
125
126 def test_postcodes_remove_all(dsn, postcode_table, place_table,
127                               tmp_path, tokenizer):
128     postcode_table.add('ch', '5613', 10, 12)
129     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
130
131     assert not postcode_table.row_set
132
133
134 def test_postcodes_multi_country(dsn, placex_table, postcode_table, 
135                                  place_row, tmp_path, tokenizer):
136     placex_table.add(country='de', geom='POINT(10 12)')
137     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='54451'))
138
139     placex_table.add(country='cc', geom='POINT(100 56)')
140     place_row(geom='SRID=4326;POINT(100 56)', address=dict(postcode='DD23 T'))
141
142     placex_table.add(country='de', geom='POINT(10.3 11.0)')
143     place_row(geom='SRID=4326;POINT(10.3 11.0)', address=dict(postcode='54452'))
144
145     placex_table.add(country='cc', geom='POINT(10.3 10.0)')
146     place_row(geom='SRID=4326;POINT(10.3 10.0)', address=dict(postcode='54452'))
147
148     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
149
150     assert postcode_table.row_set == {('de', '54451', 10, 12),
151                                       ('de', '54452', 10.3, 11.0),
152                                       ('cc', '54452', 10.3, 10.0),
153                                       ('cc', 'DD23 T', 100, 56)}
154
155
156 @pytest.mark.parametrize("gzipped", [True, False])
157 def test_postcodes_extern(dsn, placex_table, postcode_table, tmp_path,
158                           place_row, tokenizer, gzipped):
159     placex_table.add(country='xx', geom='POINT(10 12)')
160     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='AB 4511'))
161
162     extfile = tmp_path / 'xx_postcodes.csv'
163     extfile.write_text("postcode,lat,lon\nAB 4511,-4,-1\nCD 4511,-5, -10")
164
165     if gzipped:
166         subprocess.run(['gzip', str(extfile)])
167         assert not extfile.is_file()
168
169     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
170
171     assert postcode_table.row_set == {('xx', 'AB 4511', 10, 12),
172                                       ('xx', 'CD 4511', -10, -5)}
173
174
175 def test_postcodes_extern_bad_column(dsn, placex_table, postcode_table,
176                                      place_row, tmp_path, tokenizer):
177     placex_table.add(country='xx', geom='POINT(10 12)')
178     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='AB 4511'))
179
180     extfile = tmp_path / 'xx_postcodes.csv'
181     extfile.write_text("postode,lat,lon\nAB 4511,-4,-1\nCD 4511,-5, -10")
182
183     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
184
185     assert postcode_table.row_set == {('xx', 'AB 4511', 10, 12)}
186
187
188 def test_postcodes_extern_bad_number(dsn, placex_table, postcode_table,
189                                      place_row, tmp_path, tokenizer):
190     placex_table.add(country='xx', geom='POINT(10 12)')
191     place_row(geom='SRID=4326;POINT(10 12)', address=dict(postcode='AB 4511'))
192
193     extfile = tmp_path / 'xx_postcodes.csv'
194     extfile.write_text("postcode,lat,lon\nXX 4511,-4,NaN\nCD 4511,-5, -10\n34,200,0")
195
196     postcodes.update_postcodes(dsn, tmp_path, tokenizer)
197
198     assert postcode_table.row_set == {('xx', 'AB 4511', 10, 12),
199                                       ('xx', 'CD 4511', -10, -5)}
200
201 def test_can_compute(dsn, temp_db_cursor):
202     assert not postcodes.can_compute(dsn)
203     temp_db_cursor.execute('CREATE TABLE place()')
204     assert postcodes.can_compute(dsn)