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