1 # SPDX-License-Identifier: GPL-3.0-or-later
3 # This file is part of Nominatim. (https://nominatim.org)
5 # Copyright (C) 2023 by the Nominatim developer community.
6 # For a full list of authors see the git log.
8 Tests for reverse API call.
10 These tests make sure that all Python code is correct and executable.
11 Functional tests can be found in the BDD test suite.
17 import nominatim.api as napi
19 def test_reverse_rank_30(apiobj):
20 apiobj.add_placex(place_id=223, class_='place', type='house',
23 geometry='POINT(1.3 0.7)')
25 result = apiobj.api.reverse((1.3, 0.7))
27 assert result is not None
28 assert result.place_id == 223
31 @pytest.mark.parametrize('country', ['de', 'us'])
32 def test_reverse_street(apiobj, country):
33 apiobj.add_placex(place_id=990, class_='highway', type='service',
34 rank_search=27, rank_address=27,
35 name = {'name': 'My Street'},
36 centroid=(10.0, 10.0),
38 geometry='LINESTRING(9.995 10, 10.005 10)')
40 assert apiobj.api.reverse((9.995, 10)).place_id == 990
43 def test_reverse_ignore_unindexed(apiobj):
44 apiobj.add_placex(place_id=223, class_='place', type='house',
48 geometry='POINT(1.3 0.7)')
50 result = apiobj.api.reverse((1.3, 0.7))
55 @pytest.mark.parametrize('y,layer,place_id', [(0.7, napi.DataLayer.ADDRESS, 223),
56 (0.70001, napi.DataLayer.POI, 224),
57 (0.7, napi.DataLayer.ADDRESS | napi.DataLayer.POI, 224),
58 (0.70001, napi.DataLayer.ADDRESS | napi.DataLayer.POI, 223),
59 (0.7, napi.DataLayer.MANMADE, 225),
60 (0.7, napi.DataLayer.RAILWAY, 226),
61 (0.7, napi.DataLayer.NATURAL, 227),
62 (0.70003, napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, 225),
63 (0.70003, napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, 225)])
64 def test_reverse_rank_30_layers(apiobj, y, layer, place_id):
65 apiobj.add_placex(place_id=223, class_='place', type='house',
69 centroid=(1.3, 0.70001))
70 apiobj.add_placex(place_id=224, class_='amenity', type='toilet',
74 apiobj.add_placex(place_id=225, class_='man_made', type='tower',
77 centroid=(1.3, 0.70003))
78 apiobj.add_placex(place_id=226, class_='railway', type='station',
81 centroid=(1.3, 0.70004))
82 apiobj.add_placex(place_id=227, class_='natural', type='cave',
85 centroid=(1.3, 0.70005))
87 assert apiobj.api.reverse((1.3, y), layer=layer).place_id == place_id
90 def test_reverse_poi_layer_with_no_pois(apiobj):
91 apiobj.add_placex(place_id=223, class_='place', type='house',
95 centroid=(1.3, 0.70001))
97 assert apiobj.api.reverse((1.3, 0.70001), max_rank=29,
98 layer=napi.DataLayer.POI) is None
101 def test_reverse_housenumber_on_street(apiobj):
102 apiobj.add_placex(place_id=990, class_='highway', type='service',
103 rank_search=27, rank_address=27,
104 name = {'name': 'My Street'},
105 centroid=(10.0, 10.0),
106 geometry='LINESTRING(9.995 10, 10.005 10)')
107 apiobj.add_placex(place_id=991, class_='place', type='house',
109 rank_search=30, rank_address=30,
111 centroid=(10.0, 10.00001))
113 assert apiobj.api.reverse((10.0, 10.0), max_rank=30).place_id == 991
114 assert apiobj.api.reverse((10.0, 10.0), max_rank=27).place_id == 990
115 assert apiobj.api.reverse((10.0, 10.00001), max_rank=30).place_id == 991
118 def test_reverse_housenumber_interpolation(apiobj):
119 apiobj.add_placex(place_id=990, class_='highway', type='service',
120 rank_search=27, rank_address=27,
121 name = {'name': 'My Street'},
122 centroid=(10.0, 10.0),
123 geometry='LINESTRING(9.995 10, 10.005 10)')
124 apiobj.add_placex(place_id=991, class_='place', type='house',
126 rank_search=30, rank_address=30,
128 centroid=(10.0, 10.00002))
129 apiobj.add_osmline(place_id=992,
131 startnumber=1, endnumber=3, step=1,
132 centroid=(10.0, 10.00001),
133 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
135 assert apiobj.api.reverse((10.0, 10.0)).place_id == 992
138 def test_reverse_housenumber_point_interpolation(apiobj):
139 apiobj.add_placex(place_id=990, class_='highway', type='service',
140 rank_search=27, rank_address=27,
141 name = {'name': 'My Street'},
142 centroid=(10.0, 10.0),
143 geometry='LINESTRING(9.995 10, 10.005 10)')
144 apiobj.add_osmline(place_id=992,
146 startnumber=42, endnumber=42, step=1,
147 centroid=(10.0, 10.00001),
148 geometry='POINT(10.0 10.00001)')
150 res = apiobj.api.reverse((10.0, 10.0))
151 assert res.place_id == 992
152 assert res.housenumber == '42'
155 def test_reverse_tiger_number(apiobj):
156 apiobj.add_placex(place_id=990, class_='highway', type='service',
157 rank_search=27, rank_address=27,
158 name = {'name': 'My Street'},
159 centroid=(10.0, 10.0),
161 geometry='LINESTRING(9.995 10, 10.005 10)')
162 apiobj.add_tiger(place_id=992,
164 startnumber=1, endnumber=3, step=1,
165 centroid=(10.0, 10.00001),
166 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
168 assert apiobj.api.reverse((10.0, 10.0)).place_id == 992
169 assert apiobj.api.reverse((10.0, 10.00001)).place_id == 992
172 def test_reverse_point_tiger(apiobj):
173 apiobj.add_placex(place_id=990, class_='highway', type='service',
174 rank_search=27, rank_address=27,
175 name = {'name': 'My Street'},
176 centroid=(10.0, 10.0),
178 geometry='LINESTRING(9.995 10, 10.005 10)')
179 apiobj.add_tiger(place_id=992,
181 startnumber=1, endnumber=1, step=1,
182 centroid=(10.0, 10.00001),
183 geometry='POINT(10.0 10.00001)')
185 res = apiobj.api.reverse((10.0, 10.0))
186 assert res.place_id == 992
187 assert res.housenumber == '1'
190 def test_reverse_low_zoom_address(apiobj):
191 apiobj.add_placex(place_id=1001, class_='place', type='house',
195 centroid=(59.3, 80.70001))
196 apiobj.add_placex(place_id=1002, class_='place', type='town',
197 name={'name': 'Town'},
200 centroid=(59.3, 80.70001),
201 geometry="""POLYGON((59.3 80.70001, 59.3001 80.70001,
202 59.3001 80.70101, 59.3 80.70101, 59.3 80.70001))""")
204 assert apiobj.api.reverse((59.30005, 80.7005)).place_id == 1001
205 assert apiobj.api.reverse((59.30005, 80.7005), max_rank=18).place_id == 1002
208 def test_reverse_place_node_in_area(apiobj):
209 apiobj.add_placex(place_id=1002, class_='place', type='town',
210 name={'name': 'Town Area'},
213 centroid=(59.3, 80.70001),
214 geometry="""POLYGON((59.3 80.70001, 59.3001 80.70001,
215 59.3001 80.70101, 59.3 80.70101, 59.3 80.70001))""")
216 apiobj.add_placex(place_id=1003, class_='place', type='suburb',
217 name={'name': 'Suburb Point'},
221 centroid=(59.30004, 80.70055))
223 assert apiobj.api.reverse((59.30004, 80.70055)).place_id == 1003
226 @pytest.mark.parametrize('layer,place_id', [(napi.DataLayer.MANMADE, 225),
227 (napi.DataLayer.RAILWAY, 226),
228 (napi.DataLayer.NATURAL, 227),
229 (napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, 225),
230 (napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, 225)])
231 def test_reverse_larger_area_layers(apiobj, layer, place_id):
232 apiobj.add_placex(place_id=225, class_='man_made', type='dam',
233 name={'name': 'Dam'},
236 centroid=(1.3, 0.70003))
237 apiobj.add_placex(place_id=226, class_='railway', type='yard',
238 name={'name': 'Dam'},
241 centroid=(1.3, 0.70004))
242 apiobj.add_placex(place_id=227, class_='natural', type='spring',
243 name={'name': 'Dam'},
246 centroid=(1.3, 0.70005))
248 assert apiobj.api.reverse((1.3, 0.7), layer=layer).place_id == place_id
251 def test_reverse_country_lookup_no_objects(apiobj):
252 apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
254 assert apiobj.api.reverse((0.5, 0.5)) is None
257 @pytest.mark.parametrize('rank', [4, 30])
258 def test_reverse_country_lookup_country_only(apiobj, rank):
259 apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
260 apiobj.add_placex(place_id=225, class_='place', type='country',
261 name={'name': 'My Country'},
267 assert apiobj.api.reverse((0.5, 0.5), max_rank=rank).place_id == 225
270 def test_reverse_country_lookup_place_node_inside(apiobj):
271 apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
272 apiobj.add_placex(place_id=225, class_='place', type='state',
274 name={'name': 'My State'},
278 centroid=(0.5, 0.505))
280 assert apiobj.api.reverse((0.5, 0.5)).place_id == 225
283 @pytest.mark.parametrize('gtype', list(napi.GeometryFormat))
284 def test_reverse_geometry_output_placex(apiobj, gtype):
285 apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
286 apiobj.add_placex(place_id=1001, class_='place', type='house',
290 centroid=(59.3, 80.70001))
291 apiobj.add_placex(place_id=1003, class_='place', type='suburb',
292 name={'name': 'Suburb Point'},
299 details = napi.LookupDetails(geometry_output=gtype)
301 assert apiobj.api.reverse((59.3, 80.70001), details=details).place_id == 1001
302 assert apiobj.api.reverse((0.5, 0.5), details=details).place_id == 1003
305 def test_reverse_simplified_geometry(apiobj):
306 apiobj.add_placex(place_id=1001, class_='place', type='house',
310 centroid=(59.3, 80.70001))
312 details = napi.LookupDetails(geometry_output=napi.GeometryFormat.GEOJSON,
313 geometry_simplification=0.1)
314 assert apiobj.api.reverse((59.3, 80.70001), details=details).place_id == 1001
317 def test_reverse_interpolation_geometry(apiobj):
318 apiobj.add_osmline(place_id=992,
320 startnumber=1, endnumber=3, step=1,
321 centroid=(10.0, 10.00001),
322 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
324 details = napi.LookupDetails(geometry_output=napi.GeometryFormat.TEXT)
325 assert apiobj.api.reverse((10.0, 10.0), details=details)\
326 .geometry['text'] == 'POINT(10 10.00001)'
329 def test_reverse_tiger_geometry(apiobj):
330 apiobj.add_placex(place_id=990, class_='highway', type='service',
331 rank_search=27, rank_address=27,
332 name = {'name': 'My Street'},
333 centroid=(10.0, 10.0),
335 geometry='LINESTRING(9.995 10, 10.005 10)')
336 apiobj.add_tiger(place_id=992,
338 startnumber=1, endnumber=3, step=1,
339 centroid=(10.0, 10.00001),
340 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
342 details = napi.LookupDetails(geometry_output=napi.GeometryFormat.GEOJSON)
343 output = apiobj.api.reverse((10.0, 10.0), details=details).geometry['geojson']
345 assert json.loads(output) == {'coordinates': [10, 10.00001], 'type': 'Point'}