Merge "Minor changes to JUnit 4.10 to make it more like 4.12" am: 26401927b8 am: de7e697850
am: b51c910133

Change-Id: I6b57701a4817d8bd43179194cc443de70cd94ee7
diff --git a/src/main/java/org/junit/Assert.java b/src/main/java/org/junit/Assert.java
old mode 100644
new mode 100755
index b585b87..d7deb06
--- a/src/main/java/org/junit/Assert.java
+++ b/src/main/java/org/junit/Assert.java
@@ -1,8 +1,7 @@
 package org.junit;
 
-import org.hamcrest.Description;
 import org.hamcrest.Matcher;
-import org.hamcrest.StringDescription;
+import org.hamcrest.MatcherAssert;
 import org.junit.internal.ArrayComparisonFailure;
 import org.junit.internal.ExactComparisonCriteria;
 import org.junit.internal.InexactComparisonCriteria;
@@ -11,773 +10,949 @@
  * A set of assertion methods useful for writing tests. Only failed assertions
  * are recorded. These methods can be used directly:
  * <code>Assert.assertEquals(...)</code>, however, they read better if they
- * are referenced through static import:<br/>
- * 
+ * are referenced through static import:
+ *
  * <pre>
  * import static org.junit.Assert.*;
  *    ...
  *    assertEquals(...);
  * </pre>
- * 
+ *
  * @see AssertionError
+ * @since 4.0
  */
 public class Assert {
-	/**
-	 * Protect constructor since it is a static only class
-	 */
-	protected Assert() {
-	}
+    /**
+     * Protect constructor since it is a static only class
+     */
+    protected Assert() {
+    }
 
-	/**
-	 * Asserts that a condition is true. If it isn't it throws an
-	 * {@link AssertionError} with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param condition
-	 *            condition to be checked
-	 */
-	static public void assertTrue(String message, boolean condition) {
-		if (!condition)
-			fail(message);
-	}
+    /**
+     * Asserts that a condition is true. If it isn't it throws an
+     * {@link AssertionError} with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param condition condition to be checked
+     */
+    static public void assertTrue(String message, boolean condition) {
+        if (!condition) {
+            fail(message);
+        }
+    }
 
-	/**
-	 * Asserts that a condition is true. If it isn't it throws an
-	 * {@link AssertionError} without a message.
-	 * 
-	 * @param condition
-	 *            condition to be checked
-	 */
-	static public void assertTrue(boolean condition) {
-		assertTrue(null, condition);
-	}
+    /**
+     * Asserts that a condition is true. If it isn't it throws an
+     * {@link AssertionError} without a message.
+     *
+     * @param condition condition to be checked
+     */
+    static public void assertTrue(boolean condition) {
+        assertTrue(null, condition);
+    }
 
-	/**
-	 * Asserts that a condition is false. If it isn't it throws an
-	 * {@link AssertionError} with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param condition
-	 *            condition to be checked
-	 */
-	static public void assertFalse(String message, boolean condition) {
-		assertTrue(message, !condition);
-	}
+    /**
+     * Asserts that a condition is false. If it isn't it throws an
+     * {@link AssertionError} with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param condition condition to be checked
+     */
+    static public void assertFalse(String message, boolean condition) {
+        assertTrue(message, !condition);
+    }
 
-	/**
-	 * Asserts that a condition is false. If it isn't it throws an
-	 * {@link AssertionError} without a message.
-	 * 
-	 * @param condition
-	 *            condition to be checked
-	 */
-	static public void assertFalse(boolean condition) {
-		assertFalse(null, condition);
-	}
+    /**
+     * Asserts that a condition is false. If it isn't it throws an
+     * {@link AssertionError} without a message.
+     *
+     * @param condition condition to be checked
+     */
+    static public void assertFalse(boolean condition) {
+        assertFalse(null, condition);
+    }
 
-	/**
-	 * Fails a test with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @see AssertionError
-	 */
-	static public void fail(String message) {
-		if (message == null)
-			throw new AssertionError();
-		throw new AssertionError(message);
-	}
+    /**
+     * Fails a test with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @see AssertionError
+     */
+    static public void fail(String message) {
+        if (message == null) {
+            throw new AssertionError();
+        }
+        throw new AssertionError(message);
+    }
 
-	/**
-	 * Fails a test with no message.
-	 */
-	static public void fail() {
-		fail(null);
-	}
+    /**
+     * Fails a test with no message.
+     */
+    static public void fail() {
+        fail(null);
+    }
 
-	/**
-	 * Asserts that two objects are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message. If
-	 * <code>expected</code> and <code>actual</code> are <code>null</code>,
-	 * they are considered equal.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expected
-	 *            expected value
-	 * @param actual
-	 *            actual value
-	 */
-	static public void assertEquals(String message, Object expected,
-			Object actual) {
-		if (expected == null && actual == null)
-			return;
-		if (expected != null && isEquals(expected, actual))
-			return;
-		else if (expected instanceof String && actual instanceof String) {
-			String cleanMessage= message == null ? "" : message;
-			throw new ComparisonFailure(cleanMessage, (String) expected,
-					(String) actual);
-		} else
-			failNotEquals(message, expected, actual);
-	}
+    /**
+     * Asserts that two objects are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message. If
+     * <code>expected</code> and <code>actual</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expected expected value
+     * @param actual actual value
+     */
+    static public void assertEquals(String message, Object expected,
+            Object actual) {
+        if (equalsRegardingNull(expected, actual)) {
+            return;
+        } else if (expected instanceof String && actual instanceof String) {
+            String cleanMessage = message == null ? "" : message;
+            throw new ComparisonFailure(cleanMessage, (String) expected,
+                    (String) actual);
+        } else {
+            failNotEquals(message, expected, actual);
+        }
+    }
 
-	private static boolean isEquals(Object expected, Object actual) {
-		return expected.equals(actual);
-	}
+    private static boolean equalsRegardingNull(Object expected, Object actual) {
+        if (expected == null) {
+            return actual == null;
+        }
 
-	/**
-	 * Asserts that two objects are equal. If they are not, an
-	 * {@link AssertionError} without a message is thrown. If
-	 * <code>expected</code> and <code>actual</code> are <code>null</code>,
-	 * they are considered equal.
-	 * 
-	 * @param expected
-	 *            expected value
-	 * @param actual
-	 *            the value to check against <code>expected</code>
-	 */
-	static public void assertEquals(Object expected, Object actual) {
-		assertEquals(null, expected, actual);
-	}
+        return isEquals(expected, actual);
+    }
 
-	/**
-	 * Asserts that two object arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message. If
-	 * <code>expecteds</code> and <code>actuals</code> are <code>null</code>,
-	 * they are considered equal.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            expected values.
-	 * @param actuals
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            actual values
-	 */
-	public static void assertArrayEquals(String message, Object[] expecteds,
-			Object[] actuals) throws ArrayComparisonFailure {
-		internalArrayEquals(message, expecteds, actuals);
-	}
+    private static boolean isEquals(Object expected, Object actual) {
+        return expected.equals(actual);
+    }
 
-	/**
-	 * Asserts that two object arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown. If <code>expected</code> and
-	 * <code>actual</code> are <code>null</code>, they are considered
-	 * equal.
-	 * 
-	 * @param expecteds
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            expected values
-	 * @param actuals
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            actual values
-	 */
-	public static void assertArrayEquals(Object[] expecteds, Object[] actuals) {
-		assertArrayEquals(null, expecteds, actuals);
-	}
+    /**
+     * Asserts that two objects are equal. If they are not, an
+     * {@link AssertionError} without a message is thrown. If
+     * <code>expected</code> and <code>actual</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param expected expected value
+     * @param actual the value to check against <code>expected</code>
+     */
+    static public void assertEquals(Object expected, Object actual) {
+        assertEquals(null, expected, actual);
+    }
 
-	/**
-	 * Asserts that two byte arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            byte array with expected values.
-	 * @param actuals
-	 *            byte array with actual values
-	 */
-	public static void assertArrayEquals(String message, byte[] expecteds,
-			byte[] actuals) throws ArrayComparisonFailure {
-		internalArrayEquals(message, expecteds, actuals);
-	}
+    /**
+     * Asserts that two objects are <b>not</b> equals. If they are, an
+     * {@link AssertionError} is thrown with the given message. If
+     * <code>unexpected</code> and <code>actual</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param unexpected unexpected value to check
+     * @param actual the value to check against <code>unexpected</code>
+     */
+    static public void assertNotEquals(String message, Object unexpected,
+            Object actual) {
+        if (equalsRegardingNull(unexpected, actual)) {
+            failEquals(message, actual);
+        }
+    }
 
-	/**
-	 * Asserts that two byte arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown.
-	 * 
-	 * @param expecteds
-	 *            byte array with expected values.
-	 * @param actuals
-	 *            byte array with actual values
-	 */
-	public static void assertArrayEquals(byte[] expecteds, byte[] actuals) {
-		assertArrayEquals(null, expecteds, actuals);
-	}
+    /**
+     * Asserts that two objects are <b>not</b> equals. If they are, an
+     * {@link AssertionError} without a message is thrown. If
+     * <code>unexpected</code> and <code>actual</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param unexpected unexpected value to check
+     * @param actual the value to check against <code>unexpected</code>
+     */
+    static public void assertNotEquals(Object unexpected, Object actual) {
+        assertNotEquals(null, unexpected, actual);
+    }
 
-	/**
-	 * Asserts that two char arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            char array with expected values.
-	 * @param actuals
-	 *            char array with actual values
-	 */
-	public static void assertArrayEquals(String message, char[] expecteds,
-			char[] actuals) throws ArrayComparisonFailure {
-		internalArrayEquals(message, expecteds, actuals);
-	}
+    private static void failEquals(String message, Object actual) {
+        String formatted = "Values should be different. ";
+        if (message != null) {
+            formatted = message + ". ";
+        }
 
-	/**
-	 * Asserts that two char arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown.
-	 * 
-	 * @param expecteds
-	 *            char array with expected values.
-	 * @param actuals
-	 *            char array with actual values
-	 */
-	public static void assertArrayEquals(char[] expecteds, char[] actuals) {
-		assertArrayEquals(null, expecteds, actuals);
-	}
+        formatted += "Actual: " + actual;
+        fail(formatted);
+    }
 
-	/**
-	 * Asserts that two short arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            short array with expected values.
-	 * @param actuals
-	 *            short array with actual values
-	 */
-	public static void assertArrayEquals(String message, short[] expecteds,
-			short[] actuals) throws ArrayComparisonFailure {
-		internalArrayEquals(message, expecteds, actuals);
-	}
+    /**
+     * Asserts that two longs are <b>not</b> equals. If they are, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param unexpected unexpected value to check
+     * @param actual the value to check against <code>unexpected</code>
+     */
+    static public void assertNotEquals(String message, long unexpected, long actual) {
+        if (unexpected == actual) {
+            failEquals(message, Long.valueOf(actual));
+        }
+    }
 
-	/**
-	 * Asserts that two short arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown.
-	 * 
-	 * @param expecteds
-	 *            short array with expected values.
-	 * @param actuals
-	 *            short array with actual values
-	 */
-	public static void assertArrayEquals(short[] expecteds, short[] actuals) {
-		assertArrayEquals(null, expecteds, actuals);
-	}
+    /**
+     * Asserts that two longs are <b>not</b> equals. If they are, an
+     * {@link AssertionError} without a message is thrown.
+     *
+     * @param unexpected unexpected value to check
+     * @param actual the value to check against <code>unexpected</code>
+     */
+    static public void assertNotEquals(long unexpected, long actual) {
+        assertNotEquals(null, unexpected, actual);
+    }
 
-	/**
-	 * Asserts that two int arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            int array with expected values.
-	 * @param actuals
-	 *            int array with actual values
-	 */
-	public static void assertArrayEquals(String message, int[] expecteds,
-			int[] actuals) throws ArrayComparisonFailure {
-		internalArrayEquals(message, expecteds, actuals);
-	}
+    /**
+     * Asserts that two doubles are <b>not</b> equal to within a positive delta.
+     * If they are, an {@link AssertionError} is thrown with the given
+     * message. If the unexpected value is infinity then the delta value is
+     * ignored. NaNs are considered equal:
+     * <code>assertNotEquals(Double.NaN, Double.NaN, *)</code> fails
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param unexpected unexpected value
+     * @param actual the value to check against <code>unexpected</code>
+     * @param delta the maximum delta between <code>unexpected</code> and
+     * <code>actual</code> for which both numbers are still
+     * considered equal.
+     */
+    static public void assertNotEquals(String message, double unexpected,
+            double actual, double delta) {
+        if (!doubleIsDifferent(unexpected, actual, delta)) {
+            failEquals(message, Double.valueOf(actual));
+        }
+    }
 
-	/**
-	 * Asserts that two int arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown.
-	 * 
-	 * @param expecteds
-	 *            int array with expected values.
-	 * @param actuals
-	 *            int array with actual values
-	 */
-	public static void assertArrayEquals(int[] expecteds, int[] actuals) {
-		assertArrayEquals(null, expecteds, actuals);
-	}
+    /**
+     * Asserts that two doubles are <b>not</b> equal to within a positive delta.
+     * If they are, an {@link AssertionError} is thrown. If the unexpected
+     * value is infinity then the delta value is ignored.NaNs are considered
+     * equal: <code>assertNotEquals(Double.NaN, Double.NaN, *)</code> fails
+     *
+     * @param unexpected unexpected value
+     * @param actual the value to check against <code>unexpected</code>
+     * @param delta the maximum delta between <code>unexpected</code> and
+     * <code>actual</code> for which both numbers are still
+     * considered equal.
+     */
+    static public void assertNotEquals(double unexpected, double actual, double delta) {
+        assertNotEquals(null, unexpected, actual, delta);
+    }
 
-	/**
-	 * Asserts that two long arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            long array with expected values.
-	 * @param actuals
-	 *            long array with actual values
-	 */
-	public static void assertArrayEquals(String message, long[] expecteds,
-			long[] actuals) throws ArrayComparisonFailure {
-		internalArrayEquals(message, expecteds, actuals);
-	}
+    /**
+     * Asserts that two floats are <b>not</b> equal to within a positive delta.
+     * If they are, an {@link AssertionError} is thrown. If the unexpected
+     * value is infinity then the delta value is ignored.NaNs are considered
+     * equal: <code>assertNotEquals(Float.NaN, Float.NaN, *)</code> fails
+     *
+     * @param unexpected unexpected value
+     * @param actual the value to check against <code>unexpected</code>
+     * @param delta the maximum delta between <code>unexpected</code> and
+     * <code>actual</code> for which both numbers are still
+     * considered equal.
+     */
+    static public void assertNotEquals(float unexpected, float actual, float delta) {
+        assertNotEquals(null, unexpected, actual, delta);
+    }
 
-	/**
-	 * Asserts that two long arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown.
-	 * 
-	 * @param expecteds
-	 *            long array with expected values.
-	 * @param actuals
-	 *            long array with actual values
-	 */
-	public static void assertArrayEquals(long[] expecteds, long[] actuals) {
-		assertArrayEquals(null, expecteds, actuals);
-	}
-	
-	/**
-	 * Asserts that two double arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            double array with expected values.
-	 * @param actuals
-	 *            double array with actual values
-	 */
-	public static void assertArrayEquals(String message, double[] expecteds,
-			double[] actuals, double delta) throws ArrayComparisonFailure {
-		new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals);
-	}
+    /**
+     * Asserts that two object arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message. If
+     * <code>expecteds</code> and <code>actuals</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds Object array or array of arrays (multi-dimensional array) with
+     * expected values.
+     * @param actuals Object array or array of arrays (multi-dimensional array) with
+     * actual values
+     */
+    public static void assertArrayEquals(String message, Object[] expecteds,
+            Object[] actuals) throws ArrayComparisonFailure {
+        internalArrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two double arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown.
-	 * 
-	 * @param expecteds
-	 *            double array with expected values.
-	 * @param actuals
-	 *            double array with actual values
-	 */
-	public static void assertArrayEquals(double[] expecteds, double[] actuals, double delta) {
-		assertArrayEquals(null, expecteds, actuals, delta);
-	}
+    /**
+     * Asserts that two object arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown. If <code>expected</code> and
+     * <code>actual</code> are <code>null</code>, they are considered
+     * equal.
+     *
+     * @param expecteds Object array or array of arrays (multi-dimensional array) with
+     * expected values
+     * @param actuals Object array or array of arrays (multi-dimensional array) with
+     * actual values
+     */
+    public static void assertArrayEquals(Object[] expecteds, Object[] actuals) {
+        assertArrayEquals(null, expecteds, actuals);
+    }
+    
+    /**
+     * Asserts that two boolean arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message. If
+     * <code>expecteds</code> and <code>actuals</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds boolean array with expected values.
+     * @param actuals boolean array with expected values.
+     */
+    public static void assertArrayEquals(String message, boolean[] expecteds,
+            boolean[] actuals) throws ArrayComparisonFailure {
+        internalArrayEquals(message, expecteds, actuals);
+    }    
+    
+    /**
+     * Asserts that two boolean arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown. If <code>expected</code> and
+     * <code>actual</code> are <code>null</code>, they are considered
+     * equal.
+     *
+     * @param expecteds boolean array with expected values.
+     * @param actuals boolean array with expected values.
+     */
+    public static void assertArrayEquals(boolean[] expecteds, boolean[] actuals) {
+        assertArrayEquals(null, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two float arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            float array with expected values.
-	 * @param actuals
-	 *            float array with actual values
-	 */
-	public static void assertArrayEquals(String message, float[] expecteds,
-			float[] actuals, float delta) throws ArrayComparisonFailure {
-		new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals);
-	}
+    /**
+     * Asserts that two byte arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds byte array with expected values.
+     * @param actuals byte array with actual values
+     */
+    public static void assertArrayEquals(String message, byte[] expecteds,
+            byte[] actuals) throws ArrayComparisonFailure {
+        internalArrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two float arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown.
-	 * 
-	 * @param expecteds
-	 *            float array with expected values.
-	 * @param actuals
-	 *            float array with actual values
-	 */
-	public static void assertArrayEquals(float[] expecteds, float[] actuals, float delta) {
-		assertArrayEquals(null, expecteds, actuals, delta);
-	}
+    /**
+     * Asserts that two byte arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown.
+     *
+     * @param expecteds byte array with expected values.
+     * @param actuals byte array with actual values
+     */
+    public static void assertArrayEquals(byte[] expecteds, byte[] actuals) {
+        assertArrayEquals(null, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two object arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message. If
-	 * <code>expecteds</code> and <code>actuals</code> are <code>null</code>,
-	 * they are considered equal.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            expected values.
-	 * @param actuals
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            actual values
-	 */
-	private static void internalArrayEquals(String message, Object expecteds,
-			Object actuals) throws ArrayComparisonFailure {
-		new ExactComparisonCriteria().arrayEquals(message, expecteds, actuals);
-	}	
+    /**
+     * Asserts that two char arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds char array with expected values.
+     * @param actuals char array with actual values
+     */
+    public static void assertArrayEquals(String message, char[] expecteds,
+            char[] actuals) throws ArrayComparisonFailure {
+        internalArrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two doubles or floats are equal to within a positive delta.
-	 * If they are not, an {@link AssertionError} is thrown with the given
-	 * message. If the expected value is infinity then the delta value is
-	 * ignored. NaNs are considered equal:
-	 * <code>assertEquals(Double.NaN, Double.NaN, *)</code> passes
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expected
-	 *            expected value
-	 * @param actual
-	 *            the value to check against <code>expected</code>
-	 * @param delta
-	 *            the maximum delta between <code>expected</code> and
-	 *            <code>actual</code> for which both numbers are still
-	 *            considered equal.
-	 */
-	static public void assertEquals(String message, double expected,
-			double actual, double delta) {
-		if (Double.compare(expected, actual) == 0)
-			return;
-		if (!(Math.abs(expected - actual) <= delta))
-			failNotEquals(message, new Double(expected), new Double(actual));
-	}
+    /**
+     * Asserts that two char arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown.
+     *
+     * @param expecteds char array with expected values.
+     * @param actuals char array with actual values
+     */
+    public static void assertArrayEquals(char[] expecteds, char[] actuals) {
+        assertArrayEquals(null, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two longs are equal. If they are not, an
-	 * {@link AssertionError} is thrown.
-	 * 
-	 * @param expected
-	 *            expected long value.
-	 * @param actual
-	 *            actual long value
-	 */
-	static public void assertEquals(long expected, long actual) {
-		assertEquals(null, expected, actual);
-	}
+    /**
+     * Asserts that two short arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds short array with expected values.
+     * @param actuals short array with actual values
+     */
+    public static void assertArrayEquals(String message, short[] expecteds,
+            short[] actuals) throws ArrayComparisonFailure {
+        internalArrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two longs are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expected
-	 *            long expected value.
-	 * @param actual
-	 *            long actual value
-	 */
-	static public void assertEquals(String message, long expected, long actual) {
-		assertEquals(message, (Long) expected, (Long) actual);
-	}
+    /**
+     * Asserts that two short arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown.
+     *
+     * @param expecteds short array with expected values.
+     * @param actuals short array with actual values
+     */
+    public static void assertArrayEquals(short[] expecteds, short[] actuals) {
+        assertArrayEquals(null, expecteds, actuals);
+    }
 
-	/**
-	 * @deprecated Use
-	 *             <code>assertEquals(double expected, double actual, double delta)</code>
-	 *             instead
-	 */
-	@Deprecated
-	static public void assertEquals(double expected, double actual) {
-		assertEquals(null, expected, actual);
-	}
+    /**
+     * Asserts that two int arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds int array with expected values.
+     * @param actuals int array with actual values
+     */
+    public static void assertArrayEquals(String message, int[] expecteds,
+            int[] actuals) throws ArrayComparisonFailure {
+        internalArrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * @deprecated Use
-	 *             <code>assertEquals(String message, double expected, double actual, double delta)</code>
-	 *             instead
-	 */
-	@Deprecated
-	static public void assertEquals(String message, double expected,
-			double actual) {
-		fail("Use assertEquals(expected, actual, delta) to compare floating-point numbers");
-	}
+    /**
+     * Asserts that two int arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown.
+     *
+     * @param expecteds int array with expected values.
+     * @param actuals int array with actual values
+     */
+    public static void assertArrayEquals(int[] expecteds, int[] actuals) {
+        assertArrayEquals(null, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two doubles or floats are equal to within a positive delta.
-	 * If they are not, an {@link AssertionError} is thrown. If the expected
-	 * value is infinity then the delta value is ignored.NaNs are considered
-	 * equal: <code>assertEquals(Double.NaN, Double.NaN, *)</code> passes
-	 * 
-	 * @param expected
-	 *            expected value
-	 * @param actual
-	 *            the value to check against <code>expected</code>
-	 * @param delta
-	 *            the maximum delta between <code>expected</code> and
-	 *            <code>actual</code> for which both numbers are still
-	 *            considered equal.
-	 */
-	static public void assertEquals(double expected, double actual, double delta) {
-		assertEquals(null, expected, actual, delta);
-	}
+    /**
+     * Asserts that two long arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds long array with expected values.
+     * @param actuals long array with actual values
+     */
+    public static void assertArrayEquals(String message, long[] expecteds,
+            long[] actuals) throws ArrayComparisonFailure {
+        internalArrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that an object isn't null. If it is an {@link AssertionError} is
-	 * thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param object
-	 *            Object to check or <code>null</code>
-	 */
-	static public void assertNotNull(String message, Object object) {
-		assertTrue(message, object != null);
-	}
+    /**
+     * Asserts that two long arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown.
+     *
+     * @param expecteds long array with expected values.
+     * @param actuals long array with actual values
+     */
+    public static void assertArrayEquals(long[] expecteds, long[] actuals) {
+        assertArrayEquals(null, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that an object isn't null. If it is an {@link AssertionError} is
-	 * thrown.
-	 * 
-	 * @param object
-	 *            Object to check or <code>null</code>
-	 */
-	static public void assertNotNull(Object object) {
-		assertNotNull(null, object);
-	}
+    /**
+     * Asserts that two double arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds double array with expected values.
+     * @param actuals double array with actual values
+     * @param delta the maximum delta between <code>expecteds[i]</code> and
+     * <code>actuals[i]</code> for which both numbers are still
+     * considered equal.
+     */
+    public static void assertArrayEquals(String message, double[] expecteds,
+            double[] actuals, double delta) throws ArrayComparisonFailure {
+        new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that an object is null. If it is not, an {@link AssertionError}
-	 * is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param object
-	 *            Object to check or <code>null</code>
-	 */
-	static public void assertNull(String message, Object object) {
-		assertTrue(message, object == null);
-	}
+    /**
+     * Asserts that two double arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown.
+     *
+     * @param expecteds double array with expected values.
+     * @param actuals double array with actual values
+     * @param delta the maximum delta between <code>expecteds[i]</code> and
+     * <code>actuals[i]</code> for which both numbers are still
+     * considered equal.
+     */
+    public static void assertArrayEquals(double[] expecteds, double[] actuals, double delta) {
+        assertArrayEquals(null, expecteds, actuals, delta);
+    }
 
-	/**
-	 * Asserts that an object is null. If it isn't an {@link AssertionError} is
-	 * thrown.
-	 * 
-	 * @param object
-	 *            Object to check or <code>null</code>
-	 */
-	static public void assertNull(Object object) {
-		assertNull(null, object);
-	}
+    /**
+     * Asserts that two float arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds float array with expected values.
+     * @param actuals float array with actual values
+     * @param delta the maximum delta between <code>expecteds[i]</code> and
+     * <code>actuals[i]</code> for which both numbers are still
+     * considered equal.
+     */
+    public static void assertArrayEquals(String message, float[] expecteds,
+            float[] actuals, float delta) throws ArrayComparisonFailure {
+        new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two objects refer to the same object. If they are not, an
-	 * {@link AssertionError} is thrown with the given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expected
-	 *            the expected object
-	 * @param actual
-	 *            the object to compare to <code>expected</code>
-	 */
-	static public void assertSame(String message, Object expected, Object actual) {
-		if (expected == actual)
-			return;
-		failNotSame(message, expected, actual);
-	}
+    /**
+     * Asserts that two float arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown.
+     *
+     * @param expecteds float array with expected values.
+     * @param actuals float array with actual values
+     * @param delta the maximum delta between <code>expecteds[i]</code> and
+     * <code>actuals[i]</code> for which both numbers are still
+     * considered equal.
+     */
+    public static void assertArrayEquals(float[] expecteds, float[] actuals, float delta) {
+        assertArrayEquals(null, expecteds, actuals, delta);
+    }
 
-	/**
-	 * Asserts that two objects refer to the same object. If they are not the
-	 * same, an {@link AssertionError} without a message is thrown.
-	 * 
-	 * @param expected
-	 *            the expected object
-	 * @param actual
-	 *            the object to compare to <code>expected</code>
-	 */
-	static public void assertSame(Object expected, Object actual) {
-		assertSame(null, expected, actual);
-	}
+    /**
+     * Asserts that two object arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message. If
+     * <code>expecteds</code> and <code>actuals</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds Object array or array of arrays (multi-dimensional array) with
+     * expected values.
+     * @param actuals Object array or array of arrays (multi-dimensional array) with
+     * actual values
+     */
+    private static void internalArrayEquals(String message, Object expecteds,
+            Object actuals) throws ArrayComparisonFailure {
+        new ExactComparisonCriteria().arrayEquals(message, expecteds, actuals);
+    }
 
-	/**
-	 * Asserts that two objects do not refer to the same object. If they do
-	 * refer to the same object, an {@link AssertionError} is thrown with the
-	 * given message.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param unexpected
-	 *            the object you don't expect
-	 * @param actual
-	 *            the object to compare to <code>unexpected</code>
-	 */
-	static public void assertNotSame(String message, Object unexpected,
-			Object actual) {
-		if (unexpected == actual)
-			failSame(message);
-	}
+    /**
+     * Asserts that two doubles are equal to within a positive delta.
+     * If they are not, an {@link AssertionError} is thrown with the given
+     * message. If the expected value is infinity then the delta value is
+     * ignored. NaNs are considered equal:
+     * <code>assertEquals(Double.NaN, Double.NaN, *)</code> passes
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expected expected value
+     * @param actual the value to check against <code>expected</code>
+     * @param delta the maximum delta between <code>expected</code> and
+     * <code>actual</code> for which both numbers are still
+     * considered equal.
+     */
+    static public void assertEquals(String message, double expected,
+            double actual, double delta) {
+        if (doubleIsDifferent(expected, actual, delta)) {
+            failNotEquals(message, Double.valueOf(expected), Double.valueOf(actual));
+        }
+    }
 
-	/**
-	 * Asserts that two objects do not refer to the same object. If they do
-	 * refer to the same object, an {@link AssertionError} without a message is
-	 * thrown.
-	 * 
-	 * @param unexpected
-	 *            the object you don't expect
-	 * @param actual
-	 *            the object to compare to <code>unexpected</code>
-	 */
-	static public void assertNotSame(Object unexpected, Object actual) {
-		assertNotSame(null, unexpected, actual);
-	}
+    /**
+     * Asserts that two floats are equal to within a positive delta.
+     * If they are not, an {@link AssertionError} is thrown with the given
+     * message. If the expected value is infinity then the delta value is
+     * ignored. NaNs are considered equal:
+     * <code>assertEquals(Float.NaN, Float.NaN, *)</code> passes
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expected expected value
+     * @param actual the value to check against <code>expected</code>
+     * @param delta the maximum delta between <code>expected</code> and
+     * <code>actual</code> for which both numbers are still
+     * considered equal.
+     */
+    static public void assertEquals(String message, float expected,
+            float actual, float delta) {
+        if (floatIsDifferent(expected, actual, delta)) {
+            failNotEquals(message, Float.valueOf(expected), Float.valueOf(actual));
+        }
+    }
 
-	static private void failSame(String message) {
-		String formatted= "";
-		if (message != null)
-			formatted= message + " ";
-		fail(formatted + "expected not same");
-	}
+    /**
+     * Asserts that two floats are <b>not</b> equal to within a positive delta.
+     * If they are, an {@link AssertionError} is thrown with the given
+     * message. If the unexpected value is infinity then the delta value is
+     * ignored. NaNs are considered equal:
+     * <code>assertNotEquals(Float.NaN, Float.NaN, *)</code> fails
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param unexpected unexpected value
+     * @param actual the value to check against <code>unexpected</code>
+     * @param delta the maximum delta between <code>unexpected</code> and
+     * <code>actual</code> for which both numbers are still
+     * considered equal.
+     */
+    static public void assertNotEquals(String message, float unexpected,
+            float actual, float delta) {
+        if (!floatIsDifferent(unexpected, actual, delta)) {
+            failEquals(message, Float.valueOf(actual));
+        }
+    }
 
-	static private void failNotSame(String message, Object expected,
-			Object actual) {
-		String formatted= "";
-		if (message != null)
-			formatted= message + " ";
-		fail(formatted + "expected same:<" + expected + "> was not:<" + actual
-				+ ">");
-	}
+    static private boolean doubleIsDifferent(double d1, double d2, double delta) {
+        if (Double.compare(d1, d2) == 0) {
+            return false;
+        }
+        if ((Math.abs(d1 - d2) <= delta)) {
+            return false;
+        }
 
-	static private void failNotEquals(String message, Object expected,
-			Object actual) {
-		fail(format(message, expected, actual));
-	}
+        return true;
+    }
 
-	static String format(String message, Object expected, Object actual) {
-		String formatted= "";
-		if (message != null && !message.equals(""))
-			formatted= message + " ";
-		String expectedString= String.valueOf(expected);
-		String actualString= String.valueOf(actual);
-		if (expectedString.equals(actualString))
-			return formatted + "expected: "
-					+ formatClassAndValue(expected, expectedString)
-					+ " but was: " + formatClassAndValue(actual, actualString);
-		else
-			return formatted + "expected:<" + expectedString + "> but was:<"
-					+ actualString + ">";
-	}
+    static private boolean floatIsDifferent(float f1, float f2, float delta) {
+        if (Float.compare(f1, f2) == 0) {
+            return false;
+        }
+        if ((Math.abs(f1 - f2) <= delta)) {
+            return false;
+        }
 
-	private static String formatClassAndValue(Object value, String valueString) {
-		String className= value == null ? "null" : value.getClass().getName();
-		return className + "<" + valueString + ">";
-	}
+        return true;
+    }
 
-	/**
-	 * Asserts that two object arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown with the given message. If
-	 * <code>expecteds</code> and <code>actuals</code> are <code>null</code>,
-	 * they are considered equal.
-	 * 
-	 * @param message
-	 *            the identifying message for the {@link AssertionError} (<code>null</code>
-	 *            okay)
-	 * @param expecteds
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            expected values.
-	 * @param actuals
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            actual values
-	 * @deprecated use assertArrayEquals
-	 */
-	@Deprecated
-	public static void assertEquals(String message, Object[] expecteds,
-			Object[] actuals) {
-		assertArrayEquals(message, expecteds, actuals);
-	}
+    /**
+     * Asserts that two longs are equal. If they are not, an
+     * {@link AssertionError} is thrown.
+     *
+     * @param expected expected long value.
+     * @param actual actual long value
+     */
+    static public void assertEquals(long expected, long actual) {
+        assertEquals(null, expected, actual);
+    }
 
-	/**
-	 * Asserts that two object arrays are equal. If they are not, an
-	 * {@link AssertionError} is thrown. If <code>expected</code> and
-	 * <code>actual</code> are <code>null</code>, they are considered
-	 * equal.
-	 * 
-	 * @param expecteds
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            expected values
-	 * @param actuals
-	 *            Object array or array of arrays (multi-dimensional array) with
-	 *            actual values
-	 * @deprecated use assertArrayEquals
-	 */
-	@Deprecated
-	public static void assertEquals(Object[] expecteds, Object[] actuals) {
-		assertArrayEquals(expecteds, actuals);
-	}
+    /**
+     * Asserts that two longs are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expected long expected value.
+     * @param actual long actual value
+     */
+    static public void assertEquals(String message, long expected, long actual) {
+        if (expected != actual) {
+            failNotEquals(message, Long.valueOf(expected), Long.valueOf(actual));
+        }
+    }
 
-	/**
-	 * Asserts that <code>actual</code> satisfies the condition specified by
-	 * <code>matcher</code>. If not, an {@link AssertionError} is thrown with
-	 * information about the matcher and failing value. Example:
-	 * 
-	 * <pre>
-	 *   assertThat(0, is(1)); // fails:
-	 *     // failure message:
-	 *     // expected: is &lt;1&gt; 
-	 *     // got value: &lt;0&gt;
-	 *   assertThat(0, is(not(1))) // passes
-	 * </pre>
-	 * 
-	 * @param <T>
-	 *            the static type accepted by the matcher (this can flag obvious
-	 *            compile-time problems such as {@code assertThat(1, is("a"))}
-	 * @param actual
-	 *            the computed value being compared
-	 * @param matcher
-	 *            an expression, built of {@link Matcher}s, specifying allowed
-	 *            values
-	 * 
-	 * @see org.hamcrest.CoreMatchers
-	 * @see org.junit.matchers.JUnitMatchers
-	 */
-	public static <T> void assertThat(T actual, Matcher<T> matcher) {
-		assertThat("", actual, matcher);
-	}
+    /**
+     * @deprecated Use
+     *             <code>assertEquals(double expected, double actual, double delta)</code>
+     *             instead
+     */
+    @Deprecated
+    static public void assertEquals(double expected, double actual) {
+        assertEquals(null, expected, actual);
+    }
 
-	/**
-	 * Asserts that <code>actual</code> satisfies the condition specified by
-	 * <code>matcher</code>. If not, an {@link AssertionError} is thrown with
-	 * the reason and information about the matcher and failing value. Example:
-	 * 
-	 * <pre>
-	 * :
-	 *   assertThat(&quot;Help! Integers don't work&quot;, 0, is(1)); // fails:
-	 *     // failure message:
-	 *     // Help! Integers don't work
-	 *     // expected: is &lt;1&gt; 
-	 *     // got value: &lt;0&gt;
-	 *   assertThat(&quot;Zero is one&quot;, 0, is(not(1))) // passes
-	 * </pre>
-	 * 
-	 * @param reason
-	 *            additional information about the error
-	 * @param <T>
-	 *            the static type accepted by the matcher (this can flag obvious
-	 *            compile-time problems such as {@code assertThat(1, is("a"))}
-	 * @param actual
-	 *            the computed value being compared
-	 * @param matcher
-	 *            an expression, built of {@link Matcher}s, specifying allowed
-	 *            values
-	 * 
-	 * @see org.hamcrest.CoreMatchers
-	 * @see org.junit.matchers.JUnitMatchers
-	 */
-	public static <T> void assertThat(String reason, T actual,
-			Matcher<T> matcher) {
-		if (!matcher.matches(actual)) {
-			Description description= new StringDescription();
-			description.appendText(reason);
-			description.appendText("\nExpected: ");
-			description.appendDescriptionOf(matcher);
-			description.appendText("\n     got: ");
-			description.appendValue(actual);
-			description.appendText("\n");
-			throw new java.lang.AssertionError(description.toString());
-		}
-	}
+    /**
+     * @deprecated Use
+     *             <code>assertEquals(String message, double expected, double actual, double delta)</code>
+     *             instead
+     */
+    @Deprecated
+    static public void assertEquals(String message, double expected,
+            double actual) {
+        fail("Use assertEquals(expected, actual, delta) to compare floating-point numbers");
+    }
+
+    /**
+     * Asserts that two doubles are equal to within a positive delta.
+     * If they are not, an {@link AssertionError} is thrown. If the expected
+     * value is infinity then the delta value is ignored.NaNs are considered
+     * equal: <code>assertEquals(Double.NaN, Double.NaN, *)</code> passes
+     *
+     * @param expected expected value
+     * @param actual the value to check against <code>expected</code>
+     * @param delta the maximum delta between <code>expected</code> and
+     * <code>actual</code> for which both numbers are still
+     * considered equal.
+     */
+    static public void assertEquals(double expected, double actual, double delta) {
+        assertEquals(null, expected, actual, delta);
+    }
+
+    /**
+     * Asserts that two floats are equal to within a positive delta.
+     * If they are not, an {@link AssertionError} is thrown. If the expected
+     * value is infinity then the delta value is ignored. NaNs are considered
+     * equal: <code>assertEquals(Float.NaN, Float.NaN, *)</code> passes
+     *
+     * @param expected expected value
+     * @param actual the value to check against <code>expected</code>
+     * @param delta the maximum delta between <code>expected</code> and
+     * <code>actual</code> for which both numbers are still
+     * considered equal.
+     */
+
+    static public void assertEquals(float expected, float actual, float delta) {
+        assertEquals(null, expected, actual, delta);
+    }
+
+    /**
+     * Asserts that an object isn't null. If it is an {@link AssertionError} is
+     * thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param object Object to check or <code>null</code>
+     */
+    static public void assertNotNull(String message, Object object) {
+        assertTrue(message, object != null);
+    }
+
+    /**
+     * Asserts that an object isn't null. If it is an {@link AssertionError} is
+     * thrown.
+     *
+     * @param object Object to check or <code>null</code>
+     */
+    static public void assertNotNull(Object object) {
+        assertNotNull(null, object);
+    }
+
+    /**
+     * Asserts that an object is null. If it is not, an {@link AssertionError}
+     * is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param object Object to check or <code>null</code>
+     */
+    static public void assertNull(String message, Object object) {
+        if (object == null) {
+            return;
+        }
+        failNotNull(message, object);
+    }
+
+    /**
+     * Asserts that an object is null. If it isn't an {@link AssertionError} is
+     * thrown.
+     *
+     * @param object Object to check or <code>null</code>
+     */
+    static public void assertNull(Object object) {
+        assertNull(null, object);
+    }
+
+    static private void failNotNull(String message, Object actual) {
+        String formatted = "";
+        if (message != null) {
+            formatted = message + " ";
+        }
+        fail(formatted + "expected null, but was:<" + actual + ">");
+    }
+
+    /**
+     * Asserts that two objects refer to the same object. If they are not, an
+     * {@link AssertionError} is thrown with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expected the expected object
+     * @param actual the object to compare to <code>expected</code>
+     */
+    static public void assertSame(String message, Object expected, Object actual) {
+        if (expected == actual) {
+            return;
+        }
+        failNotSame(message, expected, actual);
+    }
+
+    /**
+     * Asserts that two objects refer to the same object. If they are not the
+     * same, an {@link AssertionError} without a message is thrown.
+     *
+     * @param expected the expected object
+     * @param actual the object to compare to <code>expected</code>
+     */
+    static public void assertSame(Object expected, Object actual) {
+        assertSame(null, expected, actual);
+    }
+
+    /**
+     * Asserts that two objects do not refer to the same object. If they do
+     * refer to the same object, an {@link AssertionError} is thrown with the
+     * given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param unexpected the object you don't expect
+     * @param actual the object to compare to <code>unexpected</code>
+     */
+    static public void assertNotSame(String message, Object unexpected,
+            Object actual) {
+        if (unexpected == actual) {
+            failSame(message);
+        }
+    }
+
+    /**
+     * Asserts that two objects do not refer to the same object. If they do
+     * refer to the same object, an {@link AssertionError} without a message is
+     * thrown.
+     *
+     * @param unexpected the object you don't expect
+     * @param actual the object to compare to <code>unexpected</code>
+     */
+    static public void assertNotSame(Object unexpected, Object actual) {
+        assertNotSame(null, unexpected, actual);
+    }
+
+    static private void failSame(String message) {
+        String formatted = "";
+        if (message != null) {
+            formatted = message + " ";
+        }
+        fail(formatted + "expected not same");
+    }
+
+    static private void failNotSame(String message, Object expected,
+            Object actual) {
+        String formatted = "";
+        if (message != null) {
+            formatted = message + " ";
+        }
+        fail(formatted + "expected same:<" + expected + "> was not:<" + actual
+                + ">");
+    }
+
+    static private void failNotEquals(String message, Object expected,
+            Object actual) {
+        fail(format(message, expected, actual));
+    }
+
+    static String format(String message, Object expected, Object actual) {
+        String formatted = "";
+        if (message != null && !message.equals("")) {
+            formatted = message + " ";
+        }
+        String expectedString = String.valueOf(expected);
+        String actualString = String.valueOf(actual);
+        if (expectedString.equals(actualString)) {
+            return formatted + "expected: "
+                    + formatClassAndValue(expected, expectedString)
+                    + " but was: " + formatClassAndValue(actual, actualString);
+        } else {
+            return formatted + "expected:<" + expectedString + "> but was:<"
+                    + actualString + ">";
+        }
+    }
+
+    private static String formatClassAndValue(Object value, String valueString) {
+        String className = value == null ? "null" : value.getClass().getName();
+        return className + "<" + valueString + ">";
+    }
+
+    /**
+     * Asserts that two object arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message. If
+     * <code>expecteds</code> and <code>actuals</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds Object array or array of arrays (multi-dimensional array) with
+     * expected values.
+     * @param actuals Object array or array of arrays (multi-dimensional array) with
+     * actual values
+     * @deprecated use assertArrayEquals
+     */
+    @Deprecated
+    public static void assertEquals(String message, Object[] expecteds,
+            Object[] actuals) {
+        assertArrayEquals(message, expecteds, actuals);
+    }
+
+    /**
+     * Asserts that two object arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown. If <code>expected</code> and
+     * <code>actual</code> are <code>null</code>, they are considered
+     * equal.
+     *
+     * @param expecteds Object array or array of arrays (multi-dimensional array) with
+     * expected values
+     * @param actuals Object array or array of arrays (multi-dimensional array) with
+     * actual values
+     * @deprecated use assertArrayEquals
+     */
+    @Deprecated
+    public static void assertEquals(Object[] expecteds, Object[] actuals) {
+        assertArrayEquals(expecteds, actuals);
+    }
+
+    /**
+     * Asserts that <code>actual</code> satisfies the condition specified by
+     * <code>matcher</code>. If not, an {@link AssertionError} is thrown with
+     * information about the matcher and failing value. Example:
+     *
+     * <pre>
+     *   assertThat(0, is(1)); // fails:
+     *     // failure message:
+     *     // expected: is &lt;1&gt;
+     *     // got value: &lt;0&gt;
+     *   assertThat(0, is(not(1))) // passes
+     * </pre>
+     *
+     * <code>org.hamcrest.Matcher</code> does not currently document the meaning
+     * of its type parameter <code>T</code>.  This method assumes that a matcher
+     * typed as <code>Matcher&lt;T&gt;</code> can be meaningfully applied only
+     * to values that could be assigned to a variable of type <code>T</code>.
+     *
+     * @param <T> the static type accepted by the matcher (this can flag obvious
+     * compile-time problems such as {@code assertThat(1, is("a"))}
+     * @param actual the computed value being compared
+     * @param matcher an expression, built of {@link Matcher}s, specifying allowed
+     * values
+     * @see org.hamcrest.CoreMatchers
+     * @see org.hamcrest.MatcherAssert
+     */
+    public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
+        assertThat("", actual, matcher);
+    }
+
+    /**
+     * Asserts that <code>actual</code> satisfies the condition specified by
+     * <code>matcher</code>. If not, an {@link AssertionError} is thrown with
+     * the reason and information about the matcher and failing value. Example:
+     *
+     * <pre>
+     *   assertThat(&quot;Help! Integers don't work&quot;, 0, is(1)); // fails:
+     *     // failure message:
+     *     // Help! Integers don't work
+     *     // expected: is &lt;1&gt;
+     *     // got value: &lt;0&gt;
+     *   assertThat(&quot;Zero is one&quot;, 0, is(not(1))) // passes
+     * </pre>
+     *
+     * <code>org.hamcrest.Matcher</code> does not currently document the meaning
+     * of its type parameter <code>T</code>.  This method assumes that a matcher
+     * typed as <code>Matcher&lt;T&gt;</code> can be meaningfully applied only
+     * to values that could be assigned to a variable of type <code>T</code>.
+     *
+     * @param reason additional information about the error
+     * @param <T> the static type accepted by the matcher (this can flag obvious
+     * compile-time problems such as {@code assertThat(1, is("a"))}
+     * @param actual the computed value being compared
+     * @param matcher an expression, built of {@link Matcher}s, specifying allowed
+     * values
+     * @see org.hamcrest.CoreMatchers
+     * @see org.hamcrest.MatcherAssert
+     */
+    public static <T> void assertThat(String reason, T actual,
+            Matcher<? super T> matcher) {
+        MatcherAssert.assertThat(reason, actual, matcher);
+    }
 }
diff --git a/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java b/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java
new file mode 100644
index 0000000..23f921b
--- /dev/null
+++ b/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java
@@ -0,0 +1,91 @@
+package org.junit.internal.runners.rules;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.FrameworkField;
+import org.junit.runners.model.TestClass;
+
+/**
+ * A RuleFieldValidator validates the rule fields of a
+ * {@link TestClass}. All reasons for rejecting the
+ * {@code TestClass} are written to a list of errors.
+ *
+ * There are two slightly different validators. The {@link #CLASS_RULE_VALIDATOR}
+ * validates fields with a {@link ClassRule} annotation and the
+ * {@link #RULE_VALIDATOR} validates fields with a {@link Rule} annotation.
+ */
+public enum RuleMemberValidator {
+	/**
+	 * Validates fields with a {@link ClassRule} annotation.
+	 */
+	CLASS_RULE_VALIDATOR(ClassRule.class, true),
+	/**
+	 * Validates fields with a {@link Rule} annotation.
+	 */
+	RULE_VALIDATOR(Rule.class, false);
+
+	private final Class<? extends Annotation> fAnnotation;
+
+	private final boolean fOnlyStaticFields;
+
+	private RuleMemberValidator(Class<? extends Annotation> annotation,
+			boolean onlyStaticFields) {
+		this.fAnnotation= annotation;
+		this.fOnlyStaticFields= onlyStaticFields;
+	}
+
+	/**
+	 * Validate the {@link TestClass} and adds reasons
+	 * for rejecting the class to a list of errors.
+	 * @param target the {@code TestClass} to validate.
+	 * @param errors the list of errors.
+	 */
+	public void validate(TestClass target, List<Throwable> errors) {
+		List<FrameworkField> fields= target.getAnnotatedFields(fAnnotation);
+		for (FrameworkField each : fields)
+			validateField(each, errors);
+	}
+
+	private void validateField(FrameworkField field, List<Throwable> errors) {
+		optionallyValidateStatic(field, errors);
+		validatePublic(field, errors);
+		validateTestRuleOrMethodRule(field, errors);
+	}
+
+	private void optionallyValidateStatic(FrameworkField field,
+			List<Throwable> errors) {
+		if (fOnlyStaticFields && !field.isStatic())
+			addError(errors, field, "must be static.");
+	}
+
+	private void validatePublic(FrameworkField field, List<Throwable> errors) {
+		if (!field.isPublic())
+			addError(errors, field, "must be public.");
+	}
+
+	private void validateTestRuleOrMethodRule(FrameworkField field,
+			List<Throwable> errors) {
+		if (!isMethodRule(field) && !isTestRule(field))
+			addError(errors, field, "must implement MethodRule or TestRule.");
+	}
+
+	private boolean isTestRule(FrameworkField target) {
+		return TestRule.class.isAssignableFrom(target.getType());
+	}
+
+	@SuppressWarnings("deprecation")
+	private boolean isMethodRule(FrameworkField target) {
+		return org.junit.rules.MethodRule.class.isAssignableFrom(target
+				.getType());
+	}
+
+	private void addError(List<Throwable> errors, FrameworkField field,
+			String suffix) {
+		String message= "The @" + fAnnotation.getSimpleName() + " '"
+				+ field.getName() + "' " + suffix;
+		errors.add(new Exception(message));
+	}
+}
diff --git a/src/main/java/org/junit/runner/Description.java b/src/main/java/org/junit/runner/Description.java
index b3083d5..fe47eac 100644
--- a/src/main/java/org/junit/runner/Description.java
+++ b/src/main/java/org/junit/runner/Description.java
@@ -5,238 +5,312 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
- * <p>A <code>Description</code> describes a test which is to be run or has been run. <code>Descriptions</code> 
+ * A <code>Description</code> describes a test which is to be run or has been run. <code>Descriptions</code>
  * can be atomic (a single test) or compound (containing children tests). <code>Descriptions</code> are used
  * to provide feedback about the tests that are about to run (for example, the tree view
- * visible in many IDEs) or tests that have been run (for example, the failures view).</p>
- * 
- * <p><code>Descriptions</code> are implemented as a single class rather than a Composite because
- * they are entirely informational. They contain no logic aside from counting their tests.</p>
- * 
- * <p>In the past, we used the raw {@link junit.framework.TestCase}s and {@link junit.framework.TestSuite}s
- * to display the tree of tests. This was no longer viable in JUnit 4 because atomic tests no longer have 
- * a superclass below {@link Object}. We needed a way to pass a class and name together. Description 
- * emerged from this.</p>
- * 
+ * visible in many IDEs) or tests that have been run (for example, the failures view).
+ * <p>
+ * <code>Descriptions</code> are implemented as a single class rather than a Composite because
+ * they are entirely informational. They contain no logic aside from counting their tests.
+ * <p>
+ * In the past, we used the raw {@link junit.framework.TestCase}s and {@link junit.framework.TestSuite}s
+ * to display the tree of tests. This was no longer viable in JUnit 4 because atomic tests no longer have
+ * a superclass below {@link Object}. We needed a way to pass a class and name together. Description
+ * emerged from this.
+ *
  * @see org.junit.runner.Request
  * @see org.junit.runner.Runner
+ * @since 4.0
  */
 public class Description implements Serializable {
-	private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Create a <code>Description</code> named <code>name</code>.
-	 * Generally, you will add children to this <code>Description</code>.
-	 * @param name the name of the <code>Description</code> 
-	 * @param annotations 
-	 * @return a <code>Description</code> named <code>name</code>
-	 */
-	public static Description createSuiteDescription(String name, Annotation... annotations) {
-		if (name.length() == 0)
-			throw new IllegalArgumentException("name must have non-zero length");
-		return new Description(name, annotations);
-	}
+    private static final Pattern METHOD_AND_CLASS_NAME_PATTERN = Pattern
+            .compile("([\\s\\S]*)\\((.*)\\)");
 
-	/**
-	 * Create a <code>Description</code> of a single test named <code>name</code> in the class <code>clazz</code>.
-	 * Generally, this will be a leaf <code>Description</code>.
-	 * @param clazz the class of the test
-	 * @param name the name of the test (a method name for test annotated with {@link org.junit.Test})
-	 * @param annotations meta-data about the test, for downstream interpreters
-	 * @return a <code>Description</code> named <code>name</code>
-	 */
-	public static Description createTestDescription(Class<?> clazz, String name, Annotation... annotations) {
-		return new Description(String.format("%s(%s)", name, clazz.getName()), annotations);
-	}
+    /**
+     * Create a <code>Description</code> named <code>name</code>.
+     * Generally, you will add children to this <code>Description</code>.
+     *
+     * @param name the name of the <code>Description</code>
+     * @param annotations meta-data about the test, for downstream interpreters
+     * @return a <code>Description</code> named <code>name</code>
+     */
+    public static Description createSuiteDescription(String name, Annotation... annotations) {
+        return new Description(null, name, annotations);
+    }
 
-	/**
-	 * Create a <code>Description</code> of a single test named <code>name</code> in the class <code>clazz</code>.
-	 * Generally, this will be a leaf <code>Description</code>.  
-	 * (This remains for binary compatibility with clients of JUnit 4.3)
-	 * @param clazz the class of the test
-	 * @param name the name of the test (a method name for test annotated with {@link org.junit.Test})
-	 * @return a <code>Description</code> named <code>name</code>
-	 */
-	public static Description createTestDescription(Class<?> clazz, String name) {
-		return createTestDescription(clazz, name, new Annotation[0]);
-	}
+    /**
+     * Create a <code>Description</code> named <code>name</code>.
+     * Generally, you will add children to this <code>Description</code>.
+     *
+     * @param name the name of the <code>Description</code>
+     * @param uniqueId an arbitrary object used to define uniqueness (in {@link #equals(Object)}
+     * @param annotations meta-data about the test, for downstream interpreters
+     * @return a <code>Description</code> named <code>name</code>
+     */
+    public static Description createSuiteDescription(String name, Serializable uniqueId, Annotation... annotations) {
+        return new Description(null, name, uniqueId, annotations);
+    }
 
-	/**
-	 * Create a <code>Description</code> named after <code>testClass</code>
-	 * @param testClass A {@link Class} containing tests 
-	 * @return a <code>Description</code> of <code>testClass</code>
-	 */
-	public static Description createSuiteDescription(Class<?> testClass) {
-		return new Description(testClass.getName(), testClass.getAnnotations());
-	}
-	
-	/**
-	 * Describes a Runner which runs no tests
-	 */
-	public static final Description EMPTY= new Description("No Tests");
-	
-	/**
-	 * Describes a step in the test-running mechanism that goes so wrong no
-	 * other description can be used (for example, an exception thrown from a Runner's
-	 * constructor
-	 */
-	public static final Description TEST_MECHANISM= new Description("Test mechanism");
-	
-	private final ArrayList<Description> fChildren= new ArrayList<Description>();
-	private final String fDisplayName;
-	
-	private final Annotation[] fAnnotations;
-	
-	private Description(final String displayName, Annotation... annotations) {
-		fDisplayName= displayName;
-		fAnnotations= annotations;
-	}
+    /**
+     * Create a <code>Description</code> of a single test named <code>name</code> in the 'class' named
+     * <code>className</code>. Generally, this will be a leaf <code>Description</code>. This method is a better choice
+     * than {@link #createTestDescription(Class, String, Annotation...)} for test runners whose test cases are not
+     * defined in an actual Java <code>Class</code>.
+     *
+     * @param className the class name of the test
+     * @param name the name of the test (a method name for test annotated with {@link org.junit.Test})
+     * @param annotations meta-data about the test, for downstream interpreters
+     * @return a <code>Description</code> named <code>name</code>
+     */
+    public static Description createTestDescription(String className, String name, Annotation... annotations) {
+        return new Description(null, formatDisplayName(name, className), annotations);
+    }
 
-	/**
-	 * @return a user-understandable label
-	 */
-	public String getDisplayName() {
-		return fDisplayName;
-	}
+    /**
+     * Create a <code>Description</code> of a single test named <code>name</code> in the class <code>clazz</code>.
+     * Generally, this will be a leaf <code>Description</code>.
+     *
+     * @param clazz the class of the test
+     * @param name the name of the test (a method name for test annotated with {@link org.junit.Test})
+     * @param annotations meta-data about the test, for downstream interpreters
+     * @return a <code>Description</code> named <code>name</code>
+     */
+    public static Description createTestDescription(Class<?> clazz, String name, Annotation... annotations) {
+        return new Description(clazz, formatDisplayName(name, clazz.getName()), annotations);
+    }
 
-	/**
-	 * Add <code>Description</code> as a child of the receiver.
-	 * @param description the soon-to-be child.
-	 */
-	public void addChild(Description description) {
-		getChildren().add(description);
-	}
+    /**
+     * Create a <code>Description</code> of a single test named <code>name</code> in the class <code>clazz</code>.
+     * Generally, this will be a leaf <code>Description</code>.
+     * (This remains for binary compatibility with clients of JUnit 4.3)
+     *
+     * @param clazz the class of the test
+     * @param name the name of the test (a method name for test annotated with {@link org.junit.Test})
+     * @return a <code>Description</code> named <code>name</code>
+     */
+    public static Description createTestDescription(Class<?> clazz, String name) {
+        return new Description(clazz, formatDisplayName(name, clazz.getName()));
+    }
 
-	/**
-	 * @return the receiver's children, if any
-	 */
-	public ArrayList<Description> getChildren() {
-		return fChildren;
-	}
+    /**
+     * Create a <code>Description</code> of a single test named <code>name</code> in the class <code>clazz</code>.
+     * Generally, this will be a leaf <code>Description</code>.
+     *
+     * @param name the name of the test (a method name for test annotated with {@link org.junit.Test})
+     * @return a <code>Description</code> named <code>name</code>
+     */
+    public static Description createTestDescription(String className, String name, Serializable uniqueId) {
+        return new Description(null, formatDisplayName(name, className), uniqueId);
+    }
 
-	/**
-	 * @return <code>true</code> if the receiver is a suite
-	 */
-	public boolean isSuite() {
-		return !isTest();
-	}
+    private static String formatDisplayName(String name, String className) {
+        return String.format("%s(%s)", name, className);
+    }
 
-	/**
-	 * @return <code>true</code> if the receiver is an atomic test
-	 */
-	public boolean isTest() {
-		return getChildren().isEmpty();
-	}
+    /**
+     * Create a <code>Description</code> named after <code>testClass</code>
+     *
+     * @param testClass A {@link Class} containing tests
+     * @return a <code>Description</code> of <code>testClass</code>
+     */
+    public static Description createSuiteDescription(Class<?> testClass) {
+        return new Description(testClass, testClass.getName(), testClass.getAnnotations());
+    }
 
-	/**
-	 * @return the total number of atomic tests in the receiver
-	 */
-	public int testCount() {
-		if (isTest())
-			return 1;
-		int result= 0;
-		for (Description child : getChildren())
-			result+= child.testCount();
-		return result;
-	}
+    /**
+     * Describes a Runner which runs no tests
+     */
+    public static final Description EMPTY = new Description(null, "No Tests");
 
-	@Override
-	public int hashCode() {
-		return getDisplayName().hashCode();
-	}
+    /**
+     * Describes a step in the test-running mechanism that goes so wrong no
+     * other description can be used (for example, an exception thrown from a Runner's
+     * constructor
+     */
+    public static final Description TEST_MECHANISM = new Description(null, "Test mechanism");
 
-	@Override
-	public boolean equals(Object obj) {
-		if (!(obj instanceof Description))
-			return false;
-		Description d = (Description) obj;
-		return getDisplayName().equals(d.getDisplayName());
-	}
-	
-	@Override
-	public String toString() {
-		return getDisplayName();
-	}
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
+    private final Collection<Description> fChildren = new ConcurrentLinkedQueue<Description>();
+    private final String fDisplayName;
+    private final Serializable fUniqueId;
+    private final Annotation[] fAnnotations;
+    private volatile /* write-once */ Class<?> fTestClass;
 
-	/**
-	 * @return true if this is a description of a Runner that runs no tests
-	 */
-	public boolean isEmpty() {
-		return equals(EMPTY);
-	}
+    private Description(Class<?> clazz, String displayName, Annotation... annotations) {
+        this(clazz, displayName, displayName, annotations);
+    }
 
-	/**
-	 * @return a copy of this description, with no children (on the assumption that some of the
-	 * children will be added back)
-	 */
-	public Description childlessCopy() {
-		return new Description(fDisplayName, fAnnotations);
-	}
+    private Description(Class<?> testClass, String displayName, Serializable uniqueId, Annotation... annotations) {
+        if ((displayName == null) || (displayName.length() == 0)) {
+            throw new IllegalArgumentException(
+                    "The display name must not be empty.");
+        }
+        if ((uniqueId == null)) {
+            throw new IllegalArgumentException(
+                    "The unique id must not be null.");
+        }
+        this.fTestClass = testClass;
+        this.fDisplayName = displayName;
+        this.fUniqueId = uniqueId;
+        this.fAnnotations = annotations;
+    }
 
-	/**
-	 * @return the annotation of type annotationType that is attached to this description node, 
-	 * or null if none exists
-	 */
-	public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
-		for (Annotation each : fAnnotations)
-			if (each.annotationType().equals(annotationType))
-				return annotationType.cast(each);
-		return null;
-	}
+    /**
+     * @return a user-understandable label
+     */
+    public String getDisplayName() {
+        return fDisplayName;
+    }
 
-	/**
-	 * @return all of the annotations attached to this description node
-	 */
-	public Collection<Annotation> getAnnotations() {
-		return Arrays.asList(fAnnotations);
-	}
+    /**
+     * Add <code>Description</code> as a child of the receiver.
+     *
+     * @param description the soon-to-be child.
+     */
+    public void addChild(Description description) {
+        fChildren.add(description);
+    }
 
-	/**
-	 * @return If this describes a method invocation, 
-	 * the class of the test instance.
-	 */
-	public Class<?> getTestClass() {
-		String name= getClassName();
-		if (name == null)
-			return null;
-		try {
-			return Class.forName(name);
-		} catch (ClassNotFoundException e) {
-			return null;
-		}
-	}
+    /**
+     * Gets the copy of the children of this {@code Description}.
+     * Returns an empty list if there are no children.
+     */
+    public ArrayList<Description> getChildren() {
+        return new ArrayList<Description>(fChildren);
+    }
 
-	/**
-	 * @return If this describes a method invocation, 
-	 * the name of the class of the test instance
-	 */
-	public String getClassName() {
-		Matcher matcher= methodStringMatcher();
-		return matcher.matches()
-			? matcher.group(2)
-			: toString();
-	}
-	
-	/**
-	 * @return If this describes a method invocation, 
-	 * the name of the method (or null if not)
-	 */
-	public String getMethodName() {
-		return parseMethod();
-	}
+    /**
+     * @return <code>true</code> if the receiver is a suite
+     */
+    public boolean isSuite() {
+        return !isTest();
+    }
 
-	private String parseMethod() {
-		Matcher matcher= methodStringMatcher();
-		if (matcher.matches())
-			return matcher.group(1);
-		return null;
-	}
+    /**
+     * @return <code>true</code> if the receiver is an atomic test
+     */
+    public boolean isTest() {
+        return fChildren.isEmpty();
+    }
 
-	private Matcher methodStringMatcher() {
-		return Pattern.compile("(.*)\\((.*)\\)").matcher(toString());
-	}
+    /**
+     * @return the total number of atomic tests in the receiver
+     */
+    public int testCount() {
+        if (isTest()) {
+            return 1;
+        }
+        int result = 0;
+        for (Description child : fChildren) {
+            result += child.testCount();
+        }
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        return fUniqueId.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Description)) {
+            return false;
+        }
+        Description d = (Description) obj;
+        return fUniqueId.equals(d.fUniqueId);
+    }
+
+    @Override
+    public String toString() {
+        return getDisplayName();
+    }
+
+    /**
+     * @return true if this is a description of a Runner that runs no tests
+     */
+    public boolean isEmpty() {
+        return equals(EMPTY);
+    }
+
+    /**
+     * @return a copy of this description, with no children (on the assumption that some of the
+     *         children will be added back)
+     */
+    public Description childlessCopy() {
+        return new Description(fTestClass, fDisplayName, fAnnotations);
+    }
+
+    /**
+     * @return the annotation of type annotationType that is attached to this description node,
+     *         or null if none exists
+     */
+    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+        for (Annotation each : fAnnotations) {
+            if (each.annotationType().equals(annotationType)) {
+                return annotationType.cast(each);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return all of the annotations attached to this description node
+     */
+    public Collection<Annotation> getAnnotations() {
+        return Arrays.asList(fAnnotations);
+    }
+
+    /**
+     * @return If this describes a method invocation,
+     *         the class of the test instance.
+     */
+    public Class<?> getTestClass() {
+        if (fTestClass != null) {
+            return fTestClass;
+        }
+        String name = getClassName();
+        if (name == null) {
+            return null;
+        }
+        try {
+            fTestClass = Class.forName(name, false, getClass().getClassLoader());
+            return fTestClass;
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
+     * @return If this describes a method invocation,
+     *         the name of the class of the test instance
+     */
+    public String getClassName() {
+        return fTestClass != null ? fTestClass.getName() : methodAndClassNamePatternGroupOrDefault(2, toString());
+    }
+
+    /**
+     * @return If this describes a method invocation,
+     *         the name of the method (or null if not)
+     */
+    public String getMethodName() {
+        return methodAndClassNamePatternGroupOrDefault(1, null);
+    }
+
+    private String methodAndClassNamePatternGroupOrDefault(int group,
+            String defaultString) {
+        Matcher matcher = METHOD_AND_CLASS_NAME_PATTERN.matcher(toString());
+        return matcher.matches() ? matcher.group(group) : defaultString;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
index 92e0d07..397da19 100644
--- a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
+++ b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
@@ -166,7 +166,7 @@
 			errors.add(new Exception("No runnable methods"));
 	}
 
-	private void validateFields(List<Throwable> errors) {
+	protected void validateFields(List<Throwable> errors) {
 		RULE_VALIDATOR.validate(getTestClass(), errors);
 	}