aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/junit/rules
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/junit/rules')
-rw-r--r--src/main/java/org/junit/rules/DisableOnDebug.java127
-rw-r--r--src/main/java/org/junit/rules/ErrorCollector.java113
-rw-r--r--src/main/java/org/junit/rules/ExpectedException.java382
-rw-r--r--src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java46
-rw-r--r--src/main/java/org/junit/rules/ExternalResource.java101
-rw-r--r--src/main/java/org/junit/rules/MethodRule.java32
-rw-r--r--src/main/java/org/junit/rules/RuleChain.java112
-rw-r--r--src/main/java/org/junit/rules/RunRules.java33
-rw-r--r--src/main/java/org/junit/rules/Stopwatch.java183
-rw-r--r--src/main/java/org/junit/rules/TemporaryFolder.java253
-rw-r--r--src/main/java/org/junit/rules/TestName.java50
-rw-r--r--src/main/java/org/junit/rules/TestRule.java36
-rw-r--r--src/main/java/org/junit/rules/TestWatcher.java228
-rw-r--r--src/main/java/org/junit/rules/TestWatchman.java145
-rw-r--r--src/main/java/org/junit/rules/Timeout.java256
-rw-r--r--src/main/java/org/junit/rules/Verifier.java44
16 files changed, 1474 insertions, 667 deletions
diff --git a/src/main/java/org/junit/rules/DisableOnDebug.java b/src/main/java/org/junit/rules/DisableOnDebug.java
new file mode 100644
index 0000000..afa6dee
--- /dev/null
+++ b/src/main/java/org/junit/rules/DisableOnDebug.java
@@ -0,0 +1,127 @@
+package org.junit.rules;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * The {@code DisableOnDebug} Rule allows you to label certain rules to be
+ * disabled when debugging.
+ * <p>
+ * The most illustrative use case is for tests that make use of the
+ * {@link Timeout} rule, when ran in debug mode the test may terminate on
+ * timeout abruptly during debugging. Developers may disable the timeout, or
+ * increase the timeout by making a code change on tests that need debugging and
+ * remember revert the change afterwards or rules such as {@link Timeout} that
+ * may be disabled during debugging may be wrapped in a {@code DisableOnDebug}.
+ * <p>
+ * The important benefit of this feature is that you can disable such rules
+ * without any making any modifications to your test class to remove them during
+ * debugging.
+ * <p>
+ * This does nothing to tackle timeouts or time sensitive code under test when
+ * debugging and may make this less useful in such circumstances.
+ * <p>
+ * Example usage:
+ *
+ * <pre>
+ * public static class DisableTimeoutOnDebugSampleTest {
+ *
+ * &#064;Rule
+ * public TestRule timeout = new DisableOnDebug(new Timeout(20));
+ *
+ * &#064;Test
+ * public void myTest() {
+ * int i = 0;
+ * assertEquals(0, i); // suppose you had a break point here to inspect i
+ * }
+ * }
+ * </pre>
+ *
+ * @since 4.12
+ */
+public class DisableOnDebug implements TestRule {
+ private final TestRule rule;
+ private final boolean debugging;
+
+ /**
+ * Create a {@code DisableOnDebug} instance with the timeout specified in
+ * milliseconds.
+ *
+ * @param rule to disable during debugging
+ */
+ public DisableOnDebug(TestRule rule) {
+ this(rule, ManagementFactory.getRuntimeMXBean()
+ .getInputArguments());
+ }
+
+ /**
+ * Visible for testing purposes only.
+ *
+ * @param rule the rule to disable during debugging
+ * @param inputArguments
+ * arguments provided to the Java runtime
+ */
+ DisableOnDebug(TestRule rule, List<String> inputArguments) {
+ this.rule = rule;
+ debugging = isDebugging(inputArguments);
+ }
+
+ /**
+ * @see TestRule#apply(Statement, Description)
+ */
+ public Statement apply(Statement base, Description description) {
+ if (debugging) {
+ return base;
+ } else {
+ return rule.apply(base, description);
+ }
+ }
+
+ /**
+ * Parses arguments passed to the runtime environment for debug flags
+ * <p>
+ * Options specified in:
+ * <ul>
+ * <li>
+ * <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/conninv.html#Invocation"
+ * >javase-6</a></li>
+ * <li><a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/conninv.html#Invocation"
+ * >javase-7</a></li>
+ * <li><a href="http://docs.oracle.com/javase/8/docs/technotes/guides/jpda/conninv.html#Invocation"
+ * >javase-8</a></li>
+ *
+ *
+ * @param arguments
+ * the arguments passed to the runtime environment, usually this
+ * will be {@link RuntimeMXBean#getInputArguments()}
+ * @return true if the current JVM was started in debug mode, false
+ * otherwise.
+ */
+ private static boolean isDebugging(List<String> arguments) {
+ for (final String argument : arguments) {
+ if ("-Xdebug".equals(argument)) {
+ return true;
+ } else if (argument.startsWith("-agentlib:jdwp")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if the JVM is in debug mode. This method may be used
+ * by test classes to take additional action to disable code paths that
+ * interfere with debugging if required.
+ *
+ * @return {@code true} if the current JVM is in debug mode, {@code false}
+ * otherwise
+ */
+ public boolean isDebugging() {
+ return debugging;
+ }
+
+}
diff --git a/src/main/java/org/junit/rules/ErrorCollector.java b/src/main/java/org/junit/rules/ErrorCollector.java
index 3522a65..8c6600e 100644
--- a/src/main/java/org/junit/rules/ErrorCollector.java
+++ b/src/main/java/org/junit/rules/ErrorCollector.java
@@ -1,6 +1,3 @@
-/**
- *
- */
package org.junit.rules;
import static org.junit.Assert.assertThat;
@@ -16,70 +13,72 @@ import org.junit.runners.model.MultipleFailureException;
* The ErrorCollector rule allows execution of a test to continue after the
* first problem is found (for example, to collect _all_ the incorrect rows in a
* table, and report them all at once):
- *
+ *
* <pre>
* public static class UsesErrorCollectorTwice {
* &#064;Rule
* public ErrorCollector collector= new ErrorCollector();
- *
- * &#064;Test
- * public void example() {
- * collector.addError(new Throwable(&quot;first thing went wrong&quot;));
- * collector.addError(new Throwable(&quot;second thing went wrong&quot;));
- * collector.checkThat(getResult(), not(containsString(&quot;ERROR!&quot;)));
- * // all lines will run, and then a combined failure logged at the end.
- * }
+ *
+ * &#064;Test
+ * public void example() {
+ * collector.addError(new Throwable(&quot;first thing went wrong&quot;));
+ * collector.addError(new Throwable(&quot;second thing went wrong&quot;));
+ * collector.checkThat(getResult(), not(containsString(&quot;ERROR!&quot;)));
+ * // all lines will run, and then a combined failure logged at the end.
+ * }
* }
* </pre>
+ *
+ * @since 4.7
*/
public class ErrorCollector extends Verifier {
- private List<Throwable> errors= new ArrayList<Throwable>();
+ private List<Throwable> errors = new ArrayList<Throwable>();
- @Override
- protected void verify() throws Throwable {
- MultipleFailureException.assertEmpty(errors);
- }
+ @Override
+ protected void verify() throws Throwable {
+ MultipleFailureException.assertEmpty(errors);
+ }
- /**
- * Adds a Throwable to the table. Execution continues, but the test will fail at the end.
- */
- public void addError(Throwable error) {
- errors.add(error);
- }
+ /**
+ * Adds a Throwable to the table. Execution continues, but the test will fail at the end.
+ */
+ public void addError(Throwable error) {
+ errors.add(error);
+ }
- /**
- * Adds a failure to the table if {@code matcher} does not match {@code value}.
- * Execution continues, but the test will fail at the end if the match fails.
- */
- public <T> void checkThat(final T value, final Matcher<T> matcher) {
- checkThat("", value, matcher);
- }
+ /**
+ * Adds a failure to the table if {@code matcher} does not match {@code value}.
+ * Execution continues, but the test will fail at the end if the match fails.
+ */
+ public <T> void checkThat(final T value, final Matcher<T> matcher) {
+ checkThat("", value, matcher);
+ }
- /**
- * Adds a failure with the given {@code reason}
- * to the table if {@code matcher} does not match {@code value}.
- * Execution continues, but the test will fail at the end if the match fails.
- */
- public <T> void checkThat(final String reason, final T value, final Matcher<T> matcher) {
- checkSucceeds(new Callable<Object>() {
- public Object call() throws Exception {
- assertThat(reason, value, matcher);
- return value;
- }
- });
- }
+ /**
+ * Adds a failure with the given {@code reason}
+ * to the table if {@code matcher} does not match {@code value}.
+ * Execution continues, but the test will fail at the end if the match fails.
+ */
+ public <T> void checkThat(final String reason, final T value, final Matcher<T> matcher) {
+ checkSucceeds(new Callable<Object>() {
+ public Object call() throws Exception {
+ assertThat(reason, value, matcher);
+ return value;
+ }
+ });
+ }
- /**
- * Adds to the table the exception, if any, thrown from {@code callable}.
- * Execution continues, but the test will fail at the end if
- * {@code callable} threw an exception.
- */
- public Object checkSucceeds(Callable<Object> callable) {
- try {
- return callable.call();
- } catch (Throwable e) {
- addError(e);
- return null;
- }
- }
-} \ No newline at end of file
+ /**
+ * Adds to the table the exception, if any, thrown from {@code callable}.
+ * Execution continues, but the test will fail at the end if
+ * {@code callable} threw an exception.
+ */
+ public <T> T checkSucceeds(Callable<T> callable) {
+ try {
+ return callable.call();
+ } catch (Throwable e) {
+ addError(e);
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/org/junit/rules/ExpectedException.java b/src/main/java/org/junit/rules/ExpectedException.java
index bac2fba..4d61712 100644
--- a/src/main/java/org/junit/rules/ExpectedException.java
+++ b/src/main/java/org/junit/rules/ExpectedException.java
@@ -1,136 +1,270 @@
package org.junit.rules;
+import static java.lang.String.format;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.junit.matchers.JUnitMatchers.both;
-import static org.junit.matchers.JUnitMatchers.containsString;
-import org.hamcrest.Description;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;
+import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage;
+
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
-import org.junit.Assert;
-import org.junit.internal.matchers.TypeSafeMatcher;
+import org.junit.AssumptionViolatedException;
import org.junit.runners.model.Statement;
/**
- * The ExpectedException Rule allows in-test specification of expected exception
- * types and messages:
- *
- * <pre>
- * // These tests all pass.
- * public static class HasExpectedException {
- * &#064;Rule
- * public ExpectedException thrown= ExpectedException.none();
- *
- * &#064;Test
- * public void throwsNothing() {
- * // no exception expected, none thrown: passes.
- * }
+ * The {@code ExpectedException} rule allows you to verify that your code
+ * throws a specific exception.
+ *
+ * <h3>Usage</h3>
+ *
+ * <pre> public class SimpleExpectedExceptionTest {
+ * &#064;Rule
+ * public ExpectedException thrown= ExpectedException.none();
+ *
+ * &#064;Test
+ * public void throwsNothing() {
+ * // no exception expected, none thrown: passes.
+ * }
+ *
+ * &#064;Test
+ * public void throwsExceptionWithSpecificType() {
+ * thrown.expect(NullPointerException.class);
+ * throw new NullPointerException();
+ * }
+ * }</pre>
*
- * &#064;Test
- * public void throwsNullPointerException() {
- * thrown.expect(NullPointerException.class);
- * throw new NullPointerException();
- * }
- *
- * &#064;Test
- * public void throwsNullPointerExceptionWithMessage() {
- * thrown.expect(NullPointerException.class);
- * thrown.expectMessage(&quot;happened?&quot;);
- * thrown.expectMessage(startsWith(&quot;What&quot;));
- * throw new NullPointerException(&quot;What happened?&quot;);
- * }
- * }
- * </pre>
+ * <p>
+ * You have to add the {@code ExpectedException} rule to your test.
+ * This doesn't affect your existing tests (see {@code throwsNothing()}).
+ * After specifiying the type of the expected exception your test is
+ * successful when such an exception is thrown and it fails if a
+ * different or no exception is thrown.
+ *
+ * <p>
+ * Instead of specifying the exception's type you can characterize the
+ * expected exception based on other criterias, too:
+ *
+ * <ul>
+ * <li>The exception's message contains a specific text: {@link #expectMessage(String)}</li>
+ * <li>The exception's message complies with a Hamcrest matcher: {@link #expectMessage(Matcher)}</li>
+ * <li>The exception's cause complies with a Hamcrest matcher: {@link #expectCause(Matcher)}</li>
+ * <li>The exception itself complies with a Hamcrest matcher: {@link #expect(Matcher)}</li>
+ * </ul>
+ *
+ * <p>
+ * You can combine any of the presented expect-methods. The test is
+ * successful if all specifications are met.
+ * <pre> &#064;Test
+ * public void throwsException() {
+ * thrown.expect(NullPointerException.class);
+ * thrown.expectMessage(&quot;happened&quot;);
+ * throw new NullPointerException(&quot;What happened?&quot;);
+ * }</pre>
+ *
+ * <h3>AssumptionViolatedExceptions</h3>
+ * <p>
+ * JUnit uses {@link AssumptionViolatedException}s for indicating that a test
+ * provides no useful information. (See {@link org.junit.Assume} for more
+ * information.) You have to call {@code assume} methods before you set
+ * expectations of the {@code ExpectedException} rule. In this case the rule
+ * will not handle consume the exceptions and it can be handled by the
+ * framework. E.g. the following test is ignored by JUnit's default runner.
+ *
+ * <pre> &#064;Test
+ * public void ignoredBecauseOfFailedAssumption() {
+ * assumeTrue(false); // throws AssumptionViolatedException
+ * thrown.expect(NullPointerException.class);
+ * }</pre>
+ *
+ * <h3>AssertionErrors</h3>
+ *
+ * <p>
+ * JUnit uses {@link AssertionError}s for indicating that a test is failing. You
+ * have to call {@code assert} methods before you set expectations of the
+ * {@code ExpectedException} rule, if they should be handled by the framework.
+ * E.g. the following test fails because of the {@code assertTrue} statement.
+ *
+ * <pre> &#064;Test
+ * public void throwsUnhandled() {
+ * assertTrue(false); // throws AssertionError
+ * thrown.expect(NullPointerException.class);
+ * }</pre>
+ *
+ * <h3>Missing Exceptions</h3>
+ * <p>
+ * By default missing exceptions are reported with an error message
+ * like "Expected test to throw an instance of foo". You can configure a different
+ * message by means of {@link #reportMissingExceptionWithMessage(String)}. You
+ * can use a {@code %s} placeholder for the description of the expected
+ * exception. E.g. "Test doesn't throw %s." will fail with the error message
+ * "Test doesn't throw an instance of foo.".
+ *
+ * @since 4.7
*/
public class ExpectedException implements TestRule {
- /**
- * @return a Rule that expects no exception to be thrown
- * (identical to behavior without this Rule)
- */
- public static ExpectedException none() {
- return new ExpectedException();
- }
-
- private Matcher<Object> fMatcher= null;
-
- private ExpectedException() {
-
- }
-
- public Statement apply(Statement base,
- org.junit.runner.Description description) {
- return new ExpectedExceptionStatement(base);
- }
-
- /**
- * Adds {@code matcher} to the list of requirements for any thrown exception.
- */
- // Should be able to remove this suppression in some brave new hamcrest world.
- @SuppressWarnings("unchecked")
- public void expect(Matcher<?> matcher) {
- if (fMatcher == null)
- fMatcher= (Matcher<Object>) matcher;
- else
- fMatcher= both(fMatcher).and(matcher);
- }
-
- /**
- * Adds to the list of requirements for any thrown exception that it
- * should be an instance of {@code type}
- */
- public void expect(Class<? extends Throwable> type) {
- expect(instanceOf(type));
- }
-
- /**
- * Adds to the list of requirements for any thrown exception that it
- * should <em>contain</em> string {@code substring}
- */
- public void expectMessage(String substring) {
- expectMessage(containsString(substring));
- }
-
- /**
- * Adds {@code matcher} to the list of requirements for the message
- * returned from any thrown exception.
- */
- public void expectMessage(Matcher<String> matcher) {
- expect(hasMessage(matcher));
- }
-
- private class ExpectedExceptionStatement extends Statement {
- private final Statement fNext;
-
- public ExpectedExceptionStatement(Statement base) {
- fNext= base;
- }
-
- @Override
- public void evaluate() throws Throwable {
- try {
- fNext.evaluate();
- } catch (Throwable e) {
- if (fMatcher == null)
- throw e;
- Assert.assertThat(e, fMatcher);
- return;
- }
- if (fMatcher != null)
- throw new AssertionError("Expected test to throw "
- + StringDescription.toString(fMatcher));
- }
- }
-
- private Matcher<Throwable> hasMessage(final Matcher<String> matcher) {
- return new TypeSafeMatcher<Throwable>() {
- public void describeTo(Description description) {
- description.appendText("exception with message ");
- description.appendDescriptionOf(matcher);
- }
-
- @Override
- public boolean matchesSafely(Throwable item) {
- return matcher.matches(item.getMessage());
- }
- };
- }
+ /**
+ * Returns a {@linkplain TestRule rule} that expects no exception to
+ * be thrown (identical to behavior without this rule).
+ */
+ public static ExpectedException none() {
+ return new ExpectedException();
+ }
+
+ private final ExpectedExceptionMatcherBuilder matcherBuilder = new ExpectedExceptionMatcherBuilder();
+
+ private String missingExceptionMessage= "Expected test to throw %s";
+
+ private ExpectedException() {
+ }
+
+ /**
+ * This method does nothing. Don't use it.
+ * @deprecated AssertionErrors are handled by default since JUnit 4.12. Just
+ * like in JUnit &lt;= 4.10.
+ */
+ @Deprecated
+ public ExpectedException handleAssertionErrors() {
+ return this;
+ }
+
+ /**
+ * This method does nothing. Don't use it.
+ * @deprecated AssumptionViolatedExceptions are handled by default since
+ * JUnit 4.12. Just like in JUnit &lt;= 4.10.
+ */
+ @Deprecated
+ public ExpectedException handleAssumptionViolatedExceptions() {
+ return this;
+ }
+
+ /**
+ * Specifies the failure message for tests that are expected to throw
+ * an exception but do not throw any. You can use a {@code %s} placeholder for
+ * the description of the expected exception. E.g. "Test doesn't throw %s."
+ * will fail with the error message
+ * "Test doesn't throw an instance of foo.".
+ *
+ * @param message exception detail message
+ * @return the rule itself
+ */
+ public ExpectedException reportMissingExceptionWithMessage(String message) {
+ missingExceptionMessage = message;
+ return this;
+ }
+
+ public Statement apply(Statement base,
+ org.junit.runner.Description description) {
+ return new ExpectedExceptionStatement(base);
+ }
+
+ /**
+ * Verify that your code throws an exception that is matched by
+ * a Hamcrest matcher.
+ * <pre> &#064;Test
+ * public void throwsExceptionThatCompliesWithMatcher() {
+ * NullPointerException e = new NullPointerException();
+ * thrown.expect(is(e));
+ * throw e;
+ * }</pre>
+ */
+ public void expect(Matcher<?> matcher) {
+ matcherBuilder.add(matcher);
+ }
+
+ /**
+ * Verify that your code throws an exception that is an
+ * instance of specific {@code type}.
+ * <pre> &#064;Test
+ * public void throwsExceptionWithSpecificType() {
+ * thrown.expect(NullPointerException.class);
+ * throw new NullPointerException();
+ * }</pre>
+ */
+ public void expect(Class<? extends Throwable> type) {
+ expect(instanceOf(type));
+ }
+
+ /**
+ * Verify that your code throws an exception whose message contains
+ * a specific text.
+ * <pre> &#064;Test
+ * public void throwsExceptionWhoseMessageContainsSpecificText() {
+ * thrown.expectMessage(&quot;happened&quot;);
+ * throw new NullPointerException(&quot;What happened?&quot;);
+ * }</pre>
+ */
+ public void expectMessage(String substring) {
+ expectMessage(containsString(substring));
+ }
+
+ /**
+ * Verify that your code throws an exception whose message is matched
+ * by a Hamcrest matcher.
+ * <pre> &#064;Test
+ * public void throwsExceptionWhoseMessageCompliesWithMatcher() {
+ * thrown.expectMessage(startsWith(&quot;What&quot;));
+ * throw new NullPointerException(&quot;What happened?&quot;);
+ * }</pre>
+ */
+ public void expectMessage(Matcher<String> matcher) {
+ expect(hasMessage(matcher));
+ }
+
+ /**
+ * Verify that your code throws an exception whose cause is matched by
+ * a Hamcrest matcher.
+ * <pre> &#064;Test
+ * public void throwsExceptionWhoseCauseCompliesWithMatcher() {
+ * NullPointerException expectedCause = new NullPointerException();
+ * thrown.expectCause(is(expectedCause));
+ * throw new IllegalArgumentException(&quot;What happened?&quot;, cause);
+ * }</pre>
+ */
+ public void expectCause(Matcher<? extends Throwable> expectedCause) {
+ expect(hasCause(expectedCause));
+ }
+
+ private class ExpectedExceptionStatement extends Statement {
+ private final Statement next;
+
+ public ExpectedExceptionStatement(Statement base) {
+ next = base;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ next.evaluate();
+ } catch (Throwable e) {
+ handleException(e);
+ return;
+ }
+ if (isAnyExceptionExpected()) {
+ failDueToMissingException();
+ }
+ }
+ }
+
+ private void handleException(Throwable e) throws Throwable {
+ if (isAnyExceptionExpected()) {
+ assertThat(e, matcherBuilder.build());
+ } else {
+ throw e;
+ }
+ }
+
+ private boolean isAnyExceptionExpected() {
+ return matcherBuilder.expectsThrowable();
+ }
+
+ private void failDueToMissingException() throws AssertionError {
+ fail(missingExceptionMessage());
+ }
+
+ private String missingExceptionMessage() {
+ String expectation= StringDescription.toString(matcherBuilder.build());
+ return format(missingExceptionMessage, expectation);
+ }
}
diff --git a/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java b/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java
new file mode 100644
index 0000000..e7d94c4
--- /dev/null
+++ b/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java
@@ -0,0 +1,46 @@
+package org.junit.rules;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.junit.matchers.JUnitMatchers.isThrowable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hamcrest.Matcher;
+
+/**
+ * Builds special matcher used by {@link ExpectedException}.
+ */
+class ExpectedExceptionMatcherBuilder {
+
+ private final List<Matcher<?>> matchers = new ArrayList<Matcher<?>>();
+
+ void add(Matcher<?> matcher) {
+ matchers.add(matcher);
+ }
+
+ boolean expectsThrowable() {
+ return !matchers.isEmpty();
+ }
+
+ Matcher<Throwable> build() {
+ return isThrowable(allOfTheMatchers());
+ }
+
+ private Matcher<Throwable> allOfTheMatchers() {
+ if (matchers.size() == 1) {
+ return cast(matchers.get(0));
+ }
+ return allOf(castedMatchers());
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private List<Matcher<? super Throwable>> castedMatchers() {
+ return new ArrayList<Matcher<? super Throwable>>((List) matchers);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Matcher<Throwable> cast(Matcher<?> singleMatcher) {
+ return (Matcher<Throwable>) singleMatcher;
+ }
+}
diff --git a/src/main/java/org/junit/rules/ExternalResource.java b/src/main/java/org/junit/rules/ExternalResource.java
index 1fe3719..71ca287 100644
--- a/src/main/java/org/junit/rules/ExternalResource.java
+++ b/src/main/java/org/junit/rules/ExternalResource.java
@@ -7,62 +7,65 @@ import org.junit.runners.model.Statement;
* A base class for Rules (like TemporaryFolder) that set up an external
* resource before a test (a file, socket, server, database connection, etc.),
* and guarantee to tear it down afterward:
- *
+ *
* <pre>
* public static class UsesExternalResource {
- * Server myServer= new Server();
- *
- * &#064;Rule
- * public ExternalResource resource= new ExternalResource() {
- * &#064;Override
- * protected void before() throws Throwable {
- * myServer.connect();
- * };
- *
- * &#064;Override
- * protected void after() {
- * myServer.disconnect();
- * };
- * };
- *
- * &#064;Test
- * public void testFoo() {
- * new Client().run(myServer);
- * }
+ * Server myServer= new Server();
+ *
+ * &#064;Rule
+ * public ExternalResource resource= new ExternalResource() {
+ * &#064;Override
+ * protected void before() throws Throwable {
+ * myServer.connect();
+ * };
+ *
+ * &#064;Override
+ * protected void after() {
+ * myServer.disconnect();
+ * };
+ * };
+ *
+ * &#064;Test
+ * public void testFoo() {
+ * new Client().run(myServer);
+ * }
* }
* </pre>
+ *
+ * @since 4.7
*/
public abstract class ExternalResource implements TestRule {
- public Statement apply(Statement base, Description description) {
- return statement(base);
- }
+ public Statement apply(Statement base, Description description) {
+ return statement(base);
+ }
- private Statement statement(final Statement base) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- before();
- try {
- base.evaluate();
- } finally {
- after();
- }
- }
- };
- }
+ private Statement statement(final Statement base) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ before();
+ try {
+ base.evaluate();
+ } finally {
+ after();
+ }
+ }
+ };
+ }
- /**
- * Override to set up your specific external resource.
- * @throws if setup fails (which will disable {@code after}
- */
- protected void before() throws Throwable {
- // do nothing
- }
+ /**
+ * Override to set up your specific external resource.
+ *
+ * @throws Throwable if setup fails (which will disable {@code after}
+ */
+ protected void before() throws Throwable {
+ // do nothing
+ }
- /**
- * Override to tear down your specific external resource.
- */
- protected void after() {
- // do nothing
- }
+ /**
+ * Override to tear down your specific external resource.
+ */
+ protected void after() {
+ // do nothing
+ }
}
diff --git a/src/main/java/org/junit/rules/MethodRule.java b/src/main/java/org/junit/rules/MethodRule.java
index 5167672..823ee78 100644
--- a/src/main/java/org/junit/rules/MethodRule.java
+++ b/src/main/java/org/junit/rules/MethodRule.java
@@ -12,7 +12,7 @@ import org.junit.runners.model.Statement;
* {@link Statement}, which is passed to the next {@link Rule}, if any. For
* examples of how this can be useful, see these provided MethodRules,
* or write your own:
- *
+ *
* <ul>
* <li>{@link ErrorCollector}: collect multiple errors in one test method</li>
* <li>{@link ExpectedException}: make flexible assertions about thrown exceptions</li>
@@ -23,18 +23,22 @@ import org.junit.runners.model.Statement;
* <li>{@link Timeout}: cause test to fail after a set time</li>
* <li>{@link Verifier}: fail test if object state ends up incorrect</li>
* </ul>
+ *
+ * Note that {@link MethodRule} has been replaced by {@link TestRule},
+ * which has the added benefit of supporting class rules.
+ *
+ * @since 4.7
*/
-@Deprecated
public interface MethodRule {
- /**
- * Modifies the method-running {@link Statement} to implement an additional
- * test-running rule.
- *
- * @param base The {@link Statement} to be modified
- * @param method The method to be run
- * @param target The object on with the method will be run.
- * @return a new statement, which may be the same as {@code base},
- * a wrapper around {@code base}, or a completely new Statement.
- */
- Statement apply(Statement base, FrameworkMethod method, Object target);
-} \ No newline at end of file
+ /**
+ * Modifies the method-running {@link Statement} to implement an additional
+ * test-running rule.
+ *
+ * @param base The {@link Statement} to be modified
+ * @param method The method to be run
+ * @param target The object on which the method will be run.
+ * @return a new statement, which may be the same as {@code base},
+ * a wrapper around {@code base}, or a completely new Statement.
+ */
+ Statement apply(Statement base, FrameworkMethod method, Object target);
+}
diff --git a/src/main/java/org/junit/rules/RuleChain.java b/src/main/java/org/junit/rules/RuleChain.java
index 8af3c05..f43d8f5 100644
--- a/src/main/java/org/junit/rules/RuleChain.java
+++ b/src/main/java/org/junit/rules/RuleChain.java
@@ -1,6 +1,3 @@
-/**
- *
- */
package org.junit.rules;
import java.util.ArrayList;
@@ -14,24 +11,24 @@ import org.junit.runners.model.Statement;
* The RuleChain rule allows ordering of TestRules. You create a
* {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
* {@link #around(TestRule)}:
- *
+ *
* <pre>
* public static class UseRuleChain {
* &#064;Rule
- * public TestRule chain= RuleChain
+ * public RuleChain chain= RuleChain
* .outerRule(new LoggingRule("outer rule")
* .around(new LoggingRule("middle rule")
* .around(new LoggingRule("inner rule");
- *
+ *
* &#064;Test
* public void example() {
* assertTrue(true);
- * }
+ * }
* }
* </pre>
- *
+ *
* writes the log
- *
+ *
* <pre>
* starting outer rule
* starting middle rule
@@ -40,60 +37,61 @@ import org.junit.runners.model.Statement;
* finished middle rule
* finished outer rule
* </pre>
+ *
+ * @since 4.10
*/
public class RuleChain implements TestRule {
- private static final RuleChain EMPTY_CHAIN= new RuleChain(
- Collections.<TestRule> emptyList());
+ private static final RuleChain EMPTY_CHAIN = new RuleChain(
+ Collections.<TestRule>emptyList());
- private List<TestRule> rulesStartingWithInnerMost;
+ private List<TestRule> rulesStartingWithInnerMost;
- /**
- * Returns a {@code RuleChain} without a {@link TestRule}. This method may
- * be the starting point of a {@code RuleChain}.
- *
- * @return a {@code RuleChain} without a {@link TestRule}.
- */
- public static RuleChain emptyRuleChain() {
- return EMPTY_CHAIN;
- }
+ /**
+ * Returns a {@code RuleChain} without a {@link TestRule}. This method may
+ * be the starting point of a {@code RuleChain}.
+ *
+ * @return a {@code RuleChain} without a {@link TestRule}.
+ */
+ public static RuleChain emptyRuleChain() {
+ return EMPTY_CHAIN;
+ }
- /**
- * Returns a {@code RuleChain} with a single {@link TestRule}. This method
- * is the usual starting point of a {@code RuleChain}.
- *
- * @param outerRule
- * the outer rule of the {@code RuleChain}.
- * @return a {@code RuleChain} with a single {@link TestRule}.
- */
- public static RuleChain outerRule(TestRule outerRule) {
- return emptyRuleChain().around(outerRule);
- }
+ /**
+ * Returns a {@code RuleChain} with a single {@link TestRule}. This method
+ * is the usual starting point of a {@code RuleChain}.
+ *
+ * @param outerRule the outer rule of the {@code RuleChain}.
+ * @return a {@code RuleChain} with a single {@link TestRule}.
+ */
+ public static RuleChain outerRule(TestRule outerRule) {
+ return emptyRuleChain().around(outerRule);
+ }
- private RuleChain(List<TestRule> rules) {
- this.rulesStartingWithInnerMost= rules;
- }
+ private RuleChain(List<TestRule> rules) {
+ this.rulesStartingWithInnerMost = rules;
+ }
- /**
- * Create a new {@code RuleChain}, which encloses the {@code nextRule} with
- * the rules of the current {@code RuleChain}.
- *
- * @param enclosedRule
- * the rule to enclose.
- * @return a new {@code RuleChain}.
- */
- public RuleChain around(TestRule enclosedRule) {
- List<TestRule> rulesOfNewChain= new ArrayList<TestRule>();
- rulesOfNewChain.add(enclosedRule);
- rulesOfNewChain.addAll(rulesStartingWithInnerMost);
- return new RuleChain(rulesOfNewChain);
- }
+ /**
+ * Create a new {@code RuleChain}, which encloses the {@code nextRule} with
+ * the rules of the current {@code RuleChain}.
+ *
+ * @param enclosedRule the rule to enclose.
+ * @return a new {@code RuleChain}.
+ */
+ public RuleChain around(TestRule enclosedRule) {
+ List<TestRule> rulesOfNewChain = new ArrayList<TestRule>();
+ rulesOfNewChain.add(enclosedRule);
+ rulesOfNewChain.addAll(rulesStartingWithInnerMost);
+ return new RuleChain(rulesOfNewChain);
+ }
- /**
- * {@inheritDoc}
- */
- public Statement apply(Statement base, Description description) {
- for (TestRule each : rulesStartingWithInnerMost)
- base= each.apply(base, description);
- return base;
- }
+ /**
+ * {@inheritDoc}
+ */
+ public Statement apply(Statement base, Description description) {
+ for (TestRule each : rulesStartingWithInnerMost) {
+ base = each.apply(base, description);
+ }
+ return base;
+ }
} \ No newline at end of file
diff --git a/src/main/java/org/junit/rules/RunRules.java b/src/main/java/org/junit/rules/RunRules.java
index d5905b9..131fc1f 100644
--- a/src/main/java/org/junit/rules/RunRules.java
+++ b/src/main/java/org/junit/rules/RunRules.java
@@ -5,23 +5,26 @@ import org.junit.runners.model.Statement;
/**
* Runs a collection of rules on a statement.
+ *
+ * @since 4.9
*/
public class RunRules extends Statement {
- private final Statement statement;
+ private final Statement statement;
- public RunRules(Statement base, Iterable<TestRule> rules, Description description) {
- statement= applyAll(base, rules, description);
- }
-
- @Override
- public void evaluate() throws Throwable {
- statement.evaluate();
- }
+ public RunRules(Statement base, Iterable<TestRule> rules, Description description) {
+ statement = applyAll(base, rules, description);
+ }
- private static Statement applyAll(Statement result, Iterable<TestRule> rules,
- Description description) {
- for (TestRule each : rules)
- result= each.apply(result, description);
- return result;
- }
+ @Override
+ public void evaluate() throws Throwable {
+ statement.evaluate();
+ }
+
+ private static Statement applyAll(Statement result, Iterable<TestRule> rules,
+ Description description) {
+ for (TestRule each : rules) {
+ result = each.apply(result, description);
+ }
+ return result;
+ }
}
diff --git a/src/main/java/org/junit/rules/Stopwatch.java b/src/main/java/org/junit/rules/Stopwatch.java
new file mode 100644
index 0000000..5d34e7f
--- /dev/null
+++ b/src/main/java/org/junit/rules/Stopwatch.java
@@ -0,0 +1,183 @@
+package org.junit.rules;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * The Stopwatch Rule notifies one of its own protected methods of the time spent by a test.
+ *
+ * <p>Override them to get the time in nanoseconds. For example, this class will keep logging the
+ * time spent by each passed, failed, skipped, and finished test:
+ *
+ * <pre>
+ * public static class StopwatchTest {
+ * private static final Logger logger = Logger.getLogger(&quot;&quot;);
+ *
+ * private static void logInfo(Description description, String status, long nanos) {
+ * String testName = description.getMethodName();
+ * logger.info(String.format(&quot;Test %s %s, spent %d microseconds&quot;,
+ * testName, status, TimeUnit.NANOSECONDS.toMicros(nanos)));
+ * }
+ *
+ * &#064;Rule
+ * public Stopwatch stopwatch = new Stopwatch() {
+ * &#064;Override
+ * protected void succeeded(long nanos, Description description) {
+ * logInfo(description, &quot;succeeded&quot;, nanos);
+ * }
+ *
+ * &#064;Override
+ * protected void failed(long nanos, Throwable e, Description description) {
+ * logInfo(description, &quot;failed&quot;, nanos);
+ * }
+ *
+ * &#064;Override
+ * protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
+ * logInfo(description, &quot;skipped&quot;, nanos);
+ * }
+ *
+ * &#064;Override
+ * protected void finished(long nanos, Description description) {
+ * logInfo(description, &quot;finished&quot;, nanos);
+ * }
+ * };
+ *
+ * &#064;Test
+ * public void succeeds() {
+ * }
+ *
+ * &#064;Test
+ * public void fails() {
+ * fail();
+ * }
+ *
+ * &#064;Test
+ * public void skips() {
+ * assumeTrue(false);
+ * }
+ * }
+ * </pre>
+ *
+ * An example to assert runtime:
+ * <pre>
+ * &#064;Test
+ * public void performanceTest() throws InterruptedException {
+ * long delta = 30;
+ * Thread.sleep(300L);
+ * assertEquals(300d, stopwatch.runtime(MILLISECONDS), delta);
+ * Thread.sleep(500L);
+ * assertEquals(800d, stopwatch.runtime(MILLISECONDS), delta);
+ * }
+ * </pre>
+ *
+ * @author tibor17
+ * @since 4.12
+ */
+public abstract class Stopwatch implements TestRule {
+ private final Clock clock;
+ private volatile long startNanos;
+ private volatile long endNanos;
+
+ public Stopwatch() {
+ this(new Clock());
+ }
+
+ Stopwatch(Clock clock) {
+ this.clock = clock;
+ }
+
+ /**
+ * Gets the runtime for the test.
+ *
+ * @param unit time unit for returned runtime
+ * @return runtime measured during the test
+ */
+ public long runtime(TimeUnit unit) {
+ return unit.convert(getNanos(), TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Invoked when a test succeeds
+ */
+ protected void succeeded(long nanos, Description description) {
+ }
+
+ /**
+ * Invoked when a test fails
+ */
+ protected void failed(long nanos, Throwable e, Description description) {
+ }
+
+ /**
+ * Invoked when a test is skipped due to a failed assumption.
+ */
+ protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
+ }
+
+ /**
+ * Invoked when a test method finishes (whether passing or failing)
+ */
+ protected void finished(long nanos, Description description) {
+ }
+
+ private long getNanos() {
+ if (startNanos == 0) {
+ throw new IllegalStateException("Test has not started");
+ }
+ long currentEndNanos = endNanos; // volatile read happens here
+ if (currentEndNanos == 0) {
+ currentEndNanos = clock.nanoTime();
+ }
+
+ return currentEndNanos - startNanos;
+ }
+
+ private void starting() {
+ startNanos = clock.nanoTime();
+ endNanos = 0;
+ }
+
+ private void stopping() {
+ endNanos = clock.nanoTime();
+ }
+
+ public final Statement apply(Statement base, Description description) {
+ return new InternalWatcher().apply(base, description);
+ }
+
+ private class InternalWatcher extends TestWatcher {
+
+ @Override protected void starting(Description description) {
+ Stopwatch.this.starting();
+ }
+
+ @Override protected void finished(Description description) {
+ Stopwatch.this.finished(getNanos(), description);
+ }
+
+ @Override protected void succeeded(Description description) {
+ Stopwatch.this.stopping();
+ Stopwatch.this.succeeded(getNanos(), description);
+ }
+
+ @Override protected void failed(Throwable e, Description description) {
+ Stopwatch.this.stopping();
+ Stopwatch.this.failed(getNanos(), e, description);
+ }
+
+ @Override protected void skipped(AssumptionViolatedException e, Description description) {
+ Stopwatch.this.stopping();
+ Stopwatch.this.skipped(getNanos(), e, description);
+ }
+ }
+
+ static class Clock {
+
+ public long nanoTime() {
+ return System.nanoTime();
+ }
+ }
+}
diff --git a/src/main/java/org/junit/rules/TemporaryFolder.java b/src/main/java/org/junit/rules/TemporaryFolder.java
index a7c82aa..dc75c93 100644
--- a/src/main/java/org/junit/rules/TemporaryFolder.java
+++ b/src/main/java/org/junit/rules/TemporaryFolder.java
@@ -6,108 +6,165 @@ import java.io.IOException;
import org.junit.Rule;
/**
- * The TemporaryFolder Rule allows creation of files and folders that are
- * guaranteed to be deleted when the test method finishes (whether it passes or
- * fails):
- *
+ * The TemporaryFolder Rule allows creation of files and folders that should
+ * be deleted when the test method finishes (whether it passes or
+ * fails). Whether the deletion is successful or not is not checked by this rule.
+ * No exception will be thrown in case the deletion fails.
+ *
+ * <p>Example of usage:
* <pre>
* public static class HasTempFolder {
- * &#064;Rule
- * public TemporaryFolder folder= new TemporaryFolder();
- *
- * &#064;Test
- * public void testUsingTempFolder() throws IOException {
- * File createdFile= folder.newFile(&quot;myfile.txt&quot;);
- * File createdFolder= folder.newFolder(&quot;subfolder&quot;);
- * // ...
- * }
+ * &#064;Rule
+ * public TemporaryFolder folder= new TemporaryFolder();
+ *
+ * &#064;Test
+ * public void testUsingTempFolder() throws IOException {
+ * File createdFile= folder.newFile(&quot;myfile.txt&quot;);
+ * File createdFolder= folder.newFolder(&quot;subfolder&quot;);
+ * // ...
+ * }
* }
* </pre>
+ *
+ * @since 4.7
*/
public class TemporaryFolder extends ExternalResource {
- private File folder;
-
- @Override
- protected void before() throws Throwable {
- create();
- }
-
- @Override
- protected void after() {
- delete();
- }
-
- // testing purposes only
- /**
- * for testing purposes only. Do not use.
- */
- public void create() throws IOException {
- folder= newFolder();
- }
-
- /**
- * Returns a new fresh file with the given name under the temporary folder.
- */
- public File newFile(String fileName) throws IOException {
- File file= new File(getRoot(), fileName);
- file.createNewFile();
- return file;
- }
-
- /**
- * Returns a new fresh file with a random name under the temporary folder.
- */
- public File newFile() throws IOException {
- return File.createTempFile("junit", null, folder);
- }
-
- /**
- * Returns a new fresh folder with the given name under the temporary folder.
- */
- public File newFolder(String... folderNames) {
- File file = getRoot();
- for (String folderName : folderNames) {
- file = new File(file, folderName);
- file.mkdir();
- }
- return file;
- }
-
- /**
- * Returns a new fresh folder with a random name under the temporary
- * folder.
- */
- public File newFolder() throws IOException {
- File createdFolder= File.createTempFile("junit", "", folder);
- createdFolder.delete();
- createdFolder.mkdir();
- return createdFolder;
- }
-
- /**
- * @return the location of this temporary folder.
- */
- public File getRoot() {
- if (folder == null) {
- throw new IllegalStateException("the temporary folder has not yet been created");
- }
- return folder;
- }
-
- /**
- * Delete all files and folders under the temporary folder.
- * Usually not called directly, since it is automatically applied
- * by the {@link Rule}
- */
- public void delete() {
- recursiveDelete(folder);
- }
-
- private void recursiveDelete(File file) {
- File[] files= file.listFiles();
- if (files != null)
- for (File each : files)
- recursiveDelete(each);
- file.delete();
- }
+ private final File parentFolder;
+ private File folder;
+
+ public TemporaryFolder() {
+ this(null);
+ }
+
+ public TemporaryFolder(File parentFolder) {
+ this.parentFolder = parentFolder;
+ }
+
+ @Override
+ protected void before() throws Throwable {
+ create();
+ }
+
+ @Override
+ protected void after() {
+ delete();
+ }
+
+ // testing purposes only
+
+ /**
+ * for testing purposes only. Do not use.
+ */
+ public void create() throws IOException {
+ folder = createTemporaryFolderIn(parentFolder);
+ }
+
+ /**
+ * Returns a new fresh file with the given name under the temporary folder.
+ */
+ public File newFile(String fileName) throws IOException {
+ File file = new File(getRoot(), fileName);
+ if (!file.createNewFile()) {
+ throw new IOException(
+ "a file with the name \'" + fileName + "\' already exists in the test folder");
+ }
+ return file;
+ }
+
+ /**
+ * Returns a new fresh file with a random name under the temporary folder.
+ */
+ public File newFile() throws IOException {
+ return File.createTempFile("junit", null, getRoot());
+ }
+
+ /**
+ * Returns a new fresh folder with the given name under the temporary
+ * folder.
+ */
+ public File newFolder(String folder) throws IOException {
+ return newFolder(new String[]{folder});
+ }
+
+ /**
+ * Returns a new fresh folder with the given name(s) under the temporary
+ * folder.
+ */
+ public File newFolder(String... folderNames) throws IOException {
+ File file = getRoot();
+ for (int i = 0; i < folderNames.length; i++) {
+ String folderName = folderNames[i];
+ validateFolderName(folderName);
+ file = new File(file, folderName);
+ if (!file.mkdir() && isLastElementInArray(i, folderNames)) {
+ throw new IOException(
+ "a folder with the name \'" + folderName + "\' already exists");
+ }
+ }
+ return file;
+ }
+
+ /**
+ * Validates if multiple path components were used while creating a folder.
+ *
+ * @param folderName
+ * Name of the folder being created
+ */
+ private void validateFolderName(String folderName) throws IOException {
+ File tempFile = new File(folderName);
+ if (tempFile.getParent() != null) {
+ String errorMsg = "Folder name cannot consist of multiple path components separated by a file separator."
+ + " Please use newFolder('MyParentFolder','MyFolder') to create hierarchies of folders";
+ throw new IOException(errorMsg);
+ }
+ }
+
+ private boolean isLastElementInArray(int index, String[] array) {
+ return index == array.length - 1;
+ }
+
+ /**
+ * Returns a new fresh folder with a random name under the temporary folder.
+ */
+ public File newFolder() throws IOException {
+ return createTemporaryFolderIn(getRoot());
+ }
+
+ private File createTemporaryFolderIn(File parentFolder) throws IOException {
+ File createdFolder = File.createTempFile("junit", "", parentFolder);
+ createdFolder.delete();
+ createdFolder.mkdir();
+ return createdFolder;
+ }
+
+ /**
+ * @return the location of this temporary folder.
+ */
+ public File getRoot() {
+ if (folder == null) {
+ throw new IllegalStateException(
+ "the temporary folder has not yet been created");
+ }
+ return folder;
+ }
+
+ /**
+ * Delete all files and folders under the temporary folder. Usually not
+ * called directly, since it is automatically applied by the {@link Rule}
+ */
+ public void delete() {
+ if (folder != null) {
+ recursiveDelete(folder);
+ }
+ }
+
+ private void recursiveDelete(File file) {
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File each : files) {
+ recursiveDelete(each);
+ }
+ }
+ file.delete();
+ }
}
diff --git a/src/main/java/org/junit/rules/TestName.java b/src/main/java/org/junit/rules/TestName.java
index c4ab9ce..bf72602 100644
--- a/src/main/java/org/junit/rules/TestName.java
+++ b/src/main/java/org/junit/rules/TestName.java
@@ -4,36 +4,38 @@ import org.junit.runner.Description;
/**
* The TestName Rule makes the current test name available inside test methods:
- *
+ *
* <pre>
* public class TestNameTest {
- * &#064;Rule
- * public TestName name= new TestName();
- *
- * &#064;Test
- * public void testA() {
- * assertEquals(&quot;testA&quot;, name.getMethodName());
- * }
- *
- * &#064;Test
- * public void testB() {
- * assertEquals(&quot;testB&quot;, name.getMethodName());
- * }
+ * &#064;Rule
+ * public TestName name= new TestName();
+ *
+ * &#064;Test
+ * public void testA() {
+ * assertEquals(&quot;testA&quot;, name.getMethodName());
+ * }
+ *
+ * &#064;Test
+ * public void testB() {
+ * assertEquals(&quot;testB&quot;, name.getMethodName());
+ * }
* }
* </pre>
+ *
+ * @since 4.7
*/
public class TestName extends TestWatcher {
- private String fName;
+ private String name;
- @Override
- protected void starting(Description d) {
- fName= d.getMethodName();
- }
+ @Override
+ protected void starting(Description d) {
+ name = d.getMethodName();
+ }
- /**
- * @return the name of the currently-running test method
- */
- public String getMethodName() {
- return fName;
- }
+ /**
+ * @return the name of the currently-running test method
+ */
+ public String getMethodName() {
+ return name;
+ }
}
diff --git a/src/main/java/org/junit/rules/TestRule.java b/src/main/java/org/junit/rules/TestRule.java
index b7760c4..53e2f70 100644
--- a/src/main/java/org/junit/rules/TestRule.java
+++ b/src/main/java/org/junit/rules/TestRule.java
@@ -9,16 +9,16 @@ import org.junit.runners.model.Statement;
* a test that would otherwise fail to pass, or it may perform necessary setup or
* cleanup for tests, or it may observe test execution to report it elsewhere.
* {@link TestRule}s can do everything that could be done previously with
- * methods annotated with {@link org.junit.Before},
- * {@link org.junit.After}, {@link org.junit.BeforeClass}, or
- * {@link org.junit.AfterClass}, but they are more powerful, and more easily
+ * methods annotated with {@link org.junit.Before},
+ * {@link org.junit.After}, {@link org.junit.BeforeClass}, or
+ * {@link org.junit.AfterClass}, but they are more powerful, and more easily
* shared
* between projects and classes.
- *
+ *
* The default JUnit test runners for suites and
* individual test cases recognize {@link TestRule}s introduced in two different
- * ways. {@link org.junit.Rule} annotates method-level
- * {@link TestRule}s, and {@link org.junit.ClassRule}
+ * ways. {@link org.junit.Rule} annotates method-level
+ * {@link TestRule}s, and {@link org.junit.ClassRule}
* annotates class-level {@link TestRule}s. See Javadoc for those annotations
* for more information.
*
@@ -28,7 +28,7 @@ import org.junit.runners.model.Statement;
* {@link Statement}, which is passed to the next {@link org.junit.Rule}, if any. For
* examples of how this can be useful, see these provided TestRules,
* or write your own:
- *
+ *
* <ul>
* <li>{@link ErrorCollector}: collect multiple errors in one test method</li>
* <li>{@link ExpectedException}: make flexible assertions about thrown exceptions</li>
@@ -39,16 +39,18 @@ import org.junit.runners.model.Statement;
* <li>{@link Timeout}: cause test to fail after a set time</li>
* <li>{@link Verifier}: fail test if object state ends up incorrect</li>
* </ul>
+ *
+ * @since 4.9
*/
public interface TestRule {
- /**
- * Modifies the method-running {@link Statement} to implement this
- * test-running rule.
- *
- * @param base The {@link Statement} to be modified
- * @param description A {@link Description} of the test implemented in {@code base}
- * @return a new statement, which may be the same as {@code base},
- * a wrapper around {@code base}, or a completely new Statement.
- */
- Statement apply(Statement base, Description description);
+ /**
+ * Modifies the method-running {@link Statement} to implement this
+ * test-running rule.
+ *
+ * @param base The {@link Statement} to be modified
+ * @param description A {@link Description} of the test implemented in {@code base}
+ * @return a new statement, which may be the same as {@code base},
+ * a wrapper around {@code base}, or a completely new Statement.
+ */
+ Statement apply(Statement base, Description description);
}
diff --git a/src/main/java/org/junit/rules/TestWatcher.java b/src/main/java/org/junit/rules/TestWatcher.java
index 351b449..5492b6b 100644
--- a/src/main/java/org/junit/rules/TestWatcher.java
+++ b/src/main/java/org/junit/rules/TestWatcher.java
@@ -1,94 +1,166 @@
package org.junit.rules;
-import org.junit.internal.AssumptionViolatedException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.AssumptionViolatedException;
import org.junit.runner.Description;
+import org.junit.runners.model.MultipleFailureException;
import org.junit.runners.model.Statement;
/**
* TestWatcher is a base class for Rules that take note of the testing
* action, without modifying it. For example, this class will keep a log of each
* passing and failing test:
- *
+ *
* <pre>
* public static class WatchmanTest {
- * private static String watchedLog;
- *
- * &#064;Rule
- * public MethodRule watchman= new TestWatcher() {
- * &#064;Override
- * protected void failed(Description d) {
- * watchedLog+= d + &quot;\n&quot;;
- * }
- *
- * &#064;Override
- * protected void succeeded(Description d) {
- * watchedLog+= d + &quot; &quot; + &quot;success!\n&quot;;
- * }
- * };
- *
- * &#064;Test
- * public void fails() {
- * fail();
- * }
- *
- * &#064;Test
- * public void succeeds() {
- * }
+ * private static String watchedLog;
+ *
+ * &#064;Rule
+ * public TestWatcher watchman= new TestWatcher() {
+ * &#064;Override
+ * protected void failed(Throwable e, Description description) {
+ * watchedLog+= description + &quot;\n&quot;;
+ * }
+ *
+ * &#064;Override
+ * protected void succeeded(Description description) {
+ * watchedLog+= description + &quot; &quot; + &quot;success!\n&quot;;
+ * }
+ * };
+ *
+ * &#064;Test
+ * public void fails() {
+ * fail();
+ * }
+ *
+ * &#064;Test
+ * public void succeeds() {
+ * }
* }
* </pre>
+ *
+ * @since 4.9
*/
public abstract class TestWatcher implements TestRule {
- public Statement apply(final Statement base, final Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- starting(description);
- try {
- base.evaluate();
- succeeded(description);
- } catch (AssumptionViolatedException e) {
- throw e;
- } catch (Throwable t) {
- failed(t, description);
- throw t;
- } finally {
- finished(description);
- }
- }
- };
- }
-
- /**
- * Invoked when a test succeeds
- *
- * @param description
- */
- protected void succeeded(Description description) {
- }
-
- /**
- * Invoked when a test fails
- *
- * @param e
- * @param description
- */
- protected void failed(Throwable e, Description description) {
- }
-
- /**
- * Invoked when a test is about to start
- *
- * @param description
- */
- protected void starting(Description description) {
- }
-
-
- /**
- * Invoked when a test method finishes (whether passing or failing)
- *
- * @param description
- */
- protected void finished(Description description) {
- }
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ List<Throwable> errors = new ArrayList<Throwable>();
+
+ startingQuietly(description, errors);
+ try {
+ base.evaluate();
+ succeededQuietly(description, errors);
+ } catch (@SuppressWarnings("deprecation") org.junit.internal.AssumptionViolatedException e) {
+ errors.add(e);
+ skippedQuietly(e, description, errors);
+ } catch (Throwable e) {
+ errors.add(e);
+ failedQuietly(e, description, errors);
+ } finally {
+ finishedQuietly(description, errors);
+ }
+
+ MultipleFailureException.assertEmpty(errors);
+ }
+ };
+ }
+
+ private void succeededQuietly(Description description,
+ List<Throwable> errors) {
+ try {
+ succeeded(description);
+ } catch (Throwable e) {
+ errors.add(e);
+ }
+ }
+
+ private void failedQuietly(Throwable e, Description description,
+ List<Throwable> errors) {
+ try {
+ failed(e, description);
+ } catch (Throwable e1) {
+ errors.add(e1);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private void skippedQuietly(
+ org.junit.internal.AssumptionViolatedException e, Description description,
+ List<Throwable> errors) {
+ try {
+ if (e instanceof AssumptionViolatedException) {
+ skipped((AssumptionViolatedException) e, description);
+ } else {
+ skipped(e, description);
+ }
+ } catch (Throwable e1) {
+ errors.add(e1);
+ }
+ }
+
+ private void startingQuietly(Description description,
+ List<Throwable> errors) {
+ try {
+ starting(description);
+ } catch (Throwable e) {
+ errors.add(e);
+ }
+ }
+
+ private void finishedQuietly(Description description,
+ List<Throwable> errors) {
+ try {
+ finished(description);
+ } catch (Throwable e) {
+ errors.add(e);
+ }
+ }
+
+ /**
+ * Invoked when a test succeeds
+ */
+ protected void succeeded(Description description) {
+ }
+
+ /**
+ * Invoked when a test fails
+ */
+ protected void failed(Throwable e, Description description) {
+ }
+
+ /**
+ * Invoked when a test is skipped due to a failed assumption.
+ */
+ @SuppressWarnings("deprecation")
+ protected void skipped(AssumptionViolatedException e, Description description) {
+ // For backwards compatibility with JUnit 4.11 and earlier, call the legacy version
+ org.junit.internal.AssumptionViolatedException asInternalException = e;
+ skipped(asInternalException, description);
+ }
+
+ /**
+ * Invoked when a test is skipped due to a failed assumption.
+ *
+ * @deprecated use {@link #skipped(AssumptionViolatedException, Description)}
+ */
+ @Deprecated
+ protected void skipped(
+ org.junit.internal.AssumptionViolatedException e, Description description) {
+ }
+
+ /**
+ * Invoked when a test is about to start
+ */
+ protected void starting(Description description) {
+ }
+
+ /**
+ * Invoked when a test method finishes (whether passing or failing)
+ */
+ protected void finished(Description description) {
+ }
}
diff --git a/src/main/java/org/junit/rules/TestWatchman.java b/src/main/java/org/junit/rules/TestWatchman.java
index 15daa64..c8d6c71 100644
--- a/src/main/java/org/junit/rules/TestWatchman.java
+++ b/src/main/java/org/junit/rules/TestWatchman.java
@@ -8,93 +8,84 @@ import org.junit.runners.model.Statement;
* TestWatchman is a base class for Rules that take note of the testing
* action, without modifying it. For example, this class will keep a log of each
* passing and failing test:
- *
+ *
* <pre>
* public static class WatchmanTest {
- * private static String watchedLog;
- *
- * &#064;Rule
- * public MethodRule watchman= new TestWatchman() {
- * &#064;Override
- * public void failed(Throwable e, FrameworkMethod method) {
- * watchedLog+= method.getName() + &quot; &quot; + e.getClass().getSimpleName()
- * + &quot;\n&quot;;
- * }
- *
- * &#064;Override
- * public void succeeded(FrameworkMethod method) {
- * watchedLog+= method.getName() + &quot; &quot; + &quot;success!\n&quot;;
- * }
- * };
- *
- * &#064;Test
- * public void fails() {
- * fail();
- * }
- *
- * &#064;Test
- * public void succeeds() {
- * }
+ * private static String watchedLog;
+ *
+ * &#064;Rule
+ * public MethodRule watchman= new TestWatchman() {
+ * &#064;Override
+ * public void failed(Throwable e, FrameworkMethod method) {
+ * watchedLog+= method.getName() + &quot; &quot; + e.getClass().getSimpleName()
+ * + &quot;\n&quot;;
+ * }
+ *
+ * &#064;Override
+ * public void succeeded(FrameworkMethod method) {
+ * watchedLog+= method.getName() + &quot; &quot; + &quot;success!\n&quot;;
+ * }
+ * };
+ *
+ * &#064;Test
+ * public void fails() {
+ * fail();
+ * }
+ *
+ * &#064;Test
+ * public void succeeds() {
+ * }
* }
* </pre>
- *
- * @deprecated {@link MethodRule} is deprecated.
- * Use {@link TestWatcher} implements {@link TestRule} instead.
+ *
+ * @since 4.7
+ * @deprecated Use {@link TestWatcher} (which implements {@link TestRule}) instead.
*/
@Deprecated
public class TestWatchman implements MethodRule {
- public Statement apply(final Statement base, final FrameworkMethod method,
- Object target) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- starting(method);
- try {
- base.evaluate();
- succeeded(method);
- } catch (AssumptionViolatedException e) {
- throw e;
- } catch (Throwable t) {
- failed(t, method);
- throw t;
- } finally {
- finished(method);
- }
- }
- };
- }
+ public Statement apply(final Statement base, final FrameworkMethod method,
+ Object target) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ starting(method);
+ try {
+ base.evaluate();
+ succeeded(method);
+ } catch (AssumptionViolatedException e) {
+ throw e;
+ } catch (Throwable e) {
+ failed(e, method);
+ throw e;
+ } finally {
+ finished(method);
+ }
+ }
+ };
+ }
- /**
- * Invoked when a test method succeeds
- *
- * @param method
- */
- public void succeeded(FrameworkMethod method) {
- }
+ /**
+ * Invoked when a test method succeeds
+ */
+ public void succeeded(FrameworkMethod method) {
+ }
- /**
- * Invoked when a test method fails
- *
- * @param e
- * @param method
- */
- public void failed(Throwable e, FrameworkMethod method) {
- }
+ /**
+ * Invoked when a test method fails
+ */
+ public void failed(Throwable e, FrameworkMethod method) {
+ }
- /**
- * Invoked when a test method is about to start
- *
- * @param method
- */
- public void starting(FrameworkMethod method) {
- }
+ /**
+ * Invoked when a test method is about to start
+ */
+ public void starting(FrameworkMethod method) {
+ }
- /**
- * Invoked when a test method finishes (whether passing or failing)
- *
- * @param method
- */
- public void finished(FrameworkMethod method) {
- }
+ /**
+ * Invoked when a test method finishes (whether passing or failing)
+ */
+ public void finished(FrameworkMethod method) {
+ }
}
diff --git a/src/main/java/org/junit/rules/Timeout.java b/src/main/java/org/junit/rules/Timeout.java
index 85ce6d6..45a5bc5 100644
--- a/src/main/java/org/junit/rules/Timeout.java
+++ b/src/main/java/org/junit/rules/Timeout.java
@@ -1,49 +1,233 @@
-/**
- *
- */
package org.junit.rules;
import org.junit.internal.runners.statements.FailOnTimeout;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import java.util.concurrent.TimeUnit;
+
/**
* The Timeout Rule applies the same timeout to all test methods in a class:
- *
* <pre>
- * public static class HasGlobalTimeout {
- * public static String log;
- *
- * &#064;Rule
- * public MethodRule globalTimeout= new Timeout(20);
- *
- * &#064;Test
- * public void testInfiniteLoop1() {
- * log+= &quot;ran1&quot;;
- * for (;;) {
- * }
- * }
- *
- * &#064;Test
- * public void testInfiniteLoop2() {
- * log+= &quot;ran2&quot;;
- * for (;;) {
- * }
- * }
+ * public static class HasGlobalLongTimeout {
+ *
+ * &#064;Rule
+ * public Timeout globalTimeout= new Timeout(20);
+ *
+ * &#064;Test
+ * public void run1() throws InterruptedException {
+ * Thread.sleep(100);
+ * }
+ *
+ * &#064;Test
+ * public void infiniteLoop() {
+ * while (true) {}
+ * }
* }
* </pre>
+ * <p>
+ * Each test is run in a new thread. If the specified timeout elapses before
+ * the test completes, its execution is interrupted via {@link Thread#interrupt()}.
+ * This happens in interruptable I/O and locks, and methods in {@link Object}
+ * and {@link Thread} throwing {@link InterruptedException}.
+ * <p>
+ * A specified timeout of 0 will be interpreted as not set, however tests will
+ * still launch from separate threads. This can be useful for disabling timeouts
+ * in environments where they are dynamically set based on some property.
+ *
+ * @since 4.7
*/
public class Timeout implements TestRule {
- private final int fMillis;
-
- /**
- * @param millis the millisecond timeout
- */
- public Timeout(int millis) {
- fMillis= millis;
- }
-
- public Statement apply(Statement base, Description description) {
- return new FailOnTimeout(base, fMillis);
- }
-} \ No newline at end of file
+ private final long timeout;
+ private final TimeUnit timeUnit;
+ private final boolean lookForStuckThread;
+
+ /**
+ * Returns a new builder for building an instance.
+ *
+ * @since 4.12
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Create a {@code Timeout} instance with the timeout specified
+ * in milliseconds.
+ * <p>
+ * This constructor is deprecated.
+ * <p>
+ * Instead use {@link #Timeout(long, java.util.concurrent.TimeUnit)},
+ * {@link Timeout#millis(long)}, or {@link Timeout#seconds(long)}.
+ *
+ * @param millis the maximum time in milliseconds to allow the
+ * test to run before it should timeout
+ */
+ @Deprecated
+ public Timeout(int millis) {
+ this(millis, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Create a {@code Timeout} instance with the timeout specified
+ * at the timeUnit of granularity of the provided {@code TimeUnit}.
+ *
+ * @param timeout the maximum time to allow the test to run
+ * before it should timeout
+ * @param timeUnit the time unit for the {@code timeout}
+ * @since 4.12
+ */
+ public Timeout(long timeout, TimeUnit timeUnit) {
+ this.timeout = timeout;
+ this.timeUnit = timeUnit;
+ lookForStuckThread = false;
+ }
+
+ /**
+ * Create a {@code Timeout} instance initialized with values form
+ * a builder.
+ *
+ * @since 4.12
+ */
+ protected Timeout(Builder builder) {
+ timeout = builder.getTimeout();
+ timeUnit = builder.getTimeUnit();
+ lookForStuckThread = builder.getLookingForStuckThread();
+ }
+
+ /**
+ * Creates a {@link Timeout} that will timeout a test after the
+ * given duration, in milliseconds.
+ *
+ * @since 4.12
+ */
+ public static Timeout millis(long millis) {
+ return new Timeout(millis, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Creates a {@link Timeout} that will timeout a test after the
+ * given duration, in seconds.
+ *
+ * @since 4.12
+ */
+ public static Timeout seconds(long seconds) {
+ return new Timeout(seconds, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Gets the timeout configured for this rule, in the given units.
+ *
+ * @since 4.12
+ */
+ protected final long getTimeout(TimeUnit unit) {
+ return unit.convert(timeout, timeUnit);
+ }
+
+ /**
+ * Gets whether this {@code Timeout} will look for a stuck thread
+ * when the test times out.
+ *
+ * @since 4.12
+ */
+ protected final boolean getLookingForStuckThread() {
+ return lookForStuckThread;
+ }
+
+ /**
+ * Creates a {@link Statement} that will run the given
+ * {@code statement}, and timeout the operation based
+ * on the values configured in this rule. Subclasses
+ * can override this method for different behavior.
+ *
+ * @since 4.12
+ */
+ protected Statement createFailOnTimeoutStatement(
+ Statement statement) throws Exception {
+ return FailOnTimeout.builder()
+ .withTimeout(timeout, timeUnit)
+ .withLookingForStuckThread(lookForStuckThread)
+ .build(statement);
+ }
+
+ public Statement apply(Statement base, Description description) {
+ try {
+ return createFailOnTimeoutStatement(base);
+ } catch (final Exception e) {
+ return new Statement() {
+ @Override public void evaluate() throws Throwable {
+ throw new RuntimeException("Invalid parameters for Timeout", e);
+ }
+ };
+ }
+ }
+
+ /**
+ * Builder for {@link Timeout}.
+ *
+ * @since 4.12
+ */
+ public static class Builder {
+ private boolean lookForStuckThread = false;
+ private long timeout = 0;
+ private TimeUnit timeUnit = TimeUnit.SECONDS;
+
+ protected Builder() {
+ }
+
+ /**
+ * Specifies the time to wait before timing out the test.
+ *
+ * <p>If this is not called, or is called with a
+ * {@code timeout} of {@code 0}, the returned {@code Timeout}
+ * rule instance will cause the tests to wait forever to
+ * complete, however the tests will still launch from a
+ * separate thread. This can be useful for disabling timeouts
+ * in environments where they are dynamically set based on
+ * some property.
+ *
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the {@code timeout} argument
+ * @return {@code this} for method chaining.
+ */
+ public Builder withTimeout(long timeout, TimeUnit unit) {
+ this.timeout = timeout;
+ this.timeUnit = unit;
+ return this;
+ }
+
+ protected long getTimeout() {
+ return timeout;
+ }
+
+ protected TimeUnit getTimeUnit() {
+ return timeUnit;
+ }
+
+ /**
+ * Specifies whether to look for a stuck thread. If a timeout occurs and this
+ * feature is enabled, the rule will look for a thread that appears to be stuck
+ * and dump its backtrace. This feature is experimental. Behavior may change
+ * after the 4.12 release in response to feedback.
+ *
+ * @param enable {@code true} to enable the feature
+ * @return {@code this} for method chaining.
+ */
+ public Builder withLookingForStuckThread(boolean enable) {
+ this.lookForStuckThread = enable;
+ return this;
+ }
+
+ protected boolean getLookingForStuckThread() {
+ return lookForStuckThread;
+ }
+
+
+ /**
+ * Builds a {@link Timeout} instance using the values in this builder.,
+ */
+ public Timeout build() {
+ return new Timeout(this);
+ }
+ }
+}
diff --git a/src/main/java/org/junit/rules/Verifier.java b/src/main/java/org/junit/rules/Verifier.java
index be1a55e..7a03b0c 100644
--- a/src/main/java/org/junit/rules/Verifier.java
+++ b/src/main/java/org/junit/rules/Verifier.java
@@ -7,39 +7,41 @@ import org.junit.runners.model.Statement;
* Verifier is a base class for Rules like ErrorCollector, which can turn
* otherwise passing test methods into failing tests if a verification check is
* failed
- *
+ *
* <pre>
- * public static class ErrorLogVerifier() {
+ * public static class ErrorLogVerifier {
* private ErrorLog errorLog = new ErrorLog();
- *
+ *
* &#064;Rule
- * public MethodRule verifier = new Verifier() {
+ * public Verifier verifier = new Verifier() {
* &#064;Override public void verify() {
* assertTrue(errorLog.isEmpty());
* }
* }
- *
+ *
* &#064;Test public void testThatMightWriteErrorLog() {
* // ...
* }
* }
* </pre>
+ *
+ * @since 4.7
*/
-public class Verifier implements TestRule {
- public Statement apply(final Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- base.evaluate();
- verify();
- }
- };
- }
+public abstract class Verifier implements TestRule {
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ base.evaluate();
+ verify();
+ }
+ };
+ }
- /**
- * Override this to add verification logic. Overrides should throw an
- * exception to indicate that verification failed.
- */
- protected void verify() throws Throwable {
- }
+ /**
+ * Override this to add verification logic. Overrides should throw an
+ * exception to indicate that verification failed.
+ */
+ protected void verify() throws Throwable {
+ }
}