Skip to content

Commit 24e0330

Browse files
committed
Imported throwable matchers from Junit for JunitMatchers
1 parent 6259034 commit 24e0330

File tree

7 files changed

+328
-0
lines changed

7 files changed

+328
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package org.junit.matchers;
2+
3+
import org.hamcrest.CoreMatchers;
4+
import org.hamcrest.Matcher;
5+
import org.hamcrest.collection.MatchIterables;
6+
import org.hamcrest.core.CombinableMatcher.CombinableBothMatcher;
7+
import org.hamcrest.core.CombinableMatcher.CombinableEitherMatcher;
8+
9+
/**
10+
* Transient import class. Copied here from JUnit 4.4 in preparation for removing Hamcrest from
11+
* JUnit dependencies.
12+
*
13+
* @deprecated
14+
* @since 3.0.0
15+
*/
16+
public class JUnitMatchers {
17+
/**
18+
* @return A matcher matching any collection containing element
19+
* @deprecated Please use {@link MatchIterables#hasItem(Object)} instead.
20+
*/
21+
@Deprecated
22+
public static <T> Matcher<Iterable<? super T>> hasItem(T element) {
23+
return MatchIterables.hasItem(element);
24+
}
25+
26+
/**
27+
* @return A matcher matching any collection containing an element matching elementMatcher
28+
* @deprecated Please use {@link MatchIterables#hasItem(Matcher)} instead.
29+
*/
30+
@Deprecated
31+
public static <T> Matcher<Iterable<? super T>> hasItem(Matcher<? super T> elementMatcher) {
32+
return MatchIterables.hasItem(elementMatcher);
33+
}
34+
35+
/**
36+
* @return A matcher matching any collection containing every element in elements
37+
* @deprecated Please use {@link MatchIterables#hasItems(Object...)} instead.
38+
*/
39+
@Deprecated
40+
public static <T> Matcher<Iterable<T>> hasItems(T... elements) {
41+
return MatchIterables.hasItems(elements);
42+
}
43+
44+
/**
45+
* @return A matcher matching any collection containing at least one element that matches
46+
* each matcher in elementMatcher (this may be one element matching all matchers,
47+
* or different elements matching each matcher)
48+
* @deprecated Please use {@link MatchIterables#hasItems(Matcher...)} instead.
49+
*/
50+
@Deprecated
51+
public static <T> Matcher<Iterable<T>> hasItems(Matcher<? super T>... elementMatchers) {
52+
return MatchIterables.hasItems(elementMatchers);
53+
}
54+
55+
/**
56+
* @return A matcher matching any collection in which every element matches elementMatcher
57+
* @deprecated Please use {@link MatchIterables#everyItem(Matcher)} instead.
58+
*/
59+
@Deprecated
60+
public static <T> Matcher<Iterable<? extends T>> everyItem(final Matcher<T> elementMatcher) {
61+
return MatchIterables.everyItem(elementMatcher);
62+
}
63+
64+
/**
65+
* @return a matcher matching any string that contains substring
66+
* @deprecated Please use {@link CoreMatchers#containsString(String)} instead.
67+
*/
68+
@Deprecated
69+
public static Matcher<String> containsString(String substring) {
70+
return CoreMatchers.containsString(substring);
71+
}
72+
73+
/**
74+
* This is useful for fluently combining matchers that must both pass. For example:
75+
* <pre>
76+
* assertThat(string, both(containsString("a")).and(containsString("b")));
77+
* </pre>
78+
*
79+
* @deprecated Please use {@link CoreMatchers#both(Matcher)} instead.
80+
*/
81+
@Deprecated
82+
public static <T> CombinableBothMatcher<T> both(Matcher<? super T> matcher) {
83+
return CoreMatchers.both(matcher);
84+
}
85+
86+
/**
87+
* This is useful for fluently combining matchers where either may pass, for example:
88+
* <pre>
89+
* assertThat(string, either(containsString("a")).or(containsString("b")));
90+
* </pre>
91+
*
92+
* @deprecated Please use {@link CoreMatchers#either(Matcher)} instead.
93+
*/
94+
@Deprecated
95+
public static <T> CombinableEitherMatcher<T> either(Matcher<? super T> matcher) {
96+
return CoreMatchers.either(matcher);
97+
}
98+
99+
/**
100+
* @return A matcher that delegates to throwableMatcher and in addition
101+
* appends the stacktrace of the actual Throwable in case of a mismatch.
102+
*/
103+
public static <T extends Throwable> Matcher<T> isThrowable(Matcher<T> throwableMatcher) {
104+
return MatchThrowables.isThrowable(throwableMatcher);
105+
}
106+
107+
/**
108+
* @return A matcher that delegates to exceptionMatcher and in addition
109+
* appends the stacktrace of the actual Exception in case of a mismatch.
110+
*/
111+
public static <T extends Exception> Matcher<T> isException(Matcher<T> exceptionMatcher) {
112+
return MatchThrowables.isException(exceptionMatcher);
113+
}
114+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.junit.matchers;
2+
3+
import org.hamcrest.Matcher;
4+
5+
/**
6+
* Matchers ported from JUnit 4
7+
* @since 3.0
8+
*/
9+
public class MatchThrowables {
10+
public static <T extends Throwable> Matcher<T> isThrowable(Matcher<T> throwableMatcher) {
11+
return new StacktracePrintingMatcher<>(throwableMatcher);
12+
}
13+
14+
public static <T extends Exception> Matcher<T> isException(Matcher<T> exceptionMatcher) {
15+
return new StacktracePrintingMatcher<>(exceptionMatcher);
16+
}
17+
18+
/**
19+
* Returns a matcher that verifies that the outer exception has a cause for which the supplied matcher
20+
* evaluates to true.
21+
*
22+
* @param matcher to apply to the cause of the outer exception
23+
* @param <T> type of the outer exception
24+
*/
25+
public static <T extends Throwable> Matcher<T> hasCause(final Matcher<? extends Throwable> matcher) {
26+
return new ThrowableCauseMatcher<>(matcher);
27+
}
28+
29+
/**
30+
* Returns a matcher that verifies that the outer exception has a message for which the supplied matcher
31+
* evaluates to true.
32+
*
33+
* @param matcher to apply to the cause of the outer exception
34+
* @param <T> type of the outer exception
35+
*/
36+
public static <T extends Throwable> Matcher<T> hasMessage(final Matcher<String> matcher) {
37+
return new ThrowableMessageMatcher<>(matcher);
38+
}
39+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.junit.matchers;
2+
3+
import org.hamcrest.Description;
4+
import org.hamcrest.Matcher;
5+
import org.hamcrest.TypeSafeMatcher;
6+
7+
import java.io.PrintWriter;
8+
import java.io.StringWriter;
9+
10+
/**
11+
* A matcher that delegates to throwableMatcher and in addition appends the
12+
* stacktrace of the actual Throwable in case of a mismatch.
13+
* @since 3.0
14+
*/
15+
public class StacktracePrintingMatcher<T extends Throwable> extends TypeSafeMatcher<T> {
16+
17+
private final Matcher<T> throwableMatcher;
18+
19+
public StacktracePrintingMatcher(Matcher<T> throwableMatcher) {
20+
this.throwableMatcher = throwableMatcher;
21+
}
22+
23+
public void describeTo(Description description) {
24+
throwableMatcher.describeTo(description);
25+
}
26+
27+
@Override
28+
protected boolean matchesSafely(T item) {
29+
return throwableMatcher.matches(item);
30+
}
31+
32+
@Override
33+
protected void describeMismatchSafely(T item, Description description) {
34+
throwableMatcher.describeMismatch(item, description);
35+
description.appendText("\nStacktrace was: ");
36+
description.appendText(readStacktrace(item));
37+
}
38+
39+
private String readStacktrace(Throwable throwable) {
40+
StringWriter stringWriter = new StringWriter();
41+
throwable.printStackTrace(new PrintWriter(stringWriter));
42+
return stringWriter.toString();
43+
}
44+
45+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.junit.matchers;
2+
3+
import org.hamcrest.Description;
4+
import org.hamcrest.Matcher;
5+
import org.hamcrest.TypeSafeMatcher;
6+
7+
/**
8+
* A matcher that applies a delegate matcher to the cause of the given Throwable
9+
*
10+
* @param <T> the type of the throwable being matched
11+
* @since 3.0
12+
*/
13+
public class ThrowableCauseMatcher<T extends Throwable> extends TypeSafeMatcher<T> {
14+
15+
private final Matcher<? extends Throwable> causeMatcher;
16+
17+
public ThrowableCauseMatcher(Matcher<? extends Throwable> causeMatcher) {
18+
this.causeMatcher = causeMatcher;
19+
}
20+
21+
public void describeTo(Description description) {
22+
description.appendText("throwable with cause ");
23+
description.appendDescriptionOf(causeMatcher);
24+
}
25+
26+
@Override
27+
protected boolean matchesSafely(T item) {
28+
return causeMatcher.matches(item.getCause());
29+
}
30+
31+
@Override
32+
protected void describeMismatchSafely(T item, Description description) {
33+
description.appendText("cause ");
34+
causeMatcher.describeMismatch(item.getCause(), description);
35+
}
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.junit.matchers;
2+
3+
import org.hamcrest.Description;
4+
import org.hamcrest.Matcher;
5+
import org.hamcrest.TypeSafeMatcher;
6+
7+
/**
8+
* A matcher that applies a delegate matcher to the message of the given Throwable
9+
*
10+
* @param <T> the type of the throwable being matched
11+
* @since 3.0
12+
*/
13+
public class ThrowableMessageMatcher<T extends Throwable> extends TypeSafeMatcher<T> {
14+
15+
private final Matcher<String> matcher;
16+
17+
public ThrowableMessageMatcher(Matcher<String> matcher) {
18+
this.matcher = matcher;
19+
}
20+
21+
public void describeTo(Description description) {
22+
description.appendText("exception with message ");
23+
description.appendDescriptionOf(matcher);
24+
}
25+
26+
@Override
27+
protected boolean matchesSafely(T item) {
28+
return matcher.matches(item.getMessage());
29+
}
30+
31+
@Override
32+
protected void describeMismatchSafely(T item, Description description) {
33+
description.appendText("message ");
34+
matcher.describeMismatch(item.getMessage(), description);
35+
}
36+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.junit.matchers;
2+
3+
import org.junit.Test;
4+
5+
import static org.hamcrest.core.StringContains.containsString;
6+
import static org.hamcrest.object.MatchObjects.*;
7+
import static org.junit.Assert.*;
8+
import static org.junit.matchers.MatchThrowables.isException;
9+
import static org.junit.matchers.MatchThrowables.isThrowable;
10+
11+
public class StacktracePrintingMatcherTest {
12+
13+
@Test
14+
public void succeedsWhenInnerMatcherSucceeds() throws Exception {
15+
assertTrue(isThrowable(any(Throwable.class)).matches(new Exception()));
16+
}
17+
18+
@Test
19+
public void failsWhenInnerMatcherFails() throws Exception {
20+
assertFalse(isException(notNullValue(Exception.class)).matches(null));
21+
}
22+
23+
@Test
24+
public void assertThatIncludesStacktrace() {
25+
Exception actual = new IllegalArgumentException("my message");
26+
Exception expected = new NullPointerException();
27+
28+
try {
29+
assertThat(actual, isThrowable(equalTo(expected)));
30+
} catch (AssertionError e) {
31+
assertThat(e.getMessage(), containsString("Stacktrace was: java.lang.IllegalArgumentException: my message"));
32+
}
33+
}
34+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.junit.matchers;
2+
3+
import org.junit.Test;
4+
5+
import static org.hamcrest.CoreMatchers.sameInstance;
6+
import static org.hamcrest.object.MatchObjects.equalTo;
7+
import static org.junit.Assert.assertThat;
8+
import static org.junit.matchers.MatchThrowables.hasCause;
9+
import static org.junit.matchers.MatchThrowables.hasMessage;
10+
11+
public class ThrowableMatchersTest {
12+
13+
@Test
14+
public void shouldAllowCauseOfDifferentClassFromRoot() throws Exception {
15+
NullPointerException expectedCause = new NullPointerException("expected");
16+
Exception actual = new Exception(expectedCause) {
17+
@Override public String getMessage() { return "the exception message"; }
18+
};
19+
20+
assertThat(actual, hasCause(sameInstance(expectedCause)));
21+
assertThat(actual, hasMessage(equalTo("the exception message")));
22+
23+
}
24+
}

0 commit comments

Comments
 (0)