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), layers=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 layers=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), layers=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 assert apiobj.api.reverse((59.3, 80.70001), geometry_output=gtype).place_id == 1001
300 assert apiobj.api.reverse((0.5, 0.5), geometry_output=gtype).place_id == 1003
303 def test_reverse_simplified_geometry(apiobj):
304 apiobj.add_placex(place_id=1001, class_='place', type='house',
308 centroid=(59.3, 80.70001))
310 details = dict(geometry_output=napi.GeometryFormat.GEOJSON,
311 geometry_simplification=0.1)
312 assert apiobj.api.reverse((59.3, 80.70001), **details).place_id == 1001
315 def test_reverse_interpolation_geometry(apiobj):
316 apiobj.add_osmline(place_id=992,
318 startnumber=1, endnumber=3, step=1,
319 centroid=(10.0, 10.00001),
320 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
322 assert apiobj.api.reverse((10.0, 10.0), geometry_output=napi.GeometryFormat.TEXT)\
323 .geometry['text'] == 'POINT(10 10.00001)'
326 def test_reverse_tiger_geometry(apiobj):
327 apiobj.add_placex(place_id=990, class_='highway', type='service',
328 rank_search=27, rank_address=27,
329 name = {'name': 'My Street'},
330 centroid=(10.0, 10.0),
332 geometry='LINESTRING(9.995 10, 10.005 10)')
333 apiobj.add_tiger(place_id=992,
335 startnumber=1, endnumber=3, step=1,
336 centroid=(10.0, 10.00001),
337 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
339 output = apiobj.api.reverse((10.0, 10.0),
340 geometry_output=napi.GeometryFormat.GEOJSON).geometry['geojson']
342 assert json.loads(output) == {'coordinates': [10, 10.00001], 'type': 'Point'}