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_tiger_number(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),
144 geometry='LINESTRING(9.995 10, 10.005 10)')
145 apiobj.add_tiger(place_id=992,
147 startnumber=1, endnumber=3, step=1,
148 centroid=(10.0, 10.00001),
149 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
151 assert apiobj.api.reverse((10.0, 10.0)).place_id == 992
152 assert apiobj.api.reverse((10.0, 10.00001)).place_id == 992
155 def test_reverse_low_zoom_address(apiobj):
156 apiobj.add_placex(place_id=1001, class_='place', type='house',
160 centroid=(59.3, 80.70001))
161 apiobj.add_placex(place_id=1002, class_='place', type='town',
162 name={'name': 'Town'},
165 centroid=(59.3, 80.70001),
166 geometry="""POLYGON((59.3 80.70001, 59.3001 80.70001,
167 59.3001 80.70101, 59.3 80.70101, 59.3 80.70001))""")
169 assert apiobj.api.reverse((59.30005, 80.7005)).place_id == 1001
170 assert apiobj.api.reverse((59.30005, 80.7005), max_rank=18).place_id == 1002
173 def test_reverse_place_node_in_area(apiobj):
174 apiobj.add_placex(place_id=1002, class_='place', type='town',
175 name={'name': 'Town Area'},
178 centroid=(59.3, 80.70001),
179 geometry="""POLYGON((59.3 80.70001, 59.3001 80.70001,
180 59.3001 80.70101, 59.3 80.70101, 59.3 80.70001))""")
181 apiobj.add_placex(place_id=1003, class_='place', type='suburb',
182 name={'name': 'Suburb Point'},
186 centroid=(59.30004, 80.70055))
188 assert apiobj.api.reverse((59.30004, 80.70055)).place_id == 1003
191 @pytest.mark.parametrize('layer,place_id', [(napi.DataLayer.MANMADE, 225),
192 (napi.DataLayer.RAILWAY, 226),
193 (napi.DataLayer.NATURAL, 227),
194 (napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, 225),
195 (napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, 225)])
196 def test_reverse_larger_area_layers(apiobj, layer, place_id):
197 apiobj.add_placex(place_id=225, class_='man_made', type='dam',
198 name={'name': 'Dam'},
201 centroid=(1.3, 0.70003))
202 apiobj.add_placex(place_id=226, class_='railway', type='yard',
203 name={'name': 'Dam'},
206 centroid=(1.3, 0.70004))
207 apiobj.add_placex(place_id=227, class_='natural', type='spring',
208 name={'name': 'Dam'},
211 centroid=(1.3, 0.70005))
213 assert apiobj.api.reverse((1.3, 0.7), layer=layer).place_id == place_id
216 def test_reverse_country_lookup_no_objects(apiobj):
217 apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
219 assert apiobj.api.reverse((0.5, 0.5)) is None
222 @pytest.mark.parametrize('rank', [4, 30])
223 def test_reverse_country_lookup_country_only(apiobj, rank):
224 apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
225 apiobj.add_placex(place_id=225, class_='place', type='country',
226 name={'name': 'My Country'},
232 assert apiobj.api.reverse((0.5, 0.5), max_rank=rank).place_id == 225
235 def test_reverse_country_lookup_place_node_inside(apiobj):
236 apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
237 apiobj.add_placex(place_id=225, class_='place', type='state',
239 name={'name': 'My State'},
243 centroid=(0.5, 0.505))
245 assert apiobj.api.reverse((0.5, 0.5)).place_id == 225
248 @pytest.mark.parametrize('gtype', list(napi.GeometryFormat))
249 def test_reverse_geometry_output_placex(apiobj, gtype):
250 apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
251 apiobj.add_placex(place_id=1001, class_='place', type='house',
255 centroid=(59.3, 80.70001))
256 apiobj.add_placex(place_id=1003, class_='place', type='suburb',
257 name={'name': 'Suburb Point'},
264 details = napi.LookupDetails(geometry_output=gtype)
266 assert apiobj.api.reverse((59.3, 80.70001), details=details).place_id == 1001
267 assert apiobj.api.reverse((0.5, 0.5), details=details).place_id == 1003
270 def test_reverse_simplified_geometry(apiobj):
271 apiobj.add_placex(place_id=1001, class_='place', type='house',
275 centroid=(59.3, 80.70001))
277 details = napi.LookupDetails(geometry_output=napi.GeometryFormat.GEOJSON,
278 geometry_simplification=0.1)
279 assert apiobj.api.reverse((59.3, 80.70001), details=details).place_id == 1001
282 def test_reverse_interpolation_geometry(apiobj):
283 apiobj.add_osmline(place_id=992,
285 startnumber=1, endnumber=3, step=1,
286 centroid=(10.0, 10.00001),
287 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
289 details = napi.LookupDetails(geometry_output=napi.GeometryFormat.TEXT)
290 assert apiobj.api.reverse((10.0, 10.0), details=details)\
291 .geometry['text'] == 'POINT(10 10.00001)'
294 def test_reverse_tiger_geometry(apiobj):
295 apiobj.add_placex(place_id=990, class_='highway', type='service',
296 rank_search=27, rank_address=27,
297 name = {'name': 'My Street'},
298 centroid=(10.0, 10.0),
300 geometry='LINESTRING(9.995 10, 10.005 10)')
301 apiobj.add_tiger(place_id=992,
303 startnumber=1, endnumber=3, step=1,
304 centroid=(10.0, 10.00001),
305 geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
307 details = napi.LookupDetails(geometry_output=napi.GeometryFormat.GEOJSON)
308 output = apiobj.api.reverse((10.0, 10.0), details=details).geometry['geojson']
310 assert json.loads(output) == {'coordinates': [10, 10.00001], 'type': 'Point'}