You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2012/09/30 13:25:30 UTC
svn commit: r1391998 - in /sis/trunk: ./
sis-utility/src/main/java/org/apache/sis/util/
sis-utility/src/test/java/org/apache/sis/internal/
sis-utility/src/test/java/org/apache/sis/internal/test/
sis-utility/src/test/java/org/apache/sis/test/
Author: desruisseaux
Date: Sun Sep 30 11:25:29 2012
New Revision: 1391998
URL: http://svn.apache.org/viewvc?rev=1391998&view=rev
Log:
Initial commit of org.apache.sis.test package, including a JUnit TestRunner taking in account the @Dependency annotation.
Added:
sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Workaround.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/
sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/
sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/AssertTest.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/XMLComparatorTest.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/package-info.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/test/
sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Dependency.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java (with props)
sis/trunk/sis-utility/src/test/java/org/apache/sis/test/package-info.java (with props)
Modified:
sis/trunk/NOTICE
sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Debug.java
Modified: sis/trunk/NOTICE
URL: http://svn.apache.org/viewvc/sis/trunk/NOTICE?rev=1391998&r1=1391997&r2=1391998&view=diff
==============================================================================
--- sis/trunk/NOTICE (original)
+++ sis/trunk/NOTICE Sun Sep 30 11:25:29 2012
@@ -4,3 +4,5 @@ Copyright 2010-2012 The Apache Software
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
+The test suite includes software developed by
+the JUnit community (http://github.com/junit-team/junit.contrib/)
Modified: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Debug.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Debug.java?rev=1391998&r1=1391997&r2=1391998&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Debug.java (original)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Debug.java Sun Sep 30 11:25:29 2012
@@ -28,7 +28,15 @@ import java.lang.annotation.RetentionPol
* is defined in order to make easier to find which debugging tools are available in case of
* problem. See the "<cite>Use</cite>" javadoc link for a list of annotated classes and methods.
*
- * @author Martin Desruisseaux (Geomatys)
+ * {@section <code>Object.toString()</code> policy}
+ * Subclasses override the {@link Object#toString()} method for various purposes, sometime providing
+ * content targeted to the end user (e.g. {@link java.lang.CharSequence}) and sometime providing
+ * debugging information for developers only. In the Apache SIS library, <code>toString()</code>
+ * methods without <code>@Debug</code> annotation shall be understandable by the end users,
+ * while <code>toString()</code> methods with <code>@Debug</code> annotation is targeted to
+ * developers and may change in any future version.
+ *
+ * @author Martin Desruisseaux (Geomatys)
* @since 0.3 (derived from geotk-3.19)
* @version 0.3
* @module
Added: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Workaround.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Workaround.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Workaround.java (added)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Workaround.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+
+/**
+ * Annotates code containing workarounds for bugs or limitations in an external library.
+ * This is marker annotation for source code only, in order to keep trace of code to revisit
+ * when new versions of external libraries become available.
+ *
+ * {@note When only a portion of a method contains a workaround and the annotation can not be
+ * applied to that specific part, than it is applied to the whole method. Developers need to
+ * refer to code comments in order to locate the specific part.}
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.15)
+ * @version 0.3
+ * @module
+ */
+@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD,
+ ElementType.FIELD, ElementType.LOCAL_VARIABLE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface Workaround {
+ /**
+ * A string identifying the library having a bug or limitation.
+ * Examples: {@code "JDK"}, {@code "NetCDF"}, {@code "JUnit"}, {@code "SIS"}.
+ *
+ * @return An identifier of the library having a bug or limitation.
+ */
+ String library();
+
+ /**
+ * The last library version on which the bug has been verified.
+ * The bug may have existed before, and may still exist later.
+ *
+ * @return The library version on which the bug has been observed.
+ */
+ String version();
+}
Propchange: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Workaround.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/Workaround.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/AssertTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/AssertTest.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/AssertTest.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/AssertTest.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.test;
+
+import org.junit.*;
+import static org.apache.sis.test.Assert.*;
+
+
+/**
+ * Tests the {@link org.apache.sis.test.Assert} class.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.00)
+ * @version 0.3
+ * @module
+ */
+public final strictfp class AssertTest {
+ /**
+ * Tests the {@link Assert#assertMultilinesEquals(String, String)} method.
+ */
+ @Test
+ public void testAssertEqualsMultilines() {
+ assertMultilinesEquals("Line 1\nLine 2\r\nLine 3\n\rLine 5",
+ "Line 1\rLine 2\nLine 3\n\nLine 5");
+ }
+
+ /**
+ * Tests the {@link Assert#assertSerializedEquals(Object)} method.
+ */
+ @Test
+ public void testSerialize() {
+ final String local = "Le silence éternel de ces espaces infinis m'effraie";
+ assertNotSame(local, assertSerializedEquals(local));
+ }
+}
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/AssertTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/AssertTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/XMLComparatorTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/XMLComparatorTest.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/XMLComparatorTest.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/XMLComparatorTest.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.test;
+
+import org.apache.sis.test.XMLComparator;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests the {@link XMLComparator} class.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.17)
+ * @version 0.3
+ * @module
+ */
+public final strictfp class XMLComparatorTest {
+ /**
+ * Tests the {@link XMLComparator#ignoredAttributes} and {@link XMLComparator#ignoredNodes}
+ * sets.
+ *
+ * @throws Exception Should never happen.
+ */
+ @Test
+ public void testIgnore() throws Exception {
+ final XMLComparator cmp = new XMLComparator(
+ "<body>\n" +
+ " <form id=\"MyForm\">\n" +
+ " <table cellpading=\"1\">\n" +
+ " <tr><td>foo</td></tr>\n" +
+ " </table>\n" +
+ " </form>\n" +
+ "</body>",
+ "<body>\n" +
+ " <form id=\"MyForm\">\n" +
+ " <table cellpading=\"2\">\n" +
+ " <tr><td>foo</td></tr>\n" +
+ " </table>\n" +
+ " </form>\n" +
+ "</body>");
+
+ ensureFail("Should fail because the \"cellpading\" attribute value is different.", cmp);
+
+ // Following comparison should not fail anymore.
+ cmp.ignoredAttributes.add("cellpading");
+ cmp.compare();
+
+ cmp.ignoredAttributes.clear();
+ cmp.ignoredAttributes.add("bgcolor");
+ ensureFail("The \"cellpading\" attribute should not be ignored anymore.", cmp);
+
+ // Ignore the table node, which contains the faulty attribute.
+ cmp.ignoredNodes.add("table");
+ cmp.compare();
+
+ // Ignore the form node and all its children.
+ cmp.ignoredNodes.clear();
+ cmp.ignoredNodes.add("form");
+ cmp.compare();
+ }
+
+ /**
+ * Ensures that the call to {@link XMLComparator#compare()} fails. This method is
+ * invoked in order to test that the comparator rightly detected an error that we
+ * were expected to detect.
+ *
+ * @param message The message for JUnit if the comparison does not fail.
+ * @param cmp The comparator on which to invoke {@link XMLComparator#compare()}.
+ */
+ private static void ensureFail(final String message, final XMLComparator cmp) {
+ try {
+ cmp.compare();
+ } catch (AssertionError e) {
+ return;
+ }
+ fail(message);
+ }
+}
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/XMLComparatorTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/XMLComparatorTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/package-info.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/package-info.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/package-info.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Self tests of the {@link org.apache.sis.test} package.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.00)
+ * @version 0.3
+ * @module
+ */
+package org.apache.sis.internal.test;
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/package-info.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/internal/test/package-info.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,320 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.test;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RectangularShape;
+import java.awt.image.RenderedImage;
+import javax.swing.tree.TreeNode;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.SAXException;
+
+import org.apache.sis.util.CharSequences;
+
+
+/**
+ * Assertion methods used by the SIS project in addition of the JUnit and GeoAPI assertions.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.00)
+ * @version 0.3
+ * @module
+ */
+public strictfp class Assert extends org.opengis.test.Assert {
+ /**
+ * For subclass constructor only.
+ */
+ protected Assert() {
+ }
+
+ /**
+ * Asserts that two strings are equal, ignoring the differences in EOL characters.
+ * The comparisons is performed one a line-by-line basis. For each line, leading
+ * and trailing spaces are ignored in order to make the comparison independent of
+ * indentation.
+ *
+ * @param expected The expected string.
+ * @param actual The actual string.
+ */
+ public static void assertMultilinesEquals(final CharSequence expected, final CharSequence actual) {
+ assertArrayEquals(CharSequences.split(expected, '\n'), CharSequences.split(actual, '\n'));
+ }
+
+ /**
+ * Asserts that two strings are equal, ignoring the differences in EOL characters.
+ * The comparisons is performed one a line-by-line basis. For each line, leading
+ * and trailing spaces are ignored in order to make the comparison independent of
+ * indentation.
+ *
+ * @param message The message to print in case of failure, or {@code null} if none.
+ * @param expected The expected string.
+ * @param actual The actual string.
+ */
+ public static void assertMultilinesEquals(final String message, final CharSequence expected, final CharSequence actual) {
+ assertArrayEquals(message, CharSequences.split(expected, '\n'), CharSequences.split(actual, '\n'));
+ }
+
+ /**
+ * Ensures that a tree is equals to an other tree.
+ * This method invokes itself recursively for every child nodes.
+ *
+ * @param expected The expected tree, or {@code null}.
+ * @param actual The tree to compare with the expected one, or {@code null}.
+ * @return The number of nodes.
+ */
+ public static int assertTreeEquals(final TreeNode expected, final TreeNode actual) {
+ if (expected == null) {
+ assertNull(actual);
+ return 0;
+ }
+ int n = 1;
+ assertNotNull(actual);
+ assertEquals("isLeaf()", expected.isLeaf(), actual.isLeaf());
+ assertEquals("getAllowsChildren()", expected.getAllowsChildren(), actual.getAllowsChildren());
+ assertEquals("getChildCount()", expected.getChildCount(), actual.getChildCount());
+ @SuppressWarnings("unchecked") final Enumeration<? extends TreeNode> ec = expected.children();
+ @SuppressWarnings("unchecked") final Enumeration<? extends TreeNode> ac = actual .children();
+
+ int childIndex = 0;
+ while (ec.hasMoreElements()) {
+ assertTrue("hasMoreElements()", ac.hasMoreElements());
+ final TreeNode nextExpected = ec.nextElement();
+ final TreeNode nextActual = ac.nextElement();
+ final String message = "getChildAt(" + childIndex + ')';
+ assertSame(message, nextExpected, expected.getChildAt(childIndex));
+ assertSame(message, nextActual, actual .getChildAt(childIndex));
+ assertSame("getParent()", expected, nextExpected.getParent());
+ assertSame("getParent()", actual, nextActual .getParent());
+ assertSame("getIndex(TreeNode)", childIndex, expected.getIndex(nextExpected));
+ assertSame("getIndex(TreeNode)", childIndex, actual .getIndex(nextActual));
+ n += assertTreeEquals(nextExpected, nextActual);
+ childIndex++;
+ }
+ assertFalse("hasMoreElements()", ac.hasMoreElements());
+ assertEquals("toString()", expected.toString(), actual.toString());
+ return n;
+ }
+
+ /**
+ * Parses two XML tree as DOM documents, and compares the nodes.
+ * The inputs given to this method can be any of the following types:
+ * <p>
+ * <ul>
+ * <li>{@link org.w3c.dom.Node}; used directly without further processing.</li>
+ * <li>{@link java.io.File}, {@link java.net.URL} or {@link java.net.URI}: the
+ * stream is opened and parsed as a XML document.</li>
+ * <li>{@link String}: The string content is parsed directly as a XML document.
+ * Encoding <strong>must</strong> be UTF-8 (no other encoding is supported
+ * by current implementation of this method).</li>
+ * </ul>
+ * <p>
+ * This method will ignore comments and the optional attributes given in arguments.
+ *
+ * @param expected The expected XML document.
+ * @param actual The XML document to compare.
+ * @param ignoredAttributes The fully-qualified names of attributes to ignore
+ * (typically {@code "xmlns:*"} and {@code "xsi:schemaLocation"}).
+ *
+ * @see XMLComparator
+ */
+ public static void assertXmlEquals(final Object expected, final Object actual,
+ final String... ignoredAttributes)
+ {
+ assertXmlEquals(expected, actual, 0, ignoredAttributes);
+ }
+
+ /**
+ * Parses two XML tree as DOM documents, and compares the nodes with the given tolerance
+ * threshold for numerical values. The inputs given to this method can be any of the types
+ * documented {@linkplain #assertXmlEquals(Object, Object, String[]) above}. This method
+ * will ignore comments and the optional attributes given in arguments.
+ *
+ * @param expected The expected XML document.
+ * @param actual The XML document to compare.
+ * @param tolerance The tolerance threshold for comparison of numerical values.
+ * @param ignoredAttributes The fully-qualified names of attributes to ignore
+ * (typically {@code "xmlns:*"} and {@code "xsi:schemaLocation"}).
+ *
+ * @see XMLComparator
+ */
+ public static void assertXmlEquals(final Object expected, final Object actual,
+ final double tolerance, final String... ignoredAttributes)
+ {
+ final XMLComparator comparator;
+ try {
+ comparator = new XMLComparator(expected, actual);
+ } catch (IOException e) {
+ // We don't throw directly those exceptions since failing to parse the XML file can
+ // be considered as part of test failures and the JUnit exception for such failures
+ // is AssertionError. Having no checked exception in "assert" methods allow us to
+ // declare the checked exceptions only for the library code being tested.
+ throw new AssertionError(e);
+ } catch (ParserConfigurationException e) {
+ throw new AssertionError(e);
+ } catch (SAXException e) {
+ throw new AssertionError(e);
+ }
+ comparator.tolerance = tolerance;
+ comparator.ignoreComments = true;
+ comparator.ignoredAttributes.addAll(Arrays.asList(ignoredAttributes));
+ comparator.compare();
+ }
+
+ /**
+ * Tests if the given {@code outer} shape contains the given {@code inner} rectangle.
+ * This method will also verify class consistency by invoking the {@code intersects}
+ * method, and by interchanging the arguments.
+ * <p>
+ * This method can be used for testing the {@code outer} implementation -
+ * it should not be needed for standard JDK implementations.
+ *
+ * @param outer The shape which is expected to contains the given rectangle.
+ * @param inner The rectangle which should be contained by the shape.
+ */
+ public static void assertContains(final RectangularShape outer, final Rectangle2D inner) {
+ assertTrue("outer.contains(inner)", outer.contains (inner));
+ assertTrue("outer.intersects(inner)", outer.intersects(inner));
+ if (outer instanceof Rectangle2D) {
+ assertTrue ("inner.intersects(outer)", inner.intersects((Rectangle2D) outer));
+ assertFalse("inner.contains(outer)", inner.contains ((Rectangle2D) outer));
+ }
+ assertTrue("outer.contains(centerX, centerY)",
+ outer.contains(inner.getCenterX(), inner.getCenterY()));
+ }
+
+ /**
+ * Tests if the given {@code r1} shape is disjoint with the given {@code r2} rectangle.
+ * This method will also verify class consistency by invoking the {@code contains}
+ * method, and by interchanging the arguments.
+ * <p>
+ * This method can be used for testing the {@code r1} implementation -
+ * it should not be needed for standard implementations.
+ *
+ * @param r1 The first shape to test.
+ * @param r2 The second rectangle to test.
+ */
+ public static void assertDisjoint(final RectangularShape r1, final Rectangle2D r2) {
+ assertFalse("r1.intersects(r2)", r1.intersects(r2));
+ assertFalse("r1.contains(r2)", r1.contains(r2));
+ if (r1 instanceof Rectangle2D) {
+ assertFalse("r2.intersects(r1)", r2.intersects((Rectangle2D) r1));
+ assertFalse("r2.contains(r1)", r2.contains ((Rectangle2D) r1));
+ }
+ for (int i=0; i<9; i++) {
+ final double x, y;
+ switch (i % 3) {
+ case 0: x = r2.getMinX(); break;
+ case 1: x = r2.getCenterX(); break;
+ case 2: x = r2.getMaxX(); break;
+ default: throw new AssertionError(i);
+ }
+ switch (i / 3) {
+ case 0: y = r2.getMinY(); break;
+ case 1: y = r2.getCenterY(); break;
+ case 2: y = r2.getMaxY(); break;
+ default: throw new AssertionError(i);
+ }
+ assertFalse("r1.contains(" + x + ", " + y + ')', r1.contains(x, y));
+ }
+ }
+
+ /**
+ * Asserts that two rectangles have the same location and the same size.
+ *
+ * @param expected The expected rectangle.
+ * @param actual The rectangle to compare with the expected one.
+ * @param tolx The tolerance threshold on location along the <var>x</var> axis.
+ * @param toly The tolerance threshold on location along the <var>y</var> axis.
+ */
+ public static void assertRectangleEquals(final RectangularShape expected,
+ final RectangularShape actual, final double tolx, final double toly)
+ {
+ assertEquals("Min X", expected.getMinX(), actual.getMinX(), tolx);
+ assertEquals("Min Y", expected.getMinY(), actual.getMinY(), toly);
+ assertEquals("Max X", expected.getMaxX(), actual.getMaxX(), tolx);
+ assertEquals("Max Y", expected.getMaxY(), actual.getMaxY(), toly);
+ assertEquals("Center X", expected.getCenterX(), actual.getCenterX(), tolx);
+ assertEquals("Center Y", expected.getCenterY(), actual.getCenterY(), toly);
+ assertEquals("Width", expected.getWidth(), actual.getWidth(), tolx*2);
+ assertEquals("Height", expected.getHeight(), actual.getHeight(), toly*2);
+ }
+
+ /**
+ * Asserts that two images have the same origin and the same size.
+ *
+ * @param expected The image having the expected size.
+ * @param actual The image to compare with the expected one.
+ */
+ public static void assertBoundEquals(final RenderedImage expected, final RenderedImage actual) {
+ assertEquals("Min X", expected.getMinX(), actual.getMinX());
+ assertEquals("Min Y", expected.getMinY(), actual.getMinY());
+ assertEquals("Width", expected.getWidth(), actual.getWidth());
+ assertEquals("Height", expected.getHeight(), actual.getHeight());
+ }
+
+ /**
+ * Serializes the given object in memory, deserialize it and ensure that the deserialized
+ * object is equal to the original one. This method doesn't write anything to the disk.
+ * <p>
+ * If the serialization fails, then this method thrown a {@link AssertionError}
+ * as do the other JUnit assertion methods.
+ *
+ * @param <T> The type of the object to serialize.
+ * @param object The object to serialize.
+ * @return The deserialized object.
+ */
+ public static <T> T assertSerializedEquals(final T object) {
+ final Object deserialized;
+ try {
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ final ObjectOutputStream out = new ObjectOutputStream(buffer);
+ try {
+ out.writeObject(object);
+ } finally {
+ out.close();
+ }
+ // Now reads the object we just serialized.
+ final byte[] data = buffer.toByteArray();
+ final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data));
+ try {
+ try {
+ deserialized = in.readObject();
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ } finally {
+ in.close();
+ }
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ // Compares with the original object and returns it.
+ @SuppressWarnings("unchecked")
+ final Class<? extends T> type = (Class<? extends T>) object.getClass();
+ assertEquals("Deserialized object not equal to the original one.", object, deserialized);
+ assertEquals("Deserialized object has a different hash code.",
+ object.hashCode(), deserialized.hashCode());
+ return type.cast(deserialized);
+ }
+}
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Dependency.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Dependency.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Dependency.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Dependency.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Identifies the dependencies of a test. If any of the dependencies of a test can not be
+ * executed successfully, (i.e. those tests failed, threw an error, or were skipped) then
+ * the annotated test will be skipped.
+ *
+ * @author Stephen Connolly
+ * @since 0.3 (derived from <a href="http://github.com/junit-team/junit.contrib/tree/master/assumes">junit-team</a>)
+ * @version 0.3
+ * @module
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Dependency {
+ /**
+ * The names of test methods on which the annotated method depends.
+ *
+ * @return The names of test methods on which the annotated method depends.
+ */
+ public String[] value();
+}
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Dependency.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Dependency.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.test;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.logging.Logger;
+import java.util.logging.Handler;
+import java.util.logging.ConsoleHandler;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.io.Console;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.logging.Logging;
+
+import org.junit.AfterClass;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Base class of Apache SIS tests (except the ones that extend GeoAPI tests).
+ * This base class provides some configuration commons to all subclasses.
+ *
+ * {@section Printing to the console}
+ * Subclasses should avoid printing to {@link System#out}. If nevertheless a test method
+ * produces some information considered worth to be known, consider using the following
+ * pattern instead:
+ *
+ * {@preformat java
+ * if (out != null) {
+ * out.println("Put here some information of particular interest.");
+ * }
+ * }
+ *
+ * The above example uses the {@link #out} field, which will be set to a non-null value
+ * if the following option has been provided on the command line:
+ *
+ * <blockquote><code>-D{@value #VERBOSE_KEY}=true</code></blockquote>
+ *
+ * Developers can also optionally provide the following option, which is useful on Windows
+ * or MacOS platforms having a console encoding different than the system encoding:
+ *
+ * <blockquote><code>-D{@value #ENCODING_KEY}=UTF-8</code> (or any other valid encoding name)</blockquote>
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.16)
+ * @version 0.3
+ * @module
+ */
+@RunWith(TestRunner.class)
+public abstract strictfp class TestCase {
+ /**
+ * The name of a system property for setting whatever the tests should provide verbose output.
+ * If this property is set to {@code true}, then the {@link #out} field will be set to a
+ * non-null value:
+ */
+ private static final String VERBOSE_KEY = "org.apache.sis.test.verbose";
+
+ /**
+ * The name of a system property for setting the encoding of test output.
+ * This property is used only if the {@link #VERBOSE_KEY} property is set
+ * to "{@code true}". If this property is not set, then the system encoding
+ * will be used.
+ */
+ private static final String ENCODING_KEY = "org.apache.sis.test.encoding";
+
+ /**
+ * If verbose outputs are enabled, the output writer where to print.
+ * Otherwise {@code null}.
+ * <p>
+ * This field will be assigned a non-null value if the {@value #VERBOSE_KEY}
+ * {@linkplain System#getProperties() system property} is set to {@code true}.
+ * The encoding will by the system-default, unless the {@value #ENCODING_KEY}
+ * system property has been set to a different value.
+ */
+ public static final PrintWriter out;
+
+ /**
+ * The buffer which is backing the {@linkplain #out} stream, or {@code null} if none.
+ */
+ private static final StringWriter buffer;
+
+ /**
+ * Sets the {@link #out} writer and its underlying {@link #buffer}.
+ */
+ static {
+ if (Boolean.getBoolean(VERBOSE_KEY)) {
+ out = new PrintWriter(buffer = new StringWriter());
+ } else {
+ buffer = null;
+ out = null;
+ }
+ }
+
+ /**
+ * Sets the encoding of the console logging handler, if an encoding has been specified.
+ * Note that we look specifically for {@link ConsoleHandler}; we do not generalize to
+ * {@link StreamHandler} because the log files may not be intended for being show in
+ * the console.
+ * <p>
+ * In case of failure to use the given encoding, we will just print a short error
+ * message and left the encoding unchanged.
+ */
+ static {
+ final String encoding = System.getProperty(ENCODING_KEY);
+ if (encoding != null) try {
+ for (Logger logger=Logger.getLogger("org.apache.sis"); logger!=null; logger=logger.getParent()) {
+ for (final Handler handler : logger.getHandlers()) {
+ if (handler instanceof ConsoleHandler) {
+ ((ConsoleHandler) handler).setEncoding(encoding);
+ }
+ }
+ if (!logger.getUseParentHandlers()) {
+ break;
+ }
+ }
+ } catch (UnsupportedEncodingException e) {
+ Logging.recoverableException(TestCase.class, "<clinit>", e);
+ }
+ }
+
+ /**
+ * Date parser and formatter using the {@code "yyyy-MM-dd HH:mm:ss"} pattern
+ * and UTC time zone.
+ */
+ private static final DateFormat dateFormat;
+ static {
+ dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CANADA);
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ dateFormat.setLenient(false);
+ };
+
+ /**
+ * Creates a new test case.
+ */
+ protected TestCase() {
+ }
+
+ /**
+ * Parses the date for the given string using the {@code "yyyy-MM-dd HH:mm:ss"} pattern
+ * in UTC timezone.
+ *
+ * @param date The date as a {@link String}.
+ * @return The date as a {@link Date}.
+ */
+ public static Date date(final String date) {
+ ArgumentChecks.ensureNonNull("date", date);
+ try {
+ synchronized (dateFormat) {
+ return dateFormat.parse(date);
+ }
+ } catch (ParseException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
+ * Formats the given date using the {@code "yyyy-MM-dd HH:mm:ss"} pattern in UTC timezone.
+ *
+ * @param date The date to format.
+ * @return The date as a {@link String}.
+ */
+ public static String format(final Date date) {
+ ArgumentChecks.ensureNonNull("date", date);
+ synchronized (dateFormat) {
+ return dateFormat.format(date);
+ }
+ }
+
+ /**
+ * If verbose output is enabled, flushes the {@link #out} stream to the
+ * {@linkplain System#console() console} after every tests in the class
+ * have been run.
+ * <p>
+ * This method is invoked automatically by JUnit and doesn't need to be invoked
+ * explicitely, unless the developer wants to flush the output at some specific
+ * point.
+ */
+ @AfterClass
+ public static void flushVerboseOutput() {
+ System.out.flush();
+ System.err.flush();
+ if (out == null) {
+ return;
+ }
+ synchronized (buffer) { // This is the lock used by the 'out' PrintWriter.
+ out.flush();
+ /*
+ * Get the text content and remove the trailing spaces
+ * (including line feeds), if any.
+ */
+ String content = buffer.toString();
+ int length = content.length();
+ do if (length == 0) return;
+ while (Character.isWhitespace(content.charAt(--length)));
+ content = content.substring(0, ++length);
+ /*
+ * Get the output writer, using the specified encoding if any.
+ */
+ PrintWriter writer = null;
+ final String encoding = System.getProperty(ENCODING_KEY);
+ if (encoding == null) {
+ final Console console = System.console();
+ if (console != null) {
+ writer = console.writer();
+ }
+ }
+ if (writer == null) {
+ if (encoding != null) try {
+ writer = new PrintWriter(new OutputStreamWriter(System.out, encoding));
+ } catch (UnsupportedEncodingException e) {
+ // Ignore. We will use the default encoding.
+ }
+ if (writer == null) {
+ writer = new PrintWriter(System.out);
+ }
+ }
+ writer.println(content);
+ writer.flush();
+ buffer.getBuffer().setLength(0);
+ }
+ }
+}
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.test;
+
+import java.util.Set;
+import java.util.List;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.util.Comparator;
+import net.jcip.annotations.NotThreadSafe;
+
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runner.manipulation.Sorter;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+import static org.apache.sis.util.Arrays.resize;
+
+
+/**
+ * The SIS test runner for individual classes.
+ * This class extends the JUnit standard test runner with additional features:
+ * <p>
+ * <ul>
+ * <li>Support of the {@link Dependency} annotation.</li>
+ * </ul>
+ * <p>
+ * This runner is not designed for parallel execution of tests.
+ *
+ * @author Stephen Connolly
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from <a href="http://github.com/junit-team/junit.contrib/tree/master/assumes">junit-team</a>)
+ * @version 0.3
+ * @module
+ */
+@NotThreadSafe
+public final class TestRunner extends BlockJUnit4ClassRunner {
+ /**
+ * The test methods to be executed, sorted according their dependencies.
+ * This array is created by {@link #getFilteredChildren()} when first needed.
+ */
+ private FrameworkMethod[] filteredChildren;
+
+ /**
+ * The dependency methods that failed. This set will be created only when first needed.
+ *
+ * @see #addDependencyFailure(String)
+ */
+ private Set<String> dependencyFailures;
+
+ /**
+ * The listener to use for keeping trace of methods that failed.
+ */
+ final RunListener listener = new RunListener() {
+ @Override
+ public void testFailure(final Failure failure) {
+ addDependencyFailure(failure.getDescription().getMethodName());
+ }
+
+ @Override
+ public void testAssumptionFailure(final Failure failure) {
+ addDependencyFailure(failure.getDescription().getMethodName());
+ }
+
+ @Override
+ public void testIgnored(final Description description) {
+ addDependencyFailure(description.getMethodName());
+ }
+ };
+
+ /**
+ * Creates a {@code Corollaries} to run {@code klass}.
+ *
+ * @param klass The class to run.
+ * @throws InitializationError If the test class is malformed.
+ */
+ public TestRunner(final Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+
+ /**
+ * Returns the test methods to be executed, with dependencies sorted before dependant tests.
+ *
+ * @return The test method to be executed in dependencies order.
+ */
+ @Override
+ public List<FrameworkMethod> getChildren() {
+ return Arrays.asList(getFilteredChildren());
+ }
+
+ /**
+ * Returns the test methods to be executed, with dependencies sorted before dependant tests.
+ *
+ * @return The test method to be executed in dependencies order.
+ */
+ private FrameworkMethod[] getFilteredChildren() {
+ if (filteredChildren == null) {
+ final List<FrameworkMethod> children = super.getChildren();
+ filteredChildren = children.toArray(new FrameworkMethod[children.size()]);
+ sortDependantTestsLast(filteredChildren);
+ }
+ return filteredChildren;
+ }
+
+ /**
+ * Sorts the tests methods using the given sorter. The resulting order may not be totally
+ * conform to the sorter specification, since this method will ensure that dependencies
+ * are still sorted before dependant tests.
+ *
+ * @param sorter The sorter to use for sorting tests.
+ */
+ @Override
+ public void sort(final Sorter sorter) {
+ final FrameworkMethod[] children = getFilteredChildren();
+ for (final FrameworkMethod method : children) {
+ sorter.apply(method);
+ }
+ Arrays.sort(children, new Comparator<FrameworkMethod>() {
+ @Override
+ public int compare(FrameworkMethod o1, FrameworkMethod o2) {
+ return sorter.compare(describeChild(o1), describeChild(o2));
+ }
+ });
+ sortDependantTestsLast(children);
+ filteredChildren = children;
+ }
+
+ /**
+ * Sorts the given array of methods in dependencies order.
+ *
+ * @param methods The methods to sort.
+ */
+ private static void sortDependantTestsLast(final FrameworkMethod[] methods) {
+ Set<String> dependencies = null;
+ for (int i=methods.length-1; --i>=0;) {
+ final FrameworkMethod method = methods[i];
+ final Dependency depend = method.getAnnotation(Dependency.class);
+ if (depend != null) {
+ if (dependencies == null) {
+ dependencies = new HashSet<String>();
+ }
+ dependencies.addAll(Arrays.asList(depend.value()));
+ for (int j=methods.length; --j>i;) {
+ if (dependencies.contains(methods[j].getName())) {
+ // Found a method j which is a dependency of i. Move i after j.
+ // The order of other methods relative to j is left unchanged.
+ System.arraycopy(methods, i+1, methods, i, j-i);
+ methods[j] = method;
+ break;
+ }
+ }
+ dependencies.clear();
+ }
+ }
+ }
+
+ /**
+ * Removes tests that don't pass the parameter {@code filter}.
+ *
+ * @param filter The filter to apply.
+ * @throws NoTestsRemainException If all tests are filtered out.
+ */
+ @Override
+ public void filter(final Filter filter) throws NoTestsRemainException {
+ int count = 0;
+ FrameworkMethod[] children = getFilteredChildren();
+ for (int i=0; i<children.length; i++) {
+ final FrameworkMethod method = children[i];
+ if (filter.shouldRun(describeChild(method))) {
+ try {
+ filter.apply(method);
+ } catch (NoTestsRemainException e) {
+ continue;
+ }
+ children[count++] = method;
+ }
+ }
+ if (count == 0) {
+ throw new NoTestsRemainException();
+ }
+ filteredChildren = resize(children, count);
+ }
+
+ /**
+ * Returns the {@link Statement} which will execute all the tests in the class given
+ * to the constructor.
+ *
+ * @param notifier The object to notify about test results.
+ * @return The statement to execute for running the tests.
+ */
+ @Override
+ protected Statement childrenInvoker(final RunNotifier notifier) {
+ final Statement stmt = super.childrenInvoker(notifier);
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ notifier.addListener(listener);
+ try {
+ stmt.evaluate();
+ } finally {
+ notifier.removeListener(listener);
+ }
+ }
+ };
+ }
+
+ /**
+ * Before to delegate to the {@linkplain BlockJUnit4ClassRunner#runChild default implementation},
+ * check if a dependency of the given method failed. In such case, the test will be ignored.
+ *
+ * @param method The test method to execute.
+ * @param notifier The object to notify about test results.
+ */
+ @Override
+ protected void runChild(final FrameworkMethod method, final RunNotifier notifier) {
+ if (dependencyFailures != null) {
+ final Dependency assumptions = method.getAnnotation(Dependency.class);
+ if (assumptions != null) {
+ for (final String assumption : assumptions.value()) {
+ if (dependencyFailures.contains(assumption)) {
+ dependencyFailures.add(method.getName());
+ notifier.fireTestIgnored(describeChild(method));
+ return;
+ }
+ }
+ }
+ }
+ super.runChild(method, notifier);
+ }
+
+ /**
+ * Declares that the given method failed. Other methods depending on this method
+ * will be ignored.
+ *
+ * @param methodName The name of the method that failed.
+ */
+ final void addDependencyFailure(final String methodName) {
+ if (dependencyFailures == null) {
+ dependencyFailures = new HashSet<String>();
+ }
+ dependencyFailures.add(methodName);
+ }
+}
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,694 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.test;
+
+import java.util.Set;
+import java.util.List;
+import java.util.HashSet;
+import java.util.ArrayList;
+import java.net.URI;
+import java.net.URL;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.xml.sax.SAXException;
+
+import org.apache.sis.util.ArgumentChecks;
+
+import static java.lang.StrictMath.*;
+import static org.opengis.test.Assert.*;
+
+
+/**
+ * Compares the XML document produced by a test method with the expected XML document.
+ * The two XML documents are specified at construction time. The comparison is performed
+ * by a call to the {@link #compare()} method. The execution is delegated to the various
+ * protected methods defined in this class, which can be overridden.
+ * <p>
+ * By default, this comparator expects the documents to contain the same elements and
+ * the same attributes (but the order of attributes may be different). However it is
+ * possible to:
+ * <p>
+ * <ul>
+ * <li>Specify attributes to ignore in comparisons (see {@link #ignoredAttributes})</li>
+ * </ul>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.17)
+ * @version 0.3
+ * @module
+ */
+public strictfp class XMLComparator {
+ /**
+ * The expected document.
+ */
+ private final Node expectedDoc;
+
+ /**
+ * The document resulting from the test method.
+ */
+ private final Node actualDoc;
+
+ /**
+ * {@code true} if the comments shall be ignored. The default value is {@code false}.
+ */
+ public boolean ignoreComments;
+
+ /**
+ * The fully-qualified name of attributes to ignore in comparisons. The name shall be in
+ * the form {@code "namespace:name"}, or only {@code "name"} if there is no name space.
+ * In order to ignore everything in a name space, use {@code "namespace:*"}.
+ * <p>
+ * For example in order to ignore the name space, type and schema location declaration,
+ * the following strings can be added in this set:
+ *
+ * {@preformat text
+ * "xmlns:*", "xsi:schemaLocation", "xsi:type"
+ * }
+ *
+ * This set is initially empty. Users can add or remove elements in this set as they wish.
+ * The content of this set will be honored by the default {@link #compareAttributes(Node, Node)}
+ * implementation.
+ */
+ public final Set<String> ignoredAttributes;
+
+ /**
+ * The fully-qualified name of nodes to ignore in comparisons. The name shall be in the form
+ * {@code "namespace:name"}, or only {@code "name"} if there is no name space. In order to
+ * ignore everything in a name space, use {@code "namespace:*"}.
+ * <p>
+ * This set provides a way to ignore a node of the given name <em>and all its children</em>.
+ * In order to ignore a node but still compare its children, override the
+ * {@link #compareNode(Node, Node)} method instead.
+ * <p>
+ * This set is initially empty. Users can add or remove elements in this set as they wish.
+ * The content of this set will be honored by the default {@link #compareChildren(Node, Node)}
+ * implementation.
+ */
+ public final Set<String> ignoredNodes;
+
+ /**
+ * The tolerance threshold for comparisons of numerical values, or 0 for strict comparisons.
+ * The default value is 0.
+ */
+ public double tolerance;
+
+ /**
+ * Creates a new comparator for the given root nodes.
+ *
+ * @param expected The root node of the expected XML document.
+ * @param actual The root node of the XML document to compare.
+ */
+ public XMLComparator(final Node expected, final Node actual) {
+ ArgumentChecks.ensureNonNull("expected", expected);
+ ArgumentChecks.ensureNonNull("actual", actual);
+ expectedDoc = expected;
+ actualDoc = actual;
+ ignoredAttributes = new HashSet<String>();
+ ignoredNodes = new HashSet<String>();
+ }
+
+ /**
+ * Creates a new comparator for the given inputs.
+ * The inputs can be any of the following types:
+ * <p>
+ * <ul>
+ * <li>{@link Node}; used directly without further processing.</li>
+ * <li>{@link File}, {@link URL} or {@link URI}: the stream is opened and parsed
+ * as a XML document.</li>
+ * <li>{@link String}: The string content is parsed directly as a XML document.
+ * Encoding <strong>must</strong> be UTF-8 (no other encoding is supported
+ * by current implementation of this method).</li>
+ * </ul>
+ *
+ * @param expected The expected XML document.
+ * @param actual The XML document to compare.
+ * @throws IOException If the stream can not be read.
+ * @throws ParserConfigurationException If a {@link DocumentBuilder} can not be created.
+ * @throws SAXException If an error occurred while parsing the XML document.
+ */
+ public XMLComparator(final Object expected, final Object actual)
+ throws IOException, ParserConfigurationException, SAXException
+ {
+ this((expected instanceof Node) ? (Node) expected : read(expected),
+ (actual instanceof Node) ? (Node) actual : read(actual));
+ }
+
+ /**
+ * Convenience method to acquire a DOM document from an input. This convenience method
+ * uses the default JRE classes, so it may not be the fastest parsing method.
+ */
+ private static Document read(final Object input)
+ throws IOException, ParserConfigurationException, SAXException
+ {
+ final Document document;
+ final InputStream stream = toInputStream(input);
+ try {
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ final DocumentBuilder constructeur = factory.newDocumentBuilder();
+ document = constructeur.parse(stream);
+ } finally {
+ stream.close();
+ }
+ return document;
+ }
+
+ /**
+ * Converts the given object to a stream.
+ * See the constructor Javadoc for the list of allowed input type.
+ */
+ private static InputStream toInputStream(final Object input) throws IOException {
+ if (input instanceof InputStream) return (InputStream) input;
+ if (input instanceof File) return new FileInputStream((File) input);
+ if (input instanceof URI) return ((URI) input).toURL().openStream();
+ if (input instanceof URL) return ((URL) input).openStream();
+ if (input instanceof String) return new ByteArrayInputStream(input.toString().getBytes("UTF-8"));
+ throw new IOException("Can not handle input type: " + (input != null ? input.getClass() : input));
+ }
+
+ /**
+ * Compares the XML document specified at construction time. Before to invoke this
+ * method, users may consider to add some values to the {@link #ignoredAttributes}
+ * set.
+ */
+ public void compare() {
+ compareNode(expectedDoc, actualDoc);
+ }
+
+ /**
+ * Compares the two given nodes. This method delegates to one of the given methods depending
+ * on the expected node type:
+ * <p>
+ * <ul>
+ * <li>{@link #compareCDATASectionNode(CDATASection, Node)}</li>
+ * <li>{@link #compareTextNode(Text, Node)}</li>
+ * <li>{@link #compareCommentNode(Comment, Node)}</li>
+ * <li>{@link #compareProcessingInstructionNode(ProcessingInstruction, Node)}</li>
+ * <li>For all other types, {@link #compareNames(Node, Node)} and
+ * {@link #compareAttributes(Node, Node)}</li>
+ * </ul>
+ * <p>
+ * Then this method invokes itself recursively for every children,
+ * by a call to {@link #compareChildren(Node, Node)}.
+ *
+ * @param expected The expected node.
+ * @param actual The node to compare.
+ */
+ protected void compareNode(final Node expected, final Node actual) {
+ if (expected == null || actual == null) {
+ fail(formatErrorMessage(expected, actual));
+ }
+ /*
+ * Check text value for types:
+ * TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE
+ */
+ if (expected instanceof CDATASection) {
+ compareCDATASectionNode((CDATASection) expected, actual);
+ } else if (expected instanceof Text) {
+ compareTextNode((Text) expected, actual);
+ } else if (expected instanceof Comment) {
+ compareCommentNode((Comment) expected, actual);
+ } else if (expected instanceof ProcessingInstruction) {
+ compareProcessingInstructionNode((ProcessingInstruction) expected, actual);
+ } else if (expected instanceof Attr) {
+ compareAttributeNode((Attr) expected, actual);
+ } else {
+ compareNames(expected, actual);
+ compareAttributes(expected, actual);
+ }
+ /*
+ * Check child nodes recursivly if it's not an attribut.
+ */
+ if (expected.getNodeType() != Node.ATTRIBUTE_NODE) {
+ compareChildren(expected, actual);
+ }
+ }
+
+ /**
+ * Compares a node which is expected to be of {@link Text} type. The default implementation
+ * ensures that the given node is an instance of {@link Text}, then ensures that both nodes
+ * have the same names, attributes and text content.
+ * <p>
+ * Subclasses can override this method if they need a different processing.
+ *
+ * @param expected The expected node.
+ * @param actual The actual node.
+ */
+ protected void compareTextNode(final Text expected, final Node actual) {
+ assertInstanceOf("Actual node is not of the expected type.", Text.class, actual);
+ compareNames(expected, actual);
+ compareAttributes(expected, actual);
+ assertTextContentEquals(expected, actual);
+ }
+
+ /**
+ * Compares a node which is expected to be of {@link CDATASection} type. The default
+ * implementation ensures that the given node is an instance of {@link CDATASection},
+ * then ensures that both nodes have the same names, attributes and text content.
+ * <p>
+ * Subclasses can override this method if they need a different processing.
+ *
+ * @param expected The expected node.
+ * @param actual The actual node.
+ */
+ protected void compareCDATASectionNode(final CDATASection expected, final Node actual) {
+ assertInstanceOf("Actual node is not of the expected type.", CDATASection.class, actual);
+ compareNames(expected, actual);
+ compareAttributes(expected, actual);
+ assertTextContentEquals(expected, actual);
+ }
+
+ /**
+ * Compares a node which is expected to be of {@link Comment} type. The default
+ * implementation ensures that the given node is an instance of {@link Comment},
+ * then ensures that both nodes have the same names, attributes and text content.
+ * <p>
+ * Subclasses can override this method if they need a different processing.
+ *
+ * @param expected The expected node.
+ * @param actual The actual node.
+ */
+ protected void compareCommentNode(final Comment expected, final Node actual) {
+ assertInstanceOf("Actual node is not of the expected type.", Comment.class, actual);
+ compareNames(expected, actual);
+ compareAttributes(expected, actual);
+ assertTextContentEquals(expected, actual);
+ }
+
+ /**
+ * Compares a node which is expected to be of {@link ProcessingInstruction} type. The default
+ * implementation ensures that the given node is an instance of {@link ProcessingInstruction},
+ * then ensures that both nodes have the same names, attributes and text content.
+ * <p>
+ * Subclasses can override this method if they need a different processing.
+ *
+ * @param expected The expected node.
+ * @param actual The actual node.
+ */
+ protected void compareProcessingInstructionNode(final ProcessingInstruction expected, final Node actual) {
+ assertInstanceOf("Actual node is not of the expected type.", ProcessingInstruction.class, actual);
+ compareNames(expected, actual);
+ compareAttributes(expected, actual);
+ assertTextContentEquals(expected, actual);
+ }
+
+ /**
+ * Compares a node which is expected to be of {@link Attr} type. The default
+ * implementation ensures that the given node is an instance of {@link Attr},
+ * then ensures that both nodes have the same names and text content.
+ * <p>
+ * Subclasses can override this method if they need a different processing.
+ *
+ * @param expected The expected node.
+ * @param actual The actual node.
+ */
+ protected void compareAttributeNode(final Attr expected, final Node actual) {
+ assertInstanceOf("Actual node is not of the expected type.", Attr.class, actual);
+ compareNames(expected, actual);
+ compareAttributes(expected, actual);
+ assertTextContentEquals(expected, actual);
+ }
+
+ /**
+ * Compares the children of the given nodes. The node themselves are not compared.
+ * Children shall appear in the same order. Nodes having a name declared in the
+ * {@link #ignoredNodes} set are ignored.
+ * <p>
+ * Subclasses can override this method if they need a different processing.
+ *
+ * @param expected The expected node.
+ * @param actual The node for which to compare children.
+ */
+ protected void compareChildren(Node expected, Node actual) {
+ expected = firstNonEmptySibling(expected.getFirstChild());
+ actual = firstNonEmptySibling(actual .getFirstChild());
+ while (expected != null) {
+ compareNode(expected, actual);
+ expected = firstNonEmptySibling(expected.getNextSibling());
+ actual = firstNonEmptySibling(actual .getNextSibling());
+ }
+ if (actual != null) {
+ fail(formatErrorMessage(expected, actual));
+ }
+ }
+
+ /**
+ * Compares the names and name spaces of the given node.
+ * Subclasses can override this method if they need a different comparison.
+ *
+ * @param expected The node having the expected name and name space.
+ * @param actual The node to compare.
+ */
+ protected void compareNames(final Node expected, final Node actual) {
+ assertPropertyEquals("namespace", expected.getNamespaceURI(), actual.getNamespaceURI(), expected, actual);
+ assertPropertyEquals("name", expected.getNodeName(), actual.getNodeName(), expected, actual);
+ }
+
+ /**
+ * Compares the attributes of the given nodes.
+ * Subclasses can override this method if they need a different comparison.
+ * <p>
+ * <strong>NOTE:</strong> Current implementation requires the number of attributes to be the
+ * same only if the {@link #ignoredAttributes} set is empty. If the {@code ignoredAttributes}
+ * set is not empty, then the actual node could have more attributes than the expected node;
+ * the extra attributes are ignored. This may change in a future version if it appears to be
+ * a problem in practice.
+ *
+ * @param expected The node having the expected attributes.
+ * @param actual The node to compare.
+ */
+ protected void compareAttributes(final Node expected, final Node actual) {
+ final NamedNodeMap expectedAttributes = expected.getAttributes();
+ final NamedNodeMap actualAttributes = actual.getAttributes();
+ final int n = (expectedAttributes != null) ? expectedAttributes.getLength() : 0;
+ if (ignoredAttributes.isEmpty()) {
+ assertPropertyEquals("nbAttributes", n,
+ (actualAttributes != null) ? actualAttributes.getLength() : 0, expected, actual);
+ }
+ for (int i=0; i<n; i++) {
+ final Node expAttr = expectedAttributes.item(i);
+ final String ns = expAttr.getNamespaceURI();
+ final String name = expAttr.getNodeName();
+ if (!isIgnored(ignoredAttributes, ns, name)) {
+ final Node actAttr;
+ if (ns == null) {
+ actAttr = actualAttributes.getNamedItem(name);
+ } else {
+ actAttr = actualAttributes.getNamedItemNS(ns, name);
+ }
+ compareNode(expAttr, actAttr);
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if the given node or attribute shall be ignored.
+ *
+ * @param ignored The set of node or attribute fully qualified names to ignore.
+ * @param ns The node or attribute name space, or {@code null}.
+ * @param name The node or attribute name.
+ * @return {@coce true} if the node or attribute shall be ignored.
+ */
+ private static boolean isIgnored(final Set<String> ignored, String ns, final String name) {
+ if (!ignored.isEmpty()) {
+ if (ignored.contains((ns != null) ? ns + ':' + name : name)) {
+ // Ignore a specific node (for example "xsi:schemaLocation")
+ return true;
+ }
+ if (ns == null) {
+ final int s = name.indexOf(':');
+ if (s >= 1) {
+ ns = name.substring(0, s);
+ }
+ }
+ if (ns != null && ignored.contains(ns + ":*")) {
+ // Ignore a full namespace (typically "xmlns:*")
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the first sibling of the given node having a non-empty text content, or {@code null}
+ * if none. This method first check the given node, then check all siblings. Attribute nodes are
+ * ignored.
+ *
+ * @param node The node to check, or {@code null}.
+ * @return The first node having a non-empty text content, or {@code null} if none.
+ */
+ private Node firstNonEmptySibling(Node node) {
+ for (; node != null; node = node.getNextSibling()) {
+ if (!isIgnored(ignoredNodes, node.getNamespaceURI(), node.getNodeName())) {
+ switch (node.getNodeType()) {
+ // For attribute node, continue the search unconditionally.
+ case Node.ATTRIBUTE_NODE: continue;
+
+ // For text node, continue the search if the node is empty.
+ case Node.TEXT_NODE: {
+ final String text = node.getTextContent();
+ if (text == null || text.trim().isEmpty()) {
+ continue;
+ }
+ break;
+ }
+
+ // Ignore comment nodes only if requested.
+ case Node.COMMENT_NODE: {
+ if (ignoreComments) {
+ continue;
+ }
+ break;
+ }
+ }
+ // Found a node: stop the search.
+ break;
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Verifies that the text content of the given nodes are equal.
+ *
+ * @param expected The node that contains the expected text.
+ * @param actual The node that contains the actual text to verify.
+ */
+ protected void assertTextContentEquals(final Node expected, final Node actual) {
+ assertPropertyEquals("textContent", expected.getTextContent(), actual.getTextContent(), expected, actual);
+ }
+
+ /**
+ * Verifies that the given property (text or number) are equal, ignoring spaces. If they are
+ * not equal, then an error message is formatted using the given property name and nodes.
+ *
+ * @param propertyName The name of the property being compared (typically "name", "name space", etc.).
+ * @param expected The property value from the expected node to compare.
+ * @param actual The property value to compare to the expected one.
+ * @param expectedNode The node from which the expected property has been fetched.
+ * @param actualNode The node being compared to the expected node.
+ */
+ protected void assertPropertyEquals(final String propertyName, Comparable<?> expected, Comparable<?> actual,
+ final Node expectedNode, final Node actualNode)
+ {
+ expected = trim(expected);
+ actual = trim(actual);
+ if ((expected != actual) && (expected == null || !expected.equals(actual))) {
+ // Before to declare a test failure, compares again as numerical values if possible.
+ if (tolerance > 0 && abs(doubleValue(expected) - doubleValue(actual)) <= tolerance) {
+ return;
+ }
+ final String lineSeparator = System.getProperty("line.separator", "\n");
+ final StringBuilder buffer = new StringBuilder(1024).append("Expected ")
+ .append(propertyName).append(" \"")
+ .append(expected).append("\" but got \"")
+ .append(actual).append("\" for nodes:")
+ .append(lineSeparator);
+ formatErrorMessage(buffer, expectedNode, actualNode, lineSeparator);
+ fail(buffer.toString());
+ }
+ }
+
+ /**
+ * Trims the leading and trailing spaces in the given property
+ * if it is actually a {@link String} object.
+ */
+ private static Comparable<?> trim(final Comparable<?> property) {
+ return (property instanceof String) ? ((String) property).trim() : property;
+ }
+
+ /**
+ * Parses the given text as a number. If the given text is null or can not be parsed,
+ * returns {@code NaN}. This is used only if a {@linkplain #tolerance} threshold greater
+ * than zero has been provided.
+ */
+ private static double doubleValue(final Comparable<?> property) {
+ if (property instanceof Number) {
+ return ((Number) property).doubleValue();
+ }
+ if (property instanceof CharSequence) try {
+ return Double.parseDouble(property.toString());
+ } catch (NumberFormatException e) {
+ // Ignore, as specified in method javadoc.
+ }
+ return Double.NaN;
+ }
+
+ /**
+ * Formats an error message for a node mismatch. The message will contain a string
+ * representation of the expected and actual node.
+ *
+ * @param expected The expected node.
+ * @param result The actual node.
+ * @return An error message containing the expected and actual node.
+ */
+ protected String formatErrorMessage(final Node expected, final Node result) {
+ final String lineSeparator = System.getProperty("line.separator", "\n");
+ final StringBuilder buffer = new StringBuilder(256).append("Nodes are not equal:").append(lineSeparator);
+ formatErrorMessage(buffer, expected, result, lineSeparator);
+ return buffer.toString();
+ }
+
+ /**
+ * Formats in the given buffer an error message for a node mismatch.
+ *
+ * @param lineSeparator The platform-specific line separator.
+ */
+ private static void formatErrorMessage(final StringBuilder buffer, final Node expected,
+ final Node result, final String lineSeparator)
+ {
+ formatNode(buffer.append("Expected node: "), expected, lineSeparator);
+ formatNode(buffer.append("Actual node: "), result, lineSeparator);
+ buffer.append("Expected hierarchy:").append(lineSeparator);
+ final List<String> hierarchy = formatHierarchy(buffer, expected, null, lineSeparator);
+ buffer.append("Actual hierarchy:").append(lineSeparator);
+ formatHierarchy(buffer, result, hierarchy, lineSeparator);
+ }
+
+ /**
+ * Appends to the given buffer the string representation of the node hierarchy.
+ * The first line will contains the root of the tree. Other lines will contain
+ * the child down in the hierarchy until the given node, inclusive.
+ * <p>
+ * This method formats only a summary if the hierarchy is equals to the expected one.
+ *
+ * @param buffer The buffer in which to append the formatted hierarchy.
+ * @param node The node for which to format the parents.
+ * @param expected The expected hierarchy, or {@code null} if unknown.
+ * @param lineSeparator The platform-specific line separator.
+ */
+ private static List<String> formatHierarchy(final StringBuilder buffer, Node node,
+ final List<String> expected, final String lineSeparator)
+ {
+ final List<String> hierarchy = new ArrayList<String>();
+ while (node != null) {
+ hierarchy.add(node.getNodeName());
+ node = node.getParentNode();
+ }
+ if (hierarchy.equals(expected)) {
+ buffer.append("\u2514\u2500Same as expected").append(lineSeparator);
+ } else {
+ int indent = 2;
+ for (int i=hierarchy.size(); --i>=0;) {
+ for (int j=indent; --j>=0;) {
+ buffer.append('\u00A0');
+ }
+ buffer.append("\u2514\u2500").append(hierarchy.get(i)).append(lineSeparator);
+ indent += 4;
+ }
+ }
+ return hierarchy;
+ }
+
+ /**
+ * Appends to the given buffer a string representation of the given node.
+ * The string representation is terminated by a line feed.
+ *
+ * @param buffer The buffer in which to append the formatted node.
+ * @param node The node to format.
+ * @param lineSeparator The platform-specific line separator.
+ */
+ private static void formatNode(final StringBuilder buffer, final Node node, final String lineSeparator) {
+ if (node == null) {
+ buffer.append("(no node)").append(lineSeparator);
+ return;
+ }
+ // Format the text content, together with the text content of the
+ // child if there is exactly one child.
+ final String ns = node.getNamespaceURI();
+ if (ns != null) {
+ buffer.append(ns).append(':');
+ }
+ buffer.append(node.getNodeName());
+ boolean hasText = appendTextContent(buffer, node);
+ final NodeList children = node.getChildNodes();
+ int numChildren = 0;
+ if (children != null) {
+ numChildren = children.getLength();
+ if (numChildren == 1 && !hasText) {
+ hasText = appendTextContent(buffer, children.item(0));
+ }
+ }
+
+ // Format the number of children and the number of attributes, if any.
+ String separator = " (";
+ if (numChildren != 0) {
+ buffer.append(separator).append("nbChild=").append(numChildren);
+ separator = ", ";
+ }
+ final NamedNodeMap atts = node.getAttributes();
+ int numAtts = 0;
+ if (atts != null) {
+ numAtts = atts.getLength();
+ if (numAtts != 0) {
+ buffer.append(separator).append("nbAtt=").append(numAtts);
+ separator = ", ";
+ }
+ }
+ if (!separator.equals(" (")) {
+ buffer.append(')');
+ }
+
+ // Format all attributes, if any.
+ separator = " [";
+ for (int i=0; i<numAtts; i++) {
+ buffer.append(separator).append(atts.item(i));
+ separator = ", ";
+ }
+ if (!separator.equals(" [")) {
+ buffer.append(']');
+ }
+ buffer.append(lineSeparator);
+ }
+
+ /**
+ * Appends the text content of the given node only if the node is an instance of {@link Text}
+ * or related type ({@link CDATASection}, {@link Comment} or {@link ProcessingInstruction}).
+ * Otherwise this method does nothing.
+ *
+ * @param buffer The buffer in which to append text content.
+ * @param node The node for which to append text content.
+ * @return {@code true} if a text has been formatted.
+ */
+ private static boolean appendTextContent(final StringBuilder buffer, final Node node) {
+ if (node instanceof Text ||
+ node instanceof Comment ||
+ node instanceof CDATASection ||
+ node instanceof ProcessingInstruction)
+ {
+ buffer.append("=\"").append(node.getTextContent()).append('"');
+ return true;
+ }
+ return false;
+ }
+}
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/package-info.java?rev=1391998&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/package-info.java (added)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/package-info.java Sun Sep 30 11:25:29 2012
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tools for SIS tests. This package defines a base class, {@link org.apache.sis.test.TestCase},
+ * which is extended directly or indirectly by many (but not all) SIS tests.
+ * This package defines also an {@link org.apache.sis.test.Assert} class which extend the GeoAPI
+ * {@link org.opengis.test.Assert} (which itself extends the JUnit {@link org.junit.Assert} class)
+ * with the addition of assertion methods commonly used in SIS tests.
+ * <p>
+ * By default, successful tests do not produce any output. However it is possible to ask for
+ * verbose output, which is sometime useful for debugging purpose. This behavior is controlled
+ * by {@linkplain java.lang.System#getProperties() system properties} like below:
+ * <p>
+ * <ul>
+ * <li><code>-D{@value org.apache.sis.test.TestBase#VERBOSE_KEY}=true</code>
+ * for verbose console output.</li>
+ * <li><code>-D{@value org.apache.sis.test.TestBase#ENCODING_KEY}=UTF-8</code>
+ * (or any other valid encoding name) for the encoding of the above-cited
+ * verbose output. If omitted, the platform encoding will be used.</li>
+ * </ul>
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.00)
+ * @version 0.3
+ * @module
+ */
+package org.apache.sis.test;
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/package-info.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/package-info.java
------------------------------------------------------------------------------
svn:mime-type = text/plain