add BDD tests for DB

This commit is contained in:
Sarah Hoffmann
2025-04-09 14:52:34 +02:00
parent 5f44aa2873
commit b34991d85f
33 changed files with 6095 additions and 46 deletions

View File

@@ -12,6 +12,7 @@ import json
from pathlib import Path
import psycopg
from psycopg import sql as pysql
# always test against the source
SRC_DIR = (Path(__file__) / '..' / '..' / '..').resolve()
@@ -25,13 +26,13 @@ pytest.register_assert_rewrite('utils')
from utils.api_runner import APIRunner
from utils.api_result import APIResult
from utils.checks import ResultAttr, COMPARATOR_TERMS, check_table_content, check_table_has_lines
from utils.checks import ResultAttr, COMPARATOR_TERMS
from utils.geometry_alias import ALIASES
from utils.grid import Grid
from utils.db import DBManager
from nominatim_db.config import Configuration
from nominatim_db import cli
from nominatim_db.data.country_info import setup_country_config
def _strlist(inp):
@@ -77,6 +78,11 @@ def node_grid():
return Grid([[]], None, None)
@pytest.fixture(scope='session', autouse=True)
def setup_country_info():
setup_country_config(Configuration(None))
@pytest.fixture(scope='session')
def template_db(pytestconfig):
""" Create a template database containing the extensions and base data
@@ -147,6 +153,28 @@ def reverse_geocode_via_api(test_config_env, pytestconfig, datatable, lat, lon):
return result
@when(step_parse(r'reverse geocoding at node (?P<node>[\d]+)'),
target_fixture='nominatim_result')
def reverse_geocode_via_api_and_grid(test_config_env, pytestconfig, node_grid, datatable, node):
coords = node_grid.get(node)
if coords is None:
raise ValueError('Unknown node id')
runner = APIRunner(test_config_env, pytestconfig.option.NOMINATIM_API_ENGINE)
api_response = runner.run_step('reverse',
{'lat': coords[1], 'lon': coords[0]},
datatable, 'jsonv2', {})
assert api_response.status == 200
assert api_response.headers['content-type'] == 'application/json; charset=utf-8'
result = APIResult('json', 'reverse', api_response.body)
assert result.is_simple()
result.result['centroid'] = f"POINT({result.result['lon']:.7f} {result.result['lat']:.7f})"
return result
@when(step_parse(r'geocoding(?: "(?P<query>.*)")?'),
target_fixture='nominatim_result')
def forward_geocode_via_api(test_config_env, pytestconfig, datatable, query):
@@ -164,6 +192,9 @@ def forward_geocode_via_api(test_config_env, pytestconfig, datatable, query):
result = APIResult('json', 'search', api_response.body)
assert not result.is_simple()
for res in result.result:
res['centroid'] = f"POINT({res['lon']:.7f} {res['lat']:.7f})"
return result
@@ -194,7 +225,7 @@ def check_metadata_for_field_presence(nominatim_result, attributes):
@then(step_parse(r'the result contains(?: in field (?P<field>\S+))?'))
def check_result_for_fields(nominatim_result, datatable, field):
def check_result_for_fields(nominatim_result, datatable, node_grid, field):
assert nominatim_result.is_simple()
if datatable[0] == ['param', 'value']:
@@ -205,7 +236,7 @@ def check_result_for_fields(nominatim_result, datatable, field):
prefix = field + '+' if field else ''
for k, v in pairs:
assert ResultAttr(nominatim_result.result, prefix + k) == v
assert ResultAttr(nominatim_result.result, prefix + k, grid=node_grid) == v
@then(step_parse('the result has attributes (?P<attributes>.*)'),
@@ -248,6 +279,7 @@ def check_result_list_match(nominatim_result, datatable, exact):
converters={'attributes': _strlist})
def check_all_results_for_field_presence(nominatim_result, attributes):
assert not nominatim_result.is_simple()
assert len(nominatim_result) > 0
for res in nominatim_result.result:
assert all(a in res for a in attributes), \
f"Missing one of the attributes '{attributes}' in\n{_pretty_json(res)}"
@@ -257,14 +289,16 @@ def check_all_results_for_field_presence(nominatim_result, attributes):
converters={'attributes': _strlist})
def check_all_result_for_field_absence(nominatim_result, attributes):
assert not nominatim_result.is_simple()
assert len(nominatim_result) > 0
for res in nominatim_result.result:
assert all(a not in res for a in attributes), \
f"Unexpectedly have one of the attributes '{attributes}' in\n{_pretty_json(res)}"
@then(step_parse(r'all results contain(?: in field (?P<field>\S+))?'))
def check_all_results_contain(nominatim_result, datatable, field):
def check_all_results_contain(nominatim_result, datatable, node_grid, field):
assert not nominatim_result.is_simple()
assert len(nominatim_result) > 0
if datatable[0] == ['param', 'value']:
pairs = datatable[1:]
@@ -275,14 +309,14 @@ def check_all_results_contain(nominatim_result, datatable, field):
for k, v in pairs:
for r in nominatim_result.result:
assert ResultAttr(r, prefix + k) == v
assert ResultAttr(r, prefix + k, grid=node_grid) == v
@then(step_parse(r'result (?P<num>\d+) contains(?: in field (?P<field>\S+))?'),
converters={'num': int})
def check_specific_result_for_fields(nominatim_result, datatable, num, field):
assert not nominatim_result.is_simple()
assert len(nominatim_result) >= num + 1
assert len(nominatim_result) > num
if datatable[0] == ['param', 'value']:
pairs = datatable[1:]
@@ -313,3 +347,18 @@ def set_node_grid(datatable, step, origin):
raise RuntimeError('Grid origin must be either coordinate or alias.')
return Grid(datatable, step, origin)
@then(step_parse('(?P<table>placex?) has no entry for '
r'(?P<osm_type>[NRW])(?P<osm_id>\d+)(?::(?P<osm_class>\S+))?'),
converters={'osm_id': int})
def check_place_missing_lines(db_conn, table, osm_type, osm_id, osm_class):
sql = pysql.SQL("""SELECT count(*) FROM {}
WHERE osm_type = %s and osm_id = %s""").format(pysql.Identifier(table))
params = [osm_type, int(osm_id)]
if osm_class:
sql += pysql.SQL(' AND class = %s')
params.append(osm_class)
with db_conn.cursor() as cur:
assert cur.execute(sql, params).fetchone()[0] == 0

View File

@@ -0,0 +1,531 @@
Feature: Address computation
Tests for filling of place_addressline
Scenario: place nodes are added to the address when they are close enough
Given the 0.002 grid
| 2 | | | | | | 1 | | 3 |
And the places
| osm | class | type | name | geometry |
| N1 | place | square | Square | 1 |
| N2 | place | hamlet | West Farm | 2 |
| N3 | place | hamlet | East Farm | 3 |
When importing
Then place_addressline contains exactly
| object | address | fromarea |
| N1 | N3 | False |
When geocoding "Square"
Then the result set contains
| object | display_name |
| N1 | Square, East Farm |
Scenario: given two place nodes, the closer one wins for the address
Given the grid
| 2 | | | 1 | | 3 |
And the named places
| osm | class | type | geometry |
| N1 | place | square | 1 |
| N2 | place | hamlet | 2 |
| N3 | place | hamlet | 3 |
When importing
Then place_addressline contains
| object | address | fromarea | isaddress |
| N1 | N3 | False | True |
| N1 | N2 | False | False |
Scenario: boundaries around the place are added to the address
Given the grid
| 1 | | 4 | | 7 | 10 |
| 2 | | 5 | | 8 | 11 |
| | | | | | |
| | | | | | |
| | | 6 | | 9 | |
| | 99 | | | | |
| 3 | | | | | 12 |
And the named places
| osm | class | type | admin | geometry |
| R1 | boundary | administrative | 3 | (1,2,3,12,11,10,7,8,9,6,5,4,1) |
| R2 | boundary | administrative | 4 | (2,3,12,11,8,9,6,5,2) |
| N1 | place | square | 15 | 99 |
When importing
Then place_addressline contains
| object | address | isaddress |
| N1 | R1 | True |
| N1 | R2 | True |
Scenario: with boundaries of same rank the one with the closer centroid is preferred
Given the grid
| 1 | | | 3 | | 5 |
| | 9 | | | | |
| 2 | | | 4 | | 6 |
And the named places
| osm | class | type | admin | geometry |
| R1 | boundary | administrative | 8 | (1,2,4,3,1) |
| R2 | boundary | administrative | 8 | (1,2,6,5,1) |
| N1 | place | square | 15 | 9 |
When importing
Then place_addressline contains
| object | address | isaddress |
| N1 | R1 | True |
| N1 | R2 | False |
Scenario: boundary areas are preferred over place nodes in the address
Given the grid
| 1 | | | | 10 | | 3 |
| | 5 | | | | | |
| | 6 | | | | | |
| 2 | | | | 11 | | 4 |
And the named places
| osm | class | type | admin | geometry |
| N1 | place | square | 15 | 5 |
| N2 | place | city | 15 | 6 |
| R1 | place | city | 8 | (1,2,4,3,1) |
| R2 | boundary | administrative | 9 | (1,10,11,2,1) |
When importing
Then place_addressline contains
| object | address | isaddress | cached_rank_address |
| N1 | R1 | True | 16 |
| N1 | R2 | True | 18 |
| N1 | N2 | False | 18 |
Scenario: place nodes outside a smaller ranked area are ignored
Given the grid
| 1 | | 2 | |
| | 7 | | 9 |
| 4 | | 3 | |
And the named places
| osm | class | type | admin | geometry |
| N1 | place | square | 15 | 7 |
| N2 | place | city | 15 | 9 |
| R1 | place | city | 8 | (1,2,3,4,1) |
When importing
Then place_addressline contains exactly
| object | address | isaddress | cached_rank_address |
| N1 | R1 | True | 16 |
Scenario: place nodes close enough to smaller ranked place nodes are included
Given the 0.002 grid
| 2 | | 3 | 1 |
And the named places
| osm | class | type | geometry |
| N1 | place | square | 1 |
| N2 | place | hamlet | 2 |
| N3 | place | quarter | 3 |
When importing
Then place_addressline contains
| object | address | fromarea | isaddress |
| N1 | N2 | False | True |
| N1 | N3 | False | True |
Scenario: place nodes too far away from a smaller ranked place nodes are marked non-address
Given the 0.002 grid
| 2 | | | 1 | | 3 |
And the named places
| osm | class | type | geometry |
| N1 | place | square | 1 |
| N2 | place | hamlet | 2 |
| N3 | place | quarter | 3 |
When importing
Then place_addressline contains
| object | address | fromarea | isaddress |
| N1 | N2 | False | True |
| N1 | N3 | False | False |
# github #121
Scenario: Roads crossing boundaries should contain both states
Given the grid
| 1 | | | 2 | | 3 |
| | 7 | | | 8 | |
| 4 | | | 5 | | 6 |
And the named places
| osm | class | type | geometry |
| W1 | highway | road | 7, 8 |
And the named places
| osm | class | type | admin | geometry |
| W10 | boundary | administrative | 5 | (1, 2, 5, 4, 1) |
| W11 | boundary | administrative | 5 | (2, 3, 6, 5, 2) |
When importing
Then place_addressline contains
| object | address | cached_rank_address |
| W1 | W10 | 10 |
| W1 | W11 | 10 |
Scenario: Roads following a boundary should contain both states
Given the grid
| 1 | | | 2 | | 3 |
| | | 8 | 7 | | |
| 4 | | | 5 | | 6 |
And the named places
| osm | class | type | geometry |
| W1 | highway | road | 2, 7, 8 |
And the named places
| osm | class | type | admin | geometry |
| W10 | boundary | administrative | 5 | (1, 2, 5, 4, 1) |
| W11 | boundary | administrative | 5 | (2, 3, 6, 5, 2) |
When importing
Then place_addressline contains
| object | address | cached_rank_address |
| W1 | W10 | 10 |
| W1 | W11 | 10 |
Scenario: Roads should not contain boundaries they touch in a end point
Given the grid
| 1 | | | 2 | | 3 |
| | 7 | | 8 | | |
| 4 | | | 5 | | 6 |
And the named places
| osm | class | type | geometry |
| W1 | highway | road | 7, 8 |
And the named places
| osm | class | type | admin | geometry |
| W10 | boundary | administrative | 5 | (1, 2, 8, 5, 4, 1) |
| W11 | boundary | administrative | 5 | (2, 3, 6, 5, 8, 2) |
When importing
Then place_addressline contains exactly
| object | address | cached_rank_address |
| W1 | W10 | 10 |
Scenario: Roads should not contain boundaries they touch in a middle point
Given the grid
| 1 | | | 2 | | 3 |
| | 7 | | 8 | | |
| 4 | | 9 | 5 | | 6 |
And the named places
| osm | class | type | geometry |
| W1 | highway | road | 7, 8, 9 |
And the named places
| osm | class | type | admin | geometry |
| W10 | boundary | administrative | 5 | (1, 2, 8, 5, 4, 1) |
| W11 | boundary | administrative | 5 | (2, 3, 6, 5, 8, 2) |
When importing
Then place_addressline contains exactly
| object | address | cached_rank_address |
| W1 | W10 | 10 |
Scenario: Locality points should contain all boundaries they touch
Given the 0.001 grid
| 1 | | | 2 | | 3 |
| | | | 8 | | |
| 4 | | | 5 | | 6 |
And the named places
| osm | class | type | geometry |
| N1 | place | locality | 8 |
And the named places
| osm | class | type | admin | geometry |
| W10 | boundary | administrative | 5 | (1, 2, 8, 5, 4, 1) |
| W11 | boundary | administrative | 5 | (2, 3, 6, 5, 8, 2) |
When importing
Then place_addressline contains
| object | address | cached_rank_address |
| N1 | W10 | 10 |
| N1 | W11 | 10 |
Scenario: Areas should not contain boundaries they touch
Given the grid
| 1 | | | 2 | | 3 |
| | | | | | |
| 4 | | | 5 | | 6 |
And the named places
| osm | class | type | geometry |
| W1 | landuse | industrial | (1, 2, 5, 4, 1) |
And the named places
| osm | class | type | admin | geometry |
| W10 | boundary | administrative | 5 | (2, 3, 6, 5, 2) |
When importing
Then place_addressline contains exactly
| object | address |
Scenario: buildings with only addr:postcodes do not appear in the address of a way
Given the grid with origin DE
| 1 | | | | | 8 | | 6 | | 2 |
| |10 |11 | | | | | | | |
| |13 |12 | | | | | | | |
| 20| | | 21| | | | | | |
| | | | | | | | | | |
| | | | | | 9 | | | | |
| 4 | | | | | | | 7 | | 3 |
And the named places
| osm | class | type | admin | addr+postcode | geometry |
| R1 | boundary | administrative | 6 | 10000 | (1,2,3,4,1)|
| R34 | boundary | administrative | 8 | 11200 | (1,6,7,4,1)|
| R4 | boundary | administrative | 10 | 11230 | (1,8,9,4,1)|
And the named places
| osm | class | type | geometry |
| W93 | highway | residential | 20,21 |
And the places
| osm | class | type | addr+postcode | geometry |
| W22 | place | postcode | 11234 | (10,11,12,13,10) |
When importing
Then place_addressline contains exactly
| object | address |
| R4 | R1 |
| R4 | R34 |
| R34 | R1 |
| W93 | R1 |
| W93 | R34 |
| W93 | R4 |
Scenario: postcode boundaries do appear in the address of a way
Given the grid with origin DE
| 1 | | | | | 8 | | 6 | | 2 |
| |10 |11 | | | | | | | |
| |13 |12 | | | | | | | |
| 20| | | 21| | | | | | |
| | | | | | | | | | |
| | | | | | 9 | | | | |
| 4 | | | | | | | 7 | | 3 |
And the named places
| osm | class | type | admin | addr+postcode | geometry |
| R1 | boundary | administrative | 6 | 10000 | (1,2,3,4,1) |
| R34 | boundary | administrative | 8 | 11000 | (1,6,7,4,1) |
And the places
| osm | class | type | addr+postcode | geometry |
| R4 | boundary | postal_code | 11200 | (1,8,9,4,1) |
And the named places
| osm | class | type | geometry |
| W93 | highway | residential | 20,21 |
And the places
| osm | class | type | addr+postcode | geometry |
| W22 | place | postcode | 11234 | (10,11,12,13,10) |
When importing
Then place_addressline contains
| object | address |
| W93 | R4 |
Scenario: squares do not appear in the address of a street
Given the grid
| | 1 | | 2 | |
| 8 | | | | 9 |
| | 4 | | 3 | |
And the named places
| osm | class | type | geometry |
| W1 | highway | residential | 8, 9 |
| W2 | place | square | (1, 2, 3 ,4, 1) |
When importing
Then place_addressline contains exactly
| object | address |
Scenario: addr:* tags are honored even when a street is far away from the place
Given the grid
| 1 | | 2 | | | 5 |
| | | | 8 | 9 | |
| 4 | | 3 | | | 6 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
And the places
| osm | class | type | addr+city | geometry |
| W1 | highway | primary | Left | 8,9 |
| W2 | highway | primary | Right | 8,9 |
When importing
Then place_addressline contains exactly
| object | address | isaddress |
| W1 | R1 | True |
| W1 | R2 | False |
| W2 | R2 | True |
Scenario: addr:* tags are honored even when a POI is far away from the place
Given the grid
| 1 | | 2 | | | 5 |
| | | | 8 | 9 | |
| 4 | | 3 | | | 6 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
And the places
| osm | class | type | name | addr+city | geometry |
| W1 | highway | primary | Wonderway | Right | 8,9 |
| N1 | amenity | cafe | Bolder | Left | 9 |
When importing
Then place_addressline contains exactly
| object | address | isaddress |
| W1 | R2 | True |
| N1 | R1 | True |
When geocoding "Bolder"
Then the result set contains
| object | display_name |
| N1 | Bolder, Wonderway, Left |
Scenario: addr:* tags do not produce addresslines when the parent has the address part
Given the grid
| 1 | | | 5 |
| | 8 | 9 | |
| 4 | | | 6 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 8 | Outer | (1,5,6,4,1) |
And the places
| osm | class | type | name | addr+city | geometry |
| W1 | highway | primary | Wonderway | Outer | 8,9 |
| N1 | amenity | cafe | Bolder | Outer | 9 |
When importing
Then place_addressline contains exactly
| object | address | isaddress |
| W1 | R1 | True |
When geocoding "Bolder"
Then the result set contains
| object | display_name |
| N1 | Bolder, Wonderway, Outer |
Scenario: addr:* tags on outside do not produce addresslines when the parent has the address part
Given the grid
| 1 | | 2 | | | 5 |
| | | | 8 | 9 | |
| 4 | | 3 | | | 6 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
And the places
| osm | class | type | name | addr+city | geometry |
| W1 | highway | primary | Wonderway | Left | 8,9 |
| N1 | amenity | cafe | Bolder | Left | 9 |
When importing
Then place_addressline contains exactly
| object | address | isaddress |
| W1 | R1 | True |
| W1 | R2 | False |
When geocoding "Bolder"
Then the result set contains
| object | display_name |
| N1 | Bolder, Wonderway, Left |
Scenario: POIs can correct address parts on the fly
Given the grid
| 1 | | | | 2 | | 5 |
| | | | 9 | | 8 | |
| 4 | | | | 3 | | 6 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
And the places
| osm | class | type | name | geometry |
| W1 | highway | primary | Wonderway | 2,3 |
| N1 | amenity | cafe | Bolder | 9 |
| N2 | amenity | cafe | Leftside | 8 |
When importing
Then place_addressline contains exactly
| object | address | isaddress |
| W1 | R1 | False |
| W1 | R2 | True |
When geocoding "Bolder"
Then the result set contains
| object | display_name |
| N1 | Bolder, Wonderway, Left |
When geocoding "Leftside"
Then the result set contains
| object | display_name |
| N2 | Leftside, Wonderway, Right |
Scenario: POIs can correct address parts on the fly (with partial unmatching address)
Given the grid
| 1 | | | | 2 | | 5 |
| | | | 9 | | 8 | |
| | 10| 11| | | 12| |
| 4 | | | | 3 | | 6 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
And the places
| osm | class | type | name | geometry |
| W1 | highway | primary | Wonderway | 10,11,12 |
And the places
| osm | class | type | name | addr+suburb | geometry |
| N1 | amenity | cafe | Bolder | Boring | 9 |
| N2 | amenity | cafe | Leftside | Boring | 8 |
When importing
Then place_addressline contains exactly
| object | address | isaddress |
| W1 | R1 | True |
| W1 | R2 | False |
When geocoding "Bolder"
Then the result set contains
| object | display_name |
| N1 | Bolder, Wonderway, Left |
When geocoding "Leftside"
Then the result set contains
| object | display_name |
| N2 | Leftside, Wonderway, Right |
Scenario: POIs can correct address parts on the fly (with partial matching address)
Given the grid
| 1 | | | | 2 | | 5 |
| | | | 9 | | 8 | |
| | 10| 11| | | 12| |
| 4 | | | | 3 | | 6 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
And the places
| osm | class | type | name | geometry |
| W1 | highway | primary | Wonderway | 10,11,12 |
And the places
| osm | class | type | name | addr+state | geometry |
| N1 | amenity | cafe | Bolder | Left | 9 |
| N2 | amenity | cafe | Leftside | Left | 8 |
When importing
Then place_addressline contains exactly
| object | address | isaddress |
| W1 | R1 | True |
| W1 | R2 | False |
When geocoding "Bolder"
Then the result set contains
| object | display_name |
| N1 | Bolder, Wonderway, Left |
When geocoding "Leftside"
Then the result set contains
| object | display_name |
| N2 | Leftside, Wonderway, Left |
Scenario: addr:* tags always match the closer area
Given the grid
| 1 | | | | 2 | | 5 |
| | | | | | | |
| 4 | | | | 3 | | 6 |
| | 10| 11| | | | |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | Left | (2,3,6,5,2) |
And the places
| osm | class | type | name | addr+city | geometry |
| W1 | highway | primary | Wonderway | Left | 10,11 |
When importing
Then place_addressline contains exactly
| object | address |
| W1 | R1 |
Scenario: Full name is prefered for unlisted addr:place tags
Given the grid
| | 1 | 2 | |
| 8 | | | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | place | city | Away | (8,1,2,9,8) |
And the places
| osm | class | type | name | addr+city | geometry |
| W1 | highway | residential | Royal Terrace | Gardens | 8,9 |
And the places
| osm | class | type | housenr | addr+place | geometry | extra+foo |
| N1 | place | house | 1 | Royal Terrace Gardens | 1 | bar |
And the places
| osm | class | type | housenr | addr+street | geometry |
| N2 | place | house | 2 | Royal Terrace | 2 |
When importing
When geocoding "1, Royal Terrace Gardens"
Then result 0 contains
| object |
| N1 |

View File

@@ -0,0 +1,91 @@
Feature: Country handling
Tests for import and use of country information
Scenario: Country names from OSM country relations are added
Given the places
| osm | class | type | admin | name+name:xy | country | geometry |
| R1 | boundary | administrative | 2 | Loudou | de | (9 52, 9 53, 10 52, 9 52) |
Given the places
| osm | class | type | name | geometry |
| N1 | place | town | Wenig | country:de |
When importing
When geocoding "Wenig, Loudou"
Then the result set contains
| object | display_name |
| N1 | Wenig, Deutschland |
When geocoding "Wenig"
| accept-language |
| xy,en |
Then the result set contains
| object | display_name |
| N1 | Wenig, Loudou |
Scenario: OSM country relations outside expected boundaries are ignored for naming
Given the grid
| 1 | | 2 |
| 4 | | 3 |
Given the places
| osm | class | type | admin | name+name:xy | country | geometry |
| R1 | boundary | administrative | 2 | Loudou | de | (1,2,3,4,1) |
Given the places
| osm | class | type | name | geometry |
| N1 | place | town | Wenig | country:de |
When importing
When geocoding "Wenig"
| accept-language |
| xy,en |
Then the result set contains
| object | display_name |
| N1 | Wenig, Germany |
Scenario: Pre-defined country names are used
Given the grid with origin CH
| 1 |
Given the places
| osm | class | type | name | geometry |
| N1 | place | town | Ingb | 1 |
When importing
And geocoding "Ingb"
| accept-language |
| en,de |
Then the result set contains
| object | display_name |
| N1 | Ingb, Switzerland |
Scenario: For overlapping countries, pre-defined countries are tie-breakers
Given the grid with origin US
| 1 | | 2 | | 5 |
| | 9 | | 8 | |
| 4 | | 3 | | 6 |
Given the named places
| osm | class | type | admin | country | geometry |
| R1 | boundary | administrative | 2 | de | (1,5,6,4,1) |
| R2 | boundary | administrative | 2 | us | (1,2,3,4,1) |
And the named places
| osm | class | type | geometry |
| N1 | place | town | 9 |
| N2 | place | town | 8 |
When importing
Then placex contains
| object | country_code |
| N1 | us |
| N2 | de |
Scenario: For overlapping countries outside pre-define countries prefer smaller partition
Given the grid with origin US
| 1 | | 2 | | 5 |
| | 9 | | 8 | |
| 4 | | 3 | | 6 |
Given the named places
| osm | class | type | admin | country | geometry |
| R1 | boundary | administrative | 2 | ch | (1,5,6,4,1) |
| R2 | boundary | administrative | 2 | de | (1,2,3,4,1) |
And the named places
| osm | class | type | geometry |
| N1 | place | town | 9 |
| N2 | place | town | 8 |
When importing
Then placex contains
| object | country_code |
| N1 | de |
| N2 | ch |

View File

@@ -0,0 +1,616 @@
Feature: Import of address interpolations
Tests that interpolated addresses are added correctly
Scenario: Simple even interpolation line with two points and no street nearby
Given the grid with origin 1,1
| 1 | | 9 | | 2 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,2 |
And the ways
| id | nodes |
| 1 | 1,2 |
When importing
Then W1 expands to no interpolation
Scenario: Simple even interpolation line with two points
Given the grid with origin 1,1
| 1 | | 9 | | 2 |
| 4 | | | | 5 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 4 | 9 |
Scenario: Backwards even two point interpolation line
Given the grid with origin 1,1
| 1 | 8 | 9 | 2 |
| 4 | | | 5 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 8 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 2,1 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 2,1 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 6 | 8,9 |
Scenario: Simple odd two point interpolation
Given the grid with origin 1,1
| 1 | 8 | | | 9 | 2 |
| 4 | | | | 5 | |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 1 |
| N2 | place | house | 11 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | odd | 1,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 3 | 9 | 8,9 |
Scenario: Simple all two point interpolation
Given the grid with origin 1,1
| 1 | 8 | 9 | 2 |
| 4 | | | 5 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 1 |
| N2 | place | house | 4 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | all | 1,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 2 | 3 | 8,9 |
Scenario: Even two point interpolation line with intermediate empty node
Given the grid
| 1 | 8 | | 3 | 9 | 2 |
| 4 | | | | 5 | |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 12 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,3,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,3,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 10 | 8,3,9 |
Scenario: Even two point interpolation line with intermediate duplicated empty node
Given the grid
| 4 | | | | 5 |
| 1 | 8 | 3 | 9 | 2 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 10 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,3,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,3,3,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 8 | 8,3,9 |
Scenario: Simple even three point interpolation line
Given the grid
| 4 | | | | | | 5 |
| 1 | 8 | | 9 | 3 | 7 | 2 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 14 |
| N3 | place | house | 10 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,3,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,3,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 8 | 8,9 |
| 12 | 12 | 7 |
Scenario: Simple even four point interpolation line
Given the grid
| 1 | 10 | | 11 | 3 |
| | | | | 12|
| | | 4 | 13 | 2 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 14 |
| N3 | place | house | 10 |
| N4 | place | house | 18 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,3,2,4 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 1,3,2,4 |
And the ways
| id | nodes |
| 1 | 1,3,2,4 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 8 | 10,11 |
| 12 | 12 | 12 |
| 16 | 16 | 13 |
Scenario: Reverse simple even three point interpolation line
Given the grid
| 1 | 8 | | 9 | 3 | 7 | 2 |
| 4 | | | | | | 5 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 14 |
| N3 | place | house | 10 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 2,3,1 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 2,3,1 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 8 | 8,9 |
| 12 | 12 | 7 |
Scenario: Even three point interpolation line with odd center point
Given the grid
| 1 | | 10 | | 11 | 3 | 2 |
| 4 | | | | | | 5 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 8 |
| N3 | place | house | 7 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,3,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,3,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 6 | 10,11 |
Scenario: Interpolation line with self-intersecting way
Given the grid
| 1 | 9 | 2 |
| | | 8 |
| | | 3 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
| N3 | place | house | 10 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,2,3,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 1,2,3 |
And the ways
| id | nodes |
| 1 | 1,2,3,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 4 | 9 |
| 8 | 8 | 8 |
| 8 | 8 | 8 |
Scenario: Interpolation line with self-intersecting way II
Given the grid
| 1 | 9 | 2 |
| | | 3 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,2,3,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 1,2,3 |
And the ways
| id | nodes |
| 1 | 1,2,3,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 4 | 9 |
Scenario: addr:street on interpolation way
Given the grid
| | 1 | | 2 | |
| 10 | | | | 11 |
| 20 | | | | 21 |
And the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 2 | 1 |
| N2 | place | house | 6 | 2 |
| N3 | place | house | 12 | 1 |
| N4 | place | house | 16 | 2 |
And the places
| osm | class | type | addr+interpolation | street | geometry |
| W10 | place | houses | even | | 1,2 |
| W11 | place | houses | even | Cloud Street | 1,2 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | tertiary | Sun Way | 10,11 |
| W3 | highway | tertiary | Cloud Street | 20,21 |
And the ways
| id | nodes |
| 10 | 1,2 |
| 11 | 3,4 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
| N3 | W3 |
| N4 | W3 |
Then W10 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
Then W11 expands to interpolation
| parent_place_id | start | end |
| W3 | 14 | 14 |
When geocoding "16 Cloud Street"
Then result 0 contains
| object |
| N4 |
When geocoding "14 Cloud Street"
Then result 0 contains
| object |
| W11 |
Scenario: addr:street on housenumber way
Given the grid
| | 1 | | 2 | |
| 10 | | | | 11 |
| 20 | | | | 21 |
And the places
| osm | class | type | housenr | street | geometry |
| N1 | place | house | 2 | | 1 |
| N2 | place | house | 6 | | 2 |
| N3 | place | house | 12 | Cloud Street | 1 |
| N4 | place | house | 16 | Cloud Street | 2 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W10 | place | houses | even | 1,2 |
| W11 | place | houses | even | 1,2 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | tertiary | Sun Way | 10,11 |
| W3 | highway | tertiary | Cloud Street | 20,21 |
And the ways
| id | nodes |
| 10 | 1,2 |
| 11 | 3,4 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
| N3 | W3 |
| N4 | W3 |
Then W10 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
Then W11 expands to interpolation
| parent_place_id | start | end |
| W3 | 14 | 14 |
When geocoding "16 Cloud Street"
Then result 0 contains
| object |
| N4 |
When geocoding "14 Cloud Street"
Then result 0 contains
| object |
| W11 |
Scenario: Geometry of points and way don't match (github #253)
Given the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 10 | 144.9632341 -37.76163 |
| N2 | place | house | 6 | 144.9630541 -37.7628174 |
| N3 | shop | supermarket | 2 | 144.9629794 -37.7630755 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 144.9632341 -37.76163,144.9630541 -37.7628172,144.9629794 -37.7630755 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 144.9632341 -37.76163,144.9629794 -37.7630755 |
And the ways
| id | nodes |
| 1 | 1,2,3 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 4 | 144.96301672 -37.76294644 |
| 8 | 8 | 144.96314407 -37.762223692 |
Scenario: Place with missing address information
Given the grid
| 1 | | 2 | | | 3 |
| 4 | | | | | 5 |
And the places
| osm | class | type | housenr |
| N1 | place | house | 23 |
| N2 | amenity | school | |
| N3 | place | house | 29 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | odd | 1,2,3 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,2,3 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 25 | 27 | 0.0000166 0,0.00002 0,0.0000333 0 |
Scenario: Ways without node entries are ignored
Given the places
| osm | class | type | housenr | geometry |
| W1 | place | houses | even | 1 1, 1 1.001 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 1 1, 1 1.001 |
When importing
Then W1 expands to no interpolation
Scenario: Ways with nodes without housenumbers are ignored
Given the grid
| 1 | | 2 |
| 4 | | 5 |
Given the places
| osm | class | type |
| N1 | place | house |
| N2 | place | house |
Given the places
| osm | class | type | housenr | geometry |
| W1 | place | houses | even | 1,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
When importing
Then W1 expands to no interpolation
Scenario: Two point interpolation starting at 0
Given the grid with origin 1,1
| 1 | 10 | | | 11 | 2 |
| 4 | | | | | 5 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 0 |
| N2 | place | house | 10 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,2 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | residential | London Road |4,5 |
And the ways
| id | nodes |
| 1 | 1,2 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 2 | 8 | 10,11 |
When reverse geocoding 1,1
Then the result contains
| object | type | display_name |
| N1 | house | 0, London Road |
Scenario: Parenting of interpolation with additional tags
Given the grid
| 1 | | | | | |
| | | | | | |
| | 8 | | | 9 | |
| | | | | | |
| 2 | | | | | 3 |
Given the places
| osm | class | type | housenr | addr+street |
| N8 | place | house | 10 | Horiz St |
| N9 | place | house | 16 | Horiz St |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | Vert St | 1,2 |
| W2 | highway | residential | Horiz St | 2,3 |
And the places
| osm | class | type | addr+interpolation | addr+inclusion | geometry |
| W10 | place | houses | even | actual | 8,9 |
And the ways
| id | nodes |
| 10 | 8,9 |
When importing
Then placex contains
| object | parent_place_id |
| N8 | W2 |
| N9 | W2 |
And W10 expands to interpolation
| start | end | parent_place_id |
| 12 | 14 | W2 |
Scenario Outline: Bad interpolation values are ignored
Given the grid with origin 1,1
| 1 | | 9 | | 2 |
| 4 | | | | 5 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | <value> | 1,2 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,2 |
When importing
Then W1 expands to no interpolation
Examples:
| value |
| foo |
| x |
| 12-2 |
Scenario: Interpolation line where points have been moved (Github #3022)
Given the 0.00001 grid
| 1 | | | | | | | | 2 | 3 | 9 | | | | | | | | 4 |
Given the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 2 | 1 |
| N2 | place | house | 18 | 3 |
| N3 | place | house | 24 | 9 |
| N4 | place | house | 42 | 4 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,2,3,4 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 1,4 |
And the ways
| id | nodes |
| 1 | 1,2,3,4 |
When importing
Then W1 expands to interpolation
| start | end |
| 4 | 16 |
| 20 | 22 |
| 26 | 40 |
Scenario: Interpolation line with duplicated points
Given the grid
| 7 | 10 | 8 | 11 | 9 |
| 4 | | | | 5 |
Given the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 2 | 7 |
| N2 | place | house | 6 | 8 |
| N3 | place | house | 10 | 8 |
| N4 | place | house | 14 | 9 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 7,8,8,9 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 4,5 |
And the ways
| id | nodes |
| 1 | 1,2,3,4 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 4 | 10 |
| 12 | 12 | 11 |
Scenario: Interpolaton line with broken way geometry (Github #2986)
Given the grid
| 1 | 8 | 10 | 11 | 9 | 2 | 3 | 4 |
Given the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 8 |
| N3 | place | house | 12 |
| N4 | place | house | 14 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 8,9 |
And the named places
| osm | class | type | geometry |
| W10 | highway | residential | 1,4 |
And the ways
| id | nodes |
| 1 | 1,8,9,2,3,4 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
| 4 | 6 | 10,11 |

View File

@@ -0,0 +1,332 @@
Feature: Linking of places
Tests for correctly determining linked places
Scenario: Only address-describing places can be linked
Given the grid
| 1 | | | | 2 |
| | | 9 | | |
| 4 | | | | 3 |
And the places
| osm | class | type | name | geometry |
| R13 | landuse | forest | Garbo | (1,2,3,4,1) |
| N256 | natural | peak | Garbo | 9 |
When importing
Then placex contains
| object | linked_place_id |
| R13 | - |
| N256 | - |
Scenario: Postcode areas cannot be linked
Given the grid with origin US
| 1 | | 2 |
| | 9 | |
| 4 | | 3 |
And the named places
| osm | class | type | addr+postcode | extra+wikidata | geometry |
| R13 | boundary | postal_code | 12345 | Q87493 | (1,2,3,4,1) |
| N25 | place | suburb | 12345 | Q87493 | 9 |
When importing
Then placex contains
| object | linked_place_id |
| R13 | - |
| N25 | - |
Scenario: Waterways are linked when in waterway relations
Given the grid
| 1 | | | | 3 | 4 | | | | 6 |
| | | 2 | | | 10 | | 5 | | |
| | | | | | 11 | | | | |
And the places
| osm | class | type | name | geometry |
| W1 | waterway | river | Rhein | 1,2,3 |
| W2 | waterway | river | Rhein | 3,4,5 |
| R13 | waterway | river | Rhein | 1,2,3,4,5,6 |
| R23 | waterway | river | Limmat| 4,10,11 |
And the relations
| id | members | tags+type |
| 13 | R23:tributary,W1,W2:main_stream | waterway |
When importing
Then placex contains
| object | linked_place_id |
| W1 | R13 |
| W2 | R13 |
| R13 | - |
| R23 | - |
When geocoding "rhein"
Then the result set contains
| object |
| R13 |
Scenario: Relations are not linked when in waterway relations
Given the grid
| 1 | | | | 3 | 4 | | | | 6 |
| | | 2 | | | 10 | | 5 | | |
| | | | | | 11 | | | | |
And the places
| osm | class | type | name | geometry |
| W1 | waterway | stream | Rhein | 1,2,3,4 |
| W2 | waterway | river | Rhein | 4,5,6 |
| R1 | waterway | river | Rhein | 1,2,3,4 |
| R2 | waterway | river | Limmat| 4,10,11 |
And the relations
| id | members | tags+type |
| 1 | R2 | waterway |
When importing
Then placex contains
| object | linked_place_id |
| W1 | - |
| W2 | - |
| R1 | - |
| R2 | - |
When geocoding "rhein"
Then result 0 contains
| object |
| R1 |
And result 1 contains
| object |
| W2 |
Scenario: Empty waterway relations are handled correctly
Given the grid
| 1 | | | | 3 |
And the places
| osm | class | type | name | geometry |
| R1 | waterway | river | Rhein | 1,3 |
And the relations
| id | members | tags+type |
| 1 | | waterway |
When importing
Then placex contains
| object | linked_place_id |
| R1 | - |
Scenario: Waterways are not linked when the way type is not a river feature
Given the grid
| 1 | | 2 |
| | | |
| 3 | | 4 |
And the places
| osm | class | type | name | geometry |
| W1 | waterway | lock | Rhein | 3,4 |
| R1 | landuse | meadow | Rhein | (3,1,2,4,3) |
And the relations
| id | members | tags+type |
| 1 | W1,W2 | multipolygon |
When importing
Then placex contains
| object | linked_place_id |
| W1 | - |
| R1 | - |
Scenario: Side streams are linked only when they have the same name
Given the grid
| | | | | 8 | | | |
| 1 | | 2 | 3 | | 4 | 5 | 6|
| | | | | | 9 | | |
And the places
| osm | class | type | name | geometry |
| W1 | waterway | river | Rhein2 | 2,8,4 |
| W2 | waterway | river | Rhein | 3,9,5 |
| R1 | waterway | river | Rhein | 1,2,3,4,5,6 |
And the relations
| id | members | tags+type |
| 1 | W1:side_stream,W2:side_stream,W3 | waterway |
When importing
Then placex contains
| object | linked_place_id |
| W1 | - |
| W2 | R1 |
When geocoding "rhein2"
Then the result set contains
| object |
| W1 |
# github #573
Scenario: Boundaries should only be linked to places
Given the 0.05 grid
| 1 | | 2 |
| | 9 | |
| 4 | | 3 |
Given the named places
| osm | class | type | extra+wikidata | admin | geometry |
| R1 | boundary | administrative | 34 | 8 | (1,2,3,4,1) |
And the named places
| osm | class | type |
| N9 | natural | island |
| N9 | place | city |
And the relations
| id | members |
| 1 | N9:label |
When importing
Then placex contains
| object | linked_place_id |
| N9:natural | - |
| N9:place | R1 |
Scenario: Nodes with 'role' label are always linked
Given the 0.05 grid
| 1 | | 2 |
| | 9 | |
| 4 | | 3 |
Given the places
| osm | class | type | admin | name | geometry |
| R13 | boundary | administrative | 6 | Garbo | (1,2,3,4,1) |
| N2 | place | hamlet | 15 | Vario | 9 |
And the relations
| id | members | tags+type |
| 13 | N2:label | boundary |
When importing
Then placex contains
| object | linked_place_id |
| N2 | R13 |
And placex contains
| object | centroid!wkt | name+name | extratags+linked_place |
| R13 | 9 | Garbo | hamlet |
Scenario: Boundaries with place tags are linked against places with same type
Given the 0.01 grid
| 1 | | 2 |
| | 9 | |
| 4 | | 3 |
Given the places
| osm | class | type | admin | name | extra+place | geometry |
| R13 | boundary | administrative | 4 | Berlin | city | (1,2,3,4,1) |
And the places
| osm | class | type | name | geometry |
| N2 | place | city | Berlin | 9 |
When importing
Then placex contains
| object | linked_place_id |
| N2 | R13 |
And placex contains
| object | rank_address |
| R13 | 16 |
When geocoding ""
| city |
| Berlin |
Then result 0 contains
| object |
| R13 |
When geocoding ""
| state |
| Berlin |
Then result 0 contains
| object |
| R13 |
Scenario: Boundaries without place tags only link against same admin level
Given the 0.05 grid
| 1 | | 2 |
| | 9 | |
| 4 | | 3 |
Given the places
| osm | class | type | admin | name | geometry |
| R13 | boundary | administrative | 4 | Berlin | (1,2,3,4,1) |
And the places
| osm | class | type | name | geometry |
| N2 | place | city | Berlin | 9 |
When importing
Then placex contains
| object | linked_place_id |
| N2 | - |
And placex contains
| object | rank_address |
| R13 | 8 |
When geocoding ""
| state |
| Berlin |
Then result 0 contains
| object |
| R13 |
When geocoding ""
| city |
| Berlin |
Then result 0 contains
| object |
| N2 |
# github #1352
Scenario: Do not use linked centroid when it is outside the area
Given the 0.05 grid
| 1 | | 2 | |
| | | | 9 |
| 4 | | 3 | |
Given the named places
| osm | class | type | admin | geometry |
| R13 | boundary | administrative | 4 | (1,2,3,4,1) |
And the named places
| osm | class | type | geometry |
| N2 | place | city | 9 |
And the relations
| id | members | tags+type |
| 13 | N2:label | boundary |
When importing
Then placex contains
| object | linked_place_id |
| N2 | R13 |
And placex contains
| object | centroid!in_box |
| R13 | 0,0,0.1,0.1 |
Scenario: Place nodes can only be linked once
Given the 0.02 grid
| 1 | | 2 | | 5 |
| | 9 | | | |
| 4 | | 3 | | 6 |
Given the named places
| osm | class | type | extra+wikidata | geometry |
| N2 | place | city | Q1234 | 9 |
And the named places
| osm | class | type | extra+wikidata | admin | geometry |
| R1 | boundary | administrative | Q1234 | 8 | (1,2,5,6,3,4,1) |
| R2 | boundary | administrative | Q1234 | 9 | (1,2,3,4,1) |
When importing
Then placex contains
| object | linked_place_id |
| N2 | R1 |
And placex contains
| object | extratags!dict |
| R1 | 'linked_place' : 'city', 'wikidata': 'Q1234' |
| R2 | 'wikidata': 'Q1234' |
Scenario: Boundaries without names inherit names from linked places
Given the 0.05 grid
| 1 | | 2 |
| | 9 | |
| 4 | | 3 |
Given the places
| osm | class | type | extra+wikidata | admin | geometry |
| R1 | boundary | administrative | 34 | 8 | (1,2,3,4,1) |
And the places
| osm | class | type | name+name |
| N9 | place | city | LabelPlace |
And the relations
| id | members |
| 1 | N9:label |
When importing
Then placex contains
| object | name+_place_name |
| R1 | LabelPlace |
@skip
Scenario: Linked places expand default language names
Given the grid
| 1 | | 2 |
| | 9 | |
| 4 | | 3 |
Given the places
| osm | class | type | name+name | geometry |
| N9 | place | city | Popayán | 9 |
| R1 | boundary | administrative | Perímetro Urbano Popayán | (1,2,3,4,1) |
And the relations
| id | members |
| 1 | N9:label |
When importing
Then placex contains
| object | name+_place_name | name+_place_name:es |
| R1 | Popayán | Popayán |

View File

@@ -0,0 +1,104 @@
Feature: Import and search of names
Tests all naming related import issues
Scenario: No copying name tag if only one name
Given the places
| osm | class | type | name+name | geometry |
| N1 | place | locality | german | country:de |
When importing
Then placex contains
| object | country_code | name+name |
| N1 | de | german |
Scenario: Copying name tag to default language if it does not exist
Given the places
| osm | class | type | name+name | name+name:fi | geometry |
| N1 | place | locality | german | finnish | country:de |
When importing
Then placex contains
| object | country_code | name+name | name+name:fi | name+name:de |
| N1 | de | german | finnish | german |
Scenario: Copying default language name tag to name if it does not exist
Given the places
| osm | class | type | name+name:de | name+name:fi | geometry |
| N1 | place | locality | german | finnish | country:de |
When importing
Then placex contains
| object | country_code | name+name | name+name:fi | name+name:de |
| N1 | de | german | finnish | german |
Scenario: Do not overwrite default language with name tag
Given the places
| osm | class | type | name+name | name+name:fi | name+name:de | geometry |
| N1 | place | locality | german | finnish | local | country:de |
When importing
Then placex contains
| object | country_code | name+name | name+name:fi | name+name:de |
| N1 | de | german | finnish | local |
Scenario Outline: Names in any script can be found
Given the places
| osm | class | type | name+name |
| N1 | place | hamlet | <name> |
When importing
And geocoding "<name>"
Then the result set contains
| object |
| N1 |
Examples:
| name |
| Berlin |
| |
| Вологда |
| Αθήνα |
| القاهرة |
| |
| |
| |
Scenario: German umlauts can be found when expanded
Given the places
| osm | class | type | name+name:de |
| N1 | place | city | Münster |
| N2 | place | city | Köln |
| N3 | place | city | Gräfenroda |
When importing
When geocoding "münster"
Then the result set contains
| object |
| N1 |
When geocoding "muenster"
Then the result set contains
| object |
| N1 |
When geocoding "munster"
Then the result set contains
| object |
| N1 |
When geocoding "Köln"
Then the result set contains
| object |
| N2 |
When geocoding "Koeln"
Then the result set contains
| object |
| N2 |
When geocoding "Koln"
Then the result set contains
| object |
| N2 |
When geocoding "gräfenroda"
Then the result set contains
| object |
| N3 |
When geocoding "graefenroda"
Then the result set contains
| object |
| N3 |
When geocoding "grafenroda"
Then the result set contains
| object |
| N3 |

View File

@@ -0,0 +1,651 @@
Feature: Parenting of objects
Tests that the correct parent is chosen
Scenario: Address inherits postcode from its street unless it has a postcode
Given the grid with origin DE
| 10 | | | | | 11 |
| | | | | | |
| | 1 | | 2 | | |
And the places
| osm | class | type | housenr |
| N1 | place | house | 4 |
And the places
| osm | class | type | housenr | postcode |
| N2 | place | house | 5 | 99999 |
And the places
| osm | class | type | name | postcode | geometry |
| W1 | highway | residential | galoo | 12345 | 10,11 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
| N2 | W1 |
When geocoding "4 galoo"
Then result 0 contains
| object | display_name |
| N1 | 4, galoo, 12345, Deutschland |
When geocoding "5 galoo"
Then result 0 contains
| object | display_name |
| N2 | 5, galoo, 99999, Deutschland |
Scenario: Address without tags, closest street
Given the grid
| 10 | | | | | 11 |
| | 1 | 2 | | | |
| | | | 3 | 4 | |
| 20 | | | | | 21 |
And the places
| osm | class | type |
| N1 | place | house |
| N2 | place | house |
| N3 | place | house |
| N4 | place | house |
And the named places
| osm | class | type | geometry |
| W1 | highway | residential | 10,11 |
| W2 | highway | residential | 20,21 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
| N2 | W1 |
| N3 | W2 |
| N4 | W2 |
Scenario: Address without tags avoids unnamed streets
Given the grid
| 10 | | | | | 11 |
| | 1 | 2 | | | |
| | | | 3 | 4 | |
| 20 | | | | | 21 |
And the places
| osm | class | type |
| N1 | place | house |
| N2 | place | house |
| N3 | place | house |
| N4 | place | house |
And the places
| osm | class | type | geometry |
| W1 | highway | residential | 10,11 |
And the named places
| osm | class | type | geometry |
| W2 | highway | residential | 20,21 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
| N3 | W2 |
| N4 | W2 |
Scenario: addr:street tag parents to appropriately named street
Given the grid
| 10 | | | | | 11 |
| | 1 | 2 | | | |
| | | | 3 | 4 | |
| 20 | | | | | 21 |
And the places
| osm | class | type | street|
| N1 | place | house | south |
| N2 | place | house | north |
| N3 | place | house | south |
| N4 | place | house | north |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | north | 10,11 |
| W2 | highway | residential | south | 20,21 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W1 |
| N3 | W2 |
| N4 | W1 |
Scenario: addr:street tag parents to appropriately named street, locale names
Given the grid
| 10 | | | | | 11 |
| | 1 | 2 | | | |
| | | | 3 | 4 | |
| 20 | | | | | 21 |
And the places
| osm | class | type | street| addr+street:de |
| N1 | place | house | south | Süd |
| N2 | place | house | north | Nord |
| N3 | place | house | south | Süd |
| N4 | place | house | north | Nord |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | Nord | 10,11 |
| W2 | highway | residential | Süd | 20,21 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W1 |
| N3 | W2 |
| N4 | W1 |
Scenario: addr:street tag parents to appropriately named street with abbreviation
Given the grid
| 10 | | | | | 11 |
| | 1 | 2 | | | |
| | | | 3 | 4 | |
| 20 | | | | | 21 |
And the places
| osm | class | type | street |
| N1 | place | house | south st |
| N2 | place | house | north st |
| N3 | place | house | south st |
| N4 | place | house | north st |
And the places
| osm | class | type | name+name:en | geometry |
| W1 | highway | residential | north street | 10,11 |
| W2 | highway | residential | south street | 20,21 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W1 |
| N3 | W2 |
| N4 | W1 |
Scenario: addr:street tag parents to next named street
Given the grid
| 10 | | | | | 11 |
| | 1 | 2 | | | |
| | | | 3 | 4 | |
| 20 | | | | | 21 |
And the places
| osm | class | type | street |
| N1 | place | house | abcdef |
| N2 | place | house | abcdef |
| N3 | place | house | abcdef |
| N4 | place | house | abcdef |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | abcdef | 10,11 |
| W2 | highway | residential | abcdef | 20,21 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
| N2 | W1 |
| N3 | W2 |
| N4 | W2 |
Scenario: addr:street tag without appropriately named street
Given the grid
| 10 | | | | | 11 |
| | 1 | | | | |
| | | | 3 | | |
| 20 | | | | | 21 |
And the places
| osm | class | type | street |
| N1 | place | house | abcdef |
| N3 | place | house | abcdef |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | abcde | 10,11 |
| W2 | highway | residential | abcde | 20,21 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
| N3 | W2 |
Scenario: addr:place address
Given the grid
| 10 | | | |
| | 1 | | 2 |
| 11 | | | |
And the places
| osm | class | type | addr_place |
| N1 | place | house | myhamlet |
And the places
| osm | class | type | name | geometry |
| N2 | place | hamlet | myhamlet | 2 |
| W1 | highway | residential | myhamlet | 10,11 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | N2 |
Scenario: addr:street is preferred over addr:place
Given the grid
| 10 | | | |
| | | 1 | 2 |
| 11 | | | |
And the places
| osm | class | type | addr_place | street |
| N1 | place | house | myhamlet | mystreet|
And the places
| osm | class | type | name | geometry |
| N2 | place | hamlet | myhamlet | 2 |
| W1 | highway | residential | mystreet | 10,11 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
Scenario: Untagged address in simple associated street relation
Given the grid
| 10 | | | | | 11 |
| | 2 | | 3 | | |
| | | | | | |
| 12 | 1 | | | | |
And the places
| osm | class | type |
| N1 | place | house |
| N2 | place | house |
| N3 | place | house |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | foo | 10,11 |
| W2 | highway | service | bar | 10,12 |
And the relations
| id | members | tags+type |
| 1 | W1:street,N1,N2,N3 | associatedStreet |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
| N2 | W1 |
| N3 | W1 |
Scenario: Avoid unnamed streets in simple associated street relation
Given the grid
| 10 | | | | | 11 |
| | 2 | | 3 | | |
| | | | | | |
| 12 | 1 | | | | |
And the places
| osm | class | type |
| N1 | place | house |
| N2 | place | house |
| N3 | place | house |
And the places
| osm | class | type | geometry |
| W2 | highway | residential | 10,12 |
And the named places
| osm | class | type | geometry |
| W1 | highway | residential | 10,11 |
And the relations
| id | members | tags+type |
| 1 | N1,N2,N3,W2:street,W1:street | associatedStreet |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
| N2 | W1 |
| N3 | W1 |
Scenario: Associated street relation overrides addr:street
Given the grid
| 10 | | | | 11 |
| | | | | |
| | | 1 | | |
| | 20 | | 21 | |
And the places
| osm | class | type | street |
| N1 | place | house | bar |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | foo | 10,11 |
| W2 | highway | residential | bar | 20,21 |
And the relations
| id | members | tags+type |
| 1 | W1:street,N1 | associatedStreet |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
Scenario: Building without tags, closest street from center point
Given the grid
| 10 | | | | 11 |
| | | 1 | 2 | |
| 12 | | 4 | 3 | |
And the named places
| osm | class | type | geometry |
| W1 | building | yes | (1,2,3,4,1) |
| W2 | highway | primary | 10,11 |
| W3 | highway | residential | 10,12 |
When importing
Then placex contains
| object | parent_place_id |
| W1 | W2 |
Scenario: Building with addr:street tags
Given the grid
| 10 | | | | 11 |
| | | 1 | 2 | |
| 12 | | 4 | 3 | |
And the named places
| osm | class | type | street | geometry |
| W1 | building | yes | foo | (1,2,3,4,1) |
And the places
| osm | class | type | name | geometry |
| W2 | highway | primary | bar | 10,11 |
| W3 | highway | residential | foo | 10,12 |
When importing
Then placex contains
| object | parent_place_id |
| W1 | W3 |
Scenario: Building with addr:place tags
Given the grid
| 10 | | | | |
| | 1 | 2 | | 9 |
| 11 | 4 | 3 | | |
And the places
| osm | class | type | name | geometry |
| N9 | place | village | bar | 9 |
| W2 | highway | primary | bar | 10,11 |
And the named places
| osm | class | type | addr_place | geometry |
| W1 | building | yes | bar | (1,2,3,4,1) |
When importing
Then placex contains
| object | parent_place_id |
| W1 | N9 |
Scenario: Building in associated street relation
Given the grid
| 10 | | | | 11 |
| | | 1 | 2 | |
| 12 | | 4 | 3 | |
And the named places
| osm | class | type | geometry |
| W1 | building | yes | (1,2,3,4,1) |
And the places
| osm | class | type | name | geometry |
| W2 | highway | primary | bar | 10,11 |
| W3 | highway | residential | foo | 10,12 |
And the relations
| id | members | tags+type |
| 1 | W1:house,W3:street | associatedStreet |
When importing
Then placex contains
| object | parent_place_id |
| W1 | W3 |
Scenario: Building in associated street relation overrides addr:street
Given the grid
| 10 | | | | 11 |
| | | 1 | 2 | |
| 12 | | 4 | 3 | |
And the named places
| osm | class | type | street | geometry |
| W1 | building | yes | foo | (1,2,3,4,1) |
And the places
| osm | class | type | name | geometry |
| W2 | highway | primary | bar | 10,11 |
| W3 | highway | residential | foo | 10,12 |
And the relations
| id | members | tags+type |
| 1 | W1:house,W2:street | associatedStreet |
When importing
Then placex contains
| object | parent_place_id |
| W1 | W2 |
Scenario: Wrong member in associated street relation is ignored
Given the grid
| 10 | | | | | | | 11 |
| | 1 | | 3 | 4 | | | |
| | | | 6 | 5 | | | |
And the named places
| osm | class | type | geometry |
| N1 | place | house | 11 |
And the named places
| osm | class | type | street | geometry |
| W1 | building | yes | foo | (3,4,5,6,3) |
And the places
| osm | class | type | name | geometry |
| W3 | highway | residential | foo | 10,11 |
And the relations
| id | members | tags+type |
| 1 | N1:house,W1:street,W3:street | associatedStreet |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W3 |
Scenario: street member in associatedStreet relation can be a relation
Given the grid
| 1 | | | 2 |
| 3 | | | 4 |
| | | | |
| | 9 | | |
| 5 | | | 6 |
And the places
| osm | class | type | housenr | geometry |
| N9 | place | house | 34 | 9 |
And the named places
| osm | class | type | name | geometry |
| R14 | highway | pedestrian | Right St | (1,2,4,3,1) |
| W14 | highway | pedestrian | Left St | 5,6 |
And the relations
| id | members | tags+type |
| 1 | N9:house,R14:street | associatedStreet |
When importing
Then placex contains
| object | parent_place_id |
| N9 | R14 |
Scenario: Choose closest street in associatedStreet relation
Given the grid
| 1 | | | | 3 |
| 10 | | 11 | | 12 |
And the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 1 | 1 |
| N3 | place | house | 3 | 3 |
And the named places
| osm | class | type | geometry |
| W100 | highway | residential | 10,11 |
| W101 | highway | residential | 11,12 |
And the relations
| id | members | tags+type |
| 1 | N1:house,N3:house,W100:street,W101:street | associatedStreet |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W100 |
| N3 | W101 |
Scenario: POIs in building inherit address
Given the grid
| 10 | | | | | | 11 |
| | | 5 | 2 | 6 | | |
| | | 3 | 1 | | | |
| 12 | | 8 | | 7 | | |
And the named places
| osm | class | type |
| N1 | amenity | bank |
| N2 | shop | bakery |
| N3 | shop | supermarket|
And the places
| osm | class | type | street | housenr | geometry |
| W1 | building | yes | foo | 3 | (5,6,7,8,5) |
And the places
| osm | class | type | name | geometry |
| W2 | highway | primary | bar | 10,11 |
| W3 | highway | residential | foo | 10,12 |
When importing
Then placex contains
| object | parent_place_id | housenumber |
| W1 | W3 | 3 |
| N1 | W3 | 3 |
| N2 | W3 | 3 |
| N3 | W3 | 3 |
When geocoding "3, foo"
Then the result set contains
| address+house_number |
| 3 |
Scenario: POIs don't inherit from streets
Given the grid
| 10 | | | | 11 |
| | 5 | 1 | 6 | |
| | 8 | | 7 | |
And the named places
| osm | class | type |
| N1 | amenity | bank |
And the places
| osm | class | type | name | street | housenr | geometry |
| W1 | highway | path | bar | foo | 3 | (5,6,7,8,5) |
And the places
| osm | class | type | name | geometry |
| W3 | highway | residential | foo | 10,11 |
When importing
Then placex contains
| object | parent_place_id | housenumber |
| N1 | W1 | None |
Scenario: POIs with own address do not inherit building address
Given the grid
| 10 | | | | | | 11 |
| | | 6 | 2 | 7 | | |
| | | 3 | 1 | | 5 | 4 |
| 12 | | 9 | | 8 | | |
And the named places
| osm | class | type | street |
| N1 | amenity | bank | bar |
And the named places
| osm | class | type | housenr |
| N2 | shop | bakery | 4 |
And the named places
| osm | class | type | addr_place |
| N3 | shop | supermarket| nowhere |
And the places
| osm | class | type | name |
| N4 | place | isolated_dwelling | theplace |
| N5 | place | isolated_dwelling | nowhere |
And the places
| osm | class | type | addr_place | housenr | geometry |
| W1 | building | yes | theplace | 3 | (6,7,8,9,6) |
And the places
| osm | class | type | name | geometry |
| W2 | highway | primary | bar | 10,11 |
| W3 | highway | residential | foo | 10,12 |
When importing
Then placex contains
| object | parent_place_id | housenumber |
| W1 | N4 | 3 |
| N1 | W2 | None |
| N2 | W2 | 4 |
| N3 | N5 | None |
Scenario: POIs parent a road if they are attached to it
Given the grid
| | 10 | |
| 20 | 1 | 21 |
| | 11 | |
And the named places
| osm | class | type |
| N1 | highway | bus_stop |
And the places
| osm | class | type | name | geometry |
| W1 | highway | secondary | North St | 10,11 |
| W2 | highway | unclassified | South St | 20,1,21 |
And the ways
| id | nodes |
| 1 | 10,11 |
| 2 | 20,1,21 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
Scenario: POIs do not parent non-roads they are attached to
Given the grid
| 10 | | 1 | | 11 | | 30 |
| 14 | | | | 15 | | |
| 13 | | 2 | | 12 | | 31 |
And the named places
| osm | class | type | street |
| N1 | highway | bus_stop | North St |
| N2 | highway | bus_stop | South St |
And the places
| osm | class | type | name | geometry |
| W1 | landuse | residential | North St | (14,15,12,2,13,14) |
| W2 | waterway| river | South St | 10,1,11 |
| W3 | highway | residential | foo | 30,31 |
And the ways
| id | nodes |
| 1 | 10,11,12,2,13,10 |
| 2 | 10,1,11 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W3 |
| N2 | W3 |
Scenario: POIs on building outlines inherit associated street relation
Given the grid
| 10 | | | | 11 |
| | 5 | 1 | 6 | |
| 12 | 8 | | 7 | |
And the named places
| osm | class | type | geometry |
| N1 | place | house | 1 |
| W1 | building | yes | (5,1,6,7,8,5)|
And the places
| osm | class | type | name | geometry |
| W2 | highway | primary | bar | 10,11 |
| W3 | highway | residential | foo | 10,12 |
And the relations
| id | members | tags+type |
| 1 | W1:house,W3:street | associatedStreet |
And the ways
| id | nodes |
| 1 | 5,1,6,7,8,5 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W3 |
# github #1056
Scenario: Full names should be preferably matched for nearest road
Given the grid
| 1 | | 2 | 5 |
| | | | |
| 3 | | | 4 |
| | 10| | |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Via Cavassico superiore | 1, 2 |
| W3 | highway | residential | Via Cavassico superiore | 2, 5 |
| W2 | highway | primary | Via Frazione Cavassico | 3, 4 |
And the named places
| osm | class | type | addr+street |
| N10 | shop | yes | Via Cavassico superiore |
When importing
Then placex contains
| object | parent_place_id |
| N10 | W1 |
Scenario: place=square may be parented via addr:place
Given the grid
| | | 9 | | |
| | 5 | | 6 | |
| | 8 | | 7 | |
And the places
| osm | class | type | name+name | geometry |
| W2 | place | square | Foo pl | (5, 6, 7, 8, 5) |
And the places
| osm | class | type | name+name | housenr | addr_place | geometry |
| N10 | shop | grocery | le shop | 5 | Foo pl | 9 |
When importing
Then placex contains
| object | rank_address |
| W2 | 25 |
Then placex contains
| object | parent_place_id |
| N10 | W2 |

View File

@@ -0,0 +1,193 @@
Feature: Import into placex
Tests that data in placex is completed correctly.
Scenario: No country code tag is available
Given the named places
| osm | class | type | geometry |
| N1 | highway | primary | country:us |
When importing
Then placex contains
| object | address | country_code |
| N1 | - | us |
Scenario: Location overwrites country code tag
Given the named places
| osm | class | type | country | geometry |
| N1 | highway | primary | de | country:us |
When importing
Then placex contains
| object | addr+country | country_code |
| N1 | de | us |
Scenario: Country code tag overwrites location for countries
Given the named places
| osm | class | type | admin | country | geometry |
| R1 | boundary | administrative | 2 | de | (-100 40, -101 40, -101 41, -100 41, -100 40) |
When importing
Then placex contains
| object | rank_search| addr+country | country_code |
| R1 | 4 | de | de |
Scenario: Illegal country code tag for countries is ignored
Given the named places
| osm | class | type | admin | country | geometry |
| R1 | boundary | administrative | 2 | xx | (-100 40, -101 40, -101 41, -100 41, -100 40) |
When importing
Then placex contains
| object | addr+country | country_code |
| R1 | xx | us |
Scenario: admin level is copied over
Given the named places
| osm | class | type | admin |
| N1 | place | state | 3 |
When importing
Then placex contains
| object | admin_level |
| N1 | 3 |
Scenario: postcode node without postcode is dropped
Given the places
| osm | class | type | name+ref |
| N1 | place | postcode | 12334 |
When importing
Then placex has no entry for N1
Scenario: postcode boundary without postcode is dropped
Given the 0.01 grid
| 1 | 2 |
| 3 | |
Given the places
| osm | class | type | name+ref | geometry |
| R1 | boundary | postal_code | 554476 | (1,2,3,1) |
When importing
Then placex has no entry for R1
Scenario: search and address ranks for boundaries are correctly assigned
Given the named places
| osm | class | type |
| N1 | boundary | administrative |
And the named places
| osm | class | type | geometry |
| W10 | boundary | administrative | 10 10, 11 11 |
And the named places
| osm | class | type | admin | geometry |
| R20 | boundary | administrative | 2 | (1 1, 2 2, 1 2, 1 1) |
| R21 | boundary | administrative | 32 | (3 3, 4 4, 3 4, 3 3) |
| R22 | boundary | nature_park | 6 | (0 0, 1 0, 0 1, 0 0) |
| R23 | boundary | natural_reserve| 10 | (0 0, 1 1, 1 0, 0 0) |
And the named places
| osm | class | type | geometry |
| R40 | place | country | (1 1, 2 2, 1 2, 1 1) |
| R41 | place | state | (3 3, 4 4, 3 4, 3 3) |
When importing
Then placex has no entry for N1
And placex has no entry for W10
And placex contains
| object | rank_search | rank_address |
| R20 | 4 | 4 |
| R21 | 25 | 0 |
| R22 | 25 | 0 |
| R23 | 25 | 0 |
| R40 | 4 | 0 |
| R41 | 8 | 0 |
Scenario: search and address ranks for highways correctly assigned
Given the grid
| 10 | 1 | 11 | | 12 | | 13 | | 14 | | 15 | | 16 |
And the places
| osm | class | type |
| N1 | highway | bus_stop |
And the places
| osm | class | type | geometry |
| W1 | highway | primary | 10,11 |
| W2 | highway | secondary | 11,12 |
| W3 | highway | tertiary | 12,13 |
| W4 | highway | residential | 13,14 |
| W5 | highway | unclassified | 14,15 |
| W6 | highway | something | 15,16 |
When importing
Then placex contains
| object | rank_search | rank_address |
| N1 | 30 | 30 |
| W1 | 26 | 26 |
| W2 | 26 | 26 |
| W3 | 26 | 26 |
| W4 | 26 | 26 |
| W5 | 26 | 26 |
| W6 | 30 | 30 |
Scenario: rank and inclusion of landuses
Given the 0.4 grid
| 1 | 2 | | | | | | 5 |
| 4 | 3 | | | | | | 6 |
Given the named places
| osm | class | type |
| N2 | landuse | residential |
And the named places
| osm | class | type | geometry |
| W2 | landuse | residential | 1,2,5 |
| W4 | landuse | residential | (1,4,3,1) |
| R2 | landuse | residential | (1,2,3,4,1) |
| R3 | landuse | forrest | (1,5,6,4,1) |
When importing
Then placex contains
| object | rank_search | rank_address |
| N2 | 30 | 30 |
| W2 | 30 | 30 |
| W4 | 22 | 22 |
| R2 | 22 | 22 |
| R3 | 22 | 0 |
Scenario: rank and inclusion of naturals
Given the 0.4 grid
| 1 | 2 | | | | | | 5 |
| 4 | 3 | | | | | | 6 |
Given the named places
| osm | class | type |
| N2 | natural | peak |
| N4 | natural | volcano |
| N5 | natural | foobar |
And the named places
| osm | class | type | geometry |
| W2 | natural | mountain_range | 1,2,5 |
| W3 | natural | foobar | 2,3 |
| R3 | natural | volcano | (1,2,4,1) |
| R4 | natural | foobar | (1,2,3,4,1) |
| R5 | natural | sea | (1,2,5,6,3,4,1) |
| R6 | natural | sea | (2,3,4,2) |
When importing
Then placex contains
| object | rank_search | rank_address |
| N2 | 18 | 0 |
| N4 | 18 | 0 |
| N5 | 22 | 0 |
| W2 | 18 | 0 |
| R3 | 18 | 0 |
| R4 | 22 | 0 |
| R5 | 4 | 0 |
| R6 | 4 | 0 |
| W3 | 22 | 0 |
Scenario: boundary ways for countries and states are ignored
Given the 0.3 grid
| 1 | 2 |
| 4 | 3 |
Given the named places
| osm | class | type | admin | geometry |
| W4 | boundary | administrative | 2 | (1,2,3,4,1) |
| R4 | boundary | administrative | 2 | (1,2,3,4,1) |
| W5 | boundary | administrative | 3 | (1,2,3,4,1) |
| R5 | boundary | administrative | 3 | (1,2,3,4,1) |
| W6 | boundary | administrative | 4 | (1,2,3,4,1) |
| R6 | boundary | administrative | 4 | (1,2,3,4,1) |
| W7 | boundary | administrative | 5 | (1,2,3,4,1) |
| R7 | boundary | administrative | 5 | (1,2,3,4,1) |
When importing
Then placex contains exactly
| object |
| R4 |
| R5 |
| R6 |
| W7 |
| R7 |

View File

@@ -0,0 +1,208 @@
Feature: Import of postcodes
Tests for postcode estimation
Scenario: Postcodes on the object are preferred over those on the address
Given the grid with origin FR
| 1 | | | | 4 | | 6 | | 8 |
| | 10 | | 11 | | | | | |
| | | 22 | | | | | | |
| 2 | | | | 3 | | 5 | | 7 |
And the named places
| osm | class | type | admin | addr+postcode | geometry |
| R1 | boundary | administrative | 6 | 10000 | (1,8,7,2,1) |
| R34 | boundary | administrative | 8 | 11000 | (1,6,5,2,1) |
| R4 | boundary | administrative | 10 | 11200 | (1,4,3,2,1) |
And the named places
| osm | class | type | addr+postcode | geometry |
| W93 | highway | residential | 11250 | 10,11 |
| N22 | building | yes | 11254 | 22 |
When importing
Then placex contains
| object | postcode |
| N22 | 11254 |
| W93 | 11250 |
| R4 | 11200 |
| R34 | 11000 |
| R1 | 10000 |
Scenario: Postcodes from a road are inherited by an attached building
Given the grid with origin DE
| 10 | | | | 11 |
| | 1 | 2 | | |
| | 4 | 3 | | |
And the named places
| osm | class | type | addr+postcode | geometry |
| W93 | highway | residential | 86034 | 10,11 |
And the named places
| osm | class | type | geometry |
| W22 | building | yes | (1,2,3,4,1) |
When importing
Then placex contains
| object | postcode | parent_place_id |
| W22 | 86034 | W93 |
Scenario: Postcodes from the lowest admin area are inherited by ways
Given the grid with origin FR
| 1 | | | | 4 | | 6 | | 8 |
| | 10 | | 11 | | | | | |
| 2 | | | | 3 | | 5 | | 7 |
And the named places
| osm | class | type | admin | addr+postcode | geometry |
| R1 | boundary | administrative | 6 | 10000 | (1,8,7,2,1) |
| R34 | boundary | administrative | 8 | 11000 | (1,6,5,2,1) |
| R4 | boundary | administrative | 10 | 11200 | (1,4,3,2,1) |
And the named places
| osm | class | type | geometry |
| W93 | highway | residential | 10,11 |
When importing
Then placex contains
| object | postcode |
| W93 | 11200 |
Scenario: Postcodes from the lowest admin area with postcode are inherited by ways
Given the grid with origin FR
| 1 | | | | 4 | | 6 | | 8 |
| | 10 | | 11 | | | | | |
| 2 | | | | 3 | | 5 | | 7 |
And the named places
| osm | class | type | admin | addr+postcode | geometry |
| R1 | boundary | administrative | 6 | 10000 | (1,8,7,2,1) |
| R34 | boundary | administrative | 8 | 11000 | (1,6,5,2,1) |
And the named places
| osm | class | type | admin | geometry |
| R4 | boundary | administrative | 10 | (1,4,3,2,1) |
And the named places
| osm | class | type | geometry |
| W93 | highway | residential | 10,11 |
When importing
Then placex contains
| object | postcode | parent_place_id |
| W93 | 11000 | R4 |
Scenario: Postcodes from the lowest admin area are inherited by buildings
Given the grid with origin FR
| 1 | | | | 4 | | 6 | | 8 |
| | 10 | | 11 | | | | | |
| | 13 | | 12 | | | | | |
| 2 | | | | 3 | | 5 | | 7 |
And the named places
| osm | class | type | admin | addr+postcode | geometry |
| R1 | boundary | administrative | 6 | 10000 | (1,8,7,2,1) |
| R34 | boundary | administrative | 8 | 11000 | (1,6,5,2,1) |
| R4 | boundary | administrative | 10 | 11200 | (1,4,3,2,1) |
And the named places
| osm | class | type | geometry |
| W22 | building | yes | (10,11,12,13,10) |
When importing
Then placex contains
| object | postcode |
| W22 | 11200 |
Scenario: Roads get postcodes from nearby named buildings without other info
Given the grid with origin US
| 10 | | | | 11 |
| | 1 | 2 | | |
| | 4 | 3 | | |
And the named places
| osm | class | type | geometry |
| W93 | highway | residential | 10,11 |
And the named places
| osm | class | type | addr+postcode | geometry |
| W22 | building | yes | 45023 | (1,2,3,4,1) |
When importing
Then placex contains
| object | postcode |
| W93 | 45023 |
Scenario: Road areas get postcodes from nearby named buildings without other info
Given the grid with origin US
| 10 | | | | 11 |
| 13 | | | | 12 |
| | 1 | 2 | | |
| | 4 | 3 | | |
And the named places
| osm | class | type | geometry |
| W93 | highway | pedestriant | (10,11,12,13,10) |
And the named places
| osm | class | type | addr+postcode | geometry |
| W22 | building | yes | 45023 | (1,2,3,4,1) |
When importing
Then placex contains
| object | postcode |
| W93 | 45023 |
Scenario: Roads get postcodes from nearby unnamed buildings without other info
Given the grid with origin US
| 10 | | | | 11 |
| | 1 | 2 | | |
| | 4 | 3 | | |
And the named places
| osm | class | type | geometry |
| W93 | highway | residential | 10,11 |
And the places
| osm | class | type | addr+postcode | geometry |
| W22 | place | postcode | 45023 | (1,2,3,4,1) |
When importing
Then placex contains
| object | postcode |
| W93 | 45023 |
Scenario: Postcodes from admin boundaries are preferred over estimated postcodes
Given the grid with origin FR
| 1 | | | | 4 | | 6 | | 8 |
| | 10 | | 11 | | | | | |
| | | 22 | | | | | | |
| 2 | | | | 3 | | 5 | | 7 |
And the named places
| osm | class | type | admin | addr+postcode | geometry |
| R1 | boundary | administrative | 6 | 10000 | (1,8,7,2,1) |
| R34 | boundary | administrative | 8 | 11000 | (1,6,5,2,1) |
| R4 | boundary | administrative | 10 | 11200 | (1,4,3,2,1) |
And the named places
| osm | class | type | geometry |
| W93 | highway | residential | 10,1 |
And the named places
| osm | class | type | addr+postcode |
| N22 | building | yes | 45023 |
When importing
Then placex contains
| object | postcode |
| W93 | 11200 |
Scenario: Postcodes are added to the postcode
Given the places
| osm | class | type | addr+postcode | addr+housenumber | geometry |
| N34 | place | house | 01982 | 111 |country:de |
When importing
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt |
| de | 01982 | country:de |
@skip
Scenario: search and address ranks for GB post codes correctly assigned
Given the places
| osm | class | type | postcode | geometry |
| N1 | place | postcode | E45 2CD | country:gb |
| N2 | place | postcode | E45 2 | country:gb |
| N3 | place | postcode | Y45 | country:gb |
When importing
Then location_postcode contains exactly
| postcode | country_code | rank_search | rank_address |
| E45 2CD | gb | 25 | 5 |
| E45 2 | gb | 23 | 5 |
| Y45 | gb | 21 | 5 |
Scenario: Postcodes outside all countries are not added to the postcode table
Given the places
| osm | class | type | addr+postcode | addr+housenumber | addr+place | geometry |
| N34 | place | house | 01982 | 111 | Null Island | 0 0.00001 |
And the places
| osm | class | type | name | geometry |
| N1 | place | hamlet | Null Island | 0 0 |
When importing
Then location_postcode contains exactly
| place_id |
When geocoding "111, 01982 Null Island"
Then the result set contains
| object | display_name |
| N34 | 111, Null Island, 01982 |

View File

@@ -0,0 +1,295 @@
Feature: Rank assignment
Tests for assignment of search and address ranks.
Scenario: Ranks for place nodes are assigned according to their type
Given the named places
| osm | class | type | geometry |
| N1 | foo | bar | 0 0 |
| N11 | place | Continent | 0 0 |
| N12 | place | continent | 0 0 |
| N13 | place | sea | 0 0 |
| N14 | place | country | 0 0 |
| N15 | place | state | 0 0 |
| N16 | place | region | 0 0 |
| N17 | place | county | 0 0 |
| N18 | place | city | 0 0 |
| N19 | place | island | 0 0 |
| N36 | place | house | 0 0 |
And the named places
| osm | class | type | extra+capital | geometry |
| N101 | place | city | yes | 0 0 |
When importing
Then placex contains
| object | rank_search | rank_address |
| N1 | 30 | 30 |
| N11 | 22 | 0 |
| N12 | 2 | 0 |
| N13 | 2 | 0 |
| N14 | 4 | 0 |
| N15 | 8 | 0 |
| N16 | 18 | 0 |
| N17 | 12 | 12 |
| N18 | 16 | 16 |
| N19 | 17 | 0 |
| N101 | 15 | 16 |
| N36 | 30 | 30 |
Scenario: Ranks for boundaries are assigned according to admin level
Given the named places
| osm | class | type | admin | geometry |
| R20 | boundary | administrative | 2 | (1 1, 2 2, 1 2, 1 1) |
| R21 | boundary | administrative | 32 | (3 3, 4 4, 3 4, 3 3) |
| R22 | boundary | administrative | 6 | (0 0, 1 0, 0 1, 0 0) |
| R23 | boundary | administrative | 10 | (0 0, 1 1, 1 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R20 | 4 | 4 |
| R21 | 25 | 0 |
| R22 | 12 | 12 |
| R23 | 20 | 20 |
Scenario: Ranks for addressable boundaries with place assignment go with place address ranks if available
Given the named places
| osm | class | type | admin | extra+place | geometry |
| R20 | boundary | administrative | 3 | state | (1 1, 2 2, 1 2, 1 1) |
| R21 | boundary | administrative | 32 | suburb | (3 3, 4 4, 3 4, 3 3) |
| R22 | boundary | administrative | 6 | town | (0 0, 1 0, 0 1, 0 0) |
| R23 | boundary | administrative | 10 | village | (0 0, 1 1, 1 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R20 | 6 | 6 |
| R21 | 25 | 0 |
| R22 | 12 | 16 |
| R23 | 20 | 16 |
Scenario: Place address ranks cannot overtake a parent address rank
Given the named places
| osm | class | type | admin | extra+place | geometry |
| R20 | boundary | administrative | 8 | town | (0 0, 0 2, 2 2, 2 0, 0 0) |
| R21 | boundary | administrative | 9 | municipality | (0 0, 0 1, 1 1, 1 0, 0 0) |
| R22 | boundary | administrative | 9 | suburb | (0 0, 0 1, 1 1, 1 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R20 | 16 | 16 |
| R21 | 18 | 18 |
| R22 | 18 | 20 |
Then place_addressline contains
| object | address | cached_rank_address |
| R21 | R20 | 16 |
| R22 | R20 | 16 |
Scenario: Admin levels cannot overtake each other due to place address ranks
Given the named places
| osm | class | type | admin | extra+place | geometry |
| R20 | boundary | administrative | 6 | town | (0 0, 0 2, 2 2, 2 0, 0 0) |
| R21 | boundary | administrative | 8 | | (0 0, 0 1, 1 1, 1 0, 0 0) |
| R22 | boundary | administrative | 8 | suburb | (0 0, 0 1, 1 1, 1 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R20 | 12 | 16 |
| R21 | 16 | 18 |
| R22 | 16 | 20 |
Then place_addressline contains
| object | address | cached_rank_address |
| R21 | R20 | 16 |
| R22 | R20 | 16 |
Scenario: Admin levels cannot overtake each other due to place address ranks even when slightly misaligned
Given the named places
| osm | class | type | admin | extra+place | geometry |
| R20 | boundary | administrative | 6 | town | (0 0, 0 2, 2 2, 2 0, 0 0) |
| R21 | boundary | administrative | 8 | | (0 0, -0.0001 1, 1 1, 1 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R20 | 12 | 16 |
| R21 | 16 | 18 |
Then place_addressline contains
| object | address | cached_rank_address |
| R21 | R20 | 16 |
Scenario: Admin levels must not be larger than 25
Given the named places
| osm | class | type | admin | extra+place | geometry |
| R20 | boundary | administrative | 6 | neighbourhood | (0 0, 0 2, 2 2, 2 0, 0 0) |
| R21 | boundary | administrative | 7 | | (0 0, 0 1, 1 1, 1 0, 0 0) |
| R22 | boundary | administrative | 8 | | (0 0, 0 0.5, 0.5 0.5, 0.5 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R20 | 12 | 22 |
| R21 | 14 | 24 |
| R22 | 16 | 25 |
Scenario: admin levels contained in a place area must not overtake address ranks
Given the named places
| osm | class | type | admin | geometry |
| R10 | place | city | 15 | (0 0, 0 2, 2 0, 0 0) |
| R20 | boundary | administrative | 6 | (0 0, 0 1, 1 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R10 | 16 | 16 |
| R20 | 12 | 18 |
Scenario: admin levels overlapping a place area are not demoted
Given the named places
| osm | class | type | admin | geometry |
| R10 | place | city | 15 | (0 0, 0 2, 2 0, 0 0) |
| R20 | boundary | administrative | 6 | (-1 0, 0 1, 1 0, -1 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R10 | 16 | 16 |
| R20 | 12 | 12 |
Scenario: admin levels with equal area as a place area are not demoted
Given the named places
| osm | class | type | admin | geometry |
| R10 | place | city | 15 | (0 0, 0 2, 2 0, 0 0) |
| R20 | boundary | administrative | 6 | (0 0, 0 2, 2 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R10 | 16 | 16 |
| R20 | 12 | 12 |
Scenario: adjacent admin_levels are considered the same object when they have the same wikidata
Given the named places
| osm | class | type | admin | extra+wikidata | geometry |
| N20 | place | square | 15 | Q123 | 0.1 0.1 |
| R23 | boundary | administrative | 10 | Q444 | (0 0, 0 1, 1 1, 1 0, 0 0) |
| R21 | boundary | administrative | 9 | Q444 | (0 0, 0 1, 1 1, 1 0, 0 0) |
| R22 | boundary | administrative | 8 | Q444 | (0 0, 0 1, 1 1, 1 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R23 | 20 | 0 |
| R21 | 18 | 0 |
| R22 | 16 | 16 |
Then place_addressline contains exactly
| object | address | cached_rank_address |
| N20 | R22 | 16 |
Scenario: adjacent admin_levels are considered different objects when they have different wikidata
Given the named places
| osm | class | type | admin | extra+wikidata | geometry |
| N20 | place | square | 15 | Q123 | 0.1 0.1 |
| R21 | boundary | administrative | 9 | Q4441 | (0 0, 0 1, 1 1, 1 0, 0 0) |
| R22 | boundary | administrative | 8 | Q444 | (0 0, 0 1, 1 1, 1 0, 0 0) |
When importing
Then placex contains
| object | rank_search | rank_address |
| R21 | 18 | 18 |
| R22 | 16 | 16 |
Then place_addressline contains
| object | address | cached_rank_address |
| N20 | R22 | 16 |
| N20 | R21 | 18 |
Scenario: Mixes of admin boundaries and place areas I
Given the grid
| 1 | | 10 | | | 2 |
| | 9 | | | | |
| 20| | 21 | | | |
| 4 | | 11 | | | 3 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 5 | Greater London | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | Kensington | (1,10,11,4,1) |
And the places
| osm | class | type | name | geometry |
| R10 | place | city | London | (1,2,3,4,1) |
| N9 | place | town | Fulham | 9 |
| W1 | highway | residential | Lots Grove | 20,21 |
When importing
Then placex contains
| object | rank_search | rank_address |
| R1 | 10 | 10 |
| R10 | 16 | 16 |
| R2 | 16 | 18 |
| N9 | 18 | 18 |
And place_addressline contains
| object | address | isaddress | cached_rank_address |
| W1 | R1 | True | 10 |
| W1 | R10 | True | 16 |
| W1 | R2 | True | 18 |
| W1 | N9 | False | 18 |
Scenario: Mixes of admin boundaries and place areas II
Given the grid
| 1 | | 10 | | 5 | 2 |
| | 9 | | | | |
| 20| | 21 | | | |
| 4 | | 11 | | 6 | 3 |
And the places
| osm | class | type | admin | name | geometry |
| R1 | boundary | administrative | 5 | Greater London | (1,2,3,4,1) |
| R2 | boundary | administrative | 8 | London | (1,5,6,4,1) |
And the places
| osm | class | type | name | geometry |
| R10 | place | city | Westminster | (1,10,11,4,1) |
| N9 | place | town | Fulham | 9 |
| W1 | highway | residential | Lots Grove | 20,21 |
When importing
Then placex contains
| object | rank_search | rank_address |
| R1 | 10 | 10 |
| R2 | 16 | 16 |
| R10 | 16 | 18 |
| N9 | 18 | 18 |
And place_addressline contains
| object | address | isaddress | cached_rank_address |
| W1 | R1 | True | 10 |
| W1 | R10 | True | 18 |
| W1 | R2 | True | 16 |
| W1 | N9 | False | 18 |
Scenario: POI nodes with place tags
Given the places
| osm | class | type | name | extratags |
| N23 | amenity | playground | AB | "place": "city" |
| N23 | place | city | AB | "amenity": "playground" |
When importing
Then placex contains exactly
| object | rank_search | rank_address |
| N23:amenity | 30 | 30 |
| N23:place | 16 | 16 |
Scenario: Address rank 25 is only used for addr:place
Given the grid
| 10 | 33 | 34 | 11 |
Given the places
| osm | class | type | name |
| N10 | place | village | vil |
| N11 | place | farm | farm |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | RD | 33,11 |
And the places
| osm | class | type | name | addr+farm | geometry |
| W2 | highway | residential | RD2 | farm | 34,11 |
And the places
| osm | class | type | housenr |
| N33 | place | house | 23 |
And the places
| osm | class | type | housenr | addr+place |
| N34 | place | house | 23 | farm |
When importing
Then placex contains
| object | parent_place_id |
| N11 | N10 |
| N33 | W1 |
| N34 | N11 |
And place_addressline contains
| object | address |
| W1 | N10 |
| W2 | N10 |
| W2 | N11 |

View File

@@ -0,0 +1,389 @@
Feature: Creation of search terms
Tests that search_name table is filled correctly
Scenario: Semicolon-separated names appear as separate full names
Given the places
| osm | class | type | name+alt_name |
| N1 | place | city | New York; Big Apple |
| N2 | place | town | New York Big Apple |
When importing
And geocoding "New York Big Apple"
Then result 0 contains
| object |
| N2 |
Scenario: Comma-separated names appear as a single full name
Given the places
| osm | class | type | name+name |
| N1 | place | city | New York, Big Apple |
| N2 | place | town | New York Big Apple |
When importing
And geocoding "New York Big Apple"
Then result 0 contains
| object |
| N1 |
Scenario: Name parts before brackets appear as full names
Given the places
| osm | class | type | name+name |
| N1 | place | city | Halle (Saale) |
| N2 | place | town | Halle |
When importing
And geocoding "Halle"
Then result 0 contains
| object |
| N1 |
When geocoding "Halle (Saale)"
Then the result set contains
| object |
| N1 |
Scenario: Unknown addr: tags can be found for unnamed POIs
Given the grid
| | 1 | | |
| 10 | | | 11 |
And the places
| osm | class | type | housenr | addr+city |
| N1 | place | house | 23 | Walltown |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
When importing
When geocoding "23 Rose Street, Walltown"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
When geocoding "Walltown, Rose Street 23"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
When geocoding "Rose Street 23, Walltown"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
Scenario: Searching for unknown addr: tags also works for multiple words
Given the grid
| | 1 | | |
| 10 | | | 11 |
And the places
| osm | class | type | housenr | addr+city |
| N1 | place | house | 23 | Little Big Town |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
When importing
When geocoding "23 Rose Street, Little Big Town"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
When geocoding "Rose Street 23, Little Big Town"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
When geocoding "Little big Town, Rose Street 23"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
Scenario: Unnamed POI can be found when it has known addr: tags
Given the grid
| | 1 | | |
| 10 | | | 11 |
And the places
| osm | class | type | housenr | addr+city |
| N1 | place | house | 23 | Walltown |
And the places
| osm | class | type | name+name | addr+city | geometry |
| W1 | highway | residential | Rose Street | Walltown | 10,11 |
When importing
When geocoding "23 Rose Street, Walltown"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
Scenario: Unnamed POIs inherit parent name when unknown addr:place is present
Given the grid
| 100 | | | | | 101 |
| | | 1 | | | |
| 103 | 10 | | | 11 | 102 |
And the places
| osm | class | type | housenr | addr+place |
| N1 | place | house | 23 | Walltown |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
| R1 | place | city | Strange Town | (100,101,102,103,100) |
When importing
Then placex contains
| object | parent_place_id |
| N1 | R1 |
When geocoding "23 Rose Street"
Then all results contain
| object | display_name |
| W1 | Rose Street, Strange Town |
When geocoding "23 Walltown, Strange Town"
Then the result set contains
| object | display_name |
| N1 | 23, Walltown, Strange Town |
When geocoding "Walltown 23, Strange Town"
Then the result set contains
| object | display_name |
| N1 | 23, Walltown, Strange Town |
When geocoding "Strange Town, Walltown 23"
Then the result set contains
| object | display_name |
| N1 | 23, Walltown, Strange Town |
Scenario: Named POIs can be searched by housenumber when unknown addr:place is present
Given the grid
| 100 | | | | | 101 |
| | | 1 | | | |
| 103 | 10 | | | 11 | 102 |
And the places
| osm | class | type | name | housenr | addr+place |
| N1 | place | house | Blue house | 23 | Walltown |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
| R1 | place | city | Strange Town | (100,101,102,103,100) |
When importing
When geocoding "23 Walltown, Strange Town"
Then the result set contains
| object | display_name |
| N1 | Blue house, 23, Walltown, Strange Town |
When geocoding "Walltown 23, Strange Town"
Then the result set contains
| object | display_name |
| N1 | Blue house, 23, Walltown, Strange Town |
When geocoding "Strange Town, Walltown 23"
Then the result set contains
| object | display_name |
| N1 | Blue house, 23, Walltown, Strange Town |
When geocoding "Strange Town, Walltown 23, Blue house"
Then the result set contains
| object | display_name |
| N1 | Blue house, 23, Walltown, Strange Town |
When geocoding "Strange Town, Walltown, Blue house"
Then the result set contains
| object | display_name |
| N1 | Blue house, 23, Walltown, Strange Town |
Scenario: Named POIs can be found when unknown multi-word addr:place is present
Given the grid
| 100 | | | | | 101 |
| | | 1 | | | |
| 103 | 10 | | | 11 | 102 |
And the places
| osm | class | type | name | housenr | addr+place |
| N1 | place | house | Blue house | 23 | Moon sun |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
| R1 | place | city | Strange Town | (100,101,102,103,100) |
When importing
When geocoding "23 Moon Sun, Strange Town"
Then the result set contains
| object | display_name |
| N1 | Blue house, 23, Moon sun, Strange Town |
When geocoding "Blue house, Moon Sun, Strange Town"
Then the result set contains
| object | display_name |
| N1 | Blue house, 23, Moon sun, Strange Town |
Scenario: Unnamed POIs doesn't inherit parent name when addr:place is present only in parent address
Given the grid
| 100 | | | | | 101 |
| | | 1 | | | |
| 103 | 10 | | | 11 | 102 |
And the places
| osm | class | type | housenr | addr+place |
| N1 | place | house | 23 | Walltown |
And the places
| osm | class | type | name+name | addr+city | geometry |
| W1 | highway | residential | Rose Street | Walltown | 10,11 |
| R1 | place | suburb | Strange Town | Walltown | (100,101,102,103,100) |
When importing
When geocoding "23 Rose Street, Walltown"
Then all results contain
| object | display_name |
| W1 | Rose Street, Strange Town |
When geocoding "23 Walltown"
Then all results contain
| object | display_name |
| N1 | 23, Walltown, Strange Town |
Scenario: Unnamed POIs does inherit parent name when unknown addr:place and addr:street is present
Given the grid
| | 1 | | |
| 10 | | | 11 |
And the places
| osm | class | type | housenr | addr+place | addr+street |
| N1 | place | house | 23 | Walltown | Lily Street |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
When importing
When geocoding "23 Rose Street"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
When geocoding "23 Lily Street"
Then exactly 0 results are returned
Scenario: An unknown addr:street is ignored
Given the grid
| | 1 | | |
| 10 | | | 11 |
And the places
| osm | class | type | housenr | addr+street |
| N1 | place | house | 23 | Lily Street |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
When importing
When geocoding "23 Rose Street"
Then the result set contains
| object | display_name |
| N1 | 23, Rose Street |
When geocoding "23 Lily Street"
Then exactly 0 results are returned
Scenario: Named POIs can be found through unknown address tags
Given the grid
| | 1 | | |
| 10 | | | 11 |
And the places
| osm | class | type | name+name | housenr | addr+city |
| N1 | place | house | Green Moss | 26 | Walltown |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
When importing
When geocoding "Green Moss, Rose Street, Walltown"
Then the result set contains
| object | display_name |
| N1 | Green Moss, 26, Rose Street |
When geocoding "Green Moss, 26, Rose Street, Walltown"
Then the result set contains
| object | display_name |
| N1 | Green Moss, 26, Rose Street |
When geocoding "26, Rose Street, Walltown"
Then the result set contains
| object | display_name |
| N1 | Green Moss, 26, Rose Street |
When geocoding "Rose Street 26, Walltown"
Then the result set contains
| object | display_name |
| N1 | Green Moss, 26, Rose Street |
When geocoding "Walltown, Rose Street 26"
Then the result set contains
| object | display_name |
| N1 | Green Moss, 26, Rose Street |
Scenario: Named POI doesn't inherit parent name when addr:place is present only in parent address
Given the grid
| 100 | | | | | 101 |
| | | 1 | | | |
| 103 | 10 | | | 11 | 102 |
And the places
| osm | class | type | name+name | addr+place |
| N1 | place | house | Green Moss | Walltown |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | 10,11 |
| R1 | place | suburb | Strange Town | (100,101,102,103,100) |
When importing
When geocoding "Green Moss, Rose Street, Walltown"
Then exactly 0 results are returned
When geocoding "Green Moss, Walltown"
Then the result set contains
| object | display_name |
| N1 | Green Moss, Walltown, Strange Town |
Scenario: Named POIs inherit address from parent
Given the grid
| | 1 | | |
| 10 | | | 11 |
And the places
| osm | class | type | name | geometry |
| N1 | place | house | foo | 1 |
| W1 | highway | residential | the road | 10,11 |
When importing
When geocoding "foo, the road"
Then all results contain
| object |
| N1 |
Scenario: Some addr: tags are added to address
Given the grid
| | 2 | 3 | |
| 10 | | | 11 |
And the places
| osm | class | type | name |
| N2 | place | city | bonn |
| N3 | place | suburb | smalltown|
And the places
| osm | class | type | name | addr+city | addr+municipality | addr+suburb | geometry |
| W1 | highway | service | the end | bonn | New York | Smalltown | 10,11 |
When importing
When geocoding "the end, new york, bonn, smalltown"
Then all results contain
| object |
| W1 |
Scenario: A known addr:* tag is added even if the name is unknown
Given the grid
| 10 | | | | 11 |
And the places
| osm | class | type | name | addr+city | geometry |
| W1 | highway | residential | Road | Nandu | 10,11 |
When importing
And geocoding "Road, Nandu"
Then all results contain
| object |
| W1 |
Scenario: a linked place does not show up in search name
Given the 0.01 grid
| 10 | | 11 |
| | 2 | |
| 13 | | 12 |
Given the places
| osm | class | type | name | admin | geometry |
| R13 | boundary | administrative | Roma | 9 | (10,11,12,13,10) |
And the places
| osm | class | type | name |
| N2 | place | city | Cite |
And the relations
| id | members | tags+type |
| 13 | N2:label | boundary |
When importing
Then placex contains
| object | linked_place_id |
| N2 | R13 |
When geocoding "Cite"
Then all results contain
| object |
| R13 |
Scenario: a linked waterway does not show up in search name
Given the grid
| 1 | | 2 | | 3 |
And the places
| osm | class | type | name | geometry |
| W1 | waterway | river | Rhein | 1,2 |
| W2 | waterway | river | Rhein | 2,3 |
| R13 | waterway | river | Rhein | 1,2,3 |
And the relations
| id | members | tags+type |
| 13 | W1,W2:main_stream | waterway |
When importing
Then placex contains
| object | linked_place_id |
| W1 | R13 |
| W2 | R13 |
When geocoding "Rhein"
Then all results contain
| object |
| R13 |

View File

@@ -0,0 +1,320 @@
Feature: Searching of house numbers
Test for specialised treeatment of housenumbers
Background:
Given the grid
| 1 | | 2 | | 3 |
| | 9 | | | |
| | | | | 4 |
Scenario: A simple ascii digit housenumber is found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | 45 | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | North Road | 1,2,3 |
When importing
And geocoding "45, North Road"
Then the result set contains
| object |
| N1 |
When geocoding "North Road 45"
Then the result set contains
| object |
| N1 |
Scenario Outline: Numeral housenumbers in any script are found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <number> | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | North Road | 1,2,3 |
When importing
And geocoding "45, North Road"
Then the result set contains
| object |
| N1 |
When geocoding "North Road "
Then the result set contains
| object |
| N1 |
When geocoding "North Road 𑁪𑁫"
Then the result set contains
| object |
| N1 |
Examples:
| number |
| 45 |
| |
| 𑁪𑁫 |
Scenario Outline: Each housenumber in a list is found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <hnrs> | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | Multistr | 1,2,3 |
When importing
When geocoding "2 Multistr"
Then the result set contains
| object |
| N1 |
When geocoding "4 Multistr"
Then the result set contains
| object |
| N1 |
When geocoding "12 Multistr"
Then the result set contains
| object |
| N1 |
Examples:
| hnrs |
| 2;4;12 |
| 2,4,12 |
| 2, 4, 12 |
Scenario Outline: Housenumber - letter combinations are found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <hnr> | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | Multistr | 1,2,3 |
When importing
When geocoding "2A Multistr"
Then the result set contains
| object |
| N1 |
When geocoding "2 a Multistr"
Then the result set contains
| object |
| N1 |
When geocoding "2-A Multistr"
Then the result set contains
| object |
| N1 |
When geocoding "Multistr 2 A"
Then the result set contains
| object |
| N1 |
Examples:
| hnr |
| 2a |
| 2 A |
| 2-a |
| 2/A |
Scenario Outline: Number - Number combinations as a housenumber are found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <hnr> | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | Chester St | 1,2,3 |
When importing
When geocoding "34-10 Chester St"
Then the result set contains
| object |
| N1 |
When geocoding "34/10 Chester St"
Then the result set contains
| object |
| N1 |
When geocoding "34 10 Chester St"
Then the result set contains
| object |
| N1 |
When geocoding "3410 Chester St"
Then the result set contains
| object |
| W10 |
Examples:
| hnr |
| 34-10 |
| 34 10 |
| 34/10 |
Scenario Outline: a bis housenumber is found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <hnr> | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | Rue Paris | 1,2,3 |
When importing
When geocoding "Rue Paris 45bis"
Then the result set contains
| object |
| N1 |
When geocoding "Rue Paris 45 BIS"
Then the result set contains
| object |
| N1 |
When geocoding "Rue Paris 45BIS"
Then the result set contains
| object |
| N1 |
When geocoding "Rue Paris 45 bis"
Then the result set contains
| object |
| N1 |
Examples:
| hnr |
| 45bis |
| 45BIS |
| 45 BIS |
| 45 bis |
Scenario Outline: a ter housenumber is found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <hnr> | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | Rue du Berger | 1,2,3 |
When importing
When geocoding "Rue du Berger 45ter"
Then the result set contains
| object |
| N1 |
When geocoding "Rue du Berger 45 TER"
Then the result set contains
| object |
| N1 |
When geocoding "Rue du Berger 45TER"
Then the result set contains
| object |
| N1 |
When geocoding "Rue du Berger 45 ter"
Then the result set contains
| object |
| N1 |
Examples:
| hnr |
| 45ter |
| 45TER |
| 45 ter |
| 45 TER |
Scenario Outline: a number - letter - number combination housenumber is found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <hnr> | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | Herengracht | 1,2,3 |
When importing
When geocoding "501-H 1 Herengracht"
Then the result set contains
| object |
| N1 |
When geocoding "501H-1 Herengracht"
Then the result set contains
| object |
| N1 |
When geocoding "501H1 Herengracht"
Then the result set contains
| object |
| N1 |
When geocoding "501-H1 Herengracht"
Then the result set contains
| object |
| N1 |
Examples:
| hnr |
| 501 H1 |
| 501H 1 |
| 501/H/1 |
| 501h1 |
Scenario Outline: Russian housenumbers are found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <hnr> | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | Голубинская улица | 1,2,3 |
When importing
When geocoding "Голубинская улица 55к3"
Then the result set contains
| object |
| N1 |
When geocoding "Голубинская улица 55 k3"
Then the result set contains
| object |
| N1 |
When geocoding "Голубинская улица 55 к-3"
Then the result set contains
| object |
| N1 |
Examples:
| hnr |
| 55к3 |
| 55 к3 |
Scenario: A name mapped as a housenumber is found
Given the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | Warring | 9 |
And the places
| osm | class | type | name | geometry |
| W10 | highway | path | Chester St | 1,2,3 |
When importing
When geocoding "Chester St Warring"
Then the result set contains
| object |
| N1 |
Scenario: Interpolations are found according to their type
Given the grid
| 10 | | 11 |
| 100 | | 101 |
| 20 | | 21 |
And the places
| osm | class | type | name | geometry |
| W100 | highway | residential | Ringstr | 100, 101 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W10 | place | houses | even | 10, 11 |
| W20 | place | houses | odd | 20, 21 |
And the places
| osm | class | type | housenr | geometry |
| N10 | place | house | 10 | 10 |
| N11 | place | house | 20 | 11 |
| N20 | place | house | 11 | 20 |
| N21 | place | house | 21 | 21 |
And the ways
| id | nodes |
| 10 | 10, 11 |
| 20 | 20, 21 |
When importing
When geocoding "Ringstr 12"
Then the result set contains
| object |
| W10 |
When geocoding "Ringstr 13"
Then the result set contains
| object |
| W20 |

View File

@@ -0,0 +1,57 @@
Feature: Query of address interpolations
Tests that interpolated addresses can be queried correctly
Background:
Given the grid
| 1 | | 2 | | 3 |
| 10 | | 12 | | 13 |
| 7 | | 8 | | 9 |
Scenario: Find interpolations with single number
Given the places
| osm | class | type | name | geometry |
| W10 | highway | primary | Nickway | 10,12,13 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | odd | 1,3 |
And the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 1 | 1 |
| N3 | place | house | 5 | 3 |
And the ways
| id | nodes |
| 1 | 1,3 |
When importing
When reverse geocoding at node 2
Then the result contains
| display_name |
| 3, Nickway |
When geocoding "Nickway 3"
Then all results contain
| object | display_name |
| W1 | 3, Nickway |
Scenario: Find interpolations with multiple numbers
Given the places
| osm | class | type | name | geometry |
| W10 | highway | primary | Nickway | 10,12,13 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,3 |
And the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 2 | 1 |
| N3 | place | house | 18 | 3 |
And the ways
| id | nodes |
| 1 | 1,3 |
When importing
When reverse geocoding at node 2
Then the result contains
| display_name | centroid!wkt |
| 10, Nickway | 2 |
When geocoding "Nickway 10"
Then all results contain
| object | display_name | centroid!wkt |
| W1 | 10, Nickway | 2 |

View File

@@ -0,0 +1,28 @@
Feature: Searches in Japan
Test specifically for searches of Japanese addresses and in Japanese language.
Scenario: A block house-number is parented to the neighbourhood
Given the grid with origin JP
| 1 | | | | 2 |
| | 3 | | | |
| | | 9 | | |
| | | | 6 | |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | | 1,2 |
And the places
| osm | class | type | housenr | addr+block_number | addr+neighbourhood | geometry |
| N3 | amenity | restaurant | 2 | 6 | 2 | 3 |
And the places
| osm | class | type | name | geometry |
| N9 | place | neighbourhood | 2 | 9 |
And the places
| osm | class | type | name | geometry |
| N6 | place | quarter | | 6 |
When importing
Then placex contains
| object | parent_place_id |
| N3 | N9 |
When geocoding "2 6-2"
Then all results contain
| object |
| N3 |

View File

@@ -0,0 +1,63 @@
Feature: Searching linked places
Tests that information from linked places can be searched correctly
Scenario: Additional names from linked places are searchable
Given the 0.1 grid
| 10 | | 11 |
| | 2 | |
| 13 | | 12 |
Given the places
| osm | class | type | admin | name | geometry |
| R13 | boundary | administrative | 6 | Garbo | (10,11,12,13,10) |
Given the places
| osm | class | type | admin | name+name:it |
| N2 | place | hamlet | 15 | Vario |
And the relations
| id | members | tags+type |
| 13 | N2:label | boundary |
When importing
Then placex contains
| object | linked_place_id |
| N2 | R13 |
When geocoding "Vario"
| namedetails |
| 1 |
Then all results contain
| object | display_name | namedetails!dict |
| R13 | Garbo | "name": "Garbo", "name:it": "Vario" |
When geocoding "Vario"
| accept-language |
| it |
Then all results contain
| object | display_name |
| R13 | Vario |
Scenario: Differing names from linked places are searchable
Given the 0.1 grid
| 10 | | 11 |
| | 2 | |
| 13 | | 12 |
Given the places
| osm | class | type | admin | name | geometry |
| R13 | boundary | administrative | 6 | Garbo | (10,11,12,13,10) |
Given the places
| osm | class | type | admin | name |
| N2 | place | hamlet | 15 | Vario |
And the relations
| id | members | tags+type |
| 13 | N2:label | boundary |
When importing
Then placex contains
| object | linked_place_id |
| N2 | R13 |
When geocoding "Vario"
| namedetails |
| 1 |
Then all results contain
| object | display_name | namedetails!dict |
| R13 | Garbo | "name": "Garbo", "_place_name": "Vario" |
When geocoding "Garbo"
Then all results contain
| object | display_name |
| R13 | Garbo |

View File

@@ -0,0 +1,225 @@
Feature: Import and search of names
Tests all naming related issues: normalisation,
abbreviations, internationalisation, etc.
Scenario: non-latin scripts can be found
Given the places
| osm | class | type | name |
| N1 | place | locality | Речицкий район |
| N2 | place | locality | Refugio de montaña |
| N3 | place | locality | |
| N4 | place | locality | الدوحة |
When importing
When geocoding "Речицкий район"
Then result 0 contains
| object |
| N1 |
When geocoding "Refugio de montaña"
Then result 0 contains
| object |
| N2 |
When geocoding ""
Then result 0 contains
| object |
| N3 |
When geocoding "الدوحة"
Then result 0 contains
| object |
| N4 |
Scenario: Case-insensitivity of search
Given the places
| osm | class | type | name |
| N1 | place | locality | FooBar |
When importing
Then placex contains
| object | class | type | name+name |
| N1 | place | locality | FooBar |
When geocoding "FooBar"
Then result 0 contains
| object |
| N1 |
When geocoding "foobar"
Then result 0 contains
| object |
| N1 |
When geocoding "fOObar"
Then result 0 contains
| object |
| N1 |
When geocoding "FOOBAR"
Then result 0 contains
| object |
| N1 |
Scenario: Multiple spaces in name
Given the places
| osm | class | type | name |
| N1 | place | locality | one two three |
When importing
When geocoding "one two three"
Then result 0 contains
| object |
| N1 |
When geocoding "one two three"
Then result 0 contains
| object |
| N1 |
When geocoding "one two three"
Then result 0 contains
| object |
| N1 |
When geocoding " one two three"
Then result 0 contains
| object |
| N1 |
Scenario: Special characters in name
Given the places
| osm | class | type | name+name:de |
| N1 | place | locality | Jim-Knopf-Straße |
| N2 | place | locality | Smith/Weston |
| N3 | place | locality | space mountain |
| N4 | place | locality | space |
| N5 | place | locality | mountain |
When importing
When geocoding "Jim-Knopf-Str"
Then result 0 contains
| object |
| N1 |
When geocoding "Jim Knopf-Str"
Then result 0 contains
| object |
| N1 |
When geocoding "Jim Knopf Str"
Then result 0 contains
| object |
| N1 |
When geocoding "Jim/Knopf-Str"
Then result 0 contains
| object |
| N1 |
When geocoding "Jim-Knopfstr"
Then result 0 contains
| object |
| N1 |
When geocoding "Smith/Weston"
Then result 0 contains
| object |
| N2 |
When geocoding "Smith Weston"
Then result 0 contains
| object |
| N2 |
When geocoding "Smith-Weston"
Then result 0 contains
| object |
| N2 |
When geocoding "space mountain"
Then result 0 contains
| object |
| N3 |
When geocoding "space-mountain"
Then result 0 contains
| object |
| N3 |
When geocoding "space/mountain"
Then result 0 contains
| object |
| N3 |
When geocoding "space\mountain"
Then result 0 contains
| object |
| N3 |
When geocoding "space(mountain)"
Then result 0 contains
| object |
| N3 |
Scenario: Landuse with name are found
Given the grid
| 1 | 2 |
| 3 | |
Given the places
| osm | class | type | name | geometry |
| R1 | natural | meadow | landuse1 | (1,2,3,1) |
| R2 | landuse | industrial | landuse2 | (2,3,1,2) |
When importing
When geocoding "landuse1"
Then result 0 contains
| object |
| R1 |
When geocoding "landuse2"
Then result 0 contains
| object |
| R2 |
Scenario: Postcode boundaries without ref
Given the grid with origin FR
| | 2 | |
| 1 | | 3 |
Given the places
| osm | class | type | postcode | geometry |
| R1 | boundary | postal_code | 123-45 | (1,2,3,1) |
When importing
When geocoding "123-45"
Then result 0 contains
| object |
| R1 |
Scenario Outline: Housenumbers with special characters are found
Given the grid
| 1 | | | | 2 |
| | | 9 | | |
And the places
| osm | class | type | name | geometry |
| W1 | highway | primary | Main St | 1,2 |
And the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <nr> | 9 |
When importing
And geocoding "Main St <nr>"
Then result 0 contains
| object | display_name |
| N1 | <nr>, Main St |
Examples:
| nr |
| 1 |
| 3456 |
| 1 a |
| 56b |
| 1 A |
| 2 |
| 1Б |
| 1 к1 |
| 23-123 |
Scenario Outline: Housenumbers in lists are found
Given the grid
| 1 | | | | 2 |
| | | 9 | | |
And the places
| osm | class | type | name | geometry |
| W1 | highway | primary | Main St | 1,2 |
And the places
| osm | class | type | housenr | geometry |
| N1 | building | yes | <nr-list> | 9 |
When importing
And geocoding "Main St <nr>"
Then result 0 contains
| object | display_name |
| N1 | <nr-list>, Main St |
Examples:
| nr-list | nr |
| 1,2,3 | 1 |
| 1,2,3 | 2 |
| 1, 2, 3 | 3 |
| 45 ;67;3 | 45 |
| 45 ;67;3 | 67 |
| 1a;1k | 1a |
| 1a;1k | 1k |
| 34/678 | 34 |
| 34/678 | 678 |
| 34/678 | 34/678 |

View File

@@ -0,0 +1,109 @@
Feature: Querying fo postcode variants
Scenario: Postcodes in Singapore (6-digit postcode)
Given the grid with origin SG
| 10 | | | | 11 |
And the places
| osm | class | type | name | addr+postcode | geometry |
| W1 | highway | path | Lorang | 399174 | 10,11 |
When importing
When geocoding "399174"
Then result 0 contains
| type | display_name |
| postcode | 399174, Singapore |
Scenario Outline: Postcodes in the Netherlands (mixed postcode with spaces)
Given the grid with origin NL
| 10 | | | | 11 |
And the places
| osm | class | type | name | addr+postcode | geometry |
| W1 | highway | path | De Weide | 3993 DX | 10,11 |
When importing
When geocoding "3993 DX"
Then result 0 contains
| type | display_name |
| postcode | 3993 DX, Nederland |
When geocoding "3993dx"
Then result 0 contains
| type | display_name |
| postcode | 3993 DX, Nederland |
Examples:
| postcode |
| 3993 DX |
| 3993DX |
| 3993 dx |
Scenario: Postcodes in Singapore (6-digit postcode)
Given the grid with origin SG
| 10 | | | | 11 |
And the places
| osm | class | type | name | addr+postcode | geometry |
| W1 | highway | path | Lorang | 399174 | 10,11 |
When importing
When geocoding "399174"
Then result 0 contains
| type | display_name |
| postcode | 399174, Singapore |
Scenario Outline: Postcodes in Andorra (with country code)
Given the grid with origin AD
| 10 | | | | 11 |
And the places
| osm | class | type | name | addr+postcode | geometry |
| W1 | highway | path | Lorang | <postcode> | 10,11 |
When importing
When geocoding "675"
Then result 0 contains
| type | display_name |
| postcode | AD675, Andorra |
When geocoding "AD675"
Then result 0 contains
| type | display_name |
| postcode | AD675, Andorra |
Examples:
| postcode |
| 675 |
| AD 675 |
| AD675 |
Scenario: Different postcodes with the same normalization can both be found
Given the places
| osm | class | type | addr+postcode | addr+housenumber | geometry |
| N34 | place | house | EH4 7EA | 111 | country:gb |
| N35 | place | house | E4 7EA | 111 | country:gb |
When importing
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt |
| gb | EH4 7EA | country:gb |
| gb | E4 7EA | country:gb |
When geocoding "EH4 7EA"
Then result 0 contains
| type | display_name |
| postcode | EH4 7EA, United Kingdom |
When geocoding "E4 7EA"
Then result 0 contains
| type | display_name |
| postcode | E4 7EA, United Kingdom |
Scenario: Postcode areas are preferred over postcode points
Given the grid with origin DE
| 1 | 2 |
| 4 | 3 |
Given the places
| osm | class | type | postcode | geometry |
| R23 | boundary | postal_code | 12345 | (1,2,3,4,1) |
When importing
Then location_postcode contains exactly
| country_code | postcode |
| de | 12345 |
When geocoding "12345, de"
Then result 0 contains
| object |
| R23 |

View File

@@ -0,0 +1,21 @@
Feature: Reverse searches
Test results of reverse queries
Scenario: POI in POI area
Given the 0.0001 grid with origin 1,1
| 1 | | | | | | | | 2 |
| | 9 | | | | | | | |
| 4 | | | | | | | | 3 |
And the places
| osm | class | type | geometry |
| W1 | aeroway | terminal | (1,2,3,4,1) |
| N1 | amenity | restaurant | 9 |
When importing
And reverse geocoding 1.0001,1.0001
Then the result contains
| object |
| N1 |
When reverse geocoding 1.0003,1.0001
Then the result contains
| object |
| W1 |

View File

@@ -0,0 +1,84 @@
Feature: Searching of simple objects
Testing simple stuff
Scenario: Search for place node
Given the places
| osm | class | type | name+name | geometry |
| N1 | place | village | Foo | 10.0 -10.0 |
When importing
And geocoding "Foo"
Then result 0 contains
| object | category | type | centroid!wkt |
| N1 | place | village | 10 -10 |
# github #1763
Scenario: Correct translation of highways under construction
Given the grid
| 1 | | | | 2 |
| | | 9 | | |
And the places
| osm | class | type | name | geometry |
| W1 | highway | construction | The build | 1,2 |
| N1 | amenity | cafe | Bean | 9 |
When importing
And geocoding "Bean"
Then result 0 contains in field address
| amenity | road |
| Bean | The build |
Scenario: when missing housenumbers in search don't return a POI
Given the places
| osm | class | type | name |
| N3 | amenity | restaurant | Wood Street |
And the places
| osm | class | type | name | housenr |
| N20 | amenity | restaurant | Red Way | 34 |
When importing
And geocoding "Wood Street 45"
Then exactly 0 results are returned
When geocoding "Red Way 34"
Then all results contain
| object |
| N20 |
Scenario: when the housenumber is missing the street is still returned
Given the grid
| 1 | | 2 |
Given the places
| osm | class | type | name | geometry |
| W1 | highway | residential | Wood Street | 1, 2 |
When importing
And geocoding "Wood Street"
Then all results contain
| object |
| W1 |
Scenario Outline: Special cased american states will be found
Given the grid
| 1 | | 2 |
| | 10 | |
| 4 | | 3 |
Given the places
| osm | class | type | admin | name | name+ref | geometry |
| R1 | boundary | administrative | 4 | <state> | <ref> | (1,2,3,4,1) |
Given the places
| osm | class | type | name | geometry |
| N2 | place | town | <city> | 10 |
| N3 | place | city | <city> | country:ca |
When importing
And geocoding "<city>, <state>"
Then all results contain
| object |
| N2 |
When geocoding "<city>, <ref>"
| accept-language |
| en |
Then all results contain
| object |
| N2 |
Examples:
| city | state | ref |
| Chicago | Illinois | IL |
| Auburn | Alabama | AL |
| New Orleans | Louisiana | LA |

View File

@@ -0,0 +1,108 @@
Feature: Country handling
Tests for update of country information
Background:
Given the 1.0 grid with origin DE
| 1 | | 2 |
| | 10 | |
| 4 | | 3 |
Scenario: When country names are changed old ones are no longer searchable
Given the places
| osm | class | type | admin | name+name:xy | country | geometry |
| R1 | boundary | administrative | 2 | Loudou | de | (1,2,3,4,1) |
Given the places
| osm | class | type | name |
| N10 | place | town | Wenig |
When importing
When geocoding "Wenig, Loudou"
Then all results contain
| object |
| N10 |
When updating places
| osm | class | type | admin | name+name:xy | country | geometry |
| R1 | boundary | administrative | 2 | Germany | de | (1,2,3,4,1) |
When geocoding "Wenig, Loudou"
Then exactly 0 results are returned
Scenario: When country names are deleted they are no longer searchable
Given the places
| osm | class | type | admin | name+name:xy | country | geometry |
| R1 | boundary | administrative | 2 | Loudou | de | (1,2,3,4,1) |
Given the places
| osm | class | type | name |
| N10 | place | town | Wenig |
When importing
When geocoding "Wenig, Loudou"
Then all results contain
| object |
| N10 |
When updating places
| osm | class | type | admin | name+name:en | country | geometry |
| R1 | boundary | administrative | 2 | Germany | de | (1,2,3,4,1) |
When geocoding "Wenig, Loudou"
Then exactly 0 results are returned
When geocoding "Wenig"
| accept-language |
| xy,en |
Then all results contain
| object | display_name |
| N10 | Wenig, Germany |
Scenario: Default country names are always searchable
Given the places
| osm | class | type | name |
| N10 | place | town | Wenig |
When importing
When geocoding "Wenig, Germany"
Then all results contain
| object |
| N10 |
When geocoding "Wenig, de"
Then all results contain
| object |
| N10 |
When updating places
| osm | class | type | admin | name+name:en | country | geometry |
| R1 | boundary | administrative | 2 | Lilly | de | (1,2,3,4,1) |
When geocoding "Wenig, Germany"
| accept-language |
| en,de |
Then all results contain
| object | display_name |
| N10 | Wenig, Lilly |
When geocoding "Wenig, de"
| accept-language |
| en,de |
Then all results contain
| object | display_name |
| N10 | Wenig, Lilly |
Scenario: When a localised name is deleted, the standard name takes over
Given the places
| osm | class | type | admin | name+name:de | country | geometry |
| R1 | boundary | administrative | 2 | Loudou | de | (1,2,3,4,1) |
Given the places
| osm | class | type | name |
| N10 | place | town | Wenig |
When importing
When geocoding "Wenig, Loudou"
| accept-language |
| de,en |
Then all results contain
| object | display_name |
| N10 | Wenig, Loudou |
When updating places
| osm | class | type | admin | name+name:en | country | geometry |
| R1 | boundary | administrative | 2 | Germany | de | (1,2,3,4,1) |
When geocoding "Wenig, Loudou"
Then exactly 0 results are returned
When geocoding "Wenig"
| accept-language |
| de,en |
Then all results contain
| object | display_name |
| N10 | Wenig, Deutschland |

View File

@@ -0,0 +1,418 @@
Feature: Update of address interpolations
Test the interpolated address are updated correctly
Scenario: new interpolation added to existing street
Given the grid
| 10 | | | | 11 |
| | 1 | 99 | 2 | |
| | | | | |
| 20 | | | | 21 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Sun Way | 10,11 |
| W3 | highway | unclassified | Cloud Street | 20,21 |
And the ways
| id | nodes |
| 10 | 1,2 |
When importing
Then W10 expands to no interpolation
When updating places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And updating places
| osm | class | type | addr+interpolation | geometry |
| W10 | place | houses | even | 1,2 |
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end | geometry |
| W2 | 4 | 4 | 99 |
Scenario: addr:street added to interpolation
Given the grid
| 10 | | | | 11 |
| | 1 | | 2 | |
| | | | | |
| 20 | | | | 21 |
And the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W10 | place | houses | even | 1,2 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Sun Way | 10,11 |
| W3 | highway | unclassified | Cloud Street | 20,21 |
And the ways
| id | nodes |
| 10 | 1,2 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
When updating places
| osm | class | type | addr+interpolation | street | geometry |
| W10 | place | houses | even | Cloud Street | 1,2 |
Then placex contains
| object | parent_place_id |
| N1 | W3 |
| N2 | W3 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W3 | 4 | 4 |
Scenario: addr:street added to housenumbers
Given the grid
| 10 | | | | 11 |
| | 1 | | 2 | |
| | | | | |
| 20 | | | | 21 |
And the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W10 | place | houses | even | 1,2 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Sun Way | 10,11 |
| W3 | highway | unclassified | Cloud Street | 20,21 |
And the ways
| id | nodes |
| 10 | 1,2 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
When updating places
| osm | class | type | street | housenr |
| N1 | place | house | Cloud Street| 2 |
| N2 | place | house | Cloud Street| 6 |
Then placex contains
| object | parent_place_id |
| N1 | W3 |
| N2 | W3 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W3 | 4 | 4 |
Scenario: interpolation tag removed
Given the grid
| 10 | | | | 11 |
| | 1 | | 2 | |
| | | | | |
| 20 | | | | 21 |
And the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W10 | place | houses | even | 1,2 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Sun Way | 10,11 |
| W3 | highway | unclassified | Cloud Street | 20,21 |
And the ways
| id | nodes |
| 10 | 1,2 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
When marking for delete W10
Then W10 expands to no interpolation
And placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
Scenario: referenced road added
Given the grid
| 10 | | | | 11 |
| | 1 | | 2 | |
| | | | | |
| 20 | | | | 21 |
And the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | street | geometry |
| W10 | place | houses | even | Cloud Street| 1,2 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Sun Way | 10,11 |
And the ways
| id | nodes |
| 10 | 1,2 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
When updating places
| osm | class | type | name | geometry |
| W3 | highway | unclassified | Cloud Street | 20,21 |
Then placex contains
| object | parent_place_id |
| N1 | W3 |
| N2 | W3 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W3 | 4 | 4 |
Scenario: referenced road deleted
Given the grid
| 10 | | | | 11 |
| | 1 | | 2 | |
| | | | | |
| 20 | | | | 21 |
And the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | addr+interpolation | street | geometry |
| W10 | place | houses | even | Cloud Street| 1,2 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Sun Way | 10,11 |
| W3 | highway | unclassified | Cloud Street | 20,21 |
And the ways
| id | nodes |
| 10 | 1,2 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W3 |
| N2 | W3 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W3 | 4 | 4 |
When marking for delete W3
Then placex contains
| object | parent_place_id |
| N1 | W2 |
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
Scenario: building becomes interpolation
Given the grid
| 10 | | | | 11 |
| | 1 | | 2 | |
| | 4 | | 3 | |
And the places
| osm | class | type | housenr | geometry |
| W1 | place | house | 3 | (1,2,3,4,1) |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Cloud Street | 10,11 |
When importing
Then placex contains
| object | parent_place_id |
| W1 | W2 |
Given the ways
| id | nodes |
| 1 | 1,2 |
When updating places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And updating places
| osm | class | type | addr+interpolation | street | geometry |
| W1 | place | houses | even | Cloud Street| 1,2 |
Then placex has no entry for W1
And W1 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
Scenario: interpolation becomes building
Given the grid
| 10 | | | | 11 |
| | 1 | | 2 | |
| | 4 | | 3 | |
And the places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Cloud Street | 10,11 |
And the ways
| id | nodes |
| 1 | 1,2 |
And the places
| osm | class | type | addr+interpolation | street | geometry |
| W1 | place | houses | even | Cloud Street| 1,2 |
When importing
Then placex has no entry for W1
And W1 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
When updating places
| osm | class | type | housenr | geometry |
| W1 | place | house | 3 | (1,2,3,4,1) |
Then placex contains
| object | parent_place_id |
| W1 | W2 |
And W1 expands to no interpolation
Scenario: housenumbers added to interpolation
Given the grid
| 10 | | | | 11 |
| | 1 | | 2 | |
And the places
| osm | class | type | name | geometry |
| W2 | highway | unclassified | Cloud Street | 10,11 |
And the ways
| id | nodes |
| 1 | 1,2 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1,2 |
When importing
Then W1 expands to no interpolation
When updating places
| osm | class | type | housenr |
| N1 | place | house | 2 |
| N2 | place | house | 6 |
Then W1 expands to interpolation
| parent_place_id | start | end |
| W2 | 4 | 4 |
Scenario: housenumber added in middle of interpolation
Given the grid
| 1 | | | | | 2 |
| 3 | | | 4 | | 5 |
And the places
| osm | class | type | name | geometry |
| W1 | highway | unclassified | Cloud Street | 1, 2 |
And the ways
| id | nodes |
| 2 | 3,4,5 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W2 | place | houses | even | 3,4,5 |
And the places
| osm | class | type | housenr |
| N3 | place | house | 2 |
| N5 | place | house | 10 |
When importing
Then W2 expands to interpolation
| parent_place_id | start | end |
| W1 | 4 | 8 |
When updating places
| osm | class | type | housenr |
| N4 | place | house | 6 |
Then W2 expands to interpolation
| parent_place_id | start | end |
| W1 | 4 | 4 |
| W1 | 8 | 8 |
@skip
Scenario: housenumber removed in middle of interpolation
Given the grid
| 1 | | | | | 2 |
| 3 | | | 4 | | 5 |
And the places
| osm | class | type | name | geometry |
| W1 | highway | unclassified | Cloud Street | 1, 2 |
And the ways
| id | nodes |
| 2 | 3,4,5 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W2 | place | houses | even | 3,4,5 |
And the places
| osm | class | type | housenr |
| N3 | place | house | 2 |
| N4 | place | house | 6 |
| N5 | place | house | 10 |
When importing
Then W2 expands to interpolation
| parent_place_id | start | end |
| W1 | 4 | 4 |
| W1 | 8 | 8 |
When marking for delete N4
Then W2 expands to interpolation
| parent_place_id | start | end |
| W1 | 4 | 8 |
Scenario: Change the start housenumber
Given the grid
| 1 | | 2 |
| 3 | | 4 |
And the places
| osm | class | type | name | geometry |
| W1 | highway | unclassified | Cloud Street | 1, 2 |
And the ways
| id | nodes |
| 2 | 3,4 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W2 | place | houses | even | 3,4 |
And the places
| osm | class | type | housenr |
| N3 | place | house | 2 |
| N4 | place | house | 6 |
When importing
Then W2 expands to interpolation
| parent_place_id | start | end |
| W1 | 4 | 4 |
When updating places
| osm | class | type | housenr |
| N4 | place | house | 8 |
Then W2 expands to interpolation
| parent_place_id | start | end |
| W1 | 4 | 6 |
Scenario: Legal interpolation type changed to illegal one
Given the grid
| 1 | | 2 |
| 3 | | 4 |
And the places
| osm | class | type | name | geometry |
| W1 | highway | unclassified | Cloud Street | 1, 2 |
And the ways
| id | nodes |
| 2 | 3,4 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W2 | place | houses | even | 3,4 |
And the places
| osm | class | type | housenr |
| N3 | place | house | 2 |
| N4 | place | house | 6 |
When importing
Then W2 expands to interpolation
| parent_place_id | start | end |
| W1 | 4 | 4 |
When updating places
| osm | class | type | addr+interpolation | geometry |
| W2 | place | houses | 12-2 | 3,4 |
Then W2 expands to no interpolation

View File

@@ -0,0 +1,340 @@
Feature: Updates of linked places
Tests that linked places are correctly added and deleted.
Scenario: Linking is kept when boundary is updated
Given the 0.1 grid
| 10 | | 11 |
| | 1 | |
| 13 | | 12 |
Given the places
| osm | class | type | name |
| N1 | place | city | foo |
And the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (10,11,12,13,10) |
When importing
Then placex contains
| object | linked_place_id |
| N1 | R1 |
When updating places
| osm | class | type | name | name+name:de | admin | geometry |
| R1 | boundary | administrative | foo | Dingens | 8 | (10,11,12,13,10) |
Then placex contains
| object | linked_place_id |
| N1 | R1 |
Scenario: Add linked place when linking relation is renamed
Given the 0.1 grid
| 10 | | 11 |
| | 1 | |
| 13 | | 12 |
Given the places
| osm | class | type | name |
| N1 | place | city | foo |
And the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (10,11,12,13,10) |
When importing
Then placex contains
| object | linked_place_id |
| N1 | R1 |
When geocoding "foo"
| dups |
| 1 |
Then all results contain
| object |
| R1 |
When updating places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foobar | 8 | (10,11,12,13,10) |
Then placex contains
| object | linked_place_id |
| N1 | - |
When geocoding "foo"
| dups |
| 1 |
Then all results contain
| object |
| N1 |
Scenario: Add linked place when linking relation is removed
Given the 0.1 grid
| 10 | | 11 |
| | 1 | |
| 13 | | 12 |
Given the places
| osm | class | type | name |
| N1 | place | city | foo |
And the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (10,11,12,13,10) |
When importing
And geocoding "foo"
| dups |
| 1 |
Then all results contain
| object |
| R1 |
When marking for delete R1
Then placex contains
| object | linked_place_id |
| N1 | - |
When geocoding "foo"
| dups |
| 1 |
Then all results contain
| object |
| N1 |
Scenario: Remove linked place when linking relation is added
Given the 0.1 grid
| 10 | | 11 |
| | 1 | |
| 13 | | 12 |
Given the places
| osm | class | type | name |
| N1 | place | city | foo |
When importing
And geocoding "foo"
| dups |
| 1 |
Then all results contain
| object |
| N1 |
When updating places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (10,11,12,13,10) |
Then placex contains
| object | linked_place_id |
| N1 | R1 |
When geocoding "foo"
| dups |
| 1 |
Then all results contain
| object |
| R1 |
Scenario: Remove linked place when linking relation is renamed
Given the 0.1 grid
| 10 | | 11 |
| | 1 | |
| 13 | | 12 |
Given the places
| osm | class | type | name |
| N1 | place | city | foo |
And the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foobar | 8 | (10,11,12,13,10) |
When importing
And geocoding "foo"
| dups |
| 1 |
Then all results contain
| object |
| N1 |
When updating places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (10,11,12,13,10) |
Then placex contains
| object | linked_place_id |
| N1 | R1 |
When geocoding "foo"
| dups |
| 1 |
Then all results contain
| object |
| R1 |
Scenario: Update linking relation when linkee name is updated
Given the 0.1 grid
| 10 | | 11 |
| | 3 | |
| 13 | | 12 |
Given the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | rel | 8 | (10,11,12,13,10) |
And the places
| osm | class | type | name+name:de |
| N3 | place | city | greeny |
And the relations
| id | members |
| 1 | N3:label |
When importing
Then placex contains
| object | linked_place_id | name+_place_name:de |
| R1 | - | greeny |
And placex contains
| object | linked_place_id | name+name:de |
| N3 | R1 | greeny |
When updating places
| osm | class | type | name+name:de |
| N3 | place | city | newname |
Then placex contains
| object | linked_place_id | name+name:de |
| N3 | R1 | newname |
And placex contains
| object | linked_place_id | name+_place_name:de |
| R1 | - | newname |
Scenario: Update linking relation when linkee name is deleted
Given the 0.1 grid
| 10 | | 11 |
| | 3 | |
| 13 | | 12 |
Given the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | rel | 8 | (10,11,12,13,10) |
And the places
| osm | class | type | name |
| N3 | place | city | greeny |
And the relations
| id | members |
| 1 | N3:label |
When importing
Then placex contains
| object | linked_place_id | name+_place_name | name+name |
| R1 | - | greeny | rel |
And placex contains
| object | linked_place_id | name+name |
| N3 | R1 | greeny |
When geocoding "greeny"
Then all results contain
| object |
| R1 |
When updating places
| osm | class | type | name+name:de |
| N3 | place | city | depnt |
Then placex contains
| object | linked_place_id | name+name:de |
| N3 | R1 | depnt |
And placex contains
| object | linked_place_id | name+_place_name:de | name+name |
| R1 | - | depnt | rel |
When geocoding "greeny"
Then exactly 0 results are returned
Scenario: Updating linkee extratags keeps linker's extratags
Given the 0.1 grid
| 10 | | 11 |
| | 3 | |
| 13 | | 12 |
Given the named places
| osm | class | type | extra+wikidata | admin | geometry |
| R1 | boundary | administrative | 34 | 8 | (10,11,12,13,10) |
And the named places
| osm | class | type |
| N3 | place | city |
And the relations
| id | members |
| 1 | N3:label |
When importing
Then placex contains
| object | extratags!dict |
| R1 | 'wikidata' : '34', 'linked_place' : 'city' |
When updating places
| osm | class | type | name | extra+oneway |
| N3 | place | city | newname | yes |
Then placex contains
| object | extratags!dict |
| R1 | 'wikidata' : '34', 'oneway' : 'yes', 'linked_place' : 'city' |
Scenario: Remove linked_place info when linkee is removed
Given the 0.1 grid
| 10 | | 11 |
| | 1 | |
| 13 | | 12 |
Given the places
| osm | class | type | name |
| N1 | place | city | foo |
And the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (10,11,12,13,10) |
When importing
Then placex contains
| object | extratags!dict |
| R1 | 'linked_place' : 'city' |
When marking for delete N1
Then placex contains
| object | extratags |
| R1 | - |
Scenario: Update linked_place info when linkee type changes
Given the 0.1 grid
| 10 | | 11 |
| | 1 | |
| 13 | | 12 |
Given the places
| osm | class | type | name |
| N1 | place | city | foo |
And the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (10,11,12,13,10) |
When importing
Then placex contains
| object | extratags!dict |
| R1 | 'linked_place' : 'city' |
When updating places
| osm | class | type | name |
| N1 | place | town | foo |
Then placex contains
| object | extratags!dict |
| R1 | 'linked_place' : 'town' |
Scenario: Keep linking and ranks when place type changes
Given the grid
| 1 | | | 2 |
| | | 9 | |
| 4 | | | 3 |
And the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (1,2,3,4,1) |
And the places
| osm | class | type | name | geometry |
| N1 | place | city | foo | 9 |
When importing
Then placex contains
| object | linked_place_id | rank_address |
| N1 | R1 | 16 |
| R1 | - | 16 |
When updating places
| osm | class | type | name | geometry |
| N1 | place | town | foo | 9 |
Then placex contains
| object | linked_place_id | rank_address |
| N1 | R1 | 16 |
| R1 | - | 16 |
Scenario: Invalidate surrounding place nodes when place type changes
Given the grid
| 1 | | | 2 |
| | 8 | 9 | |
| 4 | | | 3 |
And the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | foo | 8 | (1,2,3,4,1) |
And the places
| osm | class | type | name | geometry |
| N1 | place | town | foo | 9 |
| N2 | place | city | bar | 8 |
And the relations
| id | members |
| 1 | N1:label |
When importing
Then placex contains
| object | linked_place_id | rank_address |
| N1 | R1 | 16 |
| R1 | - | 16 |
| N2 | - | 18 |
When updating places
| osm | class | type | name | geometry |
| N1 | place | suburb | foo | 9 |
Then placex contains
| object | linked_place_id | rank_address |
| N1 | R1 | 20 |
| R1 | - | 20 |
| N2 | - | 16 |

View File

@@ -0,0 +1,20 @@
Feature: Update of names in place objects
Test all naming related issues in updates
Scenario: Delete postcode from postcode boundaries without ref
Given the grid with origin DE
| 1 | 2 |
| 4 | 3 |
Given the places
| osm | class | type | postcode | geometry |
| R1 | boundary | postal_code | 123-45 | (1,2,3,4,1) |
When importing
And geocoding "123-45"
Then result 0 contains
| object |
| R1 |
When updating places
| osm | class | type | geometry |
| R1 | boundary | postal_code | (1,2,3,4,1) |
Then placex has no entry for R1

View File

@@ -0,0 +1,163 @@
Feature: Update parenting of objects
Scenario: POI inside building inherits addr:street change
Given the grid
| 10 | | | | | | | 11 |
| | | 5 | | | 6 | | |
| | | | | | | | |
| | | | | 1 | | | |
| 12 | | 8 | | | 7 | | |
And the named places
| osm | class | type |
| N1 | amenity | bank |
And the places
| osm | class | type | street | housenr | geometry |
| W1 | building | yes | nowhere | 3 | (5,6,7,8,5) |
And the places
| osm | class | type | name | geometry |
| W2 | highway | primary | bar | 10,11 |
| W3 | highway | residential | foo | 10,12 |
When importing
Then placex contains
| object | parent_place_id | housenumber |
| W1 | W2 | 3 |
| N1 | W2 | 3 |
When updating places
| osm | class | type | street | addr_place | housenr | geometry |
| W1 | building | yes | foo | nowhere | 3 | (5,6,7,8,5) |
And updating places
| osm | class | type | name |
| N1 | amenity | bank | well |
Then placex contains
| object | parent_place_id | housenumber |
| W1 | W3 | 3 |
| N1 | W3 | 3 |
Scenario: Housenumber is reparented when street gets name matching addr:street
Given the grid
| 1 | | | 2 |
| | 10 | | |
| | | | |
| 3 | | | 4 |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | A street | 1,2 |
| W2 | highway | residential | B street | 3,4 |
And the places
| osm | class | type | housenr | street | geometry |
| N1 | building | yes | 3 | X street | 10 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
When updating places
| osm | class | type | name | geometry |
| W2 | highway | residential | X street | 3,4 |
Then placex contains
| object | parent_place_id |
| N1 | W2 |
Scenario: Housenumber is reparented when street looses name matching addr:street
Given the grid
| 1 | | | 2 |
| | 10 | | |
| | | | |
| 3 | | | 4 |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | A street | 1,2 |
| W2 | highway | residential | X street | 3,4 |
And the places
| osm | class | type | housenr | street | geometry |
| N1 | building | yes | 3 | X street | 10 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W2 |
When updating places
| osm | class | type | name | geometry |
| W2 | highway | residential | B street | 3,4 |
Then placex contains
| object | parent_place_id |
| N1 | W1 |
Scenario: Housenumber is reparented when street gets name matching addr:street
Given the grid
| 1 | | | 2 |
| | 10 | | |
| | | | |
| 3 | | | 4 |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | A street | 1,2 |
| W2 | highway | residential | B street | 3,4 |
And the places
| osm | class | type | housenr | street | geometry |
| N1 | building | yes | 3 | X street | 10 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | W1 |
When updating places
| osm | class | type | name | geometry |
| W2 | highway | residential | X street | 3,4 |
Then placex contains
| object | parent_place_id |
| N1 | W2 |
# Invalidation of geometries currently disabled for addr:place matches.
@skip
Scenario: Housenumber is reparented when place is renamed to matching addr:place
Given the grid
| 1 | | | 2 |
| | 10 | 4 | |
| | | | |
| | | 5 | |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | A street | 1,2 |
| N5 | place | village | Bdorf | 5 |
| N4 | place | village | Other | 4 |
And the places
| osm | class | type | housenr | addr_place | geometry |
| N1 | building | yes | 3 | Cdorf | 10 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | N4 |
When updating places
| osm | class | type | name | geometry |
| N5 | place | village | Cdorf | 5 |
Then placex contains
| object | parent_place_id |
| N1 | N5 |
Scenario: Housenumber is reparented when it looses a matching addr:place
Given the grid
| 1 | | | 2 |
| | 10 | 4 | |
| | | | |
| | | 5 | |
And the places
| osm | class | type | name | geometry |
| W1 | highway | residential | A street | 1,2 |
| N5 | place | village | Bdorf | 5 |
| N4 | place | village | Other | 4 |
And the places
| osm | class | type | housenr | addr_place | geometry |
| N1 | building | yes | 3 | Bdorf | 10 |
When importing
Then placex contains
| object | parent_place_id |
| N1 | N5 |
When updating places
| osm | class | type | name | geometry |
| N5 | place | village | Cdorf | 5 |
Then placex contains
| object | parent_place_id |
| N1 | N4 |

View File

@@ -0,0 +1,139 @@
Feature: Update of postcode
Tests for updating of data related to postcodes
Scenario: Updating postcode in postcode boundaries without ref
Given the grid
| 1 | 2 |
| 4 | 3 |
Given the places
| osm | class | type | postcode | geometry |
| R1 | boundary | postal_code | 12345 | (1,2,3,4,1) |
When importing
And geocoding "12345"
Then result 0 contains
| object |
| R1 |
When updating places
| osm | class | type | postcode | geometry |
| R1 | boundary | postal_code | 54321 | (1,2,3,4,1) |
And geocoding "12345"
Then exactly 0 results are returned
When geocoding "54321"
Then result 0 contains
| object |
| R1 |
Scenario: A new postcode appears in the postcode table
Given the places
| osm | class | type | addr+postcode | addr+housenumber | geometry |
| N34 | place | house | 01982 | 111 | country:de |
When importing
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt |
| de | 01982 | country:de |
When updating places
| osm | class | type | addr+postcode | addr+housenumber | geometry |
| N35 | place | house | 4567 | 5 | country:ch |
And updating postcodes
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt |
| de | 01982 | country:de |
| ch | 4567 | country:ch |
Scenario: When the last postcode is deleted, it is deleted from postcode
Given the places
| osm | class | type | addr+postcode | addr+housenumber | geometry |
| N34 | place | house | 01982 | 111 | country:de |
| N35 | place | house | 4567 | 5 | country:ch |
When importing
And marking for delete N34
And updating postcodes
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt |
| ch | 4567 | country:ch |
Scenario: A postcode is not deleted from postcode when it exist in another country
Given the places
| osm | class | type | addr+postcode | addr+housenumber | geometry |
| N34 | place | house | 01982 | 111 | country:de |
| N35 | place | house | 01982 | 5 | country:fr |
When importing
And marking for delete N34
And updating postcodes
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt|
| fr | 01982 | country:fr |
Scenario: Updating a postcode is reflected in postcode table
Given the places
| osm | class | type | addr+postcode | geometry |
| N34 | place | postcode | 01982 | country:de |
When importing
And updating places
| osm | class | type | addr+postcode | geometry |
| N34 | place | postcode | 20453 | country:de |
And updating postcodes
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt |
| de | 20453 | country:de |
Scenario: When changing from a postcode type, the entry appears in placex
When importing
And updating places
| osm | class | type | addr+postcode | geometry |
| N34 | place | postcode | 01982 | country:de |
Then placex has no entry for N34
When updating places
| osm | class | type | addr+postcode | housenr | geometry |
| N34 | place | house | 20453 | 1 | country:de |
Then placex contains
| object | addr+housenumber | geometry!wkt |
| N34 | 1 | country:de |
And place contains exactly
| osm_type | osm_id | class | type |
| N | 34 | place | house |
When updating postcodes
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt |
| de | 20453 | country:de |
Scenario: When changing to a postcode type, the entry disappears from placex
When importing
And updating places
| osm | class | type | addr+postcode | housenr | geometry |
| N34 | place | house | 20453 | 1 | country:de |
Then placex contains
| object | addr+housenumber | geometry!wkt |
| N34 | 1 | country:de|
When updating places
| osm | class | type | addr+postcode | geometry |
| N34 | place | postcode | 01982 | country:de |
Then placex has no entry for N34
And place contains exactly
| osm_type | osm_id | class | type |
| N | 34 | place | postcode |
When updating postcodes
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt |
| de | 01982 | country:de |
Scenario: When a parent is deleted, the postcode gets a new parent
Given the grid with origin DE
| 1 | | 3 | 4 |
| | 9 | | |
| 2 | | 5 | 6 |
Given the places
| osm | class | type | name | admin | geometry |
| R1 | boundary | administrative | Big | 6 | (1,4,6,2,1) |
| R2 | boundary | administrative | Small | 6 | (1,3,5,2,1) |
Given the places
| osm | class | type | addr+postcode | geometry |
| N9 | place | postcode | 12345 | 9 |
When importing
Then location_postcode contains exactly
| postcode | geometry!wkt | parent_place_id |
| 12345 | 9 | R2 |
When marking for delete R2
Then location_postcode contains exactly
| country_code | postcode | geometry!wkt | parent_place_id |
| de | 12345 | 9 | R1 |

View File

@@ -0,0 +1,117 @@
Feature: Update of simple objects
Testing simple updating functionality
Scenario: Do delete small boundary features
Given the 1.0 grid
| 1 | 2 |
| 4 | 3 |
Given the places
| osm | class | type | admin | geometry |
| R1 | boundary | administrative | 3 | (1,2,3,4,1) |
When importing
Then placex contains
| object | rank_search |
| R1 | 6 |
When marking for delete R1
Then placex has no entry for R1
Scenario: Do not delete large boundary features
Given the 2.0 grid
| 1 | 2 |
| 4 | 3 |
Given the places
| osm | class | type | admin | geometry |
| R1 | boundary | administrative | 3 | (1,2,3,4,1) |
When importing
Then placex contains
| object | rank_search |
| R1 | 6 |
When marking for delete R1
Then placex contains
| object | rank_search |
| R1 | 6 |
Scenario: Do delete large features of low rank
Given the 2.0 grid
| 1 | 2 |
| 4 | 3 |
Given the named places
| osm | class | type | geometry |
| W1 | place | house | (1,2,3,4,1) |
| R1 | natural | wood | (1,2,3,4,1) |
| R2 | highway | residential | (1,2,3,4,1) |
When importing
Then placex contains
| object | rank_address |
| R1 | 0 |
| R2 | 26 |
| W1 | 30 |
When marking for delete R1
And marking for delete R2
And marking for delete W1
Then placex has no entry for W1
Then placex has no entry for R1
Then placex has no entry for R2
Scenario: type mutation
Given the places
| osm | class | type | geometry |
| N3 | shop | toys | 1 -1 |
When importing
Then placex contains
| object | class | type | centroid!wkt |
| N3 | shop | toys | 1 -1 |
When updating places
| osm | class | type | geometry |
| N3 | shop | grocery | 1 -1 |
Then placex contains
| object | class | type | centroid!wkt |
| N3 | shop | grocery | 1 -1 |
Scenario: remove postcode place when house number is added
Given the places
| osm | class | type | postcode | geometry |
| N3 | place | postcode | 12345 | country:de |
When importing
Then placex has no entry for N3
When updating places
| osm | class | type | postcode | housenr | geometry |
| N3 | place | house | 12345 | 13 | country:de |
Then placex contains
| object | class | type |
| N3 | place | house |
Scenario: remove boundary when changing from polygon to way
Given the grid
| 1 | 2 |
| 3 | 4 |
And the places
| osm | class | type | name | admin | geometry |
| W1 | boundary | administrative | Haha | 5 | (1, 2, 4, 3, 1) |
When importing
Then placex contains
| object |
| W1 |
When updating places
| osm | class | type | name | admin | geometry |
| W1 | boundary | administrative | Haha | 5 | 1, 2, 4, 3 |
Then placex has no entry for W1
#895
Scenario: update rank when boundary is downgraded from admin to historic
Given the grid
| 1 | 2 |
| 3 | 4 |
And the places
| osm | class | type | name | admin | geometry |
| W1 | boundary | administrative | Haha | 5 | (1, 2, 4, 3, 1) |
When importing
Then placex contains
| object | rank_address |
| W1 | 10 |
When updating places
| osm | class | type | name | admin | geometry |
| W1 | boundary | historic | Haha | 5 | (1, 2, 4, 3, 1) |
Then placex contains
| object | rank_address |
| W1 | 0 |

245
test/bdd/test_db.py Normal file
View File

@@ -0,0 +1,245 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This file is part of Nominatim. (https://nominatim.org)
#
# Copyright (C) 2025 by the Nominatim developer community.
# For a full list of authors see the git log.
"""
Collector for BDD import acceptance tests.
These tests check the Nominatim import chain after the osm2pgsql import.
"""
import asyncio
import re
from pathlib import Path
import psycopg
import pytest
from pytest_bdd import scenarios, when, then, given
from pytest_bdd.parsers import re as step_parse
from utils.place_inserter import PlaceColumn
from utils.checks import check_table_content
from nominatim_db.config import Configuration
from nominatim_db import cli
from nominatim_db.tools.database_import import load_data, create_table_triggers
from nominatim_db.tools.postcodes import update_postcodes
from nominatim_db.tokenizer import factory as tokenizer_factory
def _rewrite_placeid_field(field, new_field, datatable, place_ids):
try:
oidx = datatable[0].index(field)
datatable[0][oidx] = new_field
for line in datatable[1:]:
line[oidx] = None if line[oidx] == '-' else place_ids[line[oidx]]
except ValueError:
pass
def _collect_place_ids(conn):
pids = {}
with conn.cursor() as cur:
for row in cur.execute('SELECT place_id, osm_type, osm_id, class FROM placex'):
pids[f"{row[1]}{row[2]}"] = row[0]
pids[f"{row[1]}{row[2]}:{row[3]}"] = row[0]
return pids
@pytest.fixture
def test_config_env(pytestconfig):
dbname = pytestconfig.getini('nominatim_test_db')
config = Configuration(None).get_os_env()
config['NOMINATIM_DATABASE_DSN'] = f"pgsql:dbname={dbname}"
config['NOMINATIM_LANGUAGES'] = 'en,de,fr,ja'
config['NOMINATIM_USE_US_TIGER_DATA'] = 'yes'
if pytestconfig.option.NOMINATIM_TOKENIZER is not None:
config['NOMINATIM_TOKENIZER'] = pytestconfig.option.NOMINATIM_TOKENIZER
return config
@pytest.fixture
def update_config(def_config):
""" Prepare the database for being updatable and return the config.
"""
cli.nominatim(['refresh', '--functions'], def_config.environ)
return def_config
@given(step_parse('the (?P<named>named )?places'), target_fixture=None)
def import_places(db_conn, named, datatable, node_grid):
""" Insert todo rows into the place table.
When 'named' is given, then a random name will be generated for all
objects.
"""
with db_conn.cursor() as cur:
for row in datatable[1:]:
PlaceColumn(node_grid).add_row(datatable[0], row, named is not None).db_insert(cur)
@given('the ways', target_fixture=None)
def import_ways(db_conn, datatable):
""" Import raw ways into the osm2pgsql way middle table.
"""
with db_conn.cursor() as cur:
id_idx = datatable[0].index('id')
node_idx = datatable[0].index('nodes')
for line in datatable[1:]:
tags = psycopg.types.json.Json(
{k[5:]: v for k, v in zip(datatable[0], line)
if k.startswith("tags+")})
nodes = [int(x) for x in line[node_idx].split(',')]
cur.execute("INSERT INTO planet_osm_ways (id, nodes, tags) VALUES (%s, %s, %s)",
(line[id_idx], nodes, tags))
@given('the relations', target_fixture=None)
def import_rels(db_conn, datatable):
""" Import raw relations into the osm2pgsql relation middle table.
"""
with db_conn.cursor() as cur:
id_idx = datatable[0].index('id')
memb_idx = datatable[0].index('members')
for line in datatable[1:]:
tags = psycopg.types.json.Json(
{k[5:]: v for k, v in zip(datatable[0], line)
if k.startswith("tags+")})
members = []
if line[memb_idx]:
for member in line[memb_idx].split(','):
m = re.fullmatch(r'\s*([RWN])(\d+)(?::(\S+))?\s*', member)
if not m:
raise ValueError(f'Illegal member {member}.')
members.append({'ref': int(m[2]), 'role': m[3] or '', 'type': m[1]})
cur.execute('INSERT INTO planet_osm_rels (id, tags, members) VALUES (%s, %s, %s)',
(int(line[id_idx]), tags, psycopg.types.json.Json(members)))
@when('importing', target_fixture='place_ids')
def do_import(db_conn, def_config):
""" Run a reduced version of the Nominatim import.
"""
create_table_triggers(db_conn, def_config)
asyncio.run(load_data(def_config.get_libpq_dsn(), 1))
tokenizer = tokenizer_factory.get_tokenizer_for_db(def_config)
update_postcodes(def_config.get_libpq_dsn(), Path('/xxxx'), tokenizer)
cli.nominatim(['index', '-q'], def_config.environ)
return _collect_place_ids(db_conn)
@when('updating places', target_fixture='place_ids')
def do_update(db_conn, update_config, node_grid, datatable):
""" Update the place table with the given data. Also runs all triggers
related to updates and reindexes the new data.
"""
with db_conn.cursor() as cur:
for row in datatable[1:]:
PlaceColumn(node_grid).add_row(datatable[0], row, False).db_insert(cur)
cur.execute('SELECT flush_deleted_places()')
db_conn.commit()
cli.nominatim(['index', '-q'], update_config.environ)
return _collect_place_ids(db_conn)
@when('updating postcodes')
def do_postcode_update(update_config):
""" Recompute the postcode centroids.
"""
cli.nominatim(['refresh', '--postcodes'], update_config.environ)
@when(step_parse(r'marking for delete (?P<otype>[NRW])(?P<oid>\d+)'),
converters={'oid': int})
def do_delete_place(db_conn, update_config, node_grid, otype, oid):
""" Remove the given place from the database.
"""
with db_conn.cursor() as cur:
cur.execute('TRUNCATE place_to_be_deleted')
cur.execute('DELETE FROM place WHERE osm_type = %s and osm_id = %s',
(otype, oid))
cur.execute('SELECT flush_deleted_places()')
db_conn.commit()
cli.nominatim(['index', '-q'], update_config.environ)
@then(step_parse(r'(?P<table>\w+) contains(?P<exact> exactly)?'))
def then_check_table_content(db_conn, place_ids, datatable, node_grid, table, exact):
_rewrite_placeid_field('object', 'place_id', datatable, place_ids)
_rewrite_placeid_field('parent_place_id', 'parent_place_id', datatable, place_ids)
_rewrite_placeid_field('linked_place_id', 'linked_place_id', datatable, place_ids)
if table == 'place_addressline':
_rewrite_placeid_field('address', 'address_place_id', datatable, place_ids)
for i, title in enumerate(datatable[0]):
if title.startswith('addr+'):
datatable[0][i] = f"address+{title[5:]}"
check_table_content(db_conn, table, datatable, grid=node_grid, exact=bool(exact))
@then(step_parse(r'(DISABLED?P<table>placex?) has no entry for (?P<oid>[NRW]\d+(?::\S+)?)'))
def then_check_place_missing_lines(db_conn, place_ids, table, oid):
assert oid in place_ids
sql = pysql.SQL("""SELECT count(*) FROM {}
WHERE place_id = %s""").format(pysql.Identifier(tablename))
with conn.cursor(row_factory=tuple_row) as cur:
assert cur.execute(sql, [place_ids[oid]]).fetchone()[0] == 0
@then(step_parse(r'W(?P<oid>\d+) expands to interpolation'),
converters={'oid': int})
def then_check_interpolation_table(db_conn, node_grid, place_ids, oid, datatable):
with db_conn.cursor() as cur:
cur.execute('SELECT count(*) FROM location_property_osmline WHERE osm_id = %s',
[oid])
assert cur.fetchone()[0] == len(datatable) - 1
converted = [['osm_id', 'startnumber', 'endnumber', 'linegeo!wkt']]
start_idx = datatable[0].index('start') if 'start' in datatable[0] else None
end_idx = datatable[0].index('end') if 'end' in datatable[0] else None
geom_idx = datatable[0].index('geometry') if 'geometry' in datatable[0] else None
converted = [['osm_id']]
for val, col in zip((start_idx, end_idx, geom_idx),
('startnumber', 'endnumber', 'linegeo!wkt')):
if val is not None:
converted[0].append(col)
for line in datatable[1:]:
convline = [oid]
for val in (start_idx, end_idx):
if val is not None:
convline.append(line[val])
if geom_idx is not None:
convline.append(line[geom_idx])
converted.append(convline)
_rewrite_placeid_field('parent_place_id', 'parent_place_id', converted, place_ids)
check_table_content(db_conn, 'location_property_osmline', converted, grid=node_grid)
@then(step_parse(r'W(?P<oid>\d+) expands to no interpolation'),
converters={'oid': int})
def then_check_interpolation_table_negative(db_conn, oid):
with db_conn.cursor() as cur:
cur.execute("""SELECT count(*) FROM location_property_osmline
WHERE osm_id = %s and startnumber is not null""",
[oid])
assert cur.fetchone()[0] == 0
scenarios('features/db')

View File

@@ -11,13 +11,16 @@ import asyncio
import random
import pytest
from pytest_bdd import scenarios, when, given
from pytest_bdd import scenarios, when, then, given
from pytest_bdd.parsers import re as step_parse
from nominatim_db import cli
from nominatim_db.tools.exec_utils import run_osm2pgsql
from nominatim_db.tools.database_import import load_data, create_table_triggers
from nominatim_db.tools.replication import run_osm2pgsql_updates
from utils.checks import check_table_content
@pytest.fixture
def osm2pgsql_options(def_config):
@@ -103,11 +106,4 @@ def check_place_content(db_conn, datatable, node_grid, table, exact):
check_table_content(db_conn, table, datatable, grid=node_grid, exact=bool(exact))
@then(step_parse('(?P<table>placex?) has no entry for '
r'(?P<osm_type>[NRW])(?P<osm_id>\d+)(?::(?P<osm_class>\S+))?'),
converters={'osm_id': int})
def check_place_missing_lines(db_conn, table, osm_type, osm_id, osm_class):
check_table_has_lines(db_conn, table, osm_type, osm_id, osm_class)
scenarios('features/osm2pgsql')

View File

@@ -12,9 +12,10 @@ import re
import math
from psycopg import sql as pysql
from psycopg.rows import dict_row, tuple_row
from psycopg.rows import dict_row
from .geometry_alias import ALIASES
COMPARATOR_TERMS = {
'exactly': lambda exp, act: exp == act,
'more than': lambda exp, act: act > exp,
@@ -26,11 +27,19 @@ def _pretty(obj):
return json.dumps(obj, sort_keys=True, indent=2)
def _pt_close(p1, p2):
return math.isclose(p1[0], p2[0], abs_tol=1e-07) \
and math.isclose(p1[1], p2[1], abs_tol=1e-07)
def within_box(value, expect):
coord = [float(x) for x in expect.split(',')]
if isinstance(value, str):
value = value.split(',')
if value.startswith('POINT'):
value = value[6:-1].split(' ')
else:
value = value.split(',')
value = list(map(float, value))
if len(value) == 2:
@@ -98,10 +107,10 @@ class ResultAttr:
self.subobj = self.subobj[sub]
def __eq__(self, other):
if not isinstance(other, str):
raise NotImplementedError()
# work around bad quoting by pytest-bdd
if not isinstance(other, str):
return self.subobj == other
other = other.replace(r'\\', '\\')
if self.fmt in COMPARISON_FUNCS:
@@ -148,18 +157,16 @@ class ResultAttr:
for pt in map(str.strip, m[2].split(','))]
if expected.startswith('country:'):
ccode = geom[8:].upper()
ccode = expected[8:].upper()
assert ccode in ALIASES, f"Geometry error: unknown country {ccode}"
return m[1] == 'POINT' and \
all(math.isclose(p1, p2) for p1, p2 in zip(converted[0], ALIASES[ccode]))
return m[1] == 'POINT' and _pt_close(converted[0], ALIASES[ccode])
if ',' not in expected:
return m[1] == 'POINT' and \
all(math.isclose(p1, p2) for p1, p2 in zip(converted[0], self.get_point(expected)))
return m[1] == 'POINT' and _pt_close(converted[0], self.get_point(expected))
if '(' not in expected:
return m[1] == 'LINESTRING' and \
all(math.isclose(p1[0], p2[0]) and math.isclose(p1[1], p2[1]) for p1, p2 in
all(_pt_close(p1, p2) for p1, p2 in
zip(converted, (self.get_point(p) for p in expected.split(','))))
if m[1] != 'POLYGON':
@@ -174,7 +181,7 @@ class ResultAttr:
"First and last point need to be the same")
for line in (exp_coords[:-1], exp_coords[-1:0:-1]):
for i in range(len(line)):
if all(math.isclose(p1[0], p2[0]) and math.isclose(p1[1], p2[1]) for p1, p2 in
if all(_pt_close(p1, p2) for p1, p2 in
zip(converted, line[i:] + line[:i])):
return True
@@ -199,7 +206,7 @@ def check_table_content(conn, tablename, data, grid=None, exact=False):
cols.extend(('osm_id', 'osm_type'))
elif '!' in col:
name, fmt = col.rsplit('!', 1)
if fmt == 'wkt':
if fmt in ('wkt', 'in_box'):
cols.append(f"ST_AsText({name}) as {name}")
else:
cols.append(name.split('+')[0])
@@ -215,7 +222,7 @@ def check_table_content(conn, tablename, data, grid=None, exact=False):
table_content += '\n' + str(row)
for i in lines:
for col, value in zip(data[0], data[i]):
if ResultAttr(row, col, grid=grid) != value:
if ResultAttr(row, col, grid=grid) != (None if value == '-' else value):
break
else:
lines.remove(i)
@@ -228,15 +235,3 @@ def check_table_content(conn, tablename, data, grid=None, exact=False):
+ '\n'.join(str(data[i]) for i in lines) \
+ "\nTable content:\n" \
+ table_content
def check_table_has_lines(conn, tablename, osm_type, osm_id, osm_class):
sql = pysql.SQL("""SELECT count(*) FROM {}
WHERE osm_type = %s and osm_id = %s""").format(pysql.Identifier(tablename))
params = [osm_type, int(osm_id)]
if osm_class:
sql += pysql.SQL(' AND class = %s')
params.append(osm_class)
with conn.cursor(row_factory=tuple_row) as cur:
assert cur.execute(sql, params).fetchone()[0] == 0

View File

@@ -13,7 +13,7 @@ from psycopg import sql as pysql
from nominatim_db.tools.database_import import setup_database_skeleton, create_tables, \
create_partition_tables, create_search_indices
from nominatim_db.data.country_info import setup_country_tables
from nominatim_db.data.country_info import setup_country_tables, create_country_names
from nominatim_db.tools.refresh import create_functions, load_address_levels_from_config
from nominatim_db.tools.exec_utils import run_osm2pgsql
from nominatim_db.tokenizer import factory as tokenizer_factory
@@ -98,4 +98,5 @@ class DBManager:
create_functions(conn, config, enable_diff_updates=False)
asyncio.run(create_search_indices(conn, config))
tokenizer_factory.create_tokenizer(config)
tokenizer = tokenizer_factory.create_tokenizer(config)
create_country_names(conn, tokenizer)

View File

@@ -38,7 +38,7 @@ class Grid:
"""
value = value.strip()
if ' ' in value:
return [int(v) for v in value.split(' ', 1)]
return [float(v) for v in value.split(' ', 1)]
return self.grid.get(value)

View File

@@ -0,0 +1,143 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# This file is part of Nominatim. (https://nominatim.org)
#
# Copyright (C) 2025 by the Nominatim developer community.
# For a full list of authors see the git log.
"""
Helper classes for filling the place table.
"""
import random
import string
from .geometry_alias import ALIASES
class PlaceColumn:
""" Helper class to collect contents from a BDD table row and
insert it into the place table.
"""
def __init__(self, grid=None):
self.columns = {'admin_level': 15}
self.grid = grid
self.geometry = None
def add_row(self, headings, row, force_name):
""" Parse the content from the given behave row as place column data.
"""
for name, value in zip(headings, row):
self._add(name, value)
assert 'osm_type' in self.columns, "osm column missing"
if force_name and 'name' not in self.columns:
self._add_hstore(
'name',
'name',
''.join(random.choices(string.printable, k=random.randrange(30))),
)
return self
def _add(self, key, value):
if hasattr(self, '_set_key_' + key):
getattr(self, '_set_key_' + key)(value)
elif key.startswith('name+'):
self._add_hstore('name', key[5:], value)
elif key.startswith('extra+'):
self._add_hstore('extratags', key[6:], value)
elif key.startswith('addr+'):
self._add_hstore('address', key[5:], value)
elif key in ('name', 'address', 'extratags'):
self.columns[key] = eval('{' + value + '}')
else:
assert key in ('class', 'type'), "Unknown column '{}'.".format(key)
self.columns[key] = None if value == '' else value
def _set_key_name(self, value):
self._add_hstore('name', 'name', value)
def _set_key_osm(self, value):
assert value[0] in 'NRW' and value[1:].isdigit(), \
"OSM id needs to be of format <NRW><id>."
self.columns['osm_type'] = value[0]
self.columns['osm_id'] = int(value[1:])
def _set_key_admin(self, value):
self.columns['admin_level'] = int(value)
def _set_key_housenr(self, value):
if value:
self._add_hstore('address', 'housenumber', value)
def _set_key_postcode(self, value):
if value:
self._add_hstore('address', 'postcode', value)
def _set_key_street(self, value):
if value:
self._add_hstore('address', 'street', value)
def _set_key_addr_place(self, value):
if value:
self._add_hstore('address', 'place', value)
def _set_key_country(self, value):
if value:
self._add_hstore('address', 'country', value)
def _set_key_geometry(self, value):
if value.startswith('country:'):
ccode = value[8:].upper()
self.geometry = "ST_SetSRID(ST_Point({}, {}), 4326)".format(*ALIASES[ccode])
elif ',' not in value:
if self.grid:
pt = self.grid.parse_point(value)
else:
pt = value.split(' ')
self.geometry = f"ST_SetSRID(ST_Point({pt[0]}, {pt[1]}), 4326)"
elif '(' not in value:
if self.grid:
coords = ','.join(' '.join(f"{p:.7f}" for p in pt)
for pt in self.grid.parse_line(value))
else:
coords = value
self.geometry = f"'srid=4326;LINESTRING({coords})'::geometry"
else:
if self.grid:
coords = ','.join(' '.join(f"{p:.7f}" for p in pt)
for pt in self.grid.parse_line(value[1:-1]))
else:
coords = value[1:-1]
self.geometry = f"'srid=4326;POLYGON(({coords}))'::geometry"
def _add_hstore(self, column, key, value):
if column in self.columns:
self.columns[column][key] = value
else:
self.columns[column] = {key: value}
def db_delete(self, cursor):
""" Issue a delete for the given OSM object.
"""
cursor.execute('DELETE FROM place WHERE osm_type = %s and osm_id = %s',
(self.columns['osm_type'], self.columns['osm_id']))
def db_insert(self, cursor):
""" Insert the collected data into the database.
"""
if self.columns['osm_type'] == 'N' and self.geometry is None:
pt = self.grid.get(str(self.columns['osm_id'])) if self.grid else None
if pt is None:
pt = (random.uniform(-180, 180), random.uniform(-90, 90))
self.geometry = "ST_SetSRID(ST_Point({}, {}), 4326)".format(*pt)
else:
assert self.geometry is not None, "Geometry missing"
query = 'INSERT INTO place ({}, geometry) values({}, {})'.format(
','.join(self.columns.keys()),
','.join(['%s' for x in range(len(self.columns))]),
self.geometry)
cursor.execute(query, list(self.columns.values()))