Permalink
Browse files

Custom matcher for ExpectedException (refactoring)

ExpectedExceptionMatcher now collects all the matchers and internally
provides custom matchers for checking the message and the cause of an
exception.
  • Loading branch information...
1 parent a68b42c commit 23793cd92c4c0f8449e2edaec745437c5ebbd619 @marcphilipp marcphilipp committed Jul 19, 2012
@@ -1,13 +1,10 @@
package org.junit.rules;
-import static org.hamcrest.CoreMatchers.both;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertThat;
-import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
-import org.hamcrest.TypeSafeMatcher;
import org.junit.internal.AssumptionViolatedException;
import org.junit.runners.model.Statement;
@@ -89,7 +86,7 @@ public static ExpectedException none() {
return new ExpectedException();
}
- private Matcher<Object> fMatcher= null;
+ private final ExpectedExceptionMatcher fMatcher= new ExpectedExceptionMatcher();
private boolean handleAssumptionViolatedExceptions= false;
@@ -117,14 +114,8 @@ public Statement apply(Statement 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<Object>) matcher);
+ fMatcher.and(matcher);
}
/**
@@ -148,15 +139,15 @@ public void expectMessage(String substring) {
* from any thrown exception.
*/
public void expectMessage(Matcher<String> matcher) {
- expect(hasMessage(matcher));
+ fMatcher.andHasMessage(matcher);
}
/**
* Adds {@code matcher} to the list of requirements for the cause of
* any thrown exception.
*/
public void expectCause(Matcher<? extends Throwable> expectedCause) {
- expect(hasCause(expectedCause));
+ fMatcher.andHasCause(expectedCause);
}
private class ExpectedExceptionStatement extends Statement {
@@ -180,7 +171,7 @@ public void evaluate() throws Throwable {
handleException(e);
return;
}
- if (fMatcher != null)
+ if (fMatcher.expectsThrowable())
throw new AssertionError("Expected test to throw "
+ StringDescription.toString(fMatcher));
}
@@ -195,36 +186,9 @@ private void optionallyHandleException(Throwable e, boolean handleException)
}
private void handleException(Throwable e) throws Throwable {
- if (fMatcher == null)
+ if (fMatcher.expectsThrowable())
+ assertThat(e, fMatcher);
+ else
throw e;
- assertThat(e, 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());
- }
- };
- }
-
- private Matcher<Throwable> hasCause(final Matcher<? extends Throwable> causeMatcher) {
- return new TypeSafeMatcher<Throwable>() {
- public void describeTo(Description description) {
- description.appendText("exception with cause ");
- description.appendDescriptionOf(causeMatcher);
- }
-
- @Override
- public boolean matchesSafely(Throwable item) {
- return causeMatcher.matches(item.getCause());
- }
- };
}
}
@@ -0,0 +1,92 @@
+package org.junit.rules;
+
+import static org.hamcrest.CoreMatchers.allOf;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Special matcher used by {@link ExpectedException}.
+ */
+class ExpectedExceptionMatcher extends TypeSafeMatcher<Throwable> {
+
+ private final List<Matcher<?>> fMatchers = new ArrayList<Matcher<?>>();
+ private Matcher<?> fCompositeMatcher;
+
+ void and(Matcher<?> matcher) {
+ fMatchers.add(matcher);
+ fCompositeMatcher= createCompositeMatcher();
+ }
+
+ void andHasMessage(Matcher<String> matcher) {
+ and(hasMessage(matcher));
+ }
+
+ void andHasCause(Matcher<? extends Throwable> causeMatcher) {
+ and(hasCause(causeMatcher));
+ }
+
+ boolean expectsThrowable() {
+ return !fMatchers.isEmpty();
+ }
+
+ @Override
+ protected boolean matchesSafely(Throwable item) {
+ return fCompositeMatcher.matches(item);
+ }
+
+ public void describeTo(Description description) {
+ fCompositeMatcher.describeTo(description);
+ }
+
+ private Matcher<?> createCompositeMatcher() {
+ if (fMatchers.size() == 1) {
+ return fMatchers.get(0);
+ }
+ return allOf(castedMatchers());
+ }
+
+ // Should be able to remove this suppression in some brave new hamcrest
+ // world.
+ @SuppressWarnings("unchecked")
+ private List<Matcher<? super Object>> castedMatchers() {
+ List<Matcher<? super Object>> castedMatchers = new LinkedList<Matcher<? super Object>>();
+ for (Matcher<?> matcher : fMatchers) {
+ castedMatchers.add((Matcher<? super Object>) matcher);
+ }
+ return castedMatchers;
+ }
+
+ 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());
+ }
+ };
+ }
+
+ private Matcher<Throwable> hasCause(final Matcher<? extends Throwable> causeMatcher) {
+ return new TypeSafeMatcher<Throwable>() {
+ public void describeTo(Description description) {
+ description.appendText("exception with cause ");
+ description.appendDescriptionOf(causeMatcher);
+ }
+
+ @Override
+ public boolean matchesSafely(Throwable item) {
+ return causeMatcher.matches(item.getCause());
+ }
+ };
+ }
+}

0 comments on commit 23793cd

Please sign in to comment.