mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-14 10:27:57 +00:00
Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f97a0a76f2 | ||
|
|
cf9b946eba | ||
|
|
7dc3924a3c | ||
|
|
20cf4b56b9 | ||
|
|
40d5b78eb8 | ||
|
|
8d0e767826 | ||
|
|
87a8c246a0 | ||
|
|
90050de717 | ||
|
|
10a7d1106d | ||
|
|
f2236f68f1 | ||
|
|
831fccdaee | ||
|
|
d2e691b63f | ||
|
|
2a508b6c99 | ||
|
|
02c3a6fffa | ||
|
|
26348764d4 | ||
|
|
f8a56ab6e6 | ||
|
|
75b4c7e56b | ||
|
|
9f1dfb1876 | ||
|
|
730b4204f6 | ||
|
|
4898704b5a | ||
|
|
0cf470f863 | ||
|
|
6220bde2d6 | ||
|
|
a4d3b57f37 | ||
|
|
618fbc63d7 | ||
|
|
3f51cb3fd1 | ||
|
|
59a947c5f5 | ||
|
|
1952290359 | ||
|
|
1a323165f9 | ||
|
|
9c2fdf5eae | ||
|
|
800c56642b | ||
|
|
b51fed025c | ||
|
|
34b72591cc | ||
|
|
bc450d110c | ||
|
|
388acf4727 | ||
|
|
3999977941 | ||
|
|
df58870e3f | ||
|
|
478a8741db | ||
|
|
7f710d2394 | ||
|
|
06e39e42d8 | ||
|
|
2ef0e20a3f | ||
|
|
b680d81f0a | ||
|
|
e0e067b1d6 | ||
|
|
3980791cfd | ||
|
|
497e27bb9a | ||
|
|
1db717b886 | ||
|
|
b47c8ccfb1 | ||
|
|
63b055283d | ||
|
|
b80e6914e7 | ||
|
|
9d00a137fe | ||
|
|
97d9e3c548 | ||
|
|
e4180936c1 | ||
|
|
34e0ecb44f | ||
|
|
d95e9737da | ||
|
|
b34991d85f | ||
|
|
5f44aa2873 | ||
|
|
dae643c040 | ||
|
|
ee62d5e1cf | ||
|
|
fb440f29a2 | ||
|
|
0f725b1880 | ||
|
|
39f56ba4b8 | ||
|
|
6959577aa4 | ||
|
|
50d4b0a386 | ||
|
|
9ff93bdb3d | ||
|
|
e0bf553aa5 | ||
|
|
2ce2d031fa | ||
|
|
186f562dd7 | ||
|
|
c5bbeb626f | ||
|
|
3bc77629c8 | ||
|
|
6cf1287c4e | ||
|
|
a49e8b9cf7 | ||
|
|
2eeec46040 | ||
|
|
6d5a4a20c5 | ||
|
|
4665ea3e77 | ||
|
|
9cf5eee5d4 | ||
|
|
12ad95067d |
2
.flake8
2
.flake8
@@ -7,5 +7,5 @@ extend-ignore =
|
||||
per-file-ignores =
|
||||
__init__.py: F401
|
||||
test/python/utils/test_json_writer.py: E131
|
||||
test/python/conftest.py: E402
|
||||
**/conftest.py: E402
|
||||
test/bdd/*: F821
|
||||
|
||||
43
.github/workflows/ci-tests.yml
vendored
43
.github/workflows/ci-tests.yml
vendored
@@ -68,26 +68,34 @@ jobs:
|
||||
with:
|
||||
dependencies: ${{ matrix.dependencies }}
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/usr/local/bin/osm2pgsql
|
||||
key: osm2pgsql-bin-22-1
|
||||
if: matrix.ubuntu == '22'
|
||||
|
||||
- name: Compile osm2pgsql
|
||||
run: |
|
||||
sudo apt-get install -y -qq libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev libicu-dev liblua${LUA_VERSION}-dev lua-dkjson nlohmann-json3-dev
|
||||
mkdir osm2pgsql-build
|
||||
cd osm2pgsql-build
|
||||
git clone https://github.com/osm2pgsql-dev/osm2pgsql
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../osm2pgsql
|
||||
make
|
||||
sudo make install
|
||||
cd ../..
|
||||
rm -rf osm2pgsql-build
|
||||
if [ ! -f /usr/local/bin/osm2pgsql ]; then
|
||||
sudo apt-get install -y -qq libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev libicu-dev liblua${LUA_VERSION}-dev lua-dkjson nlohmann-json3-dev
|
||||
mkdir osm2pgsql-build
|
||||
cd osm2pgsql-build
|
||||
git clone https://github.com/osm2pgsql-dev/osm2pgsql
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../osm2pgsql
|
||||
make
|
||||
sudo make install
|
||||
cd ../..
|
||||
rm -rf osm2pgsql-build
|
||||
else
|
||||
sudo apt-get install -y -qq libexpat1 liblua${LUA_VERSION}
|
||||
fi
|
||||
if: matrix.ubuntu == '22'
|
||||
env:
|
||||
LUA_VERSION: ${{ matrix.lua }}
|
||||
|
||||
- name: Install test prerequisites
|
||||
run: ./venv/bin/pip install behave==1.2.6
|
||||
|
||||
- name: Install test prerequisites (apt)
|
||||
run: sudo apt-get install -y -qq python3-pytest python3-pytest-asyncio uvicorn python3-falcon python3-aiosqlite python3-pyosmium
|
||||
if: matrix.dependencies == 'apt'
|
||||
@@ -96,6 +104,9 @@ jobs:
|
||||
run: ./venv/bin/pip install pytest-asyncio falcon starlette asgi_lifespan aiosqlite osmium uvicorn
|
||||
if: matrix.dependencies == 'pip'
|
||||
|
||||
- name: Install test prerequisites
|
||||
run: ./venv/bin/pip install pytest-bdd
|
||||
|
||||
- name: Install latest flake8
|
||||
run: ./venv/bin/pip install -U flake8
|
||||
|
||||
@@ -118,8 +129,8 @@ jobs:
|
||||
|
||||
- name: BDD tests
|
||||
run: |
|
||||
../../../venv/bin/python -m behave -DREMOVE_TEMPLATE=1 --format=progress3
|
||||
working-directory: Nominatim/test/bdd
|
||||
../venv/bin/python -m pytest test/bdd --nominatim-purge
|
||||
working-directory: Nominatim
|
||||
|
||||
install:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -113,3 +113,5 @@ Checklist for releases:
|
||||
* run `nominatim --version` to confirm correct version
|
||||
* [ ] tag new release and add a release on github.com
|
||||
* [ ] build pip packages and upload to pypi
|
||||
* `make build`
|
||||
* `twine upload dist/*`
|
||||
|
||||
2
Makefile
2
Makefile
@@ -27,7 +27,7 @@ lint:
|
||||
flake8 src test/python test/bdd
|
||||
|
||||
bdd:
|
||||
cd test/bdd; behave -DREMOVE_TEMPLATE=1
|
||||
pytest test/bdd --nominatim-purge
|
||||
|
||||
# Documentation
|
||||
|
||||
|
||||
15
README.md
15
README.md
@@ -27,18 +27,25 @@ can be found at nominatim.org as well.
|
||||
|
||||
A quick summary of the necessary steps:
|
||||
|
||||
1. Create a Python virtualenv and install the packages:
|
||||
|
||||
1. Clone this git repository and download the country grid
|
||||
|
||||
git clone https://github.com/osm-search/Nominatim.git
|
||||
wget -O Nominatim/data/country_osm_grid.sql.gz https://nominatim.org/data/country_grid.sql.gz
|
||||
|
||||
2. Create a Python virtualenv and install the packages:
|
||||
|
||||
python3 -m venv nominatim-venv
|
||||
./nominatim-venv/bin/pip install packaging/nominatim-{api,db}
|
||||
|
||||
2. Create a project directory, get OSM data and import:
|
||||
3. Create a project directory, get OSM data and import:
|
||||
|
||||
mkdir nominatim-project
|
||||
cd nominatim-project
|
||||
../nominatim-venv/bin/nominatim import --osm-file <your planet file>
|
||||
../nominatim-venv/bin/nominatim import --osm-file <your planet file> 2>&1 | tee setup.log
|
||||
|
||||
3. Start the webserver:
|
||||
|
||||
4. Start the webserver:
|
||||
|
||||
./nominatim-venv/bin/pip install uvicorn falcon
|
||||
../nominatim-venv/bin/nominatim serve
|
||||
|
||||
@@ -212,7 +212,7 @@ other layers.
|
||||
The featureType allows to have a more fine-grained selection for places
|
||||
from the address layer. Results can be restricted to places that make up
|
||||
the 'state', 'country' or 'city' part of an address. A featureType of
|
||||
settlement selects any human inhabited feature from 'state' down to
|
||||
`settlement` selects any human inhabited feature from 'state' down to
|
||||
'neighbourhood'.
|
||||
|
||||
When featureType is set, then results are automatically restricted
|
||||
|
||||
@@ -602,6 +602,43 @@ results gathered so far.
|
||||
Note that under high load you may observe that users receive different results
|
||||
than usual without seeing an error. This may cause some confusion.
|
||||
|
||||
#### NOMINATIM_OUTPUT_NAMES
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Specifies order of name tags |
|
||||
| **Format:** | string: comma-separated list of tag names |
|
||||
| **Default:** | name:XX,name,brand,official_name:XX,short_name:XX,official_name,short_name,ref |
|
||||
|
||||
Specifies the order in which different name tags are used.
|
||||
The values in this list determine the preferred order of name variants,
|
||||
including language-specific names (in OSM: the name tag with and without any language suffix).
|
||||
|
||||
Comma-separated list, where :XX stands for language suffix
|
||||
(e.g. name:en) and no :XX stands for general tags (e.g. name).
|
||||
|
||||
See also [NOMINATIM_DEFAULT_LANGUAGE](#nominatim_default_language).
|
||||
|
||||
!!! note
|
||||
If NOMINATIM_OUTPUT_NAMES = `name:XX,name,short_name:XX,short_name` the search follows
|
||||
|
||||
```
|
||||
'name', 'short_name'
|
||||
```
|
||||
|
||||
if we have no preferred language order for showing search results.
|
||||
|
||||
For languages ['en', 'es'] the search follows
|
||||
|
||||
```
|
||||
'name:en', 'name:es',
|
||||
'name',
|
||||
'short_name:en', 'short_name:es',
|
||||
'short_name'
|
||||
```
|
||||
|
||||
For those familiar with the internal implementation, the `_place_*` expansion is added, but to simplify, it is not included in this example.
|
||||
|
||||
### Logging Settings
|
||||
|
||||
#### NOMINATIM_LOG_DB
|
||||
|
||||
@@ -67,7 +67,13 @@ Here is an example configuration file:
|
||||
|
||||
``` yaml
|
||||
query-preprocessing:
|
||||
- normalize
|
||||
- step: split_japanese_phrases
|
||||
- step: regex_replace
|
||||
replacements:
|
||||
- pattern: https?://[^\s]* # Filter URLs starting with http or https
|
||||
replace: ''
|
||||
- step: normalize
|
||||
|
||||
normalization:
|
||||
- ":: lower ()"
|
||||
- "ß > 'ss'" # German szet is unambiguously equal to double ss
|
||||
@@ -88,8 +94,8 @@ token-analysis:
|
||||
replacements: ['ä', 'ae']
|
||||
```
|
||||
|
||||
The configuration file contains four sections:
|
||||
`normalization`, `transliteration`, `sanitizers` and `token-analysis`.
|
||||
The configuration file contains five sections:
|
||||
`query-preprocessing`, `normalization`, `transliteration`, `sanitizers` and `token-analysis`.
|
||||
|
||||
#### Query preprocessing
|
||||
|
||||
@@ -106,6 +112,19 @@ The following is a list of preprocessors that are shipped with Nominatim.
|
||||
heading_level: 6
|
||||
docstring_section_style: spacy
|
||||
|
||||
##### regex-replace
|
||||
|
||||
::: nominatim_api.query_preprocessing.regex_replace
|
||||
options:
|
||||
members: False
|
||||
heading_level: 6
|
||||
docstring_section_style: spacy
|
||||
description:
|
||||
This option runs any given regex pattern on the input and replaces values accordingly
|
||||
replacements:
|
||||
- pattern: regex pattern
|
||||
replace: string to replace with
|
||||
|
||||
|
||||
#### Normalization and Transliteration
|
||||
|
||||
|
||||
@@ -25,15 +25,15 @@ following packages should get you started:
|
||||
|
||||
## Prerequisites for testing and documentation
|
||||
|
||||
The Nominatim test suite consists of behavioural tests (using behave) and
|
||||
The Nominatim test suite consists of behavioural tests (using pytest-bdd) and
|
||||
unit tests (using pytest). It has the following additional requirements:
|
||||
|
||||
* [behave test framework](https://behave.readthedocs.io) >= 1.2.6
|
||||
* [flake8](https://flake8.pycqa.org/en/stable/) (CI always runs the latest version from pip)
|
||||
* [mypy](http://mypy-lang.org/) (plus typing information for external libs)
|
||||
* [Python Typing Extensions](https://github.com/python/typing_extensions) (for Python < 3.9)
|
||||
* [pytest](https://pytest.org)
|
||||
* [pytest-asyncio](https://pytest-asyncio.readthedocs.io)
|
||||
* [pytest-bdd](https://pytest-bdd.readthedocs.io)
|
||||
|
||||
For testing the Python search frontend, you need to install extra dependencies
|
||||
depending on your choice of webserver framework:
|
||||
@@ -48,9 +48,6 @@ The documentation is built with mkdocs:
|
||||
* [mkdocs-material](https://squidfunk.github.io/mkdocs-material/)
|
||||
* [mkdocs-gen-files](https://oprypin.github.io/mkdocs-gen-files/)
|
||||
|
||||
Please be aware that tests always run against the globally installed
|
||||
osm2pgsql, so you need to have this set up. If you want to test against
|
||||
the vendored version of osm2pgsql, you need to set the PATH accordingly.
|
||||
|
||||
### Installing prerequisites on Ubuntu/Debian
|
||||
|
||||
@@ -70,8 +67,9 @@ To set up the virtual environment with all necessary packages run:
|
||||
virtualenv ~/nominatim-dev-venv
|
||||
~/nominatim-dev-venv/bin/pip install\
|
||||
psutil 'psycopg[binary]' PyICU SQLAlchemy \
|
||||
python-dotenv jinja2 pyYAML behave \
|
||||
mkdocs 'mkdocstrings[python]' mkdocs-gen-files pytest pytest-asyncio flake8 \
|
||||
python-dotenv jinja2 pyYAML \
|
||||
mkdocs 'mkdocstrings[python]' mkdocs-gen-files \
|
||||
pytest pytest-asyncio pytest-bdd flake8 \
|
||||
types-jinja2 types-markupsafe types-psutil types-psycopg2 \
|
||||
types-pygments types-pyyaml types-requests types-ujson \
|
||||
types-urllib3 typing-extensions unicorn falcon starlette \
|
||||
|
||||
@@ -43,53 +43,53 @@ The name of the pytest binary depends on your installation.
|
||||
## BDD Functional Tests (`test/bdd`)
|
||||
|
||||
Functional tests are written as BDD instructions. For more information on
|
||||
the philosophy of BDD testing, see the
|
||||
[Behave manual](http://pythonhosted.org/behave/philosophy.html).
|
||||
|
||||
The following explanation assume that the reader is familiar with the BDD
|
||||
notations of features, scenarios and steps.
|
||||
|
||||
All possible steps can be found in the `steps` directory and should ideally
|
||||
be documented.
|
||||
the philosophy of BDD testing, read the Wikipedia article on
|
||||
[Behaviour-driven development](https://en.wikipedia.org/wiki/Behavior-driven_development).
|
||||
|
||||
### General Usage
|
||||
|
||||
To run the functional tests, do
|
||||
|
||||
cd test/bdd
|
||||
behave
|
||||
pytest test/bdd
|
||||
|
||||
The tests can be configured with a set of environment variables (`behave -D key=val`):
|
||||
The BDD tests create databases for the tests. You can set name of the databases
|
||||
through configuration variables in your `pytest.ini`:
|
||||
|
||||
* `TEMPLATE_DB` - name of template database used as a skeleton for
|
||||
the test databases (db tests)
|
||||
* `TEST_DB` - name of test database (db tests)
|
||||
* `API_TEST_DB` - name of the database containing the API test data (api tests)
|
||||
* `API_TEST_FILE` - OSM file to be imported into the API test database (api tests)
|
||||
* `API_ENGINE` - webframe to use for running search queries, same values as
|
||||
`nominatim serve --engine` parameter
|
||||
* `DB_HOST` - (optional) hostname of database host
|
||||
* `DB_PORT` - (optional) port of database on host
|
||||
* `DB_USER` - (optional) username of database login
|
||||
* `DB_PASS` - (optional) password for database login
|
||||
* `REMOVE_TEMPLATE` - if true, the template and API database will not be reused
|
||||
during the next run. Reusing the base templates speeds
|
||||
up tests considerably but might lead to outdated errors
|
||||
for some changes in the database layout.
|
||||
* `KEEP_TEST_DB` - if true, the test database will not be dropped after a test
|
||||
is finished. Should only be used if one single scenario is
|
||||
run, otherwise the result is undefined.
|
||||
* `nominatim_test_db` defines the name of the temporary database created for
|
||||
a single test (default: `test_nominatim`)
|
||||
* `nominatim_api_test_db` defines the name of the database containing
|
||||
the API test data, see also below (default: `test_api_nominatim`)
|
||||
* `nominatim_template_db` defines the name of the template database used
|
||||
for creating the temporary test databases. It contains some static setup
|
||||
which usually doesn't change between imports of OSM data
|
||||
(default: `test_template_nominatim`)
|
||||
|
||||
To change other connection parameters for the PostgreSQL database, use
|
||||
the [libpq enivronment variables](https://www.postgresql.org/docs/current/libpq-envars.html).
|
||||
Never set a password through these variables. Use a
|
||||
[password file](https://www.postgresql.org/docs/current/libpq-pgpass.html) instead.
|
||||
|
||||
The API test database and the template database are only created once and then
|
||||
left untouched. This is usually what you want because it speeds up subsequent
|
||||
runs of BDD tests. If you do change code that has an influence on the content
|
||||
of these databases, you can run pytest with the `--nominatim-purge` parameter
|
||||
and the databases will be dropped and recreated from scratch.
|
||||
|
||||
When running the BDD tests with make (using `make tests` or `make bdd`), then
|
||||
the databases will always be purged.
|
||||
|
||||
The temporary test database is usually dropped directly after the test, so
|
||||
it does not take up unnecessary space. If you want to keep the database around,
|
||||
for example while debugging a specific BDD test, use the parameter
|
||||
`--nominatim-keep-db`.
|
||||
|
||||
Logging can be defined through command line parameters of behave itself. Check
|
||||
out `behave --help` for details. Also have a look at the 'work-in-progress'
|
||||
feature of behave which comes in handy when writing new tests.
|
||||
|
||||
### API Tests (`test/bdd/api`)
|
||||
|
||||
These tests are meant to test the different API endpoints and their parameters.
|
||||
They require to import several datasets into a test database. This is normally
|
||||
done automatically during setup of the test. The API test database is then
|
||||
kept around and reused in subsequent runs of behave. Use `behave -DREMOVE_TEMPLATE`
|
||||
kept around and reused in subsequent runs of behave. Use `--nominatim-purge`
|
||||
to force a reimport of the database.
|
||||
|
||||
The official test dataset is saved in the file `test/testdb/apidb-test-data.pbf`
|
||||
@@ -109,12 +109,12 @@ test the correctness of osm2pgsql. Each test will write some data into the `plac
|
||||
table (and optionally the `planet_osm_*` tables if required) and then run
|
||||
Nominatim's processing functions on that.
|
||||
|
||||
These tests need to create their own test databases. By default they will be
|
||||
called `test_template_nominatim` and `test_nominatim`. Names can be changed with
|
||||
the environment variables `TEMPLATE_DB` and `TEST_DB`. The user running the tests
|
||||
needs superuser rights for postgres.
|
||||
These tests use the template database and create temporary test databases for
|
||||
each test.
|
||||
|
||||
### Import Tests (`test/bdd/osm2pgsql`)
|
||||
|
||||
These tests check that data is imported correctly into the place table. They
|
||||
use the same template database as the DB Creation tests, so the same remarks apply.
|
||||
These tests check that data is imported correctly into the place table.
|
||||
|
||||
These tests also use the template database and create temporary test databases
|
||||
for each test.
|
||||
|
||||
@@ -187,7 +187,7 @@ module.MAIN_TAGS_POIS = function (group)
|
||||
passing_place = group,
|
||||
street_lamp = 'named',
|
||||
traffic_signals = 'named'},
|
||||
historic = {'always',
|
||||
historic = {'fallback',
|
||||
yes = group,
|
||||
no = group},
|
||||
information = {include_when_tag_present('tourism', 'information'),
|
||||
@@ -196,6 +196,7 @@ module.MAIN_TAGS_POIS = function (group)
|
||||
trail_blaze = 'never'},
|
||||
junction = {'fallback',
|
||||
no = group},
|
||||
landuse = {cemetery = 'always'},
|
||||
leisure = {'always',
|
||||
nature_reserve = 'fallback',
|
||||
swimming_pool = 'named',
|
||||
@@ -229,6 +230,7 @@ module.MAIN_TAGS_POIS = function (group)
|
||||
shop = {'always',
|
||||
no = group},
|
||||
tourism = {'always',
|
||||
attraction = 'fallback',
|
||||
no = group,
|
||||
yes = group,
|
||||
information = exclude_when_key_present('information')},
|
||||
@@ -330,7 +332,7 @@ module.NAME_TAGS.core = {main = {'name', 'name:*',
|
||||
}
|
||||
module.NAME_TAGS.address = {house = {'addr:housename'}}
|
||||
module.NAME_TAGS.poi = group_merge({main = {'brand'},
|
||||
extra = {'iata', 'icao'}},
|
||||
extra = {'iata', 'icao', 'faa'}},
|
||||
module.NAME_TAGS.core)
|
||||
|
||||
-- Address tagging
|
||||
|
||||
@@ -944,7 +944,7 @@ kp:
|
||||
# South Korea (대한민국)
|
||||
kr:
|
||||
partition: 49
|
||||
languages: ko, en
|
||||
languages: ko
|
||||
names: !include country-names/kr.yaml
|
||||
postcode:
|
||||
pattern: "ddddd"
|
||||
|
||||
@@ -192,6 +192,13 @@ NOMINATIM_REQUEST_TIMEOUT=60
|
||||
# to geocode" instead.
|
||||
NOMINATIM_SEARCH_WITHIN_COUNTRIES=False
|
||||
|
||||
# Specifies the order in which different name tags are used.
|
||||
# The values in this list determine the preferred order of name variants,
|
||||
# including language-specific names.
|
||||
# Comma-separated list, where :XX stands for language-specific tags
|
||||
# (e.g. name:en) and no :XX stands for general tags (e.g. name).
|
||||
NOMINATIM_OUTPUT_NAMES=name:XX,name,brand,official_name:XX,short_name:XX,official_name,short_name,ref
|
||||
|
||||
### Log settings
|
||||
#
|
||||
# The following options allow to enable logging of API requests.
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
Helper functions for localizing names of results.
|
||||
"""
|
||||
from typing import Mapping, List, Optional
|
||||
from .config import Configuration
|
||||
|
||||
import re
|
||||
|
||||
@@ -20,14 +21,18 @@ class Locales:
|
||||
"""
|
||||
|
||||
def __init__(self, langs: Optional[List[str]] = None):
|
||||
self.config = Configuration(None)
|
||||
self.languages = langs or []
|
||||
self.name_tags: List[str] = []
|
||||
|
||||
# Build the list of supported tags. It is currently hard-coded.
|
||||
self._add_lang_tags('name')
|
||||
self._add_tags('name', 'brand')
|
||||
self._add_lang_tags('official_name', 'short_name')
|
||||
self._add_tags('official_name', 'short_name', 'ref')
|
||||
parts = self.config.OUTPUT_NAMES.split(',')
|
||||
|
||||
for part in parts:
|
||||
part = part.strip()
|
||||
if part.endswith(":XX"):
|
||||
self._add_lang_tags(part[:-3])
|
||||
else:
|
||||
self._add_tags(part)
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return len(self.languages) > 0
|
||||
|
||||
@@ -342,7 +342,8 @@ HTML_HEADER: str = """<!DOCTYPE html>
|
||||
<title>Nominatim - Debug</title>
|
||||
<style>
|
||||
""" + \
|
||||
(HtmlFormatter(nobackground=True).get_style_defs('.highlight') if CODE_HIGHLIGHT else '') + \
|
||||
(HtmlFormatter(nobackground=True).get_style_defs('.highlight') # type: ignore[no-untyped-call]
|
||||
if CODE_HIGHLIGHT else '') + \
|
||||
"""
|
||||
h2 { font-size: x-large }
|
||||
|
||||
|
||||
52
src/nominatim_api/query_preprocessing/regex_replace.py
Normal file
52
src/nominatim_api/query_preprocessing/regex_replace.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# 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.
|
||||
"""
|
||||
This preprocessor replaces values in a given input based on pre-defined regex rules.
|
||||
|
||||
Arguments:
|
||||
pattern: Regex pattern to be applied on the input
|
||||
replace: The string that it is to be replaced with
|
||||
"""
|
||||
from typing import List
|
||||
import re
|
||||
|
||||
from .config import QueryConfig
|
||||
from .base import QueryProcessingFunc
|
||||
from ..search.query import Phrase
|
||||
|
||||
|
||||
class _GenericPreprocessing:
|
||||
"""Perform replacements to input phrases using custom regex patterns."""
|
||||
|
||||
def __init__(self, config: QueryConfig) -> None:
|
||||
"""Initialise the _GenericPreprocessing class with patterns from the ICU config file."""
|
||||
self.config = config
|
||||
|
||||
match_patterns = self.config.get('replacements', 'Key not found')
|
||||
self.compiled_patterns = [
|
||||
(re.compile(item['pattern']), item['replace']) for item in match_patterns
|
||||
]
|
||||
|
||||
def split_phrase(self, phrase: Phrase) -> Phrase:
|
||||
"""This function performs replacements on the given text using regex patterns."""
|
||||
for item in self.compiled_patterns:
|
||||
phrase.text = item[0].sub(item[1], phrase.text)
|
||||
|
||||
return phrase
|
||||
|
||||
def __call__(self, phrases: List[Phrase]) -> List[Phrase]:
|
||||
"""
|
||||
Return the final Phrase list.
|
||||
Returns an empty list if there is nothing left after split_phrase.
|
||||
"""
|
||||
result = [p for p in map(self.split_phrase, phrases) if p.text.strip()]
|
||||
return result
|
||||
|
||||
|
||||
def create(config: QueryConfig) -> QueryProcessingFunc:
|
||||
""" Create a function for generic preprocessing."""
|
||||
return _GenericPreprocessing(config)
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Conversion from token assignment to an abstract DB search.
|
||||
@@ -146,7 +146,7 @@ class SearchBuilder:
|
||||
if address:
|
||||
sdata.lookups = [dbf.FieldLookup('nameaddress_vector',
|
||||
[t.token for r in address
|
||||
for t in self.query.get_partials_list(r)],
|
||||
for t in self.query.iter_partials(r)],
|
||||
lookups.Restrict)]
|
||||
yield dbs.PostcodeSearch(penalty, sdata)
|
||||
|
||||
@@ -159,7 +159,7 @@ class SearchBuilder:
|
||||
expected_count = sum(t.count for t in hnrs)
|
||||
|
||||
partials = {t.token: t.addr_count for trange in address
|
||||
for t in self.query.get_partials_list(trange)}
|
||||
for t in self.query.iter_partials(trange)}
|
||||
|
||||
if not partials:
|
||||
# can happen when none of the partials is indexed
|
||||
@@ -203,9 +203,9 @@ class SearchBuilder:
|
||||
are and tries to find a lookup that optimizes index use.
|
||||
"""
|
||||
penalty = 0.0 # extra penalty
|
||||
name_partials = {t.token: t for t in self.query.get_partials_list(name)}
|
||||
name_partials = {t.token: t for t in self.query.iter_partials(name)}
|
||||
|
||||
addr_partials = [t for r in address for t in self.query.get_partials_list(r)]
|
||||
addr_partials = [t for r in address for t in self.query.iter_partials(r)]
|
||||
addr_tokens = list({t.token for t in addr_partials})
|
||||
|
||||
exp_count = min(t.count for t in name_partials.values()) / (3**(len(name_partials) - 1))
|
||||
@@ -220,7 +220,7 @@ class SearchBuilder:
|
||||
if name_fulls:
|
||||
fulls_count = sum(t.count for t in name_fulls)
|
||||
|
||||
if fulls_count < 50000 or addr_count < 50000:
|
||||
if fulls_count < 80000 or addr_count < 50000:
|
||||
yield penalty, fulls_count / (2**len(addr_tokens)), \
|
||||
self.get_full_name_ranking(name_fulls, addr_partials,
|
||||
fulls_count > 30000 / max(1, len(addr_tokens)))
|
||||
@@ -282,8 +282,7 @@ class SearchBuilder:
|
||||
ranks = [dbf.RankedTokens(t.penalty, [t.token]) for t in name_fulls]
|
||||
ranks.sort(key=lambda r: r.penalty)
|
||||
# Fallback, sum of penalty for partials
|
||||
name_partials = self.query.get_partials_list(trange)
|
||||
default = sum(t.penalty for t in name_partials) + 0.2
|
||||
default = sum(t.penalty for t in self.query.iter_partials(trange)) + 0.2
|
||||
return dbf.FieldRanking(db_field, default, ranks)
|
||||
|
||||
def get_addr_ranking(self, trange: qmod.TokenRange) -> dbf.FieldRanking:
|
||||
@@ -296,35 +295,35 @@ class SearchBuilder:
|
||||
|
||||
while todo:
|
||||
neglen, pos, rank = heapq.heappop(todo)
|
||||
# partial node
|
||||
partial = self.query.nodes[pos].partial
|
||||
if partial is not None:
|
||||
if pos + 1 < trange.end:
|
||||
penalty = rank.penalty + partial.penalty \
|
||||
+ PENALTY_WORDCHANGE[self.query.nodes[pos + 1].btype]
|
||||
heapq.heappush(todo, (neglen - 1, pos + 1,
|
||||
dbf.RankedTokens(penalty, rank.tokens)))
|
||||
else:
|
||||
ranks.append(dbf.RankedTokens(rank.penalty + partial.penalty,
|
||||
rank.tokens))
|
||||
# full words
|
||||
for tlist in self.query.nodes[pos].starting:
|
||||
if tlist.ttype in (qmod.TOKEN_PARTIAL, qmod.TOKEN_WORD):
|
||||
if tlist.ttype == qmod.TOKEN_WORD:
|
||||
if tlist.end < trange.end:
|
||||
chgpenalty = PENALTY_WORDCHANGE[self.query.nodes[tlist.end].btype]
|
||||
if tlist.ttype == qmod.TOKEN_PARTIAL:
|
||||
penalty = rank.penalty + chgpenalty \
|
||||
+ max(t.penalty for t in tlist.tokens)
|
||||
for t in tlist.tokens:
|
||||
heapq.heappush(todo, (neglen - 1, tlist.end,
|
||||
dbf.RankedTokens(penalty, rank.tokens)))
|
||||
else:
|
||||
for t in tlist.tokens:
|
||||
heapq.heappush(todo, (neglen - 1, tlist.end,
|
||||
rank.with_token(t, chgpenalty)))
|
||||
rank.with_token(t, chgpenalty)))
|
||||
elif tlist.end == trange.end:
|
||||
if tlist.ttype == qmod.TOKEN_PARTIAL:
|
||||
ranks.append(dbf.RankedTokens(rank.penalty
|
||||
+ max(t.penalty for t in tlist.tokens),
|
||||
rank.tokens))
|
||||
else:
|
||||
ranks.extend(rank.with_token(t, 0.0) for t in tlist.tokens)
|
||||
if len(ranks) >= 10:
|
||||
# Too many variants, bail out and only add
|
||||
# Worst-case Fallback: sum of penalty of partials
|
||||
name_partials = self.query.get_partials_list(trange)
|
||||
default = sum(t.penalty for t in name_partials) + 0.2
|
||||
ranks.append(dbf.RankedTokens(rank.penalty + default, []))
|
||||
# Bail out of outer loop
|
||||
todo.clear()
|
||||
break
|
||||
ranks.extend(rank.with_token(t, 0.0) for t in tlist.tokens)
|
||||
|
||||
if len(ranks) >= 10:
|
||||
# Too many variants, bail out and only add
|
||||
# Worst-case Fallback: sum of penalty of partials
|
||||
default = sum(t.penalty for t in self.query.iter_partials(trange)) + 0.2
|
||||
ranks.append(dbf.RankedTokens(rank.penalty + default, []))
|
||||
# Bail out of outer loop
|
||||
break
|
||||
|
||||
ranks.sort(key=lambda r: len(r.tokens))
|
||||
default = ranks[0].penalty + 0.3
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Public interface to the search code.
|
||||
@@ -50,6 +50,9 @@ class ForwardGeocoder:
|
||||
self.query_analyzer = await make_query_analyzer(self.conn)
|
||||
|
||||
query = await self.query_analyzer.analyze_query(phrases)
|
||||
query.compute_direction_penalty()
|
||||
log().var_dump('Query direction penalty',
|
||||
lambda: f"[{'LR' if query.dir_penalty < 0 else 'RL'}] {query.dir_penalty}")
|
||||
|
||||
searches: List[AbstractSearch] = []
|
||||
if query.num_token_slots() > 0:
|
||||
@@ -115,17 +118,20 @@ class ForwardGeocoder:
|
||||
""" Remove badly matching results, sort by ranking and
|
||||
limit to the configured number of results.
|
||||
"""
|
||||
if results:
|
||||
results.sort(key=lambda r: (r.ranking, 0 if r.bbox is None else -r.bbox.area))
|
||||
min_rank = results[0].rank_search
|
||||
min_ranking = results[0].ranking
|
||||
results = SearchResults(r for r in results
|
||||
if (r.ranking + 0.03 * (r.rank_search - min_rank)
|
||||
< min_ranking + 0.5))
|
||||
results.sort(key=lambda r: (r.ranking, 0 if r.bbox is None else -r.bbox.area))
|
||||
|
||||
results = SearchResults(results[:self.limit])
|
||||
final = SearchResults()
|
||||
min_rank = results[0].rank_search
|
||||
min_ranking = results[0].ranking
|
||||
|
||||
return results
|
||||
for r in results:
|
||||
if r.ranking + 0.03 * (r.rank_search - min_rank) < min_ranking + 0.5:
|
||||
final.append(r)
|
||||
min_rank = min(r.rank_search, min_rank)
|
||||
if len(final) == self.limit:
|
||||
break
|
||||
|
||||
return final
|
||||
|
||||
def rerank_by_query(self, query: QueryStruct, results: SearchResults) -> None:
|
||||
""" Adjust the accuracy of the localized result according to how well
|
||||
@@ -150,17 +156,16 @@ class ForwardGeocoder:
|
||||
if not words:
|
||||
continue
|
||||
for qword in qwords:
|
||||
wdist = max(difflib.SequenceMatcher(a=qword, b=w).quick_ratio() for w in words)
|
||||
if wdist < 0.5:
|
||||
distance += len(qword)
|
||||
else:
|
||||
distance += (1.0 - wdist) * len(qword)
|
||||
# only add distance penalty if there is no perfect match
|
||||
if qword not in words:
|
||||
wdist = max(difflib.SequenceMatcher(a=qword, b=w).quick_ratio() for w in words)
|
||||
distance += len(qword) if wdist < 0.4 else 1
|
||||
# Compensate for the fact that country names do not get a
|
||||
# match penalty yet by the tokenizer.
|
||||
# Temporary hack that needs to be removed!
|
||||
if result.rank_address == 4:
|
||||
distance *= 2
|
||||
result.accuracy += distance * 0.4 / sum(len(w) for w in qwords)
|
||||
result.accuracy += distance * 0.3 / sum(len(w) for w in qwords)
|
||||
|
||||
async def lookup_pois(self, categories: List[Tuple[str, str]],
|
||||
phrases: List[Phrase]) -> SearchResults:
|
||||
@@ -208,9 +213,10 @@ class ForwardGeocoder:
|
||||
results = self.pre_filter_results(results)
|
||||
await add_result_details(self.conn, results, self.params)
|
||||
log().result_dump('Preliminary Results', ((r.accuracy, r) for r in results))
|
||||
self.rerank_by_query(query, results)
|
||||
log().result_dump('Results after reranking', ((r.accuracy, r) for r in results))
|
||||
results = self.sort_and_cut_results(results)
|
||||
if len(results) > 1:
|
||||
self.rerank_by_query(query, results)
|
||||
log().result_dump('Results after reranking', ((r.accuracy, r) for r in results))
|
||||
results = self.sort_and_cut_results(results)
|
||||
log().result_dump('Final Results', ((r.accuracy, r) for r in results))
|
||||
|
||||
return results
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Implementation of query analysis for the ICU tokenizer.
|
||||
@@ -267,32 +267,47 @@ class ICUQueryAnalyzer(AbstractQueryAnalyzer):
|
||||
def rerank_tokens(self, query: qmod.QueryStruct) -> None:
|
||||
""" Add penalties to tokens that depend on presence of other token.
|
||||
"""
|
||||
for i, node, tlist in query.iter_token_lists():
|
||||
if tlist.ttype == qmod.TOKEN_POSTCODE:
|
||||
tlen = len(cast(ICUToken, tlist.tokens[0]).word_token)
|
||||
for repl in node.starting:
|
||||
if repl.end == tlist.end and repl.ttype != qmod.TOKEN_POSTCODE \
|
||||
and (repl.ttype != qmod.TOKEN_HOUSENUMBER or tlen > 4):
|
||||
repl.add_penalty(0.39)
|
||||
elif (tlist.ttype == qmod.TOKEN_HOUSENUMBER
|
||||
and len(tlist.tokens[0].lookup_word) <= 3):
|
||||
if any(c.isdigit() for c in tlist.tokens[0].lookup_word):
|
||||
for repl in node.starting:
|
||||
if repl.end == tlist.end and repl.ttype != qmod.TOKEN_HOUSENUMBER:
|
||||
repl.add_penalty(0.5 - tlist.tokens[0].penalty)
|
||||
elif tlist.ttype not in (qmod.TOKEN_COUNTRY, qmod.TOKEN_PARTIAL):
|
||||
norm = ' '.join(n.term_normalized for n in query.nodes[i + 1:tlist.end + 1]
|
||||
if n.btype != qmod.BREAK_TOKEN)
|
||||
if not norm:
|
||||
# Can happen when the token only covers a partial term
|
||||
norm = query.nodes[i + 1].term_normalized
|
||||
for token in tlist.tokens:
|
||||
cast(ICUToken, token).rematch(norm)
|
||||
for start, end, tlist in query.iter_tokens_by_edge():
|
||||
if len(tlist) > 1:
|
||||
# If it looks like a Postcode, give preference.
|
||||
if qmod.TOKEN_POSTCODE in tlist:
|
||||
for ttype, tokens in tlist.items():
|
||||
if ttype != qmod.TOKEN_POSTCODE and \
|
||||
(ttype != qmod.TOKEN_HOUSENUMBER or
|
||||
start + 1 > end or
|
||||
len(query.nodes[end].term_lookup) > 4):
|
||||
for token in tokens:
|
||||
token.penalty += 0.39
|
||||
|
||||
# If it looks like a simple housenumber, prefer that.
|
||||
if qmod.TOKEN_HOUSENUMBER in tlist:
|
||||
hnr_lookup = tlist[qmod.TOKEN_HOUSENUMBER][0].lookup_word
|
||||
if len(hnr_lookup) <= 3 and any(c.isdigit() for c in hnr_lookup):
|
||||
penalty = 0.5 - tlist[qmod.TOKEN_HOUSENUMBER][0].penalty
|
||||
for ttype, tokens in tlist.items():
|
||||
if ttype != qmod.TOKEN_HOUSENUMBER:
|
||||
for token in tokens:
|
||||
token.penalty += penalty
|
||||
|
||||
# rerank tokens against the normalized form
|
||||
norm = ' '.join(n.term_normalized for n in query.nodes[start + 1:end + 1]
|
||||
if n.btype != qmod.BREAK_TOKEN)
|
||||
if not norm:
|
||||
# Can happen when the token only covers a partial term
|
||||
norm = query.nodes[start + 1].term_normalized
|
||||
for ttype, tokens in tlist.items():
|
||||
if ttype != qmod.TOKEN_COUNTRY:
|
||||
for token in tokens:
|
||||
cast(ICUToken, token).rematch(norm)
|
||||
|
||||
|
||||
def _dump_word_tokens(query: qmod.QueryStruct) -> Iterator[List[Any]]:
|
||||
yield ['type', 'from', 'to', 'token', 'word_token', 'lookup_word', 'penalty', 'count', 'info']
|
||||
for i, node in enumerate(query.nodes):
|
||||
if node.partial is not None:
|
||||
t = cast(ICUToken, node.partial)
|
||||
yield [qmod.TOKEN_PARTIAL, str(i), str(i + 1), t.token,
|
||||
t.word_token, t.lookup_word, t.penalty, t.count, t.info]
|
||||
for tlist in node.starting:
|
||||
for token in tlist.tokens:
|
||||
t = cast(ICUToken, token)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Datastructures for a tokenized query.
|
||||
@@ -12,6 +12,17 @@ from abc import ABC, abstractmethod
|
||||
from collections import defaultdict
|
||||
import dataclasses
|
||||
|
||||
# Precomputed denominator for the computation of the linear regression slope
|
||||
# used to determine the query direction.
|
||||
# The x value for the regression computation will be the position of the
|
||||
# token in the query. Thus we know the x values will be [0, query length).
|
||||
# As the denominator only depends on the x values, we can pre-compute here
|
||||
# the denominatior to use for a given query length.
|
||||
# Note that query length of two or less is special cased and will not use
|
||||
# the values from this array. Thus it is not a problem that they are 0.
|
||||
LINFAC = [i * (sum(si * si for si in range(i)) - (i - 1) * i * (i - 1) / 4)
|
||||
for i in range(50)]
|
||||
|
||||
|
||||
BreakType = str
|
||||
""" Type of break between tokens.
|
||||
@@ -183,15 +194,32 @@ class QueryNode:
|
||||
""" Penalty for the break at this node.
|
||||
"""
|
||||
term_lookup: str
|
||||
""" Transliterated term following this node.
|
||||
""" Transliterated term ending at this node.
|
||||
"""
|
||||
term_normalized: str
|
||||
""" Normalised form of term following this node.
|
||||
""" Normalised form of term ending at this node.
|
||||
When the token resulted from a split during transliteration,
|
||||
then this string contains the complete source term.
|
||||
"""
|
||||
|
||||
starting: List[TokenList] = dataclasses.field(default_factory=list)
|
||||
""" List of all full tokens starting at this node.
|
||||
"""
|
||||
partial: Optional[Token] = None
|
||||
""" Base token going to the next node.
|
||||
May be None when the query has parts for which no words are known.
|
||||
Note that the query may still be parsable when there are other
|
||||
types of tokens spanning over the gap.
|
||||
"""
|
||||
|
||||
def name_address_ratio(self) -> float:
|
||||
""" Return the propability that the partial token belonging to
|
||||
this node forms part of a name (as opposed of part of the address).
|
||||
"""
|
||||
if self.partial is None:
|
||||
return 0.5
|
||||
|
||||
return self.partial.count / (self.partial.count + self.partial.addr_count)
|
||||
|
||||
def adjust_break(self, btype: BreakType, penalty: float) -> None:
|
||||
""" Change the break type and penalty for this node.
|
||||
@@ -234,12 +262,20 @@ class QueryStruct:
|
||||
need to be direct neighbours. Thus the query is represented as a
|
||||
directed acyclic graph.
|
||||
|
||||
A query also has a direction penalty 'dir_penalty'. This describes
|
||||
the likelyhood if the query should be read from left-to-right or
|
||||
vice versa. A negative 'dir_penalty' should be read as a penalty on
|
||||
right-to-left reading, while a positive value represents a penalty
|
||||
for left-to-right reading. The default value is 0, which is equivalent
|
||||
to having no information about the reading.
|
||||
|
||||
When created, a query contains a single node: the start of the
|
||||
query. Further nodes can be added by appending to 'nodes'.
|
||||
"""
|
||||
|
||||
def __init__(self, source: List[Phrase]) -> None:
|
||||
self.source = source
|
||||
self.dir_penalty = 0.0
|
||||
self.nodes: List[QueryNode] = \
|
||||
[QueryNode(BREAK_START, source[0].ptype if source else PHRASE_ANY,
|
||||
0.0, '', '')]
|
||||
@@ -269,37 +305,63 @@ class QueryStruct:
|
||||
be added to, then the token is silently dropped.
|
||||
"""
|
||||
snode = self.nodes[trange.start]
|
||||
full_phrase = snode.btype in (BREAK_START, BREAK_PHRASE)\
|
||||
and self.nodes[trange.end].btype in (BREAK_PHRASE, BREAK_END)
|
||||
if _phrase_compatible_with(snode.ptype, ttype, full_phrase):
|
||||
tlist = snode.get_tokens(trange.end, ttype)
|
||||
if tlist is None:
|
||||
snode.starting.append(TokenList(trange.end, ttype, [token]))
|
||||
else:
|
||||
tlist.append(token)
|
||||
if ttype == TOKEN_PARTIAL:
|
||||
assert snode.partial is None
|
||||
if _phrase_compatible_with(snode.ptype, TOKEN_PARTIAL, False):
|
||||
snode.partial = token
|
||||
else:
|
||||
full_phrase = snode.btype in (BREAK_START, BREAK_PHRASE)\
|
||||
and self.nodes[trange.end].btype in (BREAK_PHRASE, BREAK_END)
|
||||
if _phrase_compatible_with(snode.ptype, ttype, full_phrase):
|
||||
tlist = snode.get_tokens(trange.end, ttype)
|
||||
if tlist is None:
|
||||
snode.starting.append(TokenList(trange.end, ttype, [token]))
|
||||
else:
|
||||
tlist.append(token)
|
||||
|
||||
def compute_direction_penalty(self) -> None:
|
||||
""" Recompute the direction probability from the partial tokens
|
||||
of each node.
|
||||
"""
|
||||
n = len(self.nodes) - 1
|
||||
if n == 1 or n >= 50:
|
||||
self.dir_penalty = 0
|
||||
elif n == 2:
|
||||
self.dir_penalty = (self.nodes[1].name_address_ratio()
|
||||
- self.nodes[0].name_address_ratio()) / 3
|
||||
else:
|
||||
ratios = [n.name_address_ratio() for n in self.nodes[:-1]]
|
||||
self.dir_penalty = (n * sum(i * r for i, r in enumerate(ratios))
|
||||
- sum(ratios) * n * (n - 1) / 2) / LINFAC[n]
|
||||
|
||||
def get_tokens(self, trange: TokenRange, ttype: TokenType) -> List[Token]:
|
||||
""" Get the list of tokens of a given type, spanning the given
|
||||
nodes. The nodes must exist. If no tokens exist, an
|
||||
empty list is returned.
|
||||
|
||||
Cannot be used to get the partial token.
|
||||
"""
|
||||
assert ttype != TOKEN_PARTIAL
|
||||
return self.nodes[trange.start].get_tokens(trange.end, ttype) or []
|
||||
|
||||
def get_partials_list(self, trange: TokenRange) -> List[Token]:
|
||||
""" Create a list of partial tokens between the given nodes.
|
||||
The list is composed of the first token of type PARTIAL
|
||||
going to the subsequent node. Such PARTIAL tokens are
|
||||
assumed to exist.
|
||||
def iter_partials(self, trange: TokenRange) -> Iterator[Token]:
|
||||
""" Iterate over the partial tokens between the given nodes.
|
||||
Missing partials are ignored.
|
||||
"""
|
||||
return [next(iter(self.get_tokens(TokenRange(i, i+1), TOKEN_PARTIAL)))
|
||||
for i in range(trange.start, trange.end)]
|
||||
return (n.partial for n in self.nodes[trange.start:trange.end] if n.partial is not None)
|
||||
|
||||
def iter_token_lists(self) -> Iterator[Tuple[int, QueryNode, TokenList]]:
|
||||
""" Iterator over all token lists in the query.
|
||||
def iter_tokens_by_edge(self) -> Iterator[Tuple[int, int, Dict[TokenType, List[Token]]]]:
|
||||
""" Iterator over all tokens except partial ones grouped by edge.
|
||||
|
||||
Returns the start and end node indexes and a dictionary
|
||||
of list of tokens by token type.
|
||||
"""
|
||||
for i, node in enumerate(self.nodes):
|
||||
by_end: Dict[int, Dict[TokenType, List[Token]]] = defaultdict(dict)
|
||||
for tlist in node.starting:
|
||||
yield i, node, tlist
|
||||
by_end[tlist.end][tlist.ttype] = tlist.tokens
|
||||
for end, endlist in by_end.items():
|
||||
yield i, end, endlist
|
||||
|
||||
def find_lookup_word_by_id(self, token: int) -> str:
|
||||
""" Find the first token with the given token ID and return
|
||||
@@ -308,6 +370,8 @@ class QueryStruct:
|
||||
debugging.
|
||||
"""
|
||||
for node in self.nodes:
|
||||
if node.partial is not None and node.partial.token == token:
|
||||
return f"[P]{node.partial.lookup_word}"
|
||||
for tlist in node.starting:
|
||||
for t in tlist.tokens:
|
||||
if t.token == token:
|
||||
@@ -339,16 +403,18 @@ class QueryStruct:
|
||||
|
||||
words: Dict[str, List[TokenRange]] = defaultdict(list)
|
||||
|
||||
for first in range(start, endpos - 1):
|
||||
word = self.nodes[first + 1].term_lookup
|
||||
for first, first_node in enumerate(self.nodes[start + 1:endpos], start):
|
||||
word = first_node.term_lookup
|
||||
penalty = base_penalty
|
||||
words[word].append(TokenRange(first, first + 1, penalty=penalty))
|
||||
if self.nodes[first + 1].btype != BREAK_PHRASE:
|
||||
for last in range(first + 2, min(first + 20, endpos)):
|
||||
word = ' '.join((word, self.nodes[last].term_lookup))
|
||||
penalty += self.nodes[last - 1].penalty
|
||||
if first_node.btype != BREAK_PHRASE:
|
||||
penalty += first_node.penalty
|
||||
max_last = min(first + 20, endpos)
|
||||
for last, last_node in enumerate(self.nodes[first + 2:max_last], first + 2):
|
||||
word = ' '.join((word, last_node.term_lookup))
|
||||
words[word].append(TokenRange(first, last, penalty=penalty))
|
||||
if self.nodes[last].btype == BREAK_PHRASE:
|
||||
if last_node.btype == BREAK_PHRASE:
|
||||
break
|
||||
penalty += last_node.penalty
|
||||
|
||||
return words
|
||||
|
||||
@@ -286,8 +286,12 @@ class _TokenSequence:
|
||||
log().var_dump('skip forward', (base.postcode, first))
|
||||
return
|
||||
|
||||
penalty = self.penalty
|
||||
if not base.country and self.direction == 1 and query.dir_penalty > 0:
|
||||
penalty += query.dir_penalty
|
||||
|
||||
log().comment('first word = name')
|
||||
yield dataclasses.replace(base, penalty=self.penalty,
|
||||
yield dataclasses.replace(base, penalty=penalty,
|
||||
name=first, address=base.address[1:])
|
||||
|
||||
# To paraphrase:
|
||||
@@ -300,14 +304,15 @@ class _TokenSequence:
|
||||
or (query.nodes[first.start].ptype != qmod.PHRASE_ANY):
|
||||
return
|
||||
|
||||
penalty = self.penalty
|
||||
|
||||
# Penalty for:
|
||||
# * <name>, <street>, <housenumber> , ...
|
||||
# * queries that are comma-separated
|
||||
if (base.housenumber and base.housenumber > first) or len(query.source) > 1:
|
||||
penalty += 0.25
|
||||
|
||||
if self.direction == 0 and query.dir_penalty > 0:
|
||||
penalty += query.dir_penalty
|
||||
|
||||
for i in range(first.start + 1, first.end):
|
||||
name, addr = first.split(i)
|
||||
log().comment(f'split first word = name ({i - first.start})')
|
||||
@@ -326,9 +331,13 @@ class _TokenSequence:
|
||||
log().var_dump('skip backward', (base.postcode, last))
|
||||
return
|
||||
|
||||
penalty = self.penalty
|
||||
if not base.country and self.direction == -1 and query.dir_penalty < 0:
|
||||
penalty -= query.dir_penalty
|
||||
|
||||
if self.direction == -1 or len(base.address) > 1 or base.postcode:
|
||||
log().comment('last word = name')
|
||||
yield dataclasses.replace(base, penalty=self.penalty,
|
||||
yield dataclasses.replace(base, penalty=penalty,
|
||||
name=last, address=base.address[:-1])
|
||||
|
||||
# To paraphrase:
|
||||
@@ -341,12 +350,14 @@ class _TokenSequence:
|
||||
or (query.nodes[last.start].ptype != qmod.PHRASE_ANY):
|
||||
return
|
||||
|
||||
penalty = self.penalty
|
||||
if base.housenumber and base.housenumber < last:
|
||||
penalty += 0.4
|
||||
if len(query.source) > 1:
|
||||
penalty += 0.25
|
||||
|
||||
if self.direction == 0 and query.dir_penalty < 0:
|
||||
penalty -= query.dir_penalty
|
||||
|
||||
for i in range(last.start + 1, last.end):
|
||||
addr, name = last.split(i)
|
||||
log().comment(f'split last word = name ({i - last.start})')
|
||||
@@ -379,11 +390,11 @@ class _TokenSequence:
|
||||
if base.postcode and base.postcode.start == 0:
|
||||
self.penalty += 0.1
|
||||
|
||||
# Right-to-left reading of the address
|
||||
# Left-to-right reading of the address
|
||||
if self.direction != -1:
|
||||
yield from self._get_assignments_address_forward(base, query)
|
||||
|
||||
# Left-to-right reading of the address
|
||||
# Right-to-left reading of the address
|
||||
if self.direction != 1:
|
||||
yield from self._get_assignments_address_backward(base, query)
|
||||
|
||||
@@ -409,11 +420,22 @@ def yield_token_assignments(query: qmod.QueryStruct) -> Iterator[TokenAssignment
|
||||
node = query.nodes[state.end_pos]
|
||||
|
||||
for tlist in node.starting:
|
||||
newstate = state.advance(tlist.ttype, tlist.end, node.btype)
|
||||
if newstate is not None:
|
||||
if newstate.end_pos == query.num_token_slots():
|
||||
if newstate.recheck_sequence():
|
||||
log().var_dump('Assignment', newstate)
|
||||
yield from newstate.get_assignments(query)
|
||||
elif not newstate.is_final():
|
||||
todo.append(newstate)
|
||||
yield from _append_state_to_todo(
|
||||
query, todo,
|
||||
state.advance(tlist.ttype, tlist.end, node.btype))
|
||||
|
||||
if node.partial is not None:
|
||||
yield from _append_state_to_todo(
|
||||
query, todo,
|
||||
state.advance(qmod.TOKEN_PARTIAL, state.end_pos + 1, node.btype))
|
||||
|
||||
|
||||
def _append_state_to_todo(query: qmod.QueryStruct, todo: List[_TokenSequence],
|
||||
newstate: Optional[_TokenSequence]) -> Iterator[TokenAssignment]:
|
||||
if newstate is not None:
|
||||
if newstate.end_pos == query.num_token_slots():
|
||||
if newstate.recheck_sequence():
|
||||
log().var_dump('Assignment', newstate)
|
||||
yield from newstate.get_assignments(query)
|
||||
elif not newstate.is_final():
|
||||
todo.append(newstate)
|
||||
|
||||
@@ -143,7 +143,7 @@ def get_application(project_dir: Path,
|
||||
|
||||
log_file = config.LOG_FILE
|
||||
if log_file:
|
||||
middleware.append(Middleware(FileLoggingMiddleware, file_name=log_file))
|
||||
middleware.append(Middleware(FileLoggingMiddleware, file_name=log_file)) # type: ignore
|
||||
|
||||
exceptions: Dict[Any, Callable[[Request, Exception], Awaitable[Response]]] = {
|
||||
TimeoutError: timeout_error,
|
||||
|
||||
@@ -122,15 +122,18 @@ class IsAddressPoint(sa.sql.functions.GenericFunction[Any]):
|
||||
|
||||
def __init__(self, table: sa.Table) -> None:
|
||||
super().__init__(table.c.rank_address,
|
||||
table.c.housenumber, table.c.name)
|
||||
table.c.housenumber, table.c.name, table.c.address)
|
||||
|
||||
|
||||
@compiles(IsAddressPoint)
|
||||
def default_is_address_point(element: IsAddressPoint,
|
||||
compiler: 'sa.Compiled', **kw: Any) -> str:
|
||||
rank, hnr, name = list(element.clauses)
|
||||
return "(%s = 30 AND (%s IS NOT NULL OR %s ? 'addr:housename'))" % (
|
||||
rank, hnr, name, address = list(element.clauses)
|
||||
return "(%s = 30 AND (%s IS NULL OR NOT %s ? '_inherited')" \
|
||||
" AND (%s IS NOT NULL OR %s ? 'addr:housename'))" % (
|
||||
compiler.process(rank, **kw),
|
||||
compiler.process(address, **kw),
|
||||
compiler.process(address, **kw),
|
||||
compiler.process(hnr, **kw),
|
||||
compiler.process(name, **kw))
|
||||
|
||||
@@ -138,9 +141,11 @@ def default_is_address_point(element: IsAddressPoint,
|
||||
@compiles(IsAddressPoint, 'sqlite')
|
||||
def sqlite_is_address_point(element: IsAddressPoint,
|
||||
compiler: 'sa.Compiled', **kw: Any) -> str:
|
||||
rank, hnr, name = list(element.clauses)
|
||||
return "(%s = 30 AND coalesce(%s, json_extract(%s, '$.addr:housename')) IS NOT NULL)" % (
|
||||
rank, hnr, name, address = list(element.clauses)
|
||||
return "(%s = 30 AND json_extract(%s, '$._inherited') IS NULL" \
|
||||
" AND coalesce(%s, json_extract(%s, '$.addr:housename')) IS NOT NULL)" % (
|
||||
compiler.process(rank, **kw),
|
||||
compiler.process(address, **kw),
|
||||
compiler.process(hnr, **kw),
|
||||
compiler.process(name, **kw))
|
||||
|
||||
|
||||
@@ -84,8 +84,9 @@ def format_base_json(results: Union[ReverseResults, SearchResults],
|
||||
|
||||
_write_osm_id(out, result.osm_object)
|
||||
|
||||
out.keyval('lat', f"{result.centroid.lat}")\
|
||||
.keyval('lon', f"{result.centroid.lon}")\
|
||||
# lat and lon must be string values
|
||||
out.keyval('lat', f"{result.centroid.lat:0.7f}")\
|
||||
.keyval('lon', f"{result.centroid.lon:0.7f}")\
|
||||
.keyval(class_label, result.category[0])\
|
||||
.keyval('type', result.category[1])\
|
||||
.keyval('place_rank', result.rank_search)\
|
||||
@@ -112,6 +113,7 @@ def format_base_json(results: Union[ReverseResults, SearchResults],
|
||||
if options.get('namedetails', False):
|
||||
out.keyval('namedetails', result.names)
|
||||
|
||||
# must be string values
|
||||
bbox = cl.bbox_from_result(result)
|
||||
out.key('boundingbox').start_array()\
|
||||
.value(f"{bbox.minlat:0.7f}").next()\
|
||||
|
||||
@@ -90,7 +90,7 @@ def format_base_xml(results: Union[ReverseResults, SearchResults],
|
||||
result will be output, otherwise a list.
|
||||
"""
|
||||
root = ET.Element(xml_root_tag)
|
||||
root.set('timestamp', dt.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S +00:00'))
|
||||
root.set('timestamp', dt.datetime.now(dt.timezone.utc).strftime('%a, %d %b %Y %H:%M:%S +00:00'))
|
||||
root.set('attribution', cl.OSM_ATTRIBUTION)
|
||||
for k, v in xml_extra_info.items():
|
||||
root.set(k, v)
|
||||
|
||||
@@ -136,6 +136,7 @@ class NominatimArgs:
|
||||
import_from_wiki: bool
|
||||
import_from_csv: Optional[str]
|
||||
no_replace: bool
|
||||
min: int
|
||||
|
||||
# Arguments to all query functions
|
||||
format: str
|
||||
|
||||
@@ -58,6 +58,8 @@ class ImportSpecialPhrases:
|
||||
help='Import special phrases from a CSV file')
|
||||
group.add_argument('--no-replace', action='store_true',
|
||||
help='Keep the old phrases and only add the new ones')
|
||||
group.add_argument('--min', type=int, default=0,
|
||||
help='Restrict special phrases by minimum occurance')
|
||||
|
||||
def run(self, args: NominatimArgs) -> int:
|
||||
|
||||
@@ -82,7 +84,9 @@ class ImportSpecialPhrases:
|
||||
|
||||
tokenizer = tokenizer_factory.get_tokenizer_for_db(args.config)
|
||||
should_replace = not args.no_replace
|
||||
min = args.min
|
||||
|
||||
with connect(args.config.get_libpq_dsn()) as db_connection:
|
||||
SPImporter(
|
||||
args.config, db_connection, loader
|
||||
).import_phrases(tokenizer, should_replace)
|
||||
).import_phrases(tokenizer, should_replace, min)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Abstract class definitions for tokenizers. These base classes are here
|
||||
@@ -10,7 +10,6 @@ mainly for documentation purposes.
|
||||
"""
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Tuple, Dict, Any, Optional, Iterable
|
||||
from pathlib import Path
|
||||
|
||||
from ..typing import Protocol
|
||||
from ..config import Configuration
|
||||
@@ -38,7 +37,7 @@ class AbstractAnalyzer(ABC):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def get_word_token_info(self, words: List[str]) -> List[Tuple[str, str, int]]:
|
||||
def get_word_token_info(self, words: List[str]) -> List[Tuple[str, str, Optional[int]]]:
|
||||
""" Return token information for the given list of words.
|
||||
|
||||
The function is used for testing and debugging only
|
||||
@@ -232,6 +231,6 @@ class TokenizerModule(Protocol):
|
||||
own tokenizer.
|
||||
"""
|
||||
|
||||
def create(self, dsn: str, data_dir: Path) -> AbstractTokenizer:
|
||||
def create(self, dsn: str) -> AbstractTokenizer:
|
||||
""" Factory for new tokenizers.
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Functions for creating a tokenizer or initialising the right one for an
|
||||
@@ -52,19 +52,10 @@ def create_tokenizer(config: Configuration, init_db: bool = True,
|
||||
if module_name is None:
|
||||
module_name = config.TOKENIZER
|
||||
|
||||
# Create the directory for the tokenizer data
|
||||
assert config.project_dir is not None
|
||||
basedir = config.project_dir / 'tokenizer'
|
||||
if not basedir.exists():
|
||||
basedir.mkdir()
|
||||
elif not basedir.is_dir():
|
||||
LOG.fatal("Tokenizer directory '%s' cannot be created.", basedir)
|
||||
raise UsageError("Tokenizer setup failed.")
|
||||
|
||||
# Import and initialize the tokenizer.
|
||||
tokenizer_module = _import_tokenizer(module_name)
|
||||
|
||||
tokenizer = tokenizer_module.create(config.get_libpq_dsn(), basedir)
|
||||
tokenizer = tokenizer_module.create(config.get_libpq_dsn())
|
||||
tokenizer.init_new_db(config, init_db=init_db)
|
||||
|
||||
with connect(config.get_libpq_dsn()) as conn:
|
||||
@@ -79,12 +70,6 @@ def get_tokenizer_for_db(config: Configuration) -> AbstractTokenizer:
|
||||
The function looks up the appropriate tokenizer in the database
|
||||
and initialises it.
|
||||
"""
|
||||
assert config.project_dir is not None
|
||||
basedir = config.project_dir / 'tokenizer'
|
||||
if not basedir.is_dir():
|
||||
# Directory will be repopulated by tokenizer below.
|
||||
basedir.mkdir()
|
||||
|
||||
with connect(config.get_libpq_dsn()) as conn:
|
||||
name = properties.get_property(conn, 'tokenizer')
|
||||
|
||||
@@ -94,7 +79,7 @@ def get_tokenizer_for_db(config: Configuration) -> AbstractTokenizer:
|
||||
|
||||
tokenizer_module = _import_tokenizer(name)
|
||||
|
||||
tokenizer = tokenizer_module.create(config.get_libpq_dsn(), basedir)
|
||||
tokenizer = tokenizer_module.create(config.get_libpq_dsn())
|
||||
tokenizer.init_from_project(config)
|
||||
|
||||
return tokenizer
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tokenizer implementing normalisation as used before Nominatim 4 but using
|
||||
@@ -12,7 +12,6 @@ from typing import Optional, Sequence, List, Tuple, Mapping, Any, cast, \
|
||||
Dict, Set, Iterable
|
||||
import itertools
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from psycopg.types.json import Jsonb
|
||||
from psycopg import sql as pysql
|
||||
@@ -38,10 +37,10 @@ WORD_TYPES = (('country_names', 'C'),
|
||||
('housenumbers', 'H'))
|
||||
|
||||
|
||||
def create(dsn: str, data_dir: Path) -> 'ICUTokenizer':
|
||||
def create(dsn: str) -> 'ICUTokenizer':
|
||||
""" Create a new instance of the tokenizer provided by this module.
|
||||
"""
|
||||
return ICUTokenizer(dsn, data_dir)
|
||||
return ICUTokenizer(dsn)
|
||||
|
||||
|
||||
class ICUTokenizer(AbstractTokenizer):
|
||||
@@ -50,9 +49,8 @@ class ICUTokenizer(AbstractTokenizer):
|
||||
normalization routines in Nominatim 3.
|
||||
"""
|
||||
|
||||
def __init__(self, dsn: str, data_dir: Path) -> None:
|
||||
def __init__(self, dsn: str) -> None:
|
||||
self.dsn = dsn
|
||||
self.data_dir = data_dir
|
||||
self.loader: Optional[ICURuleLoader] = None
|
||||
|
||||
def init_new_db(self, config: Configuration, init_db: bool = True) -> None:
|
||||
@@ -340,7 +338,7 @@ class ICUNameAnalyzer(AbstractAnalyzer):
|
||||
"""
|
||||
return cast(str, self.token_analysis.normalizer.transliterate(name)).strip()
|
||||
|
||||
def get_word_token_info(self, words: Sequence[str]) -> List[Tuple[str, str, int]]:
|
||||
def get_word_token_info(self, words: Sequence[str]) -> List[Tuple[str, str, Optional[int]]]:
|
||||
""" Return token information for the given list of words.
|
||||
If a word starts with # it is assumed to be a full name
|
||||
otherwise is a partial name.
|
||||
@@ -364,11 +362,11 @@ class ICUNameAnalyzer(AbstractAnalyzer):
|
||||
cur.execute("""SELECT word_token, word_id
|
||||
FROM word WHERE word_token = ANY(%s) and type = 'W'
|
||||
""", (list(full_tokens.values()),))
|
||||
full_ids = {r[0]: r[1] for r in cur}
|
||||
full_ids = {r[0]: cast(int, r[1]) for r in cur}
|
||||
cur.execute("""SELECT word_token, word_id
|
||||
FROM word WHERE word_token = ANY(%s) and type = 'w'""",
|
||||
(list(partial_tokens.values()),))
|
||||
part_ids = {r[0]: r[1] for r in cur}
|
||||
part_ids = {r[0]: cast(int, r[1]) for r in cur}
|
||||
|
||||
return [(k, v, full_ids.get(v, None)) for k, v in full_tokens.items()] \
|
||||
+ [(k, v, part_ids.get(v, None)) for k, v in partial_tokens.items()]
|
||||
|
||||
@@ -127,7 +127,7 @@ def import_osm_data(osm_files: Union[Path, Sequence[Path]],
|
||||
fsize += os.stat(str(fname)).st_size
|
||||
else:
|
||||
fsize = os.stat(str(osm_files)).st_size
|
||||
options['osm2pgsql_cache'] = int(min((mem.available + mem.cached) * 0.75,
|
||||
options['osm2pgsql_cache'] = int(min((mem.available + getattr(mem, 'cached', 0)) * 0.75,
|
||||
fsize * 2) / 1024 / 1024) + 1
|
||||
|
||||
run_osm2pgsql(options)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Functions for importing, updating and otherwise maintaining the table
|
||||
@@ -64,11 +64,15 @@ class _PostcodeCollector:
|
||||
if normalized:
|
||||
self.collected[normalized] += (x, y)
|
||||
|
||||
def commit(self, conn: Connection, analyzer: AbstractAnalyzer, project_dir: Path) -> None:
|
||||
""" Update postcodes for the country from the postcodes selected so far
|
||||
as well as any externally supplied postcodes.
|
||||
def commit(self, conn: Connection, analyzer: AbstractAnalyzer,
|
||||
project_dir: Optional[Path]) -> None:
|
||||
""" Update postcodes for the country from the postcodes selected so far.
|
||||
|
||||
When 'project_dir' is set, then any postcode files found in this
|
||||
directory are taken into account as well.
|
||||
"""
|
||||
self._update_from_external(analyzer, project_dir)
|
||||
if project_dir is not None:
|
||||
self._update_from_external(analyzer, project_dir)
|
||||
to_add, to_delete, to_update = self._compute_changes(conn)
|
||||
|
||||
LOG.info("Processing country '%s' (%s added, %s deleted, %s updated).",
|
||||
@@ -170,7 +174,7 @@ class _PostcodeCollector:
|
||||
return None
|
||||
|
||||
|
||||
def update_postcodes(dsn: str, project_dir: Path, tokenizer: AbstractTokenizer) -> None:
|
||||
def update_postcodes(dsn: str, project_dir: Optional[Path], tokenizer: AbstractTokenizer) -> None:
|
||||
""" Update the table of artificial postcodes.
|
||||
|
||||
Computes artificial postcode centroids from the placex table,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
from typing import Iterable, Tuple, Mapping, Sequence, Optional, Set
|
||||
import logging
|
||||
import re
|
||||
|
||||
from psycopg.sql import Identifier, SQL
|
||||
|
||||
from ...typing import Protocol
|
||||
@@ -65,7 +64,32 @@ class SPImporter():
|
||||
# special phrases class/type on the wiki.
|
||||
self.table_phrases_to_delete: Set[str] = set()
|
||||
|
||||
def import_phrases(self, tokenizer: AbstractTokenizer, should_replace: bool) -> None:
|
||||
def get_classtype_pairs(self, min: int = 0) -> Set[Tuple[str, str]]:
|
||||
"""
|
||||
Returns list of allowed special phrases from the database,
|
||||
restricting to a list of combinations of classes and types
|
||||
which occur equal to or more than a specified amount of times.
|
||||
|
||||
Default value for this is 0, which allows everything in database.
|
||||
"""
|
||||
db_combinations = set()
|
||||
|
||||
query = f"""
|
||||
SELECT class AS CLS, type AS typ
|
||||
FROM placex
|
||||
GROUP BY class, type
|
||||
HAVING COUNT(*) >= {min}
|
||||
"""
|
||||
|
||||
with self.db_connection.cursor() as db_cursor:
|
||||
db_cursor.execute(SQL(query))
|
||||
for row in db_cursor:
|
||||
db_combinations.add((row[0], row[1]))
|
||||
|
||||
return db_combinations
|
||||
|
||||
def import_phrases(self, tokenizer: AbstractTokenizer, should_replace: bool,
|
||||
min: int = 0) -> None:
|
||||
"""
|
||||
Iterate through all SpecialPhrases extracted from the
|
||||
loader and import them into the database.
|
||||
@@ -85,9 +109,10 @@ class SPImporter():
|
||||
if result:
|
||||
class_type_pairs.add(result)
|
||||
|
||||
self._create_classtype_table_and_indexes(class_type_pairs)
|
||||
self._create_classtype_table_and_indexes(class_type_pairs, min)
|
||||
if should_replace:
|
||||
self._remove_non_existent_tables_from_db()
|
||||
|
||||
self.db_connection.commit()
|
||||
|
||||
with tokenizer.name_analyzer() as analyzer:
|
||||
@@ -163,7 +188,8 @@ class SPImporter():
|
||||
return (phrase.p_class, phrase.p_type)
|
||||
|
||||
def _create_classtype_table_and_indexes(self,
|
||||
class_type_pairs: Iterable[Tuple[str, str]]) -> None:
|
||||
class_type_pairs: Iterable[Tuple[str, str]],
|
||||
min: int = 0) -> None:
|
||||
"""
|
||||
Create table place_classtype for each given pair.
|
||||
Also create indexes on place_id and centroid.
|
||||
@@ -177,10 +203,19 @@ class SPImporter():
|
||||
with self.db_connection.cursor() as db_cursor:
|
||||
db_cursor.execute("CREATE INDEX idx_placex_classtype ON placex (class, type)")
|
||||
|
||||
if min:
|
||||
allowed_special_phrases = self.get_classtype_pairs(min)
|
||||
|
||||
for pair in class_type_pairs:
|
||||
phrase_class = pair[0]
|
||||
phrase_type = pair[1]
|
||||
|
||||
# Will only filter if min is not 0
|
||||
if min and (phrase_class, phrase_type) not in allowed_special_phrases:
|
||||
LOG.warning("Skipping phrase %s=%s: not in allowed special phrases",
|
||||
phrase_class, phrase_type)
|
||||
continue
|
||||
|
||||
table_name = _classtype_table(phrase_class, phrase_type)
|
||||
|
||||
if table_name in self.table_phrases_to_delete:
|
||||
|
||||
@@ -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,63 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Localization of search results
|
||||
|
||||
Scenario: default language
|
||||
When sending details query for R1155955
|
||||
Then results contain
|
||||
| ID | localname |
|
||||
| 0 | Liechtenstein |
|
||||
|
||||
Scenario: accept-language first
|
||||
When sending details query for R1155955
|
||||
| accept-language |
|
||||
| zh,de |
|
||||
Then results contain
|
||||
| ID | localname |
|
||||
| 0 | 列支敦士登 |
|
||||
|
||||
Scenario: accept-language missing
|
||||
When sending details query for R1155955
|
||||
| accept-language |
|
||||
| xx,fr,en,de |
|
||||
Then results contain
|
||||
| ID | localname |
|
||||
| 0 | Liechtenstein |
|
||||
|
||||
Scenario: http accept language header first
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending details query for R1155955
|
||||
Then results contain
|
||||
| ID | localname |
|
||||
| 0 | Liktinstein |
|
||||
|
||||
Scenario: http accept language header and accept-language
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending details query for R1155955
|
||||
| accept-language |
|
||||
| fo,en |
|
||||
Then results contain
|
||||
| ID | localname |
|
||||
| 0 | Liktinstein |
|
||||
|
||||
Scenario: http accept language header fallback
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-ca,en-ca;q=0.5 |
|
||||
When sending details query for R1155955
|
||||
Then results contain
|
||||
| ID | localname |
|
||||
| 0 | Liktinstein |
|
||||
|
||||
Scenario: http accept language header fallback (upper case)
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-FR;q=0.8,en-ca;q=0.5 |
|
||||
When sending details query for R1155955
|
||||
Then results contain
|
||||
| ID | localname |
|
||||
| 0 | Liktinstein |
|
||||
@@ -1,96 +0,0 @@
|
||||
@APIDB
|
||||
Feature: Object details
|
||||
Testing different parameter options for details API.
|
||||
|
||||
@SQLITE
|
||||
Scenario: JSON Details
|
||||
When sending json details query for W297699560
|
||||
Then the result is valid json
|
||||
And result has attributes geometry
|
||||
And result has not attributes keywords,address,linked_places,parentof
|
||||
And results contain in field geometry
|
||||
| type |
|
||||
| Point |
|
||||
|
||||
@SQLITE
|
||||
Scenario: JSON Details with pretty printing
|
||||
When sending json details query for W297699560
|
||||
| pretty |
|
||||
| 1 |
|
||||
Then the result is valid json
|
||||
And result has attributes geometry
|
||||
And result has not attributes keywords,address,linked_places,parentof
|
||||
|
||||
@SQLITE
|
||||
Scenario: JSON Details with addressdetails
|
||||
When sending json details query for W297699560
|
||||
| addressdetails |
|
||||
| 1 |
|
||||
Then the result is valid json
|
||||
And result has attributes address
|
||||
|
||||
@SQLITE
|
||||
Scenario: JSON Details with linkedplaces
|
||||
When sending json details query for R123924
|
||||
| linkedplaces |
|
||||
| 1 |
|
||||
Then the result is valid json
|
||||
And result has attributes linked_places
|
||||
|
||||
@SQLITE
|
||||
Scenario: JSON Details with hierarchy
|
||||
When sending json details query for W297699560
|
||||
| hierarchy |
|
||||
| 1 |
|
||||
Then the result is valid json
|
||||
And result has attributes hierarchy
|
||||
|
||||
@SQLITE
|
||||
Scenario: JSON Details with grouped hierarchy
|
||||
When sending json details query for W297699560
|
||||
| hierarchy | group_hierarchy |
|
||||
| 1 | 1 |
|
||||
Then the result is valid json
|
||||
And result has attributes hierarchy
|
||||
|
||||
Scenario Outline: JSON Details with keywords
|
||||
When sending json details query for <osmid>
|
||||
| keywords |
|
||||
| 1 |
|
||||
Then the result is valid json
|
||||
And result has attributes keywords
|
||||
|
||||
Examples:
|
||||
| osmid |
|
||||
| W297699560 |
|
||||
| W243055645 |
|
||||
| W243055716 |
|
||||
| W43327921 |
|
||||
|
||||
# ticket #1343
|
||||
Scenario: Details of a country with keywords
|
||||
When sending details query for R1155955
|
||||
| keywords |
|
||||
| 1 |
|
||||
Then the result is valid json
|
||||
And result has attributes keywords
|
||||
|
||||
@SQLITE
|
||||
Scenario Outline: JSON details with full geometry
|
||||
When sending json details query for <osmid>
|
||||
| polygon_geojson |
|
||||
| 1 |
|
||||
Then the result is valid json
|
||||
And result has attributes geometry
|
||||
And results contain in field geometry
|
||||
| type |
|
||||
| <geometry> |
|
||||
|
||||
Examples:
|
||||
| osmid | geometry |
|
||||
| W297699560 | LineString |
|
||||
| W243055645 | Polygon |
|
||||
| W243055716 | Polygon |
|
||||
| W43327921 | LineString |
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Object details
|
||||
Check details page for correctness
|
||||
|
||||
Scenario Outline: Details via OSM id
|
||||
When sending details query for <type><id>
|
||||
Then the result is valid json
|
||||
And results contain
|
||||
| osm_type | osm_id |
|
||||
| <type> | <id> |
|
||||
|
||||
Examples:
|
||||
| type | id |
|
||||
| N | 5484325405 |
|
||||
| W | 43327921 |
|
||||
| R | 123924 |
|
||||
|
||||
|
||||
Scenario Outline: Details for different class types for the same OSM id
|
||||
When sending details query for N300209696:<class>
|
||||
Then the result is valid json
|
||||
And results contain
|
||||
| osm_type | osm_id | category |
|
||||
| N | 300209696 | <class> |
|
||||
|
||||
Examples:
|
||||
| class |
|
||||
| tourism |
|
||||
| mountain_pass |
|
||||
|
||||
|
||||
Scenario Outline: Details via unknown OSM id
|
||||
When sending details query for <object>
|
||||
Then a HTTP 404 is returned
|
||||
|
||||
Examples:
|
||||
| object |
|
||||
| 1 |
|
||||
| R1 |
|
||||
| N300209696:highway |
|
||||
|
||||
|
||||
Scenario: Details for interpolation way return the interpolation
|
||||
When sending details query for W1
|
||||
Then the result is valid json
|
||||
And results contain
|
||||
| category | type | osm_type | osm_id | admin_level |
|
||||
| place | houses | W | 1 | 15 |
|
||||
|
||||
|
||||
@Fail
|
||||
Scenario: Details for interpolation way return the interpolation
|
||||
When sending details query for 112871
|
||||
Then the result is valid json
|
||||
And results contain
|
||||
| category | type | admin_level |
|
||||
| place | houses | 15 |
|
||||
And result has not attributes osm_type,osm_id
|
||||
|
||||
|
||||
@Fail
|
||||
Scenario: Details for interpolation way return the interpolation
|
||||
When sending details query for 112820
|
||||
Then the result is valid json
|
||||
And results contain
|
||||
| category | type | admin_level |
|
||||
| place | postcode | 15 |
|
||||
And result has not attributes osm_type,osm_id
|
||||
|
||||
|
||||
Scenario Outline: Details debug output returns no errors
|
||||
When sending debug details query for <feature>
|
||||
Then the result is valid html
|
||||
|
||||
Examples:
|
||||
| feature |
|
||||
| N5484325405 |
|
||||
| W1 |
|
||||
| 112820 |
|
||||
| 112871 |
|
||||
@@ -1,14 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Places by osm_type and osm_id Tests
|
||||
Simple tests for errors in various response formats.
|
||||
|
||||
Scenario Outline: Force error by providing too many ids
|
||||
When sending <format> lookup query for N1,N2,N3,N4,N5,N6,N7,N8,N9,N10,N11,N12,N13,N14,N15,N16,N17,N18,N19,N20,N21,N22,N23,N24,N25,N26,N27,N28,N29,N30,N31,N32,N33,N34,N35,N36,N37,N38,N39,N40,N41,N42,N43,N44,N45,N46,N47,N48,N49,N50,N51
|
||||
Then a <format> user error is returned
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| xml |
|
||||
| json |
|
||||
| geojson |
|
||||
@@ -1,42 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Places by osm_type and osm_id Tests
|
||||
Simple tests for response format.
|
||||
|
||||
Scenario Outline: address lookup for existing node, way, relation
|
||||
When sending <format> lookup query for N5484325405,W43327921,,R123924,X99,N0
|
||||
Then the result is valid <outformat>
|
||||
And exactly 3 results are returned
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| xml | xml |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
| geocodejson | geocodejson |
|
||||
|
||||
Scenario: address lookup for non-existing or invalid node, way, relation
|
||||
When sending xml lookup query for X99,,N0,nN158845944,ABC,,W9
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario Outline: Boundingbox is returned
|
||||
When sending <format> lookup query for N5484325405,W43327921
|
||||
Then exactly 2 results are returned
|
||||
And result 0 has bounding box in 47.135,47.14,9.52,9.525
|
||||
And result 1 has bounding box in 47.07,47.08,9.50,9.52
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| geojson |
|
||||
| xml |
|
||||
|
||||
|
||||
Scenario: Lookup of a linked place
|
||||
When sending geocodejson lookup query for N1932181216
|
||||
Then exactly 1 result is returned
|
||||
And results contain
|
||||
| name |
|
||||
| Vaduz |
|
||||
@@ -1,45 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Geometries for reverse geocoding
|
||||
Tests for returning geometries with reverse
|
||||
|
||||
|
||||
Scenario: Polygons are returned fully by default
|
||||
When sending v1/reverse at 47.13803,9.52264
|
||||
| polygon_text |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| geotext |
|
||||
| ^POLYGON\(\(9.5225302 47.138066, ?9.5225348 47.1379282, ?9.5226142 47.1379294, ?9.5226143 47.1379257, ?9.522615 47.137917, ?9.5226225 47.1379098, ?9.5226334 47.1379052, ?9.5226461 47.1379037, ?9.5226588 47.1379056, ?9.5226693 47.1379107, ?9.5226762 47.1379181, ?9.5226762 47.1379268, ?9.5226761 47.1379308, ?9.5227366 47.1379317, ?9.5227352 47.1379753, ?9.5227608 47.1379757, ?9.5227595 47.1380148, ?9.5227355 47.1380145, ?9.5227337 47.1380692, ?9.5225302 47.138066\)\) |
|
||||
|
||||
|
||||
Scenario: Polygons can be slightly simplified
|
||||
When sending v1/reverse at 47.13803,9.52264
|
||||
| polygon_text | polygon_threshold |
|
||||
| 1 | 0.00001 |
|
||||
Then results contain
|
||||
| geotext |
|
||||
| ^POLYGON\(\(9.5225302 47.138066, ?9.5225348 47.1379282, ?9.5226142 47.1379294, ?9.5226225 47.1379098, ?9.5226588 47.1379056, ?9.5226761 47.1379308, ?9.5227366 47.1379317, ?9.5227352 47.1379753, ?9.5227608 47.1379757, ?9.5227595 47.1380148, ?9.5227355 47.1380145, ?9.5227337 47.1380692, ?9.5225302 47.138066\)\) |
|
||||
|
||||
|
||||
Scenario: Polygons can be much simplified
|
||||
When sending v1/reverse at 47.13803,9.52264
|
||||
| polygon_text | polygon_threshold |
|
||||
| 1 | 0.9 |
|
||||
Then results contain
|
||||
| geotext |
|
||||
| ^POLYGON\(\([0-9. ]+, ?[0-9. ]+, ?[0-9. ]+, ?[0-9. ]+(, ?[0-9. ]+)?\)\) |
|
||||
|
||||
|
||||
Scenario: For polygons return the centroid as center point
|
||||
When sending v1/reverse at 47.13836,9.52304
|
||||
Then results contain
|
||||
| centroid |
|
||||
| 9.52271080 47.13818045 |
|
||||
|
||||
|
||||
Scenario: For streets return the closest point as center point
|
||||
When sending v1/reverse at 47.13368,9.52942
|
||||
Then results contain
|
||||
| centroid |
|
||||
| 9.529431527 47.13368172 |
|
||||
@@ -1,37 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Localization of reverse search results
|
||||
|
||||
Scenario: default language
|
||||
When sending v1/reverse at 47.14,9.55
|
||||
Then result addresses contain
|
||||
| ID | country |
|
||||
| 0 | Liechtenstein |
|
||||
|
||||
Scenario: accept-language parameter
|
||||
When sending v1/reverse at 47.14,9.55
|
||||
| accept-language |
|
||||
| ja,en |
|
||||
Then result addresses contain
|
||||
| ID | country |
|
||||
| 0 | リヒテンシュタイン |
|
||||
|
||||
Scenario: HTTP accept language header
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-ca,fo;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending v1/reverse at 47.14,9.55
|
||||
Then result addresses contain
|
||||
| ID | country |
|
||||
| 0 | Liktinstein |
|
||||
|
||||
Scenario: accept-language parameter and HTTP header
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-ca,fo;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending v1/reverse at 47.14,9.55
|
||||
| accept-language |
|
||||
| en |
|
||||
Then result addresses contain
|
||||
| ID | country |
|
||||
| 0 | Liechtenstein |
|
||||
@@ -1,117 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Reverse geocoding
|
||||
Testing the reverse function
|
||||
|
||||
Scenario Outline: Simple reverse-geocoding with no results
|
||||
When sending v1/reverse at <lat>,<lon>
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 0.0 | 0.0 |
|
||||
| 91.3 | 0.4 |
|
||||
| -700 | 0.4 |
|
||||
| 0.2 | 324.44 |
|
||||
| 0.2 | -180.4 |
|
||||
|
||||
|
||||
Scenario: Unknown countries fall back to default country grid
|
||||
When sending v1/reverse at 45.174,-103.072
|
||||
Then results contain
|
||||
| category | type | display_name |
|
||||
| place | country | United States |
|
||||
|
||||
|
||||
@Tiger
|
||||
Scenario: TIGER house number
|
||||
When sending v1/reverse at 32.4752389363,-86.4810198619
|
||||
Then results contain
|
||||
| category | type |
|
||||
| place | house |
|
||||
And result addresses contain
|
||||
| house_number | road | postcode | country_code |
|
||||
| 707 | Upper Kingston Road | 36067 | us |
|
||||
|
||||
@Tiger
|
||||
Scenario: No TIGER house number for zoom < 18
|
||||
When sending v1/reverse at 32.4752389363,-86.4810198619
|
||||
| zoom |
|
||||
| 17 |
|
||||
Then results contain
|
||||
| osm_type | category |
|
||||
| way | highway |
|
||||
And result addresses contain
|
||||
| road | postcode | country_code |
|
||||
| Upper Kingston Road | 36067 | us |
|
||||
|
||||
Scenario: Interpolated house number
|
||||
When sending v1/reverse at 47.118533,9.57056562
|
||||
Then results contain
|
||||
| osm_type | category | type |
|
||||
| way | place | house |
|
||||
And result addresses contain
|
||||
| house_number | road |
|
||||
| 1019 | Grosssteg |
|
||||
|
||||
Scenario: Address with non-numerical house number
|
||||
When sending v1/reverse at 47.107465,9.52838521614
|
||||
Then result addresses contain
|
||||
| house_number | road |
|
||||
| 39A/B | Dorfstrasse |
|
||||
|
||||
|
||||
Scenario: Address with numerical house number
|
||||
When sending v1/reverse at 47.168440329479594,9.511551699184338
|
||||
Then result addresses contain
|
||||
| house_number | road |
|
||||
| 6 | Schmedgässle |
|
||||
|
||||
Scenario Outline: Zoom levels below 5 result in country
|
||||
When sending v1/reverse at 47.16,9.51
|
||||
| zoom |
|
||||
| <zoom> |
|
||||
Then results contain
|
||||
| display_name |
|
||||
| Liechtenstein |
|
||||
|
||||
Examples:
|
||||
| zoom |
|
||||
| 0 |
|
||||
| 1 |
|
||||
| 2 |
|
||||
| 3 |
|
||||
| 4 |
|
||||
|
||||
Scenario: When on a street, the closest interpolation is shown
|
||||
When sending v1/reverse at 47.118457166193245,9.570678289621355
|
||||
| zoom |
|
||||
| 18 |
|
||||
Then results contain
|
||||
| display_name |
|
||||
| 1021, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
# github 2214
|
||||
Scenario: Interpolations do not override house numbers when they are closer
|
||||
When sending v1/reverse at 47.11778,9.57255
|
||||
| zoom |
|
||||
| 18 |
|
||||
Then results contain
|
||||
| display_name |
|
||||
| 5, Grosssteg, Steg, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Scenario: Interpolations do not override house numbers when they are closer (2)
|
||||
When sending v1/reverse at 47.11834,9.57167
|
||||
| zoom |
|
||||
| 18 |
|
||||
Then results contain
|
||||
| display_name |
|
||||
| 3, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Scenario: When on a street with zoom 18, the closest housenumber is returned
|
||||
When sending v1/reverse at 47.11755503977281,9.572722250405036
|
||||
| zoom |
|
||||
| 18 |
|
||||
Then result addresses contain
|
||||
| house_number |
|
||||
| 7 |
|
||||
@@ -1,107 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Geocodejson for Reverse API
|
||||
Testing correctness of geocodejson output (API version v1).
|
||||
|
||||
Scenario Outline: Simple OSM result
|
||||
When sending v1/reverse at 47.066,9.504 with format geocodejson
|
||||
| addressdetails |
|
||||
| <has_address> |
|
||||
Then result has attributes place_id, accuracy
|
||||
And result has <attributes> country,postcode,county,city,district,street,housenumber, admin
|
||||
Then results contain
|
||||
| osm_type | osm_id | osm_key | osm_value | type |
|
||||
| node | 6522627624 | shop | bakery | house |
|
||||
And results contain
|
||||
| name | label |
|
||||
| Dorfbäckerei Herrmann | Dorfbäckerei Herrmann, 29, Gnetsch, Mäls, Balzers, Oberland, 9496, Liechtenstein |
|
||||
And results contain in field geojson
|
||||
| type | coordinates |
|
||||
| Point | [9.5036065, 47.0660892] |
|
||||
And results contain in field __geocoding
|
||||
| version | licence | attribution |
|
||||
| 0.1.0 | ODbL | ^Data © OpenStreetMap contributors, ODbL 1.0. https?://osm.org/copyright$ |
|
||||
|
||||
Examples:
|
||||
| has_address | attributes |
|
||||
| 1 | attributes |
|
||||
| 0 | not attributes |
|
||||
|
||||
|
||||
Scenario: City housenumber-level address with street
|
||||
When sending v1/reverse at 47.1068011,9.52810091 with format geocodejson
|
||||
Then results contain
|
||||
| housenumber | street | postcode | city | country |
|
||||
| 8 | Im Winkel | 9495 | Triesen | Liechtenstein |
|
||||
And results contain in field admin
|
||||
| level6 | level8 |
|
||||
| Oberland | Triesen |
|
||||
|
||||
|
||||
Scenario: Town street-level address with street
|
||||
When sending v1/reverse at 47.066,9.504 with format geocodejson
|
||||
| zoom |
|
||||
| 16 |
|
||||
Then results contain
|
||||
| name | city | postcode | country |
|
||||
| Gnetsch | Balzers | 9496 | Liechtenstein |
|
||||
|
||||
|
||||
Scenario: Poi street-level address with footway
|
||||
When sending v1/reverse at 47.06515,9.50083 with format geocodejson
|
||||
Then results contain
|
||||
| street | city | postcode | country |
|
||||
| Burgweg | Balzers | 9496 | Liechtenstein |
|
||||
|
||||
|
||||
Scenario: City address with suburb
|
||||
When sending v1/reverse at 47.146861,9.511771 with format geocodejson
|
||||
Then results contain
|
||||
| housenumber | street | district | city | postcode | country |
|
||||
| 5 | Lochgass | Ebenholz | Vaduz | 9490 | Liechtenstein |
|
||||
|
||||
|
||||
@Tiger
|
||||
Scenario: Tiger address
|
||||
When sending v1/reverse at 32.4752389363,-86.4810198619 with format geocodejson
|
||||
Then results contain
|
||||
| osm_type | osm_id | osm_key | osm_value | type |
|
||||
| way | 396009653 | place | house | house |
|
||||
And results contain
|
||||
| housenumber | street | city | county | postcode | country |
|
||||
| 707 | Upper Kingston Road | Prattville | Autauga County | 36067 | United States |
|
||||
|
||||
|
||||
Scenario: Interpolation address
|
||||
When sending v1/reverse at 47.118533,9.57056562 with format geocodejson
|
||||
Then results contain
|
||||
| osm_type | osm_id | osm_key | osm_value | type |
|
||||
| way | 1 | place | house | house |
|
||||
And results contain
|
||||
| label |
|
||||
| 1019, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
And result has not attributes name
|
||||
|
||||
|
||||
Scenario: Line geometry output is supported
|
||||
When sending v1/reverse at 47.06597,9.50467 with format geocodejson
|
||||
| param | value |
|
||||
| polygon_geojson | 1 |
|
||||
Then results contain in field geojson
|
||||
| type |
|
||||
| LineString |
|
||||
|
||||
|
||||
Scenario Outline: Only geojson polygons are supported
|
||||
When sending v1/reverse at 47.06597,9.50467 with format geocodejson
|
||||
| param | value |
|
||||
| <param> | 1 |
|
||||
Then results contain in field geojson
|
||||
| type |
|
||||
| Point |
|
||||
|
||||
Examples:
|
||||
| param |
|
||||
| polygon_text |
|
||||
| polygon_svg |
|
||||
| polygon_kml |
|
||||
@@ -1,73 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Geojson for Reverse API
|
||||
Testing correctness of geojson output (API version v1).
|
||||
|
||||
Scenario Outline: Simple OSM result
|
||||
When sending v1/reverse at 47.066,9.504 with format geojson
|
||||
| addressdetails |
|
||||
| <has_address> |
|
||||
Then result has attributes place_id, importance, __licence
|
||||
And result has <attributes> address
|
||||
And results contain
|
||||
| osm_type | osm_id | place_rank | category | type | addresstype |
|
||||
| node | 6522627624 | 30 | shop | bakery | shop |
|
||||
And results contain
|
||||
| name | display_name |
|
||||
| Dorfbäckerei Herrmann | Dorfbäckerei Herrmann, 29, Gnetsch, Mäls, Balzers, Oberland, 9496, Liechtenstein |
|
||||
And results contain
|
||||
| boundingbox |
|
||||
| [47.0660392, 47.0661392, 9.5035565, 9.5036565] |
|
||||
And results contain in field geojson
|
||||
| type | coordinates |
|
||||
| Point | [9.5036065, 47.0660892] |
|
||||
|
||||
Examples:
|
||||
| has_address | attributes |
|
||||
| 1 | attributes |
|
||||
| 0 | not attributes |
|
||||
|
||||
|
||||
@Tiger
|
||||
Scenario: Tiger address
|
||||
When sending v1/reverse at 32.4752389363,-86.4810198619 with format geojson
|
||||
Then results contain
|
||||
| osm_type | osm_id | category | type | addresstype | place_rank |
|
||||
| way | 396009653 | place | house | place | 30 |
|
||||
|
||||
|
||||
Scenario: Interpolation address
|
||||
When sending v1/reverse at 47.118533,9.57056562 with format geojson
|
||||
Then results contain
|
||||
| osm_type | osm_id | place_rank | category | type | addresstype |
|
||||
| way | 1 | 30 | place | house | place |
|
||||
And results contain
|
||||
| boundingbox |
|
||||
| ^\[47.118495\d*, 47.118595\d*, 9.570496\d*, 9.570596\d*\] |
|
||||
And results contain
|
||||
| display_name |
|
||||
| 1019, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
|
||||
Scenario: Line geometry output is supported
|
||||
When sending v1/reverse at 47.06597,9.50467 with format geojson
|
||||
| param | value |
|
||||
| polygon_geojson | 1 |
|
||||
Then results contain in field geojson
|
||||
| type |
|
||||
| LineString |
|
||||
|
||||
|
||||
Scenario Outline: Only geojson polygons are supported
|
||||
When sending v1/reverse at 47.06597,9.50467 with format geojson
|
||||
| param | value |
|
||||
| <param> | 1 |
|
||||
Then results contain in field geojson
|
||||
| type |
|
||||
| Point |
|
||||
|
||||
Examples:
|
||||
| param |
|
||||
| polygon_text |
|
||||
| polygon_svg |
|
||||
| polygon_kml |
|
||||
@@ -1,130 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Json output for Reverse API
|
||||
Testing correctness of json and jsonv2 output (API version v1).
|
||||
|
||||
Scenario Outline: OSM result with and without addresses
|
||||
When sending v1/reverse at 47.066,9.504 with format json
|
||||
| addressdetails |
|
||||
| <has_address> |
|
||||
Then result has <attributes> address
|
||||
When sending v1/reverse at 47.066,9.504 with format jsonv2
|
||||
| addressdetails |
|
||||
| <has_address> |
|
||||
Then result has <attributes> address
|
||||
|
||||
Examples:
|
||||
| has_address | attributes |
|
||||
| 1 | attributes |
|
||||
| 0 | not attributes |
|
||||
|
||||
Scenario Outline: Simple OSM result
|
||||
When sending v1/reverse at 47.066,9.504 with format <format>
|
||||
Then result has attributes place_id
|
||||
And results contain
|
||||
| licence |
|
||||
| ^Data © OpenStreetMap contributors, ODbL 1.0. https?://osm.org/copyright$ |
|
||||
And results contain
|
||||
| osm_type | osm_id |
|
||||
| node | 6522627624 |
|
||||
And results contain
|
||||
| centroid | boundingbox |
|
||||
| 9.5036065 47.0660892 | ['47.0660392', '47.0661392', '9.5035565', '9.5036565'] |
|
||||
And results contain
|
||||
| display_name |
|
||||
| Dorfbäckerei Herrmann, 29, Gnetsch, Mäls, Balzers, Oberland, 9496, Liechtenstein |
|
||||
And result has not attributes namedetails,extratags
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
Scenario: Extra attributes of jsonv2 result
|
||||
When sending v1/reverse at 47.066,9.504 with format jsonv2
|
||||
Then result has attributes importance
|
||||
Then results contain
|
||||
| category | type | name | place_rank | addresstype |
|
||||
| shop | bakery | Dorfbäckerei Herrmann | 30 | shop |
|
||||
|
||||
|
||||
@Tiger
|
||||
Scenario: Tiger address
|
||||
When sending v1/reverse at 32.4752389363,-86.4810198619 with format jsonv2
|
||||
Then results contain
|
||||
| osm_type | osm_id | category | type | addresstype |
|
||||
| way | 396009653 | place | house | place |
|
||||
|
||||
|
||||
Scenario Outline: Interpolation address
|
||||
When sending v1/reverse at 47.118533,9.57056562 with format <format>
|
||||
Then results contain
|
||||
| osm_type | osm_id |
|
||||
| way | 1 |
|
||||
And results contain
|
||||
| centroid | boundingbox |
|
||||
| 9.57054676 47.118545392 | ^\['47.118495\d*', '47.118595\d*', '9.570496\d*', '9.570596\d*'\] |
|
||||
And results contain
|
||||
| display_name |
|
||||
| 1019, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
|
||||
Scenario Outline: Output of geojson
|
||||
When sending v1/reverse at 47.06597,9.50467 with format <format>
|
||||
| param | value |
|
||||
| polygon_geojson | 1 |
|
||||
Then results contain in field geojson
|
||||
| type | coordinates |
|
||||
| LineString | [[9.5039353, 47.0657546], [9.5040437, 47.0657781], [9.5040808, 47.065787], [9.5054298, 47.0661407]] |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
|
||||
Scenario Outline: Output of WKT
|
||||
When sending v1/reverse at 47.06597,9.50467 with format <format>
|
||||
| param | value |
|
||||
| polygon_text | 1 |
|
||||
Then results contain
|
||||
| geotext |
|
||||
| ^LINESTRING\(9.5039353 47.0657546, ?9.5040437 47.0657781, ?9.5040808 47.065787, ?9.5054298 47.0661407\) |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
|
||||
Scenario Outline: Output of SVG
|
||||
When sending v1/reverse at 47.06597,9.50467 with format <format>
|
||||
| param | value |
|
||||
| polygon_svg | 1 |
|
||||
Then results contain
|
||||
| svg |
|
||||
| M 9.5039353 -47.0657546 L 9.5040437 -47.0657781 9.5040808 -47.065787 9.5054298 -47.0661407 |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
|
||||
Scenario Outline: Output of KML
|
||||
When sending v1/reverse at 47.06597,9.50467 with format <format>
|
||||
| param | value |
|
||||
| polygon_kml | 1 |
|
||||
Then results contain
|
||||
| geokml |
|
||||
| ^<LineString><coordinates>9.5039\d*,47.0657\d* 9.5040\d*,47.0657\d* 9.5040\d*,47.065\d* 9.5054\d*,47.0661\d*</coordinates></LineString> |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
@@ -1,206 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: v1/reverse Parameter Tests
|
||||
Tests for parameter inputs for the v1 reverse endpoint.
|
||||
This file contains mostly bad parameter input. Valid parameters
|
||||
are tested in the format tests.
|
||||
|
||||
Scenario: Bad format
|
||||
When sending v1/reverse at 47.14122383,9.52169581334 with format sdf
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario: Missing lon parameter
|
||||
When sending v1/reverse at 52.52,
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
|
||||
Scenario: Missing lat parameter
|
||||
When sending v1/reverse at ,52.52
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
|
||||
Scenario Outline: Bad format for lat or lon
|
||||
When sending v1/reverse at ,
|
||||
| lat | lon |
|
||||
| <lat> | <lon> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 48.9660 | 8,4482 |
|
||||
| 48,9660 | 8.4482 |
|
||||
| 48,9660 | 8,4482 |
|
||||
| 48.966.0 | 8.4482 |
|
||||
| 48.966 | 8.448.2 |
|
||||
| Nan | 8.448 |
|
||||
| 48.966 | Nan |
|
||||
| Inf | 5.6 |
|
||||
| 5.6 | -Inf |
|
||||
| <script></script> | 3.4 |
|
||||
| 3.4 | <script></script> |
|
||||
| -45.3 | ; |
|
||||
| gkjd | 50 |
|
||||
|
||||
|
||||
Scenario: Non-numerical zoom levels return an error
|
||||
When sending v1/reverse at 47.14122383,9.52169581334
|
||||
| zoom |
|
||||
| adfe |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
|
||||
Scenario Outline: Truthy values for boolean parameters
|
||||
When sending v1/reverse at 47.14122383,9.52169581334
|
||||
| addressdetails |
|
||||
| <value> |
|
||||
Then exactly 1 result is returned
|
||||
And result has attributes address
|
||||
|
||||
When sending v1/reverse at 47.14122383,9.52169581334
|
||||
| extratags |
|
||||
| <value> |
|
||||
Then exactly 1 result is returned
|
||||
And result has attributes extratags
|
||||
|
||||
When sending v1/reverse at 47.14122383,9.52169581334
|
||||
| namedetails |
|
||||
| <value> |
|
||||
Then exactly 1 result is returned
|
||||
And result has attributes namedetails
|
||||
|
||||
When sending v1/reverse at 47.14122383,9.52169581334
|
||||
| polygon_geojson |
|
||||
| <value> |
|
||||
Then exactly 1 result is returned
|
||||
And result has attributes geojson
|
||||
|
||||
When sending v1/reverse at 47.14122383,9.52169581334
|
||||
| polygon_kml |
|
||||
| <value> |
|
||||
Then exactly 1 result is returned
|
||||
And result has attributes geokml
|
||||
|
||||
When sending v1/reverse at 47.14122383,9.52169581334
|
||||
| polygon_svg |
|
||||
| <value> |
|
||||
Then exactly 1 result is returned
|
||||
And result has attributes svg
|
||||
|
||||
When sending v1/reverse at 47.14122383,9.52169581334
|
||||
| polygon_text |
|
||||
| <value> |
|
||||
Then exactly 1 result is returned
|
||||
And result has attributes geotext
|
||||
|
||||
Examples:
|
||||
| value |
|
||||
| yes |
|
||||
| no |
|
||||
| -1 |
|
||||
| 100 |
|
||||
| false |
|
||||
| 00 |
|
||||
|
||||
|
||||
Scenario: Only one geometry can be requested
|
||||
When sending v1/reverse at 47.165989816710066,9.515774846076965
|
||||
| polygon_text | polygon_svg |
|
||||
| 1 | 1 |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
|
||||
Scenario Outline: Wrapping of legal jsonp requests
|
||||
When sending v1/reverse at 67.3245,0.456 with format <format>
|
||||
| json_callback |
|
||||
| foo |
|
||||
Then the result is valid <outformat>
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
| geocodejson | geocodejson |
|
||||
|
||||
|
||||
Scenario Outline: Illegal jsonp are not allowed
|
||||
When sending v1/reverse at 47.165989816710066,9.515774846076965
|
||||
| param | value |
|
||||
|json_callback | <data> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| data |
|
||||
| 1asd |
|
||||
| bar(foo) |
|
||||
| XXX['bad'] |
|
||||
| foo; evil |
|
||||
|
||||
|
||||
Scenario Outline: Reverse debug mode produces valid HTML
|
||||
When sending v1/reverse at , with format debug
|
||||
| lat | lon |
|
||||
| <lat> | <lon> |
|
||||
Then the result is valid html
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 0.0 | 0.0 |
|
||||
| 47.06645 | 9.56601 |
|
||||
| 47.14081 | 9.52267 |
|
||||
|
||||
|
||||
Scenario Outline: Full address display for city housenumber-level address with street
|
||||
When sending v1/reverse at 47.1068011,9.52810091 with format <format>
|
||||
Then address of result 0 is
|
||||
| type | value |
|
||||
| house_number | 8 |
|
||||
| road | Im Winkel |
|
||||
| neighbourhood | Oberdorf |
|
||||
| village | Triesen |
|
||||
| ISO3166-2-lvl8 | LI-09 |
|
||||
| county | Oberland |
|
||||
| postcode | 9495 |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| geojson |
|
||||
| xml |
|
||||
|
||||
|
||||
Scenario Outline: Results with name details
|
||||
When sending v1/reverse at 47.14052,9.52202 with format <format>
|
||||
| zoom | namedetails |
|
||||
| 14 | 1 |
|
||||
Then results contain in field namedetails
|
||||
| name |
|
||||
| Ebenholz |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| xml |
|
||||
| geojson |
|
||||
|
||||
|
||||
Scenario Outline: Results with extratags
|
||||
When sending v1/reverse at 47.14052,9.52202 with format <format>
|
||||
| zoom | extratags |
|
||||
| 14 | 1 |
|
||||
Then results contain in field extratags
|
||||
| wikidata |
|
||||
| Q4529531 |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| xml |
|
||||
| geojson |
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: XML output for Reverse API
|
||||
Testing correctness of xml output (API version v1).
|
||||
|
||||
Scenario Outline: OSM result with and without addresses
|
||||
When sending v1/reverse at 47.066,9.504 with format xml
|
||||
| addressdetails |
|
||||
| <has_address> |
|
||||
Then result has attributes place_id
|
||||
Then result has <attributes> address
|
||||
And results contain
|
||||
| osm_type | osm_id | place_rank | address_rank |
|
||||
| node | 6522627624 | 30 | 30 |
|
||||
And results contain
|
||||
| centroid | boundingbox |
|
||||
| 9.5036065 47.0660892 | 47.0660392,47.0661392,9.5035565,9.5036565 |
|
||||
And results contain
|
||||
| ref | display_name |
|
||||
| Dorfbäckerei Herrmann | Dorfbäckerei Herrmann, 29, Gnetsch, Mäls, Balzers, Oberland, 9496, Liechtenstein |
|
||||
|
||||
Examples:
|
||||
| has_address | attributes |
|
||||
| 1 | attributes |
|
||||
| 0 | not attributes |
|
||||
|
||||
|
||||
@Tiger
|
||||
Scenario: Tiger address
|
||||
When sending v1/reverse at 32.4752389363,-86.4810198619 with format xml
|
||||
Then results contain
|
||||
| osm_type | osm_id | place_rank | address_rank |
|
||||
| way | 396009653 | 30 | 30 |
|
||||
And results contain
|
||||
| centroid | boundingbox |
|
||||
| -86.4808553 32.4753580 | ^32.4753080\d*,32.4754080\d*,-86.4809053\d*,-86.4808053\d* |
|
||||
And results contain
|
||||
| display_name |
|
||||
| 707, Upper Kingston Road, Upper Kingston, Prattville, Autauga County, 36067, United States |
|
||||
|
||||
|
||||
Scenario: Interpolation address
|
||||
When sending v1/reverse at 47.118533,9.57056562 with format xml
|
||||
Then results contain
|
||||
| osm_type | osm_id | place_rank | address_rank |
|
||||
| way | 1 | 30 | 30 |
|
||||
And results contain
|
||||
| centroid | boundingbox |
|
||||
| 9.57054676 47.118545392 | ^47.118495\d*,47.118595\d*,9.570496\d*,9.570596\d* |
|
||||
And results contain
|
||||
| display_name |
|
||||
| 1019, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
|
||||
Scenario: Output of geojson
|
||||
When sending v1/reverse at 47.06597,9.50467 with format xml
|
||||
| param | value |
|
||||
| polygon_geojson | 1 |
|
||||
Then results contain
|
||||
| geojson |
|
||||
| {"type":"LineString","coordinates":[[9.5039353,47.0657546],[9.5040437,47.0657781],[9.5040808,47.065787],[9.5054298,47.0661407]]} |
|
||||
|
||||
|
||||
Scenario: Output of WKT
|
||||
When sending v1/reverse at 47.06597,9.50467 with format xml
|
||||
| param | value |
|
||||
| polygon_text | 1 |
|
||||
Then results contain
|
||||
| geotext |
|
||||
| ^LINESTRING\(9.5039353 47.0657546, ?9.5040437 47.0657781, ?9.5040808 47.065787, ?9.5054298 47.0661407\) |
|
||||
|
||||
|
||||
Scenario: Output of SVG
|
||||
When sending v1/reverse at 47.06597,9.50467 with format xml
|
||||
| param | value |
|
||||
| polygon_svg | 1 |
|
||||
Then results contain
|
||||
| geosvg |
|
||||
| M 9.5039353 -47.0657546 L 9.5040437 -47.0657781 9.5040808 -47.065787 9.5054298 -47.0661407 |
|
||||
|
||||
|
||||
Scenario: Output of KML
|
||||
When sending v1/reverse at 47.06597,9.50467 with format xml
|
||||
| param | value |
|
||||
| polygon_kml | 1 |
|
||||
Then results contain
|
||||
| geokml |
|
||||
| ^<geokml><LineString><coordinates>9.5039\d*,47.0657\d* 9.5040\d*,47.0657\d* 9.5040\d*,47.065\d* 9.5054\d*,47.0661\d*</coordinates></LineString></geokml> |
|
||||
@@ -1,28 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Parameters for Search API
|
||||
Testing correctness of geocodejson output.
|
||||
|
||||
Scenario: City housenumber-level address with street
|
||||
When sending geocodejson search query "Im Winkel 8, Triesen" with address
|
||||
Then results contain
|
||||
| housenumber | street | postcode | city | country |
|
||||
| 8 | Im Winkel | 9495 | Triesen | Liechtenstein |
|
||||
|
||||
Scenario: Town street-level address with street
|
||||
When sending geocodejson search query "Gnetsch, Balzers" with address
|
||||
Then results contain
|
||||
| name | city | postcode | country |
|
||||
| Gnetsch | Balzers | 9496 | Liechtenstein |
|
||||
|
||||
Scenario: Town street-level address with footway
|
||||
When sending geocodejson search query "burg gutenberg 6000 jahre geschichte" with address
|
||||
Then results contain
|
||||
| street | city | postcode | country |
|
||||
| Burgweg | Balzers | 9496 | Liechtenstein |
|
||||
|
||||
Scenario: City address with suburb
|
||||
When sending geocodejson search query "Lochgass 5, Ebenholz, Vaduz" with address
|
||||
Then results contain
|
||||
| housenumber | street | district | city | postcode | country |
|
||||
| 5 | Lochgass | Ebenholz | Vaduz | 9490 | Liechtenstein |
|
||||
@@ -1,63 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Localization of search results
|
||||
|
||||
Scenario: default language
|
||||
When sending json search query "Liechtenstein"
|
||||
Then results contain
|
||||
| ID | display_name |
|
||||
| 0 | Liechtenstein |
|
||||
|
||||
Scenario: accept-language first
|
||||
When sending json search query "Liechtenstein"
|
||||
| accept-language |
|
||||
| zh,de |
|
||||
Then results contain
|
||||
| ID | display_name |
|
||||
| 0 | 列支敦士登 |
|
||||
|
||||
Scenario: accept-language missing
|
||||
When sending json search query "Liechtenstein"
|
||||
| accept-language |
|
||||
| xx,fr,en,de |
|
||||
Then results contain
|
||||
| ID | display_name |
|
||||
| 0 | Liechtenstein |
|
||||
|
||||
Scenario: http accept language header first
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending json search query "Liechtenstein"
|
||||
Then results contain
|
||||
| ID | display_name |
|
||||
| 0 | Liktinstein |
|
||||
|
||||
Scenario: http accept language header and accept-language
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending json search query "Liechtenstein"
|
||||
| accept-language |
|
||||
| fo,en |
|
||||
Then results contain
|
||||
| ID | display_name |
|
||||
| 0 | Liktinstein |
|
||||
|
||||
Scenario: http accept language header fallback
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-ca,en-ca;q=0.5 |
|
||||
When sending json search query "Liechtenstein"
|
||||
Then results contain
|
||||
| ID | display_name |
|
||||
| 0 | Liktinstein |
|
||||
|
||||
Scenario: http accept language header fallback (upper case)
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-FR;q=0.8,en-ca;q=0.5 |
|
||||
When sending json search query "Liechtenstein"
|
||||
Then results contain
|
||||
| ID | display_name |
|
||||
| 0 | Liktinstein |
|
||||
@@ -1,362 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Search queries
|
||||
Testing different queries and parameters
|
||||
|
||||
Scenario: Simple XML search
|
||||
When sending xml search query "Schaan"
|
||||
Then result 0 has attributes place_id,osm_type,osm_id
|
||||
And result 0 has attributes place_rank,boundingbox
|
||||
And result 0 has attributes lat,lon,display_name
|
||||
And result 0 has attributes class,type,importance
|
||||
And result 0 has not attributes address
|
||||
And result 0 has bounding box in 46.5,47.5,9,10
|
||||
|
||||
Scenario: Simple JSON search
|
||||
When sending json search query "Vaduz"
|
||||
Then result 0 has attributes place_id,licence,class,type
|
||||
And result 0 has attributes osm_type,osm_id,boundingbox
|
||||
And result 0 has attributes lat,lon,display_name,importance
|
||||
And result 0 has not attributes address
|
||||
And result 0 has bounding box in 46.5,47.5,9,10
|
||||
|
||||
Scenario: Unknown formats returns a user error
|
||||
When sending search query "Vaduz"
|
||||
| format |
|
||||
| x45 |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario Outline: Search with addressdetails
|
||||
When sending <format> search query "Triesen" with address
|
||||
Then address of result 0 is
|
||||
| type | value |
|
||||
| village | Triesen |
|
||||
| county | Oberland |
|
||||
| postcode | 9495 |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
| ISO3166-2-lvl8 | LI-09 |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| geojson |
|
||||
| xml |
|
||||
|
||||
Scenario: Coordinate search with addressdetails
|
||||
When sending json search query "47.12400621,9.6047552"
|
||||
| accept-language |
|
||||
| en |
|
||||
Then results contain
|
||||
| display_name |
|
||||
| Guschg, Valorschstrasse, Balzers, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Scenario: Address details with unknown class types
|
||||
When sending json search query "Kloster St. Elisabeth" with address
|
||||
Then results contain
|
||||
| ID | class | type |
|
||||
| 0 | amenity | monastery |
|
||||
And result addresses contain
|
||||
| ID | amenity |
|
||||
| 0 | Kloster St. Elisabeth |
|
||||
|
||||
Scenario: Disabling deduplication
|
||||
When sending json search query "Malbunstr"
|
||||
Then there are no duplicates
|
||||
When sending json search query "Malbunstr"
|
||||
| dedupe |
|
||||
| 0 |
|
||||
Then there are duplicates
|
||||
|
||||
Scenario: Search with bounded viewbox in right area
|
||||
When sending json search query "post" with address
|
||||
| bounded | viewbox |
|
||||
| 1 | 9,47,10,48 |
|
||||
Then result addresses contain
|
||||
| ID | town |
|
||||
| 0 | Vaduz |
|
||||
When sending json search query "post" with address
|
||||
| bounded | viewbox |
|
||||
| 1 | 9.49712,47.17122,9.52605,47.16242 |
|
||||
Then result addresses contain
|
||||
| town |
|
||||
| Schaan |
|
||||
|
||||
Scenario: Country search with bounded viewbox remain in the area
|
||||
When sending json search query "" with address
|
||||
| bounded | viewbox | country |
|
||||
| 1 | 9.49712,47.17122,9.52605,47.16242 | de |
|
||||
Then less than 1 result is returned
|
||||
|
||||
Scenario: Search with bounded viewboxlbrt in right area
|
||||
When sending json search query "bar" with address
|
||||
| bounded | viewboxlbrt |
|
||||
| 1 | 9.49712,47.16242,9.52605,47.17122 |
|
||||
Then result addresses contain
|
||||
| town |
|
||||
| Schaan |
|
||||
|
||||
@Fail
|
||||
Scenario: No POI search with unbounded viewbox
|
||||
When sending json search query "restaurant"
|
||||
| viewbox |
|
||||
| 9.93027,53.61634,10.10073,53.54500 |
|
||||
Then results contain
|
||||
| display_name |
|
||||
| ^[^,]*[Rr]estaurant.* |
|
||||
|
||||
Scenario: bounded search remains within viewbox, even with no results
|
||||
When sending json search query "[restaurant]"
|
||||
| bounded | viewbox |
|
||||
| 1 | 43.5403125,-5.6563282,43.54285,-5.662003 |
|
||||
Then less than 1 result is returned
|
||||
|
||||
Scenario: bounded search remains within viewbox with results
|
||||
When sending json search query "restaurant"
|
||||
| bounded | viewbox |
|
||||
| 1 | 9.49712,47.17122,9.52605,47.16242 |
|
||||
Then result has centroid in 9.49712,47.16242,9.52605,47.17122
|
||||
|
||||
Scenario: Prefer results within viewbox
|
||||
When sending json search query "Gässle" with address
|
||||
| accept-language | viewbox |
|
||||
| en | 9.52413,47.10759,9.53140,47.10539 |
|
||||
Then result addresses contain
|
||||
| ID | village |
|
||||
| 0 | Triesen |
|
||||
When sending json search query "Gässle" with address
|
||||
| accept-language | viewbox |
|
||||
| en | 9.45949,47.08421,9.54094,47.05466 |
|
||||
Then result addresses contain
|
||||
| ID | town |
|
||||
| 0 | Balzers |
|
||||
|
||||
Scenario: viewboxes cannot be points
|
||||
When sending json search query "foo"
|
||||
| viewbox |
|
||||
| 1.01,34.6,1.01,34.6 |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario Outline: viewbox must have four coordinate numbers
|
||||
When sending json search query "foo"
|
||||
| viewbox |
|
||||
| <viewbox> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| viewbox |
|
||||
| 34 |
|
||||
| 0.003,-84.4 |
|
||||
| 5.2,4.5542,12.4 |
|
||||
| 23.1,-6,0.11,44.2,9.1 |
|
||||
|
||||
Scenario Outline: viewboxlbrt must have four coordinate numbers
|
||||
When sending json search query "foo"
|
||||
| viewboxlbrt |
|
||||
| <viewbox> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| viewbox |
|
||||
| 34 |
|
||||
| 0.003,-84.4 |
|
||||
| 5.2,4.5542,12.4 |
|
||||
| 23.1,-6,0.11,44.2,9.1 |
|
||||
|
||||
Scenario: Overly large limit number for search results
|
||||
When sending json search query "restaurant"
|
||||
| limit |
|
||||
| 1000 |
|
||||
Then at most 50 results are returned
|
||||
|
||||
Scenario: Limit number of search results
|
||||
When sending json search query "landstr"
|
||||
| dedupe |
|
||||
| 0 |
|
||||
Then more than 4 results are returned
|
||||
When sending json search query "landstr"
|
||||
| limit | dedupe |
|
||||
| 4 | 0 |
|
||||
Then exactly 4 results are returned
|
||||
|
||||
Scenario: Limit parameter must be a number
|
||||
When sending search query "Blue Laguna"
|
||||
| limit |
|
||||
| ); |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario: Restrict to feature type country
|
||||
When sending xml search query "fürstentum"
|
||||
| featureType |
|
||||
| country |
|
||||
Then results contain
|
||||
| place_rank |
|
||||
| 4 |
|
||||
|
||||
Scenario: Restrict to feature type state
|
||||
When sending xml search query "Wangerberg"
|
||||
Then at least 1 result is returned
|
||||
When sending xml search query "Wangerberg"
|
||||
| featureType |
|
||||
| state |
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Restrict to feature type city
|
||||
When sending xml search query "vaduz"
|
||||
Then at least 1 result is returned
|
||||
When sending xml search query "vaduz"
|
||||
| featureType |
|
||||
| city |
|
||||
Then results contain
|
||||
| place_rank |
|
||||
| 16 |
|
||||
|
||||
Scenario: Restrict to feature type settlement
|
||||
When sending json search query "Malbun"
|
||||
Then results contain
|
||||
| ID | class |
|
||||
| 1 | landuse |
|
||||
When sending json search query "Malbun"
|
||||
| featureType |
|
||||
| settlement |
|
||||
Then results contain
|
||||
| class | type |
|
||||
| place | village |
|
||||
|
||||
Scenario Outline: Search with polygon threshold (json)
|
||||
When sending json search query "triesenberg"
|
||||
| polygon_geojson | polygon_threshold |
|
||||
| 1 | <th> |
|
||||
Then at least 1 result is returned
|
||||
And result 0 has attributes geojson
|
||||
|
||||
Examples:
|
||||
| th |
|
||||
| -1 |
|
||||
| 0.0 |
|
||||
| 0.5 |
|
||||
| 999 |
|
||||
|
||||
Scenario Outline: Search with polygon threshold (xml)
|
||||
When sending xml search query "triesenberg"
|
||||
| polygon_geojson | polygon_threshold |
|
||||
| 1 | <th> |
|
||||
Then at least 1 result is returned
|
||||
And result 0 has attributes geojson
|
||||
|
||||
Examples:
|
||||
| th |
|
||||
| -1 |
|
||||
| 0.0 |
|
||||
| 0.5 |
|
||||
| 999 |
|
||||
|
||||
Scenario Outline: Search with invalid polygon threshold (xml)
|
||||
When sending xml search query "triesenberg"
|
||||
| polygon_geojson | polygon_threshold |
|
||||
| 1 | <th> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| th |
|
||||
| x |
|
||||
| ;; |
|
||||
| 1m |
|
||||
|
||||
Scenario Outline: Search with extratags
|
||||
When sending <format> search query "Landstr"
|
||||
| extratags |
|
||||
| 1 |
|
||||
Then result has attributes extratags
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| xml |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| geojson |
|
||||
|
||||
Scenario Outline: Search with namedetails
|
||||
When sending <format> search query "Landstr"
|
||||
| namedetails |
|
||||
| 1 |
|
||||
Then result has attributes namedetails
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| xml |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| geojson |
|
||||
|
||||
Scenario Outline: Search result with contains TEXT geometry
|
||||
When sending <format> search query "triesenberg"
|
||||
| polygon_text |
|
||||
| 1 |
|
||||
Then result has attributes <response_attribute>
|
||||
|
||||
Examples:
|
||||
| format | response_attribute |
|
||||
| xml | geotext |
|
||||
| json | geotext |
|
||||
| jsonv2 | geotext |
|
||||
|
||||
Scenario Outline: Search result contains SVG geometry
|
||||
When sending <format> search query "triesenberg"
|
||||
| polygon_svg |
|
||||
| 1 |
|
||||
Then result has attributes <response_attribute>
|
||||
|
||||
Examples:
|
||||
| format | response_attribute |
|
||||
| xml | geosvg |
|
||||
| json | svg |
|
||||
| jsonv2 | svg |
|
||||
|
||||
Scenario Outline: Search result contains KML geometry
|
||||
When sending <format> search query "triesenberg"
|
||||
| polygon_kml |
|
||||
| 1 |
|
||||
Then result has attributes <response_attribute>
|
||||
|
||||
Examples:
|
||||
| format | response_attribute |
|
||||
| xml | geokml |
|
||||
| json | geokml |
|
||||
| jsonv2 | geokml |
|
||||
|
||||
Scenario Outline: Search result contains GEOJSON geometry
|
||||
When sending <format> search query "triesenberg"
|
||||
| polygon_geojson |
|
||||
| 1 |
|
||||
Then result has attributes <response_attribute>
|
||||
|
||||
Examples:
|
||||
| format | response_attribute |
|
||||
| xml | geojson |
|
||||
| json | geojson |
|
||||
| jsonv2 | geojson |
|
||||
| geojson | geojson |
|
||||
|
||||
Scenario Outline: Search result in geojson format contains no non-geojson geometry
|
||||
When sending geojson search query "triesenberg"
|
||||
| polygon_text | polygon_svg | polygon_geokml |
|
||||
| 1 | 1 | 1 |
|
||||
Then result 0 has not attributes <response_attribute>
|
||||
|
||||
Examples:
|
||||
| response_attribute |
|
||||
| geotext |
|
||||
| polygonpoints |
|
||||
| svg |
|
||||
| geokml |
|
||||
|
||||
|
||||
Scenario: Array parameters are ignored
|
||||
When sending json search query "Vaduz" with address
|
||||
| countrycodes[] | polygon_svg[] | limit[] | polygon_threshold[] |
|
||||
| IT | 1 | 3 | 3.4 |
|
||||
Then result addresses contain
|
||||
| ID | country_code |
|
||||
| 0 | li |
|
||||
@@ -1,221 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Search queries
|
||||
Generic search result correctness
|
||||
|
||||
Scenario: Search for natural object
|
||||
When sending json search query "Samina"
|
||||
| accept-language |
|
||||
| en |
|
||||
Then results contain
|
||||
| ID | class | type | display_name |
|
||||
| 0 | waterway | river | Samina, Austria |
|
||||
|
||||
Scenario: House number search for non-street address
|
||||
When sending json search query "6 Silum, Liechtenstein" with address
|
||||
| accept-language |
|
||||
| en |
|
||||
Then address of result 0 is
|
||||
| type | value |
|
||||
| house_number | 6 |
|
||||
| village | Silum |
|
||||
| town | Triesenberg |
|
||||
| county | Oberland |
|
||||
| postcode | 9497 |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
| ISO3166-2-lvl8 | LI-10 |
|
||||
|
||||
Scenario: House number interpolation
|
||||
When sending json search query "Grosssteg 1023, Triesenberg" with address
|
||||
| accept-language |
|
||||
| de |
|
||||
Then address of result 0 contains
|
||||
| type | value |
|
||||
| house_number | 1023 |
|
||||
| road | Grosssteg |
|
||||
| village | Sücka |
|
||||
| postcode | 9497 |
|
||||
| town | Triesenberg |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
|
||||
Scenario: With missing housenumber search falls back to road
|
||||
When sending json search query "Bündaweg 555" with address
|
||||
Then address of result 0 is
|
||||
| type | value |
|
||||
| road | Bündaweg |
|
||||
| village | Silum |
|
||||
| postcode | 9497 |
|
||||
| county | Oberland |
|
||||
| town | Triesenberg |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
| ISO3166-2-lvl8 | LI-10 |
|
||||
|
||||
Scenario Outline: Housenumber 0 can be found
|
||||
When sending <format> search query "Gnalpstrasse 0" with address
|
||||
Then results contain
|
||||
| display_name |
|
||||
| ^0,.* |
|
||||
And result addresses contain
|
||||
| house_number |
|
||||
| 0 |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| xml |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| geojson |
|
||||
|
||||
@Tiger
|
||||
Scenario: TIGER house number
|
||||
When sending json search query "697 Upper Kingston Road"
|
||||
Then results contain
|
||||
| osm_type | display_name |
|
||||
| way | ^697,.* |
|
||||
|
||||
Scenario: Search with class-type feature
|
||||
When sending jsonv2 search query "bars in ebenholz"
|
||||
Then results contain
|
||||
| place_rank |
|
||||
| 30 |
|
||||
|
||||
Scenario: Search with specific amenity
|
||||
When sending json search query "[restaurant] Vaduz" with address
|
||||
Then result addresses contain
|
||||
| country |
|
||||
| Liechtenstein |
|
||||
And results contain
|
||||
| class | type |
|
||||
| amenity | restaurant |
|
||||
|
||||
Scenario: Search with specific amenity also work in country
|
||||
When sending json search query "restaurants in liechtenstein" with address
|
||||
Then result addresses contain
|
||||
| country |
|
||||
| Liechtenstein |
|
||||
And results contain
|
||||
| class | type |
|
||||
| amenity | restaurant |
|
||||
|
||||
Scenario: Search with key-value amenity
|
||||
When sending json search query "[club=scout] Vaduz"
|
||||
Then results contain
|
||||
| class | type |
|
||||
| club | scout |
|
||||
|
||||
Scenario: POI search near given coordinate
|
||||
When sending json search query "restaurant near 47.16712,9.51100"
|
||||
Then results contain
|
||||
| class | type |
|
||||
| amenity | restaurant |
|
||||
|
||||
Scenario: Arbitrary key/value search near given coordinate
|
||||
When sending json search query "[leisure=firepit] 47.150° N 9.5340493° E"
|
||||
Then results contain
|
||||
| class | type |
|
||||
| leisure | firepit |
|
||||
|
||||
|
||||
Scenario: POI search in a bounded viewbox
|
||||
When sending json search query "restaurants"
|
||||
| viewbox | bounded |
|
||||
| 9.50830,47.15253,9.52043,47.14866 | 1 |
|
||||
Then results contain
|
||||
| class | type |
|
||||
| amenity | restaurant |
|
||||
|
||||
Scenario Outline: Key/value search near given coordinate can be restricted to country
|
||||
When sending json search query "[natural=peak] 47.06512,9.53965" with address
|
||||
| countrycodes |
|
||||
| <cc> |
|
||||
Then result addresses contain
|
||||
| country_code |
|
||||
| <cc> |
|
||||
|
||||
Examples:
|
||||
| cc |
|
||||
| li |
|
||||
| ch |
|
||||
|
||||
Scenario: Name search near given coordinate
|
||||
When sending json search query "sporry" with address
|
||||
Then result addresses contain
|
||||
| ID | town |
|
||||
| 0 | Vaduz |
|
||||
When sending json search query "sporry, 47.10791,9.52676" with address
|
||||
Then result addresses contain
|
||||
| ID | village |
|
||||
| 0 | Triesen |
|
||||
|
||||
Scenario: Name search near given coordinate without result
|
||||
When sending json search query "sporry, N 47 15 7 W 9 61 26"
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Arbitrary key/value search near a road
|
||||
When sending json search query "[amenity=drinking_water] Wissfläckaweg"
|
||||
Then results contain
|
||||
| class | type |
|
||||
| amenity | drinking_water |
|
||||
|
||||
Scenario: Ignore other country codes in structured search with country
|
||||
When sending json search query ""
|
||||
| city | country |
|
||||
| li | de |
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Ignore country searches when query is restricted to countries
|
||||
When sending json search query "fr"
|
||||
| countrycodes |
|
||||
| li |
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Country searches only return results for the given country
|
||||
When sending search query "Ans Trail" with address
|
||||
| countrycodes |
|
||||
| li |
|
||||
Then result addresses contain
|
||||
| country_code |
|
||||
| li |
|
||||
|
||||
# https://trac.openstreetmap.org/ticket/5094
|
||||
Scenario: housenumbers are ordered by complete match first
|
||||
When sending json search query "Austrasse 11, Vaduz" with address
|
||||
Then result addresses contain
|
||||
| ID | house_number |
|
||||
| 0 | 11 |
|
||||
|
||||
Scenario Outline: Coordinate searches with white spaces
|
||||
When sending json search query "<data>"
|
||||
Then exactly 1 result is returned
|
||||
And results contain
|
||||
| class |
|
||||
| water |
|
||||
|
||||
Examples:
|
||||
| data |
|
||||
| sporry weiher, N 47.10791° E 9.52676° |
|
||||
| sporry weiher, N 47.10791° E 9.52676° |
|
||||
| sporry weiher , N 47.10791° E 9.52676° |
|
||||
| sporry weiher, N 47.10791° E 9.52676° |
|
||||
| sporry weiher, N 47.10791° E 9.52676° |
|
||||
|
||||
Scenario: Searches with white spaces
|
||||
When sending json search query "52 Bodastr,Triesenberg"
|
||||
Then results contain
|
||||
| class | type |
|
||||
| highway | residential |
|
||||
|
||||
|
||||
# github #1949
|
||||
Scenario: Addressdetails always return the place type
|
||||
When sending json search query "Vaduz" with address
|
||||
Then result addresses contain
|
||||
| ID | town |
|
||||
| 0 | Vaduz |
|
||||
|
||||
Scenario: Search can handle complex query word sets
|
||||
When sending search query "aussenstelle universitat lichtenstein wachterhaus aussenstelle universitat lichtenstein wachterhaus aussenstelle universitat lichtenstein wachterhaus aussenstelle universitat lichtenstein wachterhaus"
|
||||
Then a HTTP 200 is returned
|
||||
@@ -1,208 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Simple Tests
|
||||
Simple tests for internal server errors and response format.
|
||||
|
||||
Scenario Outline: Testing different parameters
|
||||
When sending search query "Vaduz"
|
||||
| param | value |
|
||||
| <parameter> | <value> |
|
||||
Then at least 1 result is returned
|
||||
When sending xml search query "Vaduz"
|
||||
| param | value |
|
||||
| <parameter> | <value> |
|
||||
Then at least 1 result is returned
|
||||
When sending json search query "Vaduz"
|
||||
| param | value |
|
||||
| <parameter> | <value> |
|
||||
Then at least 1 result is returned
|
||||
When sending jsonv2 search query "Vaduz"
|
||||
| param | value |
|
||||
| <parameter> | <value> |
|
||||
Then at least 1 result is returned
|
||||
When sending geojson search query "Vaduz"
|
||||
| param | value |
|
||||
| <parameter> | <value> |
|
||||
Then at least 1 result is returned
|
||||
When sending geocodejson search query "Vaduz"
|
||||
| param | value |
|
||||
| <parameter> | <value> |
|
||||
Then at least 1 result is returned
|
||||
|
||||
Examples:
|
||||
| parameter | value |
|
||||
| addressdetails | 0 |
|
||||
| polygon_text | 0 |
|
||||
| polygon_kml | 0 |
|
||||
| polygon_geojson | 0 |
|
||||
| polygon_svg | 0 |
|
||||
| accept-language | de,en |
|
||||
| countrycodes | li |
|
||||
| bounded | 1 |
|
||||
| bounded | 0 |
|
||||
| exclude_place_ids| 385252,1234515 |
|
||||
| limit | 1000 |
|
||||
| dedupe | 1 |
|
||||
| dedupe | 0 |
|
||||
| extratags | 0 |
|
||||
| namedetails | 0 |
|
||||
|
||||
Scenario: Search with invalid output format
|
||||
When sending search query "Berlin"
|
||||
| format |
|
||||
| fd$# |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario Outline: Simple Searches
|
||||
When sending search query "<query>"
|
||||
Then the result is valid json
|
||||
When sending xml search query "<query>"
|
||||
Then the result is valid xml
|
||||
When sending json search query "<query>"
|
||||
Then the result is valid json
|
||||
When sending jsonv2 search query "<query>"
|
||||
Then the result is valid json
|
||||
When sending geojson search query "<query>"
|
||||
Then the result is valid geojson
|
||||
|
||||
Examples:
|
||||
| query |
|
||||
| New York, New York |
|
||||
| France |
|
||||
| 12, Main Street, Houston |
|
||||
| München |
|
||||
| 東京都 |
|
||||
| hotels in nantes |
|
||||
| xywxkrf |
|
||||
| gh; foo() |
|
||||
| %#$@*&l;der#$! |
|
||||
| 234 |
|
||||
| 47.4,8.3 |
|
||||
|
||||
Scenario: Empty XML search
|
||||
When sending xml search query "xnznxvcx"
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| querystring | xnznxvcx |
|
||||
| more_url | .*q=xnznxvcx.*format=xml |
|
||||
|
||||
Scenario: Empty XML search with special XML characters
|
||||
When sending xml search query "xfdghn&zxn"xvbyx<vxx>cssdex"
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| querystring | xfdghn&zxn"xvbyx<vxx>cssdex |
|
||||
| more_url | .*q=xfdghn%26zxn%22xvbyx%3Cvxx%3Ecssdex.*format=xml |
|
||||
|
||||
Scenario: Empty XML search with viewbox
|
||||
When sending xml search query "xnznxvcx"
|
||||
| viewbox |
|
||||
| 12,33,77,45.13 |
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| querystring | xnznxvcx |
|
||||
| viewbox | 12,33,77,45.13 |
|
||||
|
||||
Scenario: Empty XML search with viewboxlbrt
|
||||
When sending xml search query "xnznxvcx"
|
||||
| viewboxlbrt |
|
||||
| 12,34.13,77,45 |
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| querystring | xnznxvcx |
|
||||
| viewbox | 12,34.13,77,45 |
|
||||
|
||||
Scenario: Empty XML search with viewboxlbrt and viewbox
|
||||
When sending xml search query "pub"
|
||||
| viewbox | viewboxblrt |
|
||||
| 12,33,77,45.13 | 1,2,3,4 |
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| querystring | pub |
|
||||
| viewbox | 12,33,77,45.13 |
|
||||
|
||||
Scenario: Empty XML search with excluded place ids
|
||||
When sending xml search query "jghrleoxsbwjer"
|
||||
| exclude_place_ids |
|
||||
| 123,76,342565 |
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| exclude_place_ids | 123,76,342565 |
|
||||
|
||||
Scenario: Empty XML search with bad excluded place ids
|
||||
When sending xml search query "jghrleoxsbwjer"
|
||||
| exclude_place_ids |
|
||||
| , |
|
||||
Then result header has not attributes exclude_place_ids
|
||||
|
||||
Scenario Outline: Wrapping of legal jsonp search requests
|
||||
When sending json search query "Tokyo"
|
||||
| param | value |
|
||||
|json_callback | <data> |
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| json_func | <result> |
|
||||
|
||||
Examples:
|
||||
| data | result |
|
||||
| foo | foo |
|
||||
| FOO | FOO |
|
||||
| __world | __world |
|
||||
|
||||
Scenario Outline: Wrapping of illegal jsonp search requests
|
||||
When sending json search query "Tokyo"
|
||||
| param | value |
|
||||
|json_callback | <data> |
|
||||
Then a json user error is returned
|
||||
|
||||
Examples:
|
||||
| data |
|
||||
| 1asd |
|
||||
| bar(foo) |
|
||||
| XXX['bad'] |
|
||||
| foo; evil |
|
||||
|
||||
Scenario: Ignore jsonp parameter for anything but json
|
||||
When sending json search query "Malibu"
|
||||
| json_callback |
|
||||
| 234 |
|
||||
Then a HTTP 400 is returned
|
||||
When sending xml search query "Malibu"
|
||||
| json_callback |
|
||||
| 234 |
|
||||
Then the result is valid xml
|
||||
|
||||
Scenario Outline: Empty search
|
||||
When sending <format> search query "YHlERzzx"
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
| geojson |
|
||||
| geocodejson |
|
||||
|
||||
Scenario: Search for non-existing coordinates
|
||||
When sending json search query "-21.0,-33.0"
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Country code selection is retained in more URL (#596)
|
||||
When sending xml search query "Vaduz"
|
||||
| countrycodes |
|
||||
| pl,1,,invalid,undefined,%3Cb%3E,bo,, |
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| more_url | .*&countrycodes=pl%2Cbo&.* |
|
||||
|
||||
Scenario Outline: Search debug output does not return errors
|
||||
When sending debug search query "<query>"
|
||||
Then a HTTP 200 is returned
|
||||
|
||||
Examples:
|
||||
| query |
|
||||
| Liechtenstein |
|
||||
| Triesen |
|
||||
| Pfarrkirche |
|
||||
| Landstr 27 Steinort, Triesenberg, 9495 |
|
||||
| 9497 |
|
||||
| restaurant in triesen |
|
||||
@@ -1,79 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Structured search queries
|
||||
Testing correctness of results with
|
||||
structured queries
|
||||
|
||||
Scenario: Country only
|
||||
When sending json search query "" with address
|
||||
| country |
|
||||
| Liechtenstein |
|
||||
Then address of result 0 is
|
||||
| type | value |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
|
||||
Scenario: Postcode only
|
||||
When sending json search query "" with address
|
||||
| postalcode |
|
||||
| 9495 |
|
||||
Then results contain
|
||||
| type |
|
||||
| ^post(al_)?code |
|
||||
And result addresses contain
|
||||
| postcode |
|
||||
| 9495 |
|
||||
|
||||
Scenario: Street, postcode and country
|
||||
When sending xml search query "" with address
|
||||
| street | postalcode | country |
|
||||
| Old Palace Road | GU2 7UP | United Kingdom |
|
||||
Then result header contains
|
||||
| attr | value |
|
||||
| querystring | Old Palace Road, GU2 7UP, United Kingdom |
|
||||
|
||||
Scenario: Street with housenumber, city and postcode
|
||||
When sending xml search query "" with address
|
||||
| street | city | postalcode |
|
||||
| 19 Am schrägen Weg | Vaduz | 9490 |
|
||||
Then result addresses contain
|
||||
| house_number | road |
|
||||
| 19 | Am Schrägen Weg |
|
||||
|
||||
Scenario: Street with housenumber, city and bad postcode
|
||||
When sending xml search query "" with address
|
||||
| street | city | postalcode |
|
||||
| 19 Am schrägen Weg | Vaduz | 9491 |
|
||||
Then result addresses contain
|
||||
| house_number | road |
|
||||
| 19 | Am Schrägen Weg |
|
||||
|
||||
Scenario: Amenity, city
|
||||
When sending json search query "" with address
|
||||
| city | amenity |
|
||||
| Vaduz | bar |
|
||||
Then result addresses contain
|
||||
| country |
|
||||
| Liechtenstein |
|
||||
And results contain
|
||||
| class | type |
|
||||
| amenity | ^(pub)\|(bar)\|(restaurant) |
|
||||
|
||||
#176
|
||||
Scenario: Structured search restricts rank
|
||||
When sending json search query "" with address
|
||||
| city |
|
||||
| Vaduz |
|
||||
Then result addresses contain
|
||||
| town |
|
||||
| Vaduz |
|
||||
|
||||
#3651
|
||||
Scenario: Structured search with surrounding extra characters
|
||||
When sending xml search query "" with address
|
||||
| street | city | postalcode |
|
||||
| "19 Am schrägen Weg" | "Vaduz" | "9491" |
|
||||
Then result addresses contain
|
||||
| house_number | road |
|
||||
| 19 | Am Schrägen Weg |
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
@UNKNOWNDB
|
||||
Feature: Status queries against unknown database
|
||||
Testing status query
|
||||
|
||||
Scenario: Failed status as text
|
||||
When sending text status query
|
||||
Then a HTTP 500 is returned
|
||||
And the page contents equals "ERROR: Database connection failed"
|
||||
|
||||
Scenario: Failed status as json
|
||||
When sending json status query
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And results contain
|
||||
| status | message |
|
||||
| 700 | Database connection failed |
|
||||
And result has not attributes data_updated
|
||||
@@ -1,17 +0,0 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Status queries
|
||||
Testing status query
|
||||
|
||||
Scenario: Status as text
|
||||
When sending status query
|
||||
Then a HTTP 200 is returned
|
||||
And the page contents equals "OK"
|
||||
|
||||
Scenario: Status as json
|
||||
When sending json status query
|
||||
Then the result is valid json
|
||||
And results contain
|
||||
| status | message |
|
||||
| 0 | OK |
|
||||
And result has attributes data_updated
|
||||
358
test/bdd/conftest.py
Normal file
358
test/bdd/conftest.py
Normal file
@@ -0,0 +1,358 @@
|
||||
# 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.
|
||||
"""
|
||||
Fixtures for BDD test steps
|
||||
"""
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import psycopg
|
||||
from psycopg import sql as pysql
|
||||
|
||||
# always test against the source
|
||||
SRC_DIR = (Path(__file__) / '..' / '..' / '..').resolve()
|
||||
sys.path.insert(0, str(SRC_DIR / 'src'))
|
||||
|
||||
import pytest
|
||||
from pytest_bdd.parsers import re as step_parse
|
||||
from pytest_bdd import given, when, then
|
||||
|
||||
pytest.register_assert_rewrite('utils')
|
||||
|
||||
from utils.api_runner import APIRunner
|
||||
from utils.api_result import APIResult
|
||||
from utils.checks import ResultAttr, COMPARATOR_TERMS
|
||||
from utils.geometry_alias import ALIASES
|
||||
from utils.grid import Grid
|
||||
from utils.db import DBManager
|
||||
|
||||
from nominatim_db.config import Configuration
|
||||
from nominatim_db.data.country_info import setup_country_config
|
||||
|
||||
|
||||
def _strlist(inp):
|
||||
return [s.strip() for s in inp.split(',')]
|
||||
|
||||
|
||||
def _pretty_json(inp):
|
||||
return json.dumps(inp, indent=2)
|
||||
|
||||
|
||||
def pytest_addoption(parser, pluginmanager):
|
||||
parser.addoption('--nominatim-purge', dest='NOMINATIM_PURGE', action='store_true',
|
||||
help='Force recreation of test databases from scratch.')
|
||||
parser.addoption('--nominatim-keep-db', dest='NOMINATIM_KEEP_DB', action='store_true',
|
||||
help='Do not drop the database after tests are finished.')
|
||||
parser.addoption('--nominatim-api-engine', dest='NOMINATIM_API_ENGINE',
|
||||
default='falcon',
|
||||
help='Chose the API engine to use when sending requests.')
|
||||
parser.addoption('--nominatim-tokenizer', dest='NOMINATIM_TOKENIZER',
|
||||
metavar='TOKENIZER',
|
||||
help='Use the specified tokenizer for importing data into '
|
||||
'a Nominatim database.')
|
||||
|
||||
parser.addini('nominatim_test_db', default='test_nominatim',
|
||||
help='Name of the database used for running a single test.')
|
||||
parser.addini('nominatim_api_test_db', default='test_api_nominatim',
|
||||
help='Name of the database for storing API test data.')
|
||||
parser.addini('nominatim_template_db', default='test_template_nominatim',
|
||||
help='Name of database used as a template for test databases.')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def datatable():
|
||||
""" Default fixture for datatables, so that their presence can be optional.
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def node_grid():
|
||||
""" Default fixture for node grids. Nothing set.
|
||||
"""
|
||||
return Grid([[]], None, None)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session', autouse=True)
|
||||
def setup_country_info():
|
||||
setup_country_config(Configuration(None))
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def template_db(pytestconfig):
|
||||
""" Create a template database containing the extensions and base data
|
||||
needed by Nominatim. Using the template instead of doing the full
|
||||
setup can speed up the tests.
|
||||
|
||||
The template database will only be created if it does not exist yet
|
||||
or a purge has been explicitly requested.
|
||||
"""
|
||||
dbm = DBManager(purge=pytestconfig.option.NOMINATIM_PURGE)
|
||||
|
||||
template_db = pytestconfig.getini('nominatim_template_db')
|
||||
|
||||
template_config = Configuration(
|
||||
None, environ={'NOMINATIM_DATABASE_DSN': f"pgsql:dbname={template_db}"})
|
||||
|
||||
dbm.setup_template_db(template_config)
|
||||
|
||||
return template_db
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def def_config(pytestconfig):
|
||||
dbname = pytestconfig.getini('nominatim_test_db')
|
||||
|
||||
return Configuration(None,
|
||||
environ={'NOMINATIM_DATABASE_DSN': f"pgsql:dbname={dbname}"})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def db(template_db, pytestconfig):
|
||||
""" Set up an empty database for use with osm2pgsql.
|
||||
"""
|
||||
dbm = DBManager(purge=pytestconfig.option.NOMINATIM_PURGE)
|
||||
|
||||
dbname = pytestconfig.getini('nominatim_test_db')
|
||||
|
||||
dbm.create_db_from_template(dbname, template_db)
|
||||
|
||||
yield dbname
|
||||
|
||||
if not pytestconfig.option.NOMINATIM_KEEP_DB:
|
||||
dbm.drop_db(dbname)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def db_conn(db, def_config):
|
||||
with psycopg.connect(def_config.get_libpq_dsn()) as conn:
|
||||
info = psycopg.types.TypeInfo.fetch(conn, "hstore")
|
||||
psycopg.types.hstore.register_hstore(info, conn)
|
||||
yield conn
|
||||
|
||||
|
||||
@when(step_parse(r'reverse geocoding (?P<lat>[\d.-]*),(?P<lon>[\d.-]*)'),
|
||||
target_fixture='nominatim_result')
|
||||
def reverse_geocode_via_api(test_config_env, pytestconfig, datatable, lat, lon):
|
||||
runner = APIRunner(test_config_env, pytestconfig.option.NOMINATIM_API_ENGINE)
|
||||
api_response = runner.run_step('reverse',
|
||||
{'lat': float(lat), 'lon': float(lon)},
|
||||
datatable, 'jsonv2', {})
|
||||
|
||||
assert api_response.status == 200
|
||||
assert api_response.headers['content-type'] == 'application/json; charset=utf-8'
|
||||
|
||||
result = APIResult('json', 'reverse', api_response.body)
|
||||
assert result.is_simple()
|
||||
|
||||
assert isinstance(result.result['lat'], str)
|
||||
assert isinstance(result.result['lon'], str)
|
||||
result.result['centroid'] = f"POINT({result.result['lon']} {result.result['lat']})"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@when(step_parse(r'reverse geocoding at node (?P<node>[\d]+)'),
|
||||
target_fixture='nominatim_result')
|
||||
def reverse_geocode_via_api_and_grid(test_config_env, pytestconfig, node_grid, datatable, node):
|
||||
coords = node_grid.get(node)
|
||||
if coords is None:
|
||||
raise ValueError('Unknown node id')
|
||||
|
||||
return reverse_geocode_via_api(test_config_env, pytestconfig, datatable, coords[1], coords[0])
|
||||
|
||||
|
||||
@when(step_parse(r'geocoding(?: "(?P<query>.*)")?'),
|
||||
target_fixture='nominatim_result')
|
||||
def forward_geocode_via_api(test_config_env, pytestconfig, datatable, query):
|
||||
runner = APIRunner(test_config_env, pytestconfig.option.NOMINATIM_API_ENGINE)
|
||||
|
||||
params = {'addressdetails': '1'}
|
||||
if query:
|
||||
params['q'] = query
|
||||
|
||||
api_response = runner.run_step('search', params, datatable, 'jsonv2', {})
|
||||
|
||||
assert api_response.status == 200
|
||||
assert api_response.headers['content-type'] == 'application/json; charset=utf-8'
|
||||
|
||||
result = APIResult('json', 'search', api_response.body)
|
||||
assert not result.is_simple()
|
||||
|
||||
for res in result.result:
|
||||
assert isinstance(res['lat'], str)
|
||||
assert isinstance(res['lon'], str)
|
||||
res['centroid'] = f"POINT({res['lon']} {res['lat']})"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@then(step_parse(r'(?P<op>[a-z ]+) (?P<num>\d+) results? (?:are|is) returned'),
|
||||
converters={'num': int})
|
||||
def check_number_of_results(nominatim_result, op, num):
|
||||
assert not nominatim_result.is_simple()
|
||||
assert COMPARATOR_TERMS[op](num, len(nominatim_result))
|
||||
|
||||
|
||||
@then(step_parse('the result metadata contains'))
|
||||
def check_metadata_for_fields(nominatim_result, datatable):
|
||||
if datatable[0] == ['param', 'value']:
|
||||
pairs = datatable[1:]
|
||||
else:
|
||||
pairs = zip(datatable[0], datatable[1])
|
||||
|
||||
for k, v in pairs:
|
||||
assert ResultAttr(nominatim_result.meta, k) == v
|
||||
|
||||
|
||||
@then(step_parse('the result metadata has no attributes (?P<attributes>.*)'),
|
||||
converters={'attributes': _strlist})
|
||||
def check_metadata_for_field_presence(nominatim_result, attributes):
|
||||
assert all(a not in nominatim_result.meta for a in attributes), \
|
||||
f"Unexpectedly have one of the attributes '{attributes}' in\n" \
|
||||
f"{_pretty_json(nominatim_result.meta)}"
|
||||
|
||||
|
||||
@then(step_parse(r'the result contains(?: in field (?P<field>\S+))?'))
|
||||
def check_result_for_fields(nominatim_result, datatable, node_grid, field):
|
||||
assert nominatim_result.is_simple()
|
||||
|
||||
if datatable[0] == ['param', 'value']:
|
||||
pairs = datatable[1:]
|
||||
else:
|
||||
pairs = zip(datatable[0], datatable[1])
|
||||
|
||||
prefix = field + '+' if field else ''
|
||||
|
||||
for k, v in pairs:
|
||||
assert ResultAttr(nominatim_result.result, prefix + k, grid=node_grid) == v
|
||||
|
||||
|
||||
@then(step_parse('the result has attributes (?P<attributes>.*)'),
|
||||
converters={'attributes': _strlist})
|
||||
def check_result_for_field_presence(nominatim_result, attributes):
|
||||
assert nominatim_result.is_simple()
|
||||
assert all(a in nominatim_result.result for a in attributes)
|
||||
|
||||
|
||||
@then(step_parse('the result has no attributes (?P<attributes>.*)'),
|
||||
converters={'attributes': _strlist})
|
||||
def check_result_for_field_absence(nominatim_result, attributes):
|
||||
assert nominatim_result.is_simple()
|
||||
assert all(a not in nominatim_result.result for a in attributes)
|
||||
|
||||
|
||||
@then(step_parse('the result set contains(?P<exact> exactly)?'))
|
||||
def check_result_list_match(nominatim_result, datatable, exact):
|
||||
assert not nominatim_result.is_simple()
|
||||
|
||||
result_set = set(range(len(nominatim_result.result)))
|
||||
|
||||
for row in datatable[1:]:
|
||||
for idx in result_set:
|
||||
for key, value in zip(datatable[0], row):
|
||||
if ResultAttr(nominatim_result.result[idx], key) != value:
|
||||
break
|
||||
else:
|
||||
# found a match
|
||||
result_set.remove(idx)
|
||||
break
|
||||
else:
|
||||
assert False, f"Missing data row {row}. Full response:\n{nominatim_result}"
|
||||
|
||||
if exact:
|
||||
assert not [nominatim_result.result[i] for i in result_set]
|
||||
|
||||
|
||||
@then(step_parse('all results have attributes (?P<attributes>.*)'),
|
||||
converters={'attributes': _strlist})
|
||||
def check_all_results_for_field_presence(nominatim_result, attributes):
|
||||
assert not nominatim_result.is_simple()
|
||||
assert len(nominatim_result) > 0
|
||||
for res in nominatim_result.result:
|
||||
assert all(a in res for a in attributes), \
|
||||
f"Missing one of the attributes '{attributes}' in\n{_pretty_json(res)}"
|
||||
|
||||
|
||||
@then(step_parse('all results have no attributes (?P<attributes>.*)'),
|
||||
converters={'attributes': _strlist})
|
||||
def check_all_result_for_field_absence(nominatim_result, attributes):
|
||||
assert not nominatim_result.is_simple()
|
||||
assert len(nominatim_result) > 0
|
||||
for res in nominatim_result.result:
|
||||
assert all(a not in res for a in attributes), \
|
||||
f"Unexpectedly have one of the attributes '{attributes}' in\n{_pretty_json(res)}"
|
||||
|
||||
|
||||
@then(step_parse(r'all results contain(?: in field (?P<field>\S+))?'))
|
||||
def check_all_results_contain(nominatim_result, datatable, node_grid, field):
|
||||
assert not nominatim_result.is_simple()
|
||||
assert len(nominatim_result) > 0
|
||||
|
||||
if datatable[0] == ['param', 'value']:
|
||||
pairs = datatable[1:]
|
||||
else:
|
||||
pairs = zip(datatable[0], datatable[1])
|
||||
|
||||
prefix = field + '+' if field else ''
|
||||
|
||||
for k, v in pairs:
|
||||
for r in nominatim_result.result:
|
||||
assert ResultAttr(r, prefix + k, grid=node_grid) == v
|
||||
|
||||
|
||||
@then(step_parse(r'result (?P<num>\d+) contains(?: in field (?P<field>\S+))?'),
|
||||
converters={'num': int})
|
||||
def check_specific_result_for_fields(nominatim_result, datatable, num, field):
|
||||
assert not nominatim_result.is_simple()
|
||||
assert len(nominatim_result) > num
|
||||
|
||||
if datatable[0] == ['param', 'value']:
|
||||
pairs = datatable[1:]
|
||||
else:
|
||||
pairs = zip(datatable[0], datatable[1])
|
||||
|
||||
prefix = field + '+' if field else ''
|
||||
|
||||
for k, v in pairs:
|
||||
assert ResultAttr(nominatim_result.result[num], prefix + k) == v
|
||||
|
||||
|
||||
@given(step_parse(r'the (?P<step>[0-9.]+ )?grid(?: with origin (?P<origin>.*))?'),
|
||||
target_fixture='node_grid')
|
||||
def set_node_grid(datatable, step, origin):
|
||||
if step is not None:
|
||||
step = float(step)
|
||||
|
||||
if origin:
|
||||
if ',' in origin:
|
||||
coords = origin.split(',')
|
||||
if len(coords) != 2:
|
||||
raise RuntimeError('Grid origin expects origin with x,y coordinates.')
|
||||
origin = list(map(float, coords))
|
||||
elif origin in ALIASES:
|
||||
origin = ALIASES[origin]
|
||||
else:
|
||||
raise RuntimeError('Grid origin must be either coordinate or alias.')
|
||||
|
||||
return Grid(datatable, step, origin)
|
||||
|
||||
|
||||
@then(step_parse('(?P<table>placex?) has no entry for '
|
||||
r'(?P<osm_type>[NRW])(?P<osm_id>\d+)(?::(?P<osm_class>\S+))?'),
|
||||
converters={'osm_id': int})
|
||||
def check_place_missing_lines(db_conn, table, osm_type, osm_id, osm_class):
|
||||
sql = pysql.SQL("""SELECT count(*) FROM {}
|
||||
WHERE osm_type = %s and osm_id = %s""").format(pysql.Identifier(table))
|
||||
params = [osm_type, int(osm_id)]
|
||||
if osm_class:
|
||||
sql += pysql.SQL(' AND class = %s')
|
||||
params.append(osm_class)
|
||||
|
||||
with db_conn.cursor() as cur:
|
||||
assert cur.execute(sql, params).fetchone()[0] == 0
|
||||
@@ -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,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,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)
|
||||
83
test/bdd/features/api/details/language.feature
Normal file
83
test/bdd/features/api/details/language.feature
Normal file
@@ -0,0 +1,83 @@
|
||||
Feature: Localization of search results
|
||||
|
||||
Scenario: default language
|
||||
When sending v1/details
|
||||
| osmtype | osmid |
|
||||
| R | 1155955 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| localname |
|
||||
| Liechtenstein |
|
||||
|
||||
Scenario: accept-language first
|
||||
When sending v1/details
|
||||
| osmtype | osmid | accept-language |
|
||||
| R | 1155955 | zh,de |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| localname |
|
||||
| 列支敦士登 |
|
||||
|
||||
Scenario: accept-language missing
|
||||
When sending v1/details
|
||||
| osmtype | osmid | accept-language |
|
||||
| R | 1155955 | xx,fr,en,de |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| localname |
|
||||
| Liechtenstein |
|
||||
|
||||
Scenario: http accept language header first
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending v1/details
|
||||
| osmtype | osmid |
|
||||
| R | 1155955 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| localname |
|
||||
| Liktinstein |
|
||||
|
||||
Scenario: http accept language header and accept-language
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending v1/details
|
||||
| osmtype | osmid | accept-language |
|
||||
| R | 1155955 | fo,en |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| localname |
|
||||
| Liktinstein |
|
||||
|
||||
Scenario: http accept language header fallback
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-ca,en-ca;q=0.5 |
|
||||
When sending v1/details
|
||||
| osmtype | osmid |
|
||||
| R | 1155955 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| localname |
|
||||
| Liktinstein |
|
||||
|
||||
Scenario: http accept language header fallback (upper case)
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-FR;q=0.8,en-ca;q=0.5 |
|
||||
When sending v1/details
|
||||
| osmtype | osmid |
|
||||
| R | 1155955 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| localname |
|
||||
| Liktinstein |
|
||||
99
test/bdd/features/api/details/params.feature
Normal file
99
test/bdd/features/api/details/params.feature
Normal file
@@ -0,0 +1,99 @@
|
||||
Feature: Object details
|
||||
Testing different parameter options for details API.
|
||||
|
||||
Scenario: Basic details
|
||||
When sending v1/details
|
||||
| osmtype | osmid |
|
||||
| W | 297699560 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes geometry
|
||||
And the result has no attributes keywords,address,linked_places,parentof
|
||||
And the result contains
|
||||
| geometry+type |
|
||||
| Point |
|
||||
|
||||
Scenario: Basic details with pretty printing
|
||||
When sending v1/details
|
||||
| osmtype | osmid | pretty |
|
||||
| W | 297699560 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes geometry
|
||||
And the result has no attributes keywords,address,linked_places,parentof
|
||||
|
||||
Scenario: Details with addressdetails
|
||||
When sending v1/details
|
||||
| osmtype | osmid | addressdetails |
|
||||
| W | 297699560 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes address
|
||||
|
||||
Scenario: Details with linkedplaces
|
||||
When sending v1/details
|
||||
| osmtype | osmid | linkedplaces |
|
||||
| R | 123924 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes linked_places
|
||||
|
||||
Scenario: Details with hierarchy
|
||||
When sending v1/details
|
||||
| osmtype | osmid | hierarchy |
|
||||
| W | 297699560 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes hierarchy
|
||||
|
||||
Scenario: Details with grouped hierarchy
|
||||
When sending v1/details
|
||||
| osmtype | osmid | hierarchy | group_hierarchy |
|
||||
| W | 297699560 | 1 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes hierarchy
|
||||
|
||||
Scenario Outline: Details with keywords
|
||||
When sending v1/details
|
||||
| osmtype | osmid | keywords |
|
||||
| <type> | <id> | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
Then the result is valid json
|
||||
And the result has attributes keywords
|
||||
|
||||
Examples:
|
||||
| type | id |
|
||||
| W | 297699560 |
|
||||
| W | 243055645 |
|
||||
| W | 243055716 |
|
||||
| W | 43327921 |
|
||||
|
||||
# ticket #1343
|
||||
Scenario: Details of a country with keywords
|
||||
When sending v1/details
|
||||
| osmtype | osmid | keywords |
|
||||
| R | 1155955 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes keywords
|
||||
|
||||
Scenario Outline: Details with full geometry
|
||||
When sending v1/details
|
||||
| osmtype | osmid | polygon_geojson |
|
||||
| <type> | <id> | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes geometry
|
||||
And the result contains
|
||||
| geometry+type |
|
||||
| <geometry> |
|
||||
|
||||
Examples:
|
||||
| type | id | geometry |
|
||||
| W | 297699560 | LineString |
|
||||
| W | 243055645 | Polygon |
|
||||
| W | 243055716 | Polygon |
|
||||
| W | 43327921 | LineString |
|
||||
|
||||
|
||||
99
test/bdd/features/api/details/simple.feature
Normal file
99
test/bdd/features/api/details/simple.feature
Normal file
@@ -0,0 +1,99 @@
|
||||
Feature: Object details
|
||||
Check details page for correctness
|
||||
|
||||
Scenario Outline: Details request with OSM id
|
||||
When sending v1/details
|
||||
| osmtype | osmid |
|
||||
| <type> | <id> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| osm_type | osm_id |
|
||||
| <type> | <id> |
|
||||
|
||||
Examples:
|
||||
| type | id |
|
||||
| N | 5484325405 |
|
||||
| W | 43327921 |
|
||||
| R | 123924 |
|
||||
|
||||
Scenario Outline: Details request with different class types for the same OSM id
|
||||
When sending v1/details
|
||||
| osmtype | osmid | class |
|
||||
| N | 300209696 | <class> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| osm_type | osm_id | category |
|
||||
| N | 300209696 | <class> |
|
||||
|
||||
Examples:
|
||||
| class |
|
||||
| tourism |
|
||||
| mountain_pass |
|
||||
|
||||
Scenario: Details request without osmtype
|
||||
When sending v1/details
|
||||
| osmid |
|
||||
| <id> |
|
||||
Then a HTTP 400 is returned
|
||||
And the result is valid json
|
||||
|
||||
Scenario: Details request with unknown OSM id
|
||||
When sending v1/details
|
||||
| osmtype | osmid |
|
||||
| R | 1 |
|
||||
Then a HTTP 404 is returned
|
||||
And the result is valid json
|
||||
|
||||
Scenario: Details request with unknown class
|
||||
When sending v1/details
|
||||
| osmtype | osmid | class |
|
||||
| N | 300209696 | highway |
|
||||
Then a HTTP 404 is returned
|
||||
And the result is valid json
|
||||
|
||||
Scenario: Details for interpolation way return the interpolation
|
||||
When sending v1/details
|
||||
| osmtype | osmid |
|
||||
| W | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| category | type | osm_type | osm_id | admin_level |
|
||||
| place | houses | W | 1 | 15 |
|
||||
|
||||
|
||||
@skip
|
||||
Scenario: Details for interpolation way return the interpolation
|
||||
When sending details query for 112871
|
||||
Then the result is valid json
|
||||
And the result contains
|
||||
| category | type | admin_level |
|
||||
| place | houses | 15 |
|
||||
And result has not attributes osm_type,osm_id
|
||||
|
||||
|
||||
@skip
|
||||
Scenario: Details for postcode
|
||||
When sending details query for 112820
|
||||
Then the result is valid json
|
||||
And the result contains
|
||||
| category | type | admin_level |
|
||||
| place | postcode | 15 |
|
||||
And result has not attributes osm_type,osm_id
|
||||
|
||||
|
||||
Scenario Outline: Details debug output returns no errors
|
||||
When sending v1/details
|
||||
| osmtype | osmid | debug |
|
||||
| <type> | <id> | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid html
|
||||
|
||||
Examples:
|
||||
| type | id |
|
||||
| N | 5484325405 |
|
||||
| W | 43327921 |
|
||||
| R | 123924 |
|
||||
|
||||
71
test/bdd/features/api/lookup/simple.feature
Normal file
71
test/bdd/features/api/lookup/simple.feature
Normal file
@@ -0,0 +1,71 @@
|
||||
Feature: Tests for finding places by osm_type and osm_id
|
||||
Simple tests for response format.
|
||||
|
||||
Scenario Outline: Address lookup for existing object
|
||||
When sending v1/lookup with format <format>
|
||||
| osm_ids |
|
||||
| N5484325405,W43327921,,R123924,X99,N0 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And exactly 3 results are returned
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| xml | xml |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
| geocodejson | geocodejson |
|
||||
|
||||
Scenario: Address lookup for non-existing or invalid object
|
||||
When sending v1/lookup
|
||||
| osm_ids |
|
||||
| X99,,N0,nN158845944,ABC,,W9 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And exactly 0 results are returned
|
||||
|
||||
Scenario Outline: Boundingbox is returned
|
||||
When sending v1/lookup with format <format>
|
||||
| osm_ids |
|
||||
| N5484325405,W43327921 |
|
||||
Then the result is valid <outformat>
|
||||
And the result set contains exactly
|
||||
| object | boundingbox!in_box |
|
||||
| N5484325405 | 47.135,47.14,9.52,9.525 |
|
||||
| W43327921 | 47.07,47.08,9.50,9.52 |
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| xml | xml |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
|
||||
Scenario: Linked places return information from the linkee
|
||||
When sending v1/lookup with format geocodejson
|
||||
| osm_ids |
|
||||
| N1932181216 |
|
||||
Then the result is valid geocodejson
|
||||
And exactly 1 result is returned
|
||||
And all results contain
|
||||
| name |
|
||||
| Vaduz |
|
||||
|
||||
Scenario Outline: Force error by providing too many ids
|
||||
When sending v1/lookup with format <format>
|
||||
| osm_ids |
|
||||
| N1,N2,N3,N4,N5,N6,N7,N8,N9,N10,N11,N12,N13,N14,N15,N16,N17,N18,N19,N20,N21,N22,N23,N24,N25,N26,N27,N28,N29,N30,N31,N32,N33,N34,N35,N36,N37,N38,N39,N40,N41,N42,N43,N44,N45,N46,N47,N48,N49,N50,N51 |
|
||||
Then a HTTP 400 is returned
|
||||
And the result is valid <outformat>
|
||||
And the result contains
|
||||
| error+code | error+message |
|
||||
| 400 | Too many object IDs. |
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| xml | xml |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | json |
|
||||
| geocodejson | json |
|
||||
56
test/bdd/features/api/reverse/geometry.feature
Normal file
56
test/bdd/features/api/reverse/geometry.feature
Normal file
@@ -0,0 +1,56 @@
|
||||
Feature: Geometries for reverse geocoding
|
||||
Tests for returning geometries with reverse
|
||||
|
||||
Scenario: Reverse - polygons are returned fully by default
|
||||
When sending v1/reverse
|
||||
| lat | lon | polygon_text |
|
||||
| 47.13803 | 9.52264 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| geotext!fm |
|
||||
| POLYGON\(\(9.5225302 47.138066, ?9.5225348 47.1379282, ?9.5226142 47.1379294, ?9.5226143 47.1379257, ?9.522615 47.137917, ?9.5226225 47.1379098, ?9.5226334 47.1379052, ?9.5226461 47.1379037, ?9.5226588 47.1379056, ?9.5226693 47.1379107, ?9.5226762 47.1379181, ?9.5226762 47.1379268, ?9.5226761 47.1379308, ?9.5227366 47.1379317, ?9.5227352 47.1379753, ?9.5227608 47.1379757, ?9.5227595 47.1380148, ?9.5227355 47.1380145, ?9.5227337 47.1380692, ?9.5225302 47.138066\)\) |
|
||||
|
||||
|
||||
Scenario: Reverse - polygons can be slightly simplified
|
||||
When sending v1/reverse
|
||||
| lat | lon | polygon_text | polygon_threshold |
|
||||
| 47.13803 | 9.52264 | 1 | 0.00001 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| geotext!fm |
|
||||
| POLYGON\(\(9.5225302 47.138066, ?9.5225348 47.1379282, ?9.5226142 47.1379294, ?9.5226225 47.1379098, ?9.5226588 47.1379056, ?9.5226761 47.1379308, ?9.5227366 47.1379317, ?9.5227352 47.1379753, ?9.5227608 47.1379757, ?9.5227595 47.1380148, ?9.5227355 47.1380145, ?9.5227337 47.1380692, ?9.5225302 47.138066\)\) |
|
||||
|
||||
|
||||
Scenario: Reverse - polygons can be much simplified
|
||||
When sending v1/reverse
|
||||
| lat | lon | polygon_text | polygon_threshold |
|
||||
| 47.13803 | 9.52264 | 1 | 0.9 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| geotext!fm |
|
||||
| POLYGON\(\([0-9. ]+, ?[0-9. ]+, ?[0-9. ]+, ?[0-9. ]+(, ?[0-9. ]+)?\)\) |
|
||||
|
||||
|
||||
Scenario: Reverse - for polygons return the centroid as center point
|
||||
When sending v1/reverse
|
||||
| lat | lon |
|
||||
| 47.13836 | 9.52304 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| lon | lat |
|
||||
| 9.5227108 | 47.1381805 |
|
||||
|
||||
|
||||
Scenario: Reverse - for streets return the closest point as center point
|
||||
When sending v1/reverse
|
||||
| lat | lon |
|
||||
| 47.13368 | 9.52942 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| lon | lat |
|
||||
| 9.5294315 | 47.1336817 |
|
||||
47
test/bdd/features/api/reverse/language.feature
Normal file
47
test/bdd/features/api/reverse/language.feature
Normal file
@@ -0,0 +1,47 @@
|
||||
Feature: Localization of reverse search results
|
||||
|
||||
Scenario: Reverse - default language
|
||||
When sending v1/reverse with format jsonv2
|
||||
| lat | lon |
|
||||
| 47.14 | 9.55 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| address+country |
|
||||
| Liechtenstein |
|
||||
|
||||
Scenario: Reverse - accept-language parameter
|
||||
When sending v1/reverse with format jsonv2
|
||||
| lat | lon | accept-language |
|
||||
| 47.14 | 9.55 | ja,en |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| address+country |
|
||||
| リヒテンシュタイン |
|
||||
|
||||
Scenario: Reverse - HTTP accept language header
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-ca,fo;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending v1/reverse with format jsonv2
|
||||
| lat | lon |
|
||||
| 47.14 | 9.55 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| address+country |
|
||||
| Liktinstein |
|
||||
|
||||
Scenario: Reverse - accept-language parameter and HTTP header
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-ca,fo;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending v1/reverse with format jsonv2
|
||||
| lat | lon | accept-language |
|
||||
| 47.14 | 9.55 | en |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| address+country |
|
||||
| Liechtenstein |
|
||||
@@ -1,24 +1,20 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Layer parameter in reverse geocoding
|
||||
Testing correct function of layer selection while reverse geocoding
|
||||
|
||||
Scenario: POIs are selected by default
|
||||
When sending v1/reverse at 47.14077,9.52414
|
||||
Then results contain
|
||||
When reverse geocoding 47.14077,9.52414
|
||||
Then the result contains
|
||||
| category | type |
|
||||
| tourism | viewpoint |
|
||||
|
||||
|
||||
Scenario Outline: Same address level POI with different layers
|
||||
When sending v1/reverse at 47.14077,9.52414
|
||||
When reverse geocoding 47.14077,9.52414
|
||||
| layer |
|
||||
| <layer> |
|
||||
Then results contain
|
||||
Then the result contains
|
||||
| category |
|
||||
| <category> |
|
||||
|
||||
|
||||
Examples:
|
||||
| layer | category |
|
||||
| address | highway |
|
||||
@@ -28,12 +24,11 @@ Feature: Layer parameter in reverse geocoding
|
||||
| address,natural | highway |
|
||||
| natural,poi | tourism |
|
||||
|
||||
|
||||
Scenario Outline: POIs are not selected without housenumber for address layer
|
||||
When sending v1/reverse at 47.13816,9.52168
|
||||
When reverse geocoding 47.13816,9.52168
|
||||
| layer |
|
||||
| <layer> |
|
||||
Then results contain
|
||||
Then the result contains
|
||||
| category | type |
|
||||
| <category> | <type> |
|
||||
|
||||
@@ -42,21 +37,19 @@ Feature: Layer parameter in reverse geocoding
|
||||
| address,poi | highway | bus_stop |
|
||||
| address | amenity | parking |
|
||||
|
||||
|
||||
Scenario: Between natural and low-zoom address prefer natural
|
||||
When sending v1/reverse at 47.13636,9.52094
|
||||
When reverse geocoding 47.13636,9.52094
|
||||
| layer | zoom |
|
||||
| natural,address | 15 |
|
||||
Then results contain
|
||||
Then the result contains
|
||||
| category |
|
||||
| waterway |
|
||||
|
||||
|
||||
Scenario Outline: Search for mountain peaks begins at level 12
|
||||
When sending v1/reverse at 47.08293,9.57109
|
||||
When reverse geocoding 47.08293,9.57109
|
||||
| layer | zoom |
|
||||
| natural | <zoom> |
|
||||
Then results contain
|
||||
Then the result contains
|
||||
| category | type |
|
||||
| <category> | <type> |
|
||||
|
||||
@@ -65,12 +58,11 @@ Feature: Layer parameter in reverse geocoding
|
||||
| 12 | natural | peak |
|
||||
| 13 | waterway | river |
|
||||
|
||||
|
||||
Scenario Outline: Reverse search with manmade layers
|
||||
When sending v1/reverse at 32.46904,-86.44439
|
||||
When reverse geocoding 32.46904,-86.44439
|
||||
| layer |
|
||||
| <layer> |
|
||||
Then results contain
|
||||
Then the result contains
|
||||
| category | type |
|
||||
| <category> | <type> |
|
||||
|
||||
80
test/bdd/features/api/reverse/queries.feature
Normal file
80
test/bdd/features/api/reverse/queries.feature
Normal file
@@ -0,0 +1,80 @@
|
||||
Feature: Reverse geocoding
|
||||
Testing the reverse function
|
||||
|
||||
Scenario: Reverse - Unknown countries fall back to default country grid
|
||||
When reverse geocoding 45.174,-103.072
|
||||
Then the result contains
|
||||
| category | type | display_name |
|
||||
| place | country | United States |
|
||||
|
||||
Scenario: Reverse - No TIGER house number for zoom < 18
|
||||
When reverse geocoding 32.4752389363,-86.4810198619
|
||||
| zoom |
|
||||
| 17 |
|
||||
Then the result contains
|
||||
| osm_type | category |
|
||||
| way | highway |
|
||||
And the result contains in field address
|
||||
| road | postcode | country_code |
|
||||
| Upper Kingston Road | 36067 | us |
|
||||
|
||||
Scenario: Reverse - Address with non-numerical house number
|
||||
When reverse geocoding 47.107465,9.52838521614
|
||||
Then the result contains in field address
|
||||
| house_number | road |
|
||||
| 39A/B | Dorfstrasse |
|
||||
|
||||
Scenario: Reverse - Address with numerical house number
|
||||
When reverse geocoding 47.168440329479594,9.511551699184338
|
||||
Then the result contains in field address
|
||||
| house_number | road |
|
||||
| 6 | Schmedgässle |
|
||||
|
||||
Scenario Outline: Reverse - Zoom levels below 5 result in country
|
||||
When reverse geocoding 47.16,9.51
|
||||
| zoom |
|
||||
| <zoom> |
|
||||
Then the result contains
|
||||
| display_name |
|
||||
| Liechtenstein |
|
||||
|
||||
Examples:
|
||||
| zoom |
|
||||
| 0 |
|
||||
| 1 |
|
||||
| 2 |
|
||||
| 3 |
|
||||
| 4 |
|
||||
|
||||
Scenario: Reverse - When on a street, the closest interpolation is shown
|
||||
When reverse geocoding 47.118457166193245,9.570678289621355
|
||||
| zoom |
|
||||
| 18 |
|
||||
Then the result contains
|
||||
| display_name |
|
||||
| 1021, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
# github 2214
|
||||
Scenario: Reverse - Interpolations do not override house numbers when they are closer
|
||||
When reverse geocoding 47.11778,9.57255
|
||||
| zoom |
|
||||
| 18 |
|
||||
Then the result contains
|
||||
| display_name |
|
||||
| 5, Grosssteg, Steg, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Scenario: Reverse - Interpolations do not override house numbers when they are closer (2)
|
||||
When reverse geocoding 47.11834,9.57167
|
||||
| zoom |
|
||||
| 18 |
|
||||
Then the result contains
|
||||
| display_name |
|
||||
| 3, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Scenario: Reverse - When on a street with zoom 18, the closest housenumber is returned
|
||||
When reverse geocoding 47.11755503977281,9.572722250405036
|
||||
| zoom |
|
||||
| 18 |
|
||||
Then the result contains in field address
|
||||
| house_number |
|
||||
| 7 |
|
||||
143
test/bdd/features/api/reverse/v1_geocodejson.feature
Normal file
143
test/bdd/features/api/reverse/v1_geocodejson.feature
Normal file
@@ -0,0 +1,143 @@
|
||||
Feature: Geocodejson for Reverse API
|
||||
Testing correctness of geocodejson output (API version v1).
|
||||
|
||||
Scenario Outline: Reverse geocodejson - Simple with no results
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon |
|
||||
| <lat> | <lon> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| error |
|
||||
| Unable to geocode |
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 0.0 | 0.0 |
|
||||
| 91.3 | 0.4 |
|
||||
| -700 | 0.4 |
|
||||
| 0.2 | 324.44 |
|
||||
| 0.2 | -180.4 |
|
||||
|
||||
Scenario Outline: Reverse geocodejson - Simple OSM result
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon | addressdetails |
|
||||
| 47.066 | 9.504 | <has_address> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And the result metadata contains
|
||||
| version | licence | attribution!fm |
|
||||
| 0.1.0 | ODbL | Data © OpenStreetMap contributors, ODbL 1.0. https?://osm.org/copyright |
|
||||
And all results have <attributes> country,postcode,county,city,district,street,housenumber,admin
|
||||
And all results contain
|
||||
| param | value |
|
||||
| osm_type | node |
|
||||
| osm_id | 6522627624 |
|
||||
| osm_key | shop |
|
||||
| osm_value | bakery |
|
||||
| type | house |
|
||||
| name | Dorfbäckerei Herrmann |
|
||||
| label | Dorfbäckerei Herrmann, 29, Gnetsch, Mäls, Balzers, Oberland, 9496, Liechtenstein |
|
||||
| geojson+type | Point |
|
||||
| geojson+coordinates | [9.5036065, 47.0660892] |
|
||||
|
||||
Examples:
|
||||
| has_address | attributes |
|
||||
| 1 | attributes |
|
||||
| 0 | no attributes |
|
||||
|
||||
Scenario: Reverse geocodejson - City housenumber-level address with street
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon |
|
||||
| 47.1068011 | 9.52810091 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And all results contain
|
||||
| housenumber | street | postcode | city | country |
|
||||
| 8 | Im Winkel | 9495 | Triesen | Liechtenstein |
|
||||
And all results contain
|
||||
| admin+level6 | admin+level8 |
|
||||
| Oberland | Triesen |
|
||||
|
||||
Scenario: Reverse geocodejson - Town street-level address with street
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon | zoom |
|
||||
| 47.066 | 9.504 | 16 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And all results contain
|
||||
| name | city | postcode | country |
|
||||
| Gnetsch | Balzers | 9496 | Liechtenstein |
|
||||
|
||||
Scenario: Reverse geocodejson - Poi street-level address with footway
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon |
|
||||
| 47.06515 | 9.50083 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And all results contain
|
||||
| street | city | postcode | country |
|
||||
| Burgweg | Balzers | 9496 | Liechtenstein |
|
||||
|
||||
Scenario: Reverse geocodejson - City address with suburb
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon |
|
||||
| 47.146861 | 9.511771 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And all results contain
|
||||
| housenumber | street | district | city | postcode | country |
|
||||
| 5 | Lochgass | Ebenholz | Vaduz | 9490 | Liechtenstein |
|
||||
|
||||
Scenario: Reverse geocodejson - Tiger address
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon |
|
||||
| 32.4752389363 | -86.4810198619 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And all results contain
|
||||
| osm_type | osm_id | osm_key | osm_value | type |
|
||||
| way | 396009653 | place | house | house |
|
||||
And all results contain
|
||||
| housenumber | street | city | county | postcode | country |
|
||||
| 707 | Upper Kingston Road | Prattville | Autauga County | 36067 | United States |
|
||||
|
||||
Scenario: Reverse geocodejson - Interpolation address
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon |
|
||||
| 47.118533 | 9.57056562 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And all results contain
|
||||
| osm_type | osm_id | osm_key | osm_value | type |
|
||||
| way | 1 | place | house | house |
|
||||
And all results contain
|
||||
| label |
|
||||
| 1019, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
And all results have no attributes name
|
||||
|
||||
Scenario: Reverse geocodejson - Line geometry output is supported
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon | polygon_geojson |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And all results contain
|
||||
| geojson+type |
|
||||
| LineString |
|
||||
|
||||
Scenario Outline: Reverse geocodejson - Only geojson polygons are supported
|
||||
When sending v1/reverse with format geocodejson
|
||||
| lat | lon | <param> |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson with 1 result
|
||||
And all results contain
|
||||
| geojson+type |
|
||||
| Point |
|
||||
|
||||
Examples:
|
||||
| param |
|
||||
| polygon_text |
|
||||
| polygon_svg |
|
||||
| polygon_kml |
|
||||
102
test/bdd/features/api/reverse/v1_geojson.feature
Normal file
102
test/bdd/features/api/reverse/v1_geojson.feature
Normal file
@@ -0,0 +1,102 @@
|
||||
Feature: Geojson for Reverse API
|
||||
Testing correctness of geojson output (API version v1).
|
||||
|
||||
Scenario Outline: Reverse geojson - Simple with no results
|
||||
When sending v1/reverse with format geojson
|
||||
| lat | lon |
|
||||
| <lat> | <lon> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| error |
|
||||
| Unable to geocode |
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 0.0 | 0.0 |
|
||||
| 91.3 | 0.4 |
|
||||
| -700 | 0.4 |
|
||||
| 0.2 | 324.44 |
|
||||
| 0.2 | -180.4 |
|
||||
|
||||
Scenario Outline: Reverse geojson - Simple OSM result
|
||||
When sending v1/reverse with format geojson
|
||||
| lat | lon | addressdetails |
|
||||
| 47.066 | 9.504 | <has_address> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geojson with 1 result
|
||||
And the result metadata contains
|
||||
| licence!fm |
|
||||
| Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright |
|
||||
And all results have attributes place_id, importance
|
||||
And all results have <attributes> address
|
||||
And all results contain
|
||||
| param | value |
|
||||
| osm_type | node |
|
||||
| osm_id | 6522627624 |
|
||||
| place_rank | 30 |
|
||||
| category | shop |
|
||||
| type | bakery |
|
||||
| addresstype | shop |
|
||||
| name | Dorfbäckerei Herrmann |
|
||||
| display_name | Dorfbäckerei Herrmann, 29, Gnetsch, Mäls, Balzers, Oberland, 9496, Liechtenstein |
|
||||
| boundingbox | [47.0660392, 47.0661392, 9.5035565, 9.5036565] |
|
||||
| geojson+type | Point |
|
||||
| geojson+coordinates | [9.5036065, 47.0660892] |
|
||||
|
||||
Examples:
|
||||
| has_address | attributes |
|
||||
| 1 | attributes |
|
||||
| 0 | no attributes |
|
||||
|
||||
Scenario: Reverse geojson - Tiger address
|
||||
When sending v1/reverse with format geojson
|
||||
| lat | lon |
|
||||
| 32.4752389363 | -86.4810198619 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geojson with 1 result
|
||||
And all results contain
|
||||
| osm_type | osm_id | category | type | addresstype | place_rank |
|
||||
| way | 396009653 | place | house | place | 30 |
|
||||
|
||||
Scenario: Reverse geojson - Interpolation address
|
||||
When sending v1/reverse with format geojson
|
||||
| lat | lon |
|
||||
| 47.118533 | 9.57056562 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geojson with 1 result
|
||||
And all results contain
|
||||
| osm_type | osm_id | place_rank | category | type | addresstype |
|
||||
| way | 1 | 30 | place | house | place |
|
||||
And all results contain
|
||||
| boundingbox!in_box |
|
||||
| 47.118494, 47.118596, 9.570495, 9.570597 |
|
||||
And all results contain
|
||||
| display_name |
|
||||
| 1019, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Scenario: Reverse geojson - Line geometry output is supported
|
||||
When sending v1/reverse with format geojson
|
||||
| lat | lon | polygon_geojson |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geojson with 1 result
|
||||
And all results contain
|
||||
| geojson+type |
|
||||
| LineString |
|
||||
|
||||
Scenario Outline: Reverse geojson - Only geojson polygons are supported
|
||||
When sending v1/reverse with format geojson
|
||||
| lat | lon | <param> |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geojson with 1 result
|
||||
And all results contain
|
||||
| geojson+type |
|
||||
| Point |
|
||||
|
||||
Examples:
|
||||
| param |
|
||||
| polygon_text |
|
||||
| polygon_svg |
|
||||
| polygon_kml |
|
||||
175
test/bdd/features/api/reverse/v1_json.feature
Normal file
175
test/bdd/features/api/reverse/v1_json.feature
Normal file
@@ -0,0 +1,175 @@
|
||||
Feature: Json output for Reverse API
|
||||
Testing correctness of json and jsonv2 output (API version v1).
|
||||
|
||||
Scenario Outline: Reverse json - Simple with no results
|
||||
When sending v1/reverse with format json
|
||||
| lat | lon |
|
||||
| <lat> | <lon> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| error |
|
||||
| Unable to geocode |
|
||||
When sending v1/reverse with format jsonv2
|
||||
| lat | lon |
|
||||
| <lat> | <lon> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| error |
|
||||
| Unable to geocode |
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 0.0 | 0.0 |
|
||||
| 91.3 | 0.4 |
|
||||
| -700 | 0.4 |
|
||||
| 0.2 | 324.44 |
|
||||
| 0.2 | -180.4 |
|
||||
|
||||
Scenario Outline: Reverse json - OSM result with and without addresses
|
||||
When sending v1/reverse with format json
|
||||
| lat | lon | addressdetails |
|
||||
| 47.066 | 9.504 | <has_address> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has <attributes> address
|
||||
When sending v1/reverse with format jsonv2
|
||||
| lat | lon | addressdetails |
|
||||
| 47.066 | 9.504 | <has_address> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has <attributes> address
|
||||
|
||||
Examples:
|
||||
| has_address | attributes |
|
||||
| 1 | attributes |
|
||||
| 0 | no attributes |
|
||||
|
||||
Scenario Outline: Reverse json - Simple OSM result
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon |
|
||||
| 47.066 | 9.504 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes place_id
|
||||
And the result contains
|
||||
| licence!fm |
|
||||
| Data © OpenStreetMap contributors, ODbL 1.0. https?://osm.org/copyright |
|
||||
And the result contains
|
||||
| osm_type | osm_id |
|
||||
| node | 6522627624 |
|
||||
And the result contains
|
||||
| lon | lat | boundingbox!in_box |
|
||||
| 9.5036065 | 47.0660892 | 47.0660391, 47.0661393, 9.5035564, 9.5036566 |
|
||||
And the result contains
|
||||
| display_name |
|
||||
| Dorfbäckerei Herrmann, 29, Gnetsch, Mäls, Balzers, Oberland, 9496, Liechtenstein |
|
||||
And the result has no attributes namedetails,extratags
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
Scenario: Reverse json - Extra attributes of jsonv2 result
|
||||
When sending v1/reverse with format jsonv2
|
||||
| lat | lon |
|
||||
| 47.066 | 9.504 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result has attributes importance
|
||||
And the result contains
|
||||
| category | type | name | place_rank | addresstype |
|
||||
| shop | bakery | Dorfbäckerei Herrmann | 30 | shop |
|
||||
|
||||
Scenario: Reverse json - Tiger address
|
||||
When sending v1/reverse with format jsonv2
|
||||
| lat | lon |
|
||||
| 32.4752389363 | -86.4810198619 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| osm_type | osm_id | category | type | addresstype |
|
||||
| way | 396009653 | place | house | place |
|
||||
|
||||
Scenario Outline: Reverse json - Interpolation address
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon |
|
||||
| 47.118533 | 9.57056562 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| osm_type | osm_id |
|
||||
| way | 1 |
|
||||
And the result contains
|
||||
| lon | lat | boundingbox!in_box |
|
||||
| 9.5705468 | 47.1185454 | 47.118494, 47.118596, 9.570495, 9.570597 |
|
||||
And the result contains
|
||||
| display_name |
|
||||
| 1019, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
Scenario Outline: Reverse json - Output of geojson
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon | polygon_geojson |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| geojson+type | geojson+coordinates |
|
||||
| LineString | [[9.5039353, 47.0657546], [9.5040437, 47.0657781], [9.5040808, 47.065787], [9.5054298, 47.0661407]] |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
Scenario Outline: Reverse json - Output of WKT
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon | polygon_text |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| geotext!wkt |
|
||||
| 9.5039353 47.0657546, 9.5040437 47.0657781, 9.5040808 47.065787, 9.5054298 47.0661407 |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
Scenario Outline: Reverse json - Output of SVG
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon | polygon_svg |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| svg |
|
||||
| M 9.5039353 -47.0657546 L 9.5040437 -47.0657781 9.5040808 -47.065787 9.5054298 -47.0661407 |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
|
||||
Scenario Outline: Reverse json - Output of KML
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon | polygon_kml |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| geokml!fm |
|
||||
| <LineString><coordinates>9.5039\d*,47.0657\d* 9.5040\d*,47.0657\d* 9.5040\d*,47.065\d* 9.5054\d*,47.0661\d*</coordinates></LineString> |
|
||||
|
||||
Examples:
|
||||
| format |
|
||||
| json |
|
||||
| jsonv2 |
|
||||
169
test/bdd/features/api/reverse/v1_params.feature
Normal file
169
test/bdd/features/api/reverse/v1_params.feature
Normal file
@@ -0,0 +1,169 @@
|
||||
Feature: v1/reverse Parameter Tests
|
||||
Tests for parameter inputs for the v1 reverse endpoint.
|
||||
This file contains mostly bad parameter input. Valid parameters
|
||||
are tested in the format tests.
|
||||
|
||||
Scenario: Bad format
|
||||
When sending v1/reverse
|
||||
| lat | lon | format |
|
||||
| 47.14122383 | 9.52169581334 | sdf |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario: Missing lon parameter
|
||||
When sending v1/reverse
|
||||
| lat |
|
||||
| 52.52 |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario: Missing lat parameter
|
||||
When sending v1/reverse
|
||||
| lon |
|
||||
| 52.52 |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario Outline: Bad format for lat or lon
|
||||
When sending v1/reverse
|
||||
| lat | lon |
|
||||
| <lat> | <lon> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 48.9660 | 8,4482 |
|
||||
| 48,9660 | 8.4482 |
|
||||
| 48,9660 | 8,4482 |
|
||||
| 48.966.0 | 8.4482 |
|
||||
| 48.966 | 8.448.2 |
|
||||
| Nan | 8.448 |
|
||||
| 48.966 | Nan |
|
||||
| Inf | 5.6 |
|
||||
| 5.6 | -Inf |
|
||||
| <script></script> | 3.4 |
|
||||
| 3.4 | <script></script> |
|
||||
| -45.3 | ; |
|
||||
| gkjd | 50 |
|
||||
|
||||
Scenario: Non-numerical zoom levels return an error
|
||||
When sending v1/reverse
|
||||
| lat | lon | zoom |
|
||||
| 47.14122383 | 9.52169581334 | adfe |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario Outline: Truthy values for boolean parameters
|
||||
When sending v1/reverse
|
||||
| lat | lon | addressdetails |
|
||||
| 47.14122383 | 9.52169581334 | <value> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result has attributes address
|
||||
|
||||
When sending v1/reverse
|
||||
| lat | lon | extratags |
|
||||
| 47.14122383 | 9.52169581334 | <value> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result has attributes extratags
|
||||
|
||||
When sending v1/reverse
|
||||
| lat | lon | namedetails |
|
||||
| 47.14122383 | 9.52169581334 | <value> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result has attributes namedetails
|
||||
|
||||
Examples:
|
||||
| value |
|
||||
| yes |
|
||||
| no |
|
||||
| -1 |
|
||||
| 100 |
|
||||
| false |
|
||||
| 00 |
|
||||
|
||||
Scenario: Only one geometry can be requested
|
||||
When sending v1/reverse
|
||||
| lat | lon | polygon_text | polygon_svg |
|
||||
| 47.14122383 | 9.52169581334 | 1 | 1 |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario Outline: Illegal jsonp are not allowed
|
||||
When sending v1/reverse with format json
|
||||
| lat | lon | json_callback |
|
||||
| 47.14122383 | 9.52169581334 | <data> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| data |
|
||||
| 1asd |
|
||||
| bar(foo) |
|
||||
| XXX['bad'] |
|
||||
| foo; evil |
|
||||
|
||||
Scenario Outline: Reverse debug mode produces valid HTML
|
||||
When sending v1/reverse
|
||||
| lat | lon | debug |
|
||||
| <lat> | <lon> | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid html
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 0.0 | 0.0 |
|
||||
| 47.06645 | 9.56601 |
|
||||
| 47.14081 | 9.52267 |
|
||||
|
||||
Scenario Outline: Full address display for city housenumber-level address with street
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon |
|
||||
| 47.1068011 | 9.52810091 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And the result contains in field address
|
||||
| param | value |
|
||||
| house_number | 8 |
|
||||
| road | Im Winkel |
|
||||
| neighbourhood | Oberdorf |
|
||||
| village | Triesen |
|
||||
| ISO3166-2-lvl8 | LI-09 |
|
||||
| county | Oberland |
|
||||
| postcode | 9495 |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| xml | xml |
|
||||
|
||||
Scenario Outline: Results with name details
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon | zoom | namedetails |
|
||||
| 47.14052 | 9.52202 | 14 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And the result contains in field namedetails
|
||||
| name |
|
||||
| Ebenholz |
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| xml | xml |
|
||||
|
||||
Scenario Outline: Results with extratags
|
||||
When sending v1/reverse with format <format>
|
||||
| lat | lon | zoom | extratags |
|
||||
| 47.14052 | 9.52202 | 14 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And the result contains in field extratags
|
||||
| wikidata |
|
||||
| Q4529531 |
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| xml | xml |
|
||||
116
test/bdd/features/api/reverse/v1_xml.feature
Normal file
116
test/bdd/features/api/reverse/v1_xml.feature
Normal file
@@ -0,0 +1,116 @@
|
||||
Feature: XML output for Reverse API
|
||||
Testing correctness of xml output (API version v1).
|
||||
|
||||
Scenario Outline: Reverse XML - Simple reverse-geocoding with no results
|
||||
When sending v1/reverse
|
||||
| lat | lon |
|
||||
| <lat> | <lon> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result has no attributes osm_type, address, extratags
|
||||
And the result contains
|
||||
| error |
|
||||
| Unable to geocode |
|
||||
|
||||
Examples:
|
||||
| lat | lon |
|
||||
| 0.0 | 0.0 |
|
||||
| 91.3 | 0.4 |
|
||||
| -700 | 0.4 |
|
||||
| 0.2 | 324.44 |
|
||||
| 0.2 | -180.4 |
|
||||
|
||||
Scenario Outline: Reverse XML - OSM result with and without addresses
|
||||
When sending v1/reverse with format xml
|
||||
| lat | lon | addressdetails |
|
||||
| 47.066 | 9.504 | <has_address> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result has attributes place_id
|
||||
And the result has <attributes> address
|
||||
And the result contains
|
||||
| osm_type | osm_id | place_rank | address_rank |
|
||||
| node | 6522627624 | 30 | 30 |
|
||||
And the result contains
|
||||
| lon | lat | boundingbox |
|
||||
| 9.5036065 | 47.0660892 | 47.0660392,47.0661392,9.5035565,9.5036565 |
|
||||
And the result contains
|
||||
| ref | display_name |
|
||||
| Dorfbäckerei Herrmann | Dorfbäckerei Herrmann, 29, Gnetsch, Mäls, Balzers, Oberland, 9496, Liechtenstein |
|
||||
|
||||
Examples:
|
||||
| has_address | attributes |
|
||||
| 1 | attributes |
|
||||
| 0 | no attributes |
|
||||
|
||||
Scenario: Reverse XML - Tiger address
|
||||
When sending v1/reverse with format xml
|
||||
| lat | lon |
|
||||
| 32.4752389363 | -86.4810198619 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| osm_type | osm_id | place_rank | address_rank |
|
||||
| way | 396009653 | 30 | 30 |
|
||||
And the result contains
|
||||
| lon | lat | boundingbox |
|
||||
| -86.4808553 | 32.4753580 | 32.4753080,32.4754080,-86.4809053,-86.4808053 |
|
||||
And the result contains
|
||||
| display_name |
|
||||
| 707, Upper Kingston Road, Upper Kingston, Prattville, Autauga County, 36067, United States |
|
||||
|
||||
Scenario: Reverse XML - Interpolation address
|
||||
When sending v1/reverse with format xml
|
||||
| lat | lon |
|
||||
| 47.118533 | 9.57056562 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| osm_type | osm_id | place_rank | address_rank |
|
||||
| way | 1 | 30 | 30 |
|
||||
And the result contains
|
||||
| lon | lat | boundingbox |
|
||||
| 9.5705468 | 47.1185454 | 47.1184954,47.1185954,9.5704968,9.5705968 |
|
||||
And the result contains
|
||||
| display_name |
|
||||
| 1019, Grosssteg, Sücka, Triesenberg, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Scenario: Reverse XML - Output of geojson
|
||||
When sending v1/reverse with format xml
|
||||
| lat | lon | polygon_geojson |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| geojson |
|
||||
| {"type":"LineString","coordinates":[[9.5039353,47.0657546],[9.5040437,47.0657781],[9.5040808,47.065787],[9.5054298,47.0661407]]} |
|
||||
|
||||
Scenario: Reverse XML - Output of WKT
|
||||
When sending v1/reverse with format xml
|
||||
| lat | lon | polygon_text |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| geotext!wkt |
|
||||
| 9.5039353 47.0657546, 9.5040437 47.0657781, 9.5040808 47.065787, 9.5054298 47.0661407 |
|
||||
|
||||
Scenario: Reverse XML - Output of SVG
|
||||
When sending v1/reverse with format xml
|
||||
| lat | lon | polygon_svg |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| geosvg |
|
||||
| M 9.5039353 -47.0657546 L 9.5040437 -47.0657781 9.5040808 -47.065787 9.5054298 -47.0661407 |
|
||||
|
||||
Scenario: Reverse XML - Output of KML
|
||||
When sending v1/reverse with format xml
|
||||
| lat | lon | polygon_kml |
|
||||
| 47.06597 | 9.50467 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result contains
|
||||
| geokml!fm |
|
||||
| <geokml><LineString><coordinates>9.5039\d*,47.0657\d* 9.5040\d*,47.0657\d* 9.5040\d*,47.065\d* 9.5054\d*,47.0661\d*</coordinates></LineString></geokml> |
|
||||
83
test/bdd/features/api/search/language.feature
Normal file
83
test/bdd/features/api/search/language.feature
Normal file
@@ -0,0 +1,83 @@
|
||||
Feature: Localization of search results
|
||||
|
||||
Scenario: Search - default language
|
||||
When sending v1/search
|
||||
| q |
|
||||
| Liechtenstein |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And result 0 contains
|
||||
| display_name |
|
||||
| Liechtenstein |
|
||||
|
||||
Scenario: Search - accept-language first
|
||||
When sending v1/search
|
||||
| q | accept-language |
|
||||
| Liechtenstein | zh,de |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And result 0 contains
|
||||
| display_name |
|
||||
| 列支敦士登 |
|
||||
|
||||
Scenario: Search - accept-language missing
|
||||
When sending v1/search
|
||||
| q | accept-language |
|
||||
| Liechtenstein | xx,fr,en,de |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And result 0 contains
|
||||
| display_name |
|
||||
| Liechtenstein |
|
||||
|
||||
Scenario: Search - http accept language header first
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending v1/search
|
||||
| q |
|
||||
| Liechtenstein |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And result 0 contains
|
||||
| display_name |
|
||||
| Liktinstein |
|
||||
|
||||
Scenario: Search - http accept language header and accept-language
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3 |
|
||||
When sending v1/search
|
||||
| q | accept-language |
|
||||
| Liechtenstein | fo,en |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And result 0 contains
|
||||
| display_name |
|
||||
| Liktinstein |
|
||||
|
||||
Scenario: Search - http accept language header fallback
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-ca,en-ca;q=0.5 |
|
||||
When sending v1/search
|
||||
| q |
|
||||
| Liechtenstein |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And result 0 contains
|
||||
| display_name |
|
||||
| Liktinstein |
|
||||
|
||||
Scenario: Search - http accept language header fallback (upper case)
|
||||
Given the HTTP header
|
||||
| accept-language |
|
||||
| fo-FR;q=0.8,en-ca;q=0.5 |
|
||||
When sending v1/search
|
||||
| q |
|
||||
| Liechtenstein |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And result 0 contains
|
||||
| display_name |
|
||||
| Liktinstein |
|
||||
361
test/bdd/features/api/search/params.feature
Normal file
361
test/bdd/features/api/search/params.feature
Normal file
@@ -0,0 +1,361 @@
|
||||
Feature: Search queries
|
||||
Testing different queries and parameters
|
||||
|
||||
Scenario: Simple XML search
|
||||
When sending v1/search with format xml
|
||||
| q |
|
||||
| Schaan |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And all results have attributes place_id,osm_type,osm_id
|
||||
And all results have attributes place_rank,boundingbox
|
||||
And all results have attributes lat,lon,display_name
|
||||
And all results have attributes class,type,importance
|
||||
And all results have no attributes address
|
||||
And all results contain
|
||||
| boundingbox!in_box |
|
||||
| 46.5,47.5,9,10 |
|
||||
|
||||
Scenario Outline: Simple JSON search
|
||||
When sending v1/search with format <format>
|
||||
| q |
|
||||
| Vaduz |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And all results have attributes place_id,licence,<cname>,type
|
||||
And all results have attributes osm_type,osm_id,boundingbox
|
||||
And all results have attributes lat,lon,display_name,importance
|
||||
And all results have no attributes address
|
||||
And all results contain
|
||||
| boundingbox!in_box |
|
||||
| 46.5,47.5,9,10 |
|
||||
|
||||
Examples:
|
||||
| format | cname |
|
||||
| json | class |
|
||||
| jsonv2 | category |
|
||||
|
||||
Scenario: Unknown formats returns a user error
|
||||
When sending v1/search with format x45
|
||||
| q |
|
||||
| Vaduz |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario Outline: Search with addressdetails
|
||||
When sending v1/search with format <format>
|
||||
| q | addressdetails |
|
||||
| Triesen | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And result 0 contains in field address
|
||||
| param | value |
|
||||
| village | Triesen |
|
||||
| county | Oberland |
|
||||
| postcode | 9495 |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
| ISO3166-2-lvl8 | LI-09 |
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
| xml | xml |
|
||||
|
||||
Scenario: Coordinate search with addressdetails
|
||||
When geocoding "47.12400621,9.6047552"
|
||||
| accept-language |
|
||||
| en |
|
||||
Then all results contain
|
||||
| display_name |
|
||||
| Guschg, Valorschstrasse, Balzers, Oberland, 9497, Liechtenstein |
|
||||
|
||||
Scenario: Address details with unknown class types
|
||||
When geocoding "Kloster St. Elisabeth"
|
||||
Then result 0 contains
|
||||
| category | type | address+amenity |
|
||||
| amenity | monastery | Kloster St. Elisabeth |
|
||||
|
||||
Scenario: Disabling deduplication
|
||||
When geocoding "Malbunstr, Schaan"
|
||||
Then exactly 1 result is returned
|
||||
When geocoding "Malbunstr, Schaan"
|
||||
| dedupe |
|
||||
| 0 |
|
||||
Then exactly 4 results are returned
|
||||
|
||||
Scenario: Search with bounded viewbox in right area
|
||||
When geocoding "post"
|
||||
| bounded | viewbox |
|
||||
| 1 | 9,47,10,48 |
|
||||
Then result 0 contains
|
||||
| address+town |
|
||||
| Vaduz |
|
||||
When geocoding "post"
|
||||
| bounded | viewbox |
|
||||
| 1 | 9.49712,47.17122,9.52605,47.16242 |
|
||||
Then result 0 contains
|
||||
| address+town |
|
||||
| Schaan |
|
||||
|
||||
Scenario: Country search with bounded viewbox remain in the area
|
||||
When geocoding
|
||||
| bounded | viewbox | country |
|
||||
| 1 | 9.49712,47.17122,9.52605,47.16242 | de |
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Search with bounded viewboxlbrt in right area
|
||||
When geocoding "bar"
|
||||
| bounded | viewboxlbrt |
|
||||
| 1 | 9.49712,47.16242,9.52605,47.17122 |
|
||||
Then all results contain
|
||||
| address+town |
|
||||
| Schaan |
|
||||
|
||||
Scenario: No POI search with unbounded viewbox
|
||||
When geocoding "restaurant"
|
||||
| viewbox |
|
||||
| 9.93027,53.61634,10.10073,53.54500 |
|
||||
Then all results contain
|
||||
| display_name!fm |
|
||||
| .*[Rr]estaurant.* |
|
||||
|
||||
Scenario: bounded search remains within viewbox, even with no results
|
||||
When geocoding "[restaurant]"
|
||||
| bounded | viewbox |
|
||||
| 1 | 43.5403125,-5.6563282,43.54285,-5.662003 |
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: bounded search remains within viewbox with results
|
||||
When geocoding "restaurant"
|
||||
| bounded | viewbox |
|
||||
| 1 | 9.49712,47.17122,9.52605,47.16242 |
|
||||
Then all results contain
|
||||
| boundingbox!in_box |
|
||||
| 47.16242,47.17122,9.49712,9.52605 |
|
||||
|
||||
Scenario: Prefer results within viewbox
|
||||
When geocoding "Gässle"
|
||||
| accept-language | viewbox |
|
||||
| en | 9.52413,47.10759,9.53140,47.10539 |
|
||||
Then result 0 contains
|
||||
| address+village |
|
||||
| Triesen |
|
||||
When geocoding "Gässle"
|
||||
| accept-language | viewbox |
|
||||
| en | 9.45949,47.08421,9.54094,47.05466 |
|
||||
Then result 0 contains
|
||||
| address+town |
|
||||
| Balzers |
|
||||
|
||||
Scenario: viewboxes cannot be points
|
||||
When sending v1/search
|
||||
| q | viewbox |
|
||||
| foo | 1.01,34.6,1.01,34.6 |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario Outline: viewbox must have four coordinate numbers
|
||||
When sending v1/search
|
||||
| q | viewbox |
|
||||
| foo | <viewbox> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| viewbox |
|
||||
| 34 |
|
||||
| 0.003,-84.4 |
|
||||
| 5.2,4.5542,12.4 |
|
||||
| 23.1,-6,0.11,44.2,9.1 |
|
||||
|
||||
Scenario Outline: viewboxlbrt must have four coordinate numbers
|
||||
When sending v1/search
|
||||
| q | viewboxlbrt |
|
||||
| foo | <viewbox> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| viewbox |
|
||||
| 34 |
|
||||
| 0.003,-84.4 |
|
||||
| 5.2,4.5542,12.4 |
|
||||
| 23.1,-6,0.11,44.2,9.1 |
|
||||
|
||||
Scenario: Overly large limit number for search results
|
||||
When geocoding "restaurant"
|
||||
| limit |
|
||||
| 1000 |
|
||||
Then exactly 35 results are returned
|
||||
|
||||
Scenario: Limit number of non-duplicated search results
|
||||
When geocoding "landstr"
|
||||
| dedupe |
|
||||
| 0 |
|
||||
Then exactly 10 results are returned
|
||||
When geocoding "landstr"
|
||||
| limit | dedupe |
|
||||
| 4 | 0 |
|
||||
Then exactly 4 results are returned
|
||||
|
||||
Scenario: Limit parameter must be a number
|
||||
When sending v1/search
|
||||
| q | limit |
|
||||
| Blue Laguna | ); |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Scenario: Restrict to feature type country
|
||||
When geocoding "fürstentum"
|
||||
| featureType |
|
||||
| country |
|
||||
Then all results contain
|
||||
| place_rank |
|
||||
| 4 |
|
||||
|
||||
Scenario: Restrict to feature type state
|
||||
When geocoding "Wangerberg"
|
||||
Then more than 0 results are returned
|
||||
When geocoding "Wangerberg"
|
||||
| featureType |
|
||||
| state |
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Restrict to feature type city
|
||||
When geocoding "vaduz"
|
||||
| featureType |
|
||||
| state |
|
||||
Then exactly 0 results are returned
|
||||
When geocoding "vaduz"
|
||||
| featureType |
|
||||
| city |
|
||||
Then more than 0 results are returned
|
||||
Then all results contain
|
||||
| place_rank |
|
||||
| 16 |
|
||||
|
||||
Scenario: Restrict to feature type settlement
|
||||
When geocoding "Malbun"
|
||||
Then result 1 contains
|
||||
| category |
|
||||
| landuse |
|
||||
When geocoding "Malbun"
|
||||
| featureType |
|
||||
| settlement |
|
||||
Then all results contain
|
||||
| category | type |
|
||||
| place | village |
|
||||
|
||||
Scenario Outline: Search with polygon threshold (json)
|
||||
When sending v1/search with format json
|
||||
| q | polygon_geojson | polygon_threshold |
|
||||
| Triesenberg | 1 | <th> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And more than 0 results are returned
|
||||
And all results have attributes geojson
|
||||
|
||||
Examples:
|
||||
| th |
|
||||
| -1 |
|
||||
| 0.0 |
|
||||
| 0.5 |
|
||||
| 999 |
|
||||
|
||||
Scenario Outline: Search with polygon threshold (xml)
|
||||
When sending v1/search with format xml
|
||||
| q | polygon_geojson | polygon_threshold |
|
||||
| Triesenberg | 1 | <th> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And more than 0 results are returned
|
||||
And all results have attributes geojson
|
||||
|
||||
Examples:
|
||||
| th |
|
||||
| -1 |
|
||||
| 0.0 |
|
||||
| 0.5 |
|
||||
| 999 |
|
||||
|
||||
Scenario Outline: Search with invalid polygon threshold (xml)
|
||||
When sending v1/search with format xml
|
||||
| q | polygon_geojson | polygon_threshold |
|
||||
| Triesenberg | 1 | <th> |
|
||||
Then a HTTP 400 is returned
|
||||
|
||||
Examples:
|
||||
| th |
|
||||
| x |
|
||||
| ;; |
|
||||
| 1m |
|
||||
|
||||
Scenario Outline: Search with extratags
|
||||
When sending v1/search with format <format>
|
||||
| q | extratags |
|
||||
| Landstr | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And more than 0 results are returned
|
||||
Then all results have attributes extratags
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| xml | xml |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
|
||||
Scenario Outline: Search with namedetails
|
||||
When sending v1/search with format <format>
|
||||
| q | namedetails |
|
||||
| Landstr | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And more than 0 results are returned
|
||||
Then all results have attributes namedetails
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| xml | xml |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
|
||||
Scenario Outline: Search result with contains formatted geometry
|
||||
When sending v1/search with format <format>
|
||||
| q | <param> |
|
||||
| Triesenberg | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And more than 0 results are returned
|
||||
And all results have attributes <response_attribute>
|
||||
|
||||
Examples:
|
||||
| format | outformat | param | response_attribute |
|
||||
| xml | xml | polygon_text | geotext |
|
||||
| json | json | polygon_text | geotext |
|
||||
| jsonv2 | json | polygon_text | geotext |
|
||||
| xml | xml | polygon_svg | geosvg |
|
||||
| json | json | polygon_svg | svg |
|
||||
| jsonv2 | json | polygon_svg | svg |
|
||||
| xml | xml | polygon_kml | geokml |
|
||||
| json | json | polygon_kml | geokml |
|
||||
| jsonv2 | json | polygon_kml | geokml |
|
||||
| xml | xml | polygon_geojson | geojson |
|
||||
| json | json | polygon_geojson | geojson |
|
||||
| jsonv2 | json | polygon_geojson | geojson |
|
||||
| geojson | geojson | polygon_geojson | geojson |
|
||||
|
||||
Scenario Outline: Search result in geojson format contains no non-geojson geometry
|
||||
When sending v1/search with format geojson
|
||||
| q | <param> |
|
||||
| Triesenberg | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geojson
|
||||
And more than 0 results are returned
|
||||
And all results have no attributes <response_attribute>
|
||||
|
||||
Examples:
|
||||
| param | response_attribute |
|
||||
| polygon_text | geotext |
|
||||
| polygon_svg | svg |
|
||||
| polygon_kml | geokml |
|
||||
@@ -1,51 +1,51 @@
|
||||
@SQLITE
|
||||
@APIDB
|
||||
Feature: Searches with postcodes
|
||||
Various searches involving postcodes
|
||||
|
||||
Scenario: US 5+4 ZIP codes are shortened to 5 ZIP codes if not found
|
||||
When sending json search query "36067-1111, us" with address
|
||||
Then result addresses contain
|
||||
When geocoding "36067-1111, us"
|
||||
Then all results contain in field address
|
||||
| postcode |
|
||||
| 36067 |
|
||||
And results contain
|
||||
And all results contain
|
||||
| type |
|
||||
| postcode |
|
||||
|
||||
Scenario: Postcode search with address
|
||||
When sending json search query "9486, mauren"
|
||||
Then at least 1 result is returned
|
||||
When geocoding "9486, mauren"
|
||||
Then result 0 contains
|
||||
| type |
|
||||
| postcode |
|
||||
|
||||
Scenario: Postcode search with country
|
||||
When sending json search query "9486, li" with address
|
||||
Then result addresses contain
|
||||
When geocoding "9486, li"
|
||||
Then all results contain in field address
|
||||
| country_code |
|
||||
| li |
|
||||
|
||||
Scenario: Postcode search with country code restriction
|
||||
When sending json search query "9490" with address
|
||||
When geocoding "9490"
|
||||
| countrycodes |
|
||||
| li |
|
||||
Then result addresses contain
|
||||
Then all results contain in field address
|
||||
| country_code |
|
||||
| li |
|
||||
|
||||
Scenario: Postcode search with bounded viewbox restriction
|
||||
When sending json search query "9486" with address
|
||||
When geocoding "9486"
|
||||
| bounded | viewbox |
|
||||
| 1 | 9.55,47.20,9.58,47.22 |
|
||||
Then result addresses contain
|
||||
Then all results contain in field address
|
||||
| postcode |
|
||||
| 9486 |
|
||||
When sending json search query "9486" with address
|
||||
When geocoding "9486"
|
||||
| bounded | viewbox |
|
||||
| 1 | 5.00,20.00,6.00,21.00 |
|
||||
Then exactly 0 results are returned
|
||||
Then exactly 0 result is returned
|
||||
|
||||
Scenario: Postcode search with structured query
|
||||
When sending json search query "" with address
|
||||
When geocoding ""
|
||||
| postalcode | country |
|
||||
| 9490 | li |
|
||||
Then result addresses contain
|
||||
Then all results contain in field address
|
||||
| country_code | postcode |
|
||||
| li | 9490 |
|
||||
212
test/bdd/features/api/search/queries.feature
Normal file
212
test/bdd/features/api/search/queries.feature
Normal file
@@ -0,0 +1,212 @@
|
||||
Feature: Search queries
|
||||
Generic search result correctness
|
||||
|
||||
Scenario: Search for natural object
|
||||
When geocoding "Samina"
|
||||
| accept-language |
|
||||
| en |
|
||||
Then result 0 contains
|
||||
| category | type | display_name |
|
||||
| waterway | river | Samina, Austria |
|
||||
|
||||
Scenario: House number search for non-street address
|
||||
When geocoding "6 Silum, Liechtenstein"
|
||||
| accept-language |
|
||||
| en |
|
||||
Then result 0 contains in field address
|
||||
| param | value |
|
||||
| house_number | 6 |
|
||||
| village | Silum |
|
||||
| town | Triesenberg |
|
||||
| county | Oberland |
|
||||
| postcode | 9497 |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
| ISO3166-2-lvl8 | LI-10 |
|
||||
|
||||
Scenario: Search for house number interpolation
|
||||
When geocoding "Grosssteg 1023, Triesenberg"
|
||||
| accept-language |
|
||||
| de |
|
||||
Then result 0 contains in field address
|
||||
| param | value |
|
||||
| house_number | 1023 |
|
||||
| road | Grosssteg |
|
||||
| village | Sücka |
|
||||
| postcode | 9497 |
|
||||
| town | Triesenberg |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
|
||||
Scenario: With missing housenumber search falls back to road
|
||||
When geocoding "Bündaweg 555"
|
||||
Then result 0 contains in field address
|
||||
| param | value |
|
||||
| road | Bündaweg |
|
||||
| village | Silum |
|
||||
| postcode | 9497 |
|
||||
| county | Oberland |
|
||||
| town | Triesenberg |
|
||||
| country | Liechtenstein |
|
||||
| country_code | li |
|
||||
| ISO3166-2-lvl8 | LI-10 |
|
||||
And all results have no attributes address+house_number
|
||||
|
||||
Scenario Outline: Housenumber 0 can be found
|
||||
When sending v1/search with format <format>
|
||||
| q | addressdetails |
|
||||
| Gnalpstrasse 0 | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And all results contain
|
||||
| display_name!fm | address+house_number |
|
||||
| 0,.* | 0 |
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| xml | xml |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
|
||||
Scenario: TIGER house number
|
||||
When geocoding "697 Upper Kingston Road"
|
||||
Then all results contain
|
||||
| osm_type | display_name!fm | address+house_number |
|
||||
| way | 697,.* | 697 |
|
||||
|
||||
Scenario: Search with class-type feature
|
||||
When geocoding "bars in ebenholz"
|
||||
Then all results contain
|
||||
| place_rank |
|
||||
| 30 |
|
||||
|
||||
Scenario: Search with specific amenity
|
||||
When geocoding "[restaurant] Vaduz"
|
||||
Then all results contain
|
||||
| category | type | address+country |
|
||||
| amenity | restaurant | Liechtenstein |
|
||||
|
||||
Scenario: Search with specific amenity also work in country
|
||||
When geocoding "restaurants in liechtenstein"
|
||||
Then all results contain
|
||||
| category | type | address+country |
|
||||
| amenity | restaurant | Liechtenstein |
|
||||
|
||||
Scenario: Search with key-value amenity
|
||||
When geocoding "[club=scout] Vaduz"
|
||||
Then all results contain
|
||||
| category | type |
|
||||
| club | scout |
|
||||
|
||||
Scenario: POI search near given coordinate
|
||||
When geocoding "restaurant near 47.16712,9.51100"
|
||||
Then all results contain
|
||||
| category | type |
|
||||
| amenity | restaurant |
|
||||
|
||||
Scenario: Arbitrary key/value search near given coordinate
|
||||
When geocoding "[leisure=firepit] 47.150° N 9.5340493° E"
|
||||
Then all results contain
|
||||
| category | type |
|
||||
| leisure | firepit |
|
||||
|
||||
Scenario: POI search in a bounded viewbox
|
||||
When geocoding "restaurants"
|
||||
| viewbox | bounded |
|
||||
| 9.50830,47.15253,9.52043,47.14866 | 1 |
|
||||
Then all results contain
|
||||
| category | type |
|
||||
| amenity | restaurant |
|
||||
|
||||
Scenario Outline: Key/value search near given coordinate can be restricted to country
|
||||
When geocoding "[natural=peak] 47.06512,9.53965"
|
||||
| countrycodes |
|
||||
| <cc> |
|
||||
Then all results contain
|
||||
| address+country_code |
|
||||
| <cc> |
|
||||
|
||||
Examples:
|
||||
| cc |
|
||||
| li |
|
||||
| ch |
|
||||
|
||||
Scenario: Name search near given coordinate
|
||||
When geocoding "sporry"
|
||||
Then result 0 contains
|
||||
| address+town |
|
||||
| Vaduz |
|
||||
When geocoding "sporry, 47.10791,9.52676"
|
||||
Then result 0 contains
|
||||
| address+village |
|
||||
| Triesen |
|
||||
|
||||
Scenario: Name search near given coordinate without result
|
||||
When geocoding "sporry, N 47 15 7 W 9 61 26"
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Arbitrary key/value search near a road
|
||||
When geocoding "[amenity=drinking_water] Wissfläckaweg"
|
||||
Then all results contain
|
||||
| category | type |
|
||||
| amenity | drinking_water |
|
||||
|
||||
Scenario: Ignore other country codes in structured search with country
|
||||
When geocoding
|
||||
| countrycodes | country |
|
||||
| li | de |
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Ignore country searches when query is restricted to countries
|
||||
When geocoding "fr"
|
||||
Then all results contain
|
||||
| name |
|
||||
| France |
|
||||
When geocoding "fr"
|
||||
| countrycodes |
|
||||
| li |
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Country searches only return results for the given country
|
||||
When geocoding "Ans Trail"
|
||||
| countrycodes |
|
||||
| li |
|
||||
Then all results contain
|
||||
| address+country_code |
|
||||
| li |
|
||||
|
||||
# https://trac.openstreetmap.org/ticket/5094
|
||||
Scenario: housenumbers are ordered by complete match first
|
||||
When geocoding "Austrasse 11, Vaduz"
|
||||
Then result 0 contains
|
||||
| address+house_number |
|
||||
| 11 |
|
||||
|
||||
Scenario Outline: Coordinate searches with white spaces
|
||||
When geocoding "<data>"
|
||||
Then the result set contains exactly
|
||||
| category |
|
||||
| water |
|
||||
|
||||
Examples:
|
||||
| data |
|
||||
| sporry weiher, N 47.10791° E 9.52676° |
|
||||
| sporry weiher, N 47.10791° E 9.52676° |
|
||||
| sporry weiher , N 47.10791° E 9.52676° |
|
||||
| sporry weiher, N 47.10791° E 9.52676° |
|
||||
| sporry weiher, N 47.10791° E 9.52676° |
|
||||
|
||||
Scenario: Searches with white spaces
|
||||
When geocoding "52 Bodastr,Triesenberg"
|
||||
Then all results contain
|
||||
| category | type |
|
||||
| highway | residential |
|
||||
|
||||
|
||||
# github #1949
|
||||
Scenario: Addressdetails always return the place type
|
||||
When geocoding "Vaduz"
|
||||
Then result 0 contains
|
||||
| address+town |
|
||||
| Vaduz |
|
||||
166
test/bdd/features/api/search/simple.feature
Normal file
166
test/bdd/features/api/search/simple.feature
Normal file
@@ -0,0 +1,166 @@
|
||||
Feature: Simple Tests
|
||||
Simple tests for internal server errors and response format.
|
||||
|
||||
Scenario Outline: Garbage Searches
|
||||
When sending v1/search
|
||||
| q |
|
||||
| <query> |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And exactly 0 results are returned
|
||||
|
||||
Examples:
|
||||
| query |
|
||||
| New York, New York |
|
||||
| 12, Main Street, Houston |
|
||||
| München |
|
||||
| 東京都 |
|
||||
| hotels in sdfewf |
|
||||
| xywxkrf |
|
||||
| gh; foo() |
|
||||
| %#$@*&l;der#$! |
|
||||
| 234.23.14.5 |
|
||||
| aussenstelle universitat lichtenstein wachterhaus aussenstelle universitat lichtenstein wachterhaus aussenstelle universitat lichtenstein wachterhaus aussenstelle universitat lichtenstein wachterhaus |
|
||||
|
||||
Scenario: Empty XML search
|
||||
When sending v1/search with format xml
|
||||
| q |
|
||||
| xnznxvcx |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
Then the result metadata contains
|
||||
| param | value |
|
||||
| querystring | xnznxvcx |
|
||||
| more_url!fm | .*q=xnznxvcx.*format=xml |
|
||||
|
||||
Scenario: Empty XML search with special XML characters
|
||||
When sending v1/search with format xml
|
||||
| q |
|
||||
| xfdghn&zxn"xvbyx<vxx>cssdex |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
Then the result metadata contains
|
||||
| param | value |
|
||||
| querystring | xfdghn&zxn"xvbyx<vxx>cssdex |
|
||||
| more_url!fm | .*q=xfdghn%26zxn%22xvbyx%3Cvxx%3Ecssdex.*format=xml |
|
||||
|
||||
Scenario: Empty XML search with viewbox
|
||||
When sending v1/search with format xml
|
||||
| q | viewbox |
|
||||
| xnznxvcx | 12,33,77,45.13 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result metadata contains
|
||||
| param | value |
|
||||
| querystring | xnznxvcx |
|
||||
| viewbox | 12,33,77,45.13 |
|
||||
|
||||
Scenario: Empty XML search with viewboxlbrt
|
||||
When sending v1/search with format xml
|
||||
| q | viewboxlbrt |
|
||||
| xnznxvcx | 12,34.13,77,45 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result metadata contains
|
||||
| param | value |
|
||||
| querystring | xnznxvcx |
|
||||
| viewbox | 12,34.13,77,45 |
|
||||
|
||||
Scenario: Empty XML search with viewboxlbrt and viewbox
|
||||
When sending v1/search with format xml
|
||||
| q | viewbox | viewboxblrt |
|
||||
| pub | 12,33,77,45.13 | 1,2,3,4 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result metadata contains
|
||||
| param | value |
|
||||
| querystring | pub |
|
||||
| viewbox | 12,33,77,45.13 |
|
||||
|
||||
Scenario: Empty XML search with excluded place ids
|
||||
When sending v1/search with format xml
|
||||
| q | exclude_place_ids |
|
||||
| jghrleoxsbwjer | 123,76,342565 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result metadata contains
|
||||
| param | value |
|
||||
| exclude_place_ids | 123,76,342565 |
|
||||
|
||||
Scenario: Empty XML search with bad excluded place ids
|
||||
When sending v1/search with format xml
|
||||
| q | exclude_place_ids |
|
||||
| jghrleoxsbwjer | , |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result metadata has no attributes exclude_place_ids
|
||||
|
||||
Scenario Outline: Wrapping of illegal jsonp search requests
|
||||
When sending v1/search with format json
|
||||
| q | json_callback |
|
||||
| Tokyo | <data> |
|
||||
Then a HTTP 400 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| error+code | error+message |
|
||||
| 400 | Invalid json_callback value |
|
||||
|
||||
Examples:
|
||||
| data |
|
||||
| 1asd |
|
||||
| bar(foo) |
|
||||
| XXX['bad'] |
|
||||
| foo; evil |
|
||||
| 234 |
|
||||
|
||||
Scenario: Ignore jsonp parameter for anything but json
|
||||
When sending v1/search with format xml
|
||||
| q | json_callback |
|
||||
| Tokyo | 234 |
|
||||
Then a HTTP 200 is returned
|
||||
Then the result is valid xml
|
||||
|
||||
Scenario Outline: Empty search for json like
|
||||
When sending v1/search with format <format>
|
||||
| q |
|
||||
| YHlERzzx |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid <outformat>
|
||||
And exactly 0 results are returned
|
||||
|
||||
Examples:
|
||||
| format | outformat |
|
||||
| json | json |
|
||||
| jsonv2 | json |
|
||||
| geojson | geojson |
|
||||
| geocodejson | geocodejson |
|
||||
|
||||
Scenario: Search for non-existing coordinates
|
||||
When geocoding "-21.0,-33.0"
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Country code selection is retained in more URL (#596)
|
||||
When sending v1/search with format xml
|
||||
| q | countrycodes |
|
||||
| Vaduz | pl,1,,invalid,undefined,%3Cb%3E,bo,, |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result metadata contains
|
||||
| more_url!fm |
|
||||
| .*&countrycodes=pl%2Cbo&.* |
|
||||
|
||||
Scenario Outline: Search debug output does not return errors
|
||||
When sending v1/search
|
||||
| q | debug |
|
||||
| <query> | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid html
|
||||
|
||||
Examples:
|
||||
| query |
|
||||
| Liechtenstein |
|
||||
| Triesen |
|
||||
| Pfarrkirche |
|
||||
| Landstr 27 Steinort, Triesenberg, 9495 |
|
||||
| 9497 |
|
||||
| restaurant in triesen |
|
||||
72
test/bdd/features/api/search/structured.feature
Normal file
72
test/bdd/features/api/search/structured.feature
Normal file
@@ -0,0 +1,72 @@
|
||||
Feature: Structured search queries
|
||||
Testing correctness of results with
|
||||
structured queries
|
||||
|
||||
Scenario: Structured search for country only
|
||||
When geocoding
|
||||
| country |
|
||||
| Liechtenstein |
|
||||
Then all results contain in field address
|
||||
| country_code | country |
|
||||
| li | Liechtenstein |
|
||||
|
||||
Scenario: Structured search for postcode only
|
||||
When geocoding
|
||||
| postalcode |
|
||||
| 9495 |
|
||||
Then all results contain
|
||||
| type!fm | address+postcode |
|
||||
| ^post(al_)?code | 9495 |
|
||||
|
||||
Scenario: Structured search for street, postcode and country
|
||||
When sending v1/search with format xml
|
||||
| street | postalcode | country |
|
||||
| Old Palace Road | GU2 7UP | United Kingdom |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid xml
|
||||
And the result metadata contains
|
||||
| querystring |
|
||||
| Old Palace Road, GU2 7UP, United Kingdom |
|
||||
|
||||
Scenario: Structured search for street with housenumber, city and postcode
|
||||
When geocoding
|
||||
| street | city | postalcode |
|
||||
| 19 Am schrägen Weg | Vaduz | 9490 |
|
||||
Then all results contain in field address
|
||||
| house_number | road |
|
||||
| 19 | Am Schrägen Weg |
|
||||
|
||||
Scenario: Structured search for street with housenumber, city and bad postcode
|
||||
When geocoding
|
||||
| street | city | postalcode |
|
||||
| 19 Am schrägen Weg | Vaduz | 9491 |
|
||||
Then all results contain in field address
|
||||
| house_number | road |
|
||||
| 19 | Am Schrägen Weg |
|
||||
|
||||
Scenario: Structured search for amenity, city
|
||||
When geocoding
|
||||
| city | amenity |
|
||||
| Vaduz | bar |
|
||||
Then all results contain
|
||||
| address+country | category | type!fm |
|
||||
| Liechtenstein | amenity | (pub)\|(bar)\|(restaurant) |
|
||||
|
||||
#176
|
||||
Scenario: Structured search restricts rank
|
||||
When geocoding
|
||||
| city |
|
||||
| Steg |
|
||||
Then all results contain
|
||||
| addresstype |
|
||||
| village |
|
||||
|
||||
#3651
|
||||
Scenario: Structured search with surrounding extra characters
|
||||
When geocoding
|
||||
| street | city | postalcode |
|
||||
| "19 Am schrägen Weg" | "Vaduz" | "9491" |
|
||||
Then all results contain in field address
|
||||
| house_number | road |
|
||||
| 19 | Am Schrägen Weg |
|
||||
|
||||
42
test/bdd/features/api/search/v1_geocodejson.feature
Normal file
42
test/bdd/features/api/search/v1_geocodejson.feature
Normal file
@@ -0,0 +1,42 @@
|
||||
Feature: Search API geocodejson output
|
||||
Testing correctness of geocodejson output.
|
||||
|
||||
Scenario: Search geocodejson - City housenumber-level address with street
|
||||
When sending v1/search with format geocodejson
|
||||
| q | addressdetails |
|
||||
| Im Winkel 8, Triesen | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson
|
||||
And all results contain
|
||||
| housenumber | street | postcode | city | country |
|
||||
| 8 | Im Winkel | 9495 | Triesen | Liechtenstein |
|
||||
|
||||
Scenario: Search geocodejson - Town street-level address with street
|
||||
When sending v1/search with format geocodejson
|
||||
| q | addressdetails |
|
||||
| Gnetsch, Balzers | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson
|
||||
And all results contain
|
||||
| name | city | postcode | country |
|
||||
| Gnetsch | Balzers | 9496 | Liechtenstein |
|
||||
|
||||
Scenario: Search geocodejson - Town street-level address with footway
|
||||
When sending v1/search with format geocodejson
|
||||
| q | addressdetails |
|
||||
| burg gutenberg 6000 jahre geschichte | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson
|
||||
And all results contain
|
||||
| street | city | postcode | country |
|
||||
| Burgweg | Balzers | 9496 | Liechtenstein |
|
||||
|
||||
Scenario: Search geocodejson - City address with suburb
|
||||
When sending v1/search with format geocodejson
|
||||
| q | addressdetails |
|
||||
| Lochgass 5, Ebenholz, Vaduz | 1 |
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid geocodejson
|
||||
And all results contain
|
||||
| housenumber | street | district | city | postcode | country |
|
||||
| 5 | Lochgass | Ebenholz | Vaduz | 9490 | Liechtenstein |
|
||||
19
test/bdd/features/api/status/failures.feature
Normal file
19
test/bdd/features/api/status/failures.feature
Normal file
@@ -0,0 +1,19 @@
|
||||
Feature: Status queries against unknown database
|
||||
Testing status query
|
||||
|
||||
Background:
|
||||
Given an unknown database
|
||||
|
||||
Scenario: Failed status as text
|
||||
When sending v1/status
|
||||
Then a HTTP 500 is returned
|
||||
And the page content equals "ERROR: Database connection failed"
|
||||
|
||||
Scenario: Failed status as json
|
||||
When sending v1/status with format json
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| status!:d | message |
|
||||
| 700 | Database connection failed |
|
||||
And the result has no attributes data_updated
|
||||
15
test/bdd/features/api/status/simple.feature
Normal file
15
test/bdd/features/api/status/simple.feature
Normal file
@@ -0,0 +1,15 @@
|
||||
Feature: Status queries
|
||||
Testing status query
|
||||
|
||||
Scenario: Status as text
|
||||
When sending v1/status
|
||||
Then a HTTP 200 is returned
|
||||
And the page content equals "OK"
|
||||
|
||||
Scenario: Status as json
|
||||
When sending v1/status with format json
|
||||
Then a HTTP 200 is returned
|
||||
And the result is valid json
|
||||
And the result contains
|
||||
| status!:d | message | data_updated!fm |
|
||||
| 0 | OK | ....-..-..T..:..:...00:00 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Address computation
|
||||
Tests for filling of place_addressline
|
||||
|
||||
@@ -11,16 +10,13 @@ Feature: Address computation
|
||||
| N2 | place | hamlet | West Farm | 2 |
|
||||
| N3 | place | hamlet | East Farm | 3 |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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 |
|
||||
When geocoding "Square"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Square, East Farm |
|
||||
|
||||
Scenario: given two place nodes, the closer one wins for the address
|
||||
Given the grid
|
||||
@@ -102,12 +98,9 @@ Feature: Address computation
|
||||
| N2 | place | city | 15 | 9 |
|
||||
| R1 | place | city | 8 | (1,2,3,4,1) |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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
|
||||
@@ -191,12 +184,9 @@ Feature: Address computation
|
||||
| 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
|
||||
Then place_addressline contains exactly
|
||||
| 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
|
||||
@@ -211,12 +201,9 @@ Feature: Address computation
|
||||
| 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
|
||||
Then place_addressline contains exactly
|
||||
| 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
|
||||
@@ -248,9 +235,8 @@ Feature: Address computation
|
||||
| osm | class | type | admin | geometry |
|
||||
| W10 | boundary | administrative | 5 | (2, 3, 6, 5, 2) |
|
||||
When importing
|
||||
Then place_addressline doesn't contain
|
||||
Then place_addressline contains exactly
|
||||
| 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
|
||||
@@ -273,9 +259,14 @@ Feature: Address computation
|
||||
| osm | class | type | addr+postcode | geometry |
|
||||
| W22 | place | postcode | 11234 | (10,11,12,13,10) |
|
||||
When importing
|
||||
Then place_addressline doesn't contain
|
||||
Then place_addressline contains exactly
|
||||
| object | address |
|
||||
| W93 | W22 |
|
||||
| R4 | R1 |
|
||||
| R4 | R34 |
|
||||
| R34 | R1 |
|
||||
| W93 | R1 |
|
||||
| W93 | R34 |
|
||||
| W93 | R4 |
|
||||
|
||||
Scenario: postcode boundaries do appear in the address of a way
|
||||
Given the grid with origin DE
|
||||
@@ -314,9 +305,8 @@ Feature: Address computation
|
||||
| W1 | highway | residential | 8, 9 |
|
||||
| W2 | place | square | (1, 2, 3 ,4, 1) |
|
||||
When importing
|
||||
Then place_addressline doesn't contain
|
||||
Then place_addressline contains exactly
|
||||
| object | address |
|
||||
| W1 | W2 |
|
||||
|
||||
Scenario: addr:* tags are honored even when a street is far away from the place
|
||||
Given the grid
|
||||
@@ -332,14 +322,11 @@ Feature: Address computation
|
||||
| W1 | highway | primary | Left | 8,9 |
|
||||
| W2 | highway | primary | Right | 8,9 |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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
|
||||
@@ -356,17 +343,14 @@ Feature: Address computation
|
||||
| W1 | highway | primary | Wonderway | Right | 8,9 |
|
||||
| N1 | amenity | cafe | Bolder | Left | 9 |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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 |
|
||||
When geocoding "Bolder"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Bolder, Wonderway, Left |
|
||||
|
||||
Scenario: addr:* tags do not produce addresslines when the parent has the address part
|
||||
Given the grid
|
||||
@@ -381,16 +365,13 @@ Feature: Address computation
|
||||
| W1 | highway | primary | Wonderway | Outer | 8,9 |
|
||||
| N1 | amenity | cafe | Bolder | Outer | 9 |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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 |
|
||||
When geocoding "Bolder"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Bolder, Wonderway, Outer |
|
||||
|
||||
Scenario: addr:* tags on outside do not produce addresslines when the parent has the address part
|
||||
Given the grid
|
||||
@@ -406,17 +387,14 @@ Feature: Address computation
|
||||
| W1 | highway | primary | Wonderway | Left | 8,9 |
|
||||
| N1 | amenity | cafe | Bolder | Left | 9 |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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 |
|
||||
When geocoding "Bolder"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Bolder, Wonderway, Left |
|
||||
|
||||
Scenario: POIs can correct address parts on the fly
|
||||
Given the grid
|
||||
@@ -433,22 +411,18 @@ Feature: Address computation
|
||||
| N1 | amenity | cafe | Bolder | 9 |
|
||||
| N2 | amenity | cafe | Leftside | 8 |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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 |
|
||||
When geocoding "Bolder"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Bolder, Wonderway, Left |
|
||||
When geocoding "Leftside"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N2 | Leftside, Wonderway, Right |
|
||||
|
||||
|
||||
Scenario: POIs can correct address parts on the fly (with partial unmatching address)
|
||||
@@ -469,22 +443,18 @@ Feature: Address computation
|
||||
| N1 | amenity | cafe | Bolder | Boring | 9 |
|
||||
| N2 | amenity | cafe | Leftside | Boring | 8 |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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 |
|
||||
When geocoding "Bolder"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Bolder, Wonderway, Left |
|
||||
When geocoding "Leftside"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N2 | Leftside, Wonderway, Right |
|
||||
|
||||
|
||||
|
||||
@@ -506,30 +476,26 @@ Feature: Address computation
|
||||
| N1 | amenity | cafe | Bolder | Left | 9 |
|
||||
| N2 | amenity | cafe | Leftside | Left | 8 |
|
||||
When importing
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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 |
|
||||
When geocoding "Bolder"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Bolder, Wonderway, Left |
|
||||
When geocoding "Leftside"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N2 | Leftside, Wonderway, Left |
|
||||
|
||||
|
||||
Scenario: addr:* tags always match the closer area
|
||||
Given the grid
|
||||
| 1 | | | | 2 | | 5 |
|
||||
| | | | | | | |
|
||||
| | 10| 11| | | | |
|
||||
| 4 | | | | 3 | | 6 |
|
||||
| | 10| 11| | | | |
|
||||
And the places
|
||||
| osm | class | type | admin | name | geometry |
|
||||
| R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
|
||||
@@ -538,9 +504,9 @@ Feature: Address computation
|
||||
| osm | class | type | name | addr+city | geometry |
|
||||
| W1 | highway | primary | Wonderway | Left | 10,11 |
|
||||
When importing
|
||||
Then place_addressline doesn't contain
|
||||
Then place_addressline contains exactly
|
||||
| object | address |
|
||||
| W1 | R2 |
|
||||
| W1 | R1 |
|
||||
|
||||
Scenario: Full name is prefered for unlisted addr:place tags
|
||||
Given the grid
|
||||
@@ -559,7 +525,7 @@ Feature: Address computation
|
||||
| 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 |
|
||||
When geocoding "1, Royal Terrace Gardens"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Country handling
|
||||
Tests for import and use of country information
|
||||
|
||||
@@ -10,16 +9,16 @@ Feature: Country handling
|
||||
| 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"
|
||||
When geocoding "Wenig, Loudou"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Wenig, Deutschland |
|
||||
When geocoding "Wenig"
|
||||
| accept-language |
|
||||
| xy,en |
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Wenig, Loudou |
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Wenig, Loudou |
|
||||
|
||||
Scenario: OSM country relations outside expected boundaries are ignored for naming
|
||||
Given the grid
|
||||
@@ -32,12 +31,12 @@ Feature: Country handling
|
||||
| osm | class | type | name | geometry |
|
||||
| N1 | place | town | Wenig | country:de |
|
||||
When importing
|
||||
When sending search query "Wenig"
|
||||
When geocoding "Wenig"
|
||||
| accept-language |
|
||||
| xy,en |
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Wenig, Germany |
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Wenig, Germany |
|
||||
|
||||
Scenario: Pre-defined country names are used
|
||||
Given the grid with origin CH
|
||||
@@ -46,12 +45,12 @@ Feature: Country handling
|
||||
| osm | class | type | name | geometry |
|
||||
| N1 | place | town | Ingb | 1 |
|
||||
When importing
|
||||
And sending search query "Ingb"
|
||||
And geocoding "Ingb"
|
||||
| accept-language |
|
||||
| en,de |
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| N1 | Ingb, Switzerland |
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Ingb, Switzerland |
|
||||
|
||||
Scenario: For overlapping countries, pre-defined countries are tie-breakers
|
||||
Given the grid with origin US
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Import of address interpolations
|
||||
Tests that interpolated addresses are added correctly
|
||||
|
||||
@@ -60,7 +59,7 @@ Feature: Import of address interpolations
|
||||
When importing
|
||||
Then W1 expands to interpolation
|
||||
| start | end | geometry |
|
||||
| 4 | 6 | 9,8 |
|
||||
| 4 | 6 | 8,9 |
|
||||
|
||||
Scenario: Simple odd two point interpolation
|
||||
Given the grid with origin 1,1
|
||||
@@ -227,8 +226,8 @@ Feature: Import of address interpolations
|
||||
|
||||
Scenario: Even three point interpolation line with odd center point
|
||||
Given the grid
|
||||
| 1 | | 10 | | | 11 | 3 | 2 |
|
||||
| 4 | | | | | | | 5 |
|
||||
| 1 | | 10 | | 11 | 3 | 2 |
|
||||
| 4 | | | | | | 5 |
|
||||
Given the places
|
||||
| osm | class | type | housenr |
|
||||
| N1 | place | house | 2 |
|
||||
@@ -332,14 +331,14 @@ Feature: Import of address interpolations
|
||||
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 |
|
||||
When geocoding "16 Cloud Street"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N4 |
|
||||
When geocoding "14 Cloud Street"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| W11 |
|
||||
|
||||
Scenario: addr:street on housenumber way
|
||||
Given the grid
|
||||
@@ -377,14 +376,14 @@ Feature: Import of address interpolations
|
||||
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 |
|
||||
When geocoding "16 Cloud Street"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N4 |
|
||||
When geocoding "14 Cloud Street"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| W11 |
|
||||
|
||||
Scenario: Geometry of points and way don't match (github #253)
|
||||
Given the places
|
||||
@@ -404,7 +403,7 @@ Feature: Import of address interpolations
|
||||
When importing
|
||||
Then W1 expands to interpolation
|
||||
| start | end | geometry |
|
||||
| 4 | 4 | 144.963016 -37.762946 |
|
||||
| 4 | 4 | 144.96301672 -37.76294644 |
|
||||
| 8 | 8 | 144.96314407 -37.762223692 |
|
||||
|
||||
Scenario: Place with missing address information
|
||||
@@ -428,7 +427,7 @@ Feature: Import of address interpolations
|
||||
When importing
|
||||
Then W1 expands to interpolation
|
||||
| start | end | geometry |
|
||||
| 25 | 27 | 0.000016 0,0.00002 0,0.000033 0 |
|
||||
| 25 | 27 | 0.0000166 0,0.00002 0,0.0000333 0 |
|
||||
|
||||
Scenario: Ways without node entries are ignored
|
||||
Given the places
|
||||
@@ -478,10 +477,10 @@ Feature: Import of address interpolations
|
||||
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 |
|
||||
When reverse geocoding 1,1
|
||||
Then the result contains
|
||||
| object | type | display_name |
|
||||
| N1 | house | 0, London Road |
|
||||
|
||||
Scenario: Parenting of interpolation with additional tags
|
||||
Given the grid
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Linking of places
|
||||
Tests for correctly determining linked places
|
||||
|
||||
@@ -53,10 +52,10 @@ Feature: Linking of places
|
||||
| W2 | R13 |
|
||||
| R13 | - |
|
||||
| R23 | - |
|
||||
When sending search query "rhein"
|
||||
Then results contain
|
||||
| osm |
|
||||
| R13 |
|
||||
When geocoding "rhein"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| R13 |
|
||||
|
||||
Scenario: Relations are not linked when in waterway relations
|
||||
Given the grid
|
||||
@@ -79,11 +78,13 @@ Feature: Linking of places
|
||||
| W2 | - |
|
||||
| R1 | - |
|
||||
| R2 | - |
|
||||
When sending search query "rhein"
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R1 |
|
||||
| 1 | W2 |
|
||||
When geocoding "rhein"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| R1 |
|
||||
And result 1 contains
|
||||
| object |
|
||||
| W2 |
|
||||
|
||||
|
||||
Scenario: Empty waterway relations are handled correctly
|
||||
@@ -136,9 +137,9 @@ Feature: Linking of places
|
||||
| object | linked_place_id |
|
||||
| W1 | - |
|
||||
| W2 | R1 |
|
||||
When sending search query "rhein2"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "rhein2"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| W1 |
|
||||
|
||||
# github #573
|
||||
@@ -180,8 +181,8 @@ Feature: Linking of places
|
||||
| object | linked_place_id |
|
||||
| N2 | R13 |
|
||||
And placex contains
|
||||
| object | centroid | name+name | extratags+linked_place |
|
||||
| R13 | 9 | Garbo | hamlet |
|
||||
| object | centroid!wkt | name+name | extratags+linked_place |
|
||||
| R13 | 9 | Garbo | hamlet |
|
||||
|
||||
Scenario: Boundaries with place tags are linked against places with same type
|
||||
Given the 0.01 grid
|
||||
@@ -201,18 +202,18 @@ Feature: Linking of places
|
||||
And placex contains
|
||||
| object | rank_address |
|
||||
| R13 | 16 |
|
||||
When sending search query ""
|
||||
When geocoding ""
|
||||
| city |
|
||||
| Berlin |
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R13 |
|
||||
When sending search query ""
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| R13 |
|
||||
When geocoding ""
|
||||
| state |
|
||||
| Berlin |
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R13 |
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| R13 |
|
||||
|
||||
|
||||
Scenario: Boundaries without place tags only link against same admin level
|
||||
@@ -233,18 +234,18 @@ Feature: Linking of places
|
||||
And placex contains
|
||||
| object | rank_address |
|
||||
| R13 | 8 |
|
||||
When sending search query ""
|
||||
When geocoding ""
|
||||
| state |
|
||||
| Berlin |
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | R13 |
|
||||
When sending search query ""
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| R13 |
|
||||
When geocoding ""
|
||||
| city |
|
||||
| Berlin |
|
||||
Then results contain
|
||||
| ID | osm |
|
||||
| 0 | N2 |
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N2 |
|
||||
|
||||
# github #1352
|
||||
Scenario: Do not use linked centroid when it is outside the area
|
||||
@@ -266,8 +267,8 @@ Feature: Linking of places
|
||||
| object | linked_place_id |
|
||||
| N2 | R13 |
|
||||
And placex contains
|
||||
| object | centroid |
|
||||
| R13 | in geometry |
|
||||
| object | centroid!in_box |
|
||||
| R13 | 0,0,0.1,0.1 |
|
||||
|
||||
Scenario: Place nodes can only be linked once
|
||||
Given the 0.02 grid
|
||||
@@ -286,7 +287,7 @@ Feature: Linking of places
|
||||
| object | linked_place_id |
|
||||
| N2 | R1 |
|
||||
And placex contains
|
||||
| object | extratags |
|
||||
| object | extratags!dict |
|
||||
| R1 | 'linked_place' : 'city', 'wikidata': 'Q1234' |
|
||||
| R2 | 'wikidata': 'Q1234' |
|
||||
|
||||
@@ -310,3 +311,22 @@ Feature: Linking of places
|
||||
| object | name+_place_name |
|
||||
| R1 | LabelPlace |
|
||||
|
||||
|
||||
@skip
|
||||
Scenario: Linked places expand default language names
|
||||
Given the grid
|
||||
| 1 | | 2 |
|
||||
| | 9 | |
|
||||
| 4 | | 3 |
|
||||
Given the places
|
||||
| osm | class | type | name+name | geometry |
|
||||
| N9 | place | city | Popayán | 9 |
|
||||
| R1 | boundary | administrative | Perímetro Urbano Popayán | (1,2,3,4,1) |
|
||||
And the relations
|
||||
| id | members |
|
||||
| 1 | N9:label |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | name+_place_name | name+_place_name:es |
|
||||
| R1 | Popayán | Popayán |
|
||||
|
||||
104
test/bdd/features/db/import/naming.feature
Normal file
104
test/bdd/features/db/import/naming.feature
Normal file
@@ -0,0 +1,104 @@
|
||||
Feature: Import and search of names
|
||||
Tests all naming related import issues
|
||||
|
||||
Scenario: No copying name tag if only one name
|
||||
Given the places
|
||||
| osm | class | type | name+name | geometry |
|
||||
| N1 | place | locality | german | country:de |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | country_code | name+name |
|
||||
| N1 | de | german |
|
||||
|
||||
Scenario: Copying name tag to default language if it does not exist
|
||||
Given the places
|
||||
| osm | class | type | name+name | name+name:fi | geometry |
|
||||
| N1 | place | locality | german | finnish | country:de |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | country_code | name+name | name+name:fi | name+name:de |
|
||||
| N1 | de | german | finnish | german |
|
||||
|
||||
Scenario: Copying default language name tag to name if it does not exist
|
||||
Given the places
|
||||
| osm | class | type | name+name:de | name+name:fi | geometry |
|
||||
| N1 | place | locality | german | finnish | country:de |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | country_code | name+name | name+name:fi | name+name:de |
|
||||
| N1 | de | german | finnish | german |
|
||||
|
||||
Scenario: Do not overwrite default language with name tag
|
||||
Given the places
|
||||
| osm | class | type | name+name | name+name:fi | name+name:de | geometry |
|
||||
| N1 | place | locality | german | finnish | local | country:de |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | country_code | name+name | name+name:fi | name+name:de |
|
||||
| N1 | de | german | finnish | local |
|
||||
|
||||
Scenario Outline: Names in any script can be found
|
||||
Given the places
|
||||
| osm | class | type | name+name |
|
||||
| N1 | place | hamlet | <name> |
|
||||
When importing
|
||||
And geocoding "<name>"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Examples:
|
||||
| name |
|
||||
| Berlin |
|
||||
| 北京 |
|
||||
| Вологда |
|
||||
| Αθήνα |
|
||||
| القاهرة |
|
||||
| រាជធានីភ្នំពេញ |
|
||||
| 東京都 |
|
||||
| ပုဗ္ဗသီရိ |
|
||||
|
||||
|
||||
Scenario: German umlauts can be found when expanded
|
||||
Given the places
|
||||
| osm | class | type | name+name:de |
|
||||
| N1 | place | city | Münster |
|
||||
| N2 | place | city | Köln |
|
||||
| N3 | place | city | Gräfenroda |
|
||||
When importing
|
||||
When geocoding "münster"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "muenster"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "munster"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "Köln"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N2 |
|
||||
When geocoding "Koeln"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N2 |
|
||||
When geocoding "Koln"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N2 |
|
||||
When geocoding "gräfenroda"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N3 |
|
||||
When geocoding "graefenroda"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N3 |
|
||||
When geocoding "grafenroda"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N3 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Parenting of objects
|
||||
Tests that the correct parent is chosen
|
||||
|
||||
@@ -21,14 +20,14 @@ Feature: Parenting of objects
|
||||
| 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 |
|
||||
When geocoding "4 galoo"
|
||||
Then result 0 contains
|
||||
| object | display_name |
|
||||
| N1 | 4, galoo, 12345, Deutschland |
|
||||
When geocoding "5 galoo"
|
||||
Then result 0 contains
|
||||
| object | display_name |
|
||||
| N2 | 5, galoo, 99999, Deutschland |
|
||||
|
||||
Scenario: Address without tags, closest street
|
||||
Given the grid
|
||||
@@ -484,9 +483,9 @@ Feature: Parenting of objects
|
||||
| N1 | W3 | 3 |
|
||||
| N2 | W3 | 3 |
|
||||
| N3 | W3 | 3 |
|
||||
When sending geocodejson search query "3, foo" with address
|
||||
Then results contain
|
||||
| housenumber |
|
||||
When geocoding "3, foo"
|
||||
Then the result set contains
|
||||
| address+house_number |
|
||||
| 3 |
|
||||
|
||||
Scenario: POIs don't inherit from streets
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Import into placex
|
||||
Tests that data in placex is completed correctly.
|
||||
|
||||
@@ -8,8 +7,8 @@ Feature: Import into placex
|
||||
| N1 | highway | primary | country:us |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | addr+country | country_code |
|
||||
| N1 | - | us |
|
||||
| object | address | country_code |
|
||||
| N1 | - | us |
|
||||
|
||||
Scenario: Location overwrites country code tag
|
||||
Given the named places
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Import of postcodes
|
||||
Tests for postcode estimation
|
||||
|
||||
@@ -176,11 +175,10 @@ Feature: Import of postcodes
|
||||
| N34 | place | house | 01982 | 111 |country:de |
|
||||
When importing
|
||||
Then location_postcode contains exactly
|
||||
| country | postcode | geometry |
|
||||
| de | 01982 | country:de |
|
||||
| country_code | postcode | geometry!wkt |
|
||||
| de | 01982 | country:de |
|
||||
|
||||
|
||||
@Fail
|
||||
@skip
|
||||
Scenario: search and address ranks for GB post codes correctly assigned
|
||||
Given the places
|
||||
| osm | class | type | postcode | geometry |
|
||||
@@ -189,10 +187,10 @@ Feature: Import of postcodes
|
||||
| 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 |
|
||||
| postcode | country_code | rank_search | rank_address |
|
||||
| E45 2CD | gb | 25 | 5 |
|
||||
| E45 2 | gb | 23 | 5 |
|
||||
| Y45 | gb | 21 | 5 |
|
||||
|
||||
Scenario: Postcodes outside all countries are not added to the postcode table
|
||||
Given the places
|
||||
@@ -203,8 +201,8 @@ Feature: Import of postcodes
|
||||
| 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 |
|
||||
| place_id |
|
||||
When geocoding "111, 01982 Null Island"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N34 | 111, Null Island, 01982 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Rank assignment
|
||||
Tests for assignment of search and address ranks.
|
||||
|
||||
@@ -173,13 +172,9 @@ Feature: Rank assignment
|
||||
| R23 | 20 | 0 |
|
||||
| R21 | 18 | 0 |
|
||||
| R22 | 16 | 16 |
|
||||
Then place_addressline contains
|
||||
Then place_addressline contains exactly
|
||||
| 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
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Creation of search terms
|
||||
Tests that search_name table is filled correctly
|
||||
|
||||
@@ -6,43 +5,40 @@ Feature: Creation of search terms
|
||||
Given the places
|
||||
| osm | class | type | name+alt_name |
|
||||
| N1 | place | city | New York; Big Apple |
|
||||
| N2 | place | town | New York Big Apple |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | name_vector |
|
||||
| N1 | #New York, #Big Apple |
|
||||
And geocoding "New York Big Apple"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N2 |
|
||||
|
||||
Scenario: Comma-separated names appear as a single full name
|
||||
Given the places
|
||||
| osm | class | type | name+alt_name |
|
||||
| osm | class | type | name+name |
|
||||
| N1 | place | city | New York, Big Apple |
|
||||
| N2 | place | town | New York Big Apple |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | name_vector |
|
||||
| N1 | #New York Big Apple |
|
||||
And geocoding "New York Big Apple"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Scenario: Name parts before brackets appear as full names
|
||||
Given the places
|
||||
| osm | class | type | name+name |
|
||||
| N1 | place | city | Halle (Saale) |
|
||||
| N2 | place | town | Halle |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | name_vector |
|
||||
| N1 | #Halle Saale, #Halle |
|
||||
And geocoding "Halle"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "Halle (Saale)"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
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
|
||||
Scenario: Unknown addr: tags can be found for unnamed POIs
|
||||
Given the grid
|
||||
| | 1 | | |
|
||||
| 10 | | | 11 |
|
||||
@@ -53,21 +49,18 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
When geocoding "23 Rose Street, Walltown"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When geocoding "Walltown, Rose Street 23"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When geocoding "Rose Street 23, Walltown"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
|
||||
Scenario: Searching for unknown addr: tags also works for multiple words
|
||||
Given the grid
|
||||
@@ -80,23 +73,20 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
When geocoding "23 Rose Street, Little Big Town"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When geocoding "Rose Street 23, Little Big Town"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When geocoding "Little big Town, Rose Street 23"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
|
||||
Scenario: Unnamed POI has no search entry when it has known addr: tags
|
||||
Scenario: Unnamed POI can be found when it has known addr: tags
|
||||
Given the grid
|
||||
| | 1 | | |
|
||||
| 10 | | | 11 |
|
||||
@@ -107,24 +97,10 @@ Feature: Creation of search terms
|
||||
| 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
|
||||
When geocoding "23 Rose Street, Walltown"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
|
||||
Scenario: Unnamed POIs inherit parent name when unknown addr:place is present
|
||||
Given the grid
|
||||
@@ -142,23 +118,22 @@ Feature: Creation of search terms
|
||||
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 |
|
||||
When geocoding "23 Rose Street"
|
||||
Then all results contain
|
||||
| object | display_name |
|
||||
| W1 | Rose Street, Strange Town |
|
||||
When geocoding "23 Walltown, Strange Town"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Walltown, Strange Town |
|
||||
When geocoding "Walltown 23, Strange Town"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Walltown, Strange Town |
|
||||
When geocoding "Strange Town, Walltown 23"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Walltown, Strange Town |
|
||||
|
||||
Scenario: Named POIs can be searched by housenumber when unknown addr:place is present
|
||||
Given the grid
|
||||
@@ -173,26 +148,26 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
When geocoding "23 Walltown, Strange Town"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
When geocoding "Walltown 23, Strange Town"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
When geocoding "Strange Town, Walltown 23"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
When geocoding "Strange Town, Walltown 23, Blue house"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
When geocoding "Strange Town, Walltown, Blue house"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Blue house, 23, Walltown, Strange Town |
|
||||
|
||||
Scenario: Named POIs can be found when unknown multi-word addr:place is present
|
||||
Given the grid
|
||||
@@ -207,14 +182,14 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
When geocoding "23 Moon Sun, Strange Town"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Blue house, 23, Moon sun, Strange Town |
|
||||
When geocoding "Blue house, Moon Sun, Strange Town"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Blue house, 23, Moon sun, Strange Town |
|
||||
|
||||
Scenario: Unnamed POIs doesn't inherit parent name when addr:place is present only in parent address
|
||||
Given the grid
|
||||
@@ -229,16 +204,14 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
When geocoding "23 Rose Street, Walltown"
|
||||
Then all results contain
|
||||
| object | display_name |
|
||||
| W1 | Rose Street, Strange Town |
|
||||
When geocoding "23 Walltown"
|
||||
Then all results contain
|
||||
| object | display_name |
|
||||
| N1 | 23, Walltown, Strange Town |
|
||||
|
||||
Scenario: Unnamed POIs does inherit parent name when unknown addr:place and addr:street is present
|
||||
Given the grid
|
||||
@@ -251,12 +224,11 @@ Feature: Creation of search terms
|
||||
| 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"
|
||||
When geocoding "23 Rose Street"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When geocoding "23 Lily Street"
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: An unknown addr:street is ignored
|
||||
@@ -270,15 +242,14 @@ Feature: Creation of search terms
|
||||
| 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"
|
||||
When geocoding "23 Rose Street"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | 23, Rose Street |
|
||||
When geocoding "23 Lily Street"
|
||||
Then exactly 0 results are returned
|
||||
|
||||
Scenario: Named POIs get unknown address tags added in the search_name table
|
||||
Scenario: Named POIs can be found through unknown address tags
|
||||
Given the grid
|
||||
| | 1 | | |
|
||||
| 10 | | | 11 |
|
||||
@@ -289,29 +260,26 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
When geocoding "Green Moss, Rose Street, Walltown"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
When geocoding "Green Moss, 26, Rose Street, Walltown"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
When geocoding "26, Rose Street, Walltown"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
When geocoding "Rose Street 26, Walltown"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
When geocoding "Walltown, Rose Street 26"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Green Moss, 26, Rose Street |
|
||||
|
||||
Scenario: Named POI doesn't inherit parent name when addr:place is present only in parent address
|
||||
Given the grid
|
||||
@@ -326,12 +294,12 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
When geocoding "Green Moss, Rose Street, Walltown"
|
||||
Then exactly 0 results are returned
|
||||
When geocoding "Green Moss, Walltown"
|
||||
Then the result set contains
|
||||
| object | display_name |
|
||||
| N1 | Green Moss, Walltown, Strange Town |
|
||||
|
||||
Scenario: Named POIs inherit address from parent
|
||||
Given the grid
|
||||
@@ -342,9 +310,10 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
When geocoding "foo, the road"
|
||||
Then all results contain
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Scenario: Some addr: tags are added to address
|
||||
Given the grid
|
||||
@@ -354,13 +323,14 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
And the places
|
||||
| osm | class | type | name | addr+city | addr+municipality | addr+suburb | geometry |
|
||||
| W1 | highway | service | the end | bonn | New York | Smalltown | 10,11 |
|
||||
When importing
|
||||
Then search_name contains
|
||||
| object | nameaddress_vector |
|
||||
| W1 | bonn, new, york, smalltown |
|
||||
When geocoding "the end, new york, bonn, smalltown"
|
||||
Then all results contain
|
||||
| object |
|
||||
| W1 |
|
||||
|
||||
Scenario: A known addr:* tag is added even if the name is unknown
|
||||
Given the grid
|
||||
@@ -369,36 +339,22 @@ Feature: Creation of search terms
|
||||
| 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 |
|
||||
And geocoding "Road, Nandu"
|
||||
Then all results contain
|
||||
| object |
|
||||
| W1 |
|
||||
|
||||
Scenario: a linked place does not show up in search name
|
||||
Given the 0.01 grid
|
||||
| 10 | | 11 |
|
||||
| | 2 | |
|
||||
| 13 | | 12 |
|
||||
Given the 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 |
|
||||
Given the places
|
||||
| osm | class | type | name | admin | geometry |
|
||||
| R13 | boundary | administrative | Roma | 9 | (10,11,12,13,10) |
|
||||
And the places
|
||||
| osm | class | type | name |
|
||||
| N2 | place | city | Cite |
|
||||
And the relations
|
||||
| id | members | tags+type |
|
||||
| 13 | N2:label | boundary |
|
||||
@@ -406,7 +362,10 @@ Feature: Creation of search terms
|
||||
Then placex contains
|
||||
| object | linked_place_id |
|
||||
| N2 | R13 |
|
||||
And search_name has no entry for N2
|
||||
When geocoding "Cite"
|
||||
Then all results contain
|
||||
| object |
|
||||
| R13 |
|
||||
|
||||
Scenario: a linked waterway does not show up in search name
|
||||
Given the grid
|
||||
@@ -424,5 +383,7 @@ Feature: Creation of search terms
|
||||
| object | linked_place_id |
|
||||
| W1 | R13 |
|
||||
| W2 | R13 |
|
||||
And search_name has no entry for W1
|
||||
And search_name has no entry for W2
|
||||
When geocoding "Rhein"
|
||||
Then all results contain
|
||||
| object |
|
||||
| R13 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Searching of house numbers
|
||||
Test for specialised treeatment of housenumbers
|
||||
|
||||
@@ -17,13 +16,13 @@ Feature: Searching of house numbers
|
||||
| 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 |
|
||||
And geocoding "45, North Road"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "North Road 45"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "North Road 45"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
|
||||
@@ -35,17 +34,17 @@ Feature: Searching of house numbers
|
||||
| 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 |
|
||||
And geocoding "45, North Road"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "North Road ④⑤"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "North Road ④⑤"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "North Road 𑁪𑁫"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "North Road 𑁪𑁫"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Examples:
|
||||
@@ -63,17 +62,17 @@ Feature: Searching of house numbers
|
||||
| osm | class | type | name | geometry |
|
||||
| W10 | highway | path | Multistr | 1,2,3 |
|
||||
When importing
|
||||
When sending search query "2 Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "2 Multistr"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "4 Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "4 Multistr"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "12 Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "12 Multistr"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Examples:
|
||||
@@ -91,21 +90,21 @@ Feature: Searching of house numbers
|
||||
| osm | class | type | name | geometry |
|
||||
| W10 | highway | path | Multistr | 1,2,3 |
|
||||
When importing
|
||||
When sending search query "2A Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "2A Multistr"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "2 a Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "2 a Multistr"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "2-A Multistr"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "2-A Multistr"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Multistr 2 A"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Multistr 2 A"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Examples:
|
||||
@@ -124,21 +123,21 @@ Feature: Searching of house numbers
|
||||
| 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 |
|
||||
When geocoding "34-10 Chester St"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "34/10 Chester St"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "34/10 Chester St"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "34 10 Chester St"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "34 10 Chester St"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "3410 Chester St"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "3410 Chester St"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| W10 |
|
||||
|
||||
Examples:
|
||||
@@ -156,21 +155,21 @@ Feature: Searching of house numbers
|
||||
| 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 |
|
||||
When geocoding "Rue Paris 45bis"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Rue Paris 45 BIS"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Rue Paris 45 BIS"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Rue Paris 45BIS"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Rue Paris 45BIS"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Rue Paris 45 bis"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Rue Paris 45 bis"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Examples:
|
||||
@@ -189,21 +188,21 @@ Feature: Searching of house numbers
|
||||
| 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 |
|
||||
When geocoding "Rue du Berger 45ter"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Rue du Berger 45 TER"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Rue du Berger 45 TER"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Rue du Berger 45TER"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Rue du Berger 45TER"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Rue du Berger 45 ter"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Rue du Berger 45 ter"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Examples:
|
||||
@@ -222,21 +221,21 @@ Feature: Searching of house numbers
|
||||
| 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 |
|
||||
When geocoding "501-H 1 Herengracht"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "501H-1 Herengracht"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "501H-1 Herengracht"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "501H1 Herengracht"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "501H1 Herengracht"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "501-H1 Herengracht"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "501-H1 Herengracht"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Examples:
|
||||
@@ -255,17 +254,17 @@ Feature: Searching of house numbers
|
||||
| osm | class | type | name | geometry |
|
||||
| W10 | highway | path | Голубинская улица | 1,2,3 |
|
||||
When importing
|
||||
When sending search query "Голубинская улица 55к3"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Голубинская улица 55к3"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Голубинская улица 55 k3"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Голубинская улица 55 k3"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending search query "Голубинская улица 55 к-3"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Голубинская улица 55 к-3"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Examples:
|
||||
@@ -282,9 +281,9 @@ Feature: Searching of house numbers
|
||||
| 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 |
|
||||
When geocoding "Chester St Warring"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
|
||||
@@ -311,11 +310,11 @@ Feature: Searching of house numbers
|
||||
| 10 | 10, 11 |
|
||||
| 20 | 20, 21 |
|
||||
When importing
|
||||
When sending search query "Ringstr 12"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Ringstr 12"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| W10 |
|
||||
When sending search query "Ringstr 13"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Ringstr 13"
|
||||
Then the result set contains
|
||||
| object |
|
||||
| W20 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Query of address interpolations
|
||||
Tests that interpolated addresses can be queried correctly
|
||||
|
||||
@@ -23,14 +22,14 @@ Feature: Query of address interpolations
|
||||
| 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 |
|
||||
When reverse geocoding at node 2
|
||||
Then the result contains
|
||||
| display_name |
|
||||
| 3, Nickway |
|
||||
When geocoding "Nickway 3"
|
||||
Then all results contain
|
||||
| object | display_name |
|
||||
| W1 | 3, Nickway |
|
||||
|
||||
|
||||
Scenario: Find interpolations with multiple numbers
|
||||
@@ -48,11 +47,11 @@ Feature: Query of address interpolations
|
||||
| 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 |
|
||||
When reverse geocoding at node 2
|
||||
Then the result contains
|
||||
| display_name | centroid!wkt |
|
||||
| 10, Nickway | 2 |
|
||||
When geocoding "Nickway 10"
|
||||
Then all results contain
|
||||
| object | display_name | centroid!wkt |
|
||||
| W1 | 10, Nickway | 2 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@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
|
||||
@@ -23,7 +22,7 @@ Feature: Searches in Japan
|
||||
Then placex contains
|
||||
| object | parent_place_id |
|
||||
| N3 | N9 |
|
||||
When sending search query "2丁目 6-2"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "2丁目 6-2"
|
||||
Then all results contain
|
||||
| object |
|
||||
| N3 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Searching linked places
|
||||
Tests that information from linked places can be searched correctly
|
||||
|
||||
@@ -20,18 +19,18 @@ Feature: Searching linked places
|
||||
Then placex contains
|
||||
| object | linked_place_id |
|
||||
| N2 | R13 |
|
||||
When sending search query "Vario"
|
||||
When geocoding "Vario"
|
||||
| namedetails |
|
||||
| 1 |
|
||||
Then results contain
|
||||
| osm | display_name | namedetails |
|
||||
| R13 | Garbo | "name": "Garbo", "name:it": "Vario" |
|
||||
When sending search query "Vario"
|
||||
Then all results contain
|
||||
| object | display_name | namedetails!dict |
|
||||
| R13 | Garbo | "name": "Garbo", "name:it": "Vario" |
|
||||
When geocoding "Vario"
|
||||
| accept-language |
|
||||
| it |
|
||||
Then results contain
|
||||
| osm | display_name |
|
||||
| R13 | Vario |
|
||||
Then all results contain
|
||||
| object | display_name |
|
||||
| R13 | Vario |
|
||||
|
||||
|
||||
Scenario: Differing names from linked places are searchable
|
||||
@@ -52,13 +51,13 @@ Feature: Searching linked places
|
||||
Then placex contains
|
||||
| object | linked_place_id |
|
||||
| N2 | R13 |
|
||||
When sending search query "Vario"
|
||||
When geocoding "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 |
|
||||
Then all results contain
|
||||
| object | display_name | namedetails!dict |
|
||||
| R13 | Garbo | "name": "Garbo", "_place_name": "Vario" |
|
||||
When geocoding "Garbo"
|
||||
Then all results contain
|
||||
| object | display_name |
|
||||
| R13 | Garbo |
|
||||
225
test/bdd/features/db/query/normalization.feature
Normal file
225
test/bdd/features/db/query/normalization.feature
Normal file
@@ -0,0 +1,225 @@
|
||||
Feature: Import and search of names
|
||||
Tests all naming related issues: normalisation,
|
||||
abbreviations, internationalisation, etc.
|
||||
|
||||
Scenario: non-latin scripts can be found
|
||||
Given the places
|
||||
| osm | class | type | name |
|
||||
| N1 | place | locality | Речицкий район |
|
||||
| N2 | place | locality | Refugio de montaña |
|
||||
| N3 | place | locality | 高槻市|
|
||||
| N4 | place | locality | الدوحة |
|
||||
When importing
|
||||
When geocoding "Речицкий район"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "Refugio de montaña"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N2 |
|
||||
When geocoding "高槻市"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N3 |
|
||||
When geocoding "الدوحة"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N4 |
|
||||
|
||||
Scenario: Case-insensitivity of search
|
||||
Given the places
|
||||
| osm | class | type | name |
|
||||
| N1 | place | locality | FooBar |
|
||||
When importing
|
||||
Then placex contains
|
||||
| object | class | type | name+name |
|
||||
| N1 | place | locality | FooBar |
|
||||
When geocoding "FooBar"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "foobar"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "fOObar"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "FOOBAR"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Scenario: Multiple spaces in name
|
||||
Given the places
|
||||
| osm | class | type | name |
|
||||
| N1 | place | locality | one two three |
|
||||
When importing
|
||||
When geocoding "one two three"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "one two three"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "one two three"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding " one two three"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
|
||||
Scenario: Special characters in name
|
||||
Given the places
|
||||
| osm | class | type | name+name:de |
|
||||
| N1 | place | locality | Jim-Knopf-Straße |
|
||||
| N2 | place | locality | Smith/Weston |
|
||||
| N3 | place | locality | space mountain |
|
||||
| N4 | place | locality | space |
|
||||
| N5 | place | locality | mountain |
|
||||
When importing
|
||||
When geocoding "Jim-Knopf-Str"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "Jim Knopf-Str"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "Jim Knopf Str"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "Jim/Knopf-Str"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "Jim-Knopfstr"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N1 |
|
||||
When geocoding "Smith/Weston"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N2 |
|
||||
When geocoding "Smith Weston"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N2 |
|
||||
When geocoding "Smith-Weston"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N2 |
|
||||
When geocoding "space mountain"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N3 |
|
||||
When geocoding "space-mountain"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N3 |
|
||||
When geocoding "space/mountain"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N3 |
|
||||
When geocoding "space\mountain"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N3 |
|
||||
When geocoding "space(mountain)"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| N3 |
|
||||
|
||||
Scenario: Landuse with name are found
|
||||
Given the grid
|
||||
| 1 | 2 |
|
||||
| 3 | |
|
||||
Given the places
|
||||
| osm | class | type | name | geometry |
|
||||
| R1 | natural | meadow | landuse1 | (1,2,3,1) |
|
||||
| R2 | landuse | industrial | landuse2 | (2,3,1,2) |
|
||||
When importing
|
||||
When geocoding "landuse1"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| R1 |
|
||||
When geocoding "landuse2"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| R2 |
|
||||
|
||||
Scenario: Postcode boundaries without ref
|
||||
Given the grid with origin FR
|
||||
| | 2 | |
|
||||
| 1 | | 3 |
|
||||
Given the places
|
||||
| osm | class | type | postcode | geometry |
|
||||
| R1 | boundary | postal_code | 123-45 | (1,2,3,1) |
|
||||
When importing
|
||||
When geocoding "123-45"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| R1 |
|
||||
|
||||
Scenario Outline: Housenumbers with special characters are found
|
||||
Given the grid
|
||||
| 1 | | | | 2 |
|
||||
| | | 9 | | |
|
||||
And the places
|
||||
| osm | class | type | name | geometry |
|
||||
| W1 | highway | primary | Main St | 1,2 |
|
||||
And the places
|
||||
| osm | class | type | housenr | geometry |
|
||||
| N1 | building | yes | <nr> | 9 |
|
||||
When importing
|
||||
And geocoding "Main St <nr>"
|
||||
Then result 0 contains
|
||||
| object | display_name |
|
||||
| N1 | <nr>, Main St |
|
||||
|
||||
Examples:
|
||||
| nr |
|
||||
| 1 |
|
||||
| 3456 |
|
||||
| 1 a |
|
||||
| 56b |
|
||||
| 1 A |
|
||||
| 2號 |
|
||||
| 1Б |
|
||||
| 1 к1 |
|
||||
| 23-123 |
|
||||
|
||||
Scenario Outline: Housenumbers in lists are found
|
||||
Given the grid
|
||||
| 1 | | | | 2 |
|
||||
| | | 9 | | |
|
||||
And the places
|
||||
| osm | class | type | name | geometry |
|
||||
| W1 | highway | primary | Main St | 1,2 |
|
||||
And the places
|
||||
| osm | class | type | housenr | geometry |
|
||||
| N1 | building | yes | <nr-list> | 9 |
|
||||
When importing
|
||||
And geocoding "Main St <nr>"
|
||||
Then result 0 contains
|
||||
| object | display_name |
|
||||
| N1 | <nr-list>, Main St |
|
||||
|
||||
Examples:
|
||||
| nr-list | nr |
|
||||
| 1,2,3 | 1 |
|
||||
| 1,2,3 | 2 |
|
||||
| 1, 2, 3 | 3 |
|
||||
| 45 ;67;3 | 45 |
|
||||
| 45 ;67;3 | 67 |
|
||||
| 1a;1k | 1a |
|
||||
| 1a;1k | 1k |
|
||||
| 34/678 | 34 |
|
||||
| 34/678 | 678 |
|
||||
| 34/678 | 34/678 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Querying fo postcode variants
|
||||
|
||||
Scenario: Postcodes in Singapore (6-digit postcode)
|
||||
@@ -8,10 +7,10 @@ Feature: Querying fo postcode variants
|
||||
| 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 |
|
||||
When geocoding "399174"
|
||||
Then result 0 contains
|
||||
| type | display_name |
|
||||
| postcode | 399174, Singapore |
|
||||
|
||||
|
||||
Scenario Outline: Postcodes in the Netherlands (mixed postcode with spaces)
|
||||
@@ -21,14 +20,14 @@ Feature: Querying fo postcode variants
|
||||
| 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 |
|
||||
When geocoding "3993 DX"
|
||||
Then result 0 contains
|
||||
| type | display_name |
|
||||
| postcode | 3993 DX, Nederland |
|
||||
When geocoding "3993dx"
|
||||
Then result 0 contains
|
||||
| type | display_name |
|
||||
| postcode | 3993 DX, Nederland |
|
||||
|
||||
Examples:
|
||||
| postcode |
|
||||
@@ -44,10 +43,10 @@ Feature: Querying fo postcode variants
|
||||
| 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 |
|
||||
When geocoding "399174"
|
||||
Then result 0 contains
|
||||
| type | display_name |
|
||||
| postcode | 399174, Singapore |
|
||||
|
||||
|
||||
Scenario Outline: Postcodes in Andorra (with country code)
|
||||
@@ -57,14 +56,14 @@ Feature: Querying fo postcode variants
|
||||
| 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 |
|
||||
When geocoding "675"
|
||||
Then result 0 contains
|
||||
| type | display_name |
|
||||
| postcode | AD675, Andorra |
|
||||
When geocoding "AD675"
|
||||
Then result 0 contains
|
||||
| type | display_name |
|
||||
| postcode | AD675, Andorra |
|
||||
|
||||
Examples:
|
||||
| postcode |
|
||||
@@ -80,15 +79,15 @@ Feature: Querying fo postcode variants
|
||||
| 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
|
||||
| country_code | postcode | geometry!wkt |
|
||||
| gb | EH4 7EA | country:gb |
|
||||
| gb | E4 7EA | country:gb |
|
||||
When geocoding "EH4 7EA"
|
||||
Then result 0 contains
|
||||
| type | display_name |
|
||||
| postcode | EH4 7EA, United Kingdom |
|
||||
When sending search query "E4 7EA"
|
||||
Then results contain
|
||||
When geocoding "E4 7EA"
|
||||
Then result 0 contains
|
||||
| type | display_name |
|
||||
| postcode | E4 7EA, United Kingdom |
|
||||
|
||||
@@ -102,9 +101,9 @@ Feature: Querying fo postcode variants
|
||||
| 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 |
|
||||
| country_code | postcode |
|
||||
| de | 12345 |
|
||||
When geocoding "12345, de"
|
||||
Then result 0 contains
|
||||
| object |
|
||||
| R23 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Reverse searches
|
||||
Test results of reverse queries
|
||||
|
||||
@@ -12,11 +11,11 @@ Feature: Reverse searches
|
||||
| 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 |
|
||||
And reverse geocoding 1.0001,1.0001
|
||||
Then the result contains
|
||||
| object |
|
||||
| N1 |
|
||||
When sending v1/reverse at 1.0003,1.0001
|
||||
Then results contain
|
||||
| osm |
|
||||
When reverse geocoding 1.0003,1.0001
|
||||
Then the result contains
|
||||
| object |
|
||||
| W1 |
|
||||
@@ -1,4 +1,3 @@
|
||||
@DB
|
||||
Feature: Searching of simple objects
|
||||
Testing simple stuff
|
||||
|
||||
@@ -7,32 +6,10 @@ Feature: Searching of simple objects
|
||||
| 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 |
|
||||
And geocoding "Foo"
|
||||
Then result 0 contains
|
||||
| object | category | type | centroid!wkt |
|
||||
| N1 | place | village | 10 -10 |
|
||||
|
||||
# github #1763
|
||||
Scenario: Correct translation of highways under construction
|
||||
@@ -44,8 +21,8 @@ Feature: Searching of simple objects
|
||||
| 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
|
||||
And geocoding "Bean"
|
||||
Then result 0 contains in field address
|
||||
| amenity | road |
|
||||
| Bean | The build |
|
||||
|
||||
@@ -57,11 +34,11 @@ Feature: Searching of simple objects
|
||||
| osm | class | type | name | housenr |
|
||||
| N20 | amenity | restaurant | Red Way | 34 |
|
||||
When importing
|
||||
And sending search query "Wood Street 45"
|
||||
And geocoding "Wood Street 45"
|
||||
Then exactly 0 results are returned
|
||||
When sending search query "Red Way 34"
|
||||
Then results contain
|
||||
| osm |
|
||||
When geocoding "Red Way 34"
|
||||
Then all results contain
|
||||
| object |
|
||||
| N20 |
|
||||
|
||||
Scenario: when the housenumber is missing the street is still returned
|
||||
@@ -71,12 +48,11 @@ Feature: Searching of simple objects
|
||||
| osm | class | type | name | geometry |
|
||||
| W1 | highway | residential | Wood Street | 1, 2 |
|
||||
When importing
|
||||
And sending search query "Wood Street"
|
||||
Then results contain
|
||||
| osm |
|
||||
And geocoding "Wood Street"
|
||||
Then all results contain
|
||||
| object |
|
||||
| W1 |
|
||||
|
||||
|
||||
Scenario Outline: Special cased american states will be found
|
||||
Given the grid
|
||||
| 1 | | 2 |
|
||||
@@ -90,15 +66,15 @@ Feature: Searching of simple objects
|
||||
| N2 | place | town | <city> | 10 |
|
||||
| N3 | place | city | <city> | country:ca |
|
||||
When importing
|
||||
And sending search query "<city>, <state>"
|
||||
Then results contain
|
||||
| osm |
|
||||
And geocoding "<city>, <state>"
|
||||
Then all results contain
|
||||
| object |
|
||||
| N2 |
|
||||
When sending search query "<city>, <ref>"
|
||||
When geocoding "<city>, <ref>"
|
||||
| accept-language |
|
||||
| en |
|
||||
Then results contain
|
||||
| osm |
|
||||
Then all results contain
|
||||
| object |
|
||||
| N2 |
|
||||
|
||||
Examples:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user