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     * @deprecated Since 4.13
110     * {@link org.junit.Assert#assertThrows(Class, org.junit.function.ThrowingRunnable)
111     * Assert.assertThrows} can be used to verify that your code throws a specific
112     * exception.
113     * @since 4.7
114     */
115    public class ExpectedException implements TestRule {
116        /**
117         * Returns a {@linkplain TestRule rule} that expects no exception to
118         * be thrown (identical to behavior without this rule).
119         */
120        public static ExpectedException none() {
121            return new ExpectedException();
122        }
123    
124        private final ExpectedExceptionMatcherBuilder matcherBuilder = new ExpectedExceptionMatcherBuilder();
125    
126        private String missingExceptionMessage= "Expected test to throw %s";
127    
128        private ExpectedException() {
129        }
130    
131        /**
132         * This method does nothing. Don't use it.
133         * @deprecated AssertionErrors are handled by default since JUnit 4.12. Just
134         *             like in JUnit &lt;= 4.10.
135         */
136        @Deprecated
137        public ExpectedException handleAssertionErrors() {
138            return this;
139        }
140    
141        /**
142         * This method does nothing. Don't use it.
143         * @deprecated AssumptionViolatedExceptions are handled by default since
144         *             JUnit 4.12. Just like in JUnit &lt;= 4.10.
145         */
146        @Deprecated
147        public ExpectedException handleAssumptionViolatedExceptions() {
148            return this;
149        }
150    
151        /**
152         * Specifies the failure message for tests that are expected to throw 
153         * an exception but do not throw any. You can use a {@code %s} placeholder for
154         * the description of the expected exception. E.g. "Test doesn't throw %s."
155         * will fail with the error message
156         * "Test doesn't throw an instance of foo.".
157         *
158         * @param message exception detail message
159         * @return the rule itself
160         */
161        public ExpectedException reportMissingExceptionWithMessage(String message) {
162            missingExceptionMessage = message;
163            return this;
164        }
165    
166        public Statement apply(Statement base,
167                org.junit.runner.Description description) {
168            return new ExpectedExceptionStatement(base);
169        }
170    
171        /**
172         * Verify that your code throws an exception that is matched by
173         * a Hamcrest matcher.
174         * <pre> &#064;Test
175         * public void throwsExceptionThatCompliesWithMatcher() {
176         *     NullPointerException e = new NullPointerException();
177         *     thrown.expect(is(e));
178         *     throw e;
179         * }</pre>
180         *
181         * @deprecated use {@code org.hamcrest.junit.ExpectedException.expect()}
182         */
183        @Deprecated
184        public void expect(Matcher<?> matcher) {
185            matcherBuilder.add(matcher);
186        }
187    
188        /**
189         * Verify that your code throws an exception that is an
190         * instance of specific {@code type}.
191         * <pre> &#064;Test
192         * public void throwsExceptionWithSpecificType() {
193         *     thrown.expect(NullPointerException.class);
194         *     throw new NullPointerException();
195         * }</pre>
196         */
197        public void expect(Class<? extends Throwable> type) {
198            expect(instanceOf(type));
199        }
200    
201        /**
202         * Verify that your code throws an exception whose message contains
203         * a specific text.
204         * <pre> &#064;Test
205         * public void throwsExceptionWhoseMessageContainsSpecificText() {
206         *     thrown.expectMessage(&quot;happened&quot;);
207         *     throw new NullPointerException(&quot;What happened?&quot;);
208         * }</pre>
209         */
210        public void expectMessage(String substring) {
211            expectMessage(containsString(substring));
212        }
213    
214        /**
215         * Verify that your code throws an exception whose message is matched 
216         * by a Hamcrest matcher.
217         * <pre> &#064;Test
218         * public void throwsExceptionWhoseMessageCompliesWithMatcher() {
219         *     thrown.expectMessage(startsWith(&quot;What&quot;));
220         *     throw new NullPointerException(&quot;What happened?&quot;);
221         * }</pre>
222         *
223         * @deprecated use {@code org.hamcrest.junit.ExpectedException.expectMessage()}
224         */
225        @Deprecated
226        public void expectMessage(Matcher<String> matcher) {
227            expect(hasMessage(matcher));
228        }
229    
230        /**
231         * Verify that your code throws an exception whose cause is matched by 
232         * a Hamcrest matcher.
233         * <pre> &#064;Test
234         * public void throwsExceptionWhoseCauseCompliesWithMatcher() {
235         *     NullPointerException expectedCause = new NullPointerException();
236         *     thrown.expectCause(is(expectedCause));
237         *     throw new IllegalArgumentException(&quot;What happened?&quot;, cause);
238         * }</pre>
239         *
240         * @deprecated use {@code org.hamcrest.junit.ExpectedException.expectCause()}
241         */
242        @Deprecated
243        public void expectCause(Matcher<?> expectedCause) {
244            expect(hasCause(expectedCause));
245        }
246    
247        /**
248         * Check if any Exception is expected.
249         * @since 4.13
250         */
251        public final boolean isAnyExceptionExpected() {
252            return matcherBuilder.expectsThrowable();
253        }
254    
255        private class ExpectedExceptionStatement extends Statement {
256            private final Statement next;
257    
258            public ExpectedExceptionStatement(Statement base) {
259                next = base;
260            }
261    
262            @Override
263            public void evaluate() throws Throwable {
264                try {
265                    next.evaluate();
266                } catch (Throwable e) {
267                    handleException(e);
268                    return;
269                }
270                if (isAnyExceptionExpected()) {
271                    failDueToMissingException();
272                }
273            }
274        }
275    
276        private void handleException(Throwable e) throws Throwable {
277            if (isAnyExceptionExpected()) {
278                assertThat(e, matcherBuilder.build());
279            } else {
280                throw e;
281            }
282        }
283    
284        private void failDueToMissingException() throws AssertionError {
285            fail(missingExceptionMessage());
286        }
287        
288        private String missingExceptionMessage() {
289            String expectation= StringDescription.toString(matcherBuilder.build());
290            return format(missingExceptionMessage, expectation);
291        }
292    }