001    package org.junit.rules;
002    
003    import static java.lang.String.format;
004    import static org.hamcrest.CoreMatchers.containsString;
005    import static org.hamcrest.CoreMatchers.instanceOf;
006    import static org.junit.Assert.assertThat;
007    import static org.junit.Assert.fail;
008    import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;
009    import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage;
010    import org.hamcrest.Matcher;
011    import org.hamcrest.StringDescription;
012    import org.junit.AssumptionViolatedException;
013    import org.junit.runners.model.Statement;
014    
015    /**
016     * The {@code ExpectedException} rule allows you to verify that your code
017     * throws a specific exception.
018     *
019     * <h3>Usage</h3>
020     *
021     * <pre> public class SimpleExpectedExceptionTest {
022     *     &#064;Rule
023     *     public ExpectedException thrown = ExpectedException.none();
024     *
025     *     &#064;Test
026     *     public void throwsNothing() {
027     *         // no exception expected, none thrown: passes.
028     *     }
029     *
030     *     &#064;Test
031     *     public void throwsExceptionWithSpecificType() {
032     *         thrown.expect(NullPointerException.class);
033     *         throw new NullPointerException();
034     *     }
035     * }</pre>
036     * 
037     * <p>You have to add the {@code ExpectedException} rule to your test.
038     * This doesn't affect your existing tests (see {@code throwsNothing()}).
039     * After specifying the type of the expected exception your test is
040     * successful when such an exception is thrown and it fails if a
041     * different or no exception is thrown.
042     *
043     * <p>This rule does not perform any special magic to make execution continue
044     * as if the exception had not been thrown. So it is nearly always a mistake
045     * for a test method to have statements after the one that is expected to
046     * throw the exception.
047     *
048     * <p>Instead of specifying the exception's type you can characterize the
049     * expected exception based on other criteria, too:
050     *
051     * <ul>
052     *   <li>The exception's message contains a specific text: {@link #expectMessage(String)}</li>
053     *   <li>The exception's message complies with a Hamcrest matcher: {@link #expectMessage(Matcher)}</li>
054     *   <li>The exception's cause complies with a Hamcrest matcher: {@link #expectCause(Matcher)}</li>
055     *   <li>The exception itself complies with a Hamcrest matcher: {@link #expect(Matcher)}</li>
056     * </ul>
057     *
058     * <p>You can combine any of the presented expect-methods. The test is
059     * successful if all specifications are met.
060     * <pre> &#064;Test
061     * public void throwsException() {
062     *     thrown.expect(NullPointerException.class);
063     *     thrown.expectMessage(&quot;happened&quot;);
064     *     throw new NullPointerException(&quot;What happened?&quot;);
065     * }</pre>
066     *
067     * <p>It is recommended to set the {@link org.junit.Rule#order() order} of the
068     * {@code ExpectedException} to {@code Integer.MAX_VALUE} if it is used together
069     * with another rule that handles exceptions, e.g. {@link ErrorCollector}.
070     * Otherwise failing tests may be successful.
071     * <pre> &#064;Rule(order = Integer.MAX_VALUE)
072     * public ExpectedException thrown = ExpectedException.none();</pre>
073     *
074     * <h3>AssumptionViolatedExceptions</h3>
075     * <p>JUnit uses {@link AssumptionViolatedException}s for indicating that a test
076     * provides no useful information. (See {@link org.junit.Assume} for more
077     * information.) You have to call {@code assume} methods before you set
078     * expectations of the {@code ExpectedException} rule. In this case the rule
079     * will not handle consume the exceptions and it can be handled by the
080     * framework. E.g. the following test is ignored by JUnit's default runner.
081     *
082     * <pre> &#064;Test
083     * public void ignoredBecauseOfFailedAssumption() {
084     *     assumeTrue(false); // throws AssumptionViolatedException
085     *     thrown.expect(NullPointerException.class);
086     * }</pre>
087     *
088     * <h3>AssertionErrors</h3>
089     *
090     * <p>JUnit uses {@link AssertionError}s for indicating that a test is failing. You
091     * have to call {@code assert} methods before you set expectations of the
092     * {@code ExpectedException} rule, if they should be handled by the framework.
093     * E.g. the following test fails because of the {@code assertTrue} statement.
094     *
095     * <pre> &#064;Test
096     * public void throwsUnhandled() {
097     *     assertTrue(false); // throws AssertionError
098     *     thrown.expect(NullPointerException.class);
099     * }</pre>
100     *
101     * <h3>Missing Exceptions</h3>
102     * <p>By default missing exceptions are reported with an error message
103     * like "Expected test to throw an instance of foo". You can configure a different
104     * message by means of {@link #reportMissingExceptionWithMessage(String)}. You
105     * can use a {@code %s} placeholder for the description of the expected
106     * exception. E.g. "Test doesn't throw %s." will fail with the error message
107     * "Test doesn't throw an instance of foo.".
108     *
109     * @since 4.7
110     */
111    public class ExpectedException implements TestRule {
112        /**
113         * Returns a {@linkplain TestRule rule} that expects no exception to
114         * be thrown (identical to behavior without this rule).
115         *
116         * @deprecated Since 4.13
117         * {@link org.junit.Assert#assertThrows(Class, org.junit.function.ThrowingRunnable)
118         * Assert.assertThrows} can be used to verify that your code throws a specific
119         * exception.
120         */
121        @Deprecated
122        public static ExpectedException none() {
123            return new ExpectedException();
124        }
125    
126        private final ExpectedExceptionMatcherBuilder matcherBuilder = new ExpectedExceptionMatcherBuilder();
127    
128        private String missingExceptionMessage= "Expected test to throw %s";
129    
130        private ExpectedException() {
131        }
132    
133        /**
134         * This method does nothing. Don't use it.
135         * @deprecated AssertionErrors are handled by default since JUnit 4.12. Just
136         *             like in JUnit &lt;= 4.10.
137         */
138        @Deprecated
139        public ExpectedException handleAssertionErrors() {
140            return this;
141        }
142    
143        /**
144         * This method does nothing. Don't use it.
145         * @deprecated AssumptionViolatedExceptions are handled by default since
146         *             JUnit 4.12. Just like in JUnit &lt;= 4.10.
147         */
148        @Deprecated
149        public ExpectedException handleAssumptionViolatedExceptions() {
150            return this;
151        }
152    
153        /**
154         * Specifies the failure message for tests that are expected to throw 
155         * an exception but do not throw any. You can use a {@code %s} placeholder for
156         * the description of the expected exception. E.g. "Test doesn't throw %s."
157         * will fail with the error message
158         * "Test doesn't throw an instance of foo.".
159         *
160         * @param message exception detail message
161         * @return the rule itself
162         */
163        public ExpectedException reportMissingExceptionWithMessage(String message) {
164            missingExceptionMessage = message;
165            return this;
166        }
167    
168        public Statement apply(Statement base,
169                org.junit.runner.Description description) {
170            return new ExpectedExceptionStatement(base);
171        }
172    
173        /**
174         * Verify that your code throws an exception that is matched by
175         * a Hamcrest matcher.
176         * <pre> &#064;Test
177         * public void throwsExceptionThatCompliesWithMatcher() {
178         *     NullPointerException e = new NullPointerException();
179         *     thrown.expect(is(e));
180         *     throw e;
181         * }</pre>
182         */
183        public void expect(Matcher<?> matcher) {
184            matcherBuilder.add(matcher);
185        }
186    
187        /**
188         * Verify that your code throws an exception that is an
189         * instance of specific {@code type}.
190         * <pre> &#064;Test
191         * public void throwsExceptionWithSpecificType() {
192         *     thrown.expect(NullPointerException.class);
193         *     throw new NullPointerException();
194         * }</pre>
195         */
196        public void expect(Class<? extends Throwable> type) {
197            expect(instanceOf(type));
198        }
199    
200        /**
201         * Verify that your code throws an exception whose message contains
202         * a specific text.
203         * <pre> &#064;Test
204         * public void throwsExceptionWhoseMessageContainsSpecificText() {
205         *     thrown.expectMessage(&quot;happened&quot;);
206         *     throw new NullPointerException(&quot;What happened?&quot;);
207         * }</pre>
208         */
209        public void expectMessage(String substring) {
210            expectMessage(containsString(substring));
211        }
212    
213        /**
214         * Verify that your code throws an exception whose message is matched 
215         * by a Hamcrest matcher.
216         * <pre> &#064;Test
217         * public void throwsExceptionWhoseMessageCompliesWithMatcher() {
218         *     thrown.expectMessage(startsWith(&quot;What&quot;));
219         *     throw new NullPointerException(&quot;What happened?&quot;);
220         * }</pre>
221         */
222        public void expectMessage(Matcher<String> matcher) {
223            expect(hasMessage(matcher));
224        }
225    
226        /**
227         * Verify that your code throws an exception whose cause is matched by 
228         * a Hamcrest matcher.
229         * <pre> &#064;Test
230         * public void throwsExceptionWhoseCauseCompliesWithMatcher() {
231         *     NullPointerException expectedCause = new NullPointerException();
232         *     thrown.expectCause(is(expectedCause));
233         *     throw new IllegalArgumentException(&quot;What happened?&quot;, cause);
234         * }</pre>
235         */
236        public void expectCause(Matcher<?> expectedCause) {
237            expect(hasCause(expectedCause));
238        }
239    
240        /**
241         * Check if any Exception is expected.
242         * @since 4.13
243         */
244        public final boolean isAnyExceptionExpected() {
245            return matcherBuilder.expectsThrowable();
246        }
247    
248        private class ExpectedExceptionStatement extends Statement {
249            private final Statement next;
250    
251            public ExpectedExceptionStatement(Statement base) {
252                next = base;
253            }
254    
255            @Override
256            public void evaluate() throws Throwable {
257                try {
258                    next.evaluate();
259                } catch (Throwable e) {
260                    handleException(e);
261                    return;
262                }
263                if (isAnyExceptionExpected()) {
264                    failDueToMissingException();
265                }
266            }
267        }
268    
269        private void handleException(Throwable e) throws Throwable {
270            if (isAnyExceptionExpected()) {
271                assertThat(e, matcherBuilder.build());
272            } else {
273                throw e;
274            }
275        }
276    
277        private void failDueToMissingException() throws AssertionError {
278            fail(missingExceptionMessage());
279        }
280        
281        private String missingExceptionMessage() {
282            String expectation= StringDescription.toString(matcherBuilder.build());
283            return format(missingExceptionMessage, expectation);
284        }
285    }