/* uDig-Spatial Operations plugins
* http://b5m.gipuzkoa.net
* (C) 2006, DiputaciĆ³n Foral de Gipuzkoa, OrdenaciĆ³n Territorial.
*
* 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 es.axios.udig.ui.editingtools.merge.internal.wizard;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.geotools.data.DataUtilities;
import org.geotools.feature.FeatureFactoryImpl;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.opengis.feature.Attribute;
import org.opengis.feature.FeatureFactory;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeType;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.io.WKTReader;
import es.axios.udig.ui.editingtools.merge.internal.wizard.MergeFeatureBuilder.ChangeListener;
/**
* Test suite for {@link MergeFeatureBuilder}
*
* @author Gabriel Roldan (www.axios.es)
* @author Mauricio Pazos (www.axios.es)
* @since 1.1.0
*/
public class MergeFeatureBuilderTest extends TestCase {
private static final String ATTNAME_NAME = "name";
private static final String ATTNAME_GEOM = "geom";
private static final String ATTNAME_INTATT = "intval";
private MergeFeatureBuilder builder;
private static SimpleFeature[] features;
private static SimpleFeatureType fType;
private static Geometry mergedGeometry = null;
public MergeFeatureBuilderTest( String name ) {
super(name);
}
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(MergeFeatureBuilderTest.class);
TestSetup wrapper = new TestSetup(suite){
protected void setUp() throws Exception {
oneTimeSetUp();
}
protected void tearDown() {
oneTimeTearDown();
}
};
return wrapper;
}
private static void oneTimeSetUp() throws Exception {
String identification = "TestFeatureType";
String typeSpec = "name:string:nillable,geom:LineString,intval:Integer:nillable";
fType = DataUtilities.createType(identification, typeSpec);
features = new SimpleFeature[3];
features[0] = SimpleFeature(fType, "name1", "LINESTRING(0 0, 10 10)", 1);
features[1] = SimpleFeature(fType, "name2", "LINESTRING(10 10, 10 20)", 1);
features[2] = SimpleFeature(fType, "name3", "LINESTRING(10 20, 20 20)", 1);
mergedGeometry = new WKTReader().read("LINESTRING(0 0, 10 10, 10 20, 20 20)");
}
private static SimpleFeature SimpleFeature( SimpleFeatureType ft, String name, String geom, int intAtt ) throws Exception {
Object[] values = new Object[3];
values[0] = name;
values[1] = new WKTReader().read(geom);
values[2] = new Integer(intAtt);
SimpleFeature f = SimpleFeatureBuilder.build( ft, values, null);
return f;
}
private static void oneTimeTearDown() {
}
protected void setUp() throws Exception {
super.setUp();
builder = new MergeFeatureBuilder(features, mergedGeometry);
}
protected void tearDown() throws Exception {
super.tearDown();
builder = null;
}
public void testMergeFeatureBuilderPreConditions() throws SchemaException, IllegalAttributeException {
SimpleFeature[] empty = new SimpleFeature[0];
try {
builder = new MergeFeatureBuilder(empty, mergedGeometry);
fail("shouldn't accept empty collection");
} catch (RuntimeException e) {
assertTrue(true);
}
SimpleFeatureType anotherSchema = DataUtilities.createSubType(fType, new String[]{ATTNAME_NAME,
ATTNAME_INTATT});
SimpleFeature[] mixedFeatures = new SimpleFeature[4];
mixedFeatures[0] = features[0];
mixedFeatures[1] = features[1];
mixedFeatures[2] = features[2];
SimpleFeature nonGeometryFeature = SimpleFeatureBuilder.build( anotherSchema, new Object[]{"a name", new Integer(1000)}, null);
mixedFeatures[3] = nonGeometryFeature;
try {
builder = new MergeFeatureBuilder(mixedFeatures, mergedGeometry);
fail("shouldn't accept features of mixed schemas");
} catch (IllegalArgumentException iae) {
assertTrue(true);
}
SimpleFeature[] nonGeomCollection = {nonGeometryFeature};
try {
builder = new MergeFeatureBuilder(nonGeomCollection, mergedGeometry);
fail("shouldn't accept schema with no default geometry");
} catch (IllegalArgumentException iae) {
assertTrue(true);
}
Geometry illegalGeomType = new GeometryFactory().createPoint(new Coordinate(0, 0));
try {
builder = new MergeFeatureBuilder(features, illegalGeomType);
fail("failure expected as the merge geometry passed is not assignable "
+ "to the features schema default geom");
} catch (IllegalArgumentException e) {
assertTrue(true);
}
}
public void testAddChangeListener() {
class TestListener implements ChangeListener {
MergeFeatureBuilder callbackBuilder;
int changedAttributeIndex;
Object oldAttributeValue;
public void attributeChanged( MergeFeatureBuilder builder, int attributeIndex,
Object oldValue ) {
this.callbackBuilder = builder;
this.changedAttributeIndex = attributeIndex;
this.oldAttributeValue = oldValue;
}
}
TestListener listener = new TestListener();
builder.addChangeListener(listener);
int featureIndex = 1;
int attributeIndex = 0;
Object expectedOldValue = builder.getMergeAttribute(attributeIndex);
builder.setMergeAttribute(featureIndex, attributeIndex);
assertSame(builder, listener.callbackBuilder);
assertSame(attributeIndex, listener.changedAttributeIndex);
assertSame(expectedOldValue, listener.oldAttributeValue);
}
/**
* This test is a kind of fun; they want to force failure and ensure
* that the merge fails.
* <p>
* I am going to force failure by putting an impossible restriction on the FeatureType.
* </p>
* @throws SchemaException
* @throws IllegalAttributeException
*/
public void testBuildMergedFeatureFailsIfCreateFails() throws SchemaException, IllegalAttributeException {
/**
* DefaultFeatureType subclass with the sole pourpose of allowing us to force when to fail
* on a call to create(Object[])
*/
// class FailOnDemandType extends DefaultFeatureType {
// // flag to indicate if fail on #create(...) or not
// boolean failOnCreate = false;
// public FailOnDemandType( String typeName, String namespace, Collection types,
// Collection superTypes, GeometryAttributeType defaultGeom ) throws SchemaException, NullPointerException {
// super(typeName, namespace, types, superTypes, defaultGeom);
// }
//
// public SimpleFeature create( Object[] attributes ) throws IllegalAttributeException {
// if (failOnCreate) {
// throw new IllegalAttributeException("Forced failure for unit test purposes");
// }
// return super.create(attributes);
// }
// }
class FailFeatureFactory extends FeatureFactoryImpl {
// flag to indicate if fail on #create(...) or not
boolean failOnCreate = false;
@Override
public SimpleFeature createSimpleFeature( List<Attribute> value,
SimpleFeatureType type, String id ) {
if( failOnCreate ){
throw new IllegalAttributeException("Forced failure for unit test purposes");
}
return super.createSimpleFeature(value, type, id);
}
};
FailFeatureFactory factory = new FailFeatureFactory();
SimpleFeatureBuilder create = new SimpleFeatureBuilder( fType, factory );
create.addAll( features[0].getAttributes() );
SimpleFeature f = create.buildFeature(features[0].getID()+"_copy");
SimpleFeature[] collection = {f};
builder = new MergeFeatureBuilder(collection, null);
// now force our SimpleFeature type to fail on create
factory.failOnCreate = true;
try {
builder.setFactory(factory);
builder.buildMergedFeature();
fail("cleared a non null attribute shouldn't allow to build the merge SimpleFeature");
} catch (IllegalStateException e) {
assertTrue(true);
}
}
public void testBuildMergedFeatureNullProvidedGeometry() {
builder = new MergeFeatureBuilder(features, null);
Geometry assignedGeometry = (Geometry) features[0].getDefaultGeometry();
SimpleFeature merged = builder.buildMergedFeature();
assertSame(assignedGeometry, merged.getDefaultGeometry());
}
public void testGetMergedGeometry() {
assertSame(mergedGeometry, builder.getMergedGeometry());
builder = new MergeFeatureBuilder(features, null);
assertNull(builder.getMergedGeometry());
}
public void testMergeGeomIsUnion() throws ArrayIndexOutOfBoundsException, IllegalAttributeException {
assertTrue(builder.mergeGeomIsUnion());
final int geomAttIndex = fType.indexOf(ATTNAME_GEOM);
builder.setMergeAttribute(2, geomAttIndex);
assertFalse(builder.mergeGeomIsUnion());
builder = new MergeFeatureBuilder(features, null);
assertFalse(builder.mergeGeomIsUnion());
// say both the provided geometry is null and we assign
// de value of a SimpleFeature where the geom is also null
features[1].setAttribute(geomAttIndex, null);
builder = new MergeFeatureBuilder(features, null);
builder.setMergeAttribute(1, geomAttIndex);
// now both the assigned value and the provided geom are null
// but the assigned value is NOT the provided geom
assertFalse("expected false even if the assigned "
+ "value and the provided geom are both null", builder.mergeGeomIsUnion());
}
public void testSetAndGetMergeAttribute() {
// attribute index 1 is the geometry one
assertSame(features[0].getAttribute(0), builder.getMergeAttribute(0));
assertSame(mergedGeometry, builder.getMergeAttribute(1));
assertSame(features[0].getAttribute(2), builder.getMergeAttribute(2));
builder.setMergeAttribute(2, 1);
assertSame(features[2].getAttribute(1), builder.getMergeAttribute(1));
builder.setMergeAttribute(1, 2);
assertSame(features[1].getAttribute(2), builder.getMergeAttribute(2));
}
public void testClearMergeAttribute() {
builder.clearMergeAttribute(0);
assertNull(builder.getMergeAttribute(0));
int geomAttIndex = 1;
builder.setMergeAttribute(1, geomAttIndex);
assertNotSame(mergedGeometry, builder.getMergeAttribute(geomAttIndex));
builder.clearMergeAttribute(geomAttIndex);
assertSame(mergedGeometry, builder.getMergeAttribute(1));
builder.clearMergeAttribute(2);
assertNull(builder.getMergeAttribute(2));
}
public void testGetAttribute() {
// not much could be wronng here, lets check it so
assertSame(features[0].getAttribute(0), builder.getAttribute(0, 0));
assertSame(features[0].getAttribute(1), builder.getAttribute(0, 1));
assertSame(features[0].getAttribute(2), builder.getAttribute(0, 2));
assertSame(features[1].getAttribute(0), builder.getAttribute(1, 0));
assertSame(features[1].getAttribute(1), builder.getAttribute(1, 1));
assertSame(features[1].getAttribute(2), builder.getAttribute(1, 2));
assertSame(features[2].getAttribute(0), builder.getAttribute(2, 0));
assertSame(features[2].getAttribute(1), builder.getAttribute(2, 1));
assertSame(features[2].getAttribute(2), builder.getAttribute(2, 2));
}
}