]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge pull request #2142 from lonvia/update-bdd-api-tests
authorSarah Hoffmann <lonvia@denofr.de>
Mon, 18 Jan 2021 14:40:50 +0000 (15:40 +0100)
committerGitHub <noreply@github.com>
Mon, 18 Jan 2021 14:40:50 +0000 (15:40 +0100)
Update BDD API tests

12 files changed:
lib/SearchDescription.php
lib/output.php
test/bdd/api/details/language.feature [new file with mode: 0644]
test/bdd/api/details/params.feature
test/bdd/api/details/simple.feature
test/bdd/api/reverse/params.feature
test/bdd/api/reverse/simple.feature
test/bdd/api/search/queries.feature
test/bdd/api/search/simple.feature
test/bdd/steps/http_responses.py
test/bdd/steps/steps_api_queries.py
test/php/Nominatim/OutputTest.php [deleted file]

index f010606355144c418de9162747c8fbf104671c56..2053082f6bbff4a13bd6a5ba6c08bc89366e0c38 100644 (file)
@@ -86,18 +86,6 @@ class SearchDescription
         $this->sType = $sType;
     }
 
-    /**
-     * Check if this might be a full address search.
-     *
-     * @return bool True if the search contains name, address and housenumber.
-     */
-    public function looksLikeFullAddress()
-    {
-        return (!empty($this->aName))
-               && (!empty($this->aAddress) || $this->sCountryCode)
-               && preg_match('/[0-9]+/', $this->sHouseNumber);
-    }
-
     /**
      * Check if any operator is set.
      *
@@ -1027,7 +1015,7 @@ class SearchDescription
                 'Name terms (stop words)' => $this->aNameNonSearch,
                 'Address terms' => $this->aAddress,
                 'Address terms (stop words)' => $this->aAddressNonSearch,
-                'Address terms (full words)' => $this->aFullNameAddress,
+                'Address terms (full words)' => $this->aFullNameAddress ?? '',
                 'Special search' => $this->iOperator,
                 'Class' => $this->sClass,
                 'Type' => $this->sType,
@@ -1039,7 +1027,7 @@ class SearchDescription
     public function dumpAsHtmlTableRow(&$aWordIDs)
     {
         $kf = function ($k) use (&$aWordIDs) {
-            return $aWordIDs[$k];
+            return $aWordIDs[$k] ?? '['.$k.']';
         };
 
         echo '<tr>';
index 823a6631e08cfeab2b134d803784cf77beb985d8..8de8157623516db94c4ca3c8ca8df303326961a0 100644 (file)
@@ -16,58 +16,3 @@ function formatOSMType($sType, $bIncludeExternal = true)
 
     return '';
 }
-
-function osmLink($aFeature, $sRefText = false)
-{
-    $sOSMType = formatOSMType($aFeature['osm_type'], false);
-    if ($sOSMType) {
-        return '<a href="//www.openstreetmap.org/'.$sOSMType.'/'.$aFeature['osm_id'].'">'.$sOSMType.' '.($sRefText?$sRefText:$aFeature['osm_id']).'</a>';
-    }
-    return '';
-}
-
-function wikipediaLink($aFeature)
-{
-    if ($aFeature['wikipedia']) {
-        list($sLanguage, $sArticle) = explode(':', $aFeature['wikipedia']);
-        return '<a href="https://'.$sLanguage.'.wikipedia.org/wiki/'.urlencode($sArticle).'" target="_blank">'.$aFeature['wikipedia'].'</a>';
-    }
-    return '';
-}
-
-function detailsLink($aFeature, $sTitle = false, $sExtraProperties = false)
-{
-    if (!$aFeature['place_id']) return '';
-
-    $sHtml = '<a ';
-    if ($sExtraProperties) {
-        $sHtml .= $sExtraProperties.' ';
-    }
-
-    $sHtml .= 'href="details.php?place_id='.$aFeature['place_id'].'">'.($sTitle?$sTitle:$aFeature['place_id']).'</a>';
-
-    return $sHtml;
-}
-
-function detailsPermaLink($aFeature, $sRefText = false, $sExtraProperties = false)
-{
-    $sOSMType = formatOSMType($aFeature['osm_type'], false);
-
-    if ($sOSMType) {
-        $sHtml = '<a ';
-        if ($sExtraProperties) {
-            $sHtml .= $sExtraProperties.' ';
-        }
-        $sHtml .= 'href="details.php?osmtype='.$aFeature['osm_type']
-                  .'&osmid='.$aFeature['osm_id'].'&class='.$aFeature['class'].'">';
-
-        if ($sRefText) {
-            $sHtml .= $sRefText.'</a>';
-        } else {
-            $sHtml .= $sOSMType.' '.$aFeature['osm_id'].'</a>';
-        }
-
-        return $sHtml;
-    }
-    return detailsLink($aFeature, $sRefText, $sExtraProperties);
-}
diff --git a/test/bdd/api/details/language.feature b/test/bdd/api/details/language.feature
new file mode 100644 (file)
index 0000000..6611c81
--- /dev/null
@@ -0,0 +1,62 @@
+@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 |
index 03b91d291d2b1ebc45a728e550342fc1161512f6..87c3356c8a34d01b43c2d7f25c24647721b84b72 100644 (file)
@@ -8,14 +8,15 @@ Feature: Object details
         And result has attributes geometry
         And result has not attributes keywords,address,linked_places,parentof
 
-    Scenario: JSON Details with keywords
+    Scenario: JSON Details with pretty printing
         When sending json details query for W297699560
-            | keywords |
-            | 1 |
+            | pretty |
+            | 1      |
         Then the result is valid json
-        And result has attributes keywords
+        And result has attributes geometry
+        And result has not attributes keywords,address,linked_places,parentof
 
-    Scenario: JSON Details with addressdetails
+     Scenario: JSON Details with addressdetails
         When sending json details query for W297699560
             | addressdetails |
             | 1 |
@@ -36,22 +37,46 @@ Feature: Object details
         Then the result is valid json
         And result has attributes hierarchy
 
-    Scenario: JSON Details with linkedplaces
-        When sending json details query for R123924
-            | linkedplaces |
-            | 1 |
+    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: HTML Details with keywords
+     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
+
+    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
 
     Examples:
             | osmid |
             | W297699560 |
             | W243055645 |
             | W243055716 |
+            | W43327921  |
 
 
index 906c4ce5e9f0e6e1b69be6c365205e57ea7f6a21..a9b6d6a70553d933e5c3acd0ee01e1a2145e3b10 100644 (file)
@@ -2,36 +2,54 @@
 Feature: Object details
     Check details page for correctness
 
+    Scenario: Details by place ID
+        When sending details query for 107077
+        Then the result is valid json
+        And results contain
+            | place_id |
+            | 107077   |
+
     Scenario Outline: Details via OSM id
-        When sending <format> details query for <object>
-        Then the result is valid <format>
+        When sending details query for <type><id>
+        Then the result is valid json
+        And results contain
+            | osm_type | osm_id |
+            | <type>   | <id> |
 
     Examples:
-     | format | object |
-     | json | 107077 |
-     | json | N5484325405 |
-     | json | W43327921 |
-     | json | R123924 |
+     | type | id |
+     | N    | 5484325405 |
+     | W    | 43327921 |
+     | R    | 123924 |
+
+     Scenario: Details for interpolation way just return the dependent street
+        When sending details query for W1
+        Then the result is valid json
+        And results contain
+            | category |
+            | highway |
+
+    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 |
+     | natural |
+     | mountain_pass |
 
     Scenario Outline: Details via unknown OSM id
-        When sending <format> details query for <object>
+        When sending details query for <object>
         Then a HTTP 400 is returned
 
     Examples:
-      | format | object |
-      | json | 1 |
-      | json | R1 |
-
-    Scenario: Details with keywords
-        When sending details query for W43327921
-            | keywords |
-            | 1 |
-        Then the result is valid json
+      | object |
+      | 1 |
+      | R1 |
+      | N300209696:highway |
 
-    # ticket #1343
-    Scenario: Details of a country with keywords
-        When sending details query for R1155955
-            | keywords |
-            | 1 |
-        Then the result is valid json
 
index 374272d0594f37526f85ca17a1e9dabff0ba5186..d6ef3794bfd514d6ec3861a5ed0dd0d0a39a7b11 100644 (file)
@@ -25,6 +25,39 @@ Feature: Parameters for Reverse API
       | -45.3,;   |
       | gkjd,50   |
 
+    Scenario Outline: Zoom levels between 4 and 18 are allowed
+        When sending reverse coordinates 47.14122383,9.52169581334
+          | zoom |
+          | <zoom> |
+        Then exactly 1 result is returned
+        And result addresses contain
+          | country_code |
+          | li |
+
+    Examples:
+      | zoom |
+      | 4 |
+      | 5 |
+      | 6 |
+      | 7 |
+      | 8 |
+      | 9 |
+      | 10 |
+      | 11 |
+      | 12 |
+      | 13 |
+      | 14 |
+      | 15 |
+      | 16 |
+      | 17 |
+      | 18 |
+
+    Scenario: Non-numerical zoom levels return an error
+        When sending reverse coordinates 47.14122383,9.52169581334
+          | zoom |
+          | adfe |
+        Then a HTTP 400 is returned
+
     Scenario Outline: Reverse Geocoding with extratags
         When sending <format> reverse coordinates 47.1395013150811,9.522098077031046
           | extratags |
index 78bd47a7e6db6858aa9686ed41ab7806626589c7..4da311e78a9270b9250ffabe5400b1d68fa2e6df 100644 (file)
@@ -131,3 +131,7 @@ Feature: Simple Reverse Tests
      | 48.966   | 8.448.2 |
      | Nan      | 8.448 |
      | 48.966   | Nan |
+
+     Scenario: Reverse Debug output returns no errors
+        When sending debug reverse coordinates 47.11,9.57
+        Then a HTTP 200 is returned
index 3a62c5811831b88930a023e6e1b8b0c2ab7fae4e..ea353f4568ad46f83f8d62d7511ef400e7234e67 100644 (file)
@@ -80,6 +80,15 @@ Feature: Search queries
           | 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
@@ -114,6 +123,19 @@ Feature: Search queries
           | class    | type |
           | leisure | firepit |
 
+    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
@@ -146,6 +168,14 @@ Feature: Search queries
             | 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
@@ -182,3 +212,7 @@ Feature: Search queries
        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
index 603627b1e828db076462da83bd3d2cdd66734f82..b9323c5a62d695734cf354176a661bd7b4b2f801 100644 (file)
@@ -30,15 +30,10 @@ Feature: Simple Tests
 
     Examples:
      | parameter        | value |
-     | addressdetails   | 1 |
      | addressdetails   | 0 |
-     | polygon_text     | 1 |
      | polygon_text     | 0 |
-     | polygon_kml      | 1 |
      | polygon_kml      | 0 |
-     | polygon_geojson  | 1 |
      | polygon_geojson  | 0 |
-     | polygon_svg      | 1 |
      | polygon_svg      | 0 |
      | accept-language  | de,en |
      | countrycodes     | li |
@@ -48,9 +43,7 @@ Feature: Simple Tests
      | limit            | 1000 |
      | dedupe           | 1 |
      | dedupe           | 0 |
-     | extratags        | 1 |
      | extratags        | 0 |
-     | namedetails      | 1 |
      | namedetails      | 0 |
 
     Scenario: Search with invalid output format
@@ -180,13 +173,16 @@ Feature: Simple Tests
           | 234 |
         Then the result is valid xml
 
-    Scenario: Empty JSON search
-        When sending json search query "YHlERzzx"
+    Scenario Outline: Empty search
+        When sending <format> search query "YHlERzzx"
         Then exactly 0 results are returned
 
-    Scenario: Empty JSONv2 search
-        When sending jsonv2 search query "Flubb XdfESSaZx"
-        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"
@@ -199,3 +195,16 @@ Feature: Simple Tests
         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 |
index 1e7da93d69bfd7dfc58060ae139065c802543063..beafcd9e1ee16773294f8279d8dd26ce080a3d6e 100644 (file)
@@ -50,7 +50,7 @@ class GenericResponse:
         self.result = []
         self.header = dict()
 
-        if errorcode == 200:
+        if errorcode == 200 and fmt != 'debug':
             getattr(self, '_parse_' + fmt)()
 
     def _parse_json(self):
index fd263af72c5564581f1f46fe56dc462c16c19fa1..ad4a8515af55d39ea62a9570d76d91084f69fa22 100644 (file)
@@ -12,6 +12,7 @@ from urllib.parse import urlencode
 from utils import run_script
 from http_responses import GenericResponse, SearchResponse, ReverseResponse, StatusResponse
 from check_functions import Bbox
+from table_compare import NominatimID
 
 LOG = logging.getLogger(__name__)
 
@@ -78,7 +79,7 @@ def query_cmd(context, query, dups):
     context.response = SearchResponse(outp, 'json')
 
 def send_api_query(endpoint, params, fmt, context):
-    if fmt is not None:
+    if fmt is not None and fmt.strip() != 'debug':
         params['format'] = fmt.strip()
     if context.table:
         if context.table.headings[0] == 'param':
@@ -147,6 +148,8 @@ def website_search_request(context, fmt, query, addr):
         params['q'] = query
     if addr is not None:
         params['addressdetails'] = '1'
+    if fmt and fmt.strip() == 'debug':
+        params['debug'] = '1'
 
     outp, status = send_api_query('search', params, fmt, context)
 
@@ -159,6 +162,8 @@ def website_reverse_request(context, fmt, lat, lon):
         params['lat'] = lat
     if lon is not None:
         params['lon'] = lon
+    if fmt and fmt.strip() == 'debug':
+        params['debug'] = '1'
 
     outp, status = send_api_query('reverse', params, fmt, context)
 
@@ -168,8 +173,11 @@ def website_reverse_request(context, fmt, lat, lon):
 def website_details_request(context, fmt, query):
     params = {}
     if query[0] in 'NWR':
-        params['osmtype'] = query[0]
-        params['osmid'] = query[1:]
+        nid = NominatimID(query)
+        params['osmtype'] = nid.typ
+        params['osmid'] = nid.oid
+        if nid.cls:
+            params['class'] = nid.cls
     else:
         params['place_id'] = query
     outp, status = send_api_query('details', params, fmt, context)
@@ -199,7 +207,8 @@ def validate_result_number(context, operator, number):
 
 @then(u'a HTTP (?P<status>\d+) is returned')
 def check_http_return_status(context, status):
-    assert context.response.errorcode == int(status)
+    assert context.response.errorcode == int(status), \
+           "Return HTTP status is {}.".format(context.response.errorcode)
 
 @then(u'the page contents equals "(?P<text>.+)"')
 def check_page_content_equals(context, text):
@@ -232,9 +241,13 @@ def check_header_attr(context):
 def check_header_no_attr(context, neg, attrs):
     for attr in attrs.split(','):
         if neg:
-            assert attr not in context.response.header
+            assert attr not in context.response.header, \
+                   "Unexpected attribute {}. Full response:\n{}".format(
+                       attr, json.dumps(context.response.header, sort_keys=True, indent=2))
         else:
-            assert attr in context.response.header
+            assert attr in context.response.header, \
+                   "No attribute {}. Full response:\n{}".format(
+                       attr, json.dumps(context.response.header, sort_keys=True, indent=2))
 
 @then(u'results contain')
 def step_impl(context):
@@ -255,9 +268,13 @@ def validate_attributes(context, lid, neg, attrs):
     for i in idx:
         for attr in attrs.split(','):
             if neg:
-                assert attr not in context.response.result[i]
+                assert attr not in context.response.result[i],\
+                       "Unexpected attribute {}. Full response:\n{}".format(
+                           attr, json.dumps(context.response.result[i], sort_keys=True, indent=2))
             else:
-                assert attr in context.response.result[i]
+                assert attr in context.response.result[i], \
+                       "No attribute {}. Full response:\n{}".format(
+                           attr, json.dumps(context.response.result[i], sort_keys=True, indent=2))
 
 @then(u'result addresses contain')
 def step_impl(context):
diff --git a/test/php/Nominatim/OutputTest.php b/test/php/Nominatim/OutputTest.php
deleted file mode 100644 (file)
index cbfebb7..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-namespace Nominatim;
-
-require_once(CONST_LibDir.'/output.php');
-
-class OutputTest extends \PHPUnit\Framework\TestCase
-{
-    public function testDetailsPermaLinkNode()
-    {
-        $aFeature = array('osm_type' => 'N', 'osm_id'=> 38274, 'class' => 'place');
-        $this->assertSame(
-            detailsPermaLink($aFeature),
-            '<a href="details.php?osmtype=N&osmid=38274&class=place">node 38274</a>'
-        );
-    }
-
-    public function testDetailsPermaLinkWay()
-    {
-        $aFeature = array('osm_type' => 'W', 'osm_id'=> 65, 'class' => 'highway');
-        $this->assertSame(
-            detailsPermaLink($aFeature),
-            '<a href="details.php?osmtype=W&osmid=65&class=highway">way 65</a>'
-        );
-    }
-
-    public function testDetailsPermaLinkRelation()
-    {
-        $aFeature = array('osm_type' => 'R', 'osm_id'=> 9908, 'class' => 'waterway');
-        $this->assertSame(
-            detailsPermaLink($aFeature),
-            '<a href="details.php?osmtype=R&osmid=9908&class=waterway">relation 9908</a>'
-        );
-    }
-
-    public function testDetailsPermaLinkTiger()
-    {
-        $aFeature = array('osm_type' => 'T', 'osm_id'=> 2, 'place_id' => 334);
-        $this->assertSame(
-            detailsPermaLink($aFeature, 'foo'),
-            '<a href="details.php?place_id=334">foo</a>'
-        );
-    }
-
-    public function testDetailsPermaLinkInterpolation()
-    {
-        $aFeature = array('osm_type' => 'I', 'osm_id'=> 400, 'place_id' => 3);
-        $this->assertSame(
-            detailsPermaLink($aFeature, 'foo'),
-            '<a href="details.php?place_id=3">foo</a>'
-        );
-    }
-
-    public function testDetailsPermaLinkWithExtraPropertiesNode()
-    {
-        $aFeature = array('osm_type' => 'N', 'osm_id'=> 2, 'class' => 'amenity');
-        $this->assertSame(
-            detailsPermaLink($aFeature, 'something', 'class="xtype"'),
-            '<a class="xtype" href="details.php?osmtype=N&osmid=2&class=amenity">something</a>'
-        );
-    }
-
-    public function testDetailsPermaLinkWithExtraPropertiesTiger()
-    {
-        $aFeature = array('osm_type' => 'T', 'osm_id'=> 5, 'place_id' => 46);
-        $this->assertSame(
-            detailsPermaLink($aFeature, 'something', 'class="xtype"'),
-            '<a class="xtype" href="details.php?place_id=46">something</a>'
-        );
-    }
-}