forked from hans/Nominatim
remove usage of behave
This commit is contained in:
6
.github/workflows/ci-tests.yml
vendored
6
.github/workflows/ci-tests.yml
vendored
@@ -94,7 +94,7 @@ jobs:
|
||||
if: matrix.dependencies == 'pip'
|
||||
|
||||
- name: Install test prerequisites
|
||||
run: ./venv/bin/pip install behave==1.2.6 pytest-bdd
|
||||
run: ./venv/bin/pip install pytest-bdd
|
||||
|
||||
- name: Install latest flake8
|
||||
run: ./venv/bin/pip install -U flake8
|
||||
@@ -118,9 +118,7 @@ jobs:
|
||||
|
||||
- name: BDD tests
|
||||
run: |
|
||||
../venv/bin/python -m pytest test/bdd
|
||||
cd test/bdd
|
||||
../../../venv/bin/python -m behave -DREMOVE_TEMPLATE=1 --format=progress3 db osm2pgsql
|
||||
../venv/bin/python -m pytest test/bdd --nominatim-purge
|
||||
working-directory: Nominatim
|
||||
|
||||
install:
|
||||
|
||||
3
Makefile
3
Makefile
@@ -27,8 +27,7 @@ lint:
|
||||
flake8 src test/python test/bdd
|
||||
|
||||
bdd:
|
||||
pytest test/bdd
|
||||
cd test/bdd; behave -DREMOVE_TEMPLATE=1 db osm2pgsql
|
||||
pytest test/bdd --nominatim-purge
|
||||
|
||||
# Documentation
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
all: bdd python
|
||||
|
||||
bdd:
|
||||
cd bdd && behave -DREMOVE_TEMPLATE=1
|
||||
|
||||
python:
|
||||
pytest python
|
||||
|
||||
|
||||
.PHONY: bdd python
|
||||
@@ -1,3 +0,0 @@
|
||||
[behave]
|
||||
show_skipped=False
|
||||
default_tags=~@Fail
|
||||
@@ -1,565 +0,0 @@
|
||||
@DB
|
||||
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
|
||||
| object | address | fromarea |
|
||||
| N1 | N3 | False |
|
||||
Then place_addressline doesn't contain
|
||||
| object | address |
|
||||
| N1 | N2 |
|
||||
When sending search query "Square"
|
||||
Then results contain
|
||||
| osm | 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
|
||||
| object | address | isaddress | cached_rank_address |
|
||||
| N1 | R1 | True | 16 |
|
||||
And place_addressline doesn't contain
|
||||
| object | address |
|
||||
| N1 | N2 |
|
||||
|
||||
|
||||
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
|
||||
| object | address | cached_rank_address |
|
||||
| W1 | W10 | 10 |
|
||||
Then place_addressline doesn't contain
|
||||
| object | address |
|
||||
| W1 | W11 |
|
||||
|
||||
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
|
||||
| object | address | cached_rank_address |
|
||||
| W1 | W10 | 10 |
|
||||
Then place_addressline doesn't contain
|
||||
| object | address |
|
||||
| W1 | W11 |
|
||||
|
||||
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 doesn't contain
|
||||
| object | address |
|
||||
| W1 | W10 |
|
||||
|
||||
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 doesn't contain
|
||||
| object | address |
|
||||
| W93 | W22 |
|
||||
|
||||
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 doesn't contain
|
||||
| object | address |
|
||||
| W1 | W2 |
|
||||
|
||||
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
|
||||
| object | address | isaddress |
|
||||
| W1 | R1 | True |
|
||||
| W1 | R2 | False |
|
||||
| W2 | R2 | True |
|
||||
And place_addressline doesn't contain
|
||||
| object | address |
|
||||
| W2 | R1 |
|
||||
|
||||
|
||||
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
|
||||
| object | address | isaddress |
|
||||
| W1 | R2 | True |
|
||||
| N1 | R1 | True |
|
||||
And place_addressline doesn't contain
|
||||
| object | address |
|
||||
| W1 | R1 |
|
||||
When sending search query "Bolder"
|
||||
Then results contain
|
||||
| osm | 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
|
||||
| object | address | isaddress |
|
||||
| W1 | R1 | True |
|
||||
And place_addressline doesn't contain
|
||||
| object | address |
|
||||
| N1 | R1 |
|
||||
When sending search query "Bolder"
|
||||
Then results contain
|
||||
| osm | 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
|
||||
| object | address | isaddress |
|
||||
| W1 | R1 | True |
|
||||
| W1 | R2 | False |
|
||||
And place_addressline doesn't contain
|
||||
| object | address |
|
||||
| N1 | R1 |
|
||||
When sending search query "Bolder"
|
||||
Then results contain
|
||||
| osm | 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
|
||||
| object | address | isaddress |
|
||||
| W1 | R1 | False |
|
||||
| W1 | R2 | True |
|
||||
And place_addressline doesn't contain
|
||||
| object | address |
|
||||
| N1 | R1 |
|
||||
| N2 | R2 |
|
||||
When sending search query "Bolder"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Bolder, Wonderway, Left |
|
||||
When sending search query "Leftside"
|
||||
Then results contain
|
||||
| osm | 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
|
||||
| object | address | isaddress |
|
||||
| W1 | R1 | True |
|
||||
| W1 | R2 | False |
|
||||
And place_addressline doesn't contain
|
||||
| object | address |
|
||||
| N1 | R1 |
|
||||
| N2 | R2 |
|
||||
When sending search query "Bolder"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Bolder, Wonderway, Left |
|
||||
When sending search query "Leftside"
|
||||
Then results contain
|
||||
| osm | 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
|
||||
| object | address | isaddress |
|
||||
| W1 | R1 | True |
|
||||
| W1 | R2 | False |
|
||||
And place_addressline doesn't contain
|
||||
| object | address |
|
||||
| N1 | R1 |
|
||||
| N2 | R2 |
|
||||
When sending search query "Bolder"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Bolder, Wonderway, Left |
|
||||
When sending search query "Leftside"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N2 | Leftside, Wonderway, Left |
|
||||
|
||||
|
||||
Scenario: addr:* tags always match the closer area
|
||||
Given the grid
|
||||
| 1 | | | | 2 | | 5 |
|
||||
| | | | | | | |
|
||||
| | 10| 11| | | | |
|
||||
| 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 | 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 doesn't contain
|
||||
| object | address |
|
||||
| W1 | R2 |
|
||||
|
||||
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 sending search query "1, Royal Terrace Gardens"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
@@ -1,92 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "Wenig, Loudou"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Wenig, Deutschland |
|
||||
When sending search query "Wenig"
|
||||
| accept-language |
|
||||
| xy,en |
|
||||
Then results contain
|
||||
| osm | 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 sending search query "Wenig"
|
||||
| accept-language |
|
||||
| xy,en |
|
||||
Then results contain
|
||||
| osm | 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 sending search query "Ingb"
|
||||
| accept-language |
|
||||
| en,de |
|
||||
Then results contain
|
||||
| osm | 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 |
|
||||
@@ -1,617 +0,0 @@
|
||||
@DB
|
||||
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 | 9,8 |
|
||||
|
||||
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 sending search query "16 Cloud Street"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N4 |
|
||||
When sending search query "14 Cloud Street"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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 sending search query "16 Cloud Street"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N4 |
|
||||
When sending search query "14 Cloud Street"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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.963016 -37.762946 |
|
||||
| 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.000016 0,0.00002 0,0.000033 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 sending v1/reverse at 1,1
|
||||
Then results contain
|
||||
| ID | osm | type | display_name |
|
||||
| 0 | 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 |
|
||||
@@ -1,331 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "rhein"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "rhein"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R1 |
|
||||
| 1 | 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 sending search query "rhein2"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 | 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 sending search query ""
|
||||
| city |
|
||||
| Berlin |
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R13 |
|
||||
When sending search query ""
|
||||
| state |
|
||||
| Berlin |
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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 sending search query ""
|
||||
| state |
|
||||
| Berlin |
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R13 |
|
||||
When sending search query ""
|
||||
| city |
|
||||
| Berlin |
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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 |
|
||||
| R13 | in geometry |
|
||||
|
||||
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 |
|
||||
| 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 |
|
||||
|
||||
|
||||
@Fail
|
||||
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 |
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
@DB
|
||||
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 | 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:fi | geometry |
|
||||
| N1 | place | locality | german | finnish | country:de |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | country_code | 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: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:fi | name+name:de | geometry |
|
||||
| N1 | place | locality | german | finnish | local | country:de |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | country_code | 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 |
|
||||
| N1 | place | hamlet | <name> |
|
||||
When importing
|
||||
And sending search query "<name>"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "münster"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "muenster"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "munster"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Köln"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N2 |
|
||||
When sending search query "Koeln"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N2 |
|
||||
When sending search query "Koln"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N2 |
|
||||
When sending search query "gräfenroda"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N3 |
|
||||
When sending search query "graefenroda"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N3 |
|
||||
When sending search query "grafenroda"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N3 |
|
||||
@@ -1,652 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "4 galoo"
|
||||
Then results contain
|
||||
| ID | osm | display_name |
|
||||
| 0 | N1 | 4, galoo, 12345, Deutschland |
|
||||
When sending search query "5 galoo"
|
||||
Then results contain
|
||||
| ID | osm | display_name |
|
||||
| 0 | 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 sending geocodejson search query "3, foo" with address
|
||||
Then results contain
|
||||
| housenumber |
|
||||
| 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 |
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
@DB
|
||||
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 | addr+country | 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 |
|
||||
@@ -1,210 +0,0 @@
|
||||
@DB
|
||||
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 | postcode | geometry |
|
||||
| de | 01982 | country:de |
|
||||
|
||||
|
||||
@Fail
|
||||
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 | 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
|
||||
| country | postcode | geometry |
|
||||
When sending search query "111, 01982 Null Island"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N34 | 111, Null Island, 01982 |
|
||||
@@ -1,300 +0,0 @@
|
||||
@DB
|
||||
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
|
||||
| object | address | cached_rank_address |
|
||||
| N20 | R22 | 16 |
|
||||
Then place_addressline doesn't contain
|
||||
| object | address |
|
||||
| N20 | R21 |
|
||||
| N20 | R23 |
|
||||
|
||||
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 |
|
||||
@@ -1,428 +0,0 @@
|
||||
@DB
|
||||
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 |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | name_vector |
|
||||
| N1 | #New York, #Big Apple |
|
||||
|
||||
Scenario: Comma-separated names appear as a single full name
|
||||
Given the places
|
||||
| osm | class | type | name+alt_name |
|
||||
| N1 | place | city | New York, Big Apple |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | name_vector |
|
||||
| N1 | #New York Big Apple |
|
||||
|
||||
Scenario: Name parts before brackets appear as full names
|
||||
Given the places
|
||||
| osm | class | type | name+name |
|
||||
| N1 | place | city | Halle (Saale) |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | name_vector |
|
||||
| N1 | #Halle Saale, #Halle |
|
||||
|
||||
Scenario: Unnamed POIs have no search entry
|
||||
Given the grid
|
||||
| | 1 | | |
|
||||
| 10 | | | 11 |
|
||||
And the places
|
||||
| osm | class | type |
|
||||
| N1 | place | house |
|
||||
And the named places
|
||||
| osm | class | type | geometry |
|
||||
| W1 | highway | residential | 10,11 |
|
||||
When importing
|
||||
Then search_name has no entry for N1
|
||||
|
||||
Scenario: Unnamed POI has a search entry when it has unknown 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 | geometry |
|
||||
| W1 | highway | residential | Rose Street | 10,11 |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | nameaddress_vector |
|
||||
| N1 | #Rose Street, Walltown |
|
||||
When sending search query "23 Rose Street, Walltown"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When sending search query "Walltown, Rose Street 23"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When sending search query "Rose Street 23, Walltown"
|
||||
Then results contain
|
||||
| osm | 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
|
||||
Then search_name contains
|
||||
| object | nameaddress_vector |
|
||||
| N1 | #Rose Street, rose, Little, Big, Town |
|
||||
When sending search query "23 Rose Street, Little Big Town"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When sending search query "Rose Street 23, Little Big Town"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When sending search query "Little big Town, Rose Street 23"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
|
||||
Scenario: Unnamed POI has no search entry 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
|
||||
Then search_name has no entry for N1
|
||||
When sending search query "23 Rose Street, Walltown"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
|
||||
Scenario: Unnamed POI must have a house number to get a search entry
|
||||
Given the grid
|
||||
| | 1 | | |
|
||||
| 10 | | | 11 |
|
||||
And the places
|
||||
| osm | class | type | addr+city |
|
||||
| N1 | place | house | Walltown |
|
||||
And the places
|
||||
| osm | class | type | name+name | geometry |
|
||||
| W1 | highway | residential | Rose Street | 10,11 |
|
||||
When importing
|
||||
Then search_name has no entry for N1
|
||||
|
||||
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 sending search query "23 Rose Street"
|
||||
Then exactly 1 results are returned
|
||||
And results contain
|
||||
| osm | display_name |
|
||||
| W1 | Rose Street, Strange Town |
|
||||
When sending search query "23 Walltown, Strange Town"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Walltown, Strange Town |
|
||||
When sending search query "Walltown 23, Strange Town"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Walltown, Strange Town |
|
||||
When sending search query "Strange Town, Walltown 23"
|
||||
Then results contain
|
||||
| osm | 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 sending search query "23 Walltown, Strange Town"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
When sending search query "Walltown 23, Strange Town"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
When sending search query "Strange Town, Walltown 23"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
When sending search query "Strange Town, Walltown 23, Blue house"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
When sending search query "Strange Town, Walltown, Blue house"
|
||||
Then results contain
|
||||
| osm | 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 sending search query "23 Moon Sun, Strange Town"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Blue house, 23, Moon sun, Strange Town |
|
||||
When sending search query "Blue house, Moon Sun, Strange Town"
|
||||
Then results contain
|
||||
| osm | 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 sending search query "23 Rose Street, Walltown"
|
||||
Then exactly 1 result is returned
|
||||
And results contain
|
||||
| osm | display_name |
|
||||
| W1 | Rose Street, Strange Town |
|
||||
When sending search query "23 Walltown"
|
||||
Then exactly 1 result is returned
|
||||
And results contain
|
||||
| osm | 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
|
||||
Then search_name has no entry for N1
|
||||
When sending search query "23 Rose Street"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When sending search query "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
|
||||
Then search_name has no entry for N1
|
||||
When sending search query "23 Rose Street"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When sending search query "23 Lily Street"
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Named POIs get unknown address tags added in the search_name table
|
||||
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
|
||||
Then search_name contains
|
||||
| object | name_vector | nameaddress_vector |
|
||||
| N1 | #Green Moss | #Rose Street, Walltown |
|
||||
When sending search query "Green Moss, Rose Street, Walltown"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
When sending search query "Green Moss, 26, Rose Street, Walltown"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
When sending search query "26, Rose Street, Walltown"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
When sending search query "Rose Street 26, Walltown"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
When sending search query "Walltown, Rose Street 26"
|
||||
Then results contain
|
||||
| osm | 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 sending search query "Green Moss, Rose Street, Walltown"
|
||||
Then exactly 0 result is returned
|
||||
When sending search query "Green Moss, Walltown"
|
||||
Then results contain
|
||||
| osm | 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
|
||||
Then search_name contains
|
||||
| object | name_vector | nameaddress_vector |
|
||||
| N1 | foo | #the road |
|
||||
|
||||
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 named places
|
||||
| osm | class | type | addr+city | addr+municipality | addr+suburb | geometry |
|
||||
| W1 | highway | service | bonn | New York | Smalltown | 10,11 |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | nameaddress_vector |
|
||||
| W1 | bonn, new, york, smalltown |
|
||||
|
||||
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
|
||||
Then search_name contains
|
||||
| object | nameaddress_vector |
|
||||
| W1 | nandu |
|
||||
|
||||
Scenario: addr:postcode is not added to the address terms
|
||||
Given the grid with origin DE
|
||||
| | 1 | | |
|
||||
| 10 | | | 11 |
|
||||
And the places
|
||||
| osm | class | type | name+ref |
|
||||
| N1 | place | state | 12345 |
|
||||
And the named places
|
||||
| osm | class | type | addr+postcode | geometry |
|
||||
| W1 | highway | residential | 12345 | 10,11 |
|
||||
When importing
|
||||
Then search_name contains not
|
||||
| object | nameaddress_vector |
|
||||
| W1 | 12345 |
|
||||
|
||||
Scenario: a linked place does not show up in search name
|
||||
Given the 0.01 grid
|
||||
| 10 | | 11 |
|
||||
| | 2 | |
|
||||
| 13 | | 12 |
|
||||
Given the named places
|
||||
| osm | class | type | admin | geometry |
|
||||
| R13 | boundary | administrative | 9 | (10,11,12,13,10) |
|
||||
And the named places
|
||||
| osm | class | type |
|
||||
| N2 | place | city |
|
||||
And the relations
|
||||
| id | members | tags+type |
|
||||
| 13 | N2:label | boundary |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | linked_place_id |
|
||||
| N2 | R13 |
|
||||
And search_name has no entry for N2
|
||||
|
||||
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 |
|
||||
And search_name has no entry for W1
|
||||
And search_name has no entry for W2
|
||||
@@ -1,321 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "45, North Road"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "North Road 45"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "45, North Road"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "North Road ④⑤"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "North Road 𑁪𑁫"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "2 Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "4 Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "12 Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "2A Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "2 a Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "2-A Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Multistr 2 A"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "34-10 Chester St"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "34/10 Chester St"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "34 10 Chester St"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "3410 Chester St"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "Rue Paris 45bis"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Rue Paris 45 BIS"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Rue Paris 45BIS"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Rue Paris 45 bis"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "Rue du Berger 45ter"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Rue du Berger 45 TER"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Rue du Berger 45TER"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Rue du Berger 45 ter"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "501-H 1 Herengracht"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "501H-1 Herengracht"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "501H1 Herengracht"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "501-H1 Herengracht"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "Голубинская улица 55к3"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Голубинская улица 55 k3"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending search query "Голубинская улица 55 к-3"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "Chester St Warring"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "Ringstr 12"
|
||||
Then results contain
|
||||
| osm |
|
||||
| W10 |
|
||||
When sending search query "Ringstr 13"
|
||||
Then results contain
|
||||
| osm |
|
||||
| W20 |
|
||||
@@ -1,58 +0,0 @@
|
||||
@DB
|
||||
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 sending v1/reverse N2
|
||||
Then results contain
|
||||
| ID | display_name |
|
||||
| 0 | 3, Nickway |
|
||||
When sending search query "Nickway 3"
|
||||
Then results contain
|
||||
| osm | 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 sending v1/reverse N2
|
||||
Then results contain
|
||||
| ID | display_name | centroid |
|
||||
| 0 | 10, Nickway | 2 |
|
||||
When sending search query "Nickway 10"
|
||||
Then results contain
|
||||
| osm | display_name | centroid |
|
||||
| W1 | 10, Nickway | 2 |
|
||||
@@ -1,29 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "2丁目 6-2"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N3 |
|
||||
@@ -1,64 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "Vario"
|
||||
| namedetails |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm | display_name | namedetails |
|
||||
| R13 | Garbo | "name": "Garbo", "name:it": "Vario" |
|
||||
When sending search query "Vario"
|
||||
| accept-language |
|
||||
| it |
|
||||
Then results contain
|
||||
| osm | 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 sending search query "Vario"
|
||||
| namedetails |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm | display_name | namedetails |
|
||||
| R13 | Garbo | "name": "Garbo", "_place_name": "Vario" |
|
||||
When sending search query "Garbo"
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| R13 | Garbo |
|
||||
@@ -1,226 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "Речицкий район"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "Refugio de montaña"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N2 |
|
||||
When sending search query "高槻市"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N3 |
|
||||
When sending search query "الدوحة"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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 sending search query "FooBar"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "foobar"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "fOObar"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "FOOBAR"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
|
||||
Scenario: Multiple spaces in name
|
||||
Given the places
|
||||
| osm | class | type | name |
|
||||
| N1 | place | locality | one two three |
|
||||
When importing
|
||||
When sending search query "one two three"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "one two three"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "one two three"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query " one two three"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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 sending search query "Jim-Knopf-Str"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "Jim Knopf-Str"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "Jim Knopf Str"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "Jim/Knopf-Str"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "Jim-Knopfstr"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N1 |
|
||||
When sending search query "Smith/Weston"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N2 |
|
||||
When sending search query "Smith Weston"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N2 |
|
||||
When sending search query "Smith-Weston"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N2 |
|
||||
When sending search query "space mountain"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N3 |
|
||||
When sending search query "space-mountain"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N3 |
|
||||
When sending search query "space/mountain"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N3 |
|
||||
When sending search query "space\mountain"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N3 |
|
||||
When sending search query "space(mountain)"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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 sending search query "landuse1"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R1 |
|
||||
When sending search query "landuse2"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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 sending search query "123-45"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | 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 sending search query "Main St <nr>"
|
||||
Then results contain
|
||||
| osm | 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 sending search query "Main St <nr>"
|
||||
Then results contain
|
||||
| ID | osm | display_name |
|
||||
| 0 | 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 |
|
||||
@@ -1,110 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "399174"
|
||||
Then results contain
|
||||
| ID | type | display_name |
|
||||
| 0 | 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 sending search query "3993 DX"
|
||||
Then results contain
|
||||
| ID | type | display_name |
|
||||
| 0 | postcode | 3993 DX, Nederland |
|
||||
When sending search query "3993dx"
|
||||
Then results contain
|
||||
| ID | type | display_name |
|
||||
| 0 | 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 sending search query "399174"
|
||||
Then results contain
|
||||
| ID | type | display_name |
|
||||
| 0 | 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 sending search query "675"
|
||||
Then results contain
|
||||
| ID | type | display_name |
|
||||
| 0 | postcode | AD675, Andorra |
|
||||
When sending search query "AD675"
|
||||
Then results contain
|
||||
| ID | type | display_name |
|
||||
| 0 | 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 | postcode | geometry |
|
||||
| gb | EH4 7EA | country:gb |
|
||||
| gb | E4 7EA | country:gb |
|
||||
When sending search query "EH4 7EA"
|
||||
Then results contain
|
||||
| type | display_name |
|
||||
| postcode | EH4 7EA, United Kingdom |
|
||||
When sending search query "E4 7EA"
|
||||
Then results contain
|
||||
| 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 | postcode |
|
||||
| de | 12345 |
|
||||
When sending search query "12345, de"
|
||||
Then results contain
|
||||
| osm |
|
||||
| R23 |
|
||||
@@ -1,22 +0,0 @@
|
||||
@DB
|
||||
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 sending v1/reverse at 1.0001,1.0001
|
||||
Then results contain
|
||||
| osm |
|
||||
| N1 |
|
||||
When sending v1/reverse at 1.0003,1.0001
|
||||
Then results contain
|
||||
| osm |
|
||||
| W1 |
|
||||
@@ -1,108 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "Foo"
|
||||
Then results contain
|
||||
| ID | osm | category | type | centroid |
|
||||
| 0 | N1 | place | village | 10 -10 |
|
||||
|
||||
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 sending search query "12345"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R1 |
|
||||
When updating places
|
||||
| osm | class | type | postcode | geometry |
|
||||
| R1 | boundary | postal_code | 54321 | (1,2,3,4,1) |
|
||||
And sending search query "12345"
|
||||
Then exactly 0 results are returned
|
||||
When sending search query "54321"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R1 |
|
||||
|
||||
# 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 sending json search query "Bean" with address
|
||||
Then result addresses contain
|
||||
| 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 sending search query "Wood Street 45"
|
||||
Then exactly 0 results are returned
|
||||
When sending search query "Red Way 34"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "Wood Street"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "<city>, <state>"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N2 |
|
||||
When sending search query "<city>, <ref>"
|
||||
| accept-language |
|
||||
| en |
|
||||
Then results contain
|
||||
| osm |
|
||||
| N2 |
|
||||
|
||||
Examples:
|
||||
| city | state | ref |
|
||||
| Chicago | Illinois | IL |
|
||||
| Auburn | Alabama | AL |
|
||||
| New Orleans | Louisiana | LA |
|
||||
@@ -1,109 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "Wenig, Loudou"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "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 sending search query "Wenig, Loudou"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "Wenig, Loudou"
|
||||
Then exactly 0 results are returned
|
||||
When sending search query "Wenig"
|
||||
| accept-language |
|
||||
| xy,en |
|
||||
Then results contain
|
||||
| osm | 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 sending search query "Wenig, Germany"
|
||||
Then results contain
|
||||
| osm |
|
||||
| N10 |
|
||||
When sending search query "Wenig, de"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "Wenig, Germany"
|
||||
| accept-language |
|
||||
| en,de |
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N10 | Wenig, Lilly |
|
||||
When sending search query "Wenig, de"
|
||||
| accept-language |
|
||||
| en,de |
|
||||
Then results contain
|
||||
| osm | 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 sending search query "Wenig, Loudou"
|
||||
| accept-language |
|
||||
| de,en |
|
||||
Then results contain
|
||||
| osm | 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 sending search query "Wenig, Loudou"
|
||||
Then exactly 0 results are returned
|
||||
When sending search query "Wenig"
|
||||
| accept-language |
|
||||
| de,en |
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N10 | Wenig, Deutschland |
|
||||
|
||||
@@ -1,419 +0,0 @@
|
||||
@DB
|
||||
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 |
|
||||
|
||||
@Fail
|
||||
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
|
||||
|
||||
@@ -1,341 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "foo"
|
||||
| dups |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "foo"
|
||||
| dups |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "foo"
|
||||
| dups |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm |
|
||||
| R1 |
|
||||
When marking for delete R1
|
||||
Then placex contains
|
||||
| object | linked_place_id |
|
||||
| N1 | - |
|
||||
When sending search query "foo"
|
||||
| dups |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "foo"
|
||||
| dups |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "foo"
|
||||
| dups |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "foo"
|
||||
| dups |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "foo"
|
||||
| dups |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "greeny"
|
||||
Then results contain
|
||||
| osm |
|
||||
| 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 sending search query "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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| R1 | 'linked_place' : 'city' |
|
||||
When updating places
|
||||
| osm | class | type | name |
|
||||
| N1 | place | town | foo |
|
||||
Then placex contains
|
||||
| object | extratags |
|
||||
| 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 |
|
||||
@@ -1,21 +0,0 @@
|
||||
@DB
|
||||
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 sending search query "123-45"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R1 |
|
||||
When updating places
|
||||
| osm | class | type | geometry |
|
||||
| R1 | boundary | postal_code | (1,2,3,4,1) |
|
||||
Then placex has no entry for R1
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
@DB
|
||||
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.
|
||||
@Fail
|
||||
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 |
|
||||
@@ -1,119 +0,0 @@
|
||||
@DB
|
||||
Feature: Update of postcode
|
||||
Tests for updating of data related to postcodes
|
||||
|
||||
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 | postcode | geometry |
|
||||
| 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 | postcode | geometry |
|
||||
| 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 | postcode | geometry |
|
||||
| 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 | postcode | geometry |
|
||||
| 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 | postcode | geometry |
|
||||
| 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 |
|
||||
| N34 | 1 | country:de|
|
||||
And place contains exactly
|
||||
| object | class | type |
|
||||
| N34 | place | house |
|
||||
When updating postcodes
|
||||
Then location_postcode contains exactly
|
||||
| country | postcode | geometry |
|
||||
| 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 |
|
||||
| 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
|
||||
| object | class | type |
|
||||
| N34 | place | postcode |
|
||||
When updating postcodes
|
||||
Then location_postcode contains exactly
|
||||
| country | postcode | geometry |
|
||||
| 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 named places
|
||||
| osm | class | type | addr+postcode | geometry |
|
||||
| N9 | place | postcode | 12345 | 9 |
|
||||
When importing
|
||||
And updating postcodes
|
||||
Then location_postcode contains exactly
|
||||
| country | postcode | geometry | parent_place_id |
|
||||
| de | 12345 | 9 | R2 |
|
||||
When marking for delete R2
|
||||
Then location_postcode contains exactly
|
||||
| country | postcode | geometry | parent_place_id |
|
||||
| de | 12345 | 9 | R1 |
|
||||
@@ -1,116 +0,0 @@
|
||||
@DB
|
||||
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,R2,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 |
|
||||
| N3 | shop | toys | 1 -1 |
|
||||
When updating places
|
||||
| osm | class | type | geometry |
|
||||
| N3 | shop | grocery | 1 -1 |
|
||||
Then placex contains
|
||||
| object | class | type | centroid |
|
||||
| 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 |
|
||||
@@ -1,64 +0,0 @@
|
||||
# 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.
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from behave import * # noqa
|
||||
|
||||
sys.path.insert(1, str(Path(__file__, '..', '..', '..', 'src').resolve()))
|
||||
|
||||
from steps.geometry_factory import GeometryFactory # noqa: E402
|
||||
from steps.nominatim_environment import NominatimEnvironment # noqa: E402
|
||||
|
||||
TEST_BASE_DIR = Path(__file__, '..', '..').resolve()
|
||||
|
||||
userconfig = {
|
||||
'REMOVE_TEMPLATE': False,
|
||||
'KEEP_TEST_DB': False,
|
||||
'DB_HOST': None,
|
||||
'DB_PORT': None,
|
||||
'DB_USER': None,
|
||||
'DB_PASS': None,
|
||||
'TEMPLATE_DB': 'test_template_nominatim',
|
||||
'TEST_DB': 'test_nominatim',
|
||||
'API_TEST_DB': 'test_api_nominatim',
|
||||
'API_TEST_FILE': TEST_BASE_DIR / 'testdb' / 'apidb-test-data.pbf',
|
||||
'TOKENIZER': None, # Test with a custom tokenizer
|
||||
'STYLE': 'extratags',
|
||||
'API_ENGINE': 'falcon'
|
||||
}
|
||||
|
||||
|
||||
use_step_matcher("re") # noqa: F405
|
||||
|
||||
|
||||
def before_all(context):
|
||||
# logging setup
|
||||
context.config.setup_logging()
|
||||
# set up -D options
|
||||
for k, v in userconfig.items():
|
||||
context.config.userdata.setdefault(k, v)
|
||||
# Nominatim test setup
|
||||
context.nominatim = NominatimEnvironment(context.config.userdata)
|
||||
context.osm = GeometryFactory()
|
||||
|
||||
|
||||
def before_scenario(context, scenario):
|
||||
if 'SQLITE' not in context.tags \
|
||||
and context.config.userdata['API_TEST_DB'].startswith('sqlite:'):
|
||||
context.scenario.skip("Not usable with Sqlite database.")
|
||||
elif 'DB' in context.tags:
|
||||
context.nominatim.setup_db(context)
|
||||
elif 'APIDB' in context.tags:
|
||||
context.nominatim.setup_api_db()
|
||||
elif 'UNKNOWNDB' in context.tags:
|
||||
context.nominatim.setup_unknown_db()
|
||||
|
||||
|
||||
def after_scenario(context, scenario):
|
||||
if 'DB' in context.tags:
|
||||
context.nominatim.teardown_db(context)
|
||||
@@ -1,99 +0,0 @@
|
||||
# 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.
|
||||
"""
|
||||
Collection of assertion functions used for the steps.
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
import re
|
||||
|
||||
|
||||
OSM_TYPE = {'N': 'node', 'W': 'way', 'R': 'relation',
|
||||
'n': 'node', 'w': 'way', 'r': 'relation',
|
||||
'node': 'n', 'way': 'w', 'relation': 'r'}
|
||||
|
||||
|
||||
class OsmType:
|
||||
""" Compares an OSM type, accepting both N/R/W and node/way/relation.
|
||||
"""
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __eq__(self, other):
|
||||
return other == self.value or other == OSM_TYPE[self.value]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.value} or {OSM_TYPE[self.value]}"
|
||||
|
||||
|
||||
class Field:
|
||||
""" Generic comparator for fields, which looks at the type of the
|
||||
value compared.
|
||||
"""
|
||||
def __init__(self, value, **extra_args):
|
||||
self.value = value
|
||||
self.extra_args = extra_args
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(self.value, float):
|
||||
return math.isclose(self.value, float(other), **self.extra_args)
|
||||
|
||||
if self.value.startswith('^'):
|
||||
return re.fullmatch(self.value, str(other))
|
||||
|
||||
if isinstance(other, dict):
|
||||
return other == eval('{' + self.value + '}')
|
||||
|
||||
return str(self.value) == str(other)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
|
||||
|
||||
class Bbox:
|
||||
""" Comparator for bounding boxes.
|
||||
"""
|
||||
def __init__(self, bbox_string):
|
||||
self.coord = [float(x) for x in bbox_string.split(',')]
|
||||
|
||||
def __contains__(self, item):
|
||||
if isinstance(item, str):
|
||||
item = item.split(',')
|
||||
item = list(map(float, item))
|
||||
|
||||
if len(item) == 2:
|
||||
return self.coord[0] <= item[0] <= self.coord[2] \
|
||||
and self.coord[1] <= item[1] <= self.coord[3]
|
||||
|
||||
if len(item) == 4:
|
||||
return item[0] >= self.coord[0] and item[1] <= self.coord[1] \
|
||||
and item[2] >= self.coord[2] and item[3] <= self.coord[3]
|
||||
|
||||
raise ValueError("Not a coordinate or bbox.")
|
||||
|
||||
def __str__(self):
|
||||
return str(self.coord)
|
||||
|
||||
|
||||
def check_for_attributes(obj, attrs, presence='present'):
|
||||
""" Check that the object has the given attributes. 'attrs' is a
|
||||
string with a comma-separated list of attributes. If 'presence'
|
||||
is set to 'absent' then the function checks that the attributes do
|
||||
not exist for the object
|
||||
"""
|
||||
def _dump_json():
|
||||
return json.dumps(obj, sort_keys=True, indent=2, ensure_ascii=False)
|
||||
|
||||
for attr in attrs.split(','):
|
||||
attr = attr.strip()
|
||||
if presence == 'absent':
|
||||
assert attr not in obj, \
|
||||
f"Unexpected attribute {attr}. Full response:\n{_dump_json()}"
|
||||
else:
|
||||
assert attr in obj, \
|
||||
f"No attribute '{attr}'. Full response:\n{_dump_json()}"
|
||||
@@ -1,262 +0,0 @@
|
||||
# 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.
|
||||
"""
|
||||
Collection of aliases for various world coordinates.
|
||||
"""
|
||||
|
||||
ALIASES = {
|
||||
# Country aliases
|
||||
'AD': (1.58972, 42.54241),
|
||||
'AE': (54.61589, 24.82431),
|
||||
'AF': (65.90264, 34.84708),
|
||||
'AG': (-61.72430, 17.069),
|
||||
'AI': (-63.10571, 18.25461),
|
||||
'AL': (19.84941, 40.21232),
|
||||
'AM': (44.64229, 40.37821),
|
||||
'AO': (16.21924, -12.77014),
|
||||
'AQ': (44.99999, -75.65695),
|
||||
'AR': (-61.10759, -34.37615),
|
||||
'AS': (-170.68470, -14.29307),
|
||||
'AT': (14.25747, 47.36542),
|
||||
'AU': (138.23155, -23.72068),
|
||||
'AW': (-69.98255, 12.555),
|
||||
'AX': (19.91839, 59.81682),
|
||||
'AZ': (48.38555, 40.61639),
|
||||
'BA': (17.18514, 44.25582),
|
||||
'BB': (-59.53342, 13.19),
|
||||
'BD': (89.75989, 24.34205),
|
||||
'BE': (4.90078, 50.34682),
|
||||
'BF': (-0.56743, 11.90471),
|
||||
'BG': (24.80616, 43.09859),
|
||||
'BH': (50.52032, 25.94685),
|
||||
'BI': (29.54561, -2.99057),
|
||||
'BJ': (2.70062, 10.02792),
|
||||
'BL': (-62.79349, 17.907),
|
||||
'BM': (-64.77406, 32.30199),
|
||||
'BN': (114.52196, 4.28638),
|
||||
'BO': (-62.02473, -17.77723),
|
||||
'BQ': (-63.14322, 17.566),
|
||||
'BR': (-45.77065, -9.58685),
|
||||
'BS': (-77.60916, 23.8745),
|
||||
'BT': (90.01350, 27.28137),
|
||||
'BV': (3.35744, -54.4215),
|
||||
'BW': (23.51505, -23.48391),
|
||||
'BY': (26.77259, 53.15885),
|
||||
'BZ': (-88.63489, 16.33951),
|
||||
'CA': (-107.74817, 67.12612),
|
||||
'CC': (96.84420, -12.01734),
|
||||
'CD': (24.09544, -1.67713),
|
||||
'CF': (22.58701, 5.98438),
|
||||
'CG': (15.78875, 0.40388),
|
||||
'CH': (7.65705, 46.57446),
|
||||
'CI': (-6.31190, 6.62783),
|
||||
'CK': (-159.77835, -21.23349),
|
||||
'CL': (-70.41790, -53.77189),
|
||||
'CM': (13.26022, 5.94519),
|
||||
'CN': (96.44285, 38.04260),
|
||||
'CO': (-72.52951, 2.45174),
|
||||
'CR': (-83.83314, 9.93514),
|
||||
'CU': (-80.81673, 21.88852),
|
||||
'CV': (-24.50810, 14.929),
|
||||
'CW': (-68.96409, 12.1845),
|
||||
'CX': (105.62411, -10.48417),
|
||||
'CY': (32.95922, 35.37010),
|
||||
'CZ': (16.32098, 49.50692),
|
||||
'DE': (9.30716, 50.21289),
|
||||
'DJ': (42.96904, 11.41542),
|
||||
'DK': (9.18490, 55.98916),
|
||||
'DM': (-61.00358, 15.65470),
|
||||
'DO': (-69.62855, 18.58841),
|
||||
'DZ': (4.24749, 25.79721),
|
||||
'EC': (-77.45831, -0.98284),
|
||||
'EE': (23.94288, 58.43952),
|
||||
'EG': (28.95293, 28.17718),
|
||||
'EH': (-13.69031, 25.01241),
|
||||
'ER': (39.01223, 14.96033),
|
||||
'ES': (-2.59110, 38.79354),
|
||||
'ET': (38.61697, 7.71399),
|
||||
'FI': (26.89798, 63.56194),
|
||||
'FJ': (177.91853, -17.74237),
|
||||
'FK': (-58.99044, -51.34509),
|
||||
'FM': (151.95358, 8.5045),
|
||||
'FO': (-6.60483, 62.10000),
|
||||
'FR': (0.28410, 47.51045),
|
||||
'GA': (10.81070, -0.07429),
|
||||
'GB': (-0.92823, 52.01618),
|
||||
'GD': (-61.64524, 12.191),
|
||||
'GE': (44.16664, 42.00385),
|
||||
'GF': (-53.46524, 3.56188),
|
||||
'GG': (-2.50580, 49.58543),
|
||||
'GH': (-0.46348, 7.16051),
|
||||
'GI': (-5.32053, 36.11066),
|
||||
'GL': (-33.85511, 74.66355),
|
||||
'GM': (-16.40960, 13.25),
|
||||
'GN': (-13.83940, 10.96291),
|
||||
'GP': (-61.68712, 16.23049),
|
||||
'GQ': (10.23973, 1.43119),
|
||||
'GR': (23.17850, 39.06206),
|
||||
'GS': (-36.49430, -54.43067),
|
||||
'GT': (-90.74368, 15.20428),
|
||||
'GU': (144.73362, 13.44413),
|
||||
'GW': (-14.83525, 11.92486),
|
||||
'GY': (-58.45167, 5.73698),
|
||||
'HK': (114.18577, 22.34923),
|
||||
'HM': (73.68230, -53.22105),
|
||||
'HN': (-86.95414, 15.23820),
|
||||
'HR': (17.49966, 45.52689),
|
||||
'HT': (-73.51925, 18.32492),
|
||||
'HU': (20.35362, 47.51721),
|
||||
'ID': (123.34505, -0.83791),
|
||||
'IE': (-9.00520, 52.87725),
|
||||
'IL': (35.46314, 32.86165),
|
||||
'IM': (-4.86740, 54.023),
|
||||
'IN': (88.67620, 27.86155),
|
||||
'IO': (71.42743, -6.14349),
|
||||
'IQ': (42.58109, 34.26103),
|
||||
'IR': (56.09355, 30.46751),
|
||||
'IS': (-17.51785, 64.71687),
|
||||
'IT': (10.42639, 44.87904),
|
||||
'JE': (-2.19261, 49.12458),
|
||||
'JM': (-76.84020, 18.3935),
|
||||
'JO': (36.55552, 30.75741),
|
||||
'JP': (138.72531, 35.92099),
|
||||
'KE': (36.90602, 1.08512),
|
||||
'KG': (76.15571, 41.66497),
|
||||
'KH': (104.31901, 12.95555),
|
||||
'KI': (173.63353, 0.139),
|
||||
'KM': (44.31474, -12.241),
|
||||
'KN': (-62.69379, 17.2555),
|
||||
'KP': (126.65575, 39.64575),
|
||||
'KR': (127.27740, 36.41388),
|
||||
'KW': (47.30684, 29.69180),
|
||||
'KY': (-81.07455, 19.29949),
|
||||
'KZ': (72.00811, 49.88855),
|
||||
'LA': (102.44391, 19.81609),
|
||||
'LB': (35.48464, 33.41766),
|
||||
'LC': (-60.97894, 13.891),
|
||||
'LI': (9.54693, 47.15934),
|
||||
'LK': (80.38520, 8.41649),
|
||||
'LR': (-11.16960, 4.04122),
|
||||
'LS': (28.66984, -29.94538),
|
||||
'LT': (24.51735, 55.49293),
|
||||
'LU': (6.08649, 49.81533),
|
||||
'LV': (23.51033, 56.67144),
|
||||
'LY': (15.36841, 28.12177),
|
||||
'MA': (-4.03061, 33.21696),
|
||||
'MC': (7.47743, 43.62917),
|
||||
'MD': (29.61725, 46.66517),
|
||||
'ME': (19.72291, 43.02441),
|
||||
'MF': (-63.06666, 18.08102),
|
||||
'MG': (45.86378, -20.50245),
|
||||
'MH': (171.94982, 5.983),
|
||||
'MK': (21.42108, 41.08980),
|
||||
'ML': (-1.93310, 16.46993),
|
||||
'MM': (95.54624, 21.09620),
|
||||
'MN': (99.81138, 48.18615),
|
||||
'MO': (113.56441, 22.16209),
|
||||
'MP': (145.21345, 14.14902),
|
||||
'MQ': (-60.81128, 14.43706),
|
||||
'MR': (-9.42324, 22.59251),
|
||||
'MS': (-62.19455, 16.745),
|
||||
'MT': (14.38363, 35.94467),
|
||||
'MU': (57.55121, -20.41),
|
||||
'MV': (73.39292, 4.19375),
|
||||
'MW': (33.95722, -12.28218),
|
||||
'MX': (-105.89221, 25.86826),
|
||||
'MY': (112.71154, 2.10098),
|
||||
'MZ': (37.58689, -13.72682),
|
||||
'NA': (16.68569, -21.46572),
|
||||
'NC': (164.95322, -20.38889),
|
||||
'NE': (10.06041, 19.08273),
|
||||
'NF': (167.95718, -29.0645),
|
||||
'NG': (10.17781, 10.17804),
|
||||
'NI': (-85.87974, 13.21715),
|
||||
'NL': (-68.57062, 12.041),
|
||||
'NO': (23.11556, 70.09934),
|
||||
'NP': (83.36259, 28.13107),
|
||||
'NR': (166.93479, -0.5275),
|
||||
'NU': (-169.84873, -19.05305),
|
||||
'NZ': (167.97209, -45.13056),
|
||||
'OM': (56.86055, 20.47413),
|
||||
'PA': (-79.40160, 8.80656),
|
||||
'PE': (-78.66540, -7.54711),
|
||||
'PF': (-145.05719, -16.70862),
|
||||
'PG': (146.64600, -7.37427),
|
||||
'PH': (121.48359, 15.09965),
|
||||
'PK': (72.11347, 31.14629),
|
||||
'PL': (17.88136, 52.77182),
|
||||
'PM': (-56.19515, 46.78324),
|
||||
'PN': (-130.10642, -25.06955),
|
||||
'PR': (-65.88755, 18.37169),
|
||||
'PS': (35.39801, 32.24773),
|
||||
'PT': (-8.45743, 40.11154),
|
||||
'PW': (134.49645, 7.3245),
|
||||
'PY': (-59.51787, -22.41281),
|
||||
'QA': (51.49903, 24.99816),
|
||||
'RE': (55.77345, -21.36388),
|
||||
'RO': (26.37632, 45.36120),
|
||||
'RS': (20.40371, 44.56413),
|
||||
'RU': (116.44060, 59.06780),
|
||||
'RW': (29.57882, -1.62404),
|
||||
'SA': (47.73169, 22.43790),
|
||||
'SB': (164.63894, -10.23606),
|
||||
'SC': (46.36566, -9.454),
|
||||
'SD': (28.14720, 14.56423),
|
||||
'SE': (15.68667, 60.35568),
|
||||
'SG': (103.84187, 1.304),
|
||||
'SH': (-12.28155, -37.11546),
|
||||
'SI': (14.04738, 46.39085),
|
||||
'SJ': (15.27552, 79.23365),
|
||||
'SK': (20.41603, 48.86970),
|
||||
'SL': (-11.47773, 8.78156),
|
||||
'SM': (12.46062, 43.94279),
|
||||
'SN': (-15.37111, 14.99477),
|
||||
'SO': (46.93383, 9.34094),
|
||||
'SR': (-55.42864, 4.56985),
|
||||
'SS': (28.13573, 8.50933),
|
||||
'ST': (6.61025, 0.2215),
|
||||
'SV': (-89.36665, 13.43072),
|
||||
'SX': (-63.15393, 17.9345),
|
||||
'SY': (38.15513, 35.34221),
|
||||
'SZ': (31.78263, -26.14244),
|
||||
'TC': (-71.32554, 21.35),
|
||||
'TD': (17.42092, 13.46223),
|
||||
'TF': (137.5, -67.5),
|
||||
'TG': (1.06983, 7.87677),
|
||||
'TH': (102.00877, 16.42310),
|
||||
'TJ': (71.91349, 39.01527),
|
||||
'TK': (-171.82603, -9.20990),
|
||||
'TL': (126.22520, -8.72636),
|
||||
'TM': (57.71603, 39.92534),
|
||||
'TN': (9.04958, 34.84199),
|
||||
'TO': (-176.99320, -23.11104),
|
||||
'TR': (32.82002, 39.86350),
|
||||
'TT': (-60.70793, 11.1385),
|
||||
'TV': (178.77499, -9.41685),
|
||||
'TW': (120.30074, 23.17002),
|
||||
'TZ': (33.53892, -5.01840),
|
||||
'UA': (33.44335, 49.30619),
|
||||
'UG': (32.96523, 2.08584),
|
||||
'UM': (-169.50993, 16.74605),
|
||||
'US': (-116.39535, 40.71379),
|
||||
'UY': (-56.46505, -33.62658),
|
||||
'UZ': (61.35529, 42.96107),
|
||||
'VA': (12.33197, 42.04931),
|
||||
'VC': (-61.09905, 13.316),
|
||||
'VE': (-64.88323, 7.69849),
|
||||
'VG': (-64.62479, 18.419),
|
||||
'VI': (-64.88950, 18.32263),
|
||||
'VN': (104.20179, 10.27644),
|
||||
'VU': (167.31919, -15.88687),
|
||||
'WF': (-176.20781, -13.28535),
|
||||
'WS': (-172.10966, -13.85093),
|
||||
'YE': (45.94562, 16.16338),
|
||||
'YT': (44.93774, -12.60882),
|
||||
'ZA': (23.19488, -30.43276),
|
||||
'ZM': (26.38618, -14.39966),
|
||||
'ZW': (30.12419, -19.86907)
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
# 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.
|
||||
from steps.geometry_alias import ALIASES
|
||||
|
||||
|
||||
class GeometryFactory:
|
||||
""" Provides functions to create geometries from coordinates and data grids.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.grid = {}
|
||||
|
||||
def parse_geometry(self, geom):
|
||||
""" Create a WKT SQL term for the given geometry.
|
||||
The function understands the following formats:
|
||||
|
||||
country:<country code>
|
||||
Point geometry guaranteed to be in the given country
|
||||
<P>
|
||||
Point geometry
|
||||
<P>,...,<P>
|
||||
Line geometry
|
||||
(<P>,...,<P>)
|
||||
Polygon geometry
|
||||
|
||||
<P> may either be a coordinate of the form '<x> <y>' or a single
|
||||
number. In the latter case it must refer to a point in
|
||||
a previously defined grid.
|
||||
"""
|
||||
if geom.startswith('country:'):
|
||||
ccode = geom[8:].upper()
|
||||
assert ccode in ALIASES, "Geometry error: unknown country " + ccode
|
||||
return "ST_SetSRID('POINT({} {})'::geometry, 4326)".format(*ALIASES[ccode])
|
||||
|
||||
if geom.find(',') < 0:
|
||||
out = "POINT({})".format(self.mk_wkt_point(geom))
|
||||
elif geom.find('(') < 0:
|
||||
out = "LINESTRING({})".format(self.mk_wkt_points(geom))
|
||||
else:
|
||||
out = "POLYGON(({}))".format(self.mk_wkt_points(geom.strip('() ')))
|
||||
|
||||
return "ST_SetSRID('{}'::geometry, 4326)".format(out)
|
||||
|
||||
def mk_wkt_point(self, point):
|
||||
""" Parse a point description.
|
||||
The point may either consist of 'x y' coordinates or a number
|
||||
that refers to a grid setup.
|
||||
"""
|
||||
geom = point.strip()
|
||||
if geom.find(' ') >= 0:
|
||||
return geom
|
||||
|
||||
try:
|
||||
pt = self.grid_node(int(geom))
|
||||
except ValueError:
|
||||
assert False, "Scenario error: Point '{}' is not a number".format(geom)
|
||||
|
||||
assert pt is not None, "Scenario error: Point '{}' not found in grid".format(geom)
|
||||
return "{} {}".format(*pt)
|
||||
|
||||
def mk_wkt_points(self, geom):
|
||||
""" Parse a list of points.
|
||||
The list must be a comma-separated list of points. Points
|
||||
in coordinate and grid format may be mixed.
|
||||
"""
|
||||
return ','.join([self.mk_wkt_point(x) for x in geom.split(',')])
|
||||
|
||||
def set_grid(self, lines, grid_step, origin=(0.0, 0.0)):
|
||||
""" Replace the grid with one from the given lines.
|
||||
"""
|
||||
self.grid = {}
|
||||
y = origin[1]
|
||||
for line in lines:
|
||||
x = origin[0]
|
||||
for pt_id in line:
|
||||
if pt_id.isdigit():
|
||||
self.grid[int(pt_id)] = (x, y)
|
||||
x += grid_step
|
||||
y += grid_step
|
||||
|
||||
def grid_node(self, nodeid):
|
||||
""" Get the coordinates for the given grid node.
|
||||
"""
|
||||
return self.grid.get(nodeid)
|
||||
@@ -1,253 +0,0 @@
|
||||
# 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.
|
||||
"""
|
||||
Classes wrapping HTTP responses from the Nominatim API.
|
||||
"""
|
||||
import re
|
||||
import json
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from check_functions import OsmType, Field, check_for_attributes
|
||||
|
||||
|
||||
class GenericResponse:
|
||||
""" Common base class for all API responses.
|
||||
"""
|
||||
def __init__(self, page, fmt, errorcode=200):
|
||||
fmt = fmt.strip()
|
||||
if fmt == 'jsonv2':
|
||||
fmt = 'json'
|
||||
|
||||
self.page = page
|
||||
self.format = fmt
|
||||
self.errorcode = errorcode
|
||||
self.result = []
|
||||
self.header = dict()
|
||||
|
||||
if errorcode == 200 and fmt != 'debug':
|
||||
getattr(self, '_parse_' + fmt)()
|
||||
|
||||
def _parse_json(self):
|
||||
m = re.fullmatch(r'([\w$][^(]*)\((.*)\)', self.page)
|
||||
if m is None:
|
||||
code = self.page
|
||||
else:
|
||||
code = m.group(2)
|
||||
self.header['json_func'] = m.group(1)
|
||||
self.result = json.JSONDecoder().decode(code)
|
||||
if isinstance(self.result, dict):
|
||||
if 'error' in self.result:
|
||||
self.result = []
|
||||
else:
|
||||
self.result = [self.result]
|
||||
|
||||
def _parse_geojson(self):
|
||||
self._parse_json()
|
||||
if self.result:
|
||||
geojson = self.result[0]
|
||||
# check for valid geojson
|
||||
check_for_attributes(geojson, 'type,features')
|
||||
assert geojson['type'] == 'FeatureCollection'
|
||||
assert isinstance(geojson['features'], list)
|
||||
|
||||
self.result = []
|
||||
for result in geojson['features']:
|
||||
check_for_attributes(result, 'type,properties,geometry')
|
||||
assert result['type'] == 'Feature'
|
||||
new = result['properties']
|
||||
check_for_attributes(new, 'geojson', 'absent')
|
||||
new['geojson'] = result['geometry']
|
||||
if 'bbox' in result:
|
||||
check_for_attributes(new, 'boundingbox', 'absent')
|
||||
# bbox is minlon, minlat, maxlon, maxlat
|
||||
# boundingbox is minlat, maxlat, minlon, maxlon
|
||||
new['boundingbox'] = [result['bbox'][1],
|
||||
result['bbox'][3],
|
||||
result['bbox'][0],
|
||||
result['bbox'][2]]
|
||||
for k, v in geojson.items():
|
||||
if k not in ('type', 'features'):
|
||||
check_for_attributes(new, '__' + k, 'absent')
|
||||
new['__' + k] = v
|
||||
self.result.append(new)
|
||||
|
||||
def _parse_geocodejson(self):
|
||||
self._parse_geojson()
|
||||
if self.result:
|
||||
for r in self.result:
|
||||
assert set(r.keys()) == {'geocoding', 'geojson', '__geocoding'}, \
|
||||
f"Unexpected keys in result: {r.keys()}"
|
||||
check_for_attributes(r['geocoding'], 'geojson', 'absent')
|
||||
inner = r.pop('geocoding')
|
||||
r.update(inner)
|
||||
|
||||
def assert_address_field(self, idx, field, value):
|
||||
""" Check that result rows`idx` has a field `field` with value `value`
|
||||
in its address. If idx is None, then all results are checked.
|
||||
"""
|
||||
if idx is None:
|
||||
todo = range(len(self.result))
|
||||
else:
|
||||
todo = [int(idx)]
|
||||
|
||||
for idx in todo:
|
||||
self.check_row(idx, 'address' in self.result[idx], "No field 'address'")
|
||||
|
||||
address = self.result[idx]['address']
|
||||
self.check_row_field(idx, field, value, base=address)
|
||||
|
||||
def match_row(self, row, context=None, field=None):
|
||||
""" Match the result fields against the given behave table row.
|
||||
"""
|
||||
if 'ID' in row.headings:
|
||||
todo = [int(row['ID'])]
|
||||
else:
|
||||
todo = range(len(self.result))
|
||||
|
||||
for i in todo:
|
||||
subdict = self.result[i]
|
||||
if field is not None:
|
||||
for key in field.split('.'):
|
||||
self.check_row(i, key in subdict, f"Missing subfield {key}")
|
||||
subdict = subdict[key]
|
||||
self.check_row(i, isinstance(subdict, dict),
|
||||
f"Subfield {key} not a dict")
|
||||
|
||||
for name, value in zip(row.headings, row.cells):
|
||||
if name == 'ID':
|
||||
pass
|
||||
elif name == 'osm':
|
||||
self.check_row_field(i, 'osm_type', OsmType(value[0]), base=subdict)
|
||||
self.check_row_field(i, 'osm_id', Field(value[1:]), base=subdict)
|
||||
elif name == 'centroid':
|
||||
if ' ' in value:
|
||||
lon, lat = value.split(' ')
|
||||
elif context is not None:
|
||||
lon, lat = context.osm.grid_node(int(value))
|
||||
else:
|
||||
raise RuntimeError("Context needed when using grid coordinates")
|
||||
self.check_row_field(i, 'lat', Field(float(lat), abs_tol=1e-07), base=subdict)
|
||||
self.check_row_field(i, 'lon', Field(float(lon), abs_tol=1e-07), base=subdict)
|
||||
else:
|
||||
self.check_row_field(i, name, Field(value), base=subdict)
|
||||
|
||||
def check_row(self, idx, check, msg):
|
||||
""" Assert for the condition 'check' and print 'msg' on fail together
|
||||
with the contents of the failing result.
|
||||
"""
|
||||
class _RowError:
|
||||
def __init__(self, row):
|
||||
self.row = row
|
||||
|
||||
def __str__(self):
|
||||
return f"{msg}. Full row {idx}:\n" \
|
||||
+ json.dumps(self.row, indent=4, ensure_ascii=False)
|
||||
|
||||
assert check, _RowError(self.result[idx])
|
||||
|
||||
def check_row_field(self, idx, field, expected, base=None):
|
||||
""" Check field 'field' of result 'idx' for the expected value
|
||||
and print a meaningful error if the condition fails.
|
||||
When 'base' is set to a dictionary, then the field is checked
|
||||
in that base. The error message will still report the contents
|
||||
of the full result.
|
||||
"""
|
||||
if base is None:
|
||||
base = self.result[idx]
|
||||
|
||||
self.check_row(idx, field in base, f"No field '{field}'")
|
||||
value = base[field]
|
||||
|
||||
self.check_row(idx, expected == value,
|
||||
f"\nBad value for field '{field}'. Expected: {expected}, got: {value}")
|
||||
|
||||
|
||||
class SearchResponse(GenericResponse):
|
||||
""" Specialised class for search and lookup responses.
|
||||
Transforms the xml response in a format similar to json.
|
||||
"""
|
||||
|
||||
def _parse_xml(self):
|
||||
xml_tree = ET.fromstring(self.page)
|
||||
|
||||
self.header = dict(xml_tree.attrib)
|
||||
|
||||
for child in xml_tree:
|
||||
assert child.tag == "place"
|
||||
self.result.append(dict(child.attrib))
|
||||
|
||||
address = {}
|
||||
for sub in child:
|
||||
if sub.tag == 'extratags':
|
||||
self.result[-1]['extratags'] = {}
|
||||
for tag in sub:
|
||||
self.result[-1]['extratags'][tag.attrib['key']] = tag.attrib['value']
|
||||
elif sub.tag == 'namedetails':
|
||||
self.result[-1]['namedetails'] = {}
|
||||
for tag in sub:
|
||||
self.result[-1]['namedetails'][tag.attrib['desc']] = tag.text
|
||||
elif sub.tag == 'geokml':
|
||||
self.result[-1][sub.tag] = True
|
||||
else:
|
||||
address[sub.tag] = sub.text
|
||||
|
||||
if address:
|
||||
self.result[-1]['address'] = address
|
||||
|
||||
|
||||
class ReverseResponse(GenericResponse):
|
||||
""" Specialised class for reverse responses.
|
||||
Transforms the xml response in a format similar to json.
|
||||
"""
|
||||
|
||||
def _parse_xml(self):
|
||||
xml_tree = ET.fromstring(self.page)
|
||||
|
||||
self.header = dict(xml_tree.attrib)
|
||||
self.result = []
|
||||
|
||||
for child in xml_tree:
|
||||
if child.tag == 'result':
|
||||
assert not self.result, "More than one result in reverse result"
|
||||
self.result.append(dict(child.attrib))
|
||||
check_for_attributes(self.result[0], 'display_name', 'absent')
|
||||
self.result[0]['display_name'] = child.text
|
||||
elif child.tag == 'addressparts':
|
||||
assert 'address' not in self.result[0], "More than one address in result"
|
||||
address = {}
|
||||
for sub in child:
|
||||
assert len(sub) == 0, f"Address element '{sub.tag}' has subelements"
|
||||
address[sub.tag] = sub.text
|
||||
self.result[0]['address'] = address
|
||||
elif child.tag == 'extratags':
|
||||
assert 'extratags' not in self.result[0], "More than one extratags in result"
|
||||
self.result[0]['extratags'] = {}
|
||||
for tag in child:
|
||||
assert len(tag) == 0, f"Extratags element '{tag.attrib['key']}' has subelements"
|
||||
self.result[0]['extratags'][tag.attrib['key']] = tag.attrib['value']
|
||||
elif child.tag == 'namedetails':
|
||||
assert 'namedetails' not in self.result[0], "More than one namedetails in result"
|
||||
self.result[0]['namedetails'] = {}
|
||||
for tag in child:
|
||||
assert len(tag) == 0, \
|
||||
f"Namedetails element '{tag.attrib['desc']}' has subelements"
|
||||
self.result[0]['namedetails'][tag.attrib['desc']] = tag.text
|
||||
elif child.tag == 'geokml':
|
||||
assert 'geokml' not in self.result[0], "More than one geokml in result"
|
||||
self.result[0]['geokml'] = ET.tostring(child, encoding='unicode')
|
||||
else:
|
||||
assert child.tag == 'error', \
|
||||
f"Unknown XML tag {child.tag} on page: {self.page}"
|
||||
|
||||
|
||||
class StatusResponse(GenericResponse):
|
||||
""" Specialised class for status responses.
|
||||
Can also parse text responses.
|
||||
"""
|
||||
|
||||
def _parse_text(self):
|
||||
pass
|
||||
@@ -1,315 +0,0 @@
|
||||
# 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.
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
import psycopg
|
||||
from psycopg import sql as pysql
|
||||
|
||||
from nominatim_db import cli
|
||||
from nominatim_db.config import Configuration
|
||||
from nominatim_db.db.connection import register_hstore, execute_scalar
|
||||
from nominatim_db.tokenizer import factory as tokenizer_factory
|
||||
|
||||
|
||||
class NominatimEnvironment:
|
||||
""" Collects all functions for the execution of Nominatim functions.
|
||||
"""
|
||||
|
||||
def __init__(self, config):
|
||||
self.src_dir = (Path(__file__) / '..' / '..' / '..' / '..').resolve()
|
||||
self.db_host = config['DB_HOST']
|
||||
self.db_port = config['DB_PORT']
|
||||
self.db_user = config['DB_USER']
|
||||
self.db_pass = config['DB_PASS']
|
||||
self.template_db = config['TEMPLATE_DB']
|
||||
self.test_db = config['TEST_DB']
|
||||
self.api_test_db = config['API_TEST_DB']
|
||||
self.api_test_file = config['API_TEST_FILE']
|
||||
self.tokenizer = config['TOKENIZER']
|
||||
self.import_style = config['STYLE']
|
||||
self.reuse_template = not config['REMOVE_TEMPLATE']
|
||||
self.keep_scenario_db = config['KEEP_TEST_DB']
|
||||
|
||||
self.default_config = Configuration(None).get_os_env()
|
||||
self.test_env = None
|
||||
self.template_db_done = False
|
||||
self.api_db_done = False
|
||||
self.website_dir = None
|
||||
|
||||
if not hasattr(self, f"create_api_request_func_{config['API_ENGINE']}"):
|
||||
raise RuntimeError(f"Unknown API engine '{config['API_ENGINE']}'")
|
||||
self.api_engine = getattr(self, f"create_api_request_func_{config['API_ENGINE']}")()
|
||||
|
||||
def connect_database(self, dbname):
|
||||
""" Return a connection to the database with the given name.
|
||||
Uses configured host, user and port.
|
||||
"""
|
||||
dbargs = {'dbname': dbname, 'row_factory': psycopg.rows.dict_row}
|
||||
if self.db_host:
|
||||
dbargs['host'] = self.db_host
|
||||
if self.db_port:
|
||||
dbargs['port'] = self.db_port
|
||||
if self.db_user:
|
||||
dbargs['user'] = self.db_user
|
||||
if self.db_pass:
|
||||
dbargs['password'] = self.db_pass
|
||||
return psycopg.connect(**dbargs)
|
||||
|
||||
def write_nominatim_config(self, dbname):
|
||||
""" Set up a custom test configuration that connects to the given
|
||||
database. This sets up the environment variables so that they can
|
||||
be picked up by dotenv and creates a project directory with the
|
||||
appropriate website scripts.
|
||||
"""
|
||||
if dbname.startswith('sqlite:'):
|
||||
dsn = 'sqlite:dbname={}'.format(dbname[7:])
|
||||
else:
|
||||
dsn = 'pgsql:dbname={}'.format(dbname)
|
||||
if self.db_host:
|
||||
dsn += ';host=' + self.db_host
|
||||
if self.db_port:
|
||||
dsn += ';port=' + self.db_port
|
||||
if self.db_user:
|
||||
dsn += ';user=' + self.db_user
|
||||
if self.db_pass:
|
||||
dsn += ';password=' + self.db_pass
|
||||
|
||||
self.test_env = dict(self.default_config)
|
||||
self.test_env['NOMINATIM_DATABASE_DSN'] = dsn
|
||||
self.test_env['NOMINATIM_LANGUAGES'] = 'en,de,fr,ja'
|
||||
self.test_env['NOMINATIM_FLATNODE_FILE'] = ''
|
||||
self.test_env['NOMINATIM_IMPORT_STYLE'] = 'full'
|
||||
self.test_env['NOMINATIM_USE_US_TIGER_DATA'] = 'yes'
|
||||
self.test_env['NOMINATIM_DATADIR'] = str((self.src_dir / 'data').resolve())
|
||||
self.test_env['NOMINATIM_SQLDIR'] = str((self.src_dir / 'lib-sql').resolve())
|
||||
self.test_env['NOMINATIM_CONFIGDIR'] = str((self.src_dir / 'settings').resolve())
|
||||
if self.tokenizer is not None:
|
||||
self.test_env['NOMINATIM_TOKENIZER'] = self.tokenizer
|
||||
if self.import_style is not None:
|
||||
self.test_env['NOMINATIM_IMPORT_STYLE'] = self.import_style
|
||||
|
||||
if self.website_dir is not None:
|
||||
self.website_dir.cleanup()
|
||||
|
||||
self.website_dir = tempfile.TemporaryDirectory()
|
||||
|
||||
def get_test_config(self):
|
||||
cfg = Configuration(Path(self.website_dir.name), environ=self.test_env)
|
||||
return cfg
|
||||
|
||||
def get_libpq_dsn(self):
|
||||
dsn = self.test_env['NOMINATIM_DATABASE_DSN']
|
||||
|
||||
def quote_param(param):
|
||||
key, val = param.split('=')
|
||||
val = val.replace('\\', '\\\\').replace("'", "\\'")
|
||||
if ' ' in val:
|
||||
val = "'" + val + "'"
|
||||
return key + '=' + val
|
||||
|
||||
if dsn.startswith('pgsql:'):
|
||||
# Old PHP DSN format. Convert before returning.
|
||||
return ' '.join([quote_param(p) for p in dsn[6:].split(';')])
|
||||
|
||||
return dsn
|
||||
|
||||
def db_drop_database(self, name):
|
||||
""" Drop the database with the given name.
|
||||
"""
|
||||
with self.connect_database('postgres') as conn:
|
||||
conn.autocommit = True
|
||||
conn.execute(pysql.SQL('DROP DATABASE IF EXISTS')
|
||||
+ pysql.Identifier(name))
|
||||
|
||||
def setup_template_db(self):
|
||||
""" Setup a template database that already contains common test data.
|
||||
Having a template database speeds up tests considerably but at
|
||||
the price that the tests sometimes run with stale data.
|
||||
"""
|
||||
if self.template_db_done:
|
||||
return
|
||||
|
||||
self.template_db_done = True
|
||||
|
||||
self.write_nominatim_config(self.template_db)
|
||||
|
||||
if not self._reuse_or_drop_db(self.template_db):
|
||||
try:
|
||||
# execute nominatim import on an empty file to get the right tables
|
||||
with tempfile.NamedTemporaryFile(dir='/tmp', suffix='.xml') as fd:
|
||||
fd.write(b'<osm version="0.6"></osm>')
|
||||
fd.flush()
|
||||
self.run_nominatim('import', '--osm-file', fd.name,
|
||||
'--osm2pgsql-cache', '1',
|
||||
'--ignore-errors',
|
||||
'--offline', '--index-noanalyse')
|
||||
except: # noqa: E722
|
||||
self.db_drop_database(self.template_db)
|
||||
raise
|
||||
|
||||
self.run_nominatim('refresh', '--functions')
|
||||
|
||||
def setup_api_db(self):
|
||||
""" Setup a test against the API test database.
|
||||
"""
|
||||
self.write_nominatim_config(self.api_test_db)
|
||||
|
||||
if self.api_test_db.startswith('sqlite:'):
|
||||
return
|
||||
|
||||
if not self.api_db_done:
|
||||
self.api_db_done = True
|
||||
|
||||
if not self._reuse_or_drop_db(self.api_test_db):
|
||||
testdata = (Path(__file__) / '..' / '..' / '..' / 'testdb').resolve()
|
||||
self.test_env['NOMINATIM_WIKIPEDIA_DATA_PATH'] = str(testdata)
|
||||
simp_file = Path(self.website_dir.name) / 'secondary_importance.sql.gz'
|
||||
simp_file.symlink_to(testdata / 'secondary_importance.sql.gz')
|
||||
|
||||
try:
|
||||
self.run_nominatim('import', '--osm-file', str(self.api_test_file))
|
||||
self.run_nominatim('add-data', '--tiger-data', str(testdata / 'tiger'))
|
||||
self.run_nominatim('freeze')
|
||||
|
||||
csv_path = str(testdata / 'full_en_phrases_test.csv')
|
||||
self.run_nominatim('special-phrases', '--import-from-csv', csv_path)
|
||||
except: # noqa: E722
|
||||
self.db_drop_database(self.api_test_db)
|
||||
raise
|
||||
|
||||
tokenizer_factory.get_tokenizer_for_db(self.get_test_config())
|
||||
|
||||
def setup_unknown_db(self):
|
||||
""" Setup a test against a non-existing database.
|
||||
"""
|
||||
# The tokenizer needs an existing database to function.
|
||||
# So start with the usual database
|
||||
class _Context:
|
||||
db = None
|
||||
|
||||
context = _Context()
|
||||
self.setup_db(context)
|
||||
tokenizer_factory.create_tokenizer(self.get_test_config(), init_db=False)
|
||||
|
||||
# Then drop the DB again
|
||||
self.teardown_db(context, force_drop=True)
|
||||
|
||||
def setup_db(self, context):
|
||||
""" Setup a test against a fresh, empty test database.
|
||||
"""
|
||||
self.setup_template_db()
|
||||
with self.connect_database(self.template_db) as conn:
|
||||
conn.autocommit = True
|
||||
conn.execute(pysql.SQL('DROP DATABASE IF EXISTS')
|
||||
+ pysql.Identifier(self.test_db))
|
||||
conn.execute(pysql.SQL('CREATE DATABASE {} TEMPLATE = {}').format(
|
||||
pysql.Identifier(self.test_db),
|
||||
pysql.Identifier(self.template_db)))
|
||||
|
||||
self.write_nominatim_config(self.test_db)
|
||||
context.db = self.connect_database(self.test_db)
|
||||
context.db.autocommit = True
|
||||
register_hstore(context.db)
|
||||
|
||||
def teardown_db(self, context, force_drop=False):
|
||||
""" Remove the test database, if it exists.
|
||||
"""
|
||||
if hasattr(context, 'db'):
|
||||
context.db.close()
|
||||
|
||||
if force_drop or not self.keep_scenario_db:
|
||||
self.db_drop_database(self.test_db)
|
||||
|
||||
def _reuse_or_drop_db(self, name):
|
||||
""" Check for the existence of the given DB. If reuse is enabled,
|
||||
then the function checks for existnce and returns True if the
|
||||
database is already there. Otherwise an existing database is
|
||||
dropped and always false returned.
|
||||
"""
|
||||
if self.reuse_template:
|
||||
with self.connect_database('postgres') as conn:
|
||||
num = execute_scalar(conn,
|
||||
'select count(*) from pg_database where datname = %s',
|
||||
(name,))
|
||||
if num == 1:
|
||||
return True
|
||||
else:
|
||||
self.db_drop_database(name)
|
||||
|
||||
return False
|
||||
|
||||
def reindex_placex(self, db):
|
||||
""" Run the indexing step until all data in the placex has
|
||||
been processed. Indexing during updates can produce more data
|
||||
to index under some circumstances. That is why indexing may have
|
||||
to be run multiple times.
|
||||
"""
|
||||
self.run_nominatim('index')
|
||||
|
||||
def run_nominatim(self, *cmdline):
|
||||
""" Run the nominatim command-line tool via the library.
|
||||
"""
|
||||
if self.website_dir is not None:
|
||||
cmdline = list(cmdline) + ['--project-dir', self.website_dir.name]
|
||||
|
||||
cli.nominatim(cli_args=cmdline,
|
||||
environ=self.test_env)
|
||||
|
||||
def copy_from_place(self, db):
|
||||
""" Copy data from place to the placex and location_property_osmline
|
||||
tables invoking the appropriate triggers.
|
||||
"""
|
||||
self.run_nominatim('refresh', '--functions', '--no-diff-updates')
|
||||
|
||||
with db.cursor() as cur:
|
||||
cur.execute("""INSERT INTO placex (osm_type, osm_id, class, type,
|
||||
name, admin_level, address,
|
||||
extratags, geometry)
|
||||
SELECT osm_type, osm_id, class, type,
|
||||
name, admin_level, address,
|
||||
extratags, geometry
|
||||
FROM place
|
||||
WHERE not (class='place' and type='houses' and osm_type='W')""")
|
||||
cur.execute("""INSERT INTO location_property_osmline (osm_id, address, linegeo)
|
||||
SELECT osm_id, address, geometry
|
||||
FROM place
|
||||
WHERE class='place' and type='houses'
|
||||
and osm_type='W'
|
||||
and ST_GeometryType(geometry) = 'ST_LineString'""")
|
||||
|
||||
def create_api_request_func_starlette(self):
|
||||
import nominatim_api.server.starlette.server
|
||||
from asgi_lifespan import LifespanManager
|
||||
import httpx
|
||||
|
||||
async def _request(endpoint, params, project_dir, environ, http_headers):
|
||||
app = nominatim_api.server.starlette.server.get_application(project_dir, environ)
|
||||
|
||||
async with LifespanManager(app):
|
||||
async with httpx.AsyncClient(app=app, base_url="http://nominatim.test") as client:
|
||||
response = await client.get(f"/{endpoint}", params=params,
|
||||
headers=http_headers)
|
||||
|
||||
return response.text, response.status_code
|
||||
|
||||
return _request
|
||||
|
||||
def create_api_request_func_falcon(self):
|
||||
import nominatim_api.server.falcon.server
|
||||
import falcon.testing
|
||||
|
||||
async def _request(endpoint, params, project_dir, environ, http_headers):
|
||||
app = nominatim_api.server.falcon.server.get_application(project_dir, environ)
|
||||
|
||||
async with falcon.testing.ASGIConductor(app) as conductor:
|
||||
response = await conductor.get(f"/{endpoint}", params=params,
|
||||
headers=http_headers)
|
||||
|
||||
return response.text, response.status_code
|
||||
|
||||
return _request
|
||||
@@ -1,120 +0,0 @@
|
||||
# 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
|
||||
|
||||
|
||||
class PlaceColumn:
|
||||
""" Helper class to collect contents from a behave table row and
|
||||
insert it into the place table.
|
||||
"""
|
||||
def __init__(self, context):
|
||||
self.columns = {'admin_level': 15}
|
||||
self.context = context
|
||||
self.geometry = None
|
||||
|
||||
def add_row(self, row, force_name):
|
||||
""" Parse the content from the given behave row as place column data.
|
||||
"""
|
||||
for name, value in zip(row.headings, row.cells):
|
||||
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):
|
||||
self.geometry = self.context.osm.parse_geometry(value)
|
||||
assert self.geometry is not None, "Bad geometry: {}".format(value)
|
||||
|
||||
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.context.osm.grid_node(self.columns['osm_id'])
|
||||
if pt is None:
|
||||
pt = (random.uniform(-180, 180), random.uniform(-90, 90))
|
||||
|
||||
self.geometry = "ST_SetSRID(ST_Point(%f, %f), 4326)" % 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()))
|
||||
@@ -1,307 +0,0 @@
|
||||
# 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.
|
||||
""" Steps that run queries against the API.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import re
|
||||
import logging
|
||||
import asyncio
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from http_responses import GenericResponse, SearchResponse, ReverseResponse, StatusResponse
|
||||
from check_functions import Bbox, check_for_attributes
|
||||
from table_compare import NominatimID
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def make_todo_list(context, result_id):
|
||||
if result_id is None:
|
||||
context.execute_steps("then at least 1 result is returned")
|
||||
return range(len(context.response.result))
|
||||
|
||||
context.execute_steps(f"then more than {result_id}results are returned")
|
||||
return (int(result_id.strip()), )
|
||||
|
||||
|
||||
def compare(operator, op1, op2):
|
||||
if operator == 'less than':
|
||||
return op1 < op2
|
||||
elif operator == 'more than':
|
||||
return op1 > op2
|
||||
elif operator == 'exactly':
|
||||
return op1 == op2
|
||||
elif operator == 'at least':
|
||||
return op1 >= op2
|
||||
elif operator == 'at most':
|
||||
return op1 <= op2
|
||||
else:
|
||||
raise ValueError(f"Unknown operator '{operator}'")
|
||||
|
||||
|
||||
def send_api_query(endpoint, params, fmt, context):
|
||||
if fmt is not None:
|
||||
if fmt.strip() == 'debug':
|
||||
params['debug'] = '1'
|
||||
else:
|
||||
params['format'] = fmt.strip()
|
||||
|
||||
if context.table:
|
||||
if context.table.headings[0] == 'param':
|
||||
for line in context.table:
|
||||
params[line['param']] = line['value']
|
||||
else:
|
||||
for h in context.table.headings:
|
||||
params[h] = context.table[0][h]
|
||||
|
||||
return asyncio.run(context.nominatim.api_engine(endpoint, params,
|
||||
Path(context.nominatim.website_dir.name),
|
||||
context.nominatim.test_env,
|
||||
getattr(context, 'http_headers', {})))
|
||||
|
||||
|
||||
@given('the HTTP header')
|
||||
def add_http_header(context):
|
||||
if not hasattr(context, 'http_headers'):
|
||||
context.http_headers = {}
|
||||
|
||||
for h in context.table.headings:
|
||||
context.http_headers[h] = context.table[0][h]
|
||||
|
||||
|
||||
@when(r'sending (?P<fmt>\S+ )?search query "(?P<query>.*)"(?P<addr> with address)?')
|
||||
def website_search_request(context, fmt, query, addr):
|
||||
params = {}
|
||||
if query:
|
||||
params['q'] = query
|
||||
if addr is not None:
|
||||
params['addressdetails'] = '1'
|
||||
|
||||
outp, status = send_api_query('search', params, fmt, context)
|
||||
|
||||
context.response = SearchResponse(outp, fmt or 'json', status)
|
||||
|
||||
|
||||
@when(r'sending v1/reverse at (?P<lat>[\d.-]*),(?P<lon>[\d.-]*)(?: with format (?P<fmt>.+))?')
|
||||
def api_endpoint_v1_reverse(context, lat, lon, fmt):
|
||||
params = {}
|
||||
if lat is not None:
|
||||
params['lat'] = lat
|
||||
if lon is not None:
|
||||
params['lon'] = lon
|
||||
if fmt is None:
|
||||
fmt = 'jsonv2'
|
||||
elif fmt == "''":
|
||||
fmt = None
|
||||
|
||||
outp, status = send_api_query('reverse', params, fmt, context)
|
||||
context.response = ReverseResponse(outp, fmt or 'xml', status)
|
||||
|
||||
|
||||
@when(r'sending v1/reverse N(?P<nodeid>\d+)(?: with format (?P<fmt>.+))?')
|
||||
def api_endpoint_v1_reverse_from_node(context, nodeid, fmt):
|
||||
params = {}
|
||||
params['lon'], params['lat'] = (f'{c:f}' for c in context.osm.grid_node(int(nodeid)))
|
||||
|
||||
outp, status = send_api_query('reverse', params, fmt, context)
|
||||
context.response = ReverseResponse(outp, fmt or 'xml', status)
|
||||
|
||||
|
||||
@when(r'sending (?P<fmt>\S+ )?details query for (?P<query>.*)')
|
||||
def website_details_request(context, fmt, query):
|
||||
params = {}
|
||||
if query[0] in 'NWR':
|
||||
nid = NominatimID(query)
|
||||
params['osmtype'] = nid.typ
|
||||
params['osmid'] = nid.oid
|
||||
if nid.cls:
|
||||
params['class'] = nid.cls
|
||||
else:
|
||||
params['place_id'] = query
|
||||
outp, status = send_api_query('details', params, fmt, context)
|
||||
|
||||
context.response = GenericResponse(outp, fmt or 'json', status)
|
||||
|
||||
|
||||
@when(r'sending (?P<fmt>\S+ )?lookup query for (?P<query>.*)')
|
||||
def website_lookup_request(context, fmt, query):
|
||||
params = {'osm_ids': query}
|
||||
outp, status = send_api_query('lookup', params, fmt, context)
|
||||
|
||||
context.response = SearchResponse(outp, fmt or 'xml', status)
|
||||
|
||||
|
||||
@when(r'sending (?P<fmt>\S+ )?status query')
|
||||
def website_status_request(context, fmt):
|
||||
params = {}
|
||||
outp, status = send_api_query('status', params, fmt, context)
|
||||
|
||||
context.response = StatusResponse(outp, fmt or 'text', status)
|
||||
|
||||
|
||||
@step(r'(?P<operator>less than|more than|exactly|at least|at most) '
|
||||
r'(?P<number>\d+) results? (?:is|are) returned')
|
||||
def validate_result_number(context, operator, number):
|
||||
context.execute_steps("Then a HTTP 200 is returned")
|
||||
numres = len(context.response.result)
|
||||
assert compare(operator, numres, int(number)), \
|
||||
f"Bad number of results: expected {operator} {number}, got {numres}."
|
||||
|
||||
|
||||
@then(r'a HTTP (?P<status>\d+) is returned')
|
||||
def check_http_return_status(context, status):
|
||||
assert context.response.errorcode == int(status), \
|
||||
f"Return HTTP status is {context.response.errorcode}."\
|
||||
f" Full response:\n{context.response.page}"
|
||||
|
||||
|
||||
@then(r'the page contents equals "(?P<text>.+)"')
|
||||
def check_page_content_equals(context, text):
|
||||
assert context.response.page == text
|
||||
|
||||
|
||||
@then(r'the result is valid (?P<fmt>\w+)')
|
||||
def step_impl(context, fmt):
|
||||
context.execute_steps("Then a HTTP 200 is returned")
|
||||
if fmt.strip() == 'html':
|
||||
try:
|
||||
tree = ET.fromstring(context.response.page)
|
||||
except Exception as ex:
|
||||
assert False, f"Could not parse page: {ex}\n{context.response.page}"
|
||||
|
||||
assert tree.tag == 'html'
|
||||
body = tree.find('./body')
|
||||
assert body is not None
|
||||
assert body.find('.//script') is None
|
||||
else:
|
||||
assert context.response.format == fmt
|
||||
|
||||
|
||||
@then(r'a (?P<fmt>\w+) user error is returned')
|
||||
def check_page_error(context, fmt):
|
||||
context.execute_steps("Then a HTTP 400 is returned")
|
||||
assert context.response.format == fmt
|
||||
|
||||
if fmt == 'xml':
|
||||
assert re.search(r'<error>.+</error>', context.response.page, re.DOTALL) is not None
|
||||
else:
|
||||
assert re.search(r'({"error":)', context.response.page, re.DOTALL) is not None
|
||||
|
||||
|
||||
@then('result header contains')
|
||||
def check_header_attr(context):
|
||||
context.execute_steps("Then a HTTP 200 is returned")
|
||||
for line in context.table:
|
||||
assert line['attr'] in context.response.header, \
|
||||
f"Field '{line['attr']}' missing in header. " \
|
||||
f"Full header:\n{context.response.header}"
|
||||
value = context.response.header[line['attr']]
|
||||
assert re.fullmatch(line['value'], value) is not None, \
|
||||
f"Attribute '{line['attr']}': expected: '{line['value']}', got '{value}'"
|
||||
|
||||
|
||||
@then('result header has (?P<neg>not )?attributes (?P<attrs>.*)')
|
||||
def check_header_no_attr(context, neg, attrs):
|
||||
check_for_attributes(context.response.header, attrs,
|
||||
'absent' if neg else 'present')
|
||||
|
||||
|
||||
@then(r'results contain(?: in field (?P<field>.*))?')
|
||||
def results_contain_in_field(context, field):
|
||||
context.execute_steps("then at least 1 result is returned")
|
||||
|
||||
for line in context.table:
|
||||
context.response.match_row(line, context=context, field=field)
|
||||
|
||||
|
||||
@then(r'result (?P<lid>\d+ )?has (?P<neg>not )?attributes (?P<attrs>.*)')
|
||||
def validate_attributes(context, lid, neg, attrs):
|
||||
for i in make_todo_list(context, lid):
|
||||
check_for_attributes(context.response.result[i], attrs,
|
||||
'absent' if neg else 'present')
|
||||
|
||||
|
||||
@then(u'result addresses contain')
|
||||
def result_addresses_contain(context):
|
||||
context.execute_steps("then at least 1 result is returned")
|
||||
|
||||
for line in context.table:
|
||||
idx = int(line['ID']) if 'ID' in line.headings else None
|
||||
|
||||
for name, value in zip(line.headings, line.cells):
|
||||
if name != 'ID':
|
||||
context.response.assert_address_field(idx, name, value)
|
||||
|
||||
|
||||
@then(r'address of result (?P<lid>\d+) has(?P<neg> no)? types (?P<attrs>.*)')
|
||||
def check_address_has_types(context, lid, neg, attrs):
|
||||
context.execute_steps(f"then more than {lid} results are returned")
|
||||
|
||||
addr_parts = context.response.result[int(lid)]['address']
|
||||
|
||||
for attr in attrs.split(','):
|
||||
if neg:
|
||||
assert attr not in addr_parts
|
||||
else:
|
||||
assert attr in addr_parts
|
||||
|
||||
|
||||
@then(r'address of result (?P<lid>\d+) (?P<complete>is|contains)')
|
||||
def check_address(context, lid, complete):
|
||||
context.execute_steps(f"then more than {lid} results are returned")
|
||||
|
||||
lid = int(lid)
|
||||
addr_parts = dict(context.response.result[lid]['address'])
|
||||
|
||||
for line in context.table:
|
||||
context.response.assert_address_field(lid, line['type'], line['value'])
|
||||
del addr_parts[line['type']]
|
||||
|
||||
if complete == 'is':
|
||||
assert len(addr_parts) == 0, f"Additional address parts found: {addr_parts!s}"
|
||||
|
||||
|
||||
@then(r'result (?P<lid>\d+ )?has bounding box in (?P<coords>[\d,.-]+)')
|
||||
def check_bounding_box_in_area(context, lid, coords):
|
||||
expected = Bbox(coords)
|
||||
|
||||
for idx in make_todo_list(context, lid):
|
||||
res = context.response.result[idx]
|
||||
check_for_attributes(res, 'boundingbox')
|
||||
context.response.check_row(idx, res['boundingbox'] in expected,
|
||||
f"Bbox is not contained in {expected}")
|
||||
|
||||
|
||||
@then(r'result (?P<lid>\d+ )?has centroid in (?P<coords>[\d,.-]+)')
|
||||
def check_centroid_in_area(context, lid, coords):
|
||||
expected = Bbox(coords)
|
||||
|
||||
for idx in make_todo_list(context, lid):
|
||||
res = context.response.result[idx]
|
||||
check_for_attributes(res, 'lat,lon')
|
||||
context.response.check_row(idx, (res['lon'], res['lat']) in expected,
|
||||
f"Centroid is not inside {expected}")
|
||||
|
||||
|
||||
@then('there are(?P<neg> no)? duplicates')
|
||||
def check_for_duplicates(context, neg):
|
||||
context.execute_steps("then at least 1 result is returned")
|
||||
|
||||
resarr = set()
|
||||
has_dupe = False
|
||||
|
||||
for res in context.response.result:
|
||||
dup = (res['osm_type'], res['class'], res['type'], res['display_name'])
|
||||
if dup in resarr:
|
||||
has_dupe = True
|
||||
break
|
||||
resarr.add(dup)
|
||||
|
||||
if neg:
|
||||
assert not has_dupe, f"Found duplicate for {dup}"
|
||||
else:
|
||||
assert has_dupe, "No duplicates found"
|
||||
@@ -1,464 +0,0 @@
|
||||
# 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.
|
||||
from itertools import chain
|
||||
|
||||
import psycopg
|
||||
from psycopg import sql as pysql
|
||||
|
||||
from place_inserter import PlaceColumn
|
||||
from table_compare import NominatimID, DBRow
|
||||
|
||||
from nominatim_db.tokenizer import factory as tokenizer_factory
|
||||
|
||||
|
||||
def check_database_integrity(context):
|
||||
""" Check some generic constraints on the tables.
|
||||
"""
|
||||
with context.db.cursor(row_factory=psycopg.rows.tuple_row) as cur:
|
||||
# place_addressline should not have duplicate (place_id, address_place_id)
|
||||
cur.execute("""SELECT count(*) FROM
|
||||
(SELECT place_id, address_place_id, count(*) as c
|
||||
FROM place_addressline GROUP BY place_id, address_place_id) x
|
||||
WHERE c > 1""")
|
||||
assert cur.fetchone()[0] == 0, "Duplicates found in place_addressline"
|
||||
|
||||
# word table must not have empty word_tokens
|
||||
cur.execute("SELECT count(*) FROM word WHERE word_token = ''")
|
||||
assert cur.fetchone()[0] == 0, "Empty word tokens found in word table"
|
||||
|
||||
# GIVEN ##################################
|
||||
|
||||
|
||||
@given("the (?P<named>named )?places")
|
||||
def add_data_to_place_table(context, named):
|
||||
""" Add entries into the place table. 'named places' makes sure that
|
||||
the entries get a random name when none is explicitly given.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
cur.execute('ALTER TABLE place DISABLE TRIGGER place_before_insert')
|
||||
for row in context.table:
|
||||
PlaceColumn(context).add_row(row, named is not None).db_insert(cur)
|
||||
cur.execute('ALTER TABLE place ENABLE TRIGGER place_before_insert')
|
||||
|
||||
|
||||
@given("the relations")
|
||||
def add_data_to_planet_relations(context):
|
||||
""" Add entries into the osm2pgsql relation middle table. This is needed
|
||||
for tests on data that looks up members.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
cur.execute("SELECT value FROM osm2pgsql_properties WHERE property = 'db_format'")
|
||||
row = cur.fetchone()
|
||||
if row is None or row['value'] == '1':
|
||||
for r in context.table:
|
||||
last_node = 0
|
||||
last_way = 0
|
||||
parts = []
|
||||
if r['members']:
|
||||
members = []
|
||||
for m in r['members'].split(','):
|
||||
mid = NominatimID(m)
|
||||
if mid.typ == 'N':
|
||||
parts.insert(last_node, int(mid.oid))
|
||||
last_node += 1
|
||||
last_way += 1
|
||||
elif mid.typ == 'W':
|
||||
parts.insert(last_way, int(mid.oid))
|
||||
last_way += 1
|
||||
else:
|
||||
parts.append(int(mid.oid))
|
||||
|
||||
members.extend((mid.typ.lower() + mid.oid, mid.cls or ''))
|
||||
else:
|
||||
members = None
|
||||
|
||||
tags = chain.from_iterable([(h[5:], r[h]) for h in r.headings
|
||||
if h.startswith("tags+")])
|
||||
|
||||
cur.execute("""INSERT INTO planet_osm_rels (id, way_off, rel_off,
|
||||
parts, members, tags)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)""",
|
||||
(r['id'], last_node, last_way, parts, members, list(tags)))
|
||||
else:
|
||||
for r in context.table:
|
||||
if r['members']:
|
||||
members = []
|
||||
for m in r['members'].split(','):
|
||||
mid = NominatimID(m)
|
||||
members.append({'ref': mid.oid, 'role': mid.cls or '', 'type': mid.typ})
|
||||
else:
|
||||
members = []
|
||||
|
||||
tags = {h[5:]: r[h] for h in r.headings if h.startswith("tags+")}
|
||||
|
||||
cur.execute("""INSERT INTO planet_osm_rels (id, tags, members)
|
||||
VALUES (%s, %s, %s)""",
|
||||
(r['id'], psycopg.types.json.Json(tags),
|
||||
psycopg.types.json.Json(members)))
|
||||
|
||||
|
||||
@given("the ways")
|
||||
def add_data_to_planet_ways(context):
|
||||
""" Add entries into the osm2pgsql way middle table. This is necessary for
|
||||
tests on that that looks up node ids in this table.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
cur.execute("SELECT value FROM osm2pgsql_properties WHERE property = 'db_format'")
|
||||
row = cur.fetchone()
|
||||
json_tags = row is not None and row['value'] != '1'
|
||||
for r in context.table:
|
||||
if json_tags:
|
||||
tags = psycopg.types.json.Json({h[5:]: r[h] for h in r.headings
|
||||
if h.startswith("tags+")})
|
||||
else:
|
||||
tags = list(chain.from_iterable([(h[5:], r[h])
|
||||
for h in r.headings if h.startswith("tags+")]))
|
||||
nodes = [int(x.strip()) for x in r['nodes'].split(',')]
|
||||
|
||||
cur.execute("INSERT INTO planet_osm_ways (id, nodes, tags) VALUES (%s, %s, %s)",
|
||||
(r['id'], nodes, tags))
|
||||
|
||||
# WHEN ##################################
|
||||
|
||||
|
||||
@when("importing")
|
||||
def import_and_index_data_from_place_table(context):
|
||||
""" Import data previously set up in the place table.
|
||||
"""
|
||||
context.nominatim.run_nominatim('import', '--continue', 'load-data',
|
||||
'--index-noanalyse', '-q',
|
||||
'--offline')
|
||||
|
||||
check_database_integrity(context)
|
||||
|
||||
# Remove the output of the input, when all was right. Otherwise it will be
|
||||
# output when there are errors that had nothing to do with the import
|
||||
# itself.
|
||||
context.log_capture.buffer.clear()
|
||||
|
||||
|
||||
@when("updating places")
|
||||
def update_place_table(context):
|
||||
""" Update the place table with the given data. Also runs all triggers
|
||||
related to updates and reindexes the new data.
|
||||
"""
|
||||
context.nominatim.run_nominatim('refresh', '--functions')
|
||||
with context.db.cursor() as cur:
|
||||
for row in context.table:
|
||||
col = PlaceColumn(context).add_row(row, False)
|
||||
col.db_delete(cur)
|
||||
col.db_insert(cur)
|
||||
cur.execute('SELECT flush_deleted_places()')
|
||||
|
||||
context.nominatim.reindex_placex(context.db)
|
||||
check_database_integrity(context)
|
||||
|
||||
# Remove the output of the input, when all was right. Otherwise it will be
|
||||
# output when there are errors that had nothing to do with the import
|
||||
# itself.
|
||||
context.log_capture.buffer.clear()
|
||||
|
||||
|
||||
@when("updating postcodes")
|
||||
def update_postcodes(context):
|
||||
""" Rerun the calculation of postcodes.
|
||||
"""
|
||||
context.nominatim.run_nominatim('refresh', '--postcodes')
|
||||
|
||||
|
||||
@when("marking for delete (?P<oids>.*)")
|
||||
def delete_places(context, oids):
|
||||
""" Remove entries from the place table. Multiple ids may be given
|
||||
separated by commas. Also runs all triggers
|
||||
related to updates and reindexes the new data.
|
||||
"""
|
||||
context.nominatim.run_nominatim('refresh', '--functions')
|
||||
with context.db.cursor() as cur:
|
||||
cur.execute('TRUNCATE place_to_be_deleted')
|
||||
for oid in oids.split(','):
|
||||
NominatimID(oid).query_osm_id(cur, 'DELETE FROM place WHERE {}')
|
||||
cur.execute('SELECT flush_deleted_places()')
|
||||
|
||||
context.nominatim.reindex_placex(context.db)
|
||||
|
||||
# Remove the output of the input, when all was right. Otherwise it will be
|
||||
# output when there are errors that had nothing to do with the import
|
||||
# itself.
|
||||
context.log_capture.buffer.clear()
|
||||
|
||||
# THEN ##################################
|
||||
|
||||
|
||||
@then("(?P<table>placex|place) contains(?P<exact> exactly)?")
|
||||
def check_place_contents(context, table, exact):
|
||||
""" Check contents of place/placex tables. Each row represents a table row
|
||||
and all data must match. Data not present in the expected table, may
|
||||
be arbitrary. The rows are identified via the 'object' column which must
|
||||
have an identifier of the form '<NRW><osm id>[:<class>]'. When multiple
|
||||
rows match (for example because 'class' was left out and there are
|
||||
multiple entries for the given OSM object) then all must match. All
|
||||
expected rows are expected to be present with at least one database row.
|
||||
When 'exactly' is given, there must not be additional rows in the database.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
expected_content = set()
|
||||
for row in context.table:
|
||||
nid = NominatimID(row['object'])
|
||||
query = """SELECT *, ST_AsText(geometry) as geomtxt,
|
||||
ST_GeometryType(geometry) as geometrytype """
|
||||
if table == 'placex':
|
||||
query += ' ,ST_X(centroid) as cx, ST_Y(centroid) as cy'
|
||||
query += " FROM %s WHERE {}" % (table, )
|
||||
nid.query_osm_id(cur, query)
|
||||
assert cur.rowcount > 0, "No rows found for " + row['object']
|
||||
|
||||
for res in cur:
|
||||
if exact:
|
||||
expected_content.add((res['osm_type'], res['osm_id'], res['class']))
|
||||
|
||||
DBRow(nid, res, context).assert_row(row, ['object'])
|
||||
|
||||
if exact:
|
||||
cur.execute(pysql.SQL('SELECT osm_type, osm_id, class from')
|
||||
+ pysql.Identifier(table))
|
||||
actual = set([(r['osm_type'], r['osm_id'], r['class']) for r in cur])
|
||||
assert expected_content == actual, \
|
||||
f"Missing entries: {expected_content - actual}\n" \
|
||||
f"Not expected in table: {actual - expected_content}"
|
||||
|
||||
|
||||
@then("(?P<table>placex|place) has no entry for (?P<oid>.*)")
|
||||
def check_place_has_entry(context, table, oid):
|
||||
""" Ensure that no database row for the given object exists. The ID
|
||||
must be of the form '<NRW><osm id>[:<class>]'.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
NominatimID(oid).query_osm_id(cur, "SELECT * FROM %s where {}" % table)
|
||||
assert cur.rowcount == 0, \
|
||||
"Found {} entries for ID {}".format(cur.rowcount, oid)
|
||||
|
||||
|
||||
@then("search_name contains(?P<exclude> not)?")
|
||||
def check_search_name_contents(context, exclude):
|
||||
""" Check contents of place/placex tables. Each row represents a table row
|
||||
and all data must match. Data not present in the expected table, may
|
||||
be arbitrary. The rows are identified via the 'object' column which must
|
||||
have an identifier of the form '<NRW><osm id>[:<class>]'. All
|
||||
expected rows are expected to be present with at least one database row.
|
||||
"""
|
||||
tokenizer = tokenizer_factory.get_tokenizer_for_db(context.nominatim.get_test_config())
|
||||
|
||||
with tokenizer.name_analyzer() as analyzer:
|
||||
with context.db.cursor() as cur:
|
||||
for row in context.table:
|
||||
nid = NominatimID(row['object'])
|
||||
nid.row_by_place_id(cur, 'search_name',
|
||||
['ST_X(centroid) as cx', 'ST_Y(centroid) as cy'])
|
||||
assert cur.rowcount > 0, "No rows found for " + row['object']
|
||||
|
||||
for res in cur:
|
||||
db_row = DBRow(nid, res, context)
|
||||
for name, value in zip(row.headings, row.cells):
|
||||
if name in ('name_vector', 'nameaddress_vector'):
|
||||
items = [x.strip() for x in value.split(',')]
|
||||
tokens = analyzer.get_word_token_info(items)
|
||||
|
||||
if not exclude:
|
||||
assert len(tokens) >= len(items), \
|
||||
f"No word entry found for {value}. Entries found: {len(tokens)}"
|
||||
for word, token, wid in tokens:
|
||||
if exclude:
|
||||
assert wid not in res[name], \
|
||||
"Found term for {}/{}: {}".format(nid, name, wid)
|
||||
else:
|
||||
assert wid in res[name], \
|
||||
"Missing term for {}/{}: {}".format(nid, name, wid)
|
||||
elif name != 'object':
|
||||
assert db_row.contains(name, value), db_row.assert_msg(name, value)
|
||||
|
||||
|
||||
@then("search_name has no entry for (?P<oid>.*)")
|
||||
def check_search_name_has_entry(context, oid):
|
||||
""" Check that there is noentry in the search_name table for the given
|
||||
objects. IDs are in format '<NRW><osm id>[:<class>]'.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
NominatimID(oid).row_by_place_id(cur, 'search_name')
|
||||
|
||||
assert cur.rowcount == 0, \
|
||||
"Found {} entries for ID {}".format(cur.rowcount, oid)
|
||||
|
||||
|
||||
@then("location_postcode contains exactly")
|
||||
def check_location_postcode(context):
|
||||
""" Check full contents for location_postcode table. Each row represents a table row
|
||||
and all data must match. Data not present in the expected table, may
|
||||
be arbitrary. The rows are identified via 'country' and 'postcode' columns.
|
||||
All rows must be present as excepted and there must not be additional
|
||||
rows.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
cur.execute("SELECT *, ST_AsText(geometry) as geomtxt FROM location_postcode")
|
||||
assert cur.rowcount == len(list(context.table)), \
|
||||
"Postcode table has {cur.rowcount} rows, expected {len(list(context.table))}."
|
||||
|
||||
results = {}
|
||||
for row in cur:
|
||||
key = (row['country_code'], row['postcode'])
|
||||
assert key not in results, "Postcode table has duplicate entry: {}".format(row)
|
||||
results[key] = DBRow((row['country_code'], row['postcode']), row, context)
|
||||
|
||||
for row in context.table:
|
||||
db_row = results.get((row['country'], row['postcode']))
|
||||
assert db_row is not None, \
|
||||
f"Missing row for country '{row['country']}' postcode '{row['postcode']}'."
|
||||
|
||||
db_row.assert_row(row, ('country', 'postcode'))
|
||||
|
||||
|
||||
@then("there are(?P<exclude> no)? word tokens for postcodes (?P<postcodes>.*)")
|
||||
def check_word_table_for_postcodes(context, exclude, postcodes):
|
||||
""" Check that the tokenizer produces postcode tokens for the given
|
||||
postcodes. The postcodes are a comma-separated list of postcodes.
|
||||
Whitespace matters.
|
||||
"""
|
||||
nctx = context.nominatim
|
||||
tokenizer = tokenizer_factory.get_tokenizer_for_db(nctx.get_test_config())
|
||||
with tokenizer.name_analyzer() as ana:
|
||||
plist = [ana.normalize_postcode(p) for p in postcodes.split(',')]
|
||||
|
||||
plist.sort()
|
||||
|
||||
with context.db.cursor() as cur:
|
||||
cur.execute("SELECT word FROM word WHERE type = 'P' and word = any(%s)",
|
||||
(plist,))
|
||||
|
||||
found = [row['word'] for row in cur]
|
||||
assert len(found) == len(set(found)), f"Duplicate rows for postcodes: {found}"
|
||||
|
||||
if exclude:
|
||||
assert len(found) == 0, f"Unexpected postcodes: {found}"
|
||||
else:
|
||||
assert set(found) == set(plist), \
|
||||
f"Missing postcodes {set(plist) - set(found)}. Found: {found}"
|
||||
|
||||
|
||||
@then("place_addressline contains")
|
||||
def check_place_addressline(context):
|
||||
""" Check the contents of the place_addressline table. Each row represents
|
||||
a table row and all data must match. Data not present in the expected
|
||||
table, may be arbitrary. The rows are identified via the 'object' column,
|
||||
representing the addressee and the 'address' column, representing the
|
||||
address item.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
for row in context.table:
|
||||
nid = NominatimID(row['object'])
|
||||
pid = nid.get_place_id(cur)
|
||||
apid = NominatimID(row['address']).get_place_id(cur)
|
||||
cur.execute(""" SELECT * FROM place_addressline
|
||||
WHERE place_id = %s AND address_place_id = %s""",
|
||||
(pid, apid))
|
||||
assert cur.rowcount > 0, \
|
||||
f"No rows found for place {row['object']} and address {row['address']}."
|
||||
|
||||
for res in cur:
|
||||
DBRow(nid, res, context).assert_row(row, ('address', 'object'))
|
||||
|
||||
|
||||
@then("place_addressline doesn't contain")
|
||||
def check_place_addressline_exclude(context):
|
||||
""" Check that the place_addressline doesn't contain any entries for the
|
||||
given addressee/address item pairs.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
for row in context.table:
|
||||
pid = NominatimID(row['object']).get_place_id(cur)
|
||||
apid = NominatimID(row['address']).get_place_id(cur, allow_empty=True)
|
||||
if apid is not None:
|
||||
cur.execute(""" SELECT * FROM place_addressline
|
||||
WHERE place_id = %s AND address_place_id = %s""",
|
||||
(pid, apid))
|
||||
assert cur.rowcount == 0, \
|
||||
f"Row found for place {row['object']} and address {row['address']}."
|
||||
|
||||
|
||||
@then(r"W(?P<oid>\d+) expands to(?P<neg> no)? interpolation")
|
||||
def check_location_property_osmline(context, oid, neg):
|
||||
""" Check that the given way is present in the interpolation table.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
cur.execute("""SELECT *, ST_AsText(linegeo) as geomtxt
|
||||
FROM location_property_osmline
|
||||
WHERE osm_id = %s AND startnumber IS NOT NULL""",
|
||||
(oid, ))
|
||||
|
||||
if neg:
|
||||
assert cur.rowcount == 0, "Interpolation found for way {}.".format(oid)
|
||||
return
|
||||
|
||||
todo = list(range(len(list(context.table))))
|
||||
for res in cur:
|
||||
for i in todo:
|
||||
row = context.table[i]
|
||||
if (int(row['start']) == res['startnumber']
|
||||
and int(row['end']) == res['endnumber']):
|
||||
todo.remove(i)
|
||||
break
|
||||
else:
|
||||
assert False, "Unexpected row " + str(res)
|
||||
|
||||
DBRow(oid, res, context).assert_row(row, ('start', 'end'))
|
||||
|
||||
assert not todo, f"Unmatched lines in table: {list(context.table[i] for i in todo)}"
|
||||
|
||||
|
||||
@then("location_property_osmline contains(?P<exact> exactly)?")
|
||||
def check_osmline_contents(context, exact):
|
||||
""" Check contents of the interpolation table. Each row represents a table row
|
||||
and all data must match. Data not present in the expected table, may
|
||||
be arbitrary. The rows are identified via the 'object' column which must
|
||||
have an identifier of the form '<osm id>[:<startnumber>]'. When multiple
|
||||
rows match (for example because 'startnumber' was left out and there are
|
||||
multiple entries for the given OSM object) then all must match. All
|
||||
expected rows are expected to be present with at least one database row.
|
||||
When 'exactly' is given, there must not be additional rows in the database.
|
||||
"""
|
||||
with context.db.cursor() as cur:
|
||||
expected_content = set()
|
||||
for row in context.table:
|
||||
if ':' in row['object']:
|
||||
nid, start = row['object'].split(':', 2)
|
||||
start = int(start)
|
||||
else:
|
||||
nid, start = row['object'], None
|
||||
|
||||
query = """SELECT *, ST_AsText(linegeo) as geomtxt,
|
||||
ST_GeometryType(linegeo) as geometrytype
|
||||
FROM location_property_osmline WHERE osm_id=%s"""
|
||||
|
||||
if ':' in row['object']:
|
||||
query += ' and startnumber = %s'
|
||||
params = [int(val) for val in row['object'].split(':', 2)]
|
||||
else:
|
||||
params = (int(row['object']), )
|
||||
|
||||
cur.execute(query, params)
|
||||
assert cur.rowcount > 0, "No rows found for " + row['object']
|
||||
|
||||
for res in cur:
|
||||
if exact:
|
||||
expected_content.add((res['osm_id'], res['startnumber']))
|
||||
|
||||
DBRow(nid, res, context).assert_row(row, ['object'])
|
||||
|
||||
if exact:
|
||||
cur.execute('SELECT osm_id, startnumber from location_property_osmline')
|
||||
actual = set([(r['osm_id'], r['startnumber']) for r in cur])
|
||||
assert expected_content == actual, \
|
||||
f"Missing entries: {expected_content - actual}\n" \
|
||||
f"Not expected in table: {actual - expected_content}"
|
||||
@@ -1,144 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
import tempfile
|
||||
import random
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from nominatim_db.tools.exec_utils import run_osm2pgsql
|
||||
from nominatim_db.tools.replication import run_osm2pgsql_updates
|
||||
|
||||
from geometry_alias import ALIASES
|
||||
|
||||
|
||||
def get_osm2pgsql_options(nominatim_env, fname, append):
|
||||
return dict(import_file=fname,
|
||||
osm2pgsql='osm2pgsql',
|
||||
osm2pgsql_cache=50,
|
||||
osm2pgsql_style=str(nominatim_env.get_test_config().get_import_style_file()),
|
||||
osm2pgsql_style_path=nominatim_env.get_test_config().lib_dir.lua,
|
||||
threads=1,
|
||||
dsn=nominatim_env.get_libpq_dsn(),
|
||||
flatnode_file='',
|
||||
tablespaces=dict(slim_data='', slim_index='',
|
||||
main_data='', main_index=''),
|
||||
append=append)
|
||||
|
||||
|
||||
def write_opl_file(opl, grid):
|
||||
""" Create a temporary OSM file from OPL and return the file name. It is
|
||||
the responsibility of the caller to delete the file again.
|
||||
|
||||
Node with missing coordinates, can retrieve their coordinates from
|
||||
a supplied grid. Failing that a random coordinate is assigned.
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.opl', delete=False) as fd:
|
||||
for line in opl.splitlines():
|
||||
if line.startswith('n') and line.find(' x') < 0:
|
||||
coord = grid.grid_node(int(line[1:].split(' ')[0]))
|
||||
if coord is None:
|
||||
coord = (random.uniform(-180, 180), random.uniform(-90, 90))
|
||||
line += " x%f y%f" % coord
|
||||
fd.write(line.encode('utf-8'))
|
||||
fd.write(b'\n')
|
||||
|
||||
return fd.name
|
||||
|
||||
|
||||
@given('the lua style file')
|
||||
def lua_style_file(context):
|
||||
""" Define a custom style file to use for the import.
|
||||
"""
|
||||
style = Path(context.nominatim.website_dir.name) / 'custom.lua'
|
||||
style.write_text(context.text)
|
||||
context.nominatim.test_env['NOMINATIM_IMPORT_STYLE'] = str(style)
|
||||
|
||||
|
||||
@given(u'the ([0-9.]+ )?grid(?: with origin (?P<origin>.*))?')
|
||||
def define_node_grid(context, grid_step, origin):
|
||||
"""
|
||||
Define a grid of node positions.
|
||||
Use a table to define the grid. The nodes must be integer ids. Optionally
|
||||
you can give the grid distance. The default is 0.00001 degrees.
|
||||
"""
|
||||
if grid_step is not None:
|
||||
grid_step = float(grid_step.strip())
|
||||
else:
|
||||
grid_step = 0.00001
|
||||
|
||||
if origin:
|
||||
if ',' in origin:
|
||||
# TODO coordinate
|
||||
coords = origin.split(',')
|
||||
if len(coords) != 2:
|
||||
raise RuntimeError('Grid origin expects origin with x,y coordinates.')
|
||||
origin = (float(coords[0]), float(coords[1]))
|
||||
elif origin in ALIASES:
|
||||
origin = ALIASES[origin]
|
||||
else:
|
||||
raise RuntimeError('Grid origin must be either coordinate or alias.')
|
||||
else:
|
||||
origin = (0.0, 0.0)
|
||||
|
||||
context.osm.set_grid([context.table.headings] + [list(h) for h in context.table],
|
||||
grid_step, origin)
|
||||
|
||||
|
||||
@when(u'loading osm data')
|
||||
def load_osm_file(context):
|
||||
"""
|
||||
Load the given data into a freshly created test database using osm2pgsql.
|
||||
No further indexing is done.
|
||||
|
||||
The data is expected as attached text in OPL format.
|
||||
"""
|
||||
# create an OSM file and import it
|
||||
fname = write_opl_file(context.text, context.osm)
|
||||
try:
|
||||
run_osm2pgsql(get_osm2pgsql_options(context.nominatim, fname, append=False))
|
||||
finally:
|
||||
os.remove(fname)
|
||||
|
||||
# reintroduce the triggers/indexes we've lost by having osm2pgsql set up place again
|
||||
cur = context.db.cursor()
|
||||
cur.execute("""CREATE TRIGGER place_before_delete BEFORE DELETE ON place
|
||||
FOR EACH ROW EXECUTE PROCEDURE place_delete()""")
|
||||
cur.execute("""CREATE TRIGGER place_before_insert BEFORE INSERT ON place
|
||||
FOR EACH ROW EXECUTE PROCEDURE place_insert()""")
|
||||
cur.execute("""CREATE UNIQUE INDEX idx_place_osm_unique ON place
|
||||
USING btree(osm_id,osm_type,class,type)""")
|
||||
context.db.commit()
|
||||
|
||||
|
||||
@when(u'updating osm data')
|
||||
def update_from_osm_file(context):
|
||||
"""
|
||||
Update a database previously populated with 'loading osm data'.
|
||||
Needs to run indexing on the existing data first to yield the correct result.
|
||||
|
||||
The data is expected as attached text in OPL format.
|
||||
"""
|
||||
context.nominatim.copy_from_place(context.db)
|
||||
context.nominatim.run_nominatim('index')
|
||||
context.nominatim.run_nominatim('refresh', '--functions')
|
||||
|
||||
# create an OSM file and import it
|
||||
fname = write_opl_file(context.text, context.osm)
|
||||
try:
|
||||
run_osm2pgsql_updates(context.db,
|
||||
get_osm2pgsql_options(context.nominatim, fname, append=True))
|
||||
finally:
|
||||
os.remove(fname)
|
||||
|
||||
|
||||
@when('indexing')
|
||||
def index_database(context):
|
||||
"""
|
||||
Run the Nominatim indexing step. This will process data previously
|
||||
loaded with 'updating osm data'
|
||||
"""
|
||||
context.nominatim.run_nominatim('index')
|
||||
@@ -1,230 +0,0 @@
|
||||
# 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.
|
||||
"""
|
||||
Functions to facilitate accessing and comparing the content of DB tables.
|
||||
"""
|
||||
import math
|
||||
import re
|
||||
import json
|
||||
|
||||
import psycopg
|
||||
from psycopg import sql as pysql
|
||||
|
||||
ID_REGEX = re.compile(r"(?P<typ>[NRW])(?P<oid>\d+)(:(?P<cls>\w+))?")
|
||||
|
||||
|
||||
class NominatimID:
|
||||
""" Splits a unique identifier for places into its components.
|
||||
As place_ids cannot be used for testing, we use a unique
|
||||
identifier instead that is of the form <osmtype><osmid>[:<class>].
|
||||
"""
|
||||
|
||||
def __init__(self, oid):
|
||||
self.typ = self.oid = self.cls = None
|
||||
|
||||
if oid is not None:
|
||||
m = ID_REGEX.fullmatch(oid)
|
||||
assert m is not None, \
|
||||
"ID '{}' not of form <osmtype><osmid>[:<class>]".format(oid)
|
||||
|
||||
self.typ = m.group('typ')
|
||||
self.oid = m.group('oid')
|
||||
self.cls = m.group('cls')
|
||||
|
||||
def __str__(self):
|
||||
if self.cls is None:
|
||||
return self.typ + self.oid
|
||||
|
||||
return '{self.typ}{self.oid}:{self.cls}'.format(self=self)
|
||||
|
||||
def query_osm_id(self, cur, query):
|
||||
""" Run a query on cursor `cur` using osm ID, type and class. The
|
||||
`query` string must contain exactly one placeholder '{}' where
|
||||
the 'where' query should go.
|
||||
"""
|
||||
where = 'osm_type = %s and osm_id = %s'
|
||||
params = [self.typ, self. oid]
|
||||
|
||||
if self.cls is not None:
|
||||
where += ' and class = %s'
|
||||
params.append(self.cls)
|
||||
|
||||
cur.execute(query.format(where), params)
|
||||
|
||||
def row_by_place_id(self, cur, table, extra_columns=None):
|
||||
""" Get a row by place_id from the given table using cursor `cur`.
|
||||
extra_columns may contain a list additional elements for the select
|
||||
part of the query.
|
||||
"""
|
||||
pid = self.get_place_id(cur)
|
||||
query = "SELECT {} FROM {} WHERE place_id = %s".format(
|
||||
','.join(['*'] + (extra_columns or [])), table)
|
||||
cur.execute(query, (pid, ))
|
||||
|
||||
def get_place_id(self, cur, allow_empty=False):
|
||||
""" Look up the place id for the ID. Throws an assertion if the ID
|
||||
is not unique.
|
||||
"""
|
||||
self.query_osm_id(cur, "SELECT place_id FROM placex WHERE {}")
|
||||
if cur.rowcount == 0 and allow_empty:
|
||||
return None
|
||||
|
||||
assert cur.rowcount == 1, \
|
||||
"Place ID {!s} not unique. Found {} entries.".format(self, cur.rowcount)
|
||||
|
||||
return cur.fetchone()['place_id']
|
||||
|
||||
|
||||
class DBRow:
|
||||
""" Represents a row from a database and offers comparison functions.
|
||||
"""
|
||||
def __init__(self, nid, db_row, context):
|
||||
self.nid = nid
|
||||
self.db_row = db_row
|
||||
self.context = context
|
||||
|
||||
def assert_row(self, row, exclude_columns):
|
||||
""" Check that all columns of the given behave row are contained
|
||||
in the database row. Exclude behave rows with the names given
|
||||
in the `exclude_columns` list.
|
||||
"""
|
||||
for name, value in zip(row.headings, row.cells):
|
||||
if name not in exclude_columns:
|
||||
assert self.contains(name, value), self.assert_msg(name, value)
|
||||
|
||||
def contains(self, name, expected):
|
||||
""" Check that the DB row contains a column `name` with the given value.
|
||||
"""
|
||||
if '+' in name:
|
||||
column, field = name.split('+', 1)
|
||||
return self._contains_hstore_value(column, field, expected)
|
||||
|
||||
if name == 'geometry':
|
||||
return self._has_geometry(expected)
|
||||
|
||||
if name not in self.db_row:
|
||||
return False
|
||||
|
||||
actual = self.db_row[name]
|
||||
|
||||
if expected == '-':
|
||||
return actual is None
|
||||
|
||||
if name == 'name' and ':' not in expected:
|
||||
return self._compare_column(actual[name], expected)
|
||||
|
||||
if 'place_id' in name:
|
||||
return self._compare_place_id(actual, expected)
|
||||
|
||||
if name == 'centroid':
|
||||
return self._has_centroid(expected)
|
||||
|
||||
return self._compare_column(actual, expected)
|
||||
|
||||
def _contains_hstore_value(self, column, field, expected):
|
||||
if column == 'addr':
|
||||
column = 'address'
|
||||
|
||||
if column not in self.db_row:
|
||||
return False
|
||||
|
||||
if expected == '-':
|
||||
return self.db_row[column] is None or field not in self.db_row[column]
|
||||
|
||||
if self.db_row[column] is None:
|
||||
return False
|
||||
|
||||
return self._compare_column(self.db_row[column].get(field), expected)
|
||||
|
||||
def _compare_column(self, actual, expected):
|
||||
if isinstance(actual, dict):
|
||||
return actual == eval('{' + expected + '}')
|
||||
|
||||
return str(actual) == expected
|
||||
|
||||
def _compare_place_id(self, actual, expected):
|
||||
if expected == '0':
|
||||
return actual == 0
|
||||
|
||||
with self.context.db.cursor() as cur:
|
||||
return NominatimID(expected).get_place_id(cur) == actual
|
||||
|
||||
def _has_centroid(self, expected):
|
||||
if expected == 'in geometry':
|
||||
with self.context.db.cursor(row_factory=psycopg.rows.tuple_row) as cur:
|
||||
cur.execute("""SELECT ST_Within(ST_SetSRID(ST_Point(%(cx)s, %(cy)s), 4326),
|
||||
ST_SetSRID(%(geomtxt)s::geometry, 4326))""",
|
||||
(self.db_row))
|
||||
return cur.fetchone()[0]
|
||||
|
||||
if ' ' in expected:
|
||||
x, y = expected.split(' ')
|
||||
else:
|
||||
x, y = self.context.osm.grid_node(int(expected))
|
||||
|
||||
return math.isclose(float(x), self.db_row['cx']) \
|
||||
and math.isclose(float(y), self.db_row['cy'])
|
||||
|
||||
def _has_geometry(self, expected):
|
||||
geom = self.context.osm.parse_geometry(expected)
|
||||
with self.context.db.cursor(row_factory=psycopg.rows.tuple_row) as cur:
|
||||
cur.execute(pysql.SQL("""
|
||||
SELECT ST_Equals(ST_SnapToGrid({}, 0.00001, 0.00001),
|
||||
ST_SnapToGrid(ST_SetSRID({}::geometry, 4326), 0.00001, 0.00001))""")
|
||||
.format(pysql.SQL(geom),
|
||||
pysql.Literal(self.db_row['geomtxt'])))
|
||||
return cur.fetchone()[0]
|
||||
|
||||
def assert_msg(self, name, value):
|
||||
""" Return a string with an informative message for a failed compare.
|
||||
"""
|
||||
msg = "\nBad column '{}' in row '{!s}'.".format(name, self.nid)
|
||||
actual = self._get_actual(name)
|
||||
if actual is not None:
|
||||
msg += " Expected: {}, got: {}.".format(value, actual)
|
||||
else:
|
||||
msg += " No such column."
|
||||
|
||||
return msg + "\nFull DB row: {}".format(json.dumps(dict(self.db_row),
|
||||
indent=4, default=str))
|
||||
|
||||
def _get_actual(self, name):
|
||||
if '+' in name:
|
||||
column, field = name.split('+', 1)
|
||||
if column == 'addr':
|
||||
column = 'address'
|
||||
return (self.db_row.get(column) or {}).get(field)
|
||||
|
||||
if name == 'geometry':
|
||||
return self.db_row['geomtxt']
|
||||
|
||||
if name not in self.db_row:
|
||||
return None
|
||||
|
||||
if name == 'centroid':
|
||||
return "POINT({cx} {cy})".format(**self.db_row)
|
||||
|
||||
actual = self.db_row[name]
|
||||
|
||||
if 'place_id' in name:
|
||||
if actual is None:
|
||||
return '<null>'
|
||||
|
||||
if actual == 0:
|
||||
return "place ID 0"
|
||||
|
||||
with self.context.db.cursor(row_factory=psycopg.rows.tuple_row) as cur:
|
||||
cur.execute("""SELECT osm_type, osm_id, class
|
||||
FROM placex WHERE place_id = %s""",
|
||||
(actual, ))
|
||||
|
||||
if cur.rowcount == 1:
|
||||
return "{0[0]}{0[1]}:{0[2]}".format(cur.fetchone())
|
||||
|
||||
return "[place ID {} not found]".format(actual)
|
||||
|
||||
return actual
|
||||
Reference in New Issue
Block a user