diff options
Diffstat (limited to 'src/main')
13 files changed, 393 insertions, 564 deletions
diff --git a/src/main/java/org/junit/Assume.java b/src/main/java/org/junit/Assume.java index b7687f7..c96ff99 100644 --- a/src/main/java/org/junit/Assume.java +++ b/src/main/java/org/junit/Assume.java @@ -1,12 +1,12 @@ package org.junit; import static java.util.Arrays.asList; -import static org.hamcrest.CoreMatchers.everyItem; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import org.hamcrest.Matcher; +import org.junit.internal.matchers.Each; /** * A set of methods useful for stating assumptions about the conditions in which a test is meaningful. @@ -66,12 +66,13 @@ public class Assume { assumeTrue(message, !b); } - /** - * If called with one or more null elements in <code>objects</code>, the test will halt and be ignored. - */ - public static void assumeNotNull(Object... objects) { - assumeThat(asList(objects), everyItem(notNullValue())); - } + /** + * If called with one or more null elements in <code>objects</code>, the test will halt and be ignored. + * @param objects + */ + public static void assumeNotNull(Object... objects) { + assumeThat(asList(objects), Each.each(notNullValue())); + } /** * Call to assume that <code>actual</code> satisfies the condition specified by <code>matcher</code>. diff --git a/src/main/java/org/junit/internal/matchers/CombinableMatcher.java b/src/main/java/org/junit/internal/matchers/CombinableMatcher.java new file mode 100644 index 0000000..e9e6947 --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/CombinableMatcher.java @@ -0,0 +1,34 @@ +package org.junit.internal.matchers; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.anyOf; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; + +public class CombinableMatcher<T> extends BaseMatcher<T> { + + private final Matcher<? extends T> fMatcher; + + public CombinableMatcher(Matcher<? extends T> matcher) { + fMatcher= matcher; + } + + public boolean matches(Object item) { + return fMatcher.matches(item); + } + + public void describeTo(Description description) { + description.appendDescriptionOf(fMatcher); + } + + @SuppressWarnings("unchecked") + public CombinableMatcher<T> and(Matcher<? extends T> matcher) { + return new CombinableMatcher<T>(allOf(matcher, fMatcher)); + } + + @SuppressWarnings("unchecked") + public CombinableMatcher<T> or(Matcher<? extends T> matcher) { + return new CombinableMatcher<T>(anyOf(matcher, fMatcher)); + } +}
\ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/Each.java b/src/main/java/org/junit/internal/matchers/Each.java new file mode 100644 index 0000000..527db3b --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/Each.java @@ -0,0 +1,24 @@ +package org.junit.internal.matchers; + +import static org.hamcrest.CoreMatchers.not; +import static org.junit.internal.matchers.IsCollectionContaining.hasItem; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; + +public class Each { + public static <T> Matcher<Iterable<T>> each(final Matcher<T> individual) { + final Matcher<Iterable<T>> allItemsAre = not(hasItem(not(individual))); + + return new BaseMatcher<Iterable<T>>() { + public boolean matches(Object item) { + return allItemsAre.matches(item); + } + + public void describeTo(Description description) { + description.appendText("each "); + individual.describeTo(description); + } + }; + } +} diff --git a/src/main/java/org/junit/internal/matchers/IsCollectionContaining.java b/src/main/java/org/junit/internal/matchers/IsCollectionContaining.java new file mode 100644 index 0000000..4436a83 --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/IsCollectionContaining.java @@ -0,0 +1,67 @@ +package org.junit.internal.matchers; + +import static org.hamcrest.core.AllOf.allOf; +import static org.hamcrest.core.IsEqual.equalTo; + +import java.util.ArrayList; +import java.util.Collection; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +// Copied (hopefully temporarily) from hamcrest-library +public class IsCollectionContaining<T> extends TypeSafeMatcher<Iterable<T>> { + private final Matcher<? extends T> elementMatcher; + + public IsCollectionContaining(Matcher<? extends T> elementMatcher) { + this.elementMatcher = elementMatcher; + } + + @Override + public boolean matchesSafely(Iterable<T> collection) { + for (T item : collection) { + if (elementMatcher.matches(item)){ + return true; + } + } + return false; + } + + public void describeTo(Description description) { + description + .appendText("a collection containing ") + .appendDescriptionOf(elementMatcher); + } + + @Factory + public static <T> Matcher<Iterable<T>> hasItem(Matcher<? extends T> elementMatcher) { + return new IsCollectionContaining<T>(elementMatcher); + } + + @Factory + public static <T> Matcher<Iterable<T>> hasItem(T element) { + return hasItem(equalTo(element)); + } + + @Factory + public static <T> Matcher<Iterable<T>> hasItems(Matcher<? extends T>... elementMatchers) { + Collection<Matcher<? extends Iterable<T>>> all + = new ArrayList<Matcher<? extends Iterable<T>>>(elementMatchers.length); + for (Matcher<? extends T> elementMatcher : elementMatchers) { + all.add(hasItem(elementMatcher)); + } + return allOf(all); + } + + @Factory + public static <T> Matcher<Iterable<T>> hasItems(T... elements) { + Collection<Matcher<? extends Iterable<T>>> all + = new ArrayList<Matcher<? extends Iterable<T>>>(elements.length); + for (T element : elements) { + all.add(hasItem(element)); + } + return allOf(all); + } + +} diff --git a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java deleted file mode 100644 index 5d45ba3..0000000 --- a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.junit.internal.matchers; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.hamcrest.Description; -import org.hamcrest.Factory; -import org.hamcrest.Matcher; - -/** - * A matcher that delegates to throwableMatcher and in addition appends the - * stacktrace of the actual Throwable in case of a mismatch. - */ -public class StacktracePrintingMatcher<T extends Throwable> extends - org.hamcrest.TypeSafeMatcher<T> { - - private final Matcher<T> throwableMatcher; - - public StacktracePrintingMatcher(Matcher<T> throwableMatcher) { - this.throwableMatcher = throwableMatcher; - } - - public void describeTo(Description description) { - throwableMatcher.describeTo(description); - } - - @Override - protected boolean matchesSafely(T item) { - return throwableMatcher.matches(item); - } - - @Override - protected void describeMismatchSafely(T item, Description description) { - throwableMatcher.describeMismatch(item, description); - description.appendText("\nStacktrace was: "); - description.appendText(readStacktrace(item)); - } - - private String readStacktrace(Throwable throwable) { - StringWriter stringWriter = new StringWriter(); - throwable.printStackTrace(new PrintWriter(stringWriter)); - return stringWriter.toString(); - } - - @Factory - public static <T extends Throwable> Matcher<T> isThrowable( - Matcher<T> throwableMatcher) { - return new StacktracePrintingMatcher<T>(throwableMatcher); - } - - @Factory - public static <T extends Exception> Matcher<T> isException( - Matcher<T> exceptionMatcher) { - return new StacktracePrintingMatcher<T>(exceptionMatcher); - } -} diff --git a/src/main/java/org/junit/internal/matchers/StringContains.java b/src/main/java/org/junit/internal/matchers/StringContains.java new file mode 100644 index 0000000..e5f5334 --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/StringContains.java @@ -0,0 +1,31 @@ +/* Copyright (c) 2000-2006 hamcrest.org + */ +package org.junit.internal.matchers; + +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +/** + * Tests if the argument is a string that contains a substring. + */ +public class StringContains extends SubstringMatcher { + public StringContains(String substring) { + super(substring); + } + + @Override + protected boolean evalSubstringOf(String s) { + return s.indexOf(substring) >= 0; + } + + @Override + protected String relationship() { + return "containing"; + } + + @Factory + public static Matcher<String> containsString(String substring) { + return new StringContains(substring); + } + +}
\ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/SubstringMatcher.java b/src/main/java/org/junit/internal/matchers/SubstringMatcher.java new file mode 100644 index 0000000..1c65240 --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/SubstringMatcher.java @@ -0,0 +1,28 @@ +package org.junit.internal.matchers; + +import org.hamcrest.Description; + +public abstract class SubstringMatcher extends TypeSafeMatcher<String> { + + protected final String substring; + + protected SubstringMatcher(final String substring) { + this.substring = substring; + } + + @Override + public boolean matchesSafely(String item) { + return evalSubstringOf(item); + } + + public void describeTo(Description description) { + description.appendText("a string ") + .appendText(relationship()) + .appendText(" ") + .appendValue(substring); + } + + protected abstract boolean evalSubstringOf(String string); + + protected abstract String relationship(); +}
\ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java deleted file mode 100644 index 22ce8bd..0000000 --- a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.junit.internal.matchers; - -import org.hamcrest.Description; -import org.hamcrest.Factory; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -/** - * A matcher that applies a delegate matcher to the cause of the current Throwable, returning the result of that - * match. - * - * @param <T> the type of the throwable being matched - */ -public class ThrowableCauseMatcher<T extends Throwable> extends - TypeSafeMatcher<T> { - - private final Matcher<? extends Throwable> causeMatcher; - - public ThrowableCauseMatcher(Matcher<? extends Throwable> causeMatcher) { - this.causeMatcher = causeMatcher; - } - - public void describeTo(Description description) { - description.appendText("exception with cause "); - description.appendDescriptionOf(causeMatcher); - } - - @Override - protected boolean matchesSafely(T item) { - return causeMatcher.matches(item.getCause()); - } - - @Override - protected void describeMismatchSafely(T item, Description description) { - description.appendText("cause "); - causeMatcher.describeMismatch(item.getCause(), description); - } - - /** - * Returns a matcher that verifies that the outer exception has a cause for which the supplied matcher - * evaluates to true. - * - * @param matcher to apply to the cause of the outer exception - * @param <T> type of the outer exception - */ - @Factory - public static <T extends Throwable> Matcher<T> hasCause(final Matcher<? extends Throwable> matcher) { - return new ThrowableCauseMatcher<T>(matcher); - } -}
\ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java b/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java deleted file mode 100644 index 74386a8..0000000 --- a/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.junit.internal.matchers; - -import org.hamcrest.Description; -import org.hamcrest.Factory; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -public class ThrowableMessageMatcher<T extends Throwable> extends - TypeSafeMatcher<T> { - - private final Matcher<String> matcher; - - public ThrowableMessageMatcher(Matcher<String> matcher) { - this.matcher = matcher; - } - - public void describeTo(Description description) { - description.appendText("exception with message "); - description.appendDescriptionOf(matcher); - } - - @Override - protected boolean matchesSafely(T item) { - return matcher.matches(item.getMessage()); - } - - @Override - protected void describeMismatchSafely(T item, Description description) { - description.appendText("message "); - matcher.describeMismatch(item.getMessage(), description); - } - - @Factory - public static <T extends Throwable> Matcher<T> hasMessage(final Matcher<String> matcher) { - return new ThrowableMessageMatcher<T>(matcher); - } -}
\ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java index 4e2cc12..794a174 100644 --- a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java +++ b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java @@ -3,16 +3,13 @@ package org.junit.internal.matchers; import java.lang.reflect.Method; import org.hamcrest.BaseMatcher; -import org.junit.internal.MethodSorter; /** * Convenient base class for Matchers that require a non-null value of a specific type. * This simply implements the null check, checks the type and then casts. * * @author Joe Walnes - * @deprecated Please use {@link org.hamcrest.TypeSafeMatcher}. */ -@Deprecated public abstract class TypeSafeMatcher<T> extends BaseMatcher<T> { private Class<?> expectedType; @@ -26,27 +23,27 @@ public abstract class TypeSafeMatcher<T> extends BaseMatcher<T> { protected TypeSafeMatcher() { expectedType = findExpectedType(getClass()); } - + private static Class<?> findExpectedType(Class<?> fromClass) { for (Class<?> c = fromClass; c != Object.class; c = c.getSuperclass()) { - for (Method method : MethodSorter.getDeclaredMethods(c)) { + for (Method method : c.getDeclaredMethods()) { if (isMatchesSafelyMethod(method)) { return method.getParameterTypes()[0]; } } } - + throw new Error("Cannot determine correct type for matchesSafely() method."); } - + private static boolean isMatchesSafelyMethod(Method method) { - return method.getName().equals("matchesSafely") - && method.getParameterTypes().length == 1 - && !method.isSynthetic(); + return method.getName().equals("matchesSafely") + && method.getParameterTypes().length == 1 + && !method.isSynthetic(); } - + protected TypeSafeMatcher(Class<T> expectedType) { - this.expectedType = expectedType; + this.expectedType = expectedType; } /** diff --git a/src/main/java/org/junit/matchers/JUnitMatchers.java b/src/main/java/org/junit/matchers/JUnitMatchers.java index 13407cc..01b8489 100644 --- a/src/main/java/org/junit/matchers/JUnitMatchers.java +++ b/src/main/java/org/junit/matchers/JUnitMatchers.java @@ -1,113 +1,83 @@ package org.junit.matchers; -import org.hamcrest.CoreMatchers; import org.hamcrest.Matcher; -import org.hamcrest.core.CombinableMatcher.CombinableBothMatcher; -import org.hamcrest.core.CombinableMatcher.CombinableEitherMatcher; -import org.junit.internal.matchers.StacktracePrintingMatcher; +import org.junit.internal.matchers.CombinableMatcher; +import org.junit.internal.matchers.Each; +import org.junit.internal.matchers.IsCollectionContaining; +import org.junit.internal.matchers.StringContains; /** * Convenience import class: these are useful matchers for use with the assertThat method, but they are * not currently included in the basic CoreMatchers class from hamcrest. - * - * @since 4.4 */ public class JUnitMatchers { - /** - * @return A matcher matching any collection containing element - * @deprecated Please use {@link CoreMatchers#hasItem(Object)} instead. - */ - @Deprecated - public static <T> Matcher<Iterable<? super T>> hasItem(T element) { - return CoreMatchers.hasItem(element); - } + /** + * @param element + * @return A matcher matching any collection containing element + */ + public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItem(T element) { + return IsCollectionContaining.hasItem(element); + } - /** - * @return A matcher matching any collection containing an element matching elementMatcher - * @deprecated Please use {@link CoreMatchers#hasItem(Matcher)} instead. - */ - @Deprecated - public static <T> Matcher<Iterable<? super T>> hasItem(Matcher<? super T> elementMatcher) { - return CoreMatchers.<T>hasItem(elementMatcher); - } + /** + * @param elementMatcher + * @return A matcher matching any collection containing an element matching elementMatcher + */ + public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItem(org.hamcrest.Matcher<? extends T> elementMatcher) { + return IsCollectionContaining.hasItem(elementMatcher); + } - /** - * @return A matcher matching any collection containing every element in elements - * @deprecated Please use {@link CoreMatchers#hasItems(Object...)} instead. - */ - @Deprecated - public static <T> Matcher<Iterable<T>> hasItems(T... elements) { - return CoreMatchers.hasItems(elements); - } + /** + * @param elements + * @return A matcher matching any collection containing every element in elements + */ + public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItems(T... elements) { + return IsCollectionContaining.hasItems(elements); + } - /** - * @return A matcher matching any collection containing at least one element that matches - * each matcher in elementMatcher (this may be one element matching all matchers, - * or different elements matching each matcher) - * @deprecated Please use {@link CoreMatchers#hasItems(Matcher...)} instead. - */ - @Deprecated - public static <T> Matcher<Iterable<T>> hasItems(Matcher<? super T>... elementMatchers) { - return CoreMatchers.hasItems(elementMatchers); - } + /** + * @param elementMatchers + * @return A matcher matching any collection containing at least one element that matches + * each matcher in elementMatcher (this may be one element matching all matchers, + * or different elements matching each matcher) + */ + public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItems(org.hamcrest.Matcher<? extends T>... elementMatchers) { + return IsCollectionContaining.hasItems(elementMatchers); + } - /** - * @return A matcher matching any collection in which every element matches elementMatcher - * @deprecated Please use {@link CoreMatchers#everyItem(Matcher)} instead. - */ - @Deprecated - public static <T> Matcher<Iterable<T>> everyItem(final Matcher<T> elementMatcher) { - return CoreMatchers.everyItem(elementMatcher); - } + /** + * @param elementMatcher + * @return A matcher matching any collection in which every element matches elementMatcher + */ + public static <T> Matcher<Iterable<T>> everyItem(final Matcher<T> elementMatcher) { + return Each.each(elementMatcher); + } - /** - * @return a matcher matching any string that contains substring - * @deprecated Please use {@link CoreMatchers#containsString(String)} instead. - */ - @Deprecated - public static Matcher<java.lang.String> containsString(java.lang.String substring) { - return CoreMatchers.containsString(substring); - } - - /** - * This is useful for fluently combining matchers that must both pass. For example: - * <pre> - * assertThat(string, both(containsString("a")).and(containsString("b"))); - * </pre> - * - * @deprecated Please use {@link CoreMatchers#both(Matcher)} instead. - */ - @Deprecated - public static <T> CombinableBothMatcher<T> both(Matcher<? super T> matcher) { - return CoreMatchers.both(matcher); - } - - /** - * This is useful for fluently combining matchers where either may pass, for example: - * <pre> - * assertThat(string, either(containsString("a")).or(containsString("b"))); - * </pre> - * - * @deprecated Please use {@link CoreMatchers#either(Matcher)} instead. - */ - @Deprecated - public static <T> CombinableEitherMatcher<T> either(Matcher<? super T> matcher) { - return CoreMatchers.either(matcher); - } - - /** - * @return A matcher that delegates to throwableMatcher and in addition - * appends the stacktrace of the actual Throwable in case of a mismatch. - */ - public static <T extends Throwable> Matcher<T> isThrowable(Matcher<T> throwableMatcher) { - return StacktracePrintingMatcher.isThrowable(throwableMatcher); - } - - /** - * @return A matcher that delegates to exceptionMatcher and in addition - * appends the stacktrace of the actual Exception in case of a mismatch. - */ - public static <T extends Exception> Matcher<T> isException(Matcher<T> exceptionMatcher) { - return StacktracePrintingMatcher.isException(exceptionMatcher); - } + /** + * @param substring + * @return a matcher matching any string that contains substring + */ + public static org.hamcrest.Matcher<java.lang.String> containsString(java.lang.String substring) { + return StringContains.containsString(substring); + } + + /** + * This is useful for fluently combining matchers that must both pass. For example: + * <pre> + * assertThat(string, both(containsString("a")).and(containsString("b"))); + * </pre> + */ + public static <T> CombinableMatcher<T> both(Matcher<T> matcher) { + return new CombinableMatcher<T>(matcher); + } + + /** + * This is useful for fluently combining matchers where either may pass, for example: + * <pre> + * assertThat(string, either(containsString("a")).or(containsString("b"))); + * </pre> + */ + public static <T> CombinableMatcher<T> either(Matcher<T> matcher) { + return new CombinableMatcher<T>(matcher); + } } diff --git a/src/main/java/org/junit/rules/ExpectedException.java b/src/main/java/org/junit/rules/ExpectedException.java index 4d61712..bac2fba 100644 --- a/src/main/java/org/junit/rules/ExpectedException.java +++ b/src/main/java/org/junit/rules/ExpectedException.java @@ -1,270 +1,136 @@ package org.junit.rules; -import static java.lang.String.format; -import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause; -import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; - +import static org.junit.matchers.JUnitMatchers.both; +import static org.junit.matchers.JUnitMatchers.containsString; +import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.StringDescription; -import org.junit.AssumptionViolatedException; +import org.junit.Assert; +import org.junit.internal.matchers.TypeSafeMatcher; import org.junit.runners.model.Statement; /** - * The {@code ExpectedException} rule allows you to verify that your code - * throws a specific exception. - * - * <h3>Usage</h3> - * - * <pre> public class SimpleExpectedExceptionTest { - * @Rule - * public ExpectedException thrown= ExpectedException.none(); - * - * @Test - * public void throwsNothing() { - * // no exception expected, none thrown: passes. - * } - * - * @Test - * public void throwsExceptionWithSpecificType() { - * thrown.expect(NullPointerException.class); - * throw new NullPointerException(); - * } - * }</pre> + * The ExpectedException Rule allows in-test specification of expected exception + * types and messages: + * + * <pre> + * // These tests all pass. + * public static class HasExpectedException { + * @Rule + * public ExpectedException thrown= ExpectedException.none(); + * + * @Test + * public void throwsNothing() { + * // no exception expected, none thrown: passes. + * } * - * <p> - * You have to add the {@code ExpectedException} rule to your test. - * This doesn't affect your existing tests (see {@code throwsNothing()}). - * After specifiying the type of the expected exception your test is - * successful when such an exception is thrown and it fails if a - * different or no exception is thrown. - * - * <p> - * Instead of specifying the exception's type you can characterize the - * expected exception based on other criterias, too: - * - * <ul> - * <li>The exception's message contains a specific text: {@link #expectMessage(String)}</li> - * <li>The exception's message complies with a Hamcrest matcher: {@link #expectMessage(Matcher)}</li> - * <li>The exception's cause complies with a Hamcrest matcher: {@link #expectCause(Matcher)}</li> - * <li>The exception itself complies with a Hamcrest matcher: {@link #expect(Matcher)}</li> - * </ul> - * - * <p> - * You can combine any of the presented expect-methods. The test is - * successful if all specifications are met. - * <pre> @Test - * public void throwsException() { - * thrown.expect(NullPointerException.class); - * thrown.expectMessage("happened"); - * throw new NullPointerException("What happened?"); - * }</pre> - * - * <h3>AssumptionViolatedExceptions</h3> - * <p> - * JUnit uses {@link AssumptionViolatedException}s for indicating that a test - * provides no useful information. (See {@link org.junit.Assume} for more - * information.) You have to call {@code assume} methods before you set - * expectations of the {@code ExpectedException} rule. In this case the rule - * will not handle consume the exceptions and it can be handled by the - * framework. E.g. the following test is ignored by JUnit's default runner. - * - * <pre> @Test - * public void ignoredBecauseOfFailedAssumption() { - * assumeTrue(false); // throws AssumptionViolatedException - * thrown.expect(NullPointerException.class); - * }</pre> - * - * <h3>AssertionErrors</h3> - * - * <p> - * JUnit uses {@link AssertionError}s for indicating that a test is failing. You - * have to call {@code assert} methods before you set expectations of the - * {@code ExpectedException} rule, if they should be handled by the framework. - * E.g. the following test fails because of the {@code assertTrue} statement. - * - * <pre> @Test - * public void throwsUnhandled() { - * assertTrue(false); // throws AssertionError - * thrown.expect(NullPointerException.class); - * }</pre> - * - * <h3>Missing Exceptions</h3> - * <p> - * By default missing exceptions are reported with an error message - * like "Expected test to throw an instance of foo". You can configure a different - * message by means of {@link #reportMissingExceptionWithMessage(String)}. You - * can use a {@code %s} placeholder for the description of the expected - * exception. E.g. "Test doesn't throw %s." will fail with the error message - * "Test doesn't throw an instance of foo.". - * - * @since 4.7 + * @Test + * public void throwsNullPointerException() { + * thrown.expect(NullPointerException.class); + * throw new NullPointerException(); + * } + * + * @Test + * public void throwsNullPointerExceptionWithMessage() { + * thrown.expect(NullPointerException.class); + * thrown.expectMessage("happened?"); + * thrown.expectMessage(startsWith("What")); + * throw new NullPointerException("What happened?"); + * } + * } + * </pre> */ public class ExpectedException implements TestRule { - /** - * Returns a {@linkplain TestRule rule} that expects no exception to - * be thrown (identical to behavior without this rule). - */ - public static ExpectedException none() { - return new ExpectedException(); - } - - private final ExpectedExceptionMatcherBuilder matcherBuilder = new ExpectedExceptionMatcherBuilder(); - - private String missingExceptionMessage= "Expected test to throw %s"; - - private ExpectedException() { - } - - /** - * This method does nothing. Don't use it. - * @deprecated AssertionErrors are handled by default since JUnit 4.12. Just - * like in JUnit <= 4.10. - */ - @Deprecated - public ExpectedException handleAssertionErrors() { - return this; - } - - /** - * This method does nothing. Don't use it. - * @deprecated AssumptionViolatedExceptions are handled by default since - * JUnit 4.12. Just like in JUnit <= 4.10. - */ - @Deprecated - public ExpectedException handleAssumptionViolatedExceptions() { - return this; - } - - /** - * Specifies the failure message for tests that are expected to throw - * an exception but do not throw any. You can use a {@code %s} placeholder for - * the description of the expected exception. E.g. "Test doesn't throw %s." - * will fail with the error message - * "Test doesn't throw an instance of foo.". - * - * @param message exception detail message - * @return the rule itself - */ - public ExpectedException reportMissingExceptionWithMessage(String message) { - missingExceptionMessage = message; - return this; - } - - public Statement apply(Statement base, - org.junit.runner.Description description) { - return new ExpectedExceptionStatement(base); - } - - /** - * Verify that your code throws an exception that is matched by - * a Hamcrest matcher. - * <pre> @Test - * public void throwsExceptionThatCompliesWithMatcher() { - * NullPointerException e = new NullPointerException(); - * thrown.expect(is(e)); - * throw e; - * }</pre> - */ - public void expect(Matcher<?> matcher) { - matcherBuilder.add(matcher); - } - - /** - * Verify that your code throws an exception that is an - * instance of specific {@code type}. - * <pre> @Test - * public void throwsExceptionWithSpecificType() { - * thrown.expect(NullPointerException.class); - * throw new NullPointerException(); - * }</pre> - */ - public void expect(Class<? extends Throwable> type) { - expect(instanceOf(type)); - } - - /** - * Verify that your code throws an exception whose message contains - * a specific text. - * <pre> @Test - * public void throwsExceptionWhoseMessageContainsSpecificText() { - * thrown.expectMessage("happened"); - * throw new NullPointerException("What happened?"); - * }</pre> - */ - public void expectMessage(String substring) { - expectMessage(containsString(substring)); - } - - /** - * Verify that your code throws an exception whose message is matched - * by a Hamcrest matcher. - * <pre> @Test - * public void throwsExceptionWhoseMessageCompliesWithMatcher() { - * thrown.expectMessage(startsWith("What")); - * throw new NullPointerException("What happened?"); - * }</pre> - */ - public void expectMessage(Matcher<String> matcher) { - expect(hasMessage(matcher)); - } - - /** - * Verify that your code throws an exception whose cause is matched by - * a Hamcrest matcher. - * <pre> @Test - * public void throwsExceptionWhoseCauseCompliesWithMatcher() { - * NullPointerException expectedCause = new NullPointerException(); - * thrown.expectCause(is(expectedCause)); - * throw new IllegalArgumentException("What happened?", cause); - * }</pre> - */ - public void expectCause(Matcher<? extends Throwable> expectedCause) { - expect(hasCause(expectedCause)); - } - - private class ExpectedExceptionStatement extends Statement { - private final Statement next; - - public ExpectedExceptionStatement(Statement base) { - next = base; - } - - @Override - public void evaluate() throws Throwable { - try { - next.evaluate(); - } catch (Throwable e) { - handleException(e); - return; - } - if (isAnyExceptionExpected()) { - failDueToMissingException(); - } - } - } - - private void handleException(Throwable e) throws Throwable { - if (isAnyExceptionExpected()) { - assertThat(e, matcherBuilder.build()); - } else { - throw e; - } - } - - private boolean isAnyExceptionExpected() { - return matcherBuilder.expectsThrowable(); - } - - private void failDueToMissingException() throws AssertionError { - fail(missingExceptionMessage()); - } - - private String missingExceptionMessage() { - String expectation= StringDescription.toString(matcherBuilder.build()); - return format(missingExceptionMessage, expectation); - } + /** + * @return a Rule that expects no exception to be thrown + * (identical to behavior without this Rule) + */ + public static ExpectedException none() { + return new ExpectedException(); + } + + private Matcher<Object> fMatcher= null; + + private ExpectedException() { + + } + + public Statement apply(Statement base, + org.junit.runner.Description description) { + return new ExpectedExceptionStatement(base); + } + + /** + * Adds {@code matcher} to the list of requirements for any thrown exception. + */ + // Should be able to remove this suppression in some brave new hamcrest world. + @SuppressWarnings("unchecked") + public void expect(Matcher<?> matcher) { + if (fMatcher == null) + fMatcher= (Matcher<Object>) matcher; + else + fMatcher= both(fMatcher).and(matcher); + } + + /** + * Adds to the list of requirements for any thrown exception that it + * should be an instance of {@code type} + */ + public void expect(Class<? extends Throwable> type) { + expect(instanceOf(type)); + } + + /** + * Adds to the list of requirements for any thrown exception that it + * should <em>contain</em> string {@code substring} + */ + public void expectMessage(String substring) { + expectMessage(containsString(substring)); + } + + /** + * Adds {@code matcher} to the list of requirements for the message + * returned from any thrown exception. + */ + public void expectMessage(Matcher<String> matcher) { + expect(hasMessage(matcher)); + } + + private class ExpectedExceptionStatement extends Statement { + private final Statement fNext; + + public ExpectedExceptionStatement(Statement base) { + fNext= base; + } + + @Override + public void evaluate() throws Throwable { + try { + fNext.evaluate(); + } catch (Throwable e) { + if (fMatcher == null) + throw e; + Assert.assertThat(e, fMatcher); + return; + } + if (fMatcher != null) + throw new AssertionError("Expected test to throw " + + StringDescription.toString(fMatcher)); + } + } + + private Matcher<Throwable> hasMessage(final Matcher<String> matcher) { + return new TypeSafeMatcher<Throwable>() { + public void describeTo(Description description) { + description.appendText("exception with message "); + description.appendDescriptionOf(matcher); + } + + @Override + public boolean matchesSafely(Throwable item) { + return matcher.matches(item.getMessage()); + } + }; + } } diff --git a/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java b/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java deleted file mode 100644 index e7d94c4..0000000 --- a/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.junit.rules; - -import static org.hamcrest.CoreMatchers.allOf; -import static org.junit.matchers.JUnitMatchers.isThrowable; - -import java.util.ArrayList; -import java.util.List; - -import org.hamcrest.Matcher; - -/** - * Builds special matcher used by {@link ExpectedException}. - */ -class ExpectedExceptionMatcherBuilder { - - private final List<Matcher<?>> matchers = new ArrayList<Matcher<?>>(); - - void add(Matcher<?> matcher) { - matchers.add(matcher); - } - - boolean expectsThrowable() { - return !matchers.isEmpty(); - } - - Matcher<Throwable> build() { - return isThrowable(allOfTheMatchers()); - } - - private Matcher<Throwable> allOfTheMatchers() { - if (matchers.size() == 1) { - return cast(matchers.get(0)); - } - return allOf(castedMatchers()); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private List<Matcher<? super Throwable>> castedMatchers() { - return new ArrayList<Matcher<? super Throwable>>((List) matchers); - } - - @SuppressWarnings("unchecked") - private Matcher<Throwable> cast(Matcher<?> singleMatcher) { - return (Matcher<Throwable>) singleMatcher; - } -} |