sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1596580 - in /sis/branches/JDK8/core/sis-feature/src: main/java/org/apache/sis/feature/ test/java/org/apache/sis/feature/
Date Wed, 21 May 2014 14:17:16 GMT
Author: desruisseaux
Date: Wed May 21 14:17:16 2014
New Revision: 1596580

URL: http://svn.apache.org/r1596580
Log:
Added tests.

Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -62,7 +62,7 @@ import org.apache.sis.util.CorruptedObje
  *
  * @see DefaultFeatureType#newInstance()
  */
-public abstract class AbstractFeature implements Serializable {
+public abstract class AbstractFeature implements Cloneable, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -376,6 +376,22 @@ public abstract class AbstractFeature im
     }
 
     /**
+     * Returns a copy of this feature
+     * This method clones also all {@linkplain Cloneable cloneable} property instances in
this feature,
+     * but not necessarily property values. Whether the property values are cloned or not
(i.e. whether
+     * the clone operation is <cite>deep</cite> or <cite>shallow</cite>)
depends on the behavior or
+     * property {@code clone()} methods (see for example {@link DefaultAttribute#clone()}).
+     *
+     * @return A clone of this attribute.
+     * @throws CloneNotSupportedException if this feature can not be cloned, typically because
+     *         {@code clone()} on a property instance failed.
+     */
+    @Override
+    public AbstractFeature clone() throws CloneNotSupportedException {
+        return (AbstractFeature) super.clone();
+    }
+
+    /**
      * Returns a hash code value for this feature.
      *
      * @return A hash code value.

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -176,20 +176,18 @@ public class DefaultAssociation extends 
     }
 
     /**
-     * Returns a shallow copy of this association.
-     * The association {@linkplain #getValue() value} is <strong>not</strong>
cloned.
+     * Returns a copy of this association.
+     * The default implementation returns a <em>shallow</em> copy:
+     * the association {@linkplain #getValue() value} is <strong>not</strong>
cloned.
+     * However subclasses may choose to do otherwise.
      *
      * @return A clone of this association.
+     * @throws CloneNotSupportedException if this association can not be cloned.
+     *         The default implementation never throw this exception. However subclasses
may throw it.
      */
     @Override
-    public DefaultAssociation clone() {
-        final DefaultAssociation clone;
-        try {
-            clone = (DefaultAssociation) super.clone();
-        } catch (CloneNotSupportedException e) {
-            throw new AssertionError(e); // Should never happen since we are cloneable.
-        }
-        return clone;
+    public DefaultAssociation clone() throws CloneNotSupportedException {
+        return (DefaultAssociation) super.clone();
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -219,21 +219,20 @@ public class DefaultAttribute<T> extends
     }
 
     /**
-     * Returns a shallow copy of this attribute.
-     * The attribute {@linkplain #getValue() value} is <strong>not</strong> cloned.
+     * Returns a copy of this attribute.
+     * The default implementation returns a <em>shallow</em> copy:
+     * the attribute {@linkplain #getValue() value} is <strong>not</strong> cloned.
+     * However subclasses may choose to do otherwise.
      *
      * @return A clone of this attribute.
+     * @throws CloneNotSupportedException if this attribute can not be cloned.
+     *         The default implementation never throw this exception. However subclasses
may throw it,
+     *         for example on attempt to clone the attribute value.
      */
     @Override
     @SuppressWarnings("unchecked")
-    public DefaultAttribute<T> clone() {
-        final DefaultAttribute<T> clone;
-        try {
-            clone = (DefaultAttribute<T>) super.clone();
-        } catch (CloneNotSupportedException e) {
-            throw new AssertionError(e); // Should never happen since we are cloneable.
-        }
-        return clone;
+    public DefaultAttribute<T> clone() throws CloneNotSupportedException {
+        return (DefaultAttribute<T>) super.clone();
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -286,8 +286,17 @@ public class DefaultFeatureType extends 
             }
         }
         indices = compact(indices);
+        /*
+         * Rational for choosing whether the feature is sparse: By default, java.util.HashMap
implementation creates
+         * an internal array of length 16 (see HashMap.DEFAULT_INITIAL_CAPACITY).  In addition,
the HashMap instance
+         * itself consumes approximatively 8 "words" in memory.  Consequently there is no
advantage in using HashMap
+         * unless the number of properties is greater than 16 + 8 (note: we could specify
a smaller initial capacity,
+         * but the memory consumed by each internal Map.Entry quickly exceed the few saved
words). Next, the default
+         * HashMap threshold is 0.75, so there is again no advantage in using HashMap if
we do not expect at least 25%
+         * of unused properties. Our current implementation arbitrarily sets the threshold
to 50%.
+         */
         final int n = indices.size();
-        isSparse = (n > 16) && (mandatory < n/2); // Arbitrary criterion.
+        isSparse = (n > 24) && (mandatory <= n/2);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.Arrays;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.metadata.quality.DataQuality;
+import org.apache.sis.internal.util.Cloner;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
@@ -214,6 +215,29 @@ final class DenseFeature extends Abstrac
     }
 
     /**
+     * Returns a shallow copy of this feature.
+     * The properties are cloned, but not the property values.
+     *
+     * @return A clone of this feature.
+     */
+    @Override
+    public AbstractFeature clone() throws CloneNotSupportedException {
+        final DenseFeature clone = (DenseFeature) super.clone();
+        clone.properties = clone.properties.clone();
+        if (clone.properties instanceof Property[]) {
+            final Property[] p = (Property[]) clone.properties;
+            final Cloner cloner = new Cloner();
+            for (int i=0; i<p.length; i++) {
+                final Property property = p[i];
+                if (property instanceof Cloneable) {
+                    p[i] = (Property) cloner.clone(property);
+                }
+            }
+        }
+        return clone;
+    }
+
+    /**
      * Returns a hash code value for this feature.
      *
      * @return A hash code value.

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -19,8 +19,10 @@ package org.apache.sis.feature;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.ConcurrentModificationException;
+import java.lang.reflect.Field;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.metadata.quality.DataQuality;
+import org.apache.sis.internal.util.Cloner;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CorruptedObjectException;
 
@@ -71,7 +73,7 @@ final class SparseFeature extends Abstra
      *
      * @see #valuesKind
      */
-    private final Map<String, Object> properties;
+    private final HashMap<String, Object> properties;
 
     /**
      * {@link #PROPERTIES} if the values in the {@link #properties} map are {@link Property}
instances,
@@ -236,6 +238,40 @@ final class SparseFeature extends Abstra
     }
 
     /**
+     * Returns a copy of this feature.
+     * The properties are cloned, but not the property values.
+     *
+     * @return A clone of this feature.
+     */
+    @Override
+    public AbstractFeature clone() throws CloneNotSupportedException {
+        final SparseFeature clone = (SparseFeature) super.clone();
+        try {
+            final Field field = SparseFeature.class.getDeclaredField("properties");
+            field.setAccessible(true);
+            field.set(clone, clone.properties.clone());
+        } catch (ReflectiveOperationException e) {
+            throw new AssertionError(e);
+        }
+        switch (clone.valuesKind) {
+            default:        throw new AssertionError(clone.valuesKind);
+            case CORRUPTED: throw new CorruptedObjectException(clone.getName());
+            case VALUES:    break; // Nothing to do.
+            case PROPERTIES: {
+                final Cloner cloner = new Cloner();
+                for (final Map.Entry<String,Object> entry : clone.properties.entrySet())
{
+                    final Property property = (Property) entry.getValue();
+                    if (property instanceof Cloneable) {
+                        entry.setValue(cloner.clone(property));
+                    }
+                }
+                break;
+            }
+        }
+        return clone;
+    }
+
+    /**
      * Returns a hash code value for this feature.
      *
      * @return A hash code value.

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationTest.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -59,7 +59,7 @@ public final strictfp class DefaultAssoc
     public void testWrongValue() {
         final DefaultAssociation association  = twinTown();
         final PropertyType       population   = association.getRole().getValueType().getProperty("population");
-        final AbstractFeature     otherFeature = new DefaultFeatureType(
+        final AbstractFeature    otherFeature = new DefaultFeatureType(
                 singletonMap(DefaultFeatureType.NAME_KEY, "Population"), false, null, population).newInstance();
         try {
             association.setValue(otherFeature);
@@ -76,7 +76,8 @@ public final strictfp class DefaultAssoc
      */
     @Test
     public void testSerialization() {
-        assertSerializedEquals(twinTown());
+        final DefaultAssociation twinTown = twinTown();
+        assertNotSame(twinTown, assertSerializedEquals(twinTown));
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -132,10 +132,12 @@ public final strictfp class DefaultAttri
 
     /**
      * Tests {@link DefaultAttribute#clone()}.
+     *
+     * @throws CloneNotSupportedException Should never happen.
      */
     @Test
     @DependsOnMethod("testEquals")
-    public void testClone() {
+    public void testClone() throws CloneNotSupportedException {
         final DefaultAttribute<Integer> a1 = population();
         final DefaultAttribute<Integer> a2 = a1.clone();
         assertNotSame(a1, a2);
@@ -149,7 +151,7 @@ public final strictfp class DefaultAttri
     @DependsOnMethod("testEquals")
     public void testSerialization() {
         final DefaultAttribute<String> attribute = city();
-        assertSerializedEquals(attribute);
+        assertNotSame(attribute, assertSerializedEquals(attribute));
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -107,6 +107,14 @@ public final strictfp class DefaultFeatu
     }
 
     /**
+     * Creates a sub-type of the "metropolis" type with the "region" attribute overridden
to
+     * {@link InternationalString}.
+     */
+    static DefaultFeatureType worldMetropolis() {
+        return worldMetropolis(metropolis(), InternationalString.class);
+    }
+
+    /**
      * Creates a sub-type of the "metropolis" type with the "region" attribute overridden
to the given type.
      * The given type should be {@link InternationalString}, but we allow other type for
testing argument checks.
      */

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java?rev=1596580&r1=1596579&r2=1596580&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
[UTF-8] Wed May 21 14:17:16 2014
@@ -16,6 +16,10 @@
  */
 package org.apache.sis.feature;
 
+import org.opengis.metadata.quality.Element;
+import org.opengis.metadata.quality.Result;
+import org.opengis.metadata.quality.ConformanceResult;
+import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -98,23 +102,51 @@ abstract strictfp class FeatureTestCase 
     }
 
     /**
+     * Sets the attribute of the given name to the given value.
+     * First, this method verifies that the previous value is equals to the given one.
+     * Then, this method set the attribute to the given value and check if the result.
+     *
+     * @param name     The name of the attribute to set.
+     * @param oldValue The expected old value (may be {@code null}).
+     * @param newValue The new value to set.
+     */
+    private void setAttributeValue(final String name, final Object oldValue, final Object
newValue) {
+        assertEquals(name, oldValue, getAttributeValue(name));
+        feature.setPropertyValue(name, newValue);
+        assertEquals(name, newValue, getAttributeValue(name));
+    }
+
+    /**
      * Tests the {@link AbstractFeature#getPropertyValue(String)} method on a simple feature
without super-types.
+     * This method also tests that attempts to set a value of the wrong type throw an exception
and leave the
+     * previous value unchanged, that the feature is cloneable and that serialization works.
      */
     @Test
     public void testSimpleValues() {
         feature = createFeature(DefaultFeatureTypeTest.city());
-
-        assertEquals("Utopia", getAttributeValue("city"));
-        feature.setPropertyValue("city", "Atlantide");
-        assertEquals("Atlantide", feature.getPropertyValue("city"));
-
-        assertNull(getAttributeValue("population"));
-        feature.setPropertyValue("population", 1000);
-        assertEquals(1000, getAttributeValue("population"));
+        setAttributeValue("city", "Utopia", "Atlantide");
+        try {
+            feature.setPropertyValue("city", 2000);
+        } catch (ClassCastException e) {
+            final String message = e.getMessage();
+            assertTrue(message, message.contains("city"));
+            assertTrue(message, message.contains("Integer"));
+        }
+        assertEquals("Property shall not have been modified.", "Atlantide", getAttributeValue("city"));
+        setAttributeValue("population", null, 1000);
+        assertValid();
+        testSerialization();
+        try {
+            testClone("population", 1000, 1500);
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
     }
 
     /**
      * Tests the {@link AbstractFeature#getProperty(String)} method on a simple feature without
super-types.
+     * This method also tests that attempts to set a value of the wrong type throw an exception
and leave the
+     * previous value unchanged.
      */
     @Test
     @DependsOnMethod("testSimpleValues")
@@ -122,4 +154,87 @@ abstract strictfp class FeatureTestCase 
         getValuesFromProperty = true;
         testSimpleValues();
     }
+
+    /**
+     * Tests {@link AbstractFeature#getProperty(String)} and {@link AbstractFeature#getPropertyValue(String)}
+     * on a "complex" feature, involving inheritance and property overriding.
+     */
+    @Test
+    @DependsOnMethod({"testSimpleValues", "testSimpleProperties"})
+    public void testComplexFeature() {
+        feature = createFeature(DefaultFeatureTypeTest.worldMetropolis());
+        setAttributeValue("city", "Utopia", "New York");
+        setAttributeValue("population", null, 8405837); // Estimation for 2013.
+        /*
+         * Switch to 'getProperty' mode only after we have set at least one value,
+         * in order to test the conversion of existing values to property instances.
+         */
+        getValuesFromProperty = true;
+        setAttributeValue("isGlobal", null, Boolean.TRUE);
+        final SimpleInternationalString region = new SimpleInternationalString("State of
New York");
+        setAttributeValue("region", null, region);
+        /*
+         * In our 'metropolis' feature type, the region can be any CharSequence. But 'worldMetropolis'
+         * feature type overrides the region property with a restriction to InternationalString.
+         * Verifiy that this restriction is checked.
+         */
+        try {
+            feature.setPropertyValue("region", "State of New York");
+        } catch (ClassCastException e) {
+            final String message = e.getMessage();
+            assertTrue(message, message.contains("region"));
+            assertTrue(message, message.contains("String"));
+        }
+        assertSame("region", region, getAttributeValue("region"));
+        assertValid();
+        testSerialization();
+        try {
+            testClone("population", 8405837, 8405838); // A birth...
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Asserts that {@link AbstractFeature#quality()} reports no anomaly.
+     */
+    private void assertValid() {
+        for (final Element report : feature.quality().getReports()) {
+            for (final Result result : report.getResults()) {
+                assertInstanceOf("result", ConformanceResult.class, result);
+                assertTrue("result.pass", ((ConformanceResult) result).pass());
+            }
+        }
+    }
+
+    /**
+     * Tests the {@link AbstractFeature#clone()} method on the current {@link #feature} instance.
+     * This method is invoked from other test methods using the existing feature instance
in an opportunist way.
+     *
+     * @param  property The name of a property to change.
+     * @param  oldValue The old value of the given property.
+     * @param  newValue The new value of the given property.
+     * @throws CloneNotSupportedException Should never happen.
+     */
+    private void testClone(final String property, final Object oldValue, final Object newValue)
+            throws CloneNotSupportedException
+    {
+        final AbstractFeature clone = feature.clone();
+        assertNotSame("clone",      clone, feature);
+        assertTrue   ("equals",     clone.equals(feature));
+        assertTrue   ("hashCode",   clone.hashCode() == feature.hashCode());
+        setAttributeValue(property, oldValue, newValue);
+        assertEquals (property,     oldValue, clone  .getPropertyValue(property));
+        assertEquals (property,     newValue, feature.getPropertyValue(property));
+        assertFalse  ("equals",     clone.equals(feature));
+        assertFalse  ("hashCode",   clone.hashCode() == feature.hashCode());
+    }
+
+    /**
+     * Tests serialization of current {@link #feature} instance.
+     * This method is invoked from other test methods using the existing feature instance
in an opportunist way.
+     */
+    private void testSerialization() {
+        assertNotSame(feature, assertSerializedEquals(feature));
+    }
 }



Mime
View raw message