From 9c4e365ea50ea6f983e4b4770de66553a806c806 Mon Sep 17 00:00:00 2001 From: Paul Holser Date: Tue, 5 Jul 2011 20:03:40 -0500 Subject: [PATCH 01/26] Attempt 2: Setting up for resolving issue 64, Theories honoring generic type parameters. This commit comprises only those changes required in the core of JUnit -- basically adding a validator that the Theories runner can call to reject theories with generic type variables (that are hard to resolve), and deprecating FrameworkMethod#producesType, which only the Theories runner uses, and which will be supplanted by an equivalent method on ParameterSignature. Other required changes will be added to the Theories experiment once it migrates over to junit.contrib. --- .../junit/runners/model/FrameworkMethod.java | 15 +- .../NoGenericTypeParametersValidator.java | 53 ++++++ ...lvedGenericTypeVariablesOnTheoryParms.java | 177 ++++++++++++++++++ 3 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java create mode 100644 src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java diff --git a/src/main/java/org/junit/runners/model/FrameworkMethod.java b/src/main/java/org/junit/runners/model/FrameworkMethod.java index 8d709ba8486d..bdb3f106a67f 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,14 @@ public int hashCode() { /** * Returns true iff this is a no-arg method that returns a value assignable * to {@code type} + * + * @deprecated To be supplanted by a forthcoming + * ParameterSignature#canAcceptResultOf(FrameworkMethod) */ - 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() { 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/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 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 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 fourth, F[] fifth, + Collection[] sixth) { + } + } +} \ No newline at end of file From 89ffd7eda43f939f7dc210cfe21a196067ab08d6 Mon Sep 17 00:00:00 2001 From: Paul Holser Date: Fri, 8 Jul 2011 21:13:43 -0500 Subject: [PATCH 02/26] Adding additional javadoc context for deprecated FrameworkMethod#producesType. Adding acknowledgements entry for pholser. Starting 4.9.1 release notes. --- acknowledgements.txt | 5 +++++ doc/ReleaseNotes4.9.1.txt | 14 ++++++++++++++ .../org/junit/runners/model/FrameworkMethod.java | 8 +++++--- 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 doc/ReleaseNotes4.9.1.txt diff --git a/acknowledgements.txt b/acknowledgements.txt index 655e7f2f4013..7ca7bed0257f 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -103,3 +103,8 @@ 2011 Jun 24 Samuel Le Berrigaud (sleberrigaud@github): Report for GH-248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2 + +2011 Jul 8 + Paul Holser (pholser@alumni.rice.edu): Beginnings of fix for GH-64: + Theories doesn't honor parameterized types + diff --git a/doc/ReleaseNotes4.9.1.txt b/doc/ReleaseNotes4.9.1.txt new file mode 100644 index 000000000000..6985fa60eae0 --- /dev/null +++ b/doc/ReleaseNotes4.9.1.txt @@ -0,0 +1,14 @@ +## Summary of Changes in version 4.9 [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/org/junit/runners/model/FrameworkMethod.java b/src/main/java/org/junit/runners/model/FrameworkMethod.java index bdb3f106a67f..81c89634c7fd 100644 --- a/src/main/java/org/junit/runners/model/FrameworkMethod.java +++ b/src/main/java/org/junit/runners/model/FrameworkMethod.java @@ -123,8 +123,10 @@ public int hashCode() { * Returns true iff this is a no-arg method that returns a value assignable * to {@code type} * - * @deprecated To be supplanted by a forthcoming - * ParameterSignature#canAcceptResultOf(FrameworkMethod) + * @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. */ @Deprecated public boolean producesType(Type type) { @@ -151,4 +153,4 @@ public Annotation[] getAnnotations() { public T getAnnotation(Class annotationType) { return fMethod.getAnnotation(annotationType); } -} \ No newline at end of file +} From ab936ef8567bb8682e6034579d7c98976cd5fc22 Mon Sep 17 00:00:00 2001 From: Paul Holser Date: Tue, 12 Jul 2011 14:36:47 -0500 Subject: [PATCH 03/26] correcting version # in header of release notes for 4.9.1 --- doc/ReleaseNotes4.9.1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ReleaseNotes4.9.1.txt b/doc/ReleaseNotes4.9.1.txt index 6985fa60eae0..eded783dbb66 100644 --- a/doc/ReleaseNotes4.9.1.txt +++ b/doc/ReleaseNotes4.9.1.txt @@ -1,4 +1,4 @@ -## Summary of Changes in version 4.9 [unreleased!] ## +## Summary of Changes in version 4.9.1 [unreleased!] ## ### Theories ### From b4fc7138cbf62c471ab5526d86a89757acffd755 Mon Sep 17 00:00:00 2001 From: Rob Dawson Date: Sat, 1 May 2010 21:17:32 +1000 Subject: [PATCH 04/26] Implemented serializable on Description, Result and failure, to enable their use in RMI, as per http://github.com/KentBeck/junit/issues/issue/101. --- src/main/java/org/junit/runner/Description.java | 6 ++++-- src/main/java/org/junit/runner/Result.java | 4 +++- src/main/java/org/junit/runner/notification/Failure.java | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) 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; From 085308f8fb6bd499f5108f7cbd783b1997aceb7c Mon Sep 17 00:00:00 2001 From: Rob Dawson Date: Wed, 6 Jul 2011 20:11:25 +1000 Subject: [PATCH 05/26] Added ResultTest. --- .../java/junit/tests/runner/AllTests.java | 3 +- .../java/junit/tests/runner/ResultTest.java | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/test/java/junit/tests/runner/ResultTest.java 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); + } +} From 50758159495b0f58654934f03a3ceafa73ec826a Mon Sep 17 00:00:00 2001 From: Rob Dawson Date: Wed, 6 Jul 2011 20:20:21 +1000 Subject: [PATCH 06/26] added Rob Dawson. Conflicts: acknowledgements.txt --- acknowledgements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acknowledgements.txt b/acknowledgements.txt index 7ca7bed0257f..54c317d03ea2 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -108,3 +108,5 @@ Paul Holser (pholser@alumni.rice.edu): Beginnings of fix for GH-64: Theories doesn't honor parameterized types +2011 July 16 + Rob Dawson: Submitted a patch that makes Results serlializable. From 70fe94d031c7066899fc464cd4171db0884f1356 Mon Sep 17 00:00:00 2001 From: Esko Luontola Date: Sun, 7 Aug 2011 01:38:12 +0300 Subject: [PATCH 07/26] Fixes #278: TemporaryFolder creates files in the current working directory if applying the rule fails --- acknowledgements.txt | 3 ++ .../java/org/junit/rules/TemporaryFolder.java | 11 +++-- .../rules/TempFolderRuleTest.java | 42 +++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/acknowledgements.txt b/acknowledgements.txt index 54c317d03ea2..05e9558c57e5 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -110,3 +110,6 @@ 2011 July 16 Rob Dawson: Submitted a patch that makes Results serlializable. + +2011 Aug 7 + Esko Luontola: Fixed TemporaryFolder creating files in the current working directory (github#278). diff --git a/src/main/java/org/junit/rules/TemporaryFolder.java b/src/main/java/org/junit/rules/TemporaryFolder.java index fb8941eb20b3..7303e8c22ac7 100644 --- a/src/main/java/org/junit/rules/TemporaryFolder.java +++ b/src/main/java/org/junit/rules/TemporaryFolder.java @@ -51,7 +51,7 @@ public void create() throws IOException { * 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; } @@ -60,7 +60,7 @@ public File newFile(String fileName) throws IOException { * 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 file= new File(getRoot(), folderName); file.mkdir(); return file; } @@ -69,12 +69,15 @@ public File newFolder(String folderName) { * @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 +91,4 @@ private void recursiveDelete(File file) { recursiveDelete(each); file.delete(); } -} \ 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..966ec865189c 100644 --- a/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java +++ b/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java @@ -4,11 +4,13 @@ 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 java.io.File; import java.io.IOException; +import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -68,4 +70,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(); + } } From 8bfbd04bfc61ca364b180a54a851813cff9f58ed Mon Sep 17 00:00:00 2001 From: Stefan Birkner Date: Wed, 6 Jul 2011 21:55:37 +0200 Subject: [PATCH 08/26] Fixes #254: replaced @Rule by @ClassRule --- doc/ReleaseNotes4.9.html | 2 +- doc/ReleaseNotes4.9.txt | 2 +- src/main/java/org/junit/ClassRule.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ReleaseNotes4.9.html b/doc/ReleaseNotes4.9.html index 231740338557..dc357f4a9616 100644 --- a/doc/ReleaseNotes4.9.html +++ b/doc/ReleaseNotes4.9.html @@ -17,7 +17,7 @@

ClassRule

public class UsesExternalResource { public static Server myServer= new Server(); - @Rule + @ClassRule public static ExternalResource resource= new ExternalResource() { @Override protected void before() throws Throwable { diff --git a/doc/ReleaseNotes4.9.txt b/doc/ReleaseNotes4.9.txt index 5d42d69355e2..74f46d1f49cb 100644 --- a/doc/ReleaseNotes4.9.txt +++ b/doc/ReleaseNotes4.9.txt @@ -17,7 +17,7 @@ all the test classes run, and disconnects after they are finished: public class UsesExternalResource { public static Server myServer= new Server(); - @Rule + @ClassRule public static ExternalResource resource= new ExternalResource() { @Override protected void before() throws Throwable { diff --git a/src/main/java/org/junit/ClassRule.java b/src/main/java/org/junit/ClassRule.java index f12a0f814b5f..813bd3ea0251 100644 --- a/src/main/java/org/junit/ClassRule.java +++ b/src/main/java/org/junit/ClassRule.java @@ -37,7 +37,7 @@ * public class UsesExternalResource { * public static Server myServer= new Server(); * - * @Rule + * @ClassRule * public static ExternalResource resource= new ExternalResource() { * @Override * protected void before() throws Throwable { @@ -57,4 +57,4 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface ClassRule { -} \ No newline at end of file +} From 531d7c869e294d451314261c81837e1d76afb777 Mon Sep 17 00:00:00 2001 From: Stefan Birkner Date: Thu, 7 Jul 2011 10:46:33 -0700 Subject: [PATCH 09/26] added github#254 --- acknowledgements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acknowledgements.txt b/acknowledgements.txt index 05e9558c57e5..bc29cd3ea79e 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -104,6 +104,9 @@ Samuel Le Berrigaud (sleberrigaud@github): Report for GH-248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2 +2011 Jul 06 + Stefan Birkner: Fixed wrong docomentation of ClassRule (github#254). + 2011 Jul 8 Paul Holser (pholser@alumni.rice.edu): Beginnings of fix for GH-64: Theories doesn't honor parameterized types From bcf4785a8ae0ad21ffefd80dcfbb360621d98806 Mon Sep 17 00:00:00 2001 From: Stefan Birkner Date: Fri, 22 Jul 2011 09:44:08 +0200 Subject: [PATCH 10/26] fixed issue #89 (wrong JavaDoc of Parameterized) --- acknowledgements.txt | 3 +++ src/main/java/org/junit/runners/Parameterized.java | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/acknowledgements.txt b/acknowledgements.txt index bc29cd3ea79e..4a9b37d1e184 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -114,5 +114,8 @@ 2011 July 16 Rob Dawson: Submitted a patch that makes Results serlializable. +2011 Jul 22 + Andreas Köhler, Stefan Birkner: Fixed wrong documentation of Parameterized (github#89). + 2011 Aug 7 Esko Luontola: Fixed TemporaryFolder creating files in the current working directory (github#278). diff --git a/src/main/java/org/junit/runners/Parameterized.java b/src/main/java/org/junit/runners/Parameterized.java index 501a5a2748cc..a0ed9f11a1f8 100644 --- a/src/main/java/org/junit/runners/Parameterized.java +++ b/src/main/java/org/junit/runners/Parameterized.java @@ -31,7 +31,6 @@ * @Parameters * public static List<Object[]> data() { * return Arrays.asList(new Object[][] { - * Fibonacci, * { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, * { 6, 8 } } }); * } From 7b5641996d486bbcb33f13a9130821303e1e7d89 Mon Sep 17 00:00:00 2001 From: Stefan Birkner Date: Thu, 28 Jul 2011 09:24:06 +0200 Subject: [PATCH 11/26] fixed issue #134 (wrong JavaDoc of Assert) --- acknowledgements.txt | 3 +++ src/main/java/org/junit/Assert.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/acknowledgements.txt b/acknowledgements.txt index 4a9b37d1e184..4a79411323cd 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -117,5 +117,8 @@ 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 7 Esko Luontola: Fixed TemporaryFolder creating files in the current working directory (github#278). diff --git a/src/main/java/org/junit/Assert.java b/src/main/java/org/junit/Assert.java index 5926872942f6..b585b87524f0 100644 --- a/src/main/java/org/junit/Assert.java +++ b/src/main/java/org/junit/Assert.java @@ -474,7 +474,7 @@ static public void assertEquals(String message, long expected, long actual) { /** * @deprecated Use - * assertEquals(double expected, double actual, double epsilon) + * assertEquals(double expected, double actual, double delta) * instead */ @Deprecated @@ -484,7 +484,7 @@ static public void assertEquals(double expected, double actual) { /** * @deprecated Use - * assertEquals(String message, double expected, double actual, double epsilon) + * assertEquals(String message, double expected, double actual, double delta) * instead */ @Deprecated From 1ad3a59952f3528914d1225d51bbb04adb62c22f Mon Sep 17 00:00:00 2001 From: Stefan Birkner Date: Tue, 9 Aug 2011 22:45:17 +0200 Subject: [PATCH 12/26] Fixed FailOnTimeout class (issue #265) --- acknowledgements.txt | 3 + .../runners/statements/FailOnTimeout.java | 69 +++++++---- .../runners/statements/FailOnTimeoutTest.java | 110 ++++++++++++++++++ 3 files changed, 160 insertions(+), 22 deletions(-) create mode 100644 src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java diff --git a/acknowledgements.txt b/acknowledgements.txt index 4a79411323cd..6992a318b72b 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -114,6 +114,9 @@ 2011 July 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). 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/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 From b00a3cdcaaf0bb554ed0955f98d9f1d759710c27 Mon Sep 17 00:00:00 2001 From: Rodolfo Liviero Date: Mon, 27 Jun 2011 22:00:39 -0300 Subject: [PATCH 13/26] temporary tree folders --- .../java/org/junit/rules/TemporaryFolder.java | 9 +++-- .../rules/TempFolderRuleTest.java | 33 +++++++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/junit/rules/TemporaryFolder.java b/src/main/java/org/junit/rules/TemporaryFolder.java index fb8941eb20b3..d0a28b651784 100644 --- a/src/main/java/org/junit/rules/TemporaryFolder.java +++ b/src/main/java/org/junit/rules/TemporaryFolder.java @@ -59,9 +59,12 @@ public File newFile(String fileName) throws IOException { /** * 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 = folder; + for (String folderName : folderNames) { + file = new File(file, folderName); + file.mkdir(); + } return 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..7f32b25efe1f 100644 --- a/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java +++ b/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java @@ -39,9 +39,36 @@ 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"; + createdFile= folder.newFolder(subfolder); + new File(createdFile, 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"; + + createdFile = folder.newFolder(subfolder, anotherfolder); + new File(createdFile, 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(); } } From 0d8905ec022f2438f6347282a28fc688324b5c57 Mon Sep 17 00:00:00 2001 From: rodolfoliviero Date: Wed, 10 Aug 2011 19:10:21 -0300 Subject: [PATCH 14/26] merge branch 4.10 --- acknowledgements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acknowledgements.txt b/acknowledgements.txt index 655e7f2f4013..1a55cb6ff6c3 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -103,3 +103,6 @@ 2011 Jun 24 Samuel Le Berrigaud (sleberrigaud@github): Report for GH-248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2 + +2011 Ago 10 + rodolfoliviero@github and JoseRibeiro@github: feature to create recursively temp folders From 9dd69e975f1ff0132d4260b671e7b26d1946b283 Mon Sep 17 00:00:00 2001 From: rodolfoliviero Date: Wed, 10 Aug 2011 19:12:14 -0300 Subject: [PATCH 15/26] merge branch 4.10 --- acknowledgements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acknowledgements.txt b/acknowledgements.txt index 1a55cb6ff6c3..a3e4fd97ced2 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -104,5 +104,5 @@ Samuel Le Berrigaud (sleberrigaud@github): Report for GH-248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2 -2011 Ago 10 - rodolfoliviero@github and JoseRibeiro@github: feature to create recursively temp folders +2011 Aug 10 + rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders. From 83219d81d0173d5444c0c127374b1684fc1384df Mon Sep 17 00:00:00 2001 From: Esko Luontola Date: Fri, 12 Aug 2011 00:59:33 +0300 Subject: [PATCH 16/26] Fixes #285: Syntax error in Parameterized's usage example --- acknowledgements.txt | 3 +++ src/main/java/org/junit/runners/Parameterized.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/acknowledgements.txt b/acknowledgements.txt index 6992a318b72b..31cef78a9147 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -125,3 +125,6 @@ 2011 Aug 7 Esko Luontola: Fixed TemporaryFolder creating files in the current working directory (github#278). + +2011 Aug 12 + Esko Luontola: Fixed syntax error in Parameterized's usage example (github#285). 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; From ce867738993339a28fd7b3a25ff1e74dbc0013aa Mon Sep 17 00:00:00 2001 From: Daniel Rothmaler Date: Tue, 24 May 2011 08:27:19 +0200 Subject: [PATCH 17/26] Implemented random temp file/folder creation --- .../java/org/junit/rules/TemporaryFolder.java | 22 +++++- .../rules/TempFolderRuleTest.java | 78 ++++++++++++++++--- 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/junit/rules/TemporaryFolder.java b/src/main/java/org/junit/rules/TemporaryFolder.java index d0a28b651784..7a6182eb4662 100644 --- a/src/main/java/org/junit/rules/TemporaryFolder.java +++ b/src/main/java/org/junit/rules/TemporaryFolder.java @@ -42,9 +42,7 @@ 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(); } /** @@ -56,6 +54,13 @@ public File newFile(String fileName) throws IOException { 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. */ @@ -68,6 +73,17 @@ public File newFolder(String... folderNames) { 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. */ 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 7f32b25efe1f..03386dce856a 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,23 @@ 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.isSuccessful; +import static org.junit.internal.matchers.IsCollectionContaining.hasItem; import java.io.File; import java.io.IOException; +import java.util.Arrays; 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 +25,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 { @@ -41,8 +44,8 @@ public static class CreatesSubFolder { public void testUsingTempFolder() throws IOException { String subfolder = "subfolder"; String filename = "a.txt"; - createdFile= folder.newFolder(subfolder); - new File(createdFile, filename).createNewFile(); + createdFiles[0]= folder.newFolder(subfolder); + new File(createdFiles[0], filename).createNewFile(); File expectedFile = new File(folder.getRoot(), join(subfolder, filename)); @@ -55,8 +58,8 @@ public void testUsingTempTreeFolders() throws IOException { String anotherfolder = "anotherfolder"; String filename = "a.txt"; - createdFile = folder.newFolder(subfolder, anotherfolder); - new File(createdFile, filename).createNewFile(); + createdFiles[0] = folder.newFolder(subfolder, anotherfolder); + new File(createdFiles[0], filename).createNewFile(); File expectedFile = new File(folder.getRoot(), join(subfolder, anotherfolder, filename)); @@ -75,7 +78,54 @@ private String join(String... folderNames) { @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 @@ -88,6 +138,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(); From c60993db6a554db2fe50365ec8f7928a7ea8c3c9 Mon Sep 17 00:00:00 2001 From: Daniel Rothmaler Date: Fri, 24 Jun 2011 23:36:58 +0200 Subject: [PATCH 18/26] added drothmaler to acknowledgements.txt --- acknowledgements.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acknowledgements.txt b/acknowledgements.txt index a3e4fd97ced2..fea779a3224c 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -104,5 +104,10 @@ 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): + #234: random temp file/folder creation + #233: ErrorCollector.checkThat overload + 2011 Aug 10 - rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders. + rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders. \ No newline at end of file From da545cc5f425dd1392ffaa7d2cb8be3b2ef8a179 Mon Sep 17 00:00:00 2001 From: Daniel Rothmaler Date: Fri, 20 May 2011 10:40:09 +0200 Subject: [PATCH 19/26] added ErrorCollector.checkThat overload, that takes a reason --- src/main/java/org/junit/rules/ErrorCollector.java | 14 ++++++++++++++ .../tests/experimental/rules/VerifierRuleTest.java | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/org/junit/rules/ErrorCollector.java b/src/main/java/org/junit/rules/ErrorCollector.java index b48d99d84c12..21c1731ee3fc 100644 --- a/src/main/java/org/junit/rules/ErrorCollector.java +++ b/src/main/java/org/junit/rules/ErrorCollector.java @@ -60,6 +60,20 @@ public Object call() throws Exception { }); } + /** + * 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(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} 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 { From 5c4d8c62e341acb7d46eff730a19b2ce041c2dfe Mon Sep 17 00:00:00 2001 From: Daniel Rothmaler Date: Mon, 23 May 2011 18:35:16 +0200 Subject: [PATCH 20/26] invoke overloaded method with default value, instead of copy&paste --- src/main/java/org/junit/rules/ErrorCollector.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/junit/rules/ErrorCollector.java b/src/main/java/org/junit/rules/ErrorCollector.java index 21c1731ee3fc..3522a654f415 100644 --- a/src/main/java/org/junit/rules/ErrorCollector.java +++ b/src/main/java/org/junit/rules/ErrorCollector.java @@ -52,12 +52,7 @@ 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) { - checkSucceeds(new Callable() { - public Object call() throws Exception { - assertThat(value, matcher); - return value; - } - }); + checkThat("", value, matcher); } /** @@ -75,9 +70,9 @@ public Object call() throws 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. + * 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 { @@ -85,6 +80,6 @@ public Object checkSucceeds(Callable callable) { } catch (Throwable e) { addError(e); return null; - } + } } } \ No newline at end of file From 426f81b822663308176ee3b3a5cc9e912e6c1c87 Mon Sep 17 00:00:00 2001 From: Daniel Rothmaler Date: Thu, 8 Sep 2011 22:59:48 +0200 Subject: [PATCH 21/26] fixed acknowledgements.txt to match the new pull request numbers --- acknowledgements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acknowledgements.txt b/acknowledgements.txt index fea779a3224c..8f1ebb8c263c 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -106,8 +106,8 @@ 2011 Jun 24 Daniel Rothmaler (drothmaler@github): - #234: random temp file/folder creation - #233: ErrorCollector.checkThat overload + #299: random temp file/folder creation + #300: ErrorCollector.checkThat overload 2011 Aug 10 - rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders. \ No newline at end of file + rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders. From 74b8fc6a4c11d1fd6d584733398a77b83c54e6b6 Mon Sep 17 00:00:00 2001 From: Daniel Rothmaler Date: Thu, 8 Sep 2011 23:49:42 +0200 Subject: [PATCH 22/26] Updated build and release notes to 4.10 --- build.xml | 4 ++-- doc/ReleaseNotes4.10.html | 18 ++++++++++++++++++ doc/ReleaseNotes4.10.txt | 14 ++++++++++++++ src/main/java/junit/runner/Version.java | 2 +- 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 doc/ReleaseNotes4.10.html create mode 100644 doc/ReleaseNotes4.10.txt diff --git a/build.xml b/build.xml index 4a5a20a82938..9ac785086375 100644 --- a/build.xml +++ b/build.xml @@ -6,8 +6,8 @@ - - + + 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/src/main/java/junit/runner/Version.java b/src/main/java/junit/runner/Version.java index d9f38adece9c..e397900549e8 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.9b3"; + return "4.10snapshot"; } public static void main(String[] args) { From ada8735cda0fe94c9cfea9b8fb2012488a3a44e6 Mon Sep 17 00:00:00 2001 From: Stefan Birkner Date: Fri, 9 Sep 2011 02:32:53 +0200 Subject: [PATCH 23/26] fixed issue #296 (TestWatcher and TestWatchman don't call fail when assumption is violated) --- acknowledgements.txt | 4 ++ .../java/org/junit/rules/TestWatcher.java | 3 + .../java/org/junit/rules/TestWatchman.java | 3 + .../rules/LoggingTestWatcher.java | 32 +++++++++ .../experimental/rules/TestRuleTest.java | 42 ++++------- .../experimental/rules/TestWatcherTest.java | 52 ++++++++++++++ .../experimental/rules/TestWatchmanTest.java | 71 +++++++++++++++++++ 7 files changed, 180 insertions(+), 27 deletions(-) create mode 100644 src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java create mode 100644 src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java create mode 100644 src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java diff --git a/acknowledgements.txt b/acknowledgements.txt index 0d70914839af..d1e081a3f34b 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -124,3 +124,7 @@ 2011 Aug 09 Stefan Birkner: Fixed JavaDoc links. + +2011 Sep 09 + Robert Munteanu, Stefan Birkner: + TestWatcher and TestWatchman don't call failed when assumption is violated (github#296). 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/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/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 From 39545426e07dcb3bb3d71c930451514ba54c5999 Mon Sep 17 00:00:00 2001 From: Stefan Birkner Date: Fri, 9 Sep 2011 01:17:39 +0200 Subject: [PATCH 24/26] fixed issue #289 (removed useless code) --- acknowledgements.txt | 1 + .../java/org/junit/internal/runners/statements/RunAfters.java | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/acknowledgements.txt b/acknowledgements.txt index d1e081a3f34b..faf45c54e490 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -128,3 +128,4 @@ 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). 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) { From 84c4caaeb54249eed291274914ef6391622e07e3 Mon Sep 17 00:00:00 2001 From: David Saff Date: Tue, 13 Sep 2011 17:49:39 -0300 Subject: [PATCH 25/26] Set master version to 4.10.1 in build.xml --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index a4baad8a1c62..5db70b794f49 100644 --- a/build.xml +++ b/build.xml @@ -6,7 +6,7 @@ - + From 96df21cba5e56ee6d78fe51e86b4cc2bd2ceaf30 Mon Sep 17 00:00:00 2001 From: David Saff Date: Tue, 13 Sep 2011 17:57:11 -0300 Subject: [PATCH 26/26] Backed version up to 4.10. Oops. --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 5db70b794f49..a4baad8a1c62 100644 --- a/build.xml +++ b/build.xml @@ -6,7 +6,7 @@ - +