/* * GeoTools - OpenSource mapping toolkit * http://geotools.org * (C) 2003-2006, Geotools Project Managment Committee (PMC) * * 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; either * version 2.1 of the License, or (at your option) any later version. * * 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.memory; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import org.geotools.data.DataStore; import org.geotools.data.DataTestCase; import org.geotools.data.DataUtilities; import org.geotools.data.DefaultQuery; import org.geotools.data.DefaultTransaction; import org.geotools.data.DiffFeatureReader; import org.geotools.data.EmptyFeatureReader; import org.geotools.data.EmptyFeatureWriter; import org.geotools.data.FeatureEvent; import org.geotools.data.FeatureListener; import org.geotools.data.FeatureListenerManager; import org.geotools.data.FeatureLock; import org.geotools.data.FeatureLockFactory; import org.geotools.data.FeatureLocking; import org.geotools.data.FeatureReader; import org.geotools.data.FeatureResults; import org.geotools.data.FeatureSource; import org.geotools.data.FeatureStore; import org.geotools.data.FeatureWriter; import org.geotools.data.FilteringFeatureReader; import org.geotools.data.FilteringFeatureWriter; import org.geotools.data.InProcessLockingManager; import org.geotools.data.Query; import org.geotools.data.Transaction; import org.geotools.data.TransactionStateDiff; import org.geotools.feature.AttributeType; import org.geotools.feature.Feature; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.feature.FeatureType; import org.geotools.feature.IllegalAttributeException; import org.geotools.feature.SimpleFeature; import org.geotools.filter.FidFilter; import org.geotools.filter.Filter; import org.geotools.filter.FilterFactory; import org.geotools.filter.FilterFactoryFinder; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.MultiLineString; /** * DOCUMENT ME! * * @author Jody Garnett, Refractions Research * @source $URL$ */ public class MemoryDataStoreTest extends DataTestCase { MemoryDataStore data; /** * Constructor for MemoryDataStoreTest. * * @param arg0 */ public MemoryDataStoreTest(String arg0) { super(arg0); } /* * @see TestCase#setUp() */ protected void setUp() throws Exception { super.setUp(); data = new MemoryDataStore(); data.addFeatures(roadFeatures); data.addFeatures(riverFeatures); } /* * @see TestCase#tearDown() */ protected void tearDown() throws Exception { data = null; super.tearDown(); } public void testFixture() throws Exception { FeatureType type = DataUtilities.createType("namespace.typename", "name:String,id:0,geom:MultiLineString"); assertEquals("namespace", new URI("namespace"), type.getNamespace()); assertEquals("typename", "typename", type.getTypeName()); assertEquals("attributes", 3, type.getAttributeCount()); AttributeType[] a = type.getAttributeTypes(); assertEquals("a1", "name", a[0].getName()); assertEquals("a1", String.class, a[0].getType()); assertEquals("a2", "id", a[1].getName()); assertEquals("a2", Integer.class, a[1].getType()); assertEquals("a3", "geom", a[2].getName()); assertEquals("a3", MultiLineString.class, a[2].getType()); } public void testMemoryDataStore() throws Exception { DataStore store = new MemoryDataStore(); } /* * Test for void MemoryDataStore(FeatureCollection) */ public void testMemoryDataStoreFeatureCollection() { DataStore store = new MemoryDataStore(DataUtilities.collection( roadFeatures)); } /* * Test for void MemoryDataStore(FeatureReader) */ public void testMemoryDataStoreFeatureArray() throws IOException { DataStore store = new MemoryDataStore(roadFeatures); } /* * Test for void MemoryDataStore(FeatureReader) */ public void testMemoryDataStoreFeatureReader() throws IOException { FeatureReader reader = DataUtilities.reader(roadFeatures); DataStore store = new MemoryDataStore(reader); } public void testGetFeatureTypes() { String[] names = data.getTypeNames(); assertEquals(2, names.length); assertTrue(contains(names, "road")); assertTrue(contains(names, "river")); } boolean contains(Object[] array, Object expected) { if ((array == null) || (array.length == 0)) { return false; } for (int i = 0; i < array.length; i++) { if (array[i].equals(expected)) { return true; } } return false; } /** * Like contain but based on match rather than equals * * @param array DOCUMENT ME! * @param expected DOCUMENT ME! * * @return DOCUMENT ME! */ boolean containsLax(Feature[] array, Feature expected) { if ((array == null) || (array.length == 0)) { return false; } FeatureType type = expected.getFeatureType(); for (int i = 0; i < array.length; i++) { if (match(array[i], expected)) { return true; } } return false; } /** * Compare based on attributes not getID allows comparison of Diff contents * * @param expected DOCUMENT ME! * @param actual DOCUMENT ME! * * @return DOCUMENT ME! */ boolean match(Feature expected, Feature actual) { FeatureType type = expected.getFeatureType(); for (int i = 0; i < type.getAttributeCount(); i++) { Object av = actual.getAttribute(i); Object ev = expected.getAttribute(i); if ((av == null) && (ev != null)) { return false; } else if ((ev == null) && (av != null)) { return false; } else if (av instanceof Geometry && ev instanceof Geometry) { Geometry ag = (Geometry) av; Geometry eg = (Geometry) ev; if (!ag.equals(eg)) { return false; } } else if (!av.equals(ev)) { return false; } } return true; } public void testGetSchema() throws IOException { assertSame(roadType, data.getSchema("road")); assertSame(riverType, data.getSchema("river")); } void assertCovers(String msg, FeatureCollection c1, FeatureCollection c2) { if (c1 == c2) { return; } assertNotNull(msg, c1); assertNotNull(msg, c2); assertEquals(msg + " size", c1.size(), c2.size()); Feature f; for (FeatureIterator i = c1.features(); i.hasNext();) { f = i.next(); assertTrue(msg + " " + f.getID(), c2.contains(f)); } } public void testGetFeatureReader() throws IOException, IllegalAttributeException { FeatureReader reader = data.getFeatureReader("road"); assertCovered(roadFeatures, reader); assertEquals(false, reader.hasNext()); } public void testGetFeatureReaderMutability() throws IOException, IllegalAttributeException { FeatureReader reader = data.getFeatureReader("road"); Feature feature; while (reader.hasNext()) { feature = (Feature) reader.next(); feature.setAttribute("name", null); } reader.close(); reader = data.getFeatureReader("road"); while (reader.hasNext()) { feature = (Feature) reader.next(); assertNotNull(feature.getAttribute("name")); } reader.close(); try { reader.next(); fail("next should fail with an IOException"); } catch (IOException expected) { } } public void testGetFeatureReaderConcurancy() throws NoSuchElementException, IOException, IllegalAttributeException { FeatureReader reader1 = data.getFeatureReader("road"); FeatureReader reader2 = data.getFeatureReader("road"); FeatureReader reader3 = data.getFeatureReader("river"); Feature feature1; Feature feature2; Feature feature3; while (reader1.hasNext() || reader2.hasNext() || reader3.hasNext()) { assertTrue(contains(roadFeatures, reader1.next())); assertTrue(contains(roadFeatures, reader2.next())); if (reader3.hasNext()) { assertTrue(contains(riverFeatures, reader3.next())); } } try { reader1.next(); fail("next should fail with an IOException"); } catch (IOException expected) { } try { reader2.next(); fail("next should fail with an IOException"); } catch (IOException expected) { } try { reader3.next(); fail("next should fail with an IOException"); } catch (IOException expected) { } reader1.close(); reader2.close(); reader3.close(); } public void testGetFeatureReaderFilterAutoCommit() throws NoSuchElementException, IOException, IllegalAttributeException { FeatureType type = data.getSchema("road"); FeatureReader reader; reader = data.getFeatureReader( new DefaultQuery("road"), Transaction.AUTO_COMMIT); assertFalse(reader instanceof FilteringFeatureReader); assertEquals(type, reader.getFeatureType()); assertEquals(roadFeatures.length, count(reader)); reader = data.getFeatureReader( new DefaultQuery( "road", Filter.ALL ), Transaction.AUTO_COMMIT); assertTrue(reader instanceof EmptyFeatureReader); assertEquals(type, reader.getFeatureType()); assertEquals(0, count(reader)); reader = data.getFeatureReader( new DefaultQuery( "road", rd1Filter ), Transaction.AUTO_COMMIT); assertTrue(reader instanceof FilteringFeatureReader); assertEquals(type, reader.getFeatureType()); assertEquals(1, count(reader)); } public void testGetFeatureReaderFilterTransaction() throws NoSuchElementException, IOException, IllegalAttributeException { Transaction t = new DefaultTransaction(); FeatureType type = data.getSchema("road"); FeatureReader reader; reader = data.getFeatureReader( new DefaultQuery( "road", Filter.ALL ), t); assertTrue(reader instanceof EmptyFeatureReader); assertEquals(type, reader.getFeatureType()); assertEquals(0, count(reader)); reader = data.getFeatureReader(new DefaultQuery("road"), t); assertTrue(reader instanceof DiffFeatureReader); assertEquals(type, reader.getFeatureType()); assertEquals(roadFeatures.length, count(reader)); reader = data.getFeatureReader(new DefaultQuery( "road", rd1Filter ), t); //assertTrue(reader instanceof DiffFeatureReader);//Currently wrapped by a filtering feature reader assertEquals(type, reader.getFeatureType()); assertEquals(1, count(reader)); TransactionStateDiff state = (TransactionStateDiff) t.getState(data); FeatureWriter writer = state.writer("road", Filter.NONE); Feature feature; while (writer.hasNext()) { feature = writer.next(); if (feature.getID().equals("road.rd1")) { writer.remove(); } } reader = data.getFeatureReader(new DefaultQuery( "road", Filter.ALL ), t); assertEquals(0, count(reader)); reader = data.getFeatureReader(new DefaultQuery("road"), t); assertEquals(roadFeatures.length - 1, count(reader)); reader = data.getFeatureReader(new DefaultQuery( "road", rd1Filter), t); assertEquals(0, count(reader)); t.rollback(); reader = data.getFeatureReader(new DefaultQuery( "road", Filter.ALL ), t); assertEquals(0, count(reader)); reader = data.getFeatureReader(new DefaultQuery("road"), t); assertEquals(roadFeatures.length, count(reader)); reader = data.getFeatureReader(new DefaultQuery( "road", rd1Filter), t); assertEquals(1, count(reader)); } /** * When a data store is loaded with a reader, it would be nice if the memory * data store preserved feature order, so that features are always rendered * the same way (rendering is different if order changes and features do overlap) */ public void testOrderPreservationRoad() throws Exception { assertOrderSame(roadFeatures); } public void testOrderPreservationRiver() throws Exception { assertOrderSame(riverFeatures); } public void testOrderPreservationMemFetures() throws Exception { SimpleFeature[] dynFeatures = new SimpleFeature[3]; dynFeatures[0] = (SimpleFeature)roadType.create(new Object[] { new Integer(1), line(new int[] { 1, 1, 2, 2, 4, 2, 5, 1 }), "r1", } ); dynFeatures[1] = (SimpleFeature)roadType.create(new Object[] { new Integer(2), line(new int[] { 3, 0, 3, 2, 3, 3, 3, 4 }), "r2" } ); dynFeatures[2] = (SimpleFeature)roadType.create(new Object[] { new Integer(3), line(new int[] { 3, 2, 4, 2, 5, 3 }), "r3" } ); assertOrderSame(dynFeatures); } void assertOrderSame(Feature[] features) throws Exception { // init using readers FeatureReader reader = DataUtilities.reader(features); DataStore store1 = new MemoryDataStore(reader); assertReaderOrderSame(features, store1); // init using array directly DataStore store2 = new MemoryDataStore(features); assertReaderOrderSame(features, store2); } private void assertReaderOrderSame(Feature[] features, DataStore store) throws IOException, IllegalAttributeException { FeatureReader r1 = store.getFeatureReader(new DefaultQuery(features[0].getFeatureType().getTypeName()), Transaction.AUTO_COMMIT); FeatureReader r2 = DataUtilities.reader(features); while(r1.hasNext() && r2.hasNext()) { Feature f1 = r1.next(); Feature f2 = r2.next(); assertEquals(f1, f2); } assertEquals(r1.hasNext(), r2.hasNext()); r1.close(); r2.close(); } void assertCovered(Feature[] features, FeatureReader reader) throws NoSuchElementException, IOException, IllegalAttributeException { int count = 0; try { while (reader.hasNext()) { assertTrue(contains(features, reader.next())); count++; } } finally { reader.close(); } assertEquals(features.length, count); } /** * Ensure that FeatureReader reader contains extactly the contents of * array. * * @param reader DOCUMENT ME! * @param array DOCUMENT ME! * * @return DOCUMENT ME! * * @throws NoSuchElementException DOCUMENT ME! * @throws IOException DOCUMENT ME! * @throws IllegalAttributeException DOCUMENT ME! */ boolean covers(FeatureReader reader, Feature[] array) throws NoSuchElementException, IOException, IllegalAttributeException { Feature feature; int count = 0; try { while (reader.hasNext()) { feature = reader.next(); if (!contains(array, feature)) { return false; } count++; } } finally { reader.close(); } return count == array.length; } boolean coversLax(FeatureReader reader, Feature[] array) throws NoSuchElementException, IOException, IllegalAttributeException { Feature feature; int count = 0; try { while (reader.hasNext()) { feature = reader.next(); if (!containsLax(array, feature)) { return false; } count++; } } finally { reader.close(); } return count == array.length; } void dump(FeatureReader reader) throws NoSuchElementException, IOException, IllegalAttributeException { Feature feature; int count = 0; try { while (reader.hasNext()) { feature = reader.next(); System.out.println(count + " feature:" + feature); count++; } } finally { reader.close(); } } void dump(Object[] array) { for (int i = 0; i < array.length; i++) { System.out.println(i + " feature:" + array[i]); } } /* * Test for FeatureWriter getFeatureWriter(String, Filter, Transaction) */ public void testGetFeatureWriter() throws NoSuchElementException, IOException, IllegalAttributeException { FeatureWriter writer = data.getFeatureWriter("road", Transaction.AUTO_COMMIT); assertEquals(roadFeatures.length, count(writer)); try { writer.hasNext(); fail("Should not be able to use a closed writer"); } catch (IOException expected) { } try { writer.next(); fail("Should not be able to use a closed writer"); } catch (IOException expected) { } } public void testGetFeatureWriterRemove() throws IOException, IllegalAttributeException { FeatureWriter writer = data.getFeatureWriter("road", Transaction.AUTO_COMMIT); Feature feature; while (writer.hasNext()) { feature = writer.next(); if (feature.getID().equals("road.rd1")) { writer.remove(); } } assertEquals(roadFeatures.length - 1, data.features("road").size()); } public void testGetFeaturesWriterAdd() throws IOException, IllegalAttributeException { FeatureWriter writer = data.getFeatureWriter("road", Transaction.AUTO_COMMIT); SimpleFeature feature; while (writer.hasNext()) { feature = (SimpleFeature)writer.next(); } assertFalse(writer.hasNext()); feature = (SimpleFeature)writer.next(); feature.setAttributes(newRoad.getAttributes(null)); writer.write(); assertFalse(writer.hasNext()); assertEquals(roadFeatures.length + 1, data.features("road").size()); } public void testGetFeaturesWriterModify() throws IOException, IllegalAttributeException { FeatureWriter writer = data.getFeatureWriter("road", Transaction.AUTO_COMMIT); Feature feature; while (writer.hasNext()) { feature = writer.next(); if (feature.getID().equals("road.rd1")) { feature.setAttribute("name", "changed"); writer.write(); } } feature = (Feature) data.features("road").get("road.rd1"); assertEquals("changed", feature.getAttribute("name")); } public void testGetFeatureWriterTypeNameTransaction() throws NoSuchElementException, IOException, IllegalAttributeException { FeatureWriter writer; writer = data.getFeatureWriter("road", Transaction.AUTO_COMMIT); assertEquals(roadFeatures.length, count(writer)); writer.close(); } public void testGetFeatureWriterAppendTypeNameTransaction() throws Exception { FeatureWriter writer; writer = data.getFeatureWriterAppend("road", Transaction.AUTO_COMMIT); assertEquals(0, count(writer)); writer.close(); } /* * Test for FeatureWriter getFeatureWriter(String, boolean, Transaction) */ public void testGetFeatureWriterFilter() throws NoSuchElementException, IOException, IllegalAttributeException { FeatureWriter writer; writer = data.getFeatureWriter("road", Filter.ALL, Transaction.AUTO_COMMIT); assertTrue(writer instanceof EmptyFeatureWriter); assertEquals(0, count(writer)); writer = data.getFeatureWriter("road", Filter.NONE, Transaction.AUTO_COMMIT); assertFalse(writer instanceof FilteringFeatureWriter); assertEquals(roadFeatures.length, count(writer)); writer = data.getFeatureWriter("road", rd1Filter, Transaction.AUTO_COMMIT); assertTrue(writer instanceof FilteringFeatureWriter); assertEquals(1, count(writer)); } /** * Test two transactions one removing feature, and one adding a feature. * * @throws Exception DOCUMENT ME! */ public void testGetFeatureWriterTransaction() throws Exception { Transaction t1 = new DefaultTransaction(); Transaction t2 = new DefaultTransaction(); FeatureWriter writer1 = data.getFeatureWriter("road", rd1Filter, t1); FeatureWriter writer2 = data.getFeatureWriterAppend("road", t2); FeatureType road = data.getSchema("road"); FeatureReader reader; SimpleFeature feature; SimpleFeature[] ORIGIONAL = roadFeatures; Feature[] REMOVE = new Feature[ORIGIONAL.length - 1]; Feature[] ADD = new Feature[ORIGIONAL.length + 1]; Feature[] FINAL = new Feature[ORIGIONAL.length]; int i; int index; index = 0; for (i = 0; i < ORIGIONAL.length; i++) { feature = ORIGIONAL[i]; if (!feature.getID().equals("road.rd1")) { REMOVE[index++] = feature; } } for (i = 0; i < ORIGIONAL.length; i++) { ADD[i] = ORIGIONAL[i]; } ADD[i] = newRoad; for (i = 0; i < REMOVE.length; i++) { FINAL[i] = REMOVE[i]; } FINAL[i] = newRoad; // start of with ORIGINAL reader = data.getFeatureReader( new DefaultQuery("road"), Transaction.AUTO_COMMIT); assertTrue(covers(reader, ORIGIONAL)); // writer 1 removes road.rd1 on t1 // ------------------------------- // - tests transaction independence from DataStore while (writer1.hasNext()) { feature = (SimpleFeature)writer1.next(); assertEquals("road.rd1", feature.getID()); writer1.remove(); } // still have ORIGIONAL and t1 has REMOVE reader = data.getFeatureReader(new DefaultQuery("road"), Transaction.AUTO_COMMIT); assertTrue(covers(reader, ORIGIONAL)); reader = data.getFeatureReader(new DefaultQuery("road"), t1); assertTrue(covers(reader, REMOVE)); // close writer1 // -------------- // ensure that modification is left up to transaction commmit writer1.close(); // We still have ORIGIONAL and t1 has REMOVE reader = data.getFeatureReader(new DefaultQuery("road"), Transaction.AUTO_COMMIT); assertTrue(covers(reader, ORIGIONAL)); reader = data.getFeatureReader(new DefaultQuery("road"), t1); assertTrue(covers(reader, REMOVE)); // writer 2 adds road.rd4 on t2 // ---------------------------- // - tests transaction independence from each other feature = (SimpleFeature)writer2.next(); feature.setAttributes(newRoad.getAttributes(null)); writer2.write(); // We still have ORIGIONAL and t2 has ADD reader = data.getFeatureReader(new DefaultQuery("road"), Transaction.AUTO_COMMIT); assertTrue(covers(reader, ORIGIONAL)); reader = data.getFeatureReader(new DefaultQuery("road"), t2); assertTrue(coversLax(reader, ADD)); // close writer2 // ------------- // ensure that modification is left up to transaction commmit writer2.close(); // Still have ORIGIONAL and t2 has ADD reader = data.getFeatureReader(new DefaultQuery("road"), Transaction.AUTO_COMMIT); assertTrue(covers(reader, ORIGIONAL)); reader = data.getFeatureReader(new DefaultQuery("road"), t2); assertTrue(coversLax(reader, ADD)); // commit t1 // --------- // -ensure that delayed writing of transactions takes place // t1.commit(); // We now have REMOVE, as does t1 (which has not additional diffs) // t2 will have FINAL reader = data.getFeatureReader(new DefaultQuery("road"), Transaction.AUTO_COMMIT); assertTrue(covers(reader, REMOVE)); reader = data.getFeatureReader(new DefaultQuery("road"), t1); assertTrue(covers(reader, REMOVE)); reader = data.getFeatureReader(new DefaultQuery("road"), t2); assertTrue(coversLax(reader, FINAL)); // commit t2 // --------- // -ensure that everyone is FINAL at the end of the day t2.commit(); // We now have Number( remove one and add one) reader = data.getFeatureReader( new DefaultQuery("road"), Transaction.AUTO_COMMIT); reader = data.getFeatureReader(new DefaultQuery("road"), Transaction.AUTO_COMMIT); assertTrue(coversLax(reader, FINAL)); reader = data.getFeatureReader(new DefaultQuery("road"), t1); assertTrue(coversLax(reader, FINAL)); reader = data.getFeatureReader(new DefaultQuery("road"), t2); assertTrue(coversLax(reader, FINAL)); } /** * Test the transaction when multiple edits occur using a transaction * and a fid filter. */ public void testModifyInTransactionFidFilter() throws Exception { Transaction t1 = new DefaultTransaction(); GeometryFactory fac=new GeometryFactory(); FeatureWriter writer1 = data.getFeatureWriter("road", rd1Filter, t1); writer1.next().setDefaultGeometry( fac.createLineString( new Coordinate[]{new Coordinate(0,0), new Coordinate(0,1)})); writer1.write(); writer1.close(); FeatureReader reader = data.getFeatureReader(new DefaultQuery("road", rd1Filter), t1); Geometry geom1 = reader.next().getDefaultGeometry(); reader.close(); assertEquals(new Coordinate(0,0), geom1.getCoordinates()[0]); assertEquals(new Coordinate(0,1), geom1.getCoordinates()[1]); writer1 = data.getFeatureWriter("road", rd1Filter, t1); writer1.next().setDefaultGeometry( fac.createLineString( new Coordinate[]{new Coordinate(10,0), new Coordinate(10,1)})); writer1.write(); writer1.close(); reader = data.getFeatureReader(new DefaultQuery("road", rd1Filter), t1); geom1 = reader.next().getDefaultGeometry(); reader.close(); assertEquals(new Coordinate(10,0), geom1.getCoordinates()[0]); assertEquals(new Coordinate(10,1), geom1.getCoordinates()[1]); FeatureWriter writer = data.getFeatureWriterAppend("road", t1); Feature feature=writer.next(); feature.setDefaultGeometry( fac.createLineString( new Coordinate[]{new Coordinate(20,0), new Coordinate(20,1)})); writer.write(); writer.close(); FidFilter filter=FilterFactoryFinder.createFilterFactory().createFidFilter(feature.getID()); reader = data.getFeatureReader(new DefaultQuery("road", filter), t1); geom1 = reader.next().getDefaultGeometry(); reader.close(); assertEquals(new Coordinate(20,0), geom1.getCoordinates()[0]); assertEquals(new Coordinate(20,1), geom1.getCoordinates()[1]); writer1 = data.getFeatureWriter("road", filter, t1); writer1.next().setDefaultGeometry( fac.createLineString( new Coordinate[]{new Coordinate(30,0), new Coordinate(30,1)})); writer1.write(); writer1.close(); reader = data.getFeatureReader(new DefaultQuery("road", filter), t1); geom1 = reader.next().getDefaultGeometry(); reader.close(); assertEquals(new Coordinate(30,0), geom1.getCoordinates()[0]); assertEquals(new Coordinate(30,1), geom1.getCoordinates()[1]); } // Feature Source Testing public void testGetFeatureSourceRoad() throws IOException { FeatureSource road = data.getFeatureSource("road"); assertSame(roadType, road.getSchema()); assertSame(data, road.getDataStore()); assertEquals(3, road.getCount(Query.ALL)); assertEquals(new Envelope(1, 5, 0, 4), road.getBounds(Query.ALL)); FeatureResults all = road.getFeatures(); assertEquals(3, all.getCount()); assertEquals(roadBounds, all.getBounds()); FeatureCollection expected = DataUtilities.collection(roadFeatures); assertCovers("all", expected, all.collection()); assertEquals(roadBounds, all.collection().getBounds()); FeatureResults some = road.getFeatures( rd12Filter ); assertEquals(2, some.getCount()); assertEquals( rd12Bounds, some.getBounds() ); assertEquals( some.getSchema(), road.getSchema() ); DefaultQuery query = new DefaultQuery( "road", rd12Filter, new String[]{ "name", }); FeatureResults half = road.getFeatures( query ); assertEquals( 2, half.getCount()); assertEquals( 1, half.getSchema().getAttributeCount() ); FeatureReader reader = half.reader(); FeatureType type = reader.getFeatureType(); reader.close(); FeatureType actual = half.getSchema(); assertEquals( type.getTypeName(), actual.getTypeName() ); assertEquals( type.getNamespace(), actual.getNamespace() ); assertEquals( type.getAttributeCount(), actual.getAttributeCount() ); for( int i=0; i