org.geotools.data.DataTestCase Maven / Gradle / Ivy
Show all versions of gt-main Show documentation
/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2003-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.data;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.UUID;
import junit.framework.TestCase;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.MultiLineString;
import org.locationtech.jts.geom.Polygon;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.Id;
/**
* A set of constructs and utility methods used to test the data module.
*
* By isolating a common set of {@link SimpleFeature}s, {@link SimpleFeatureType}s and {@link
* Filter}s we are able to reduce the amount of overhead in setting up new tests.
*
*
This code has been made part of the public {@code geotools.jar} to provide a starting point
* for test cases involving Data constructs.
*
* @version $Id$
* @author Jody Garnett, Refractions Research
* @todo It should be possible to move this class in the {@code sample-data} module.
*/
public class DataTestCase extends TestCase {
protected GeometryFactory gf;
protected SimpleFeatureType roadType; // road: id,geom,name
protected SimpleFeatureType subRoadType; // road: id,geom
protected SimpleFeature[] roadFeatures;
protected ReferencedEnvelope roadBounds;
protected ReferencedEnvelope rd12Bounds;
protected Filter rd1Filter;
protected Filter rd2Filter;
protected Filter rd12Filter;
protected SimpleFeature newRoad;
protected SimpleFeatureType riverType; // river: id, geom, river, flow
protected SimpleFeatureType subRiverType; // river: river, flow
protected SimpleFeature[] riverFeatures;
protected ReferencedEnvelope riverBounds;
protected Filter rv1Filter;
protected SimpleFeature newRiver;
protected SimpleFeatureType lakeType; // lake: id, geom, name
protected SimpleFeature[] lakeFeatures;
protected ReferencedEnvelope lakeBounds;
protected SimpleFeatureType invalidGeomType; // invalidGeom: id, geom, name
protected SimpleFeature[] invalidGeomFeatures;
protected ReferencedEnvelope invalidGeomBounds;
protected SimpleFeatureType buildingType; // building: id, geom, name
protected SimpleFeature[] buildingFeatures;
protected ReferencedEnvelope buildingBounds;
protected FilterFactory2 ff;
public DataTestCase() {}
/** Creates a default test case with the given name. */
public DataTestCase(final String name) {
super(name);
}
protected int expected(Filter filter) {
if (filter instanceof Id) {
Id id = (Id) filter;
return id.getIDs().size();
}
return -1;
}
/** Invoked before a test is run. The default implementation invokes {@link #dataSetUp}. */
protected void setUp() throws Exception {
ff = (FilterFactory2) CommonFactoryFinder.getFilterFactory2(null);
dataSetUp();
}
/**
* Loads the data.
*
* @see #setUp()
*/
protected void dataSetUp() throws Exception {
String namespace = getName();
roadType =
DataUtilities.createType(
namespace + ".road", "id:0,geom:LineString,name:String,uuid:UUID");
subRoadType = DataUtilities.createType(namespace + "road", "id:0,geom:LineString");
gf = new GeometryFactory();
roadFeatures = new SimpleFeature[3];
// 3,2
// 2,2 +-----+-----+ 4,2
// / rd1 \
// 1,1+ +5,1
roadFeatures[0] =
SimpleFeatureBuilder.build(
roadType,
new Object[] {
Integer.valueOf(1),
line(new int[] {1, 1, 2, 2, 4, 2, 5, 1}),
"r1",
UUID.randomUUID()
},
"road.rd1");
// + 3,4
// + 3,3
// rd2 + 3,2
// |
// 3,0+
roadFeatures[1] =
SimpleFeatureBuilder.build(
roadType,
new Object[] {
Integer.valueOf(2),
line(new int[] {3, 0, 3, 2, 3, 3, 3, 4}),
"r2",
UUID.randomUUID()
},
"road.rd2");
// rd3 + 5,3
// /
// 3,2 +----+ 4,2
roadFeatures[2] =
SimpleFeatureBuilder.build(
roadType,
new Object[] {
Integer.valueOf(3),
line(new int[] {3, 2, 4, 2, 5, 3}),
"r3",
UUID.randomUUID()
},
"road.rd3");
roadBounds = new ReferencedEnvelope();
roadBounds.expandToInclude(new ReferencedEnvelope(roadFeatures[0].getBounds()));
roadBounds.expandToInclude(new ReferencedEnvelope(roadFeatures[1].getBounds()));
roadBounds.expandToInclude(new ReferencedEnvelope(roadFeatures[2].getBounds()));
rd1Filter = ff.id(Collections.singleton(ff.featureId("road.rd1")));
rd2Filter = ff.id(Collections.singleton(ff.featureId("road.rd2")));
Id create =
ff.id(
new HashSet(
Arrays.asList(ff.featureId("road.rd1"), ff.featureId("road.rd2"))));
rd12Filter = create;
rd12Bounds = new ReferencedEnvelope();
rd12Bounds.expandToInclude(new ReferencedEnvelope(roadFeatures[0].getBounds()));
rd12Bounds.expandToInclude(new ReferencedEnvelope(roadFeatures[1].getBounds()));
// + 2,3
// / rd4
// + 1,2
newRoad =
SimpleFeatureBuilder.build(
roadType,
new Object[] {
Integer.valueOf(4),
line(new int[] {1, 2, 2, 3}),
"r4",
UUID.randomUUID()
},
"road.rd4");
riverType =
DataUtilities.createType(
namespace + ".river", "id:0,geom:MultiLineString,river:String,flow:0.0");
subRiverType = DataUtilities.createType(namespace + ".river", "river:String,flow:0.0");
gf = new GeometryFactory();
riverFeatures = new SimpleFeature[2];
// 9,7 13,7
// +------+
// 5,5 /
// +---+ rv1
// 7,5 \
// 9,3 +----+ 11,3
riverFeatures[0] =
SimpleFeatureBuilder.build(
riverType,
new Object[] {
Integer.valueOf(1),
lines(
new int[][] {
{5, 5, 7, 4},
{7, 5, 9, 7, 13, 7},
{7, 5, 9, 3, 11, 3}
}),
"rv1",
Double.valueOf(4.5)
},
"river.rv1");
// + 6,10
// /
// rv2+ 4,8
// |
// 4,6 +
riverFeatures[1] =
SimpleFeatureBuilder.build(
riverType,
new Object[] {
Integer.valueOf(2),
lines(new int[][] {{4, 6, 4, 8, 6, 10}}),
"rv2",
Double.valueOf(3.0)
},
"river.rv2");
riverBounds = new ReferencedEnvelope();
riverBounds.expandToInclude(ReferencedEnvelope.reference(riverFeatures[0].getBounds()));
riverBounds.expandToInclude(ReferencedEnvelope.reference(riverFeatures[1].getBounds()));
rv1Filter = ff.id(Collections.singleton(ff.featureId("river.rv1")));
// 9,5 11,5
// +-----+
// rv3 \
// + 13,3
//
newRiver =
SimpleFeatureBuilder.build(
riverType,
new Object[] {
Integer.valueOf(3),
lines(new int[][] {{9, 5, 11, 5, 13, 3}}),
"rv3",
Double.valueOf(1.5)
},
"river.rv3");
lakeType =
DataUtilities.createType(
namespace + ".lake", "id:0,geom:Polygon:nillable,name:String");
lakeFeatures = new SimpleFeature[1];
// + 14,8
// / \
// 12,6 + + 16,6
// \ |
// 14,4 +-+ 16,4
//
lakeFeatures[0] =
SimpleFeatureBuilder.build(
lakeType,
new Object[] {
Integer.valueOf(0),
polygon(new int[] {12, 6, 14, 8, 16, 6, 16, 4, 14, 4, 12, 6}),
"muddy"
},
"lake.lk1");
lakeBounds = new ReferencedEnvelope();
lakeBounds.expandToInclude(ReferencedEnvelope.reference(lakeFeatures[0].getBounds()));
invalidGeomType =
DataUtilities.createType(
namespace + ".invalid", "id:0,geom:Polygon:nillable,name:String");
invalidGeomFeatures = new SimpleFeature[1];
// 12,8 14,8
// |\/\
// |/\_\
// 12,6 + + 16,6
//
invalidGeomFeatures[0] =
SimpleFeatureBuilder.build(
invalidGeomType,
new Object[] {
Integer.valueOf(0),
polygon(new int[] {12, 6, 14, 8, 16, 6, 12, 8, 12, 6}),
"notvalid"
},
"invalid.inv1");
invalidGeomBounds = new ReferencedEnvelope();
buildingType =
DataUtilities.createType(
namespace + ".building", "id:0,geom:Polygon:nillable,name:String");
buildingFeatures = new SimpleFeature[1];
// + 14,8
// / \
// 12,6 + + 16,6
// | |
// 12,4 +---+ 16,4
//
buildingFeatures[0] =
SimpleFeatureBuilder.build(
lakeType,
new Object[] {
Integer.valueOf(0),
polygon(new int[] {12, 6, 14, 8, 16, 6, 16, 4, 12, 4, 12, 6}),
"church"
},
"building.bd1");
buildingBounds = new ReferencedEnvelope();
buildingBounds.expandToInclude(
ReferencedEnvelope.reference(buildingFeatures[0].getBounds()));
}
/**
* Set all data references to {@code null}, allowing garbage collection. This method is
* automatically invoked after each test.
*/
protected void tearDown() throws Exception {
gf = null;
roadType = null;
subRoadType = null;
roadFeatures = null;
roadBounds = null;
rd1Filter = null;
rd2Filter = null;
newRoad = null;
riverType = null;
subRiverType = null;
riverFeatures = null;
riverBounds = null;
rv1Filter = null;
newRiver = null;
buildingType = null;
buildingFeatures = null;
buildingBounds = null;
}
/**
* Creates a line from the specified (x,y) coordinates. The coordinates
* are stored in a flat array.
*/
public LineString line(int[] xy) {
Coordinate[] coords = new Coordinate[xy.length / 2];
for (int i = 0; i < xy.length; i += 2) {
coords[i / 2] = new Coordinate(xy[i], xy[i + 1]);
}
return gf.createLineString(coords);
}
/** Creates a multiline from the specified (x,y) coordinates. */
public MultiLineString lines(int[][] xy) {
LineString[] lines = new LineString[xy.length];
for (int i = 0; i < xy.length; i++) {
lines[i] = line(xy[i]);
}
return gf.createMultiLineString(lines);
}
/**
* Creates a polygon from the specified (x,y) coordinates. The coordinates
* are stored in a flat array.
*/
public Polygon polygon(int[] xy) {
LinearRing shell = ring(xy);
return gf.createPolygon(shell, null);
}
/**
* Creates a line from the specified (x,y) coordinates and an arbitrary
* amount of holes.
*/
public Polygon polygon(int[] xy, int[][] holes) {
if (holes == null || holes.length == 0) {
return polygon(xy);
}
LinearRing shell = ring(xy);
LinearRing[] rings = new LinearRing[holes.length];
for (int i = 0; i < xy.length; i++) {
rings[i] = ring(holes[i]);
}
return gf.createPolygon(shell, rings);
}
/**
* Creates a ring from the specified (x,y) coordinates. The coordinates
* are stored in a flat array.
*/
public LinearRing ring(int[] xy) {
Coordinate[] coords = new Coordinate[xy.length / 2];
for (int i = 0; i < xy.length; i += 2) {
coords[i / 2] = new Coordinate(xy[i], xy[i + 1]);
}
return gf.createLinearRing(coords);
}
/** Compares two geometries for equality. */
protected void assertEquals(Geometry expected, Geometry actual) {
if (expected == actual) {
return;
}
assertNotNull(expected);
assertNotNull(actual);
assertTrue(expected.equalsExact(actual));
}
/** Compares two geometries for equality. */
protected void assertEquals(String message, Geometry expected, Geometry actual) {
if (expected == actual) {
return;
}
assertNotNull(message, expected);
assertNotNull(message, actual);
assertTrue(message, expected.equalsExact(actual));
}
/**
* Counts the number of Features returned by the specified reader.
*
*
This method will close the reader.
*/
protected int count(FeatureReader reader) throws IOException {
if (reader == null) {
return -1;
}
int count = 0;
try {
while (reader.hasNext()) {
reader.next();
count++;
}
} catch (NoSuchElementException e) {
// bad dog!
throw new DataSourceException("hasNext() lied to me at:" + count, e);
} catch (Exception e) {
throw new DataSourceException("next() could not understand feature at:" + count, e);
} finally {
reader.close();
}
return count;
}
/** Counts the number of Features in the specified writer. This method will close the writer. */
protected int count(FeatureWriter writer)
throws NoSuchElementException, IOException {
int count = 0;
try {
while (writer.hasNext()) {
writer.next();
count++;
}
} finally {
writer.close();
}
return count;
}
}