Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merging from remote

  • Loading branch information...
commit 45cee89178172749b7f75be3944d9aa367d97373 2 parents dcd07b1 + db9a456
@detinho authored
Showing with 2,972 additions and 324 deletions.
  1. +49 −1 acknowledgements.txt
  2. +63 −22 build.xml
  3. BIN  build/lib/ant-contrib-1.0b3.jar
  4. 0  { → build/maven}/pom-template.xml
  5. +49 −0 build/maven/post_maven_tests.sh
  6. +61 −0 build/maven/sample_project_template/pom.xml
  7. +33 −0 build/maven/sample_project_template/src/test/java/JunitDependencyTest.java
  8. +36 −0 build/run_tests.sh
  9. +1 −34 build_tests.sh
  10. +93 −0 doc/ReleaseNotes4.10.html
  11. +84 −0 doc/ReleaseNotes4.10.txt
  12. +1 −0  doc/ReleaseNotes4.11.html
  13. +1 −0  doc/ReleaseNotes4.11.txt
  14. +14 −0 doc/ReleaseNotes4.9.1.txt
  15. +1 −1  doc/ReleaseNotes4.9.html
  16. +1 −1  doc/ReleaseNotes4.9.txt
  17. +0 −12 pom-template.xml.asc
  18. +5 −1 src/main/java/junit/framework/AssertionFailedError.java
  19. +2 −1  src/main/java/junit/framework/TestSuite.java
  20. +1 −1  src/main/java/junit/runner/Version.java
  21. +14 −4 src/main/java/org/junit/Assert.java
  22. +32 −6 src/main/java/org/junit/ClassRule.java
  23. +29 −6 src/main/java/org/junit/Rule.java
  24. +1 −0  src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java
  25. +35 −0 src/main/java/org/junit/internal/MethodSorter.java
  26. +2 −1  src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java
  27. +2 −1  src/main/java/org/junit/internal/runners/TestClass.java
  28. +112 −0 src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java
  29. +47 −22 src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
  30. +0 −1  src/main/java/org/junit/internal/runners/statements/RunAfters.java
  31. +14 −5 src/main/java/org/junit/rules/ErrorCollector.java
  32. +99 −0 src/main/java/org/junit/rules/RuleChain.java
  33. +41 −14 src/main/java/org/junit/rules/TemporaryFolder.java
  34. +3 −0  src/main/java/org/junit/rules/TestWatcher.java
  35. +3 −0  src/main/java/org/junit/rules/TestWatchman.java
  36. +4 −2 src/main/java/org/junit/runner/Description.java
  37. +1 −8 src/main/java/org/junit/runner/JUnitCore.java
  38. +3 −1 src/main/java/org/junit/runner/Result.java
  39. +3 −1 src/main/java/org/junit/runner/notification/Failure.java
  40. +36 −37 src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
  41. +52 −36 src/main/java/org/junit/runners/Parameterized.java
  42. +23 −22 src/main/java/org/junit/runners/ParentRunner.java
  43. +20 −1 src/main/java/org/junit/runners/model/FrameworkField.java
  44. +6 −1 src/main/java/org/junit/runners/model/FrameworkMember.java
  45. +48 −5 src/main/java/org/junit/runners/model/FrameworkMethod.java
  46. +53 −0 src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
  47. +25 −2 src/main/java/org/junit/runners/model/TestClass.java
  48. +3 −1 src/test/java/junit/samples/SimpleTest.java
  49. +1 −0  src/test/java/junit/tests/framework/AllTests.java
  50. +23 −0 src/test/java/junit/tests/framework/AssertionFailedErrorTest.java
  51. +1 −0  src/test/java/junit/tests/framework/TestListenerTest.java
  52. +2 −1  src/test/java/junit/tests/runner/AllTests.java
  53. +37 −0 src/test/java/junit/tests/runner/ResultTest.java
  54. +34 −0 src/test/java/org/junit/internal/MethodSorterTest.java
  55. +3 −1 src/test/java/org/junit/samples/SimpleTest.java
  56. +10 −2 src/test/java/org/junit/tests/AllTests.java
  57. +32 −16 src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java
  58. +0 −2  src/test/java/org/junit/tests/experimental/categories/CategoryTest.java
  59. +137 −1 src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java
  60. +32 −0 src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java
  61. +60 −0 src/test/java/org/junit/tests/experimental/rules/RuleChainTest.java
  62. +189 −0 src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java
  63. +137 −8 src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java
  64. +144 −0 src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java
  65. +378 −26 src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
  66. +52 −0 src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java
  67. +72 −0 src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java
  68. +8 −0 src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
  69. +177 −0 ...test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java
  70. +110 −0 src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java
  71. +33 −0 src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java
  72. +32 −15 src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
  73. +27 −1 src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java
  74. +35 −0 src/test/java/org/junit/tests/running/classes/TestClassTest.java
View
50 acknowledgements.txt
@@ -104,8 +104,56 @@
Samuel Le Berrigaud (sleberrigaud@github): Report for GH-248:
protected BlockJUnit4ClassRunner#rules method removed from 4.8.2
+2011 Jun 24
+ Daniel Rothmaler (drothmaler@github):
+ #299: random temp file/folder creation
+ #300: ErrorCollector.checkThat overload
+
2011 Jul 06
- Stefan Birkner: Fixed wrong docomentation of ClassRule (github#254).
+ Stefan Birkner: Fixed wrong documentation of ClassRule (github#254).
+
+2011 Jul 08
+ Paul Holser (pholser@alumni.rice.edu): Beginnings of fix for GH-64:
+ Theories doesn't honor parameterized types
+
+2011 Jul 09
+ Nigel Charman: Reported Rules bugs github#257 and gihub#258.
+
+2011 Jul 09
+ Stefan Birkner: Fixed rules bugs (github#257, gihub#258, github#260).
+
+2011 Jul 09
+ Stefan Birkner: Fixed rules bugs (github#257, gihub#258, github#260).
+
+2011 Jul 16
+ Rob Dawson: Submitted a patch that makes Results serlializable.
+
+2011 Jul 20
+ Asaf Ary, Stefan Birkner: Fixed FailOnTimeout class (github#265).
2011 Jul 22
Andreas Köhler, Stefan Birkner: Fixed wrong documentation of Parameterized (github#89).
+
+2011 Jul 28
+ electrickery, Stefan Birkner: Fixed typo in JavaDoc (github#134).
+
+2011 Aug 07
+ Esko Luontola: Fixed TemporaryFolder creating files in the current working directory (github#278).
+
+2011 Aug 09
+ Stefan Birkner: Fixed JavaDoc links.
+
+2011 Aug 10
+ rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders.
+
+2011 Aug 12
+ Esko Luontola: Fixed syntax error in Parameterized's usage example (github#285).
+
+2011 Sep 09
+ Robert Munteanu, Stefan Birkner:
+ TestWatcher and TestWatchman don't call failed when assumption is violated (github#296).
+ digulla@github, Stefan Birkner: Removed useless code (github#289).
+
+== NOTE: as of September 2011, we have stopped recording contributions here.
+ For a full list of everyone who has contributed great bug reports and code, please see
+ http://github.com/KentBeck/junit
View
85 build.xml
@@ -1,13 +1,14 @@
<project name="junit" default="dist" basedir="."
xmlns:artifact="antlib:org.apache.maven.artifact.ant">
<tstamp />
+ <taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<property file="${user.home}/.junit.properties" />
<property name="src" value="src/main/java" />
<property name="target" location="target" />
<property name="bin" location="${target}/main" />
- <property name="version-base" value="4.9" />
- <property name="version-status" value="b3" />
+ <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}" />
<property name="versionfile" value="${src}/junit/runner/Version.java" />
@@ -67,6 +68,7 @@
debug="on"
classpath="@{classpath}"
includeantruntime="false"
+ source="1.5"
target="1.5"
>
<compilerarg value="-Xlint:unchecked" />
@@ -131,7 +133,8 @@
<target name="release-notes">
<property name="basename" value="doc/ReleaseNotes${version-base}" />
- <exec executable="build/Markdown.pl">
+ <exec executable="perl" failonerror="true">
+ <arg file="build/Markdown.pl"/>
<arg file="${basename}.txt"/>
<redirector output="${basename}.html" />
</exec>
@@ -217,19 +220,18 @@
<!-- to do automatic build upload, you need the maven ant tasks jar. -->
<!-- therefore, you must run ant as ant -lib build/lib stage.maven -->
- <macrodef name="stage.maven.jar">
+ <macrodef name="push.maven.jar">
<attribute name="jar" />
<attribute name="pom" />
+ <attribute name="url" />
+ <attribute name="repo.id" />
<element name="artifact.args" implicit="true" optional="true" />
<sequential>
- <property name="maven-repository-url"
- value="https://oss.sonatype.org/service/local/staging/deploy/maven2/" />
- <property name="maven-repository-id" value="sonatype-nexus-staging" />
- <echo message="Staging to maven: @{jar}" />
+ <echo message="Pushing to maven: @{jar} -> @{url}" />
<artifact:mvn failonerror="true">
<arg value="org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file" />
- <arg value="-Durl=${maven-repository-url}" />
- <arg value="-DrepositoryId=${maven-repository-id}" />
+ <arg value="-Durl=@{url}" />
+ <arg value="-DrepositoryId=@{repo.id}" />
<arg value="-DpomFile=@{pom}" />
<arg value="-Dfile=@{jar}" />
<artifact.args />
@@ -238,40 +240,79 @@
</sequential>
</macrodef>
- <macrodef name="stage.maven.artifactId">
+ <macrodef name="push.maven.artifact">
<attribute name="artifactId" />
+ <attribute name="url" />
+ <attribute name="repo.id" />
+ <attribute name="is.snapshot" default="false" />
<sequential>
+ <local name="m.prefix" />
<property name="m.prefix" value="${dist}/@{artifactId}-${version}" />
+ <local name="m.jar" />
<property name="m.jar" value="${m.prefix}.jar" />
+ <local name="m.sources.jar" />
<property name="m.sources.jar" value="${m.prefix}-src.jar" />
+ <local name="m.javadoc.jar" />
<property name="m.javadoc.jar" value="${m.prefix}-javadoc.jar" />
+ <local name="m.pom" />
<property name="m.pom" value="${dist}/pom-@{artifactId}.xml" />
<filter token="version" value="${version}" />
<filter token="artifactId" value="@{artifactId}" />
<copy
- file="pom-template.xml"
+ file="build/maven/pom-template.xml"
tofile="${m.pom}"
filtering="on"
overwrite="true"
/>
- <stage.maven.jar jar="${m.jar}" pom="${m.pom}" />
-
- <stage.maven.jar jar="${m.sources.jar}" pom="${m.pom}" >
- <arg value="-Dclassifier=sources" />
- </stage.maven.jar>
+ <push.maven.jar jar="${m.jar}" pom="${m.pom}"
+ url="@{url}" repo.id="@{repo.id}" />
+
+ <if>
+ <equals arg1="@{is.snapshot}" arg2="false" />
+ <then>
+ <push.maven.jar jar="${m.sources.jar}" pom="${m.pom}"
+ url="@{url}" repo.id="@{repo.id}">
+ <arg value="-Dclassifier=sources" />
+ </push.maven.jar>
- <stage.maven.jar jar="${m.javadoc.jar}" pom="${m.pom}" >
- <arg value="-Dclassifier=javadoc" />
- </stage.maven.jar>
+ <push.maven.jar jar="${m.javadoc.jar}" pom="${m.pom}"
+ url="@{url}" repo.id="@{repo.id}">
+ <arg value="-Dclassifier=javadoc" />
+ </push.maven.jar>
+ </then>
+ </if>
</sequential>
</macrodef>
<target name="stage.maven" depends="all.maven.jars">
- <stage.maven.artifactId artifactId="junit" />
- <stage.maven.artifactId artifactId="junit-dep" />
+ <property name="stage.url"
+ value="https://oss.sonatype.org/service/local/staging/deploy/maven2/" />
+ <property name="stage.repo.id" value="sonatype-nexus-staging" />
+
+ <push.maven.artifact artifactId="junit"
+ url="${stage.url}"
+ repo.id="${stage.repo.id}"
+ is.snapshot="false" />
+ <push.maven.artifact artifactId="junit-dep"
+ url="${stage.url}"
+ repo.id="${stage.repo.id}"
+ is.snapshot="false" />
+ </target>
+
+ <target name="snapshot.maven" depends="all.maven.jars">
+ <property name="snapshot.url"
+ value="https://oss.sonatype.org/content/repositories/snapshots/" />
+ <property name="snapshot.repo.id" value="sonatype-nexus-snapshots" />
+
+ <push.maven.artifact artifactId="junit"
+ url="${snapshot.url}"
+ repo.id="${snapshot.repo.id}" />
+ <push.maven.artifact artifactId="junit-dep"
+ url="${snapshot.url}"
+ repo.id="${snapshot.repo.id}" />
</target>
<target name="print.version">
View
BIN  build/lib/ant-contrib-1.0b3.jar
Binary file not shown
View
0  pom-template.xml → build/maven/pom-template.xml
File renamed without changes
View
49 build/maven/post_maven_tests.sh
@@ -0,0 +1,49 @@
+set -e
+set -o pipefail
+
+function TEST_junit_dep_49_plays_not_nicely_with_later_hamcrest {
+ # Make sure our system notices the bug (this broke because of a bad push)
+ ! runs_with_newer_hamcrest junit-dep 4.9
+}
+
+function TEST_junit_dep_snapshot_plays_nicely_with_later_hamcrest {
+ runs_with_newer_hamcrest junit-dep LATEST
+}
+
+function TEST_junit_snapshot_plays_not_nicely_with_later_hamcrest {
+ ! runs_with_newer_hamcrest junit LATEST
+}
+
+function runs_with_newer_hamcrest {
+ local artifact_id=$1
+ local version=$2
+ rm -rf ~/.m2/repository/junit
+ rm -rf uses_junit
+ cp -r sample_project_template uses_junit
+ sed -i '' -e "s/___ARTIFACT_ID___/$artifact_id/" uses_junit/pom.xml
+ sed -i '' -e "s/___VERSION___/$version/" uses_junit/pom.xml
+ in_dir uses_junit mvn test
+ finally rm -rf uses_junit
+}
+
+### <copied src="https://gist.github.com/1206506">
+function in_dir {
+ local dir=$1
+ shift
+ if [ ! -e $dir ]; then
+ echo "$dir does not exist"
+ return 1
+ fi
+ pushd $dir >/dev/null
+ "$@"
+ finally popd >/dev/null
+}
+
+function finally {
+ local return_this=$?
+ "$@"
+ return $return_this
+}
+### </copied>
+
+source ../run_tests.sh
View
61 build/maven/sample_project_template/pom.xml
@@ -0,0 +1,61 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.example</groupId>
+ <artifactId>junit-dependency-test</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <version.hamcrest>1.2.1</version.hamcrest>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>___ARTIFACT_ID___</artifactId>
+ <version>___VERSION___</version>
+ </dependency>
+
+ <!--
+ This dependency must be included *before* junit, because said JAR
+ contains an old hamcrest-core version. This is problematic at
+ runtime; see JunitDependencyTest.
+ If junit-dep has the right contents, the order should not matter.
+ -->
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-core</artifactId>
+ <version>${version.hamcrest}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ <version>${version.hamcrest}</version>
+ </dependency>
+ </dependencies>
+
+ <repositories>
+ <repository>
+ <id>Sonatype</id>
+ <url>https://oss.sonatype.org/content/groups/public</url>
+ <snapshots><enabled>true</enabled></snapshots>
+ <releases><enabled>true</enabled></releases>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
View
33 build/maven/sample_project_template/src/test/java/JunitDependencyTest.java
@@ -0,0 +1,33 @@
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+public final class JunitDependencyTest {
+ /**
+ * JUnit dependency test.
+ *
+ * This class has three dependencies. These can be on the classpath in
+ * different orders. Of the two orderings below, the first one will cause a
+ * NoSuchMethodError, while the second one allows the test to pass
+ * successfully. See the explanation below for more information.
+ *
+ * Ordering 1: junit-4.9, hamcrest-core-1.2.1, hamcrest-library-1.2.1.
+ * Ordering 2: hamcrest-core-1.2.1, junit-4.9, hamcrest-library-1.2.1.
+ */
+ @Test
+ public void test() {
+ /*
+ * Note that we call Matchers#anyOf(Matcher<T>, Matcher<? super T>).
+ * This method is provided by hamcrest-library-1.2.1. Said module is
+ * compiled against hamcrest-core-1.2.1. Matchers#anyOf calls
+ * AnyOf#anyOf(Matcher<T>, Matcher<? super T>). The latter method is
+ * provided by hamcrest-core-1.2.1, but *not* by hamcrest-core-1.1.
+ *
+ * However, hamcrest-core-1.1 *does* contain a class called AnyOf. Now,
+ * since junit-4.9 incorporates hamcrest-core-1.1 we must make sure that
+ * hamcrest-core-1.2.1 is placed *before* junit-4.9 on the classpath.
+ * Failure to do so will cause the wrong AnyOf class to be used. The
+ * result is a NoSuchMethodError.
+ */
+ Matchers.anyOf(Matchers.nullValue(), Matchers.notNullValue());
+ }
+}
View
36 build/run_tests.sh
@@ -0,0 +1,36 @@
+# See maven/post_maven_tests.sh for an example use
+
+SCRIPT_NAME=$0
+TEST_NAME=${1:-ALL}
+
+function get_tests() {
+ if [ $TEST_NAME == "ALL" ]; then
+ part1=function
+ part2=TEST_
+ grep "$part1 $part2" $SCRIPT_NAME | sed 's/.*\(TEST_[A-Za-z0-9_]*\).*/\1/'
+ else
+ echo "TEST_${TEST_NAME}"
+ fi
+}
+
+function run_tests() {
+ local exit_code=0
+
+ for t in $(get_tests); do
+ echo "RUNNING: $t"
+ if "$t"; then
+ echo "PASSED: $t"
+ else
+ echo "FAILED: $t"
+ return 1
+ fi
+ done
+}
+
+if run_tests; then
+ echo "ALL TESTS PASSED"
+ exit 0
+else
+ echo "A TEST FAILED"
+ exit 1
+fi
View
35 build_tests.sh
@@ -1,9 +1,6 @@
set -e
set -o pipefail
-SCRIPT_NAME=$0
-TEST_NAME=${1:-ALL}
-
function TEST_BUILDING_in_zip {
version=$(get_junit_version)
ant zip
@@ -76,34 +73,4 @@ function get_junit_version {
ant print.version | grep echo | sed 's/.*echo..\([1-9].*\)/\1/'
}
-function get_tests() {
- if [ $TEST_NAME == "ALL" ]; then
- part1=function
- part2=TEST_
- grep "$part1 $part2" $SCRIPT_NAME | sed 's/.*\(TEST_[A-Za-z0-9_]*\).*/\1/'
- else
- echo "TEST_${TEST_NAME}"
- fi
-}
-
-function run_tests() {
- local exit_code=0
-
- for t in $(get_tests); do
- echo "RUNNING: $t"
- if "$t"; then
- echo "PASSED: $t"
- else
- echo "FAILED: $t"
- return 1
- fi
- done
-}
-
-if run_tests; then
- echo "ALL TESTS PASSED"
- exit 0
-else
- echo "A TEST FAILED"
- exit 1
-fi
+source build/run_tests.sh
View
93 doc/ReleaseNotes4.10.html
@@ -0,0 +1,93 @@
+<h2>Summary of Changes in version 4.10 [unreleased!]</h2>
+
+<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>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");
+
+ @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><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>
+
+<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>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
@@ -0,0 +1,84 @@
+## 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 ###
+
+- 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]
+
+
+
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
14 doc/ReleaseNotes4.9.1.txt
@@ -0,0 +1,14 @@
+## Summary of Changes in version 4.9.1 [unreleased!] ##
+
+### Theories ###
+
+The `Theories` runner does not anticipate theory parameters that have generic
+types, as reported by github#64. Fixing this won't happen until `Theories` is
+moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the
+necessary machinery to the runner classes, and deprecates a method that only
+the `Theories` runner uses, `FrameworkMethod`#producesType().
+The Common Public License that JUnit is released under is now included
+in the source repository.
+
+Thanks to `@pholser` for identifying a potential resolution for github#64
+and initiating work on it.
View
2  doc/ReleaseNotes4.9.html
@@ -1,4 +1,4 @@
-<h2>Summary of Changes in version 4.9 [unreleased!]</h2>
+<h2>Summary of Changes in version 4.9, final</h2>
<p>Release theme: Test-class and suite level Rules.</p>
View
2  doc/ReleaseNotes4.9.txt
@@ -1,4 +1,4 @@
-## Summary of Changes in version 4.9 [unreleased!] ##
+## Summary of Changes in version 4.9, final ##
Release theme: Test-class and suite level Rules.
View
12 pom-template.xml.asc
@@ -1,12 +0,0 @@
------BEGIN PGP SIGNATURE-----
-Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
-Comment: GPGTools - http://gpgtools.org
-
-iQEcBAABAgAGBQJNmdc8AAoJEIiqH+6DGn6J1GwH/j7bKXkEJuzC3JfL8cE5WJSt
-5Ld7PP8QbXYB1Ko2X7o4cofWfaWDI8/j723LzKPW8UNs16m+jILMMvQXYY+VW/XV
-UVm/wRY+fjgjoYb2HrREKKP/M2bO4hSHjVQxPT6nga33kKCfoBQ27tVaWdQe01/Q
-siQfhKVekK21D+Odxd7TqDlSi1CN7M5HsLms6YufXwoJmjZdtiCrFlFlPBQy8vBA
-LwjmbDCpe85rWqwsOSUev5p2MA+IWX0OM6D2b1kOWYjhuGrpLg38lpcJm3yGILH/
-OewOxsvYOXoxjJ8eaEljvbW+E1+rBxwNbd24T7yRFDA/pUUx9Dz2YYtIo69NCSg=
-=wLGS
------END PGP SIGNATURE-----
View
6 src/main/java/junit/framework/AssertionFailedError.java
@@ -11,6 +11,10 @@ public AssertionFailedError() {
}
public AssertionFailedError(String message) {
- super(message);
+ super(defaultString(message));
+ }
+
+ private static String defaultString(String message) {
+ return message == null ? "" : message;
}
}
View
3  src/main/java/junit/framework/TestSuite.java
@@ -10,6 +10,7 @@
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
+import org.junit.internal.MethodSorter;
/**
* <p>A <code>TestSuite</code> is a <code>Composite</code> of Tests.
@@ -146,7 +147,7 @@ private void addTestsFromTestCase(final Class<?> theClass) {
Class<?> superClass= theClass;
List<String> names= new ArrayList<String>();
while (Test.class.isAssignableFrom(superClass)) {
- for (Method each : superClass.getDeclaredMethods())
+ for (Method each : MethodSorter.getDeclaredMethods(superClass))
addTestMethod(each, names, theClass);
superClass= superClass.getSuperclass();
}
View
2  src/main/java/junit/runner/Version.java
@@ -9,7 +9,7 @@ private Version() {
}
public static String id() {
- return "4.9b3";
+ return "4.11-SNAPSHOT";
}
public static void main(String[] args) {
View
18 src/main/java/org/junit/Assert.java
@@ -474,7 +474,7 @@ static public void assertEquals(String message, long expected, long actual) {
/**
* @deprecated Use
- * <code>assertEquals(double expected, double actual, double epsilon)</code>
+ * <code>assertEquals(double expected, double actual, double delta)</code>
* instead
*/
@Deprecated
@@ -484,7 +484,7 @@ static public void assertEquals(double expected, double actual) {
/**
* @deprecated Use
- * <code>assertEquals(String message, double expected, double actual, double epsilon)</code>
+ * <code>assertEquals(String message, double expected, double actual, double delta)</code>
* instead
*/
@Deprecated
@@ -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
38 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>
*
- * For more information and more examples, see {@link TestRule}.
+ * 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
1  src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java
@@ -80,6 +80,7 @@ private void addMultiPointMethods(List<PotentialAssignment> list) {
}
}
+ @SuppressWarnings("deprecation")
private void addSinglePointMethods(ParameterSignature sig,
List<PotentialAssignment> list) {
for (FrameworkMethod dataPointMethod : fClass
View
35 src/main/java/org/junit/internal/MethodSorter.java
@@ -0,0 +1,35 @@
+package org.junit.internal;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+
+public class MethodSorter {
+
+ /**
+ * Gets declared methods of a class in a predictable order.
+ * Using the JVM order is unwise since the Java platform does not
+ * specify any particular order, and in fact JDK 7 returns a more or less
+ * random order; well-written test code would not assume any order, but some
+ * does, and a predictable failure is better than a random failure on
+ * certain platforms. Uses an unspecified but deterministic order.
+ * @param clazz a class
+ * @return same as {@link Class#getDeclaredMethods} but sorted
+ * @see <a href="http://bugs.sun.com/view_bug.do?bug_id=7023180">JDK
+ * (non-)bug #7023180</a>
+ */
+ public static Method[] getDeclaredMethods(Class<?> clazz) {
+ Method[] methods = clazz.getDeclaredMethods();
+ Arrays.sort(methods, new Comparator<Method>() {
+ @Override public int compare(Method m1, Method m2) {
+ int i1 = m1.getName().hashCode();
+ int i2 = m2.getName().hashCode();
+ return i1 != i2 ? i1 - i2 : m1.toString().compareTo(m2.toString());
+ }
+ });
+ return methods;
+ }
+
+ private MethodSorter() {}
+
+}
View
3  src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java
@@ -3,6 +3,7 @@
import java.lang.reflect.Method;
import org.hamcrest.BaseMatcher;
+import org.junit.internal.MethodSorter;
/**
* Convenient base class for Matchers that require a non-null value of a specific type.
@@ -26,7 +27,7 @@ protected TypeSafeMatcher() {
private static Class<?> findExpectedType(Class<?> fromClass) {
for (Class<?> c = fromClass; c != Object.class; c = c.getSuperclass()) {
- for (Method method : c.getDeclaredMethods()) {
+ for (Method method : MethodSorter.getDeclaredMethods(c)) {
if (isMatchesSafelyMethod(method)) {
return method.getParameterTypes()[0];
}
View
3  src/main/java/org/junit/internal/runners/TestClass.java
@@ -11,6 +11,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.junit.internal.MethodSorter;
import org.junit.runners.BlockJUnit4ClassRunner;
/**
@@ -41,7 +42,7 @@ public TestClass(Class<?> klass) {
public List<Method> getAnnotatedMethods(Class<? extends Annotation> annotationClass) {
List<Method> results= new ArrayList<Method>();
for (Class<?> eachClass : getSuperClasses(fClass)) {
- Method[] methods= eachClass.getDeclaredMethods();
+ Method[] methods= MethodSorter.getDeclaredMethods(eachClass);
for (Method eachMethod : methods) {
Annotation annotation= eachMethod.getAnnotation(annotationClass);
if (annotation != null && ! isShadowed(eachMethod, results))
View
112 src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java
@@ -0,0 +1,112 @@
+package org.junit.internal.runners.rules;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.rules.MethodRule;
+import org.junit.rules.TestRule;
+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 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, false, true),
+ /**
+ * Validates fields with a {@link Rule} annotation.
+ */
+ 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 fStaticMembers;
+ private final boolean fMethods;
+
+ private RuleFieldValidator(Class<? extends Annotation> annotation,
+ boolean methods, boolean fStaticMembers) {
+ this.fAnnotation= annotation;
+ this.fStaticMembers= fStaticMembers;
+ this.fMethods= methods;
+ }
+
+ /**
+ * Validate the {@link org.junit.runners.model.TestClass} and adds reasons
+ * for rejecting the class to a list of errors.
+ * @param target the {@code TestClass} to validate.
+ * @param errors the list of errors.
+ */
+ public void validate(TestClass target, List<Throwable> errors) {
+ List<? extends FrameworkMember<?>> members= fMethods ? target.getAnnotatedMethods(fAnnotation)
+ : target.getAnnotatedFields(fAnnotation);
+
+ for (FrameworkMember<?> each : members)
+ validateMember(each, errors);
+ }
+
+ private void validateMember(FrameworkMember<?> member, List<Throwable> errors) {
+ validateStatic(member, errors);
+ validatePublic(member, errors);
+ validateTestRuleOrMethodRule(member, errors);
+ }
+
+ private void validateStatic(FrameworkMember<?> member,
+ List<Throwable> errors) {
+ if (fStaticMembers && !member.isStatic())
+ addError(errors, member, "must be static.");
+ if (!fStaticMembers && member.isStatic())
+ addError(errors, member, "must not be static.");
+ }
+
+ private void validatePublic(FrameworkMember<?> member, List<Throwable> errors) {
+ if (!member.isPublic())
+ addError(errors, member, "must be public.");
+ }
+
+ private void validateTestRuleOrMethodRule(FrameworkMember<?> member,
+ List<Throwable> errors) {
+ 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(FrameworkMember<?> member) {
+ return TestRule.class.isAssignableFrom(member.getType());
+ }
+
+ @SuppressWarnings("deprecation")
+ private boolean isMethodRule(FrameworkMember<?> member) {
+ return MethodRule.class.isAssignableFrom(member.getType());
+ }
+
+ private void addError(List<Throwable> errors, FrameworkMember<?> member,
+ String suffix) {
+ String message= "The @" + fAnnotation.getSimpleName() + " '"
+ + member.getName() + "' " + suffix;
+ errors.add(new Exception(message));
+ }
+}
View
69 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;
+ }
+ }
+ }
}
View
1  src/main/java/org/junit/internal/runners/statements/RunAfters.java
@@ -26,7 +26,6 @@ public RunAfters(Statement next, List<FrameworkMethod> afters, Object target) {
@Override
public void evaluate() throws Throwable {
List<Throwable> errors = new ArrayList<Throwable>();
- errors.clear();
try {
fNext.evaluate();
} catch (Throwable e) {
View
19 src/main/java/org/junit/rules/ErrorCollector.java
@@ -52,18 +52,27 @@ public void addError(Throwable error) {
* Execution continues, but the test will fail at the end if the match fails.
*/
public <T> void checkThat(final T value, final Matcher<T> matcher) {
+ checkThat("", value, matcher);
+ }
+
+ /**
+ * Adds a failure with the given {@code reason}
+ * to the table if {@code matcher} does not match {@code value}.
+ * Execution continues, but the test will fail at the end if the match fails.
+ */
+ public <T> void checkThat(final String reason, final T value, final Matcher<T> matcher) {
checkSucceeds(new Callable<Object>() {
public Object call() throws Exception {
- assertThat(value, matcher);
+ assertThat(reason, value, matcher);
return value;
}
});
}
/**
- * Adds to the table the exception, if any, thrown from {@code callable}.
- * Execution continues, but the test will fail at the end if {@code callable}
- * threw an exception.
+ * Adds to the table the exception, if any, thrown from {@code callable}.
+ * Execution continues, but the test will fail at the end if
+ * {@code callable} threw an exception.
*/
public Object checkSucceeds(Callable<Object> callable) {
try {
@@ -71,6 +80,6 @@ public Object checkSucceeds(Callable<Object> callable) {
} catch (Throwable e) {
addError(e);
return null;
- }
+ }
}
}
View
99 src/main/java/org/junit/rules/RuleChain.java
@@ -0,0 +1,99 @@
+/**
+ *
+ */
+package org.junit.rules;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * The RuleChain rule allows ordering of TestRules. You create a
+ * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
+ * {@link #around(TestRule)}:
+ *
+ * <pre>
+ * public static class UseRuleChain {
+ * &#064;Rule
+ * public TestRule chain= RuleChain
+ * .outerRule(new LoggingRule("outer rule")
+ * .around(new LoggingRule("middle rule")
+ * .around(new LoggingRule("inner rule");
+ *
+ * &#064;Test
+ * public void example() {
+ * assertTrue(true);
+ * }
+ * }
+ * </pre>
+ *
+ * writes the log
+ *
+ * <pre>
+ * starting outer rule
+ * starting middle rule
+ * starting inner rule
+ * finished inner rule
+ * finished middle rule
+ * finished outer rule
+ * </pre>
+ */
+public class RuleChain implements TestRule {
+ private static final RuleChain EMPTY_CHAIN= new RuleChain(
+ Collections.<TestRule> emptyList());
+
+ private List<TestRule> rulesStartingWithInnerMost;
+
+ /**
+ * Returns a {@code RuleChain} without a {@link TestRule}. This method may
+ * be the starting point of a {@code RuleChain}.
+ *
+ * @return a {@code RuleChain} without a {@link TestRule}.
+ */
+ public static RuleChain emptyRuleChain() {
+ return EMPTY_CHAIN;
+ }
+
+ /**
+ * Returns a {@code RuleChain} with a single {@link TestRule}. This method
+ * is the usual starting point of a {@code RuleChain}.
+ *
+ * @param outerRule
+ * the outer rule of the {@code RuleChain}.
+ * @return a {@code RuleChain} with a single {@link TestRule}.
+ */
+ public static RuleChain outerRule(TestRule outerRule) {
+ return emptyRuleChain().around(outerRule);
+ }
+
+ private RuleChain(List<TestRule> rules) {
+ this.rulesStartingWithInnerMost= rules;
+ }
+
+ /**
+ * Create a new {@code RuleChain}, which encloses the {@code nextRule} with
+ * the rules of the current {@code RuleChain}.
+ *
+ * @param enclosedRule
+ * the rule to enclose.
+ * @return a new {@code RuleChain}.
+ */
+ public RuleChain around(TestRule enclosedRule) {
+ List<TestRule> rulesOfNewChain= new ArrayList<TestRule>();
+ rulesOfNewChain.add(enclosedRule);
+ rulesOfNewChain.addAll(rulesStartingWithInnerMost);
+ return new RuleChain(rulesOfNewChain);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Statement apply(Statement base, Description description) {
+ for (TestRule each : rulesStartingWithInnerMost)
+ base= each.apply(base, description);
+ return base;
+ }
+}
View
55 src/main/java/org/junit/rules/TemporaryFolder.java
@@ -39,46 +39,73 @@ 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= File.createTempFile("junit", "");
- folder.delete();
- folder.mkdir();
+ folder= createTemporaryFolderIn(null);
}
/**
* Returns a new fresh file with the given name under the temporary folder.
*/
public File newFile(String fileName) throws IOException {
- File file= new File(folder, fileName);
+ File file= new File(getRoot(), fileName);
file.createNewFile();
return file;
}
/**
- * Returns a new fresh folder with the given name under the temporary folder.
+ * Returns a new fresh file with a random name under the temporary folder.
*/
- public File newFolder(String folderName) {
- File file= new File(folder, folderName);
- file.mkdir();
+ public File newFile() throws IOException {
+ return File.createTempFile("junit", null, getRoot());
+ }
+
+ /**
+ * Returns a new fresh folder with the given name under the temporary
+ * folder.
+ */
+ public File newFolder(String... folderNames) {
+ File file= getRoot();
+ for (String folderName : folderNames) {
+ file= new File(file, folderName);
+ file.mkdir();
+ }
return file;
}
/**
+ * Returns a new fresh folder with a random name under the temporary folder.
+ */
+ public File newFolder() throws IOException {
+ return createTemporaryFolderIn(getRoot());
+ }
+
+ private File createTemporaryFolderIn(File parentFolder) throws IOException {
+ File createdFolder= File.createTempFile("junit", "", parentFolder);
+ createdFolder.delete();
+ createdFolder.mkdir();
+ return createdFolder;
+ }
+
+ /**
* @return the location of this temporary folder.
*/
public File getRoot() {
+ if (folder == null) {
+ throw new IllegalStateException(
+ "the temporary folder has not yet been created");
+ }
return folder;
}
/**
- * Delete all files and folders under the temporary folder.
- * Usually not called directly, since it is automatically applied
- * by the {@link Rule}
+ * 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) {
@@ -88,4 +115,4 @@ private void recursiveDelete(File file) {
recursiveDelete(each);
file.delete();
}
-}
+}
View
3  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;
View
3  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;
View
6 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 <code>Description</code> named <code>name</code>.
* Generally, you will add children to this <code>Description</code>.
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
4 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<Failure> fFailures= Collections.synchronizedList(new ArrayList<Failure>());
View
4 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;
View
73 src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
@@ -1,7 +1,8 @@
package org.junit.runners;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
+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;
import org.junit.After;
@@ -21,7 +22,6 @@
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.MultipleFailureException;
@@ -46,7 +46,6 @@
* </ul>
*/
public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
-
/**
* Creates a BlockJUnit4ClassRunner to run {@code klass}
*
@@ -99,9 +98,19 @@ protected Description describeChild(FrameworkMethod method) {
protected void collectInitializationErrors(List<Throwable> errors) {
super.collectInitializationErrors(errors);
+ validateNoNonStaticInnerClass(errors);
validateConstructor(errors);
validateInstanceMethods(errors);
validateFields(errors);
+ validateMethods(errors);
+ }
+
+ protected void validateNoNonStaticInnerClass(List<Throwable> errors) {
+ if (getTestClass().isANonStaticInnerClass()) {
+ String gripe= "The inner class " + getTestClass().getName()
+ + " is not static.";
+ errors.add(new Exception(gripe));
+ }
}
/**
@@ -130,8 +139,9 @@ protected void validateOnlyOneConstructor(List<Throwable> errors) {
* parameters (do not override)
*/
protected void validateZeroArgConstructor(List<Throwable> errors) {
- if (hasOneConstructor()
- && !(getTestClass().getOnlyConstructor().getParameterTypes().length == 0)) {
+ if (!getTestClass().isANonStaticInnerClass()
+ && hasOneConstructor()
+ && (getTestClass().getOnlyConstructor().getParameterTypes().length != 0)) {
String gripe= "Test class should have exactly one public zero-argument constructor";
errors.add(new Exception(gripe));
}
@@ -159,28 +169,11 @@ protected void validateInstanceMethods(List<Throwable> errors) {
}
private void validateFields(List<Throwable> errors) {
- for (FrameworkField each : getTestClass()
- .getAnnotatedFields(Rule.class))
- validateRuleField(each.getField(), errors);
- }
-
- private void validateRuleField(Field field, List<Throwable> errors) {
- Class<?> type= field.getType();
- if (!isMethodRule(type) && !isTestRule(type))
- errors.add(new Exception("Field " + field.getName()
- + " must implement MethodRule or TestRule"));
- if (!Modifier.isPublic(field.getModifiers()))
- errors.add(new Exception("Field " + field.getName()
- + " must be public"));
+ RULE_VALIDATOR.validate(getTestClass(), errors);
}
- private boolean isTestRule(Class<?> type) {
- return TestRule.class.isAssignableFrom(type);
- }
-
- @SuppressWarnings("deprecation")
- private boolean isMethodRule(Class<?> type) {
- return org.junit.rules.MethodRule.class.isAssignableFrom(type);
+ private void validateMethods(List<Throwable> errors) {
+ RULE_METHOD_VALIDATOR.validate(getTestClass(), errors);
}
/**
@@ -339,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,7 +359,7 @@ private Statement withMethodRules(FrameworkMethod method, Object target,
* the test case instance
* @return a list of MethodRules that should be applied when executing this
* test
- * @deprecated {@link MethodRule} is a deprecated interface. Port to
+ * @deprecated {@link org.junit.rules.MethodRule} is a deprecated interface. Port to
* {@link TestRule} and
* {@link BlockJUnit4ClassRunner#getTestRules(Object)}
*/
@@ -378,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));
}
@@ -397,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
88 src/main/java/org/junit/runners/Parameterized.java
@@ -1,10 +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;
@@ -14,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>
@@ -29,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;
@@ -71,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
@@ -117,6 +105,11 @@ protected void validateConstructor(List<Throwable> errors) {
protected Statement classBlock(RunNotifier notifier) {
return childrenInvoker(notifier);
}
+
+ @Override
+ protected Annotation[] getRunnerAnnotations() {
+ return new Annotation[0];
+ }
}
private final ArrayList<Runner> runners= new ArrayList<Runner>();
@@ -125,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
@@ -138,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
45 src/main/java/org/junit/runners/ParentRunner.java
@@ -1,5 +1,8 @@
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;
import java.util.ArrayList;
@@ -27,7 +30,6 @@
import org.junit.runner.manipulation.Sorter;
import org.junit.runner.notification.RunNotifier;
import org.junit.runner.notification.StoppedByUserException;
-import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.MultipleFailureException;
@@ -109,6 +111,7 @@ protected ParentRunner(Class<?> testClass) throws InitializationError {
protected void collectInitializationErrors(List<Throwable> errors) {
validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
+ validateClassRules(errors);
}
/**
@@ -129,6 +132,11 @@ protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annota
eachTestMethod.validatePublicVoidNoArg(isStatic, errors);
}
+ private void validateClassRules(List<Throwable> errors) {
+ CLASS_RULE_VALIDATOR.validate(getTestClass(), errors);
+ CLASS_RULE_METHOD_VALIDATOR.validate(getTestClass(), errors);
+ }
+
/**
* Constructs a {@code Statement} to run all of the tests in the test class. Override to add pre-/post-processing.
* Here is an outline of the implementation:
@@ -201,26 +209,11 @@ private Statement withClassRules(Statement statement) {
* each method in the tested class.
*/
protected List<TestRule> classRules() {
- List<TestRule> results= new ArrayList<TestRule>();
- for (FrameworkField field : classRuleFields())
- results.add(getClassRule(field));
- return results;
- }
+ List<TestRule> result= fTestClass.getAnnotatedMethodValues(null, ClassRule.class, TestRule.class);
- private TestRule getClassRule(final FrameworkField field) {
- try {
- return (TestRule) field.get(null);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(
- "How did getAnnotatedFields return a field we couldn't access?");
- }
- }
-
- /**
- * @return list of {@link FrameworkField}s annotated with {@link Rule}
- */
- protected List<FrameworkField> classRuleFields() {
- return fTestClass.getAnnotatedFields(ClassRule.class);
+ result.addAll(fTestClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class));
+
+ return result;
}
/**
@@ -283,6 +276,14 @@ protected final void runLeaf(Statement statement, Description description,
}
}
+ /**
+ * @return the annotations that should be attached to this runner's
+ * description.
+ */
+ protected Annotation[] getRunnerAnnotations() {
+ return fTestClass.getAnnotations();
+ }
+
//
// Implementation of Runner
//
@@ -290,7 +291,7 @@ protected final void runLeaf(Statement statement, Description description,
@Override
public Description getDescription() {
Description description= Description.createSuiteDescription(getName(),
- fTestClass.getAnnotations());
+ getRunnerAnnotations());
for (T child : getFilteredChildren())
description.addChild(describeChild(child));
return description;
@@ -339,7 +340,7 @@ public void sort(Sorter sorter) {
sortChild(each);
Collections.sort(getFilteredChildren(), comparator());
}
-
+
//
// Private implementation
//
View
21 src/main/java/org/junit/runners/model/FrameworkField.java
@@ -2,6 +2,7 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import org.junit.runners.BlockJUnit4ClassRunner;
@@ -17,13 +18,30 @@
}
@Override
+ public String getName() {
+ return getField().getName();
+ }
+
+ @Override
public Annotation[] getAnnotations() {
return fField.getAnnotations();
}
@Override
+ public boolean isPublic() {
+ int modifiers= fField.getModifiers();
+ return Modifier.isPublic(modifiers);
+ }
+
+ @Override
public boolean isShadowedBy(FrameworkField otherMember) {
- return otherMember.getField().getName().equals(getField().getName());
+ return otherMember.getName().equals(getName());
+ }
+
+ @Override
+ public boolean isStatic() {
+ int modifiers= fField.getModifiers();
+ return Modifier.isStatic(modifiers);
}
/**
@@ -37,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
53 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;
@@ -49,6 +50,7 @@ protected Object runReflectiveCall() throws Throwable {
/**
* Returns the method's name
*/
+ @Override
public String getName() {
return fMethod.getName();
}
@@ -89,6 +91,41 @@ 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);
+ }
@Override
public boolean isShadowedBy(FrameworkMethod other) {
@@ -115,12 +152,18 @@ 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
+ * use all the generic type info that it ought to. It will be replaced
+ * with a forthcoming ParameterSignature#canAcceptResultOf(FrameworkMethod)
+ * once Theories moves to junit-contrib.
*/
- public boolean producesType(Class<?> type) {
- return getParameterTypes().length == 0
- && type.isAssignableFrom(fMethod.getReturnType());
+ @Deprecated
+ public boolean producesType(Type type) {
+ return getParameterTypes().length == 0 && type instanceof Class<?>
+ && ((Class<?>) type).isAssignableFrom(fMethod.getReturnType());
}