Permalink
Browse files

Merge branch 'master' of git://github.com/KentBeck/junit

  • Loading branch information...
2 parents 5d9e002 + 45eaab7 commit f0319c2af61edbf587b958e9aa2f0f75eed2b375 Jesse Glick committed Jan 31, 2012
Showing with 1,224 additions and 154 deletions.
  1. +8 −5 build.xml
  2. +82 −7 doc/ReleaseNotes4.10.html
  3. +77 −7 doc/ReleaseNotes4.10.txt
  4. +1 −0 doc/ReleaseNotes4.11.html
  5. +1 −0 doc/ReleaseNotes4.11.txt
  6. +1 −1 src/main/java/junit/runner/Version.java
  7. +12 −2 src/main/java/org/junit/Assert.java
  8. +31 −5 src/main/java/org/junit/ClassRule.java
  9. +29 −6 src/main/java/org/junit/Rule.java
  10. +50 −30 src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java
  11. +19 −14 src/main/java/org/junit/rules/TemporaryFolder.java
  12. +1 −8 src/main/java/org/junit/runner/JUnitCore.java
  13. +22 −10 src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
  14. +46 −36 src/main/java/org/junit/runners/Parameterized.java
  15. +7 −1 src/main/java/org/junit/runners/ParentRunner.java
  16. +4 −0 src/main/java/org/junit/runners/model/FrameworkField.java
  17. +6 −1 src/main/java/org/junit/runners/model/FrameworkMember.java
  18. +33 −1 src/main/java/org/junit/runners/model/FrameworkMethod.java
  19. +16 −0 src/main/java/org/junit/runners/model/TestClass.java
  20. +7 −3 src/test/java/org/junit/tests/AllTests.java
  21. +137 −1 src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java
  22. +93 −0 src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java
  23. +144 −0 src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java
  24. +365 −1 src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
  25. +32 −15 src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
View
13 build.xml
@@ -7,7 +7,7 @@
<property name="src" value="src/main/java" />
<property name="target" location="target" />
<property name="bin" location="${target}/main" />
- <property name="version-base" value="4.10" />
+ <property name="version-base" value="4.11" />
<property name="version-status" value="-SNAPSHOT" />
<property name="version" value="${version-base}${version-status}" />
<property name="dist" value="junit${version}" />
@@ -133,7 +133,8 @@
<target name="release-notes">
<property name="basename" value="doc/ReleaseNotes${version-base}" />
- <exec executable="build/Markdown.pl" failonerror="true">
+ <exec executable="perl" failonerror="true">
+ <arg file="build/Markdown.pl"/>
<arg file="${basename}.txt"/>
<redirector output="${basename}.html" />
</exec>
@@ -270,7 +271,7 @@
url="@{url}" repo.id="@{repo.id}" />
<if>
- <equals arg1="${is.snapshot}" arg2="false" />
+ <equals arg1="@{is.snapshot}" arg2="false" />
<then>
<push.maven.jar jar="${m.sources.jar}" pom="${m.pom}"
url="@{url}" repo.id="@{repo.id}">
@@ -293,10 +294,12 @@
<push.maven.artifact artifactId="junit"
url="${stage.url}"
- repo.id="${stage.repo.id}" />
+ repo.id="${stage.repo.id}"
+ is.snapshot="false" />
<push.maven.artifact artifactId="junit-dep"
url="${stage.url}"
- repo.id="${stage.repo.id}" />
+ repo.id="${stage.repo.id}"
+ is.snapshot="false" />
</target>
<target name="snapshot.maven" depends="all.maven.jars">
View
89 doc/ReleaseNotes4.10.html
@@ -1,18 +1,93 @@
<h2>Summary of Changes in version 4.10 [unreleased!]</h2>
-<h3>Bug fixes</h3>
+<p>A full summary of commits between 4.9 and 4.10 is on <a href="https://github.com/KentBeck/junit/compare/r4.9...4.10">github</a></p>
-<h3>Minor changes</h3>
+<h3>junit-dep has correct contents</h3>
+
+<p>junit-dep-4.9.jar incorrectly contained hamcrest classes, which could lead to version conflicts in projects that depend on hamcrest directly. This is fixed in 4.10 [@dsaff, closing gh-309]</p>
+
+<h3>RuleChain</h3>
+
+<p>The RuleChain rule allows ordering of TestRules:</p>
+
+<pre><code>public static class UseRuleChain {
+ @Rule
+ public TestRule chain= RuleChain
+ .outerRule(new LoggingRule("outer rule")
+ .around(new LoggingRule("middle rule")
+ .around(new LoggingRule("inner rule");
-<p>Thanks to <code>@rodolfoliviero</code> for:</p>
+ @Test
+ public void example() {
+ assertTrue(true);
+ }
+}
+</code></pre>
+
+<p>writes the log</p>
+
+<pre><code>starting outer rule
+starting middle rule
+starting inner rule
+finished inner rule
+finished middle rule
+finished outer rule
+</code></pre>
+
+<h3>TemporaryFolder</h3>
<ul>
-<li>github#283: Feature to create recursive temporary folders.</li>
+<li><code>TemporaryFolder#newFolder(String... folderNames)</code> creates recursively deep temporary folders
+[@rodolfoliviero, closing gh-283]</li>
+<li><code>TemporaryFolder#newFile()</code> creates a randomly named new file, and <code>#newFolder()</code> creates a randomly named new folder
+[@Daniel Rothmaler, closing gh-299]</li>
</ul>
-<p>Thanks to <code>@drothmaler</code> for:</p>
+<h3>Theories</h3>
+
+<p>The <code>Theories</code> runner does not anticipate theory parameters that have generic
+types, as reported by github#64. Fixing this won't happen until <code>Theories</code> 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 <code>Theories</code> runner uses, <code>FrameworkMethod</code>#producesType().
+The Common Public License that JUnit is released under is now included
+in the source repository.</p>
+
+<p>Thanks to <code>@pholser</code> for identifying a potential resolution for github#64
+and initiating work on it.</p>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>Built-in Rules implementations
+<ul>
+<li>TemporaryFolder should not create files in the current working directory if applying the rule fails
+[@orfjackal, fixing gh-278]</li>
+<li>TestWatcher and TestWatchman should not call failed for AssumptionViolatedExceptions
+[@stefanbirkner, fixing gh-296]</li>
+</ul></li>
+<li>Javadoc bugs
+<ul>
+<li>Assert documentation [@stefanbirkner, fixing gh-134]</li>
+<li>ClassRule [@stefanbirkner, fixing gh-254]</li>
+<li>Parameterized [@stefanbirkner, fixing gh-89]</li>
+<li>Parameterized, again [@orfjackal, fixing gh-285]</li>
+</ul></li>
+<li>Miscellaneous
+<ul>
+<li>Useless code in RunAfters [@stefanbirkner, fixing gh-289]</li>
+<li>Parameterized test classes should be able to have <code>@Category</code> annotations
+[@dsaff, fixing gh-291]</li>
+<li>Error count should be initialized in junit.tests.framework.TestListenerTest [@stefanbirkner, fixing gh-225]</li>
+<li>AssertionFailedError constructor shouldn't call super with null message [@stefanbirkner, fixing gh-318]</li>
+<li>Clearer error message for non-static inner test classes [@stefanbirkner, fixing gh-42]</li>
+</ul></li>
+</ul>
+
+<h3>Minor changes</h3>
<ul>
-<li>github#299: Random temporary file/folder creation</li>
-<li>github#300: New <code>ErrorCollector.checkThat</code> overload, that allows you to specify a reason</li>
+<li>Description, Result and Failure are Serializable [@ephox-rob, closing gh-101]</li>
+<li>FailOnTimeout is reusable, allowing for retrying Rules [@stefanbirkner, closing gh-265]</li>
+<li>New <code>ErrorCollector.checkThat</code> overload, that allows you to specify a reason [@drothmaler, closing gh-300]</li>
</ul>
View
84 doc/ReleaseNotes4.10.txt
@@ -1,14 +1,84 @@
-## Summary of Changes in version 4.10 [unreleased!] ##
+## Summary of Changes in version 4.10 ##
+
+Thanks to a full cast of contributors of bug fixes and new features.
+
+A full summary of commits between 4.9 and 4.10 is on [github](https://github.com/KentBeck/junit/compare/r4.9...4.10)
+
+### junit-dep has correct contents ###
+
+junit-dep-4.9.jar incorrectly contained hamcrest classes, which could lead to version conflicts in projects that depend on hamcrest directly. This is fixed in 4.10 [@dsaff, closing gh-309]
+
+### RuleChain ###
+
+The RuleChain rule allows ordering of TestRules:
+
+ public static class UseRuleChain {
+ @Rule
+ public TestRule chain= RuleChain
+ .outerRule(new LoggingRule("outer rule")
+ .around(new LoggingRule("middle rule")
+ .around(new LoggingRule("inner rule");
+
+ @Test
+ public void example() {
+ assertTrue(true);
+ }
+ }
+
+writes the log
+
+ starting outer rule
+ starting middle rule
+ starting inner rule
+ finished inner rule
+ finished middle rule
+ finished outer rule
+
+### TemporaryFolder ###
+
+- `TemporaryFolder#newFolder(String... folderNames)` creates recursively deep temporary folders
+ [@rodolfoliviero, closing gh-283]
+- `TemporaryFolder#newFile()` creates a randomly named new file, and `#newFolder()` creates a randomly named new folder
+ [@Daniel Rothmaler, closing gh-299]
+
+### 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.
### Bug fixes ###
-
+
+- Built-in Rules implementations
+ - TemporaryFolder should not create files in the current working directory if applying the rule fails
+ [@orfjackal, fixing gh-278]
+ - TestWatcher and TestWatchman should not call failed for AssumptionViolatedExceptions
+ [@stefanbirkner, fixing gh-296]
+- Javadoc bugs
+ - Assert documentation [@stefanbirkner, fixing gh-134]
+ - ClassRule [@stefanbirkner, fixing gh-254]
+ - Parameterized [@stefanbirkner, fixing gh-89]
+ - Parameterized, again [@orfjackal, fixing gh-285]
+- Miscellaneous
+ - Useless code in RunAfters [@stefanbirkner, fixing gh-289]
+ - Parameterized test classes should be able to have `@Category` annotations
+ [@dsaff, fixing gh-291]
+ - Error count should be initialized in junit.tests.framework.TestListenerTest [@stefanbirkner, fixing gh-225]
+ - AssertionFailedError constructor shouldn't call super with null message [@stefanbirkner, fixing gh-318]
+ - Clearer error message for non-static inner test classes [@stefanbirkner, fixing gh-42]
+
### Minor changes ###
-Thanks to `@rodolfoliviero` for:
+- Description, Result and Failure are Serializable [@ephox-rob, closing gh-101]
+- FailOnTimeout is reusable, allowing for retrying Rules [@stefanbirkner, closing gh-265]
+- New `ErrorCollector.checkThat` overload, that allows you to specify a reason [@drothmaler, closing gh-300]
-- 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
View
1 doc/ReleaseNotes4.11.html
@@ -0,0 +1 @@
+<h2>Summary of Changes in version 4.11 [unreleased!]</h2>
View
1 doc/ReleaseNotes4.11.txt
@@ -0,0 +1 @@
+## Summary of Changes in version 4.11 [unreleased!] ##
View
2 src/main/java/junit/runner/Version.java
@@ -9,7 +9,7 @@ private Version() {
}
public static String id() {
- return "4.10-SNAPSHOT";
+ return "4.11-SNAPSHOT";
}
public static void main(String[] args) {
View
14 src/main/java/org/junit/Assert.java
@@ -721,6 +721,11 @@ public static void assertEquals(Object[] expecteds, Object[] actuals) {
* // got value: &lt;0&gt;
* assertThat(0, is(not(1))) // passes
* </pre>
+ *
+ * <code>org.hamcrest.Matcher</code> does not currently document the meaning
+ * of its type parameter <code>T</code>. This method assumes that a matcher
+ * typed as <code>Matcher&lt;T&gt;</code> can be meaningfully applied only
+ * to values that could be assigned to a variable of type <code>T</code>.
*
* @param <T>
* the static type accepted by the matcher (this can flag obvious
@@ -734,7 +739,7 @@ public static void assertEquals(Object[] expecteds, Object[] actuals) {
* @see org.hamcrest.CoreMatchers
* @see org.junit.matchers.JUnitMatchers
*/
- public static <T> void assertThat(T actual, Matcher<T> matcher) {
+ public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
assertThat("", actual, matcher);
}
@@ -753,6 +758,11 @@ public static void assertEquals(Object[] expecteds, Object[] actuals) {
* assertThat(&quot;Zero is one&quot;, 0, is(not(1))) // passes
* </pre>
*
+ * <code>org.hamcrest.Matcher</code> does not currently document the meaning
+ * of its type parameter <code>T</code>. This method assumes that a matcher
+ * typed as <code>Matcher&lt;T&gt;</code> can be meaningfully applied only
+ * to values that could be assigned to a variable of type <code>T</code>.
+ *
* @param reason
* additional information about the error
* @param <T>
@@ -768,7 +778,7 @@ public static void assertEquals(Object[] expecteds, Object[] actuals) {
* @see org.junit.matchers.JUnitMatchers
*/
public static <T> void assertThat(String reason, T actual,
- Matcher<T> matcher) {
+ Matcher<? super T> matcher) {
if (!matcher.matches(actual)) {
Description description= new StringDescription();
description.appendText(reason);
View
36 src/main/java/org/junit/ClassRule.java
@@ -6,8 +6,9 @@
import java.lang.annotation.Target;
/**
- * Annotates static fields that contain rules. Such a field must be public,
- * static, and a subtype of {@link org.junit.rules.TestRule}.
+ * Annotates static fields that contain rules or methods that return them. A field must be public,
+ * static, and a subtype of {@link org.junit.rules.TestRule}. A method must be public static, and return
+ * a subtype of {@link org.junit.rules.TestRule}
* The {@link org.junit.runners.model.Statement} passed
* to the {@link org.junit.rules.TestRule} will run any {@link BeforeClass} methods,
* then the entire body of the test class (all contained methods, if it is
@@ -25,13 +26,13 @@
* If there are multiple
* annotated {@link ClassRule}s on a class, they will be applied in an order
* that depends on your JVM's implementation of the reflection API, which is
- * undefined, in general.
+ * undefined, in general. However, Rules defined by fields will always be applied
+ * before Rules defined by methods.
*
* For example, here is a test suite that connects to a server once before
* all the test classes run, and disconnects after they are finished:
*
* <pre>
- *
* &#064;RunWith(Suite.class)
* &#064;SuiteClasses({A.class, B.class, C.class})
* public class UsesExternalResource {
@@ -52,9 +53,34 @@
* }
* </pre>
*
+ * and the same using a method
+ *
+ * <pre>
+ * &#064;RunWith(Suite.class)
+ * &#064;SuiteClasses({A.class, B.class, C.class})
+ * public class UsesExternalResource {
+ * public static Server myServer= new Server();
+ *
+ * &#064;ClassRule
+ * public static ExternalResource getResource() {
+ * return new ExternalResource() {
+ * &#064;Override
+ * protected void before() throws Throwable {
+ * myServer.connect();
+ * }
+ *
+ * &#064;Override
+ * protected void after() {
+ * myServer.disconnect();
+ * }
+ * };
+ * }
+ * }
+ * </pre>
+ *
* For more information and more examples, see {@link org.junit.rules.TestRule}.
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
+@Target({ElementType.FIELD, ElementType.METHOD})
public @interface ClassRule {
}
View
35 src/main/java/org/junit/Rule.java
@@ -6,15 +6,18 @@
import java.lang.annotation.Target;
/**
- * Annotates fields that contain rules. Such a field must be public, not
- * static, and a subtype of {@link org.junit.rules.TestRule}.
+ * Annotates fields that contain rules or methods that return a rule. A field must be public, not
+ * static, and a subtype of {@link org.junit.rules.TestRule}. A method must be public, not static
+ * and must return a subtype of {@link org.junit.rules.TestRule}.
* The {@link org.junit.runners.model.Statement} passed
* to the {@link org.junit.rules.TestRule} will run any {@link Before} methods,
* then the {@link Test} method, and finally any {@link After} methods,
* throwing an exception if any of these fail. If there are multiple
- * annotated {@link Rule}s on a class, they will be applied in an order
+ * annotated {@link Rule}s on a class, they will be applied in order of fields first, then methods.
+ * However, if there are mutliple fields (or methods) they will be applied in an order
* that depends on your JVM's implementation of the reflection API, which is
- * undefined, in general.
+ * undefined, in general. Rules defined by fields will always be applied
+ * before Rules defined by methods.
*
* For example, here is a test class that creates a temporary folder before
* each test method, and deletes it after each:
@@ -33,15 +36,35 @@
* }
* </pre>
*
+ * And the same using a method.
+ *
+ * <pre>
+ * public static class HasTempFolder {
+ * private TemporaryFolder folder= new TemporaryFolder();
+ *
+ * &#064;Rule
+ * public TemporaryFolder getFolder() {
+ * return folder;
+ * }
+ *
+ * &#064;Test
+ * public void testUsingTempFolder() throws IOException {
+ * File createdFile= folder.newFile(&quot;myfile.txt&quot;);
+ * File createdFolder= folder.newFolder(&quot;subfolder&quot;);
+ * // ...
+ * }
+ * }
+ * </pre>
+ *
* For more information and more examples, see
* {@link org.junit.rules.TestRule}.
*
* Note: for backwards compatibility, this annotation may also mark
- * fields of type {@link org.junit.rules.MethodRule}, which will be honored. However,
+ * fields or methods of type {@link org.junit.rules.MethodRule}, which will be honored. However,
* this is a deprecated interface and feature.
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
+@Target({ElementType.FIELD, ElementType.METHOD})
public @interface Rule {
}
View
80 src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java
@@ -5,37 +5,52 @@
import org.junit.ClassRule;
import org.junit.Rule;
+import org.junit.rules.MethodRule;
import org.junit.rules.TestRule;
-import org.junit.runners.model.FrameworkField;
+import org.junit.runners.model.FrameworkMember;
import org.junit.runners.model.TestClass;
/**
* A RuleFieldValidator validates the rule fields of a
* {@link org.junit.runners.model.TestClass}. All reasons for rejecting the
* {@code TestClass} are written to a list of errors.
*
- * There are two slightly different validators. The {@link #CLASS_RULE_VALIDATOR}
+ * There are four slightly different validators. The {@link #CLASS_RULE_VALIDATOR}
* validates fields with a {@link ClassRule} annotation and the
* {@link #RULE_VALIDATOR} validates fields with a {@link Rule} annotation.
+ *
+ * The {@link #CLASS_RULE_METHOD_VALIDATOR}
+ * validates methods with a {@link ClassRule} annotation and the
+ * {@link #RULE_METHOD_VALIDATOR} validates methods with a {@link Rule} annotation.
*/
public enum RuleFieldValidator {
/**
* Validates fields with a {@link ClassRule} annotation.
*/
- CLASS_RULE_VALIDATOR(ClassRule.class, true),
+ CLASS_RULE_VALIDATOR(ClassRule.class, false, true),
/**
* Validates fields with a {@link Rule} annotation.
*/
- RULE_VALIDATOR(Rule.class, false);
+ RULE_VALIDATOR(Rule.class, false, false),
+ /**
+ * Validates methods with a {@link ClassRule} annotation.
+ */
+ CLASS_RULE_METHOD_VALIDATOR(ClassRule.class, true, true),
+ /**
+ * Validates methods with a {@link Rule} annotation.
+ */
+ RULE_METHOD_VALIDATOR(Rule.class, true, false);
private final Class<? extends Annotation> fAnnotation;
- private final boolean fOnlyStaticFields;
+ private final boolean fStaticMembers;
+ private final boolean fMethods;
private RuleFieldValidator(Class<? extends Annotation> annotation,
- boolean onlyStaticFields) {
+ boolean methods, boolean fStaticMembers) {
this.fAnnotation= annotation;
- this.fOnlyStaticFields= onlyStaticFields;
+ this.fStaticMembers= fStaticMembers;
+ this.fMethods= methods;
}
/**
@@ -45,48 +60,53 @@ private RuleFieldValidator(Class<? extends Annotation> annotation,
* @param errors the list of errors.
*/
public void validate(TestClass target, List<Throwable> errors) {
- List<FrameworkField> fields= target.getAnnotatedFields(fAnnotation);
- for (FrameworkField each : fields)
- validateField(each, errors);
+ List<? extends FrameworkMember<?>> members= fMethods ? target.getAnnotatedMethods(fAnnotation)
+ : target.getAnnotatedFields(fAnnotation);
+
+ for (FrameworkMember<?> each : members)
+ validateMember(each, errors);
}
- private void validateField(FrameworkField field, List<Throwable> errors) {
- optionallyValidateStatic(field, errors);
- validatePublic(field, errors);
- validateTestRuleOrMethodRule(field, errors);
+ private void validateMember(FrameworkMember<?> member, List<Throwable> errors) {
+ validateStatic(member, errors);
+ validatePublic(member, errors);
+ validateTestRuleOrMethodRule(member, errors);
}
- private void optionallyValidateStatic(FrameworkField field,
+ private void validateStatic(FrameworkMember<?> member,
List<Throwable> errors) {
- if (fOnlyStaticFields && !field.isStatic())
- addError(errors, field, "must be static.");
+ if (fStaticMembers && !member.isStatic())
+ addError(errors, member, "must be static.");
+ if (!fStaticMembers && member.isStatic())
+ addError(errors, member, "must not be static.");
}
- private void validatePublic(FrameworkField field, List<Throwable> errors) {
- if (!field.isPublic())
- addError(errors, field, "must be public.");
+ private void validatePublic(FrameworkMember<?> member, List<Throwable> errors) {
+ if (!member.isPublic())
+ addError(errors, member, "must be public.");
}
- private void validateTestRuleOrMethodRule(FrameworkField field,
+ private void validateTestRuleOrMethodRule(FrameworkMember<?> member,
List<Throwable> errors) {
- if (!isMethodRule(field) && !isTestRule(field))
- addError(errors, field, "must implement MethodRule or TestRule.");
+ if (!isMethodRule(member) && !isTestRule(member))
+ addError(errors, member, fMethods ?
+ "must return an implementation of MethodRule or TestRule." :
+ "must implement MethodRule or TestRule.");
}
- private boolean isTestRule(FrameworkField target) {
- return TestRule.class.isAssignableFrom(target.getType());
+ private boolean isTestRule(FrameworkMember<?> member) {
+ return TestRule.class.isAssignableFrom(member.getType());
}
@SuppressWarnings("deprecation")
- private boolean isMethodRule(FrameworkField target) {
- return org.junit.rules.MethodRule.class.isAssignableFrom(target
- .getType());
+ private boolean isMethodRule(FrameworkMember<?> member) {
+ return MethodRule.class.isAssignableFrom(member.getType());
}
- private void addError(List<Throwable> errors, FrameworkField field,
+ private void addError(List<Throwable> errors, FrameworkMember<?> member,
String suffix) {
String message= "The @" + fAnnotation.getSimpleName() + " '"
- + field.getName() + "' " + suffix;
+ + member.getName() + "' " + suffix;
errors.add(new Exception(message));
}
}
View
33 src/main/java/org/junit/rules/TemporaryFolder.java
@@ -39,10 +39,10 @@ protected void after() {
// testing purposes only
/**
- * for testing purposes only. Do not use.
+ * for testing purposes only. Do not use.
*/
public void create() throws IOException {
- folder= newFolder();
+ folder= createTemporaryFolderIn(null);
}
/**
@@ -58,27 +58,31 @@ public File newFile(String fileName) throws IOException {
* Returns a new fresh file with a random name under the temporary folder.
*/
public File newFile() throws IOException {
- return File.createTempFile("junit", null, folder);
+ return File.createTempFile("junit", null, getRoot());
}
/**
- * Returns a new fresh folder with the given name under the temporary folder.
+ * Returns a new fresh folder with the given name under the temporary
+ * folder.
*/
public File newFolder(String... folderNames) {
- File file = getRoot();
+ File file= getRoot();
for (String folderName : folderNames) {
- file = new File(file, folderName);
+ file= new File(file, folderName);
file.mkdir();
}
return file;
}
/**
- * Returns a new fresh folder with a random name under the temporary
- * folder.
+ * Returns a new fresh folder with a random name under the temporary folder.
*/
public File newFolder() throws IOException {
- File createdFolder= File.createTempFile("junit", "", folder);
+ return createTemporaryFolderIn(getRoot());
+ }
+
+ private File createTemporaryFolderIn(File parentFolder) throws IOException {
+ File createdFolder= File.createTempFile("junit", "", parentFolder);
createdFolder.delete();
createdFolder.mkdir();
return createdFolder;
@@ -89,18 +93,19 @@ public File newFolder() throws IOException {
*/
public File getRoot() {
if (folder == null) {
- throw new IllegalStateException("the temporary folder has not yet been created");
+ throw new IllegalStateException(
+ "the temporary folder has not yet been created");
}
return folder;
}
/**
- * Delete all files and folders under the temporary folder.
- * Usually not called directly, since it is automatically applied
- * by the {@link Rule}
+ * Delete all files and folders under the temporary folder. Usually not
+ * called directly, since it is automatically applied by the {@link Rule}
*/
public void delete() {
- recursiveDelete(folder);
+ if (folder != null)
+ recursiveDelete(folder);
}
private void recursiveDelete(File file) {
View
9 src/main/java/org/junit/runner/JUnitCore.java
@@ -25,14 +25,7 @@
* @see org.junit.runner.Request
*/
public class JUnitCore {
- private RunNotifier fNotifier;
-
- /**
- * Create a new <code>JUnitCore</code> to run tests.
- */
- public JUnitCore() {
- fNotifier= new RunNotifier();
- }
+ private final RunNotifier fNotifier= new RunNotifier();
/**
* Run the tests contained in the classes named in the <code>args</code>.
View
32 src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
@@ -1,6 +1,7 @@
package org.junit.runners;
import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_METHOD_VALIDATOR;
import java.util.List;
@@ -101,6 +102,7 @@ protected void collectInitializationErrors(List<Throwable> errors) {
validateConstructor(errors);
validateInstanceMethods(errors);
validateFields(errors);
+ validateMethods(errors);
}
protected void validateNoNonStaticInnerClass(List<Throwable> errors) {
@@ -170,6 +172,10 @@ private void validateFields(List<Throwable> errors) {
RULE_VALIDATOR.validate(getTestClass(), errors);
}
+ private void validateMethods(List<Throwable> errors) {
+ RULE_METHOD_VALIDATOR.validate(getTestClass(), errors);
+ }
+
/**
* Adds to {@code errors} for each method annotated with {@code @Test}that
* is not a public, void instance method with no arguments.
@@ -326,16 +332,17 @@ protected Statement withAfters(FrameworkMethod method, Object target,
private Statement withRules(FrameworkMethod method, Object target,
Statement statement) {
+ List<TestRule> testRules= getTestRules(target);
Statement result= statement;
- result= withMethodRules(method, target, result);
- result= withTestRules(method, target, result);
+ result= withMethodRules(method, testRules, target, result);
+ result= withTestRules(method, testRules, result);
+
return result;
}
@SuppressWarnings("deprecation")
- private Statement withMethodRules(FrameworkMethod method, Object target,
- Statement result) {
- List<TestRule> testRules= getTestRules(target);
+ private Statement withMethodRules(FrameworkMethod method, List<TestRule> testRules,
+ Object target, Statement result) {
for (org.junit.rules.MethodRule each : getMethodRules(target))
if (! testRules.contains(each))
result= each.apply(result, method, target);
@@ -365,14 +372,14 @@ private Statement withMethodRules(FrameworkMethod method, Object target,
/**
* Returns a {@link Statement}: apply all non-static {@link Value} fields
* annotated with {@link Rule}.
- *
+ * @param method
+ * @param testRules
* @param statement The base statement
* @return a RunRules statement if any class-level {@link Rule}s are
* found, or the base statement
*/
- private Statement withTestRules(FrameworkMethod method, Object target,
+ private Statement withTestRules(FrameworkMethod method, List<TestRule> testRules,
Statement statement) {
- List<TestRule> testRules= getTestRules(target);
return testRules.isEmpty() ? statement :
new RunRules(statement, testRules, describeChild(method));
}
@@ -384,10 +391,15 @@ private Statement withTestRules(FrameworkMethod method, Object target,
* test
*/
protected List<TestRule> getTestRules(Object target) {
- return getTestClass().getAnnotatedFieldValues(target,
+ List<TestRule> result = getTestClass().getAnnotatedMethodValues(target,
Rule.class, TestRule.class);
- }
+
+ result.addAll(getTestClass().getAnnotatedFieldValues(target,
+ Rule.class, TestRule.class));
+ return result;
+ }
+
private Class<? extends Throwable> getExpectedException(Test annotation) {
if (annotation == null || annotation.expected() == None.class)
return null;
View
82 src/main/java/org/junit/runners/Parameterized.java
@@ -1,11 +1,12 @@
package org.junit.runners;
+import static java.lang.String.format;
+
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -15,7 +16,6 @@
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
-import org.junit.runners.model.TestClass;
/**
* <p>
@@ -30,10 +30,9 @@
* &#064;RunWith(Parameterized.class)
* public class FibonacciTest {
* &#064;Parameters
- * public static List&lt;Object[]&gt; data() {
- * return Arrays.asList(new Object[][] {
- * { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
- * });
+ * public static Iterable&lt;Object[]&gt; data() {
+ * return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
+ * { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
* }
*
* private int fInput;
@@ -72,30 +71,18 @@
BlockJUnit4ClassRunner {
private final int fParameterSetNumber;
- private final List<Object[]> fParameterList;
+ private final Object[] fParameters;
- TestClassRunnerForParameters(Class<?> type,
- List<Object[]> parameterList, int i) throws InitializationError {
+ TestClassRunnerForParameters(Class<?> type, Object[] parameters, int i)
+ throws InitializationError {
super(type);
- fParameterList= parameterList;
+ fParameters= parameters;
fParameterSetNumber= i;
}
@Override
public Object createTest() throws Exception {
- return getTestClass().getOnlyConstructor().newInstance(
- computeParams());
- }
-
- private Object[] computeParams() throws Exception {
- try {
- return fParameterList.get(fParameterSetNumber);
- } catch (ClassCastException e) {
- throw new Exception(String.format(
- "%s.%s() must return a Collection of arrays.",
- getTestClass().getName(), getParametersMethod(
- getTestClass()).getName()));
- }
+ return getTestClass().getOnlyConstructor().newInstance(fParameters);
}
@Override
@@ -131,11 +118,9 @@ protected Statement classBlock(RunNotifier notifier) {
* Only called reflectively. Do not use programmatically.
*/
public Parameterized(Class<?> klass) throws Throwable {
- super(klass, Collections.<Runner>emptyList());
- List<Object[]> parametersList= getParametersList(getTestClass());
- for (int i= 0; i < parametersList.size(); i++)
- runners.add(new TestClassRunnerForParameters(getTestClass().getJavaClass(),
- parametersList, i));
+ super(klass, Collections.<Runner> emptyList());
+ Iterable<Object[]> allParameters= getAllParameters();
+ createRunnersForParameters(allParameters);
}
@Override
@@ -144,24 +129,49 @@ public Parameterized(Class<?> klass) throws Throwable {
}
@SuppressWarnings("unchecked")
- private List<Object[]> getParametersList(TestClass klass)
+ private Iterable<Object[]> getAllParameters()
throws Throwable {
- return (List<Object[]>) getParametersMethod(klass).invokeExplosively(
- null);
+ Object parameters= getParametersMethod().invokeExplosively(null);
+ if (parameters instanceof Iterable)
+ return (Iterable<Object[]>) parameters;
+ else
+ throw parametersMethodReturnedWrongType();
}
- private FrameworkMethod getParametersMethod(TestClass testClass)
+ private FrameworkMethod getParametersMethod()
throws Exception {
- List<FrameworkMethod> methods= testClass
+ List<FrameworkMethod> methods= getTestClass()
.getAnnotatedMethods(Parameters.class);
for (FrameworkMethod each : methods) {
- int modifiers= each.getMethod().getModifiers();
- if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
+ if (each.isStatic() && each.isPublic())
return each;
}
throw new Exception("No public static parameters method on class "
- + testClass.getName());
+ + getTestClass().getName());
}
+ private void createRunnersForParameters(Iterable<Object[]> allParameters)
+ throws InitializationError, Exception {
+ try {
+ int i= 0;
+ for (Object[] parametersOfSingleTest : allParameters) {
+ TestClassRunnerForParameters runner= new TestClassRunnerForParameters(
+ getTestClass().getJavaClass(), parametersOfSingleTest,
+ i);
+ runners.add(runner);
+ ++i;
+ }
+ } catch (ClassCastException e) {
+ throw parametersMethodReturnedWrongType();
+ }
+ }
+
+ private Exception parametersMethodReturnedWrongType() throws Exception {
+ String className= getTestClass().getName();
+ String methodName= getParametersMethod().getName();
+ String message= format("%s.%s() must return an Iterable of arrays.",
+ className, methodName);
+ return new Exception(message);
+ }
}
View
8 src/main/java/org/junit/runners/ParentRunner.java
@@ -1,6 +1,7 @@
package org.junit.runners;
import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_METHOD_VALIDATOR;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@@ -133,6 +134,7 @@ protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annota
private void validateClassRules(List<Throwable> errors) {
CLASS_RULE_VALIDATOR.validate(getTestClass(), errors);
+ CLASS_RULE_METHOD_VALIDATOR.validate(getTestClass(), errors);
}
/**
@@ -207,7 +209,11 @@ private Statement withClassRules(Statement statement) {
* each method in the tested class.
*/
protected List<TestRule> classRules() {
- return fTestClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class);
+ List<TestRule> result= fTestClass.getAnnotatedMethodValues(null, ClassRule.class, TestRule.class);
+
+ result.addAll(fTestClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class));
+
+ return result;
}
/**
View
4 src/main/java/org/junit/runners/model/FrameworkField.java
@@ -17,6 +17,7 @@
fField= field;
}
+ @Override
public String getName() {
return getField().getName();
}
@@ -26,6 +27,7 @@ public String getName() {
return fField.getAnnotations();
}
+ @Override
public boolean isPublic() {
int modifiers= fField.getModifiers();
return Modifier.isPublic(modifiers);
@@ -36,6 +38,7 @@ public boolean isShadowedBy(FrameworkField otherMember) {
return otherMember.getName().equals(getName());
}
+ @Override
public boolean isStatic() {
int modifiers= fField.getModifiers();
return Modifier.isStatic(modifiers);
@@ -52,6 +55,7 @@ public Field getField() {
* @return the underlying Java Field type
* @see java.lang.reflect.Field#getType()
*/
+ @Override
public Class<?> getType() {
return fField.getType();
}
View
7 src/main/java/org/junit/runners/model/FrameworkMember.java
@@ -3,7 +3,7 @@
import java.lang.annotation.Annotation;
import java.util.List;
-abstract class FrameworkMember<T extends FrameworkMember<T>> {
+public abstract class FrameworkMember<T extends FrameworkMember<T>> {
/**
* Returns the annotations on this method
*/
@@ -17,4 +17,9 @@ boolean isShadowedBy(List<T> members) {
return true;
return false;
}
+
+ public abstract boolean isPublic();
+ public abstract boolean isStatic();
+ public abstract String getName();
+ public abstract Class<?> getType();
}
View
34 src/main/java/org/junit/runners/model/FrameworkMethod.java
@@ -50,6 +50,7 @@ protected Object runReflectiveCall() throws Throwable {
/**
* Returns the method's name
*/
+ @Override
public String getName() {
return fMethod.getName();
}
@@ -90,6 +91,37 @@ public void validatePublicVoid(boolean isStatic, List<Throwable> errors) {
if (fMethod.getReturnType() != Void.TYPE)
errors.add(new Exception("Method " + fMethod.getName() + "() should be void"));
}
+
+ /**
+ * Returns true if this method is static, false if not
+ */
+ @Override
+ public boolean isStatic() {
+ return Modifier.isStatic(fMethod.getModifiers());
+ }
+
+ /**
+ * Returns true if this method is public, false if not
+ */
+ @Override
+ public boolean isPublic() {
+ return Modifier.isPublic(fMethod.getModifiers());
+ }
+
+ /**
+ * Returns the return type of the method
+ */
+ public Class<?> getReturnType() {
+ return fMethod.getReturnType();
+ }
+
+ /**
+ * Returns the return type of the method
+ */
+ @Override
+ public Class<?> getType() {
+ return getReturnType();
+ }
public void validateNoTypeParametersOnArgs(List<Throwable> errors) {
new NoGenericTypeParametersValidator(fMethod).validate(errors);
@@ -120,7 +152,7 @@ public int hashCode() {
}
/**
- * Returns true iff this is a no-arg method that returns a value assignable
+ * Returns true if 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
View
16 src/main/java/org/junit/runners/model/TestClass.java
@@ -154,6 +154,22 @@ public String getName() {
return results;
}
+ public <T> List<T> getAnnotatedMethodValues(Object test,
+ Class<? extends Annotation> annotationClass, Class<T> valueClass) {
+ List<T> results= new ArrayList<T>();
+ for (FrameworkMethod each : getAnnotatedMethods(annotationClass)) {
+ try {
+ Object fieldValue= each.invokeExplosively(test, new Object[]{});
+ if (valueClass.isInstance(fieldValue))
+ results.add(valueClass.cast(fieldValue));
+ } catch (Throwable e) {
+ throw new RuntimeException(
+ "Exception in " + each.getName(), e);
+ }
+ }
+ return results;
+ }
+
public boolean isANonStaticInnerClass() {
return fClass.isMemberClass() && !isStatic(fClass.getModifiers());
}
View
10 src/test/java/org/junit/tests/AllTests.java
@@ -29,8 +29,10 @@
import org.junit.tests.experimental.rules.ExternalResourceRuleTest;
import org.junit.tests.experimental.rules.MethodRulesTest;
import org.junit.tests.experimental.rules.NameRulesTest;
+import org.junit.tests.experimental.rules.RuleFieldValidatorTest;
import org.junit.tests.experimental.rules.RuleChainTest;
import org.junit.tests.experimental.rules.TempFolderRuleTest;
+import org.junit.tests.experimental.rules.TemporaryFolderUsageTest;
import org.junit.tests.experimental.rules.TestRuleTest;
import org.junit.tests.experimental.rules.TimeoutRuleTest;
import org.junit.tests.experimental.rules.VerifierRuleTest;
@@ -77,7 +79,7 @@
import org.junit.tests.validation.InaccessibleBaseClassTest;
import org.junit.tests.validation.ValidationTest;
-// These test files need to be cleaned. See
+// These test files need to be cleaned. See
// https://sourceforge.net/pm/task.php?func=detailtask&project_task_id=136507&group_id=15278&group_project_id=51407
@SuppressWarnings("deprecation")
@@ -147,14 +149,16 @@
ClassRulesTest.class,
ExpectedExceptionRuleTest.class,
TempFolderRuleTest.class,
+ TemporaryFolderUsageTest.class,
ExternalResourceRuleTest.class,
VerifierRuleTest.class,
CategoryTest.class,
CategoriesAndParameterizedTest.class,
ParentRunnerFilteringTest.class,
+ BlockJUnit4ClassRunnerOverrideTest.class,
+ RuleFieldValidatorTest.class,
RuleChainTest.class,
- BlockJUnit4ClassRunnerTest.class,
- BlockJUnit4ClassRunnerOverrideTest.class
+ BlockJUnit4ClassRunnerTest.class
})
public class AllTests {
public static Test suite() {
View
138 src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java
@@ -4,18 +4,28 @@
package org.junit.tests.experimental.rules;
import static org.junit.Assert.assertEquals;
+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 java.util.LinkedList;
+import java.util.List;
+
import org.junit.ClassRule;
import org.junit.Test;
-import org.junit.rules.TestRule;
import org.junit.rules.ExternalResource;
+import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runners.model.Statement;
/**
* Tests to exercise class-level rules.
+ * This test class is very similar to {@link ClassRulesMethodTest}. If you add a test here, then it is likely that the other will have to be changed.
+ * This tests {@link ClassRule}s attached to fields.
+ * {@link ClassRulesMethodTest} tests {@link ClassRule}s attached to methods.
*/
public class ClassRulesTest {
public static class Counter extends ExternalResource {
@@ -98,4 +108,130 @@ public void customRuleIsAppliedOnce() {
assertTrue(result.wasSuccessful());
assertEquals(1, ExampleTestWithCustomClassRule.counter.count);
}
+
+ private static final List<String> orderList= new LinkedList<String>();
+
+ private static class OrderTestRule implements TestRule {
+ private String name;
+
+ public OrderTestRule(String name) {
+ this.name= name;
+ }
+
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ orderList.add(name);
+ base.evaluate();
+ }
+ };
+ }
+ };
+
+ public static class UsesFieldAndMethodRule {
+ @ClassRule public static OrderTestRule orderMethod() { return new OrderTestRule("orderMethod"); }
+ @ClassRule public static OrderTestRule orderField= new OrderTestRule("orderField");
+ @Test public void foo() {
+ assertEquals("orderField", orderList.get(0));
+ assertEquals("orderMethod", orderList.get(1));
+ }
+ }
+
+ @Test public void usesFieldAndMethodRule() {
+ orderList.clear();
+ assertThat(testResult(UsesFieldAndMethodRule.class), isSuccessful());
+ }
+
+
+ public static class MethodExampleTestWithClassRule {
+ private static Counter counter= new Counter();
+
+ @ClassRule
+ public static Counter getCounter() {
+ return counter;
+ }
+
+ @Test
+ public void firstTest() {
+ assertEquals(1, counter.count);
+ }
+
+ @Test
+ public void secondTest() {
+ assertEquals(1, counter.count);
+ }
+ }
+
+ @Test
+ public void methodRuleIsAppliedOnce() {
+ MethodExampleTestWithClassRule.counter.count= 0;
+ JUnitCore.runClasses(MethodExampleTestWithClassRule.class);
+ assertEquals(1, MethodExampleTestWithClassRule.counter.count);
+ }
+
+ public static class MethodSubclassOfTestWithClassRule extends
+ MethodExampleTestWithClassRule {
+
+ }
+
+ @Test
+ public void methodRuleIsIntroducedAndEvaluatedOnSubclass() {
+ MethodExampleTestWithClassRule.counter.count= 0;
+ JUnitCore.runClasses(MethodSubclassOfTestWithClassRule.class);
+ assertEquals(1, MethodExampleTestWithClassRule.counter.count);
+ }
+
+ public static class MethodExampleTestWithCustomClassRule {
+ private static CustomCounter counter= new CustomCounter();
+
+ @ClassRule
+ public static CustomCounter getCounter() {
+ return counter;
+ }
+
+ @Test
+ public void firstTest() {
+ assertEquals(1, counter.count);
+ }
+
+ @Test
+ public void secondTest() {
+ assertEquals(1, counter.count);
+ }
+ }
+
+
+ @Test
+ public void methodCustomRuleIsAppliedOnce() {
+ MethodExampleTestWithCustomClassRule.counter.count= 0;
+ Result result= JUnitCore.runClasses(MethodExampleTestWithCustomClassRule.class);
+ assertTrue(result.wasSuccessful());
+ assertEquals(1, MethodExampleTestWithCustomClassRule.counter.count);
+ }
+
+ public static class CallMethodOnlyOnceRule {
+ static int countOfMethodCalls = 0;
+ private static class Dummy implements TestRule {
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ base.evaluate();
+ };
+ };
+ }
+ }
+ @ClassRule public static Dummy both() { countOfMethodCalls++; return new Dummy(); }
+
+ @Test public void onlyOnce() {
+ assertEquals(1, countOfMethodCalls);
+ }
+ }
+
+ @Test
+ public void testCallMethodOnlyOnceRule() {
+ CallMethodOnlyOnceRule.countOfMethodCalls = 0;
+ assertTrue(JUnitCore.runClasses(CallMethodOnlyOnceRule.class).wasSuccessful());
+ }
}
View
93 src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java
@@ -1,7 +1,9 @@
package org.junit.tests.experimental.rules;
import static org.junit.Assert.assertEquals;
+import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_METHOD_VALIDATOR;
import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_METHOD_VALIDATOR;
import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_VALIDATOR;
import java.util.ArrayList;
@@ -58,6 +60,18 @@ public void acceptNonStaticTestRule() {
}
@Test
+ public void rejectStaticTestRule() {
+ TestClass target= new TestClass(TestWithStaticTestRule.class);
+ RULE_VALIDATOR.validate(target, errors);
+ assertOneErrorWithMessage("The @Rule 'temporaryFolder' must not be static.");
+ }
+
+ public static class TestWithStaticTestRule {
+ @Rule
+ public static TestRule temporaryFolder = new TemporaryFolder();
+ }
+
+ @Test
public void acceptMethodRule() throws Exception {
TestClass target= new TestClass(TestWithMethodRule.class);
RULE_VALIDATOR.validate(target, errors);
@@ -85,6 +99,85 @@ public void rejectArbitraryObjectWithRuleAnnotation() throws Exception {
public Object arbitraryObject = 1;
}
+ @Test
+ public void methodRejectProtectedClassRule() {
+ TestClass target= new TestClass(MethodTestWithProtectedClassRule.class);
+ CLASS_RULE_METHOD_VALIDATOR.validate(target, errors);
+ assertOneErrorWithMessage("The @ClassRule 'getTemporaryFolder' must be public.");
+ }
+
+ public static class MethodTestWithProtectedClassRule {
+ @ClassRule
+ protected static TestRule getTemporaryFolder() {
+ return new TemporaryFolder();
+ }
+ }
+
+ @Test
+ public void methodRejectNonStaticClassRule() {
+ TestClass target= new TestClass(MethodTestWithNonStaticClassRule.class);
+ CLASS_RULE_METHOD_VALIDATOR.validate(target, errors);
+ assertOneErrorWithMessage("The @ClassRule 'getTemporaryFolder' must be static.");
+ }
+
+ public static class MethodTestWithNonStaticClassRule {
+ @ClassRule
+ public TestRule getTemporaryFolder() { return new TemporaryFolder(); }
+ }
+
+ @Test
+ public void acceptMethodNonStaticTestRule() {
+ TestClass target= new TestClass(TestMethodWithNonStaticTestRule.class);
+ RULE_METHOD_VALIDATOR.validate(target, errors);
+ assertNumberOfErrors(0);
+ }
+
+ public static class TestMethodWithNonStaticTestRule {
+ @Rule
+ public TestRule getTemporaryFolder() { return new TemporaryFolder(); }
+ }
+
+ @Test
+ public void rejectMethodStaticTestRule() {
+ TestClass target= new TestClass(TestMethodWithStaticTestRule.class);
+ RULE_METHOD_VALIDATOR.validate(target, errors);
+ assertOneErrorWithMessage("The @Rule 'getTemporaryFolder' must not be static.");
+ }
+
+ public static class TestMethodWithStaticTestRule {
+ @Rule
+ public static TestRule getTemporaryFolder() { return new TemporaryFolder(); }
+ }
+
+ @Test
+ public void methodAcceptMethodRuleMethod() throws Exception {
+ TestClass target= new TestClass(MethodTestWithMethodRule.class);
+ RULE_METHOD_VALIDATOR.validate(target, errors);
+ assertNumberOfErrors(0);
+ }
+
+ public static class MethodTestWithMethodRule {
+ @Rule
+ public MethodRule getTemporaryFolder() { return new MethodRule(){
+ public Statement apply(Statement base, FrameworkMethod method,
+ Object target) {
+ return null;
+ }};
+ }
+ }
+
+ @Test
+ public void methodRejectArbitraryObjectWithRuleAnnotation() throws Exception {
+ TestClass target= new TestClass(MethodTestWithArbitraryObjectWithRuleAnnotation.class);
+ RULE_METHOD_VALIDATOR.validate(target, errors);
+ assertOneErrorWithMessage("The @Rule 'getArbitraryObject' must return an implementation of MethodRule or TestRule.");
+ }
+
+ public static class MethodTestWithArbitraryObjectWithRuleAnnotation {
+ @Rule
+ public Object getArbitraryObject() { return 1; }
+ }
+
private void assertOneErrorWithMessage(String message) {
assertNumberOfErrors(1);
assertEquals("Wrong error message:", message, errors.get(0).getMessage());
View
144 src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java
@@ -0,0 +1,144 @@
+package org.junit.tests.experimental.rules;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * <tt>TemporaryFolderUsageTest</tt> provides tests for API usage correctness
+ * and ensure implementation symmetry of public methods against a root folder.
+ */
+public class TemporaryFolderUsageTest {
+
+ private TemporaryFolder tempFolder;
+
+ @Before
+ public void setUp() {
+ tempFolder= new TemporaryFolder();
+ }
+
+ @After
+ public void tearDown() {
+ tempFolder.delete();
+ }
+
+ @Test(expected= IllegalStateException.class)
+ public void getRootShouldThrowIllegalStateExceptionIfCreateWasNotInvoked() {
+ new TemporaryFolder().getRoot();
+ }
+
+ @Test(expected= IllegalStateException.class)
+ public void newFileThrowsIllegalStateExceptionIfCreateWasNotInvoked()
+ throws IOException {
+ new TemporaryFolder().newFile();
+ }
+
+ @Test(expected= IllegalStateException.class)
+ public void newFileWithGivenNameThrowsIllegalStateExceptionIfCreateWasNotInvoked()
+ throws IOException {
+ new TemporaryFolder().newFile("MyFile.txt");
+ }
+
+ @Test(expected= IllegalStateException.class)
+ public void newFolderThrowsIllegalStateExceptionIfCreateWasNotInvoked()
+ throws IOException {
+ new TemporaryFolder().newFolder();
+ }
+
+ @Test(expected= IllegalStateException.class)
+ public void newFolderWithGivenPathThrowsIllegalStateExceptionIfCreateWasNotInvoked() {
+ new TemporaryFolder().newFolder("level1", "leve2", "leve3");
+ }
+
+ @Test
+ public void createInitializesRootFolder() throws IOException {
+ tempFolder.create();
+ assertFileExists(tempFolder.getRoot());
+ }
+
+ @Test
+ public void deleteShouldDoNothingIfRootFolderWasNotInitialized() {
+ tempFolder.delete();
+ }
+
+ @Test
+ public void deleteRemovesRootFolder() throws IOException {
+ tempFolder.create();
+ tempFolder.delete();
+ assertFileDoesNotExist(tempFolder.getRoot());
+ }
+
+ @Test
+ public void newRandomFileIsCreatedUnderRootFolder() throws IOException {
+ tempFolder.create();
+
+ File f= tempFolder.newFile();
+ assertFileExists(f);
+ assertFileCreatedUnderRootFolder("Random file", f);
+ }
+
+ @Test
+ public void newNamedFileIsCreatedUnderRootFolder() throws IOException {
+ final String fileName= "SampleFile.txt";
+ tempFolder.create();
+
+ File f= tempFolder.newFile(fileName);
+
+ assertFileExists(f);
+ assertFileCreatedUnderRootFolder("Named file", f);
+ assertThat("file name", f.getName(), equalTo(fileName));
+ }
+
+ @Test
+ public void newRandomFolderIsCreatedUnderRootFolder() throws IOException {
+ tempFolder.create();
+
+ File f= tempFolder.newFolder();
+ assertFileExists(f);
+ assertFileCreatedUnderRootFolder("Random folder", f);
+ }
+
+ @Test
+ public void newNestedFoldersCreatedUnderRootFolder() throws IOException {
+ tempFolder.create();
+
+ File f= tempFolder.newFolder("top", "middle", "bottom");
+ assertFileExists(f);
+ assertParentFolderForFileIs(f, new File(tempFolder.getRoot(),
+ "top/middle"));
+ assertParentFolderForFileIs(f.getParentFile(),
+ new File(tempFolder.getRoot(), "top"));
+ assertFileCreatedUnderRootFolder("top", f.getParentFile()
+ .getParentFile());
+ }
+
+ private void assertFileDoesNotExist(File file) {
+ checkFileExists("exists", file, false);
+ }
+
+ private void checkFileExists(String msg, File file, boolean exists) {
+ assertThat("File is null", file, is(notNullValue()));
+ assertThat("File '" + file.getAbsolutePath() + "' " + msg,
+ file.exists(), is(exists));
+ }
+
+ private void assertFileExists(File file) {
+ checkFileExists("does not exist", file, true);
+ }
+
+ private void assertFileCreatedUnderRootFolder(String msg, File f) {
+ assertParentFolderForFileIs(f, tempFolder.getRoot());
+ }
+
+ private void assertParentFolderForFileIs(File f, File parentFolder) {
+ assertThat("'" + f.getAbsolutePath() + "': not under root",
+ f.getParentFile(), is(parentFolder));
+ }
+}
View
366 src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
@@ -9,6 +9,10 @@
import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
import static org.junit.experimental.results.ResultMatchers.isSuccessful;
import static org.junit.matchers.JUnitMatchers.containsString;
+
+import java.util.LinkedList;
+import java.util.List;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -22,6 +26,11 @@
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
+/**
+ * This test class is very similar to {@link TestMethodRuleTest}. If you add a test here, then it is likely that the other will have to be changed.
+ * This tests {@link Rule}s attached to fields.
+ * {@link TestMethodRuleTest} tests {@link Rule}s attached to methods.
+ */
public class TestRuleTest {
private static boolean wasRun;
@@ -286,4 +295,359 @@ public void evaluate() throws Throwable {
@Test public void useCustomMethodRule() {
assertThat(testResult(UsesCustomMethodRule.class), isSuccessful());
}
-}
+
+ public static class MethodExampleTest {
+ private TestRule example = new TestRule() {
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ wasRun= true;
+ base.evaluate();
+ };
+ };
+ }
+ };
+
+ @Rule
+ public TestRule getExample() {
+ return example;
+ }
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void methodRuleIsIntroducedAndEvaluated() {
+ wasRun= false;
+ JUnitCore.runClasses(MethodExampleTest.class);
+ assertTrue(wasRun);
+ }
+
+ @SuppressWarnings("deprecation")
+ public static class MethodBothKindsOfRule implements TestRule, org.junit.rules.MethodRule {
+ public int applications = 0;
+
+ public Statement apply(Statement base, FrameworkMethod method,
+ Object target) {
+ applications++;
+ return base;
+ }
+
+ public Statement apply(Statement base, Description description) {
+ applications++;
+ return base;
+ }
+ }
+
+ public static class MethodOneFieldTwoKindsOfRule {
+ private MethodBothKindsOfRule both = new MethodBothKindsOfRule();
+
+ @Rule
+ public MethodBothKindsOfRule getBoth() {
+ return both;
+ }
+
+ @Test public void onlyOnce() {
+ assertEquals(1, both.applications);
+ }
+ }
+
+
+ @Test
+ public void methodOnlyApplyOnceEvenIfImplementsBothInterfaces() {
+ assertTrue(JUnitCore.runClasses(MethodOneFieldTwoKindsOfRule.class).wasSuccessful());
+ }
+
+ public static class MethodSonOfExampleTest extends MethodExampleTest {
+
+ }
+
+ @Test
+ public void methodRuleIsIntroducedAndEvaluatedOnSubclass() {
+ wasRun= false;
+ JUnitCore.runClasses(MethodSonOfExampleTest.class);
+ assertTrue(wasRun);
+ }
+
+// private static int runCount;
+
+ public static class MethodMultipleRuleTest {
+ private static class Increment implements TestRule {
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ runCount++;
+ base.evaluate();
+ };
+ };
+ }
+ }
+
+ private TestRule incrementor1= new Increment();
+
+ @Rule
+ public TestRule getIncrementor1() {
+ return incrementor1;
+ }
+
+ private TestRule incrementor2= new Increment();
+
+ @Rule
+ public TestRule getIncrementor2() {
+ return incrementor2;
+ }
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void methodMultipleRulesAreRun() {
+ runCount= 0;
+ JUnitCore.runClasses(MethodMultipleRuleTest.class);
+ assertEquals(2, runCount);
+ }
+
+ public static class MethodNoRulesTest {
+ public int x;
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void methodIgnoreNonRules() {
+ Result result= JUnitCore.runClasses(MethodNoRulesTest.class);
+ assertEquals(0, result.getFailureCount());
+ }
+
+ public static class MethodOnFailureTest {
+ private TestRule watchman= new TestWatcher() {
+ @Override
+ protected void failed(Throwable e, Description description) {
+ log+= description + " " + e.getClass().getSimpleName();
+ }
+ };
+
+ @Rule
+ public TestRule getWatchman() {
+ return watchman;
+ }
+
+ @Test
+ public void nothing() {
+ fail();
+ }
+ }
+
+ @Test
+ public void methodOnFailure() {
+ log= "";
+ Result result= JUnitCore.runClasses(MethodOnFailureTest.class);
+ assertEquals(String.format("nothing(%s) AssertionError", MethodOnFailureTest.class.getName()), log);
+ assertEquals(1, result.getFailureCount());
+ }
+
+ public static class MethodWatchmanTest {
+ private static String watchedLog;
+
+ private TestRule watchman= new TestWatcher() {
+ @Override
+ protected void failed(Throwable e, Description description) {
+ watchedLog+= description + " "
+ + e.getClass().getSimpleName() + "\n";
+ }
+
+ @Override
+ protected void succeeded(Description description) {
+ watchedLog+= description + " " + "success!\n";
+ }
+ };
+
+ @Rule
+ public TestRule getWatchman() {
+ return watchman;
+ }
+
+ @Test
+ public void fails() {
+ fail();
+ }
+
+ @Test
+ public void succeeds() {
+ }
+ }
+
+ @Test
+ public void methodSucceeded() {
+ WatchmanTest.watchedLog= "";
+ JUnitCore.runClasses(WatchmanTest.class);
+ assertThat(WatchmanTest.watchedLog, containsString(String.format("fails(%s) AssertionError", WatchmanTest.class.getName())));
+ assertThat(WatchmanTest.watchedLog, containsString(String.format("succeeds(%s) success!", WatchmanTest.class.getName())));
+ }
+
+ public static class MethodBeforesAndAfters {
+ private static String watchedLog;
+
+ @Before public void before() {
+ watchedLog+= "before ";
+ }
+
+ private 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 ";
+ }
+ };
+
+ @Rule
+ public TestRule getWatchman() {
+ return watchman;
+ }
+
+ @After public void after() {
+ watchedLog+= "after ";
+ }
+
+ @Test
+ public void succeeds() {
+ watchedLog+= "test ";
+ }
+ }
+
+ @Test
+ public void methodBeforesAndAfters() {
+ MethodBeforesAndAfters.watchedLog= "";
+ JUnitCore.runClasses(MethodBeforesAndAfters.class);
+ assertThat(MethodBeforesAndAfters.watchedLog, is("starting before test after succeeded finished "));
+ }
+
+ public static class MethodWrongTypedField {
+ @Rule public int getX() { return 5; }
+ @Test public void foo() {}
+ }
+
+ @Test public void methodValidateWrongTypedField() {
+ assertThat(testResult(MethodWrongTypedField.class),
+ hasSingleFailureContaining("must return an implementation of MethodRule"));
+ }
+
+ public static class MethodSonOfWrongTypedField extends MethodWrongTypedField {
+
+ }
+
+ @Test public void methodValidateWrongTypedFieldInSuperclass() {
+ assertThat(testResult(MethodSonOfWrongTypedField.class),
+ hasSingleFailureContaining("must return an implementation of MethodRule"));
+ }
+
+ public static class MethodPrivateRule {
+ @SuppressWarnings("unused")
+ @Rule private TestRule getRule() { return new TestName(); }
+ @Test public void foo() {}
+ }
+
+ @Test public void methodValidatePrivateRule() {
+ assertThat(testResult(MethodPrivateRule.class),
+ hasSingleFailureContaining("must be public"));
+ }
+
+ public static class MethodUsesCustomMethodRule {
+ private CustomTestName counter = new CustomTestName();
+ @Rule public CustomTestName getCounter() { return counter; }
+ @Test public void foo() {
+ assertEquals("foo", counter.name);
+ }
+ }
+
+ @Test public void methodUseCustomMethodRule() {
+ assertThat(testResult(MethodUsesCustomMethodRule.class), isSuccessful());
+ }
+
+ private static final List<String> orderList= new LinkedList<String>();
+
+ private static class OrderTestRule implements TestRule {
+ private String name;
+
+ public OrderTestRule(String name) {
+ this.name= name;
+ }
+
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ orderList.add(name);
+ base.evaluate();
+ }
+ };
+ }
+ };
+
+ public static class UsesFieldAndMethodRule {
+ @Rule public OrderTestRule orderMethod() { return new OrderTestRule("orderMethod"); }
+ @Rule public OrderTestRule orderField= new OrderTestRule("orderField");
+ @Test public void foo() {
+ assertEquals("orderField", orderList.get(0));
+ assertEquals("orderMethod", orderList.get(1));
+ }
+ }
+
+ @Test public void usesFieldAndMethodRule() {
+ orderList.clear();
+ assertThat(testResult(UsesFieldAndMethodRule.class), isSuccessful());
+ }
+
+ public static class MultipleCallsTest implements TestRule {
+ public int applications = 0;
+
+ public Statement apply(Statement base, Description description) {
+ applications++;
+ return base;
+ }
+ }
+
+ public static class CallMethodOnlyOnceRule {
+ int countOfMethodCalls = 0;
+ private static class Dummy implements TestRule {
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ base.evaluate();
+ };
+ };
+ }
+ }
+ @Rule public Dummy both() { countOfMethodCalls++; return new Dummy(); }
+
+ @Test public void onlyOnce() {
+ assertEquals(1, countOfMethodCalls);
+ }
+ }
+
+ @Test
+ public void testCallMethodOnlyOnceRule() {
+ assertTrue(JUnitCore.runClasses(CallMethodOnlyOnceRule.class).wasSuccessful());
+ }
+}
View
47 src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
@@ -26,7 +26,7 @@
@RunWith(Parameterized.class)
static public class FibonacciTest {
@Parameters
- public static Collection<Object[]> data() {
+ public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
{ 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
}
@@ -60,9 +60,9 @@ public void count() {
@Test
public void failuresNamedCorrectly() {
Result result= JUnitCore.runClasses(FibonacciTest.class);
- assertEquals(String
- .format("test[1](%s)", FibonacciTest.class.getName()), result
- .getFailures().get(0).getTestHeader());
+ assertEquals(
+ String.format("test[1](%s)", FibonacciTest.class.getName()),
+ result.getFailures().get(0).getTestHeader());
}
@Test
@@ -141,7 +141,7 @@ public int test() {
@Parameters
public static Collection<Object[]> data() {
- return Collections.singletonList(new Object[] {1});
+ return Collections.singletonList(new Object[] { 1 });
}
}
@@ -175,7 +175,7 @@ public void meaningfulFailureWhenParametersNotPublic() throws Exception {
@RunWith(Parameterized.class)
static public class WrongElementType {
@Parameters
- public static Collection<String> data() {
+ public static Iterable<String> data() {
return Arrays.asList("a", "b", "c");
}
@@ -185,14 +185,31 @@ public void aTest() {
}
@Test
- public void meaningfulFailureWhenParameterListsAreNotArrays() {
- String expected= String.format(
- "%s.data() must return a Collection of arrays.",
- WrongElementType.class.getName());
- assertThat(testResult(WrongElementType.class).toString(),
- containsString(expected));
+ public void meaningfulFailureWhenParametersAreNotArrays() {
+ assertThat(
+ testResult(WrongElementType.class).toString(),
+ containsString("WrongElementType.data() must return an Iterable of arrays."));
+ }
+
+ @RunWith(Parameterized.class)
+ static public class ParametersNotIterable {
+ @Parameters
+ public static String data() {
+ return "foo";
+ }
+
+ @Test
+ public void aTest() {
+ }
+ }
+
+ @Test
+ public void meaningfulFailureWhenParametersAreNotAnIterable() {
+ assertThat(
+ testResult(ParametersNotIterable.class).toString(),
+ containsString("ParametersNotIterable.data() must return an Iterable of arrays."));
}
-
+
@RunWith(Parameterized.class)
static public class PrivateConstructor {
private PrivateConstructor(int x) {
@@ -208,8 +225,8 @@ private PrivateConstructor(int x) {
public void aTest() {
}
}
-
- @Test(expected=InitializationError.class)
+
+ @Test(expected= InitializationError.class)
public void exceptionWhenPrivateConstructor() throws Throwable {
new Parameterized(PrivateConstructor.class);
}

0 comments on commit f0319c2

Please sign in to comment.