1b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpackage org.junit.rules;
2b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
3b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport static org.hamcrest.CoreMatchers.instanceOf;
4b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport static org.junit.matchers.JUnitMatchers.both;
5b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport static org.junit.matchers.JUnitMatchers.containsString;
6b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.hamcrest.Description;
7b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.hamcrest.Matcher;
8b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.hamcrest.StringDescription;
9b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.Assert;
10b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.internal.matchers.TypeSafeMatcher;
11b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.runners.model.Statement;
12b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
13b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot/**
14b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * The ExpectedException Rule allows in-test specification of expected exception
15b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * types and messages:
16b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot *
17b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * <pre>
18b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * // These tests all pass.
19b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * public static class HasExpectedException {
20b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	&#064;Rule
21b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	public ExpectedException thrown= ExpectedException.none();
22b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot *
23b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	&#064;Test
24b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	public void throwsNothing() {
25b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot *    // no exception expected, none thrown: passes.
26b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	}
27b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot *
28b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	&#064;Test
29b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	public void throwsNullPointerException() {
30b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 		thrown.expect(NullPointerException.class);
31b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 		throw new NullPointerException();
32b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	}
33b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot *
34b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	&#064;Test
35b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	public void throwsNullPointerExceptionWithMessage() {
36b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 		thrown.expect(NullPointerException.class);
37b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 		thrown.expectMessage(&quot;happened?&quot;);
38b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 		thrown.expectMessage(startsWith(&quot;What&quot;));
39b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 		throw new NullPointerException(&quot;What happened?&quot;);
40b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 	}
41b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * }
42b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * </pre>
43b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */
44b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpublic class ExpectedException implements TestRule {
45b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	/**
46b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * @return a Rule that expects no exception to be thrown
47b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * (identical to behavior without this Rule)
48b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 */
49b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public static ExpectedException none() {
50b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return new ExpectedException();
51b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
52b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
53b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private Matcher<Object> fMatcher= null;
54b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
55b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private ExpectedException() {
56b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
57b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
58b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
59b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public Statement apply(Statement base,
60b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			org.junit.runner.Description description) {
61b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return new ExpectedExceptionStatement(base);
62b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
63b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
64b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	/**
65b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * Adds {@code matcher} to the list of requirements for any thrown exception.
66b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 */
67b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	// Should be able to remove this suppression in some brave new hamcrest world.
68b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	@SuppressWarnings("unchecked")
69b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public void expect(Matcher<?> matcher) {
70b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		if (fMatcher == null)
71b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			fMatcher= (Matcher<Object>) matcher;
72b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		else
73b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			fMatcher= both(fMatcher).and(matcher);
74b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
75b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
76b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	/**
77b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * Adds to the list of requirements for any thrown exception that it
78b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * should be an instance of {@code type}
79b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 */
80b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public void expect(Class<? extends Throwable> type) {
81b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		expect(instanceOf(type));
82b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
83b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
84b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	/**
85b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * Adds to the list of requirements for any thrown exception that it
86b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * should <em>contain</em> string {@code substring}
87b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 */
88b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public void expectMessage(String substring) {
89b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		expectMessage(containsString(substring));
90b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
91b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
92b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	/**
93b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * Adds {@code matcher} to the list of requirements for the message
94b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * returned from any thrown exception.
95b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 */
96b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public void expectMessage(Matcher<String> matcher) {
97b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		expect(hasMessage(matcher));
98b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
99b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
100b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private class ExpectedExceptionStatement extends Statement {
101b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		private final Statement fNext;
102b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
103b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		public ExpectedExceptionStatement(Statement base) {
104b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			fNext= base;
105b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
106b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
107b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		@Override
108b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		public void evaluate() throws Throwable {
109b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			try {
110b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				fNext.evaluate();
111b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			} catch (Throwable e) {
112b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				if (fMatcher == null)
113b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot					throw e;
114b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				Assert.assertThat(e, fMatcher);
115b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				return;
116b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			}
117b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			if (fMatcher != null)
118b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				throw new AssertionError("Expected test to throw "
119b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot						+ StringDescription.toString(fMatcher));
120b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
121b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
122b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
123b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private Matcher<Throwable> hasMessage(final Matcher<String> matcher) {
124b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return new TypeSafeMatcher<Throwable>() {
125b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			public void describeTo(Description description) {
126b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				description.appendText("exception with message ");
127b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				description.appendDescriptionOf(matcher);
128b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			}
129b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
130b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			@Override
131b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			public boolean matchesSafely(Throwable item) {
132b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				return matcher.matches(item.getMessage());
133b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			}
134b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		};
135b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
136b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot}
137