diff --git a/acknowledgements.txt b/acknowledgements.txt
index 0d70914839af..4d7ee6c40655 100644
--- a/acknowledgements.txt
+++ b/acknowledgements.txt
@@ -104,9 +104,18 @@
Samuel Le Berrigaud (sleberrigaud@github): Report for GH-248:
protected BlockJUnit4ClassRunner#rules method removed from 4.8.2
+2011 Jun 24
+ Daniel Rothmaler (drothmaler@github):
+ #299: random temp file/folder creation
+ #300: ErrorCollector.checkThat overload
+
2011 Jul 06
Stefan Birkner: Fixed wrong documentation of ClassRule (github#254).
+2011 Jul 08
+ Paul Holser (pholser@alumni.rice.edu): Beginnings of fix for GH-64:
+ Theories doesn't honor parameterized types
+
2011 Jul 09
Nigel Charman: Reported Rules bugs github#257 and gihub#258.
@@ -116,11 +125,35 @@
2011 Jul 09
Stefan Birkner: Fixed rules bugs (github#257, gihub#258, github#260).
+2011 Jul 16
+ Rob Dawson: Submitted a patch that makes Results serlializable.
+
+2011 Jul 20
+ Asaf Ary, Stefan Birkner: Fixed FailOnTimeout class (github#265).
+
2011 Jul 22
Andreas Köhler, Stefan Birkner: Fixed wrong documentation of Parameterized (github#89).
2011 Jul 28
electrickery, Stefan Birkner: Fixed typo in JavaDoc (github#134).
+2011 Aug 07
+ Esko Luontola: Fixed TemporaryFolder creating files in the current working directory (github#278).
+
2011 Aug 09
Stefan Birkner: Fixed JavaDoc links.
+
+2011 Aug 10
+ rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders.
+
+2011 Aug 12
+ Esko Luontola: Fixed syntax error in Parameterized's usage example (github#285).
+
+2011 Sep 09
+ Robert Munteanu, Stefan Birkner:
+ TestWatcher and TestWatchman don't call failed when assumption is violated (github#296).
+ digulla@github, Stefan Birkner: Removed useless code (github#289).
+
+== NOTE: as of September 2011, we have stopped recording contributions here.
+ For a full list of everyone who has contributed great bug reports and code, please see
+ http://github.com/KentBeck/junit
diff --git a/build.xml b/build.xml
index 6e2e8675c10b..26f3275f7452 100644
--- a/build.xml
+++ b/build.xml
@@ -7,7 +7,7 @@
-
+
diff --git a/doc/ReleaseNotes4.10.html b/doc/ReleaseNotes4.10.html
new file mode 100644
index 000000000000..eb6a53668726
--- /dev/null
+++ b/doc/ReleaseNotes4.10.html
@@ -0,0 +1,18 @@
+
Summary of Changes in version 4.10 [unreleased!]
+
+Bug fixes
+
+Minor changes
+
+Thanks to @rodolfoliviero
for:
+
+
+github#283: Feature to create recursive temporary folders.
+
+
+Thanks to @drothmaler
for:
+
+
+github#299: Random temporary file/folder creation
+github#300: New ErrorCollector.checkThat
overload, that allows you to specify a reason
+
diff --git a/doc/ReleaseNotes4.10.txt b/doc/ReleaseNotes4.10.txt
new file mode 100644
index 000000000000..d8f7d9b322cd
--- /dev/null
+++ b/doc/ReleaseNotes4.10.txt
@@ -0,0 +1,14 @@
+## Summary of Changes in version 4.10 [unreleased!] ##
+
+### Bug fixes ###
+
+### Minor changes ###
+
+Thanks to `@rodolfoliviero` for:
+
+- github#283: Feature to create recursive temporary folders.
+
+Thanks to `@drothmaler` for:
+
+- github#299: Random temporary file/folder creation
+- github#300: New `ErrorCollector.checkThat` overload, that allows you to specify a reason
diff --git a/doc/ReleaseNotes4.9.1.txt b/doc/ReleaseNotes4.9.1.txt
new file mode 100644
index 000000000000..eded783dbb66
--- /dev/null
+++ b/doc/ReleaseNotes4.9.1.txt
@@ -0,0 +1,14 @@
+## Summary of Changes in version 4.9.1 [unreleased!] ##
+
+### Theories ###
+
+The `Theories` runner does not anticipate theory parameters that have generic
+types, as reported by github#64. Fixing this won't happen until `Theories` is
+moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the
+necessary machinery to the runner classes, and deprecates a method that only
+the `Theories` runner uses, `FrameworkMethod`#producesType().
+The Common Public License that JUnit is released under is now included
+in the source repository.
+
+Thanks to `@pholser` for identifying a potential resolution for github#64
+and initiating work on it.
diff --git a/src/main/java/junit/runner/Version.java b/src/main/java/junit/runner/Version.java
index 01db4a37b3b2..21aabfa12079 100644
--- a/src/main/java/junit/runner/Version.java
+++ b/src/main/java/junit/runner/Version.java
@@ -9,7 +9,7 @@ private Version() {
}
public static String id() {
- return "4.9.1-SNAPSHOT";
+ return "4.10-SNAPSHOT";
}
public static void main(String[] args) {
diff --git a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
index 8f5d77a7dcf7..bff7c7235107 100644
--- a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
+++ b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
@@ -6,41 +6,66 @@
import org.junit.runners.model.Statement;
public class FailOnTimeout extends Statement {
- private Statement fNext;
+ private final Statement fOriginalStatement;
private final long fTimeout;
- private boolean fFinished= false;
-
- private Throwable fThrown= null;
-
- public FailOnTimeout(Statement next, long timeout) {
- fNext= next;
+ public FailOnTimeout(Statement originalStatement, long timeout) {
+ fOriginalStatement= originalStatement;
fTimeout= timeout;
}
@Override
public void evaluate() throws Throwable {
- Thread thread= new Thread() {
- @Override
- public void run() {
- try {
- fNext.evaluate();
- fFinished= true;
- } catch (Throwable e) {
- fThrown= e;
- }
- }
- };
+ StatementThread thread= evaluateStatement();
+ if (!thread.fFinished)
+ throwExceptionForUnfinishedThread(thread);
+ }
+
+ private StatementThread evaluateStatement() throws InterruptedException {
+ StatementThread thread= new StatementThread(fOriginalStatement);
thread.start();
thread.join(fTimeout);
- if (fFinished)
- return;
- if (fThrown != null)
- throw fThrown;
+ thread.interrupt();
+ return thread;
+ }
+
+ private void throwExceptionForUnfinishedThread(StatementThread thread)
+ throws Throwable {
+ if (thread.fExceptionThrownByOriginalStatement != null)
+ throw thread.fExceptionThrownByOriginalStatement;
+ else
+ throwTimeoutException(thread);
+ }
+
+ private void throwTimeoutException(StatementThread thread) throws Exception {
Exception exception= new Exception(String.format(
"test timed out after %d milliseconds", fTimeout));
exception.setStackTrace(thread.getStackTrace());
throw exception;
}
+
+ private static class StatementThread extends Thread {
+ private final Statement fStatement;
+
+ private boolean fFinished= false;
+
+ private Throwable fExceptionThrownByOriginalStatement= null;
+
+ public StatementThread(Statement statement) {
+ fStatement= statement;
+ }
+
+ @Override
+ public void run() {
+ try {
+ fStatement.evaluate();
+ fFinished= true;
+ } catch (InterruptedException e) {
+ //don't log the InterruptedException
+ } catch (Throwable e) {
+ fExceptionThrownByOriginalStatement= e;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/runners/statements/RunAfters.java b/src/main/java/org/junit/internal/runners/statements/RunAfters.java
index 3f9573a745c2..475ec7261684 100644
--- a/src/main/java/org/junit/internal/runners/statements/RunAfters.java
+++ b/src/main/java/org/junit/internal/runners/statements/RunAfters.java
@@ -26,7 +26,6 @@ public RunAfters(Statement next, List afters, Object target) {
@Override
public void evaluate() throws Throwable {
List errors = new ArrayList();
- errors.clear();
try {
fNext.evaluate();
} catch (Throwable e) {
diff --git a/src/main/java/org/junit/rules/ErrorCollector.java b/src/main/java/org/junit/rules/ErrorCollector.java
index b48d99d84c12..3522a654f415 100644
--- a/src/main/java/org/junit/rules/ErrorCollector.java
+++ b/src/main/java/org/junit/rules/ErrorCollector.java
@@ -52,18 +52,27 @@ public void addError(Throwable error) {
* Execution continues, but the test will fail at the end if the match fails.
*/
public void checkThat(final T value, final Matcher 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 void checkThat(final String reason, final T value, final Matcher matcher) {
checkSucceeds(new Callable() {
public Object call() throws Exception {
- assertThat(value, matcher);
+ 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.
+ * 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 callable) {
try {
@@ -71,6 +80,6 @@ public Object checkSucceeds(Callable callable) {
} catch (Throwable e) {
addError(e);
return null;
- }
+ }
}
}
\ No newline at end of file
diff --git a/src/main/java/org/junit/rules/TemporaryFolder.java b/src/main/java/org/junit/rules/TemporaryFolder.java
index fb8941eb20b3..a7c82aab5246 100644
--- a/src/main/java/org/junit/rules/TemporaryFolder.java
+++ b/src/main/java/org/junit/rules/TemporaryFolder.java
@@ -42,39 +42,61 @@ protected void after() {
* for testing purposes only. Do not use.
*/
public void create() throws IOException {
- folder= File.createTempFile("junit", "");
- folder.delete();
- folder.mkdir();
+ 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(folder, fileName);
+ 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 folderName) {
- File file= new File(folder, folderName);
- file.mkdir();
+ 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
+ * Usually not called directly, since it is automatically applied
* by the {@link Rule}
*/
public void delete() {
@@ -88,4 +110,4 @@ private void recursiveDelete(File file) {
recursiveDelete(each);
file.delete();
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/rules/TestWatcher.java b/src/main/java/org/junit/rules/TestWatcher.java
index 35603adeaf24..351b449e522d 100644
--- a/src/main/java/org/junit/rules/TestWatcher.java
+++ b/src/main/java/org/junit/rules/TestWatcher.java
@@ -1,5 +1,6 @@
package org.junit.rules;
+import org.junit.internal.AssumptionViolatedException;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@@ -45,6 +46,8 @@ public void evaluate() throws Throwable {
try {
base.evaluate();
succeeded(description);
+ } catch (AssumptionViolatedException e) {
+ throw e;
} catch (Throwable t) {
failed(t, description);
throw t;
diff --git a/src/main/java/org/junit/rules/TestWatchman.java b/src/main/java/org/junit/rules/TestWatchman.java
index 6ebd45f84bd3..15daa6419373 100644
--- a/src/main/java/org/junit/rules/TestWatchman.java
+++ b/src/main/java/org/junit/rules/TestWatchman.java
@@ -1,5 +1,6 @@
package org.junit.rules;
+import org.junit.internal.AssumptionViolatedException;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
@@ -51,6 +52,8 @@ public void evaluate() throws Throwable {
try {
base.evaluate();
succeeded(method);
+ } catch (AssumptionViolatedException e) {
+ throw e;
} catch (Throwable t) {
failed(t, method);
throw t;
diff --git a/src/main/java/org/junit/runner/Description.java b/src/main/java/org/junit/runner/Description.java
index 7bba883248e6..b3083d5e05a7 100644
--- a/src/main/java/org/junit/runner/Description.java
+++ b/src/main/java/org/junit/runner/Description.java
@@ -1,5 +1,6 @@
package org.junit.runner;
+import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
@@ -24,8 +25,9 @@
* @see org.junit.runner.Request
* @see org.junit.runner.Runner
*/
-public class Description {
-
+public class Description implements Serializable {
+ private static final long serialVersionUID = 1L;
+
/**
* Create a Description
named name
.
* Generally, you will add children to this Description
.
diff --git a/src/main/java/org/junit/runner/Result.java b/src/main/java/org/junit/runner/Result.java
index de5cf02784e4..edfb97c543f7 100644
--- a/src/main/java/org/junit/runner/Result.java
+++ b/src/main/java/org/junit/runner/Result.java
@@ -1,5 +1,6 @@
package org.junit.runner;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
@@ -13,7 +14,8 @@
* tests. Since tests are expected to run correctly, successful tests are only noted in
* the count of tests that ran.
*/
-public class Result {
+public class Result implements Serializable {
+ private static final long serialVersionUID = 1L;
private AtomicInteger fCount = new AtomicInteger();
private AtomicInteger fIgnoreCount= new AtomicInteger();
private final List fFailures= Collections.synchronizedList(new ArrayList());
diff --git a/src/main/java/org/junit/runner/notification/Failure.java b/src/main/java/org/junit/runner/notification/Failure.java
index 6a2d1a268394..501caa5ed1e0 100644
--- a/src/main/java/org/junit/runner/notification/Failure.java
+++ b/src/main/java/org/junit/runner/notification/Failure.java
@@ -1,6 +1,7 @@
package org.junit.runner.notification;
import java.io.PrintWriter;
+import java.io.Serializable;
import java.io.StringWriter;
import org.junit.runner.Description;
@@ -12,7 +13,8 @@
* test (for example, if a {@link org.junit.BeforeClass} method is not static), it may describe
* something other than a single test.
*/
-public class Failure {
+public class Failure implements Serializable {
+ private static final long serialVersionUID = 1L;
private final Description fDescription;
private final Throwable fThrownException;
diff --git a/src/main/java/org/junit/runners/Parameterized.java b/src/main/java/org/junit/runners/Parameterized.java
index a0ed9f11a1f8..c006cd6b3a60 100644
--- a/src/main/java/org/junit/runners/Parameterized.java
+++ b/src/main/java/org/junit/runners/Parameterized.java
@@ -31,8 +31,8 @@
* @Parameters
* public static List<Object[]> data() {
* return Arrays.asList(new Object[][] {
- * { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 },
- * { 6, 8 } } });
+ * { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
+ * });
* }
*
* private int fInput;
diff --git a/src/main/java/org/junit/runners/model/FrameworkMethod.java b/src/main/java/org/junit/runners/model/FrameworkMethod.java
index 8d709ba8486d..81c89634c7fd 100644
--- a/src/main/java/org/junit/runners/model/FrameworkMethod.java
+++ b/src/main/java/org/junit/runners/model/FrameworkMethod.java
@@ -4,6 +4,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
import java.util.List;
import org.junit.internal.runners.model.ReflectiveCallable;
@@ -90,6 +91,10 @@ public void validatePublicVoid(boolean isStatic, List errors) {
errors.add(new Exception("Method " + fMethod.getName() + "() should be void"));
}
+ public void validateNoTypeParametersOnArgs(List errors) {
+ new NoGenericTypeParametersValidator(fMethod).validate(errors);
+ }
+
@Override
public boolean isShadowedBy(FrameworkMethod other) {
if (!other.getName().equals(getName()))
@@ -117,10 +122,16 @@ public int hashCode() {
/**
* Returns true iff this is a no-arg method that returns a value assignable
* to {@code type}
+ *
+ * @deprecated This is used only by the Theories runner, and does not
+ * use all the generic type info that it ought to. It will be replaced
+ * with a forthcoming ParameterSignature#canAcceptResultOf(FrameworkMethod)
+ * once Theories moves to junit-contrib.
*/
- public boolean producesType(Class> type) {
- return getParameterTypes().length == 0
- && type.isAssignableFrom(fMethod.getReturnType());
+ @Deprecated
+ public boolean producesType(Type type) {
+ return getParameterTypes().length == 0 && type instanceof Class>
+ && ((Class>) type).isAssignableFrom(fMethod.getReturnType());
}
private Class>[] getParameterTypes() {
@@ -142,4 +153,4 @@ public Annotation[] getAnnotations() {
public T getAnnotation(Class annotationType) {
return fMethod.getAnnotation(annotationType);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java b/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
new file mode 100644
index 000000000000..77662b8cd124
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
@@ -0,0 +1,53 @@
+package org.junit.runners.model;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+
+class NoGenericTypeParametersValidator {
+ private final Method fMethod;
+
+ NoGenericTypeParametersValidator(Method method) {
+ this.fMethod = method;
+ }
+
+ void validate(List errors) {
+ for (Type each : fMethod.getGenericParameterTypes())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnType(Type type, List errors) {
+ if (type instanceof TypeVariable>) {
+ errors.add(new Exception("Method " + fMethod.getName()
+ + "() contains unresolved type variable " + type));
+ } else if (type instanceof ParameterizedType)
+ validateNoTypeParameterOnParameterizedType((ParameterizedType) type, errors);
+ else if (type instanceof WildcardType)
+ validateNoTypeParameterOnWildcardType((WildcardType) type, errors);
+ else if (type instanceof GenericArrayType)
+ validateNoTypeParameterOnGenericArrayType((GenericArrayType) type, errors);
+ }
+
+ private void validateNoTypeParameterOnParameterizedType(ParameterizedType parameterized,
+ List errors) {
+ for (Type each : parameterized.getActualTypeArguments())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnWildcardType(WildcardType wildcard,
+ List errors) {
+ for (Type each : wildcard.getUpperBounds())
+ validateNoTypeParameterOnType(each, errors);
+ for (Type each : wildcard.getLowerBounds())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnGenericArrayType(
+ GenericArrayType arrayType, List errors) {
+ validateNoTypeParameterOnType(arrayType.getGenericComponentType(), errors);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/junit/tests/runner/AllTests.java b/src/test/java/junit/tests/runner/AllTests.java
index 62001ddf2aa6..a0aa11668e21 100644
--- a/src/test/java/junit/tests/runner/AllTests.java
+++ b/src/test/java/junit/tests/runner/AllTests.java
@@ -16,6 +16,7 @@ public static void main(String[] args) {
public static Test suite() { // Collect tests manually because we have to test class collection code
TestSuite suite= new TestSuite("Framework Tests");
suite.addTestSuite(StackFilterTest.class);
+ suite.addTestSuite(ResultTest.class);
suite.addTestSuite(BaseTestRunnerTest.class);
suite.addTestSuite(TextFeedbackTest.class);
suite.addTestSuite(TextRunnerSingleMethodTest.class);
@@ -27,4 +28,4 @@ static boolean isJDK11() {
String version= System.getProperty("java.version");
return version.startsWith("1.1");
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/junit/tests/runner/ResultTest.java b/src/test/java/junit/tests/runner/ResultTest.java
new file mode 100644
index 000000000000..ba3b509b3abb
--- /dev/null
+++ b/src/test/java/junit/tests/runner/ResultTest.java
@@ -0,0 +1,37 @@
+package junit.tests.runner;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import junit.framework.TestCase;
+import junit.tests.framework.Success;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.tests.running.methods.AnnotationTest;
+
+public class ResultTest extends TestCase {
+
+ public void testRunFailureResultCanBeSerialised() throws Exception {
+ JUnitCore runner = new JUnitCore();
+ Result result = runner.run(AnnotationTest.FailureTest.class);
+ assertResultSerializable(result);
+ }
+
+ public void testRunSuccessResultCanBeSerialised() throws Exception {
+ JUnitCore runner = new JUnitCore();
+ Result result = runner.run(Success.class);
+ assertResultSerializable(result);
+ }
+
+ private void assertResultSerializable(Result result) throws IOException, ClassNotFoundException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ new ObjectOutputStream(byteArrayOutputStream).writeObject(result);
+ byte[] bytes = byteArrayOutputStream.toByteArray();
+ ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
+ Result fromStream = (Result) objectInputStream.readObject();
+ assertNotNull(fromStream);
+ }
+}
diff --git a/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java b/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java
new file mode 100644
index 000000000000..98251b96aa06
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java
@@ -0,0 +1,32 @@
+package org.junit.tests.experimental.rules;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+class LoggingTestWatcher extends TestWatcher {
+ private final StringBuilder log;
+
+ LoggingTestWatcher(StringBuilder log) {
+ this.log= log;
+ }
+
+ @Override
+ protected void succeeded(Description description) {
+ log.append("succeeded ");
+ }
+
+ @Override
+ protected void failed(Throwable e, Description description) {
+ log.append("failed ");
+ }
+
+ @Override
+ protected void starting(Description description) {
+ log.append("starting ");
+ }
+
+ @Override
+ protected void finished(Description description) {
+ log.append("finished ");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java b/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java
index d5487fc00d3e..03393a1a55f1 100644
--- a/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java
@@ -1,20 +1,25 @@
package org.junit.tests.experimental.rules;
+import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.failureCountIs;
import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
import java.io.File;
import java.io.IOException;
+import java.util.Arrays;
+import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class TempFolderRuleTest {
- private static File createdFile;
+ private static File[] createdFiles= new File[20];
public static class HasTempFolder {
@Rule
@@ -22,15 +27,15 @@ public static class HasTempFolder {
@Test
public void testUsingTempFolder() throws IOException {
- createdFile= folder.newFile("myfile.txt");
- assertTrue(createdFile.exists());
+ createdFiles[0]= folder.newFile("myfile.txt");
+ assertTrue(createdFiles[0].exists());
}
}
@Test
public void tempFolderIsDeleted() {
assertThat(testResult(HasTempFolder.class), isSuccessful());
- assertFalse(createdFile.exists());
+ assertFalse(createdFiles[0].exists());
}
public static class CreatesSubFolder {
@@ -39,16 +44,90 @@ public static class CreatesSubFolder {
@Test
public void testUsingTempFolder() throws IOException {
- createdFile= folder.newFolder("subfolder");
- new File(createdFile, "a.txt").createNewFile();
- assertTrue(createdFile.exists());
+ String subfolder = "subfolder";
+ String filename = "a.txt";
+ createdFiles[0]= folder.newFolder(subfolder);
+ new File(createdFiles[0], filename).createNewFile();
+
+ File expectedFile = new File(folder.getRoot(), join(subfolder, filename));
+
+ assertTrue(expectedFile.exists());
+ }
+
+ @Test
+ public void testUsingTempTreeFolders() throws IOException {
+ String subfolder = "subfolder";
+ String anotherfolder = "anotherfolder";
+ String filename = "a.txt";
+
+ createdFiles[0] = folder.newFolder(subfolder, anotherfolder);
+ new File(createdFiles[0], filename).createNewFile();
+
+ File expectedFile = new File(folder.getRoot(), join(subfolder, anotherfolder, filename));
+
+ assertTrue(expectedFile.exists());
+ }
+
+ private String join(String... folderNames) {
+ StringBuilder path = new StringBuilder();
+ for (String folderName : folderNames) {
+ path.append(File.separator).append(folderName);
+ }
+ return path.toString();
}
}
@Test
public void subFolderIsDeleted() {
assertThat(testResult(CreatesSubFolder.class), isSuccessful());
- assertFalse(createdFile.exists());
+ assertFalse(createdFiles[0].exists());
+ }
+
+ public static class CreatesRandomSubFolders {
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testUsingRandomTempFolders() throws IOException {
+ for (int i= 0; i < 20; i++) {
+ File newFolder= folder.newFolder();
+ assertThat(Arrays.asList(createdFiles), not(hasItem(newFolder)));
+ createdFiles[i]= newFolder;
+ new File(newFolder, "a.txt").createNewFile();
+ assertTrue(newFolder.exists());
+ }
+ }
+ }
+
+ @Test
+ public void randomSubFoldersAreDeleted() {
+ assertThat(testResult(CreatesRandomSubFolders.class), isSuccessful());
+ for (File f : createdFiles) {
+ assertFalse(f.exists());
+ }
+ }
+
+ public static class CreatesRandomFiles {
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testUsingRandomTempFiles() throws IOException {
+ for (int i= 0; i < 20; i++) {
+ File newFile= folder.newFile();
+ assertThat(Arrays.asList(createdFiles), not(hasItem(newFile)));
+ createdFiles[i]= newFile;
+ assertTrue(newFile.exists());
+ }
+ }
+ }
+
+ @Test
+ public void randomFilesAreDeleted() {
+ assertThat(testResult(CreatesRandomFiles.class), isSuccessful());
+ for (File f : createdFiles) {
+ assertFalse(f.exists());
+ }
}
@Test
@@ -61,6 +140,16 @@ public void recursiveDeleteFolderWithOneElement() throws IOException {
assertFalse(folder.getRoot().exists());
}
+ @Test
+ public void recursiveDeleteFolderWithOneRandomElement() throws IOException {
+ TemporaryFolder folder= new TemporaryFolder();
+ folder.create();
+ File file= folder.newFile();
+ folder.delete();
+ assertFalse(file.exists());
+ assertFalse(folder.getRoot().exists());
+ }
+
@Test
public void recursiveDeleteFolderWithZeroElements() throws IOException {
TemporaryFolder folder= new TemporaryFolder();
@@ -68,4 +157,44 @@ public void recursiveDeleteFolderWithZeroElements() throws IOException {
folder.delete();
assertFalse(folder.getRoot().exists());
}
+
+ private static final String GET_ROOT_DUMMY= "dummy-getRoot";
+
+ private static final String NEW_FILE_DUMMY= "dummy-newFile";
+
+ private static final String NEW_FOLDER_DUMMY= "dummy-newFolder";
+
+ public static class IncorrectUsage {
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testGetRoot() throws IOException {
+ new File(folder.getRoot(), GET_ROOT_DUMMY).createNewFile();
+ }
+
+ @Test
+ public void testNewFile() throws IOException {
+ folder.newFile(NEW_FILE_DUMMY);
+ }
+
+ @Test
+ public void testNewFolder() throws IOException {
+ folder.newFolder(NEW_FOLDER_DUMMY);
+ }
+ }
+
+ @Test
+ public void incorrectUsageWithoutApplyingTheRuleShouldNotPolluteTheCurrentWorkingDirectory() {
+ assertThat(testResult(IncorrectUsage.class), failureCountIs(3));
+ assertFalse("getRoot should have failed early", new File(GET_ROOT_DUMMY).exists());
+ assertFalse("newFile should have failed early", new File(NEW_FILE_DUMMY).exists());
+ assertFalse("newFolder should have failed early", new File(NEW_FOLDER_DUMMY).exists());
+ }
+
+ @After
+ public void cleanCurrentWorkingDirectory() {
+ new File(GET_ROOT_DUMMY).delete();
+ new File(NEW_FILE_DUMMY).delete();
+ new File(NEW_FOLDER_DUMMY).delete();
+ }
}
diff --git a/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java b/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
index c469e84703fb..167eb201beb4 100644
--- a/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
@@ -146,7 +146,7 @@ public void ignoreNonRules() {
public static class OnFailureTest {
@Rule
- public TestRule watchman= new TestWatcher() {
+ public TestRule watcher= new TestWatcher() {
@Override
protected void failed(Throwable e, Description description) {
log+= description + " " + e.getClass().getSimpleName();
@@ -171,7 +171,7 @@ public static class WatchmanTest {
private static String watchedLog;
@Rule
- public TestRule watchman= new TestWatcher() {
+ public TestRule watcher= new TestWatcher() {
@Override
protected void failed(Throwable e, Description description) {
watchedLog+= description + " "
@@ -203,45 +203,33 @@ public void succeeded() {
}
public static class BeforesAndAfters {
- private static String watchedLog;
+ private static StringBuilder watchedLog= new StringBuilder();
- @Before public void before() {
- watchedLog+= "before ";
+ @Before
+ public void before() {
+ watchedLog.append("before ");
}
@Rule
- public TestRule watchman= new TestWatcher() {
- @Override
- protected void starting(Description d) {
- watchedLog+= "starting ";
- }
-
- @Override
- protected void finished(Description d) {
- watchedLog+= "finished ";
- }
-
- @Override
- protected void succeeded(Description d) {
- watchedLog+= "succeeded ";
- }
- };
+ public TestRule watcher= new LoggingTestWatcher(watchedLog);
- @After public void after() {
- watchedLog+= "after ";
+ @After
+ public void after() {
+ watchedLog.append("after ");
}
@Test
public void succeeds() {
- watchedLog+= "test ";
+ watchedLog.append("test ");
}
}
@Test
public void beforesAndAfters() {
- BeforesAndAfters.watchedLog= "";
+ BeforesAndAfters.watchedLog= new StringBuilder();
JUnitCore.runClasses(BeforesAndAfters.class);
- assertThat(BeforesAndAfters.watchedLog, is("starting before test after succeeded finished "));
+ assertThat(BeforesAndAfters.watchedLog.toString(),
+ is("starting before test after succeeded finished "));
}
public static class WrongTypedField {
@@ -298,4 +286,4 @@ public static class UsesCustomMethodRule {
@Test public void useCustomMethodRule() {
assertThat(testResult(UsesCustomMethodRule.class), isSuccessful());
}
-}
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java b/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java
new file mode 100644
index 000000000000..19ac3e6aea1e
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java
@@ -0,0 +1,52 @@
+package org.junit.tests.experimental.rules;
+
+import static junit.framework.Assert.fail;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.runner.JUnitCore.runClasses;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+
+public class TestWatcherTest {
+ public static class ViolatedAssumptionTest {
+ private static StringBuilder watchedLog= new StringBuilder();
+
+ @Rule
+ public TestRule watcher= new LoggingTestWatcher(watchedLog);
+
+ @Test
+ public void succeeds() {
+ assumeTrue(false);
+ }
+ }
+
+ @Test
+ public void neitherLogSuccessNorFailedForViolatedAssumption() {
+ ViolatedAssumptionTest.watchedLog= new StringBuilder();
+ runClasses(ViolatedAssumptionTest.class);
+ assertThat(ViolatedAssumptionTest.watchedLog.toString(),
+ is("starting finished "));
+ }
+
+ public static class FailingTest {
+ private static StringBuilder watchedLog= new StringBuilder();
+
+ @Rule
+ public TestRule watcher= new LoggingTestWatcher(watchedLog);
+
+ @Test
+ public void succeeds() {
+ fail();
+ }
+ }
+
+ @Test
+ public void logFailingTest() {
+ FailingTest.watchedLog= new StringBuilder();
+ runClasses(FailingTest.class);
+ assertThat(FailingTest.watchedLog.toString(),
+ is("starting failed finished "));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java b/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java
new file mode 100644
index 000000000000..0296a1eb371c
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java
@@ -0,0 +1,71 @@
+package org.junit.tests.experimental.rules;
+
+import static junit.framework.Assert.fail;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.runner.JUnitCore.runClasses;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestWatchman;
+import org.junit.runners.model.FrameworkMethod;
+
+public class TestWatchmanTest {
+ public static class ViolatedAssumptionTest {
+ @Rule
+ public static LoggingTestWatchman watchman= new LoggingTestWatchman();
+
+ @Test
+ public void succeeds() {
+ assumeTrue(false);
+ }
+ }
+
+ @Test
+ public void neitherLogSuccessNorFailedForViolatedAssumption() {
+ runClasses(ViolatedAssumptionTest.class);
+ assertThat(ViolatedAssumptionTest.watchman.log.toString(),
+ is("starting finished "));
+ }
+
+ public static class FailingTest {
+ @Rule
+ public static LoggingTestWatchman watchman= new LoggingTestWatchman();
+
+ @Test
+ public void succeeds() {
+ fail();
+ }
+ }
+
+ @Test
+ public void logFailingTest() {
+ runClasses(FailingTest.class);
+ assertThat(FailingTest.watchman.log.toString(),
+ is("starting failed finished "));
+ }
+
+ private static class LoggingTestWatchman extends TestWatchman {
+ private final StringBuilder log= new StringBuilder();
+
+ @Override
+ public void succeeded(FrameworkMethod method) {
+ log.append("succeeded ");
+ }
+
+ @Override
+ public void failed(Throwable e, FrameworkMethod method) {
+ log.append("failed ");
+ }
+
+ @Override
+ public void starting(FrameworkMethod method) {
+ log.append("starting ");
+ }
+
+ @Override
+ public void finished(FrameworkMethod method) {
+ log.append("finished ");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java b/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
index 2c24fd713868..95e8ec3c4a73 100644
--- a/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
@@ -52,6 +52,8 @@ public static class UsesErrorCollectorCheckThat {
@Test public void example() {
collector.checkThat(3, is(4));
collector.checkThat(5, is(6));
+ collector.checkThat("reason 1", 7, is(8));
+ collector.checkThat("reason 2", 9, is(16));
}
}
@@ -59,6 +61,10 @@ public static class UsesErrorCollectorCheckThat {
PrintableResult testResult= testResult(UsesErrorCollectorCheckThat.class);
assertThat(testResult, hasFailureContaining("got: <3>"));
assertThat(testResult, hasFailureContaining("got: <5>"));
+ assertThat(testResult, hasFailureContaining("reason 1"));
+ assertThat(testResult, hasFailureContaining("got: <7>"));
+ assertThat(testResult, hasFailureContaining("reason 2"));
+ assertThat(testResult, hasFailureContaining("got: <9>"));
}
public static class UsesErrorCollectorCheckSucceeds {
diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java
new file mode 100644
index 000000000000..579fc7e343dd
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java
@@ -0,0 +1,177 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.junit.Assert.*;
+import static org.junit.experimental.results.PrintableResult.*;
+import static org.junit.experimental.results.ResultMatchers.*;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.experimental.results.PrintableResult;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+public class WithUnresolvedGenericTypeVariablesOnTheoryParms {
+ @Test
+ public void whereTypeVariableIsOnTheTheory() {
+ PrintableResult result= testResult(TypeVariableOnTheoryOnly.class);
+ assertThat(result, isSuccessful());
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnTheoryOnly {
+ @DataPoint
+ public static List strings = Arrays.asList("foo", "bar");
+
+ @Theory
+ public void forItems(Collection> items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable T"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnTheoryParm {
+ @DataPoint
+ public static String string = "foo";
+
+ @Theory
+ public void forItem(T item) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnParameterizedTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnParameterizedTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable T"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnParameterizedTheoryParm {
+ @DataPoint
+ public static List strings = Arrays.asList("foo", "bar");
+
+ @Theory
+ public void forItems(Collection items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnWildcardUpperBoundOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnWildcardUpperBoundOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable U"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnWildcardUpperBoundOnTheoryParm {
+ @DataPoint
+ public static List strings = Arrays.asList("foo", "bar");
+
+ @Theory
+ public void forItems(Collection extends U> items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnWildcardLowerBoundOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnWildcardLowerBoundOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable V"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnWildcardLowerBoundOnTheoryParm {
+ @DataPoint
+ public static List strings = Arrays.asList("foo", "bar");
+
+ @Theory
+ public void forItems(Collection super V> items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnArrayTypeOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnArrayTypeOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable T"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnArrayTypeOnTheoryParm {
+ @DataPoints
+ public static String[][] items() {
+ return new String[][] { new String[] { "foo" }, new String[] { "bar" } };
+ }
+
+ @Theory
+ public void forItems(T[] items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnComponentOfArrayTypeOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnComponentOfArrayTypeOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable U"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnComponentOfArrayTypeOnTheoryParm {
+ @DataPoints
+ public static List>[][] items() {
+ return new List>[][] {
+ new List>[] { Arrays.asList("foo") },
+ new List>[] { Arrays.asList("bar") }
+ };
+ }
+
+ @Theory
+ public void forItems(Collection[] items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnTheoryClass() {
+ PrintableResult result= testResult(TypeVariableOnTheoryClass.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable T"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnTheoryClass {
+ @DataPoint
+ public static String item = "bar";
+
+ @Theory
+ public void forItem(T item) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariablesAbound() {
+ PrintableResult result= testResult(TypeVariablesAbound.class);
+ assertThat(result, failureCountIs(7));
+ assertThat(result, hasFailureContaining("unresolved type variable A"));
+ assertThat(result, hasFailureContaining("unresolved type variable B"));
+ assertThat(result, hasFailureContaining("unresolved type variable C"));
+ assertThat(result, hasFailureContaining("unresolved type variable D"));
+ assertThat(result, hasFailureContaining("unresolved type variable E"));
+ assertThat(result, hasFailureContaining("unresolved type variable F"));
+ assertThat(result, hasFailureContaining("unresolved type variable G"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariablesAbound> {
+ @Theory
+ public void forItem(A first, Collection second,
+ Map third, List super E> fourth, F[] fifth,
+ Collection[] sixth) {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java b/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java
new file mode 100644
index 000000000000..152d64139bb5
--- /dev/null
+++ b/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java
@@ -0,0 +1,110 @@
+package org.junit.tests.internal.runners.statements;
+
+import static java.lang.Thread.sleep;
+import static org.junit.Assert.assertTrue;
+import static org.hamcrest.core.Is.is;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.internal.runners.statements.FailOnTimeout;
+import org.junit.rules.ExpectedException;
+import org.junit.runners.model.Statement;
+
+/**
+ * @author Asaf Ary, Stefan Birkner
+ */
+public class FailOnTimeoutTest {
+ private static final int TIMEOUT= 100;
+
+ @Rule
+ public final ExpectedException thrown= ExpectedException.none();
+
+ private final TestStatement statement= new TestStatement();
+
+ private final FailOnTimeout failOnTimeout= new FailOnTimeout(statement,
+ TIMEOUT);
+
+ @Test
+ public void throwExceptionWithNiceMessageOnTimeout() throws Throwable {
+ thrown.expectMessage("test timed out after 100 milliseconds");
+ evaluateWithWaitDuration(TIMEOUT + 50);
+ }
+
+ @Test
+ public void sendUpExceptionThrownByStatement() throws Throwable {
+ RuntimeException exception= new RuntimeException();
+ thrown.expect(is(exception));
+ evaluateWithException(exception);
+ }
+
+ @Test
+ public void throwExceptionIfTheSecondCallToEvaluateNeedsTooMuchTime()
+ throws Throwable {
+ thrown.expect(Exception.class);
+ evaluateWithWaitDuration(0);
+ evaluateWithWaitDuration(TIMEOUT + 50);
+ }
+
+ @Test
+ public void throwTimeoutExceptionOnSecondCallAlthoughFirstCallThrowsException()
+ throws Throwable {
+ thrown.expectMessage("test timed out after 100 milliseconds");
+ try {
+ evaluateWithException(new RuntimeException());
+ } catch (Throwable expected) {
+ }
+ evaluateWithWaitDuration(TIMEOUT + 50);
+ }
+
+ private void evaluateWithException(Exception exception) throws Throwable {
+ statement.nextException= exception;
+ statement.waitDuration= 0;
+ failOnTimeout.evaluate();
+ }
+
+ private void evaluateWithWaitDuration(int waitDuration) throws Throwable {
+ statement.nextException= null;
+ statement.waitDuration= waitDuration;
+ failOnTimeout.evaluate();
+ }
+
+ private static final class TestStatement extends Statement {
+ int waitDuration;
+
+ Exception nextException;
+
+ @Override
+ public void evaluate() throws Throwable {
+ sleep(waitDuration);
+ if (nextException != null)
+ throw nextException;
+ }
+ }
+
+ @Test
+ public void stopEndlessStatement() throws Throwable {
+ InfiniteLoopStatement infiniteLoop= new InfiniteLoopStatement();
+ FailOnTimeout infiniteLoopTimeout= new FailOnTimeout(infiniteLoop,
+ TIMEOUT);
+ try {
+ infiniteLoopTimeout.evaluate();
+ } catch (Exception timeoutException) {
+ sleep(20); // time to interrupt the thread
+ int firstCount= InfiniteLoopStatement.COUNT;
+ sleep(20); // time to increment the count
+ assertTrue("Thread has not been stopped.",
+ firstCount == InfiniteLoopStatement.COUNT);
+ }
+ }
+
+ private static final class InfiniteLoopStatement extends Statement {
+ private static int COUNT= 0;
+
+ @Override
+ public void evaluate() throws Throwable {
+ while (true) {
+ sleep(10); //sleep in order to enable interrupting thread
+ ++COUNT;
+ }
+ }
+ }
+}
\ No newline at end of file