diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java index d578de28d0a6d9e8dbb13f30bd4dfaf1a8aa60de..181075d0bc0f52b21595ba15de9f00c190f6ad60 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java @@ -18,9 +18,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; import org.opengroup.osdu.indexer.model.geojson.jackson.PositionDeserializer; import org.opengroup.osdu.indexer.model.geojson.jackson.PositionSerializer; @@ -28,6 +26,7 @@ import java.io.Serializable; @Getter @NoArgsConstructor +@EqualsAndHashCode @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(using = PositionDeserializer.class) @JsonSerialize(using = PositionSerializer.class) diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionDeserializerTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionDeserializerTest.java index 26a35352056182038fa62110beaa1514d13d216c..f7204581f79ec65a892f33763eb9f57c56f8b6f6 100644 --- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionDeserializerTest.java +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionDeserializerTest.java @@ -1,168 +1,202 @@ package org.opengroup.osdu.indexer.model.geojson.jackson; -import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; -import com.google.gson.internal.LinkedTreeMap; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import joptsimple.internal.Strings; +import lombok.SneakyThrows; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.opengroup.osdu.indexer.model.geojson.Feature; import org.opengroup.osdu.indexer.model.geojson.FeatureCollection; -import org.opengroup.osdu.indexer.model.geojson.LineString; -import org.opengroup.osdu.indexer.model.geojson.Position; import org.springframework.test.context.junit4.SpringRunner; -import java.util.ArrayList; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.List; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.junit.jupiter.api.Assertions.*; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.*; @RunWith(SpringRunner.class) public class FeatureCollectionDeserializerTest { - private ObjectMapper mapper = new ObjectMapper(); + @InjectMocks + private FeatureCollectionDeserializer featureCollectionDeserializer; - private FeatureCollection featureCollection = createFeatureCollection(); + private final ObjectMapper mapper = new ObjectMapper(); + private final JsonFactory factory = mapper.getFactory(); @Test - public void should_returnFeatureList_extractFeatureTest(){ - Map<String, Object> objectMap = createObjectMap(); + public void should_throwException_provided_emptyGeoJson() { + String shapeJson = "{}"; - try { - FeatureCollection collection = mapper.readValue(mapper.writeValueAsString(objectMap), FeatureCollection.class); - assertEquals(featureCollection, collection); - } catch (JsonProcessingException e) { - fail("unable to parse FeatureCollection"); - } + this.validateInput(shapeJson, Strings.EMPTY, "shape not included"); } @Test - public void should_throwException_extractFeatureTest(){ - assertThrows(InvalidTypeIdException.class, () -> mapper.readValue(mapper.writeValueAsString(new LinkedTreeMap()), FeatureCollection.class)); + public void should_throwException_parseInvalidPoint() { + String shapeJson = getFeatureFromFile("input/invalid_point.json"); + this.validateInput(shapeJson, Strings.EMPTY, "unable to parse FeatureCollection"); } @Test - public void should_throwException_whenInvalidFeature_extractFeatureTest(){ - Map<String, Object> objectMap = createInvalidObjectMap(); - assertThrows(InvalidTypeIdException.class, () -> mapper.readValue(mapper.writeValueAsString(objectMap), FeatureCollection.class)); + public void should_throwException_parseInvalidPoint_NaN() { + String shapeJson = getFeatureFromFile("input/invalid_point_nan.json"); + this.validateInput(shapeJson, Strings.EMPTY, "unable to parse FeatureCollection"); } @Test - public void should_returnFeatureList_withoutGeometry_extractFeatureTest() { - FeatureCollection featureCollection = createFeatureCollectionWithoutGeometry(); - Map<String, Object> objectMap = createInvalidObjectMapWithoutGeometry(); - - try { - FeatureCollection collection = mapper.readValue(mapper.writeValueAsString(objectMap), FeatureCollection.class); - assertEquals(featureCollection, collection); - } catch (JsonProcessingException e) { - fail("unable to parse FeatureCollection"); - } + public void should_throwException_parseInvalidPoint_missingLatitude() { + String shapeJson = getFeatureFromFile("input/invalid_point_missing_latitude.json"); + this.validateInput(shapeJson, Strings.EMPTY, "unable to parse FeatureCollection"); } - private FeatureCollection createFeatureCollection(){ - Position position = new Position(90, 80); - List<Position> positions = new ArrayList<>(); - positions.add(position); - - LineString lineString = new LineString(); - lineString.setCoordinates(positions); - Feature feature = new Feature(); - feature.setGeometry(lineString); - - List<Feature> futures = new ArrayList<>(); - futures.add(feature); - FeatureCollection featureCollection = new FeatureCollection(); - featureCollection.setFeatures(futures); - - return featureCollection; + @Test + public void should_throwException_missingMandatoryAttribute() { + String shapeJson = getFeatureFromFile("input/missing_mandatory_attribute.json"); + this.validateInput(shapeJson, Strings.EMPTY, "must be a valid FeatureCollection"); } - private FeatureCollection createFeatureCollectionWithoutGeometry(){ - Feature feature = new Feature(); - - List<Feature> futures = new ArrayList<>(); - futures.add(feature); - FeatureCollection featureCollection = new FeatureCollection(); - featureCollection.setFeatures(futures); + @Test + public void should_throwException_parseInvalidShape() { + String shapeJson = getFeatureFromFile("input/invalid_shape.json"); + this.validateInput(shapeJson, Strings.EMPTY, "must be a valid FeatureCollection"); + } - return featureCollection; + @Test + public void should_parseValidPoint() { + String shapeJson = getFeatureFromFile("input/valid_point.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); } - private Map<String, Object> createObjectMap(){ - Map<String, String> type = new LinkedTreeMap<>(); - type.put("type", "Feature"); + @Test + public void should_parseValidMultiPoint() { + String shapeJson = getFeatureFromFile("input/valid_multi_point.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - List<Double> objectList2 = new ArrayList<>(); - objectList2.add(90d); - objectList2.add(80d); - List<Object> objectList1 = new ArrayList<>(); - objectList1.add(objectList2); - LinkedTreeMap<String, Object> geometry = new LinkedTreeMap<>(); - geometry.put("type", "LineString"); - geometry.put("coordinates", objectList1); + @Test + public void should_parseValidLineString() { + String shapeJson = getFeatureFromFile("input/valid_line_string.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - LinkedTreeMap<String, Object> objectList11 = new LinkedTreeMap<>(); - objectList11.put("type", "Feature"); - objectList11.put("geometry", geometry); - objectList11.put("property", new LinkedTreeMap<>()); + @Test + public void should_parseValidMultiLineString() { + String shapeJson = getFeatureFromFile("input/valid_multi_line_string.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - List<Object> objectList = new ArrayList<>(); - objectList.add(objectList11); + @Test + public void should_parseValidPolygon() { + String shapeJson = getFeatureFromFile("input/valid_polygon.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - Map<String, Object> objectMap = new LinkedTreeMap(); - objectMap.put("features", objectList); - objectMap.put("type", "FeatureCollection"); + @Test + public void should_throwException_parseInvalidPolygon_malformedLatitude() { + String shapeJson = getFeatureFromFile("input/invalid_polygon_malformed_latitude.json"); + this.validateInput(shapeJson, Strings.EMPTY, "unable to parse FeatureCollection"); + } - return objectMap; + @Test + public void should_parseValidMultiPolygon() { + String shapeJson = getFeatureFromFile("input/valid_multi_polygon.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); } - private Map<String, Object> createInvalidObjectMap(){ - Map<String, String> type = new LinkedTreeMap<>(); - type.put("type", "Feature"); + @Test + public void should_parseValidGeometryCollection() { + String shapeJson = getFeatureFromFile("input/valid_geometry_collection.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - List<Double> objectList2 = new ArrayList<>(); - objectList2.add(90d); - objectList2.add(80d); - List<Object> objectList1 = new ArrayList<>(); - objectList1.add(objectList2); - LinkedTreeMap<String, Object> geometry = new LinkedTreeMap<>(); - geometry.put("type", "LineString"); - geometry.put("coordinates", objectList1); + @Test + public void should_parseValidFeatureCollection() { + String shapeJson = getFeatureFromFile("input/valid_feature_collection.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - LinkedTreeMap<String, Object> objectList11 = new LinkedTreeMap<>(); - objectList11.put("type", "FeatuIre"); - objectList11.put("geometry", geometry); - objectList11.put("property", new LinkedTreeMap<>()); + @Test + public void should_parseValidFeatureCollection_withZCoordinate() { + String shapeJson = getFeatureFromFile("input/valid_feature_collection_with_z_coordinate.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - List<Object> objectList = new ArrayList<>(); - objectList.add(objectList11); + @Test + public void should_throwException_parseUnsupportedType_feature() { + String shapeJson = getFeatureFromFile("input/valid_feature_collection_with_z_coordinate.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - Map<String, Object> objectMap = new LinkedTreeMap(); - objectMap.put("features", objectList); - objectMap.put("type", "FeatureCollection"); + @Test + public void shouldParseValidMultiPolygonWithZCoordinates() { + String shapeJson = getFeatureFromFile("input/multi_polygon_with_z_coordinates.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - return objectMap; + @Test + public void shouldParseValidLineStringWithZCoordinates() { + String shapeJson = getFeatureFromFile("input/line_string_with_z_coordinate.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); } - private Map<String, Object> createInvalidObjectMapWithoutGeometry(){ - Map<String, String> type = new LinkedTreeMap<>(); - type.put("type", "Feature"); + @Test + public void shouldParseValidMultiLineStringWithZCoordinates() { + String shapeJson = getFeatureFromFile("input/valid_milti_line_string_with_z_coordinate.json"); + this.validateInput(shapeJson, shapeJson, Strings.EMPTY); + } - LinkedTreeMap<String, Object> objectList11 = new LinkedTreeMap<>(); - objectList11.put("type", "Feature"); - objectList11.put("property", new LinkedTreeMap<>()); - List<Object> objectList = new ArrayList<>(); - objectList.add(objectList11); + private void validateInput(String shapeJson, String expectedParsedShape, String errorMessage) { + try { + Type type = new TypeToken<Map<String, Object>>() {}.getType(); + Map<String, Object> expectedShape = new Gson().fromJson(expectedParsedShape, type); + FeatureCollection featureCollection = mapper.convertValue(expectedShape, FeatureCollection.class); + + JsonParser parser = factory.createParser(shapeJson); + List<Feature> result = (List<Feature>) callPrivateMethod_ExtractFeature(parser); + + assertNotNull(result); + assertTrue(Strings.isNullOrEmpty(errorMessage)); + assertEquals(featureCollection.getFeatures(), result); + } catch (IllegalArgumentException e) { + if (Strings.isNullOrEmpty(errorMessage)) { + fail(String.format("error parsing valid feature-json %s", shapeJson)); + } else { + assertThat(String.format("Incorrect error message for feature-json parsing [ %s ]", shapeJson), e.getMessage(), containsString(errorMessage)); + } + } catch (IOException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } - Map<String, Object> objectMap = new LinkedTreeMap(); - objectMap.put("features", objectList); - objectMap.put("type", "FeatureCollection"); + @SneakyThrows + private String getFeatureFromFile(String file) { + InputStream inStream = this.getClass().getResourceAsStream("/geojson/parsing/" + file); + assert inStream != null; + BufferedReader br = new BufferedReader(new InputStreamReader(inStream)); + StringBuilder stringBuilder = new StringBuilder(); + String sCurrentLine; + while ((sCurrentLine = br.readLine()) != null) { + stringBuilder.append(sCurrentLine).append("\n"); + } + return stringBuilder.toString(); + } - return objectMap; + public Object callPrivateMethod_ExtractFeature(JsonParser parser) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException { + Method method = featureCollectionDeserializer.getClass().getDeclaredMethod("extractFeature", JsonParser.class); + method.setAccessible(true); + return method.invoke(featureCollectionDeserializer, parser); } -} \ No newline at end of file +}