From e56782e8ac859b676aaeeae406b1cb1304d776d8 Mon Sep 17 00:00:00 2001 From: Lyn Elisa Goltz Date: Mon, 2 Jul 2018 12:30:58 +0200 Subject: [PATCH] #8 - set bbox parameter as described in ATS and the extent of the collection and assured that test are not skipped if optional properties are missing --- .../collections/GetFeaturesOperation.java | 116 ++++++++---------- .../org/opengis/cite/wfs30/util/BBox.java | 64 ++++++++++ .../opengis/cite/wfs30/util/JsonUtils.java | 31 +++++ .../collections/GetFeaturesOperationIT.java | 11 +- .../cite/wfs30/util/JsonUtilsTest.java | 16 +++ 5 files changed, 172 insertions(+), 66 deletions(-) create mode 100644 src/main/java/org/opengis/cite/wfs30/util/BBox.java diff --git a/src/main/java/org/opengis/cite/wfs30/collections/GetFeaturesOperation.java b/src/main/java/org/opengis/cite/wfs30/collections/GetFeaturesOperation.java index f0fd167a..0d3eff95 100644 --- a/src/main/java/org/opengis/cite/wfs30/collections/GetFeaturesOperation.java +++ b/src/main/java/org/opengis/cite/wfs30/collections/GetFeaturesOperation.java @@ -10,6 +10,7 @@ import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithoutRelOrType; import static org.opengis.cite.wfs30.util.JsonUtils.findUnsupportedTypes; import static org.opengis.cite.wfs30.util.JsonUtils.hasProperty; +import static org.opengis.cite.wfs30.util.JsonUtils.parseExtent; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; @@ -20,6 +21,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -27,6 +29,7 @@ import org.opengis.cite.wfs30.SuiteAttribute; import org.opengis.cite.wfs30.openapi3.OpenApiUtils; import org.opengis.cite.wfs30.openapi3.TestPoint; +import org.opengis.cite.wfs30.util.BBox; import org.testng.ITestContext; import org.testng.SkipException; import org.testng.annotations.BeforeClass; @@ -79,23 +82,26 @@ public Object[][] collectionItemUrisWithLimits( ITestContext testContext ) { } @DataProvider(name = "collectionItemUrisWithBboxes") - public Object[][] collectionItemUrisWithBboxes( ITestContext testContext ) { - // TODO: find example with values in extend - Object[][] collectionsData = new Object[collections.size() * 5][]; + public Iterator collectionItemUrisWithBboxes( ITestContext testContext ) { + List collectionsWithBboxes = new ArrayList<>(); int i = 0; for ( Map collection : collections ) { - // These should include test cases which cross the - // meridian, - collectionsData[i++] = new Object[] { collection, new BBox( -1.5, 50.0, 1.5, 53.0 ) }; - // equator, - collectionsData[i++] = new Object[] { collection, new BBox( -80.0, -5.0, -70.0, 5.0 ) }; - // 180 longitude, - collectionsData[i++] = new Object[] { collection, new BBox( 177.0, 65.0, -177.0, 70.0 ) }; - // and polar regions. - collectionsData[i++] = new Object[] { collection, new BBox( -70.0, -20.0, -70.0, 160.0 ) }; - collectionsData[i++] = new Object[] { collection, new BBox( 70.0, -20.0, 70.0, 160.0 ) }; + BBox extent = parseExtent( collection ); + if ( extent != null ) { + collectionsWithBboxes.add( new Object[] { collection, extent } ); + // These should include test cases which cross the + // meridian, + collectionsWithBboxes.add( new Object[] { collection, new BBox( -1.5, 50.0, 1.5, 53.0 ) } ); + // equator, + collectionsWithBboxes.add( new Object[] { collection, new BBox( -80.0, -5.0, -70.0, 5.0 ) } ); + // 180 longitude, + collectionsWithBboxes.add( new Object[] { collection, new BBox( 177.0, 65.0, -177.0, 70.0 ) } ); + // and polar regions. + collectionsWithBboxes.add( new Object[] { collection, new BBox( -70.0, -20.0, -70.0, 160.0 ) } ); + collectionsWithBboxes.add( new Object[] { collection, new BBox( 70.0, -20.0, 70.0, 160.0 ) } ); + } } - return collectionsData; + return collectionsWithBboxes.iterator(); } @DataProvider(name = "collectionItemUrisWithTimes") @@ -243,7 +249,8 @@ public void validateGetFeaturesOperationResponse_property_timeStamp( Map collection, int assertTrue( numberOfFeatures <= limit, "Number of features for collection with name " + collectionName + " is unexpected (was " + numberOfFeatures + "), expected are " + limit + " or less" ); - assertTimeStamp( collectionName, jsonPath, timeStampBeforeResponse, timeStampAfterResponse ); - assertNumberReturned( collectionName, jsonPath ); - assertNumberMatched( collectionName, jsonPath ); + assertTimeStamp( collectionName, jsonPath, timeStampBeforeResponse, timeStampAfterResponse, false ); + assertNumberReturned( collectionName, jsonPath, false ); + assertNumberMatched( collectionName, jsonPath, false ); } /** @@ -507,9 +514,9 @@ public void validateBboxParameter_requests( Map collection, BBox Date timeStampAfterResponse = new Date(); JsonPath jsonPath = response.jsonPath(); - assertTimeStamp( collectionName, jsonPath, timeStampBeforeResponse, timeStampAfterResponse ); - assertNumberReturned( collectionName, jsonPath ); - assertNumberMatched( collectionName, jsonPath ); + assertTimeStamp( collectionName, jsonPath, timeStampBeforeResponse, timeStampAfterResponse, false ); + assertNumberReturned( collectionName, jsonPath, false ); + assertNumberMatched( collectionName, jsonPath, false ); // TODO: assert returned features } @@ -600,18 +607,21 @@ public void validateTimeParameter_requests( Map collection, Stri Date timeStampAfterResponse = new Date(); JsonPath jsonPath = response.jsonPath(); - assertTimeStamp( collectionName, jsonPath, timeStampBeforeResponse, timeStampAfterResponse ); - assertNumberReturned( collectionName, jsonPath ); - assertNumberMatched( collectionName, jsonPath ); + assertTimeStamp( collectionName, jsonPath, timeStampBeforeResponse, timeStampAfterResponse, false ); + assertNumberReturned( collectionName, jsonPath, false ); + assertNumberMatched( collectionName, jsonPath, false ); // TODO: assert returned features } private void assertTimeStamp( String collectionName, JsonPath jsonPath, Date timeStampBeforeResponse, - Date timeStampAfterResponse ) { + Date timeStampAfterResponse, boolean skipIfNoTimeStamp ) { String timeStamp = jsonPath.getString( "timeStamp" ); if ( timeStamp == null ) - throw new SkipException( "Property timeStamp is not set in collection items '" + collectionName + "'" ); + if ( skipIfNoTimeStamp ) + throw new SkipException( "Property timeStamp is not set in collection items '" + collectionName + "'" ); + else + return; Date date = parseAsDate( timeStamp ); assertTrue( date.before( timeStampAfterResponse ), @@ -623,23 +633,30 @@ private void assertTimeStamp( String collectionName, JsonPath jsonPath, Date tim + ") but was '" + timeStamp + "'" ); } - private void assertNumberReturned( String collectionName, JsonPath jsonPath ) { - if ( !hasProperty( "numberReturned", jsonPath ) ) { - throw new SkipException( "Property numberReturned is not set in collection items '" + collectionName + "'" ); - } - int numberReturned = jsonPath.getInt( "numberReturned" ); + private void assertNumberReturned( String collectionName, JsonPath jsonPath, boolean skipIfNoNumberReturned ) { + if ( !hasProperty( "numberReturned", jsonPath ) ) + if ( skipIfNoNumberReturned ) + throw new SkipException( "Property numberReturned is not set in collection items '" + collectionName + + "'" ); + else + return; + int numberReturned = jsonPath.getInt( "numberReturned" ); int numberOfFeatures = jsonPath.getList( "features" ).size(); assertEquals( numberReturned, numberOfFeatures, "Value of numberReturned (" + numberReturned + ") does not match the number of features in the response (" + numberOfFeatures + ")" ); } - private void assertNumberMatched( String collectionName, JsonPath jsonPath ) + private void assertNumberMatched( String collectionName, JsonPath jsonPath, boolean skipIfNoNumberMatched ) throws URISyntaxException { - if ( !hasProperty( "numberMatched", jsonPath ) ) { - throw new SkipException( "Property numberMatched is not set in collection items '" + collectionName + "'" ); - } + if ( !hasProperty( "numberMatched", jsonPath ) ) + if ( skipIfNoNumberMatched ) + throw new SkipException( "Property numberMatched is not set in collection items '" + collectionName + + "'" ); + else + return; + int numberMatched = jsonPath.getInt( "numberMatched" ); int numberOfAllReturnedFeatures = collectNumberOfAllReturnedFeatures( jsonPath ); assertEquals( numberMatched, numberOfAllReturnedFeatures, @@ -729,29 +746,4 @@ public JsonPath jsonPath() { } } - private class BBox { - double minX; - - double minY; - - double maxX; - - double maxY; - - private BBox( double minX, double minY, double maxX, double maxY ) { - this.minX = minX; - this.minY = minY; - this.maxX = maxX; - this.maxY = maxY; - } - - private String asQueryParameter() { - StringBuilder sb = new StringBuilder(); - sb.append( minX ).append( "," ); - sb.append( minY ).append( "," ); - sb.append( maxX ).append( "," ); - sb.append( maxY ); - return sb.toString(); - } - } } diff --git a/src/main/java/org/opengis/cite/wfs30/util/BBox.java b/src/main/java/org/opengis/cite/wfs30/util/BBox.java new file mode 100644 index 00000000..ed6e5167 --- /dev/null +++ b/src/main/java/org/opengis/cite/wfs30/util/BBox.java @@ -0,0 +1,64 @@ +package org.opengis.cite.wfs30.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Locale; + +/** + * @author Lyn Goltz + */ +public class BBox { + + private static final String PATTERN = "###.0000000"; + + private final double minX; + + private final double minY; + + private final double maxX; + + private final double maxY; + + /** + * @param minX + * Lower left corner, coordinate axis 1 + * @param minY + * Lower left corner, coordinate axis 2 + * @param maxX + * Upper right corner, coordinate axis 1 + * @param maxY + * Upper right corner, coordinate axis 2 + */ + public BBox( double minX, double minY, double maxX, double maxY ) { + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + /** + * @return the bbox as query string like '-12,10, 12,20' + */ + public String asQueryParameter() { + StringBuilder sb = new StringBuilder(); + DecimalFormat formatter = formatter(); + sb.append( formatter.format( minX ) ).append( "," ); + sb.append( formatter.format( minY ) ).append( "," ); + sb.append( formatter.format( maxX ) ).append( "," ); + sb.append( formatter.format( maxY ) ); + return sb.toString(); + } + + @Override + public String toString() { + return asQueryParameter(); + } + + private DecimalFormat formatter() { + NumberFormat nf = NumberFormat.getNumberInstance( Locale.ENGLISH ); + DecimalFormat df = (DecimalFormat) nf; + df.applyPattern( PATTERN ); + return df; + } + +} \ No newline at end of file diff --git a/src/main/java/org/opengis/cite/wfs30/util/JsonUtils.java b/src/main/java/org/opengis/cite/wfs30/util/JsonUtils.java index f60bf055..608208b3 100644 --- a/src/main/java/org/opengis/cite/wfs30/util/JsonUtils.java +++ b/src/main/java/org/opengis/cite/wfs30/util/JsonUtils.java @@ -22,6 +22,37 @@ public class JsonUtils { private JsonUtils() { } + /** + * Parses the extent from the passed collection. + * + * @param collection + * the collection containing the extent to parse, never null + * @return the parsed bbox, null if no extent exists + * @throws IllegalArgumentException + * if the number of items in the extent invalid + * + */ + public static BBox parseExtent( Map collection ) { + Object extent = collection.get( "extent" ); + if ( extent == null || !( extent instanceof Map ) ) + return null; + Object spatial = ( (Map) extent ).get( "spatial" ); + if ( spatial == null || !( spatial instanceof List ) ) + return null; + List coords = (List) spatial; + if ( coords.size() == 4 ) { + double minX = (Float) coords.get( 0 ); + double minY = (Float) coords.get( 1 ); + double maxX = (Float) coords.get( 2 ); + double maxY = (Float) coords.get( 3 ); + return new BBox( minX, minY, maxX, maxY ); + } else if ( coords.size() == 6 ) { + throw new IllegalArgumentException( "BBox with " + coords.size() + + " coordinates is currently not supported" ); + } + throw new IllegalArgumentException( "BBox with " + coords.size() + " coordinates is invalid" ); + } + /** * Parses all links with 'type' of one of the passed mediaTypes and the 'rel' property with the passed value. * diff --git a/src/test/java/org/opengis/cite/wfs30/collections/GetFeaturesOperationIT.java b/src/test/java/org/opengis/cite/wfs30/collections/GetFeaturesOperationIT.java index cf79f835..81485745 100644 --- a/src/test/java/org/opengis/cite/wfs30/collections/GetFeaturesOperationIT.java +++ b/src/test/java/org/opengis/cite/wfs30/collections/GetFeaturesOperationIT.java @@ -7,12 +7,14 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.util.Iterator; import java.util.List; import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; import org.opengis.cite.wfs30.SuiteAttribute; +import org.opengis.cite.wfs30.util.BBox; import org.testng.ISuite; import org.testng.ITestContext; @@ -82,11 +84,12 @@ public void testGetFeatureOperations() // getFeaturesOperation.validateLimitParameter_requests( parameter, limit ); } - Object[][] collectionsWithBboxes = getFeaturesOperation.collectionItemUrisWithBboxes( testContext ); - for ( Object[] collection : collectionsWithBboxes ) { + Iterator collectionsWithBboxes = getFeaturesOperation.collectionItemUrisWithBboxes( testContext ); + for ( Iterator collectionWithBbox = collectionsWithBboxes; collectionWithBbox.hasNext(); ) { + Object[] collection = collectionWithBbox.next(); Map parameter = (Map) collection[0]; - String bbox = (String) collection[1]; - // fails: response is empty + BBox bbox = (BBox) collection[1]; + // fails: in collections.json must the links (rel: item, type: application/geo+json) changed to https // getFeaturesOperation.validateBboxParameter_requests( parameter, bbox ); } diff --git a/src/test/java/org/opengis/cite/wfs30/util/JsonUtilsTest.java b/src/test/java/org/opengis/cite/wfs30/util/JsonUtilsTest.java index 38a1a45f..1f18705f 100644 --- a/src/test/java/org/opengis/cite/wfs30/util/JsonUtilsTest.java +++ b/src/test/java/org/opengis/cite/wfs30/util/JsonUtilsTest.java @@ -1,12 +1,14 @@ package org.opengis.cite.wfs30.util; import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.opengis.cite.wfs30.util.JsonUtils.findLinkByRel; import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithSupportedMediaTypeByRel; import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithoutRelOrType; import static org.opengis.cite.wfs30.util.JsonUtils.hasProperty; import static org.opengis.cite.wfs30.util.JsonUtils.linkIncludesRelAndType; +import static org.opengis.cite.wfs30.util.JsonUtils.parseExtent; import java.io.InputStream; import java.util.Arrays; @@ -31,6 +33,20 @@ public static void parseJson() { jsonPath = new JsonPath( json ); } + @Test + public void testParseExtent() { + List collections = jsonPath.getList( "collections" ); + BBox extent = parseExtent( (Map) collections.get( 0 ) ); + + String queryParam = extent.asQueryParameter(); + String[] queryParams = queryParam.split( "," ); + assertThat( queryParams.length, is( 4 ) ); + assertEquals( Double.parseDouble( queryParams[0] ), 5.61272621360749, 0.00001 ); + assertEquals( Double.parseDouble( queryParams[1] ), 50.2373512077239, 0.00001 ); + assertEquals( Double.parseDouble( queryParams[2] ), 9.58963433710139, 0.00001 ); + assertEquals( Double.parseDouble( queryParams[3] ), 52.5286304537795, 0.00001 ); + } + @Test public void testFindLinkToItself() { List> links = jsonPath.getList( "links" );