Merge pull request #1174 from cnauroth/timeout-javadoc-sample-fix-deprecation

Avoid calling a deprecated constructor in the JavaDoc sample for the …
diff --git a/.classpath b/.classpath
index c982591..f648ca6 100644
--- a/.classpath
+++ b/.classpath
@@ -2,6 +2,8 @@
 <classpath>
 	<classpathentry kind="src" path="src/main/java"/>
 	<classpathentry kind="src" path="src/test/java"/>
+	<classpathentry kind="src" path="src/test/resources"/>
+	<classpathentry kind="src" path="src/main/resources"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
 	<classpathentry exported="true" kind="lib" path="lib/hamcrest-core-1.3.jar" sourcepath="lib/hamcrest-core-1.3-sources.jar"/>
 	<classpathentry kind="output" path="bin"/>
diff --git a/.cvsignore b/.cvsignore
deleted file mode 100644
index a23e28c..0000000
--- a/.cvsignore
+++ /dev/null
@@ -1,10 +0,0 @@
-bin
-junit4.1
-junit*-SNAPSHOT-*
-target
-reports
-buildfile
-java.hprof.txt
-junit4.5-RC1
-junit4.*
-*.ser
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index 0125987..d54f4c2 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -247,7 +247,7 @@
 org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
 org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
 org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
@@ -351,7 +351,7 @@
 org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
-org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.char=space
 org.eclipse.jdt.core.formatter.tabulation.size=4
 org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
 org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..378d461
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,7 @@
+language: java
+script: mvn verify javadoc:javadoc site:site
+jdk:
+  - oraclejdk7
+  - oraclejdk8
+  - openjdk7
+  - openjdk6
diff --git a/BUILDING b/BUILDING
index 832bb75..5d1ec90 100644
--- a/BUILDING
+++ b/BUILDING
@@ -1,7 +1,7 @@
 BUILDING FROM GITHUB:
 =====================
 
-git clone https://github.com/KentBeck/junit.git
+git clone https://github.com/junit-team/junit.git
 cd junit
 mvn install
 
@@ -11,4 +11,4 @@
 The contents of the zip and jar files are largely maintained for historical
 reasons.  We do not at this time have an official way to build from the src
 jar or zip.  If this is an important missing feature, please let us know
-at http://github.com/KentBeck/junit/issues
\ No newline at end of file
+at http://github.com/junit-team/junit/issues
diff --git a/CODING_STYLE.txt b/CODING_STYLE.txt
new file mode 100644
index 0000000..d9600af
--- /dev/null
+++ b/CODING_STYLE.txt
@@ -0,0 +1,3 @@
+JUnit project uses the Google Java Style (http://google-styleguide.googlecode.com/svn/trunk/javaguide.html) for all new
+code (under org.junit.*). Legacy code (under junit.*) used the legacy guide specified in LEGACY_CODING_STYLE.txt in the
+project root.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..4ce0de7
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,26 @@
+### Project License:  Eclipse Public License v1.0
+
+- You will only Submit Contributions where You have authored 100% of the content.
+- You will only Submit Contributions to which You have the necessary rights. This means that if You are employed You have received the necessary permissions from Your employer to make the Contributions.
+- Whatever content You Contribute will be provided under the Project License(s).
+
+---
+
+### How to submit a pull request
+
+We love pull requests. Here is a quick guide:
+
+1. You need to have Maven and a JDK (at least version 1.5) installed.
+2. [Fork the repo](https://help.github.com/articles/fork-a-repo).
+3. [Create a new branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/) from master.
+4. Ensure that you have a clean state by running `mvn verify`.
+5. Add your change together with a test (tests are not needed for refactorings and documentation changes).
+6. Format your code: Import the JUnit project in Eclipse and use its formatter or apply the rules in the `CODING_STYLE` file manually. Only format the code you've changed; reformatting unrelated code makes it harder for us to review your changes.
+7. Run `mvn verify` again and ensure all tests are passing.
+8. Push to your fork and [submit a pull request](https://help.github.com/articles/creating-a-pull-request/).
+
+Now you are waiting on us. We review your pull request and at least leave some comments.
+
+
+Note that if you are thinking of providing a fix for one of the bugs or feature requests, it's usually
+a good idea to add a comment to the bug to make sure that there's agreement on how we should proceed.
diff --git a/CODING_STYLE b/LEGACY_CODING_STYLE.txt
similarity index 98%
rename from CODING_STYLE
rename to LEGACY_CODING_STYLE.txt
index f5880ae..81e553b 100644
--- a/CODING_STYLE
+++ b/LEGACY_CODING_STYLE.txt
@@ -86,7 +86,7 @@
 * Class annotations : Wrap always
 * Method annotations : Wrap always
 * Field annotations : Wrap always
-* Paramater annotations : Do not wrap
+* Parameter annotations : Do not wrap
 * Local variable annotations : Do not wrap
 
 ----------------------------------
@@ -129,4 +129,4 @@
 import javax.*
 import com.*
 <blank line> 
-import (all other imports)
\ No newline at end of file
+import (all other imports)
diff --git a/LICENSE.txt b/LICENSE-junit.txt
similarity index 94%
rename from LICENSE.txt
rename to LICENSE-junit.txt
index 1aba77a..fb68629 100644
--- a/LICENSE.txt
+++ b/LICENSE-junit.txt
@@ -1,8 +1,8 @@
 JUnit
 
-Common Public License - v 1.0
+Eclipse Public License - v 1.0
 
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
 LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
 CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
 
@@ -173,11 +173,7 @@
 provision shall be reformed to the minimum extent necessary to make such
 provision valid and enforceable.
 
-If Recipient institutes patent litigation against a Contributor with respect to
-a patent applicable to software (including a cross-claim or counterclaim in a
-lawsuit), then any patent licenses granted by that Contributor to such
-Recipient under this Agreement shall terminate as of the date such litigation
-is filed. In addition, if Recipient institutes patent litigation against any
+If Recipient institutes patent litigation against any
 entity (including a cross-claim or counterclaim in a lawsuit) alleging that the
 Program itself (excluding combinations of the Program with other software or
 hardware) infringes such Recipient's patent(s), then such Recipient's rights
@@ -198,7 +194,7 @@
 modified in the following manner. The Agreement Steward reserves the right to
 publish new versions (including revisions) of this Agreement from time to time.
 No one other than the Agreement Steward has the right to modify this Agreement.
-IBM is the initial Agreement Steward. IBM may assign the responsibility to
+The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to
 serve as the Agreement Steward to a suitable separate entity. Each new version
 of the Agreement will be given a distinguishing version number. The Program
 (including Contributions) may always be distributed subject to the version of
diff --git a/README.md b/README.md
index 8c71a15..660111c 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,9 @@
 JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks.
 
 For more information, please visit:
-* [Wiki](https://github.com/KentBeck/junit/wiki)
-* [Download and Install guide](https://github.com/KentBeck/junit/wiki/Download-and-Install)
-* [Getting Started](https://github.com/KentBeck/junit/wiki/Getting-started)
+* [Wiki](https://github.com/junit-team/junit/wiki)
+* [Download and Install guide](https://github.com/junit-team/junit/wiki/Download-and-Install)
+* [Getting Started](https://github.com/junit-team/junit/wiki/Getting-started)
 
 [![Latest Build Status](https://junit.ci.cloudbees.com/job/JUnit/badge/icon)](https://junit.ci.cloudbees.com/)
 
diff --git a/acknowledgements.txt b/acknowledgements.txt
index a887217..fa1aa85 100644
--- a/acknowledgements.txt
+++ b/acknowledgements.txt
@@ -82,7 +82,7 @@
      reinholdfuereder@github For initial test for GH-39
 
 2011 Apr 15
-     ububenheimer@github for bug report https://github.com/KentBeck/junit/issues/208
+     ububenheimer@github for bug report https://github.com/junit-team/junit/issues/208
 
 2011 Apr 29
      reinholdfuereder@github: bug report, test, and fix for GH-38:
@@ -160,4 +160,4 @@
 
 == 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
+   http://github.com/junit-team/junit
diff --git a/build.xml b/build.xml
deleted file mode 100644
index bcb3aa3..0000000
--- a/build.xml
+++ /dev/null
@@ -1,379 +0,0 @@
-<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.12" />
-  <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" />
-  <property name="zipfile"  value="${dist}/${dist}.zip" />
-  <property name="testsrc" location="src/test/java" />
-  <property name="testbin" location="${target}/test/java" />
-  <property name="unjarred" 
-            value="**/*.jar, ${testfiles}, doc/**, README.md, .classpath, .project, cpl-v10.html" />
-
-  <property name="binjar" value="junit-${version}.jar" />
-  <property name="srcjar" value="junit-${version}-src.jar" />
-  <property name="docjar" value="junit-${version}-javadoc.jar" />
-
-  <property name="depjar" value="junit-dep-${version}.jar" />
-  <property name="depsrcjar" value="junit-dep-${version}-src.jar" />
-  <property name="depdocjar" value="junit-dep-${version}-javadoc.jar" />
-
-  <property name="javadocdir" location="${dist}/javadoc" />
-  <property name="javadoczip" location="${dist}-javadoc.zip" />
-  <property name="hamcrestlib" location="lib/hamcrest-core-1.3.jar" />
-  <property name="hamcrestlibsources" location="lib/hamcrest-core-1.3-sources.jar" />
-  <property name="hamcrestsrc" location="${dist}/temp.hamcrest.source" />
-
-  <property name="maven.deploy.goal" value="org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file" />
-
-  <target name="init">
-    <tstamp/>
-  </target>
-
-  <target name="versiontag" depends="init">
-    <filter token="version" value="${version}" />
-  
-    <copy 
-        file="${versionfile}.template" 
-        tofile="${versionfile}" 
-        filtering="on"
-        overwrite="true"
-        />
-  </target>
-
-  <target name="clean">
-    <!-- If two builds are made within a minute -->
-    <delete dir="${dist}" quiet="true" />
-    <!-- Delete all previous temporary build artifacts -->
-    <delete dir="${target}" quiet="true" />
-    
-    <delete file="${zipfile}" quiet="true"/>
-    <delete file="${javadoczip}" />
-  </target>
-
-  <macrodef name="junit_compilation">
-    <attribute name="srcdir"/>
-    <attribute name="destdir"/>
-    <attribute name="classpath"/>
-    <sequential>
-      <mkdir dir="@{destdir}"/>
-      <javac 
-          srcdir="@{srcdir}"
-          destdir="@{destdir}"
-          debug="on"
-          classpath="@{classpath}"
-          includeantruntime="false"
-          source="1.5"
-          target="1.5"
-          >
-        <compilerarg value="-Xlint:unchecked" />
-      </javac>
-    </sequential>
-  </macrodef>
-  
-  <target name="build" depends="versiontag">
-    <junit_compilation srcdir="${src}" destdir="${bin}" classpath="${hamcrestlib}"/>
-    <unjar src="${hamcrestlib}" dest="${bin}" />
-    <junit_compilation srcdir="${testsrc}" destdir="${testbin}" classpath="${hamcrestlib};${bin}"/>
-  </target>
-
-  <target name="jars" depends="build">
-    <mkdir dir="${dist}" />
-    <jar 
-        jarfile="${dist}/${srcjar}"
-        basedir="${src}"
-        excludes="${unjarred}, **/*.class"
-        />
-    <jar 
-        jarfile="${dist}/${binjar}"
-        basedir="${bin}"
-        excludes="${unjarred}, **/*.java, build.xml"
-        />
-    <jar 
-        jarfile="${dist}/${depjar}" 
-        basedir="${bin}" 
-        excludes="${unjarred}, org/hamcrest/**, **/*.java, build.xml" 
-        />
-  </target>
-
-  <target name="all.maven.jars" depends="jars,javadoc">
-    <mkdir dir="${dist}" />
-    <jar 
-        jarfile="${dist}/${depsrcjar}"
-        basedir="${src}"
-        excludes="${unjarred}, **/*.class"
-        />
-    <jar 
-        jarfile="${dist}/${depdocjar}"
-        basedir="${javadocdir}"
-        excludes="${unjarred}, org/hamcrest/**"
-        />
-  </target>
-
-  <target name="samples-and-tests">
-    <copy todir="${dist}">
-      <fileset dir="${testbin}" />
-      <fileset dir="${testsrc}" />
-    </copy>
-  </target>
-
-  <target name="unjar.hamcrest">
-    <unjar src="${hamcrestlibsources}" dest="${hamcrestsrc}" />
-  </target>
-  
-  <target name="release-notes">
-    <property name="basename" value="doc/ReleaseNotes${version-base}" />
-    <exec executable="perl" failonerror="true">
-      <arg file="build/Markdown.pl"/>
-      <arg file="${basename}.md"/>
-      <redirector output="${basename}.html" />
-    </exec>
-  </target>
-  
-  <target name="javadoc" depends="unjar.hamcrest">
-    <javadoc destdir="${javadocdir}"
-             author="false"
-             version="false"
-             use="false"
-             windowtitle="JUnit API"
-             stylesheetfile="stylesheet.css"
-             >
-      <excludepackage name="junit.*" />
-      <excludepackage name="org.junit.internal.*" />
-      <excludepackage name="org.junit.experimental.theories.internal.*" />
-      
-      <sourcepath location="${src}" />
-      <sourcepath location="${hamcrestsrc}" />
-      <link href="http://java.sun.com/javase/6/docs/api/" />
-    </javadoc>
-  </target>
-
-  <target name="javadoczip">
-    <delete file="${javadoczip}" />
-    <antcall target="javadoc" />
-    <zip basedir="${javadocdir}" file="${javadoczip}" />
-  </target>
-
-  <target name="populate-dist" 
-          depends="clean, build, jars, samples-and-tests, javadoc, release-notes"
-          >
-    <copy todir="${dist}/doc">
-      <fileset dir="doc"/>
-    </copy>
-    <copy file="README.md" tofile="${dist}/README.md" />
-    <copy file="BUILDING" tofile="${dist}/BUILDING" />
-    <copy file="cpl-v10.html" tofile="${dist}/cpl-v10.html" />
-    <copy file="build.xml" tofile="${dist}/build.xml" />
-  </target>
-
-  <macrodef name="run-dist-tests">
-    <!-- Runs the tests against the built jar files -->
-    <element name="extra-args" implicit="yes" />
-    <sequential>
-      <java classname="org.junit.runner.JUnitCore" fork="yes" failonerror="true">
-        <extra-args />  
-        <arg value="org.junit.tests.AllTests"/>
-        <classpath>
-          <pathelement location="${dist}" />
-          <pathelement location="${dist}/${binjar}" />
-        </classpath>
-      </java>    
-    </sequential>
-  </macrodef>
-
-  <macrodef name="run-local-tests">
-    <!-- Runs the tests against the local class files -->
-    <sequential>
-      <java classname="org.junit.runner.JUnitCore" fork="yes" failonerror="true">
-        <arg value="org.junit.tests.AllTests"/>
-        <classpath>
-          <pathelement location="${bin}" />
-          <pathelement location="${testbin}" />
-          <pathelement location="${hamcrestlib}" />
-        </classpath>
-      </java>    
-    </sequential>
-  </macrodef>
-
-  <target name="test" depends="build">
-    <run-local-tests />
-  </target>
-
-  <target name="dist" depends="populate-dist">
-    <run-dist-tests>
-      <jvmarg value="-Dignore.this=ignored"/>
-    </run-dist-tests>
-  </target>
-
-  <target name="profile" depends="populate-dist">
-    <run-dist-tests>
-      <jvmarg value="-agentlib:hprof=cpu=samples"/>
-    </run-dist-tests>
-  </target>
-
-  <target name="zip" depends="dist">
-    <zip zipfile="${zipfile}" basedir="." includes="${dist}/**" />
-  </target>
-
-  <target name="upload.to.sourceforge" depends="zip">
-    <ftp server="upload.sourceforge.net"
-         userid="anonymous"
-         password="saff@mit.edu"
-         remotedir="incoming"
-         >
-      <fileset dir="${dist}" includes="*.jar" />
-      <fileset file="${zipfile}" />
-    </ftp>
-    <echo message="To upload docs, use build/upload_docs.sh" />
-  </target>
-
-  <!-- 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="push.maven.artifact">
-    <attribute name="file" />
-    <attribute name="pom" />
-    <attribute name="packaging" />
-    <attribute name="url" />
-    <attribute name="repo.id" />
-    <element name="artifact.args" implicit="true" optional="true" />
-    <sequential>
-      <artifact:mvn failonerror="true">
-        <arg value="${maven.deploy.goal}" />
-        <arg value="-Durl=@{url}" />
-        <arg value="-DrepositoryId=@{repo.id}" />
-        <arg value="-DpomFile=@{pom}" />
-        <arg value="-Dfile=@{file}" />
-        <arg value="-Dpackaging=@{packaging}" />
-        <artifact.args />
-        <arg value="-Pgpg" />
-      </artifact:mvn>
-    </sequential>
-  </macrodef>
-
-  <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>
-      <echo message="Pushing JAR to Maven: @{jar} -> @{url}" />
-      <push.maven.artifact file="@{jar}" pom="@{pom}" packaging="jar"
-                           url="@{url}" repo.id="@{repo.id}">
-      	<artifact.args />
-      </push.maven.artifact>
-    </sequential>
-  </macrodef>
-
-  <macrodef name="push.maven.pom">
-    <attribute name="pom" />
-    <attribute name="url" />
-    <attribute name="repo.id" />
-    <element name="artifact.args" implicit="true" optional="true" />
-    <sequential>
-      <echo message="Pushing POM to Maven: @{pom} -> @{url}" />
-      <push.maven.artifact file="@{pom}" pom="@{pom}" packaging="pom"
-                           url="@{url}" repo.id="@{repo.id}">
-      	<artifact.args />
-      </push.maven.artifact>
-    </sequential>
-  </macrodef>
-	
-  <macrodef name="push.junit.maven.artifact">
-    <attribute name="url" />
-    <attribute name="repo.id" />
-    <attribute name="is.snapshot" default="true" />
-    <sequential>
-      <local name="m.prefix" />
-      <property name="m.prefix" value="${dist}/junit-dep-${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-junit.xml" />
-
-      <filter token="version" value="${version}" />
-      <copy 
-          file="build/maven/junit-pom-template.xml" 
-          tofile="${m.pom}" 
-          filtering="on"
-          overwrite="true"
-          />
-
-      <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>
-          <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>
-
-  <macrodef name="push.junit-dep.maven.artifact">
-    <attribute name="url" />
-    <attribute name="repo.id" />
-    <sequential>
-      <local name="m.pom" />
-      <property name="m.pom" value="${dist}/pom-junit-dep.xml" />
-
-      <filter token="version" value="${version}" />
-      <copy 
-          file="build/maven/junit-dep-pom-template.xml" 
-          tofile="${m.pom}" 
-          filtering="on"
-          overwrite="true"
-          />
-
-      <push.maven.pom pom="${m.pom}" 
-                      url="@{url}" repo.id="@{repo.id}" />
-    </sequential>
-  </macrodef>
-
-  <target name="stage.maven" depends="all.maven.jars">
-    <property name="stage.url" 
-              value="https://oss.sonatype.org/service/local/staging/deploy/maven2/" />
-    <property name="stage.repo.id" value="sonatype-nexus-staging" />
-    
-    <push.junit.maven.artifact url="${stage.url}"
-                               repo.id="${stage.repo.id}" 
-                               is.snapshot="false" />
-    <push.junit-dep.maven.artifact url="${stage.url}"
-                                   repo.id="${stage.repo.id}" />
-  </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.junit.maven.artifact url="${snapshot.url}"
-                               repo.id="${snapshot.repo.id}" />
-    <push.junit-dep.maven.artifact url="${snapshot.url}"
-                                   repo.id="${snapshot.repo.id}" />
-  </target>
-
-  <target name="print.version">
-    <echo message="${version}" />
-  </target>
-</project>
diff --git a/build/.cvsignore b/build/.cvsignore
deleted file mode 100644
index 5d6a3e2..0000000
--- a/build/.cvsignore
+++ /dev/null
@@ -1,4 +0,0 @@
-Changes
-java.hprof.txt
-historical_javadoc
-compare_with_44.sh
diff --git a/build/.releaserc b/build/.releaserc
deleted file mode 100644
index b1dc30f..0000000
--- a/build/.releaserc
+++ /dev/null
@@ -1,8 +0,0 @@
-sf_user = dsaff
-sf_group_id = 15278
-sf_package_id = 226053
-cpan_user = <none>
-sf_release_match = junit-(.*).jar
-sf_release_replace = $1
-sf_type_id = 2601
-sf_processor_id = 8500
\ No newline at end of file
diff --git a/build/Markdown.pl b/build/Markdown.pl
deleted file mode 100755
index e4c8469..0000000
--- a/build/Markdown.pl
+++ /dev/null
@@ -1,1450 +0,0 @@
-#!/usr/bin/perl
-
-#
-# Markdown -- A text-to-HTML conversion tool for web writers
-#
-# Copyright (c) 2004 John Gruber
-# <http://daringfireball.net/projects/markdown/>
-#
-
-
-package Markdown;
-require 5.006_000;
-use strict;
-use warnings;
-
-use Digest::MD5 qw(md5_hex);
-use vars qw($VERSION);
-$VERSION = '1.0.1';
-# Tue 14 Dec 2004
-
-## Disabled; causes problems under Perl 5.6.1:
-# use utf8;
-# binmode( STDOUT, ":utf8" );  # c.f.: http://acis.openlib.org/dev/perl-unicode-struggle.html
-
-
-#
-# Global default settings:
-#
-my $g_empty_element_suffix = " />";     # Change to ">" for HTML output
-my $g_tab_width = 4;
-
-
-#
-# Globals:
-#
-
-# Regex to match balanced [brackets]. See Friedl's
-# "Mastering Regular Expressions", 2nd Ed., pp. 328-331.
-my $g_nested_brackets;
-$g_nested_brackets = qr{
-	(?> 								# Atomic matching
-	   [^\[\]]+							# Anything other than brackets
-	 | 
-	   \[
-		 (??{ $g_nested_brackets })		# Recursive set of nested brackets
-	   \]
-	)*
-}x;
-
-
-# Table of hash values for escaped characters:
-my %g_escape_table;
-foreach my $char (split //, '\\`*_{}[]()>#+-.!') {
-	$g_escape_table{$char} = md5_hex($char);
-}
-
-
-# Global hashes, used by various utility routines
-my %g_urls;
-my %g_titles;
-my %g_html_blocks;
-
-# Used to track when we're inside an ordered or unordered list
-# (see _ProcessListItems() for details):
-my $g_list_level = 0;
-
-
-#### Blosxom plug-in interface ##########################################
-
-# Set $g_blosxom_use_meta to 1 to use Blosxom's meta plug-in to determine
-# which posts Markdown should process, using a "meta-markup: markdown"
-# header. If it's set to 0 (the default), Markdown will process all
-# entries.
-my $g_blosxom_use_meta = 0;
-
-sub start { 1; }
-sub story {
-	my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
-
-	if ( (! $g_blosxom_use_meta) or
-	     (defined($meta::markup) and ($meta::markup =~ /^\s*markdown\s*$/i))
-	     ){
-			$$body_ref  = Markdown($$body_ref);
-     }
-     1;
-}
-
-
-#### Movable Type plug-in interface #####################################
-eval {require MT};  # Test to see if we're running in MT.
-unless ($@) {
-    require MT;
-    import  MT;
-    require MT::Template::Context;
-    import  MT::Template::Context;
-
-	eval {require MT::Plugin};  # Test to see if we're running >= MT 3.0.
-	unless ($@) {
-		require MT::Plugin;
-		import  MT::Plugin;
-		my $plugin = new MT::Plugin({
-			name => "Markdown",
-			description => "A plain-text-to-HTML formatting plugin. (Version: $VERSION)",
-			doc_link => 'http://daringfireball.net/projects/markdown/'
-		});
-		MT->add_plugin( $plugin );
-	}
-
-	MT::Template::Context->add_container_tag(MarkdownOptions => sub {
-		my $ctx	 = shift;
-		my $args = shift;
-		my $builder = $ctx->stash('builder');
-		my $tokens = $ctx->stash('tokens');
-
-		if (defined ($args->{'output'}) ) {
-			$ctx->stash('markdown_output', lc $args->{'output'});
-		}
-
-		defined (my $str = $builder->build($ctx, $tokens) )
-			or return $ctx->error($builder->errstr);
-		$str;		# return value
-	});
-
-	MT->add_text_filter('markdown' => {
-		label     => 'Markdown',
-		docs      => 'http://daringfireball.net/projects/markdown/',
-		on_format => sub {
-			my $text = shift;
-			my $ctx  = shift;
-			my $raw  = 0;
-		    if (defined $ctx) {
-		    	my $output = $ctx->stash('markdown_output'); 
-				if (defined $output  &&  $output =~ m/^html/i) {
-					$g_empty_element_suffix = ">";
-					$ctx->stash('markdown_output', '');
-				}
-				elsif (defined $output  &&  $output eq 'raw') {
-					$raw = 1;
-					$ctx->stash('markdown_output', '');
-				}
-				else {
-					$raw = 0;
-					$g_empty_element_suffix = " />";
-				}
-			}
-			$text = $raw ? $text : Markdown($text);
-			$text;
-		},
-	});
-
-	# If SmartyPants is loaded, add a combo Markdown/SmartyPants text filter:
-	my $smartypants;
-
-	{
-		no warnings "once";
-		$smartypants = $MT::Template::Context::Global_filters{'smarty_pants'};
-	}
-
-	if ($smartypants) {
-		MT->add_text_filter('markdown_with_smartypants' => {
-			label     => 'Markdown With SmartyPants',
-			docs      => 'http://daringfireball.net/projects/markdown/',
-			on_format => sub {
-				my $text = shift;
-				my $ctx  = shift;
-				if (defined $ctx) {
-					my $output = $ctx->stash('markdown_output'); 
-					if (defined $output  &&  $output eq 'html') {
-						$g_empty_element_suffix = ">";
-					}
-					else {
-						$g_empty_element_suffix = " />";
-					}
-				}
-				$text = Markdown($text);
-				$text = $smartypants->($text, '1');
-			},
-		});
-	}
-}
-else {
-#### BBEdit/command-line text filter interface ##########################
-# Needs to be hidden from MT (and Blosxom when running in static mode).
-
-    # We're only using $blosxom::version once; tell Perl not to warn us:
-	no warnings 'once';
-    unless ( defined($blosxom::version) ) {
-		use warnings;
-
-		#### Check for command-line switches: #################
-		my %cli_opts;
-		use Getopt::Long;
-		Getopt::Long::Configure('pass_through');
-		GetOptions(\%cli_opts,
-			'version',
-			'shortversion',
-			'html4tags',
-		);
-		if ($cli_opts{'version'}) {		# Version info
-			print "\nThis is Markdown, version $VERSION.\n";
-			print "Copyright 2004 John Gruber\n";
-			print "http://daringfireball.net/projects/markdown/\n\n";
-			exit 0;
-		}
-		if ($cli_opts{'shortversion'}) {		# Just the version number string.
-			print $VERSION;
-			exit 0;
-		}
-		if ($cli_opts{'html4tags'}) {			# Use HTML tag style instead of XHTML
-			$g_empty_element_suffix = ">";
-		}
-
-
-		#### Process incoming text: ###########################
-		my $text;
-		{
-			local $/;               # Slurp the whole file
-			$text = <>;
-		}
-        print Markdown($text);
-    }
-}
-
-
-
-sub Markdown {
-#
-# Main function. The order in which other subs are called here is
-# essential. Link and image substitutions need to happen before
-# _EscapeSpecialChars(), so that any *'s or _'s in the <a>
-# and <img> tags get encoded.
-#
-	my $text = shift;
-
-	# Clear the global hashes. If we don't clear these, you get conflicts
-	# from other articles when generating a page which contains more than
-	# one article (e.g. an index page that shows the N most recent
-	# articles):
-	%g_urls = ();
-	%g_titles = ();
-	%g_html_blocks = ();
-
-
-	# Standardize line endings:
-	$text =~ s{\r\n}{\n}g; 	# DOS to Unix
-	$text =~ s{\r}{\n}g; 	# Mac to Unix
-
-	# Make sure $text ends with a couple of newlines:
-	$text .= "\n\n";
-
-	# Convert all tabs to spaces.
-	$text = _Detab($text);
-
-	# Strip any lines consisting only of spaces and tabs.
-	# This makes subsequent regexen easier to write, because we can
-	# match consecutive blank lines with /\n+/ instead of something
-	# contorted like /[ \t]*\n+/ .
-	$text =~ s/^[ \t]+$//mg;
-
-	# Turn block-level HTML blocks into hash entries
-	$text = _HashHTMLBlocks($text);
-
-	# Strip link definitions, store in hashes.
-	$text = _StripLinkDefinitions($text);
-
-	$text = _RunBlockGamut($text);
-
-	$text = _UnescapeSpecialChars($text);
-
-	return $text . "\n";
-}
-
-
-sub _StripLinkDefinitions {
-#
-# Strips link definitions from text, stores the URLs and titles in
-# hash references.
-#
-	my $text = shift;
-	my $less_than_tab = $g_tab_width - 1;
-
-	# Link defs are in the form: ^[id]: url "optional title"
-	while ($text =~ s{
-						^[ ]{0,$less_than_tab}\[(.+)\]:	# id = $1
-						  [ \t]*
-						  \n?				# maybe *one* newline
-						  [ \t]*
-						<?(\S+?)>?			# url = $2
-						  [ \t]*
-						  \n?				# maybe one newline
-						  [ \t]*
-						(?:
-							(?<=\s)			# lookbehind for whitespace
-							["(]
-							(.+?)			# title = $3
-							[")]
-							[ \t]*
-						)?	# title is optional
-						(?:\n+|\Z)
-					}
-					{}mx) {
-		$g_urls{lc $1} = _EncodeAmpsAndAngles( $2 );	# Link IDs are case-insensitive
-		if ($3) {
-			$g_titles{lc $1} = $3;
-			$g_titles{lc $1} =~ s/"/&quot;/g;
-		}
-	}
-
-	return $text;
-}
-
-
-sub _HashHTMLBlocks {
-	my $text = shift;
-	my $less_than_tab = $g_tab_width - 1;
-
-	# Hashify HTML blocks:
-	# We only want to do this for block-level HTML tags, such as headers,
-	# lists, and tables. That's because we still want to wrap <p>s around
-	# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
-	# phrase emphasis, and spans. The list of tags we're looking for is
-	# hard-coded:
-	my $block_tags_a = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del/;
-	my $block_tags_b = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math/;
-
-	# First, look for nested blocks, e.g.:
-	# 	<div>
-	# 		<div>
-	# 		tags for inner block must be indented.
-	# 		</div>
-	# 	</div>
-	#
-	# The outermost tags must start at the left margin for this to match, and
-	# the inner nested divs must be indented.
-	# We need to do this before the next, more liberal match, because the next
-	# match will start at the first `<div>` and stop at the first `</div>`.
-	$text =~ s{
-				(						# save in $1
-					^					# start of line  (with /m)
-					<($block_tags_a)	# start tag = $2
-					\b					# word break
-					(.*\n)*?			# any number of lines, minimally matching
-					</\2>				# the matching end tag
-					[ \t]*				# trailing spaces/tabs
-					(?=\n+|\Z)	# followed by a newline or end of document
-				)
-			}{
-				my $key = md5_hex($1);
-				$g_html_blocks{$key} = $1;
-				"\n\n" . $key . "\n\n";
-			}egmx;
-
-
-	#
-	# Now match more liberally, simply from `\n<tag>` to `</tag>\n`
-	#
-	$text =~ s{
-				(						# save in $1
-					^					# start of line  (with /m)
-					<($block_tags_b)	# start tag = $2
-					\b					# word break
-					(.*\n)*?			# any number of lines, minimally matching
-					.*</\2>				# the matching end tag
-					[ \t]*				# trailing spaces/tabs
-					(?=\n+|\Z)	# followed by a newline or end of document
-				)
-			}{
-				my $key = md5_hex($1);
-				$g_html_blocks{$key} = $1;
-				"\n\n" . $key . "\n\n";
-			}egmx;
-	# Special case just for <hr />. It was easier to make a special case than
-	# to make the other regex more complicated.	
-	$text =~ s{
-				(?:
-					(?<=\n\n)		# Starting after a blank line
-					|				# or
-					\A\n?			# the beginning of the doc
-				)
-				(						# save in $1
-					[ ]{0,$less_than_tab}
-					<(hr)				# start tag = $2
-					\b					# word break
-					([^<>])*?			# 
-					/?>					# the matching end tag
-					[ \t]*
-					(?=\n{2,}|\Z)		# followed by a blank line or end of document
-				)
-			}{
-				my $key = md5_hex($1);
-				$g_html_blocks{$key} = $1;
-				"\n\n" . $key . "\n\n";
-			}egx;
-
-	# Special case for standalone HTML comments:
-	$text =~ s{
-				(?:
-					(?<=\n\n)		# Starting after a blank line
-					|				# or
-					\A\n?			# the beginning of the doc
-				)
-				(						# save in $1
-					[ ]{0,$less_than_tab}
-					(?s:
-						<!
-						(--.*?--\s*)+
-						>
-					)
-					[ \t]*
-					(?=\n{2,}|\Z)		# followed by a blank line or end of document
-				)
-			}{
-				my $key = md5_hex($1);
-				$g_html_blocks{$key} = $1;
-				"\n\n" . $key . "\n\n";
-			}egx;
-
-
-	return $text;
-}
-
-
-sub _RunBlockGamut {
-#
-# These are all the transformations that form block-level
-# tags like paragraphs, headers, and list items.
-#
-	my $text = shift;
-
-	$text = _DoHeaders($text);
-
-	# Do Horizontal Rules:
-	$text =~ s{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}{\n<hr$g_empty_element_suffix\n}gmx;
-	$text =~ s{^[ ]{0,2}([ ]? -[ ]?){3,}[ \t]*$}{\n<hr$g_empty_element_suffix\n}gmx;
-	$text =~ s{^[ ]{0,2}([ ]? _[ ]?){3,}[ \t]*$}{\n<hr$g_empty_element_suffix\n}gmx;
-
-	$text = _DoLists($text);
-
-	$text = _DoCodeBlocks($text);
-
-	$text = _DoBlockQuotes($text);
-
-	# We already ran _HashHTMLBlocks() before, in Markdown(), but that
-	# was to escape raw HTML in the original Markdown source. This time,
-	# we're escaping the markup we've just created, so that we don't wrap
-	# <p> tags around block-level tags.
-	$text = _HashHTMLBlocks($text);
-
-	$text = _FormParagraphs($text);
-
-	return $text;
-}
-
-
-sub _RunSpanGamut {
-#
-# These are all the transformations that occur *within* block-level
-# tags like paragraphs, headers, and list items.
-#
-	my $text = shift;
-
-	$text = _DoCodeSpans($text);
-
-	$text = _EscapeSpecialChars($text);
-
-	# Process anchor and image tags. Images must come first,
-	# because ![foo][f] looks like an anchor.
-	$text = _DoImages($text);
-	$text = _DoAnchors($text);
-
-	# Make links out of things like `<http://example.com/>`
-	# Must come after _DoAnchors(), because you can use < and >
-	# delimiters in inline links like [this](<url>).
-	$text = _DoAutoLinks($text);
-
-	$text = _EncodeAmpsAndAngles($text);
-
-	$text = _DoItalicsAndBold($text);
-
-	# Do hard breaks:
-	$text =~ s/ {2,}\n/ <br$g_empty_element_suffix\n/g;
-
-	return $text;
-}
-
-
-sub _EscapeSpecialChars {
-	my $text = shift;
-	my $tokens ||= _TokenizeHTML($text);
-
-	$text = '';   # rebuild $text from the tokens
-# 	my $in_pre = 0;	 # Keep track of when we're inside <pre> or <code> tags.
-# 	my $tags_to_skip = qr!<(/?)(?:pre|code|kbd|script|math)[\s>]!;
-
-	foreach my $cur_token (@$tokens) {
-		if ($cur_token->[0] eq "tag") {
-			# Within tags, encode * and _ so they don't conflict
-			# with their use in Markdown for italics and strong.
-			# We're replacing each such character with its
-			# corresponding MD5 checksum value; this is likely
-			# overkill, but it should prevent us from colliding
-			# with the escape values by accident.
-			$cur_token->[1] =~  s! \* !$g_escape_table{'*'}!gx;
-			$cur_token->[1] =~  s! _  !$g_escape_table{'_'}!gx;
-			$text .= $cur_token->[1];
-		} else {
-			my $t = $cur_token->[1];
-			$t = _EncodeBackslashEscapes($t);
-			$text .= $t;
-		}
-	}
-	return $text;
-}
-
-
-sub _DoAnchors {
-#
-# Turn Markdown link shortcuts into XHTML <a> tags.
-#
-	my $text = shift;
-
-	#
-	# First, handle reference-style links: [link text] [id]
-	#
-	$text =~ s{
-		(					# wrap whole match in $1
-		  \[
-		    ($g_nested_brackets)	# link text = $2
-		  \]
-
-		  [ ]?				# one optional space
-		  (?:\n[ ]*)?		# one optional newline followed by spaces
-
-		  \[
-		    (.*?)		# id = $3
-		  \]
-		)
-	}{
-		my $result;
-		my $whole_match = $1;
-		my $link_text   = $2;
-		my $link_id     = lc $3;
-
-		if ($link_id eq "") {
-			$link_id = lc $link_text;     # for shortcut links like [this][].
-		}
-
-		if (defined $g_urls{$link_id}) {
-			my $url = $g_urls{$link_id};
-			$url =~ s! \* !$g_escape_table{'*'}!gx;		# We've got to encode these to avoid
-			$url =~ s!  _ !$g_escape_table{'_'}!gx;		# conflicting with italics/bold.
-			$result = "<a href=\"$url\"";
-			if ( defined $g_titles{$link_id} ) {
-				my $title = $g_titles{$link_id};
-				$title =~ s! \* !$g_escape_table{'*'}!gx;
-				$title =~ s!  _ !$g_escape_table{'_'}!gx;
-				$result .=  " title=\"$title\"";
-			}
-			$result .= ">$link_text</a>";
-		}
-		else {
-			$result = $whole_match;
-		}
-		$result;
-	}xsge;
-
-	#
-	# Next, inline-style links: [link text](url "optional title")
-	#
-	$text =~ s{
-		(				# wrap whole match in $1
-		  \[
-		    ($g_nested_brackets)	# link text = $2
-		  \]
-		  \(			# literal paren
-		  	[ \t]*
-			<?(.*?)>?	# href = $3
-		  	[ \t]*
-			(			# $4
-			  (['"])	# quote char = $5
-			  (.*?)		# Title = $6
-			  \5		# matching quote
-			)?			# title is optional
-		  \)
-		)
-	}{
-		my $result;
-		my $whole_match = $1;
-		my $link_text   = $2;
-		my $url	  		= $3;
-		my $title		= $6;
-
-		$url =~ s! \* !$g_escape_table{'*'}!gx;		# We've got to encode these to avoid
-		$url =~ s!  _ !$g_escape_table{'_'}!gx;		# conflicting with italics/bold.
-		$result = "<a href=\"$url\"";
-
-		if (defined $title) {
-			$title =~ s/"/&quot;/g;
-			$title =~ s! \* !$g_escape_table{'*'}!gx;
-			$title =~ s!  _ !$g_escape_table{'_'}!gx;
-			$result .=  " title=\"$title\"";
-		}
-
-		$result .= ">$link_text</a>";
-
-		$result;
-	}xsge;
-
-	return $text;
-}
-
-
-sub _DoImages {
-#
-# Turn Markdown image shortcuts into <img> tags.
-#
-	my $text = shift;
-
-	#
-	# First, handle reference-style labeled images: ![alt text][id]
-	#
-	$text =~ s{
-		(				# wrap whole match in $1
-		  !\[
-		    (.*?)		# alt text = $2
-		  \]
-
-		  [ ]?				# one optional space
-		  (?:\n[ ]*)?		# one optional newline followed by spaces
-
-		  \[
-		    (.*?)		# id = $3
-		  \]
-
-		)
-	}{
-		my $result;
-		my $whole_match = $1;
-		my $alt_text    = $2;
-		my $link_id     = lc $3;
-
-		if ($link_id eq "") {
-			$link_id = lc $alt_text;     # for shortcut links like ![this][].
-		}
-
-		$alt_text =~ s/"/&quot;/g;
-		if (defined $g_urls{$link_id}) {
-			my $url = $g_urls{$link_id};
-			$url =~ s! \* !$g_escape_table{'*'}!gx;		# We've got to encode these to avoid
-			$url =~ s!  _ !$g_escape_table{'_'}!gx;		# conflicting with italics/bold.
-			$result = "<img src=\"$url\" alt=\"$alt_text\"";
-			if (defined $g_titles{$link_id}) {
-				my $title = $g_titles{$link_id};
-				$title =~ s! \* !$g_escape_table{'*'}!gx;
-				$title =~ s!  _ !$g_escape_table{'_'}!gx;
-				$result .=  " title=\"$title\"";
-			}
-			$result .= $g_empty_element_suffix;
-		}
-		else {
-			# If there's no such link ID, leave intact:
-			$result = $whole_match;
-		}
-
-		$result;
-	}xsge;
-
-	#
-	# Next, handle inline images:  ![alt text](url "optional title")
-	# Don't forget: encode * and _
-
-	$text =~ s{
-		(				# wrap whole match in $1
-		  !\[
-		    (.*?)		# alt text = $2
-		  \]
-		  \(			# literal paren
-		  	[ \t]*
-			<?(\S+?)>?	# src url = $3
-		  	[ \t]*
-			(			# $4
-			  (['"])	# quote char = $5
-			  (.*?)		# title = $6
-			  \5		# matching quote
-			  [ \t]*
-			)?			# title is optional
-		  \)
-		)
-	}{
-		my $result;
-		my $whole_match = $1;
-		my $alt_text    = $2;
-		my $url	  		= $3;
-		my $title		= '';
-		if (defined($6)) {
-			$title		= $6;
-		}
-
-		$alt_text =~ s/"/&quot;/g;
-		$title    =~ s/"/&quot;/g;
-		$url =~ s! \* !$g_escape_table{'*'}!gx;		# We've got to encode these to avoid
-		$url =~ s!  _ !$g_escape_table{'_'}!gx;		# conflicting with italics/bold.
-		$result = "<img src=\"$url\" alt=\"$alt_text\"";
-		if (defined $title) {
-			$title =~ s! \* !$g_escape_table{'*'}!gx;
-			$title =~ s!  _ !$g_escape_table{'_'}!gx;
-			$result .=  " title=\"$title\"";
-		}
-		$result .= $g_empty_element_suffix;
-
-		$result;
-	}xsge;
-
-	return $text;
-}
-
-
-sub _DoHeaders {
-	my $text = shift;
-
-	# Setext-style headers:
-	#	  Header 1
-	#	  ========
-	#  
-	#	  Header 2
-	#	  --------
-	#
-	$text =~ s{ ^(.+)[ \t]*\n=+[ \t]*\n+ }{
-		"<h1>"  .  _RunSpanGamut($1)  .  "</h1>\n\n";
-	}egmx;
-
-	$text =~ s{ ^(.+)[ \t]*\n-+[ \t]*\n+ }{
-		"<h2>"  .  _RunSpanGamut($1)  .  "</h2>\n\n";
-	}egmx;
-
-
-	# atx-style headers:
-	#	# Header 1
-	#	## Header 2
-	#	## Header 2 with closing hashes ##
-	#	...
-	#	###### Header 6
-	#
-	$text =~ s{
-			^(\#{1,6})	# $1 = string of #'s
-			[ \t]*
-			(.+?)		# $2 = Header text
-			[ \t]*
-			\#*			# optional closing #'s (not counted)
-			\n+
-		}{
-			my $h_level = length($1);
-			"<h$h_level>"  .  _RunSpanGamut($2)  .  "</h$h_level>\n\n";
-		}egmx;
-
-	return $text;
-}
-
-
-sub _DoLists {
-#
-# Form HTML ordered (numbered) and unordered (bulleted) lists.
-#
-	my $text = shift;
-	my $less_than_tab = $g_tab_width - 1;
-
-	# Re-usable patterns to match list item bullets and number markers:
-	my $marker_ul  = qr/[*+-]/;
-	my $marker_ol  = qr/\d+[.]/;
-	my $marker_any = qr/(?:$marker_ul|$marker_ol)/;
-
-	# Re-usable pattern to match any entirel ul or ol list:
-	my $whole_list = qr{
-		(								# $1 = whole list
-		  (								# $2
-			[ ]{0,$less_than_tab}
-			(${marker_any})				# $3 = first list item marker
-			[ \t]+
-		  )
-		  (?s:.+?)
-		  (								# $4
-			  \z
-			|
-			  \n{2,}
-			  (?=\S)
-			  (?!						# Negative lookahead for another list item marker
-				[ \t]*
-				${marker_any}[ \t]+
-			  )
-		  )
-		)
-	}mx;
-
-	# We use a different prefix before nested lists than top-level lists.
-	# See extended comment in _ProcessListItems().
-	#
-	# Note: There's a bit of duplication here. My original implementation
-	# created a scalar regex pattern as the conditional result of the test on
-	# $g_list_level, and then only ran the $text =~ s{...}{...}egmx
-	# substitution once, using the scalar as the pattern. This worked,
-	# everywhere except when running under MT on my hosting account at Pair
-	# Networks. There, this caused all rebuilds to be killed by the reaper (or
-	# perhaps they crashed, but that seems incredibly unlikely given that the
-	# same script on the same server ran fine *except* under MT. I've spent
-	# more time trying to figure out why this is happening than I'd like to
-	# admit. My only guess, backed up by the fact that this workaround works,
-	# is that Perl optimizes the substition when it can figure out that the
-	# pattern will never change, and when this optimization isn't on, we run
-	# afoul of the reaper. Thus, the slightly redundant code to that uses two
-	# static s/// patterns rather than one conditional pattern.
-
-	if ($g_list_level) {
-		$text =~ s{
-				^
-				$whole_list
-			}{
-				my $list = $1;
-				my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol";
-				# Turn double returns into triple returns, so that we can make a
-				# paragraph for the last item in a list, if necessary:
-				$list =~ s/\n{2,}/\n\n\n/g;
-				my $result = _ProcessListItems($list, $marker_any);
-				$result = "<$list_type>\n" . $result . "</$list_type>\n";
-				$result;
-			}egmx;
-	}
-	else {
-		$text =~ s{
-				(?:(?<=\n\n)|\A\n?)
-				$whole_list
-			}{
-				my $list = $1;
-				my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol";
-				# Turn double returns into triple returns, so that we can make a
-				# paragraph for the last item in a list, if necessary:
-				$list =~ s/\n{2,}/\n\n\n/g;
-				my $result = _ProcessListItems($list, $marker_any);
-				$result = "<$list_type>\n" . $result . "</$list_type>\n";
-				$result;
-			}egmx;
-	}
-
-
-	return $text;
-}
-
-
-sub _ProcessListItems {
-#
-#	Process the contents of a single ordered or unordered list, splitting it
-#	into individual list items.
-#
-
-	my $list_str = shift;
-	my $marker_any = shift;
-
-
-	# The $g_list_level global keeps track of when we're inside a list.
-	# Each time we enter a list, we increment it; when we leave a list,
-	# we decrement. If it's zero, we're not in a list anymore.
-	#
-	# We do this because when we're not inside a list, we want to treat
-	# something like this:
-	#
-	#		I recommend upgrading to version
-	#		8. Oops, now this line is treated
-	#		as a sub-list.
-	#
-	# As a single paragraph, despite the fact that the second line starts
-	# with a digit-period-space sequence.
-	#
-	# Whereas when we're inside a list (or sub-list), that line will be
-	# treated as the start of a sub-list. What a kludge, huh? This is
-	# an aspect of Markdown's syntax that's hard to parse perfectly
-	# without resorting to mind-reading. Perhaps the solution is to
-	# change the syntax rules such that sub-lists must start with a
-	# starting cardinal number; e.g. "1." or "a.".
-
-	$g_list_level++;
-
-	# trim trailing blank lines:
-	$list_str =~ s/\n{2,}\z/\n/;
-
-
-	$list_str =~ s{
-		(\n)?							# leading line = $1
-		(^[ \t]*)						# leading whitespace = $2
-		($marker_any) [ \t]+			# list marker = $3
-		((?s:.+?)						# list item text   = $4
-		(\n{1,2}))
-		(?= \n* (\z | \2 ($marker_any) [ \t]+))
-	}{
-		my $item = $4;
-		my $leading_line = $1;
-		my $leading_space = $2;
-
-		if ($leading_line or ($item =~ m/\n{2,}/)) {
-			$item = _RunBlockGamut(_Outdent($item));
-		}
-		else {
-			# Recursion for sub-lists:
-			$item = _DoLists(_Outdent($item));
-			chomp $item;
-			$item = _RunSpanGamut($item);
-		}
-
-		"<li>" . $item . "</li>\n";
-	}egmx;
-
-	$g_list_level--;
-	return $list_str;
-}
-
-
-
-sub _DoCodeBlocks {
-#
-#	Process Markdown `<pre><code>` blocks.
-#	
-
-	my $text = shift;
-
-	$text =~ s{
-			(?:\n\n|\A)
-			(	            # $1 = the code block -- one or more lines, starting with a space/tab
-			  (?:
-			    (?:[ ]{$g_tab_width} | \t)  # Lines must start with a tab or a tab-width of spaces
-			    .*\n+
-			  )+
-			)
-			((?=^[ ]{0,$g_tab_width}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
-		}{
-			my $codeblock = $1;
-			my $result; # return value
-
-			$codeblock = _EncodeCode(_Outdent($codeblock));
-			$codeblock = _Detab($codeblock);
-			$codeblock =~ s/\A\n+//; # trim leading newlines
-			$codeblock =~ s/\s+\z//; # trim trailing whitespace
-
-			$result = "\n\n<pre><code>" . $codeblock . "\n</code></pre>\n\n";
-
-			$result;
-		}egmx;
-
-	return $text;
-}
-
-
-sub _DoCodeSpans {
-#
-# 	*	Backtick quotes are used for <code></code> spans.
-# 
-# 	*	You can use multiple backticks as the delimiters if you want to
-# 		include literal backticks in the code span. So, this input:
-#     
-#         Just type ``foo `bar` baz`` at the prompt.
-#     
-#     	Will translate to:
-#     
-#         <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
-#     
-#		There's no arbitrary limit to the number of backticks you
-#		can use as delimters. If you need three consecutive backticks
-#		in your code, use four for delimiters, etc.
-#
-#	*	You can use spaces to get literal backticks at the edges:
-#     
-#         ... type `` `bar` `` ...
-#     
-#     	Turns to:
-#     
-#         ... type <code>`bar`</code> ...
-#
-
-	my $text = shift;
-
-	$text =~ s@
-			(`+)		# $1 = Opening run of `
-			(.+?)		# $2 = The code block
-			(?<!`)
-			\1			# Matching closer
-			(?!`)
-		@
- 			my $c = "$2";
- 			$c =~ s/^[ \t]*//g; # leading whitespace
- 			$c =~ s/[ \t]*$//g; # trailing whitespace
- 			$c = _EncodeCode($c);
-			"<code>$c</code>";
-		@egsx;
-
-	return $text;
-}
-
-
-sub _EncodeCode {
-#
-# Encode/escape certain characters inside Markdown code runs.
-# The point is that in code, these characters are literals,
-# and lose their special Markdown meanings.
-#
-    local $_ = shift;
-
-	# Encode all ampersands; HTML entities are not
-	# entities within a Markdown code span.
-	s/&/&amp;/g;
-
-	# Encode $'s, but only if we're running under Blosxom.
-	# (Blosxom interpolates Perl variables in article bodies.)
-	{
-		no warnings 'once';
-    	if (defined($blosxom::version)) {
-    		s/\$/&#036;/g;	
-    	}
-    }
-
-
-	# Do the angle bracket song and dance:
-	s! <  !&lt;!gx;
-	s! >  !&gt;!gx;
-
-	# Now, escape characters that are magic in Markdown:
-	s! \* !$g_escape_table{'*'}!gx;
-	s! _  !$g_escape_table{'_'}!gx;
-	s! {  !$g_escape_table{'{'}!gx;
-	s! }  !$g_escape_table{'}'}!gx;
-	s! \[ !$g_escape_table{'['}!gx;
-	s! \] !$g_escape_table{']'}!gx;
-	s! \\ !$g_escape_table{'\\'}!gx;
-
-	return $_;
-}
-
-
-sub _DoItalicsAndBold {
-	my $text = shift;
-
-	# <strong> must go first:
-	$text =~ s{ (\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1 }
-		{<strong>$2</strong>}gsx;
-
-	$text =~ s{ (\*|_) (?=\S) (.+?) (?<=\S) \1 }
-		{<em>$2</em>}gsx;
-
-	return $text;
-}
-
-
-sub _DoBlockQuotes {
-	my $text = shift;
-
-	$text =~ s{
-		  (								# Wrap whole match in $1
-			(
-			  ^[ \t]*>[ \t]?			# '>' at the start of a line
-			    .+\n					# rest of the first line
-			  (.+\n)*					# subsequent consecutive lines
-			  \n*						# blanks
-			)+
-		  )
-		}{
-			my $bq = $1;
-			$bq =~ s/^[ \t]*>[ \t]?//gm;	# trim one level of quoting
-			$bq =~ s/^[ \t]+$//mg;			# trim whitespace-only lines
-			$bq = _RunBlockGamut($bq);		# recurse
-
-			$bq =~ s/^/  /g;
-			# These leading spaces screw with <pre> content, so we need to fix that:
-			$bq =~ s{
-					(\s*<pre>.+?</pre>)
-				}{
-					my $pre = $1;
-					$pre =~ s/^  //mg;
-					$pre;
-				}egsx;
-
-			"<blockquote>\n$bq\n</blockquote>\n\n";
-		}egmx;
-
-
-	return $text;
-}
-
-
-sub _FormParagraphs {
-#
-#	Params:
-#		$text - string to process with html <p> tags
-#
-	my $text = shift;
-
-	# Strip leading and trailing lines:
-	$text =~ s/\A\n+//;
-	$text =~ s/\n+\z//;
-
-	my @grafs = split(/\n{2,}/, $text);
-
-	#
-	# Wrap <p> tags.
-	#
-	foreach (@grafs) {
-		unless (defined( $g_html_blocks{$_} )) {
-			$_ = _RunSpanGamut($_);
-			s/^([ \t]*)/<p>/;
-			$_ .= "</p>";
-		}
-	}
-
-	#
-	# Unhashify HTML blocks
-	#
-	foreach (@grafs) {
-		if (defined( $g_html_blocks{$_} )) {
-			$_ = $g_html_blocks{$_};
-		}
-	}
-
-	return join "\n\n", @grafs;
-}
-
-
-sub _EncodeAmpsAndAngles {
-# Smart processing for ampersands and angle brackets that need to be encoded.
-
-	my $text = shift;
-
-	# Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
-	#   http://bumppo.net/projects/amputator/
- 	$text =~ s/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/&amp;/g;
-
-	# Encode naked <'s
- 	$text =~ s{<(?![a-z/?\$!])}{&lt;}gi;
-
-	return $text;
-}
-
-
-sub _EncodeBackslashEscapes {
-#
-#   Parameter:  String.
-#   Returns:    The string, with after processing the following backslash
-#               escape sequences.
-#
-    local $_ = shift;
-
-    s! \\\\  !$g_escape_table{'\\'}!gx;		# Must process escaped backslashes first.
-    s! \\`   !$g_escape_table{'`'}!gx;
-    s! \\\*  !$g_escape_table{'*'}!gx;
-    s! \\_   !$g_escape_table{'_'}!gx;
-    s! \\\{  !$g_escape_table{'{'}!gx;
-    s! \\\}  !$g_escape_table{'}'}!gx;
-    s! \\\[  !$g_escape_table{'['}!gx;
-    s! \\\]  !$g_escape_table{']'}!gx;
-    s! \\\(  !$g_escape_table{'('}!gx;
-    s! \\\)  !$g_escape_table{')'}!gx;
-    s! \\>   !$g_escape_table{'>'}!gx;
-    s! \\\#  !$g_escape_table{'#'}!gx;
-    s! \\\+  !$g_escape_table{'+'}!gx;
-    s! \\\-  !$g_escape_table{'-'}!gx;
-    s! \\\.  !$g_escape_table{'.'}!gx;
-    s{ \\!  }{$g_escape_table{'!'}}gx;
-
-    return $_;
-}
-
-
-sub _DoAutoLinks {
-	my $text = shift;
-
-	$text =~ s{<((https?|ftp):[^'">\s]+)>}{<a href="$1">$1</a>}gi;
-
-	# Email addresses: <address@domain.foo>
-	$text =~ s{
-		<
-        (?:mailto:)?
-		(
-			[-.\w]+
-			\@
-			[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
-		)
-		>
-	}{
-		_EncodeEmailAddress( _UnescapeSpecialChars($1) );
-	}egix;
-
-	return $text;
-}
-
-
-sub _EncodeEmailAddress {
-#
-#	Input: an email address, e.g. "foo@example.com"
-#
-#	Output: the email address as a mailto link, with each character
-#		of the address encoded as either a decimal or hex entity, in
-#		the hopes of foiling most address harvesting spam bots. E.g.:
-#
-#	  <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;
-#       x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;
-#       &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>
-#
-#	Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
-#	mailing list: <http://tinyurl.com/yu7ue>
-#
-
-	my $addr = shift;
-
-	srand;
-	my @encode = (
-		sub { '&#' .                 ord(shift)   . ';' },
-		sub { '&#x' . sprintf( "%X", ord(shift) ) . ';' },
-		sub {                            shift          },
-	);
-
-	$addr = "mailto:" . $addr;
-
-	$addr =~ s{(.)}{
-		my $char = $1;
-		if ( $char eq '@' ) {
-			# this *must* be encoded. I insist.
-			$char = $encode[int rand 1]->($char);
-		} elsif ( $char ne ':' ) {
-			# leave ':' alone (to spot mailto: later)
-			my $r = rand;
-			# roughly 10% raw, 45% hex, 45% dec
-			$char = (
-				$r > .9   ?  $encode[2]->($char)  :
-				$r < .45  ?  $encode[1]->($char)  :
-							 $encode[0]->($char)
-			);
-		}
-		$char;
-	}gex;
-
-	$addr = qq{<a href="$addr">$addr</a>};
-	$addr =~ s{">.+?:}{">}; # strip the mailto: from the visible part
-
-	return $addr;
-}
-
-
-sub _UnescapeSpecialChars {
-#
-# Swap back in all the special characters we've hidden.
-#
-	my $text = shift;
-
-	while( my($char, $hash) = each(%g_escape_table) ) {
-		$text =~ s/$hash/$char/g;
-	}
-    return $text;
-}
-
-
-sub _TokenizeHTML {
-#
-#   Parameter:  String containing HTML markup.
-#   Returns:    Reference to an array of the tokens comprising the input
-#               string. Each token is either a tag (possibly with nested,
-#               tags contained therein, such as <a href="<MTFoo>">, or a
-#               run of text between tags. Each element of the array is a
-#               two-element array; the first is either 'tag' or 'text';
-#               the second is the actual value.
-#
-#
-#   Derived from the _tokenize() subroutine from Brad Choate's MTRegex plugin.
-#       <http://www.bradchoate.com/past/mtregex.php>
-#
-
-    my $str = shift;
-    my $pos = 0;
-    my $len = length $str;
-    my @tokens;
-
-    my $depth = 6;
-    my $nested_tags = join('|', ('(?:<[a-z/!$](?:[^<>]') x $depth) . (')*>)' x  $depth);
-    my $match = qr/(?s: <! ( -- .*? -- \s* )+ > ) |  # comment
-                   (?s: <\? .*? \?> ) |              # processing instruction
-                   $nested_tags/ix;                   # nested tags
-
-    while ($str =~ m/($match)/g) {
-        my $whole_tag = $1;
-        my $sec_start = pos $str;
-        my $tag_start = $sec_start - length $whole_tag;
-        if ($pos < $tag_start) {
-            push @tokens, ['text', substr($str, $pos, $tag_start - $pos)];
-        }
-        push @tokens, ['tag', $whole_tag];
-        $pos = pos $str;
-    }
-    push @tokens, ['text', substr($str, $pos, $len - $pos)] if $pos < $len;
-    \@tokens;
-}
-
-
-sub _Outdent {
-#
-# Remove one level of line-leading tabs or spaces
-#
-	my $text = shift;
-
-	$text =~ s/^(\t|[ ]{1,$g_tab_width})//gm;
-	return $text;
-}
-
-
-sub _Detab {
-#
-# Cribbed from a post by Bart Lateur:
-# <http://www.nntp.perl.org/group/perl.macperl.anyperl/154>
-#
-	my $text = shift;
-
-	$text =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge;
-	return $text;
-}
-
-
-1;
-
-__END__
-
-
-=pod
-
-=head1 NAME
-
-B<Markdown>
-
-
-=head1 SYNOPSIS
-
-B<Markdown.pl> [ B<--html4tags> ] [ B<--version> ] [ B<-shortversion> ]
-    [ I<file> ... ]
-
-
-=head1 DESCRIPTION
-
-Markdown is a text-to-HTML filter; it translates an easy-to-read /
-easy-to-write structured text format into HTML. Markdown's text format
-is most similar to that of plain text email, and supports features such
-as headers, *emphasis*, code blocks, blockquotes, and links.
-
-Markdown's syntax is designed not as a generic markup language, but
-specifically to serve as a front-end to (X)HTML. You can  use span-level
-HTML tags anywhere in a Markdown document, and you can use block level
-HTML tags (like <div> and <table> as well).
-
-For more information about Markdown's syntax, see:
-
-    http://daringfireball.net/projects/markdown/
-
-
-=head1 OPTIONS
-
-Use "--" to end switch parsing. For example, to open a file named "-z", use:
-
-	Markdown.pl -- -z
-
-=over 4
-
-
-=item B<--html4tags>
-
-Use HTML 4 style for empty element tags, e.g.:
-
-    <br>
-
-instead of Markdown's default XHTML style tags, e.g.:
-
-    <br />
-
-
-=item B<-v>, B<--version>
-
-Display Markdown's version number and copyright information.
-
-
-=item B<-s>, B<--shortversion>
-
-Display the short-form version number.
-
-
-=back
-
-
-
-=head1 BUGS
-
-To file bug reports or feature requests (other than topics listed in the
-Caveats section above) please send email to:
-
-    support@daringfireball.net
-
-Please include with your report: (1) the example input; (2) the output
-you expected; (3) the output Markdown actually produced.
-
-
-=head1 VERSION HISTORY
-
-See the readme file for detailed release notes for this version.
-
-1.0.1 - 14 Dec 2004
-
-1.0 - 28 Aug 2004
-
-
-=head1 AUTHOR
-
-    John Gruber
-    http://daringfireball.net
-
-    PHP port and other contributions by Michel Fortin
-    http://michelf.com
-
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2003-2004 John Gruber   
-<http://daringfireball.net/>   
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-* Redistributions of source code must retain the above copyright notice,
-  this list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-
-* Neither the name "Markdown" nor the names of its contributors may
-  be used to endorse or promote products derived from this software
-  without specific prior written permission.
-
-This software is provided by the copyright holders and contributors "as
-is" and any express or implied warranties, including, but not limited
-to, the implied warranties of merchantability and fitness for a
-particular purpose are disclaimed. In no event shall the copyright owner
-or contributors be liable for any direct, indirect, incidental, special,
-exemplary, or consequential damages (including, but not limited to,
-procurement of substitute goods or services; loss of use, data, or
-profits; or business interruption) however caused and on any theory of
-liability, whether in contract, strict liability, or tort (including
-negligence or otherwise) arising in any way out of the use of this
-software, even if advised of the possibility of such damage.
-
-=cut
diff --git a/build/github_upload.rb b/build/github_upload.rb
deleted file mode 100644
index ad5df46..0000000
--- a/build/github_upload.rb
+++ /dev/null
@@ -1,211 +0,0 @@
-# require
-require 'rubygems'
-
-#### INLINE: fixed version of https://github.com/github/upload ####
-
-require 'tempfile'
-require 'nokogiri'
-require 'httpclient'
-require 'stringio'
-require 'json'
-require 'faster_xml_simple'
-
-module Net
-  module GitHub
-    class Upload
-      VERSION = '0.0.5'
-      def initialize params=nil
-        @login = params[:login]
-        @token = params[:token]
-
-        if @login.empty? or @token.empty?
-          raise "login or token is empty"
-        end
-      end
-
-      def upload info
-        unless info[:repos]
-          raise "required repository name"
-        end
-        info[:repos] = @login + '/' + info[:repos] unless info[:repos].include? '/'
-
-        if info[:file]
-          file = info[:file]
-          unless File.exist?(file) && File.readable?(file)
-            raise "file does not exsits or readable"
-          end
-          info[:name] ||= File.basename(file)
-        end
-        unless  info[:file] || info[:data]
-          raise "required file or data parameter to upload"
-        end
-
-        unless info[:name]
-          raise "required name parameter for filename with data parameter"
-        end
-
-        if info[:replace]
-          list_files(info[:repos]).each { |obj|
-            next unless obj[:name] == info[:name]
-            delete info[:repos], obj[:id]
-          }
-        elsif list_files(info[:repos]).any?{|obj| obj[:name] == info[:name]}
-          raise "file '#{info[:name]}' is already uploaded. please try different name"
-        end
-
-        info[:content_type] ||= 'application/octet-stream'
-        stat = HTTPClient.post("https://github.com/#{info[:repos]}/downloads", {
-          "file_size"    => info[:file] ? File.stat(info[:file]).size : info[:data].size,
-          "content_type" => info[:content_type],
-          "file_name"    => info[:name],
-          "description"  => info[:description] || '',
-          "login"        => @login,
-          "token"        => @token
-        })
-
-        unless stat.code == 200
-          raise "Failed to post file info"
-        end
-
-        upload_info = JSON.parse(stat.content)
-        if info[:file]
-          f = File.open(info[:file], 'rb')
-        else
-          f = Tempfile.open('net-github-upload')
-          f << info[:data]
-          f.flush
-        end
-        stat = HTTPClient.post("http://github.s3.amazonaws.com/", [
-          ['Filename', info[:name]],
-          ['policy', upload_info['policy']],
-          ['success_action_status', 201],
-          ['key', upload_info['path']],
-          ['AWSAccessKeyId', upload_info['accesskeyid']],
-          ['Content-Type', upload_info['content_type'] || 'application/octet-stream'],
-          ['signature', upload_info['signature']],
-          ['acl', upload_info['acl']],
-          ['file', f]
-        ])
-        f.close
-
-        if stat.code == 201
-          return FasterXmlSimple.xml_in(stat.content)['PostResponse']['Location']
-        else
-          raise 'Failed to upload' + extract_error_message(stat)
-        end
-      end
-
-      def replace info
-         upload info.merge( :replace => true )
-      end
-
-      def delete_all repos
-        unless repos
-          raise "required repository name"
-        end
-        repos = @login + '/' + repos unless repos.include? '/'
-        list_files(repos).each { |obj|
-          delete repos, obj[:id]
-        }
-      end
-
-      private
-
-      def extract_error_message(stat)
-        # @see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/ErrorResponses.html
-        error = FasterXmlSimple.xml_in(stat.content)['Error']
-        " due to #{error['Code']} (#{error['Message']})"
-      rescue
-        ''
-      end
-
-      def delete repos, id
-        HTTPClient.post("https://github.com/#{repos}/downloads/#{id.gsub( "download_", '')}", {
-          "_method"      => "delete",
-          "login"        => @login,
-          "token"        => @token
-        })
-      end
-
-      def list_files repos
-        raise "required repository name" unless repos
-        res = HTTPClient.get_content("https://github.com/#{repos}/downloads", {
-          "login" => @login,
-          "token" => @token
-        })
-        Nokogiri::HTML(res).xpath('id("manual_downloads")/li').map do |fileinfo|
-          obj = {
-            :description => fileinfo.at_xpath('descendant::h4').text,
-            :date        => fileinfo.at_xpath('descendant::p/time').attribute('title').text,
-            :size        => fileinfo.at_xpath('descendant::p/strong').text,
-            :id          => /\d+$/.match(fileinfo.at_xpath('a').attribute('href').text)[0]
-          }
-          anchor = fileinfo.at_xpath('descendant::h4/a')
-          obj[:link] = anchor.attribute('href').text
-          obj[:name] = anchor.text
-          obj
-        end
-      end
-    end
-  end
-end
-
-#### END INLINE ####
-
-# setup
-login = `git config github.user`.chomp  # your login for github
-token = `git config github.token`.chomp # your token for github
-repos = 'KentBeck/junit'               # your repos name (like 'taberareloo')
-gh = Net::GitHub::Upload.new(
-  :login => login,
-  :token => token
-)
-
-version = ARGV[0]
-
-def upload(gh, version, repos, filename, description)
-  gh.upload(:repos => repos, 
-            :file => "junit#{version}/#{filename}", 
-            :description => description)
-end
-
-upload(gh, version, repos, "junit-#{version}-src.jar", 'Source jar')
-upload(gh, version, repos, "junit-#{version}.jar", 'Basic jar')
-upload(gh, version, repos, "junit-dep-#{version}.jar", 'Jar without hamcrest')
-upload(gh, version, repos, "junit#{version}.zip", 'Source zip')
-
-# # file upload
-# direct_link = gh.upload(
-#   :repos => repos,
-#   :file  => 'test/test',
-#   :description => "test file"
-# )
-# # direct link is link to Amazon S3.
-# # Because GitHub refrection for file changing is async,
-# # if you get changed file synchronously, you use this "direct_link"
-# 
-# # data upload
-# # you can define content_type => Amazon S3 Content-Type
-# time = Time.now.to_i
-# direct_link = gh.upload(
-#   :repos => repos,
-#   :data  => 'test',
-#   :name  => "test_#{time}.txt",
-#   :content_type => 'text/plain',
-#   :description => "test file2"
-# )
-# 
-# # replace file or data
-# # thx id:rngtng !
-# direct_link = gh.replace(
-#   :repos => repos,
-#   :file  => 'test/test',
-#   :description => "test file"
-# )
-# direct_link = gh.replace(
-#   :repos => repos,
-#   :data  => 'test',
-#   :name  => "test_#{time}.txt",
-#   :content_type => 'text/plain',
-#   :description => "test file2"
-# )
diff --git a/build/lib/ant-contrib-1.0b3.jar b/build/lib/ant-contrib-1.0b3.jar
deleted file mode 100644
index 0625376..0000000
--- a/build/lib/ant-contrib-1.0b3.jar
+++ /dev/null
Binary files differ
diff --git a/build/lib/commons-net-1.4.1.jar b/build/lib/commons-net-1.4.1.jar
deleted file mode 100644
index 9666a92..0000000
--- a/build/lib/commons-net-1.4.1.jar
+++ /dev/null
Binary files differ
diff --git a/build/lib/jakarta-oro-2.0.8.jar b/build/lib/jakarta-oro-2.0.8.jar
deleted file mode 100644
index 23488d2..0000000
--- a/build/lib/jakarta-oro-2.0.8.jar
+++ /dev/null
Binary files differ
diff --git a/build/lib/maven-ant-tasks-2.1.1.jar b/build/lib/maven-ant-tasks-2.1.1.jar
deleted file mode 100644
index 7810a54..0000000
--- a/build/lib/maven-ant-tasks-2.1.1.jar
+++ /dev/null
Binary files differ
diff --git a/build/maven/junit-dep-pom-template.xml b/build/maven/junit-dep-pom-template.xml
deleted file mode 100644
index e3c64d6..0000000
--- a/build/maven/junit-dep-pom-template.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<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/maven-v4_0_0.xsd ">
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>junit</groupId>
-    <artifactId>junit-dep</artifactId>
-    <packaging>pom</packaging>
-    <version>@version@</version>
-    <distributionManagement>
-        <relocation>
-            <artifactId>junit</artifactId>
-            <version>@version@</version>
-            <message>The artifact junit:junit does not contain Hamcrest anymore but declares a dependency to Hamcrest. Thus, junit:junit-dep has become obsolete.</message>
-        </relocation>
-    </distributionManagement>
-    <name>JUnit</name>
-    <url>http://junit.org</url>
-    <description>
-        JUnit is a regression testing framework written by Erich Gamma and Kent Beck.
-        It is used by the developer who implements unit tests in Java.
-    </description>
-    <organization>
-        <name>JUnit</name>
-        <url>http://www.junit.org</url>
-    </organization>
-    <mailingLists>
-        <mailingList>
-            <name>JUnit Mailing List</name>
-            <post>junit@yahoogroups.com</post>
-            <archive>
-                http://tech.groups.yahoo.com/group/junit/
-            </archive>
-        </mailingList>
-    </mailingLists>
-    <licenses>
-        <license>
-            <name>Common Public License Version 1.0</name>
-            <url>http://www.opensource.org/licenses/cpl1.0.txt</url>
-        </license>
-    </licenses>
-    <scm>
-        <connection>scm:git:git://github.com/KentBeck/junit.git</connection>
-        <developerConnection>scm:git:git@github.com:KentBeck/junit.git</developerConnection>
-        <url>http://github.com/KentBeck/junit/tree/master</url>
-    </scm>
-    <developers>
-      <developer>
-        <id>dsaff</id>
-        <name>David Saff</name>
-        <email>david@saff.net</email>
-      </developer>
-    </developers>
-</project>
\ No newline at end of file
diff --git a/build/maven/junit-pom-template.xml b/build/maven/junit-pom-template.xml
deleted file mode 100644
index 2a853f5..0000000
--- a/build/maven/junit-pom-template.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<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/maven-v4_0_0.xsd ">
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>junit</groupId>
-    <artifactId>junit</artifactId>
-    <version>@version@</version>
-    <name>JUnit</name>
-    <url>http://junit.org</url>
-    <description>
-        JUnit is a regression testing framework written by Erich Gamma and Kent Beck.
-        It is used by the developer who implements unit tests in Java.
-    </description>
-    <organization>
-        <name>JUnit</name>
-        <url>http://www.junit.org</url>
-    </organization>
-    <mailingLists>
-        <mailingList>
-            <name>JUnit Mailing List</name>
-            <post>junit@yahoogroups.com</post>
-            <archive>
-                http://tech.groups.yahoo.com/group/junit/
-            </archive>
-        </mailingList>
-    </mailingLists>
-    <licenses>
-        <license>
-            <name>Common Public License Version 1.0</name>
-            <url>http://www.opensource.org/licenses/cpl1.0.txt</url>
-        </license>
-    </licenses>
-    <scm>
-        <connection>scm:git:git://github.com/KentBeck/junit.git</connection>
-        <developerConnection>scm:git:git@github.com:KentBeck/junit.git</developerConnection>
-        <url>http://github.com/KentBeck/junit/tree/master</url>
-    </scm>
-    <developers>
-      <developer>
-        <id>dsaff</id>
-        <name>David Saff</name>
-        <email>david@saff.net</email>
-      </developer>
-    </developers>
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <configuration>
-                    <encoding>ISO-8859-1</encoding>
-                    <source>${jdk.version}</source>
-                    <target>${jdk.version}</target>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-    <dependencies>
-        <dependency>
-          <groupId>org.hamcrest</groupId>
-          <artifactId>hamcrest-core</artifactId>
-          <version>1.3</version>
-          <scope>compile</scope>
-        </dependency>
-    </dependencies>
-    <properties>
-         <jdk.version>1.5</jdk.version>
-    </properties>
-</project>
\ No newline at end of file
diff --git a/build/maven/post_maven_tests.sh b/build/maven/post_maven_tests.sh
deleted file mode 100755
index c7510f5..0000000
--- a/build/maven/post_maven_tests.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-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
\ No newline at end of file
diff --git a/build/maven/sample_project_template/pom.xml b/build/maven/sample_project_template/pom.xml
deleted file mode 100644
index 8fa02a6..0000000
--- a/build/maven/sample_project_template/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<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.3</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>
diff --git a/build/maven/sample_project_template/src/test/java/JunitDependencyTest.java b/build/maven/sample_project_template/src/test/java/JunitDependencyTest.java
deleted file mode 100644
index f6db3f5..0000000
--- a/build/maven/sample_project_template/src/test/java/JunitDependencyTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-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());
-	}
-}
diff --git a/build/profile_junit.sh b/build/profile_junit.sh
deleted file mode 100644
index daf9abf..0000000
--- a/build/profile_junit.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-java -classpath ../bin:../lib/hamcrest-core-1.3.jar -agentlib:hprof=cpu=samples,depth=18 org.junit.runner.JUnitCore org.junit.tests.AllTests
-cat java.hprof.txt
\ No newline at end of file
diff --git a/build/release b/build/release
deleted file mode 100755
index 53bdf75..0000000
--- a/build/release
+++ /dev/null
@@ -1,389 +0,0 @@
-#!/usr/bin/perl
-
-eval 'exec /usr/bin/perl  -S $0 ${1+"$@"}'
-    if 0; # not running under some shell
-use strict;
-use warnings;
-
-# $Id: release,v 1.1 2007/09/04 17:59:38 dsaff Exp $
-
-=head1 NAME
-
-release - upload files to the CPAN and SourceForge.net
-
-=head1 SYNOPSIS
-
-	release [ LOCAL_FILE [ REMOTE_FILE ] ]
-	
-	# try a dry run without uploading anything
-	release -t
-	
-	# print a help message
-	release -h
-	
-	# print debugging information
-	release -d 
-
-=head1 DESCRIPTION
-
-This is the prototype program for using Module::Release. You should
-modify it to fit your needs.
-
-This program automates Perl module releases.  It makes the
-distribution, tests it, checks that source control is up to date, tags
-source control, uploads it to the PAUSE anonymous FTP directory and to
-the incoming directory for SourceForge.net, claims it on PAUSE for
-your CPAN account, and releases it on SourceForge.net.
-
-By default this script assumes that you use CVS, but recognizes SVN
-and switches when appropriate.
-
-=head2 Process
-
-The release script checks many things before it actually releases the
-file.  Some of these are annoying, but they are also the last line of
-defense against releasing bad distributions.
-
-=over 4
-
-=item Read the configuration data
-
-Look in the current working directory for C<.releaserc>.  See the
-Configuration section.  If release cannot find the configuration file,
-it dies.
-
-=item Test and make the distribution
-
-Run make realclean, perl Makefile.PL, make test, make dist, make
-disttest.  If testing fails, release dies.  make dist provides the
-name of the distribution if LOCAL_FILE is not provided on the command
-line.
-
-=item Check that source control is up-to-date
-
-If there are modified files, added files, or extra files so that
-source control complains, fail.
-
-=item Upload to PAUSE and SourceForge.net
-
-Simply drop the distribution in the incoming/ directory of these
-servers.
-
-=item Claim the file on PAUSE
-
-Connect to the PAUSE web thingy and claim the uploaded file for your
-CPAN account.
-
-=item Tag the repository
-
-Use the version number (in the distribution name) to tag the
-repository.  You should be able to checkout the code from any release.
-
-=item Release to SourceForge.net
-
-The release name is the distribution name without the .tar.gz. The
-file name is the distribution name.  SourceForge.net divides things
-into projects (with project IDs) and packages within the project (with
-package IDs).  Specify these in the configuration file.
-
-=back
-
-=head2 Configuration
-
-The release script uses a configuration file in the current working
-directory.  The file name is F<.releaserc>.  Although most of the
-information is the same for all of your projects, the C<sf_package_id>
-is probably different.  You can get the C<sf_package_id> from the data
-in the Quick Release Form.
-
-release's own F<.releaserc> looks like this:
-
-    sf_user comdog
-    sf_group_id 36221
-    sf_package_id 56559
-    cpan_user BDFOY
-
-=over 4
-
-=item cpan_user
-
-=item sf_user
-
-If C<cpan_user> or C<sf_user> is set to C<< <none> >>, the program will
-skip releasing for that system.  You must release for at least one system.
-
-=item sf_group_id
-
-=item sf_package_id
-
-=item sf_processor_id
-
-=item sf_type_id
-
-=item sf_release_match
-
-=item sf_release_replace
-
-To find C<sf_package_id> and C<sf_group_id>, go to the Add/Edit
-Release page for your project.  The link for "[Add Release]" might
-look something like this (this is the link for the F<release> package
-itself):
-
-    https://sourceforge.net/project/admin/newrelease.php?package_id=56559&group_id=36221
-
-so C<sf_package_id> is 56559 and C<sf_group_id> is 36221.
-
-C<sf_processor_id> and C<sf_type_id> are optional, and default to "Any"
-and "Source .gz".  See the HTML in a file release form on SourceForge.net
-for other options.
-
-C<sf_release_match> and C<sf_release_replace> are for defining the release
-name, if you don't like the default.  For example, the default would
-set the name for this program to something like "release-0.10".
-But if you want the name to be only the version number, set
-C<sf_release_match=^.+-([\d.]+)$> and C<sf_release_replace=$1>.
-
-=item passive_ftp
-
-Set C<passive_ftp> to "y" or "yes" for passive FTP transfers.  Usually
-this is to get around a firewall issue.
-
-=item release_subclass
-
-Specify the name of a subclass to use instead of Module::Release.  The
-subclass can override any of the Module::Release methods.  This makes
-it possible to maintain your own local releasing procedures.  For
-instance, one such subclass might look like this:
-
-  package Module::Release::KWILLIAMS;
-  use base qw(Module::Release);
-  
-  sub make_cvs_tag {
-    my $self = shift;
-    (my $version) = $self->{remote} =~ / - (\d[\w.]*) \.tar \.gz $/x;
-    $version =~ s/[^a-z0-9_]/_/gi;
-    return "release-$version";
-  }
-  1;
-
-To use this subclass, you'd put it in your C<@INC> somewhere, then set
-C<release_subclass> to C<Module::Release::KWILLIAMS>.
-
-=back
-
-=head2 Environment
-
-=over 4
-
-=item * CPAN_PASS
-
-=item * SF_PASS
-
-release reads the C<CPAN_PASS> and C<SF_PASS> environment variables to
-set the passwords for PAUSE and SourceForge.net, respectively.  Of course,
-you don't need to set the password for a system you're not uploading to.
-
-=item * RELEASE_DEBUG
-
-The C<RELEASE_DEBUG> environment variable sets the debugging value,
-which is 0 by default.  Set C<RELEASE_DEBUG> to a true value to get
-debugging output.
-
-=item * PERL
-
-The C<PERL> environment variable sets the path to perl for use in the
-make; otherwise, the perl used to run release will be used.
-
-=back
-
-=head1 TO DO
-
-=over 4
-
-=item * check make disttest (to catch MANIFEST errors) -- needs error catching and reporting
-
-=back
-
-=head1 SOURCE AVAILABILITY
-
-This source is part of a SourceForge.net project which always has the
-latest sources in CVS, as well as all of the previous releases.
-
-        http://sourceforge.net/projects/brian-d-foy/
-
-If, for some reason, I disappear from the world, one of the other
-members of the project can shepherd this software appropriately.
-
-=head1 AUTHOR
-
-brian d foy, C<< <bdfoy@cpan.org> >>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2002-2007, brian d foy, All rights reserved.
-
-You may use this software under the same terms as Perl itself.
-
-=head1 CREDITS
-
-Ken Williams turned the original release(1) script into a module.
-
-Andy Lester contributed to the module and script. 
-
-=cut
-
-use Getopt::Std;
-use Module::Release;
-
-my $class = "Module::Release";
-
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-my %opts;
-getopts('hdt', \%opts) or $opts{h} = 1;
-
-if( $opts{h} ) 
-	{
-	print <<"USE";
-
-Use: release -hdt [ LOCAL_FILE [ REMOTE_FILE ] ]
-
-Will upload current release LOCAL_FILE, naming it REMOTE_FILE.  Will
-get LOCAL_FILE and REMOTE_FILE automatically (using same name for
-both) if not supplied.
-
-	-h   This help 
-	-d   Print extra debugging information 
-	-t   Just make and test distribution, don't tag/upload
-
-The program works in the current directory, and looks for a .releaserc
-or releaserc file and the environment for its preferences.  See
-`perldoc $0`, for more information.
-
-USE
-
-	exit;
-	}
-
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-if( -d '.svn' )
-	{
-	$class = "Module::Release::Subversion";
-	
-	print STDERR "I see an .svn directory, so I'm loading $class"
-		if $opts{d};
-		
-	eval "use Module::Release::Subversion";
-	die "Could not load $class: $@\n" if $@;
-	}
-
-my( $script_version ) = 
-	sprintf "%1.%02d", q$Revision: 1.1 $ =~ m/ (\d+) /xg;
-
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-my %params;
-$params{local}  = shift @ARGV if @ARGV;
-
-if( @ARGV ) 
-	{
-    $params{remote} = shift @ARGV;
-	} 
-elsif( $params{local} ) 
-	{
-    $params{remote} = $params{local};
-	}
-
-$params{debug} = 1 if $opts{d};
-
-my $release = $class->new( %params );
-
-print STDERR "release $script_version, using $class " .  $class->VERSION . "\n" 
-	if $release->debug;
-
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-$release->clean;
-$release->build_makefile;
-$release->test;
-$release->dist;
-$release->check_kwalitee;
-$release->dist_test;
-# $release->check_cvs;
-
-my $Version = $release->dist_version;
-
-print STDERR "dist version is  $Version\n" if $release->debug;
-
-exit if $opts{t};
-
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-my $Changes = do {
-	my $changes = "Changes";
-	my $bak     = $changes . ".bak";
-	
-	die "Changes file does not exist!\n" unless -e $changes;
-	
-	print "\n", "-" x 73, "\n", "Enter Changes section\n\n> ";
-	
-	my $str = $Version . " - " . localtime() . "\n";
-	
-	while( <STDIN> )
-		{
-		$_ =~ s/^(\S)/\t$1/; # always indent
-		
-		$str .= $_;
-		print "> ";
-		}
-		
-	$str .= "\n";
-	
-	rename $changes, $bak or die "Could not backup $changes. $!\n";
-	open my $in, $bak or die "Could not read old $changes file! $!\n";
-	open my $out, ">", $changes;
-	
-	while( <$in> )
-		{
-		print $out $_;
-		last unless m/\S/;
-		}
-		
-	print $out $str;
-	
-	print $out $_ while( <$in> );
-	
-	close $in;
-	close $out;
-
-	my $command = do {
-		if(    -d 'CVS' )  { 'cvs' }
-		elsif( -d '.svn' ) { 'svn' }
-		};
-		
-	my $cvs_commit = `$command commit -m "* for version $Version" 2>&1`;
-	
-	print $cvs_commit;
-	
-	$str;
-	};
-
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-$release->clean;
-$release->build_makefile;
-$release->dist;
-
-$release->check_for_passwords;
-$release->ftp_upload;
-$release->pause_claim;
-$release->cvs_tag;
-
-$release->sf_login;
-$release->sf_qrs;
-$release->sf_release;
-
-print "Done.\n";
-
-__END__
diff --git a/build/run_tests.sh b/build/run_tests.sh
deleted file mode 100644
index 79b96fd..0000000
--- a/build/run_tests.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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
diff --git a/build/upload_docs.sh b/build/upload_docs.sh
deleted file mode 100644
index b9f402b..0000000
--- a/build/upload_docs.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-scp -r ../doc/* dsaff@web.sourceforge.net:/home/groups/j/ju/junit/htdocs/doc
-scp ../doc/homepage.html dsaff@web.sourceforge.net:/home/groups/j/ju/junit/htdocs/index.html
\ No newline at end of file
diff --git a/build_tests.sh b/build_tests.sh
deleted file mode 100755
index d6485e5..0000000
--- a/build_tests.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-set -e
-set -o pipefail
-
-function TEST_BUILDING_in_zip {
-  version=$(get_junit_version)
-  ant zip
-  unzip -l junit${version}/junit${version}.zip | grep BUILDING >/dev/null
-}
-
-function TEST_get_junit_version {
-  version=$(get_junit_version)
-  if [[ ! ($version == 4.*) ]]; then
-    echo "Bad version: $version"
-    return 1
-  fi
-}
-
-function TEST_ant_dist {
-  version=$(get_junit_version)
-  ant dist
-  ls junit${version}/junit-${version}.jar
-}
-
-function TEST_ant_profile {
-  rm -rf java.hprof.txt
-  ant profile
-  ls java.hprof.txt
-}
-
-function TEST_jars {
-  version=$(get_junit_version)
-  binjar=junit${version}/junit-${version}.jar
-  srcjar=junit${version}/junit-${version}-src.jar
-  depjar=junit${version}/junit-dep-${version}.jar
-
-  ant clean
-  ant jars
-
-  jar tf $binjar | grep -q class \
-    && jar tf $srcjar | grep -q java \
-    && jar tf $depjar | grep -q class \
-    && jar tf $depjar | not grep hamcrest
-}
-
-function TEST_all_maven_jars {
-  version=$(get_junit_version)
-  binjar=junit${version}/junit-${version}.jar
-  srcjar=junit${version}/junit-${version}-src.jar
-  docjar=junit${version}/junit-${version}-javadoc.jar
-  depbin=junit${version}/junit-dep-${version}.jar
-  depsrc=junit${version}/junit-dep-${version}-src.jar
-  depdoc=junit${version}/junit-dep-${version}-javadoc.jar
-
-  ant clean
-  ant all.maven.jars
-
-  jar tf $binjar | grep -q class \
-    && jar tf $srcjar | grep -q java \
-    && jar tf $docjar | grep -q html \
-    && jar tf $depbin | grep -q class \
-    && jar tf $depsrc | grep -q java \
-    && jar tf $depdoc | grep -q html \
-    && jar tf $depbin | not grep hamcrest \
-    && jar tf $depsrc | not grep hamcrest \
-    && jar tf $depdoc | not grep hamcrest
-}
-
-function not {
-  ! "$@"
-}
-
-function get_junit_version {
-  ant print.version | grep echo | sed 's/.*echo..\([1-9].*\)/\1/'
-}
-
-source build/run_tests.sh
\ No newline at end of file
diff --git a/cpl-v10.html b/cpl-v10.html
deleted file mode 100644
index 36aa208..0000000
--- a/cpl-v10.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
-<HTML>
-<HEAD>
-<TITLE>Common Public License - v 1.0</TITLE>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-</HEAD>
-
-<BODY BGCOLOR="#FFFFFF" VLINK="#800000">
-
-
-<P ALIGN="CENTER"><B>Common Public License - v 1.0</B>
-<P><B></B><FONT SIZE="3"></FONT>
-<P><FONT SIZE="3"></FONT><FONT SIZE="2">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT").  ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"><B>1.  DEFINITIONS</B></FONT>
-<P><FONT SIZE="2">"Contribution" means:</FONT>
-
-<UL><FONT SIZE="2">a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and<BR CLEAR="LEFT">
-b) in the case of each subsequent Contributor:</FONT></UL>
-
-
-<UL><FONT SIZE="2">i)	 	changes to the Program, and</FONT></UL>
-
-
-<UL><FONT SIZE="2">ii)		additions to the Program;</FONT></UL>
-
-
-<UL><FONT SIZE="2">where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.  </FONT><FONT SIZE="2">A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf.  </FONT><FONT SIZE="2">Contributions do not include additions to the Program which:  (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.  </FONT></UL>
-
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">"Contributor" means any person or entity that distributes the Program.</FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.  </FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2">"Program" means the Contributions distributed in accordance with this Agreement.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.</FONT>
-<P><FONT SIZE="2"><B></B></FONT>
-<P><FONT SIZE="2"><B>2.  GRANT OF RIGHTS</B></FONT>
-
-<UL><FONT SIZE="2"></FONT><FONT SIZE="2">a)	</FONT><FONT SIZE="2">Subject to the terms of this Agreement, each Contributor hereby grants</FONT><FONT SIZE="2"> Recipient a non-exclusive, worldwide, royalty-free copyright license to</FONT><FONT SIZE="2" COLOR="#FF0000"> </FONT><FONT SIZE="2">reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.</FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT><FONT SIZE="2">b) 	Subject to the terms of this Agreement, each Contributor hereby grants </FONT><FONT SIZE="2">Recipient a non-exclusive, worldwide,</FONT><FONT SIZE="2" COLOR="#008000"> </FONT><FONT SIZE="2">royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form.  This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents.  The patent license shall not apply to any other combinations which include the Contribution.  No hardware per se is licensed hereunder.   </FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT></UL>
-
-
-<UL><FONT SIZE="2">c)	Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity.  Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise.  As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any.  For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.</FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT></UL>
-
-
-<UL><FONT SIZE="2">d)	Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. </FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT></UL>
-
-<P><FONT SIZE="2"><B>3.  REQUIREMENTS</B></FONT>
-<P><FONT SIZE="2"><B></B>A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:</FONT>
-
-<UL><FONT SIZE="2">a)	it complies with the terms and conditions of this Agreement; and</FONT></UL>
-
-
-<UL><FONT SIZE="2">b)	its license agreement:</FONT></UL>
-
-
-<UL><FONT SIZE="2">i)	effectively disclaims</FONT><FONT SIZE="2"> on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; </FONT></UL>
-
-
-<UL><FONT SIZE="2">ii) 	effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; </FONT></UL>
-
-
-<UL><FONT SIZE="2">iii)</FONT><FONT SIZE="2">	states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and</FONT></UL>
-
-
-<UL><FONT SIZE="2">iv)	states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.</FONT><FONT SIZE="2" COLOR="#0000FF"> </FONT><FONT SIZE="2" COLOR="#FF0000"></FONT></UL>
-
-
-<UL><FONT SIZE="2" COLOR="#FF0000"></FONT><FONT SIZE="2"></FONT></UL>
-
-<P><FONT SIZE="2">When the Program is made available in source code form:</FONT>
-
-<UL><FONT SIZE="2">a)	it must be made available under this Agreement; and </FONT></UL>
-
-
-<UL><FONT SIZE="2">b)	a copy of this Agreement must be included with each copy of the Program.  </FONT></UL>
-
-<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT>
-<P><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT><FONT SIZE="2">Contributors may not remove or alter any copyright notices contained within the Program.  </FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.  </FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"><B>4.  COMMERCIAL DISTRIBUTION</B></FONT>
-<P><FONT SIZE="2">Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like.  While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors.   Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering.  The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement.  In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations.  The Indemnified Contributor may participate in any such claim at its own expense.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">For example, a Contributor might include the Program in a commercial product offering, Product X.  That Contributor is then a Commercial Contributor.  If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.  Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.</FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"></FONT>
-<P><FONT SIZE="2" COLOR="#0000FF"></FONT><FONT SIZE="2"><B>5.  NO WARRANTY</B></FONT>
-<P><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is</FONT><FONT SIZE="2"> solely responsible for determining the appropriateness of using and distributing </FONT><FONT SIZE="2">the Program</FONT><FONT SIZE="2"> and assumes all risks associated with its exercise of rights under this Agreement</FONT><FONT SIZE="2">, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, </FONT><FONT SIZE="2">programs or equipment, and unavailability or interruption of operations</FONT><FONT SIZE="2">.  </FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"><B>6.  DISCLAIMER OF LIABILITY</B></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES </FONT><FONT SIZE="2">(INCLUDING WITHOUT LIMITATION LOST PROFITS),</FONT><FONT SIZE="2"> HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"><B>7.  GENERAL</B></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2">If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed.  In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. </FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance.  If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable.  However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.  </FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2">Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted  and may only be modified in the following manner. The Agreement Steward reserves the right to </FONT><FONT SIZE="2">publish new versions (including revisions) of this Agreement from time to </FONT><FONT SIZE="2">time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward.   IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity.  </FONT><FONT SIZE="2">Each new version of the Agreement will be given a distinguishing version number.  The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new </FONT><FONT SIZE="2">version.  </FONT><FONT SIZE="2">Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, </FONT><FONT SIZE="2">by implication, estoppel or otherwise</FONT><FONT SIZE="2">.</FONT><FONT SIZE="2">  All rights in the Program not expressly granted under this Agreement are reserved.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose.  Each party waives its rights to a jury trial in any resulting litigation.</FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT>
-
-</BODY>
-
-</HTML>
\ No newline at end of file
diff --git a/doc/ReleaseNotes4.10.html b/doc/ReleaseNotes4.10.html
index ebf4174..84bc3d4 100644
--- a/doc/ReleaseNotes4.10.html
+++ b/doc/ReleaseNotes4.10.html
@@ -1,6 +1,6 @@
 <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>
+<p>A full summary of commits between 4.9 and 4.10 is on <a href="https://github.com/junit-team/junit/compare/r4.9...4.10">github</a></p>
 
 <h3>junit-dep has correct contents</h3>
 
diff --git a/doc/ReleaseNotes4.10.md b/doc/ReleaseNotes4.10.md
index ccf8625..0b0a9d3 100644
--- a/doc/ReleaseNotes4.10.md
+++ b/doc/ReleaseNotes4.10.md
@@ -2,7 +2,7 @@
 
 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)
+A full summary of commits between 4.9 and 4.10 is on [github](https://github.com/junit-team/junit/compare/r4.9...4.10)
 
 ### junit-dep has correct contents ###
 
@@ -12,18 +12,20 @@
 
 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);
-    	}
-    }
+```java
+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
 
diff --git a/doc/ReleaseNotes4.11.md b/doc/ReleaseNotes4.11.md
index 8d65a06..740c64a 100644
--- a/doc/ReleaseNotes4.11.md
+++ b/doc/ReleaseNotes4.11.md
@@ -6,7 +6,9 @@
 
 #### Example
 
-    assertThat(Long.valueOf(1), instanceOf(Integer.class));
+```java
+assertThat(Long.valueOf(1), instanceOf(Integer.class));
+```
 
 Old error message:
 
@@ -20,19 +22,21 @@
 
 Hamcrest's new `FeatureMatcher` makes writing custom matchers that make use of custom mismatch descriptions quite easy:
 
-	@Test
-	public void featureMatcher() throws Exception {
-		assertThat("Hello World!", length(is(0)));
-	}
+```java
+@Test
+public void featureMatcher() throws Exception {
+    assertThat("Hello World!", length(is(0)));
+}
 
-	private Matcher<String> length(Matcher<? super Integer> matcher) {
-		return new FeatureMatcher<String, Integer>(matcher, "a String of length that", "length") {
-			@Override
-			protected Integer featureValueOf(String actual) {
-				return actual.length();
-			}
-		};
-	}
+private Matcher<String> length(Matcher<? super Integer> matcher) {
+    return new FeatureMatcher<String, Integer>(matcher, "a String of length that", "length") {
+        @Override
+        protected Integer featureValueOf(String actual) {
+            return actual.length();
+        }
+    };
+}
+```
 
 Running this test will return the following failure message:
 
@@ -51,28 +55,30 @@
 
 #### Example
 
-    @RunWith(Parameterized.class)
-    public class FibonacciTest {
+```java
+@RunWith(Parameterized.class)
+public class FibonacciTest {
     
-    	@Parameters(name = "{index}: fib({0})={1}")
-    	public static Iterable<Object[]> data() {
-    		return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
-    				{ 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
-    	}
-    
-    	private int input;
-    	private int expected;
-    
-    	public FibonacciTest(int input, int expected) {
-    		this.input = input;
-    		this.expected = expected;
-    	}
-    
-    	@Test
-    	public void test() {
-    		assertEquals(expected, Fibonacci.compute(input));
-    	}
+    @Parameters(name = "{index}: fib({0})={1}")
+    public static Iterable<Object[]> data() {
+        return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
+    		{ 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
     }
+    
+    private int input;
+    private int expected;
+    
+    public FibonacciTest(int input, int expected) {
+        this.input = input;
+    	this.expected = expected;
+    }
+    
+    @Test
+    public void test() {
+        assertEquals(expected, Fibonacci.compute(input));
+    }
+}
+```
 
 In the example given above, the `Parameterized` runner creates names like `[1: fib(3)=2]`. If you don't specify a name, the current parameter index will be used by default.
 
diff --git a/doc/ReleaseNotes4.12.md b/doc/ReleaseNotes4.12.md
index 1a226fc..c165103 100644
--- a/doc/ReleaseNotes4.12.md
+++ b/doc/ReleaseNotes4.12.md
@@ -1,6 +1,732 @@
-## Summary of changes in version 4.12 [unreleased!]
+## Summary of changes in version 4.12
 
-We collect release notes in the wiki:
-https://github.com/KentBeck/junit/wiki/4.12-release-notes
+# Assertions
 
-This file will be updated right before release.
+### [Pull request #611:](https://github.com/junit-team/junit/pull/611) Assert.assertNotEquals() for `float` parameters
+
+Version 4.11 added `Assert.assertEquals()` for `float` parameters with a delta, and `Assert.assertNotEquals()`. This is the combination of those two features.
+
+
+### [Pull request #632:](https://github.com/junit-team/junit/pull/632) Assert.assertArrayEquals() for `boolean[]` parameters.
+
+`Assert.assertArrayEquals()` previously existed for all primitive array types, except `boolean[]`. This has now been added for `boolean[]`.
+
+
+### [Pull request #918:](https://github.com/junit-team/junit/pull/918) Avoid potentially expensive reflection-based loop in Assert.assertArrayEquals()
+
+In the usual case, where the array elements are in fact exactly equal, the potentially expensive reflection-based loop to compare them is avoided by using `Arrays.deepEquals()` first. The exact comparison is only executed when `deepEquals()` returns `false`.
+
+
+# Command-line options
+### [Pull request #647:](https://github.com/junit-team/junit/pull/647) Support command-line `--filter` param.
+
+When running JUnit from the command line, a command-line parameter can be supplied using `--filter`, which supplies a filter that will restrict which tests and subtests from the rest of the command will be run.  For example, this will run only the tests in ExampleTestSuite that are in categories Cat1 or Cat2:
+
+```
+java org.junit.runner.JUnitCore \
+  --filter=org.junit.experimental.categories.IncludeCategories=pkg.of.Cat1,pkg.of.Cat2 \
+  com.example.ExampleTestSuite
+```
+
+In general, the argument to `--filter` should be `ClassName=param`, where `ClassName` names an implementation of `FilterFactory`, whose `createFilter` method will be called with an instance of `FilterFactoryParams` that contains `"param"`, in order to return the filter to be applied.
+
+# Test Runners
+
+
+### [Pull request #763:](https://github.com/junit-team/junit/pull/763) Allow custom test runners to create their own TestClasses and customize the scanning of annotations.
+
+This introduces some extension points to `ParentRunner` to allow subclasses to control creation
+of the `TestClass` instance and to scan for annotations.
+
+### [Pull request #817:](https://github.com/junit-team/junit/pull/817) Support for context hierarchies
+
+The `AnnotatedBuilder` is a strategy for constructing runners for test classes that have been annotated with the `@RunWith` annotation. All tests within such a class will be executed using the runner that was specified within the annotation.
+
+Prior to JUnit 4.12, this covered only the tests within the annotated test class. With 4.12, the `AnnotationBuilder` will also support inner member classes. If a custom test runner supports inner member classes (which JUnit does not support out-of-the-box), the member classes will inherit the runner from the enclosing class, e.g.:
+
+```java
+@RunWith(MyRunner.class)
+public class MyTest {
+    // some tests might go here
+
+    public class MyMemberClass {
+        @Test
+        public void thisTestRunsWith_MyRunner() {
+            // some test logic
+        }
+
+        // some more tests might go here
+    }
+
+    @RunWith(AnotherRunner.class)
+    public class AnotherMemberClass {
+        // some tests might go here
+
+        public class DeepInnerClass {
+            @Test
+            public void thisTestRunsWith_AnotherRunner() {
+                // some test logic
+            }
+        }
+
+        public class DeepInheritedClass extends SuperTest {
+            @Test
+            public void thisTestRunsWith_SuperRunner() {
+                // some test logic
+            }
+        }
+    }
+}
+
+@RunWith(SuperRunner.class)
+public class SuperTest {
+    // some tests might go here
+}
+```
+
+The key points to note here are:
+
+* If there is no `@RunWith` annotation, no runner will be created.
+* The resolve step is inside-out, e.g. the closest `@RunWith` annotation wins.
+* `@RunWith` annotations are inherited and work as if the class was annotated itself.
+* The default JUnit runner does not support inner member classes, so this is only valid for custom runners that support inner member classes.
+* Custom runners with support for inner classes may or may not support `@RunWith` annotations for member classes. Please refer to the custom runner documentation.
+
+One example of a runner that makes use of this extension is the Hierarchical Context Runner (see https://github.com/bechte/junit-hierarchicalcontextrunner/wiki).
+
+
+### [Pull request #716:](https://github.com/junit-team/junit/pull/716) Fix annotation collection from superclasses of JUnit3 tests.
+
+Previously `Description.getAnnotations()` would always return an empty list for _test*_ methods derived from superclasses. 
+
+
+### [Pull request #625 (commit 72af03c49f):](https://github.com/junit-team/junit/commit/72af03c49fdad5f10e36c7eb4e7045feb971d253) Make `RunNotifier` code concurrent.
+
+When running tests from multiple threads, JUnit will now call `RunListener` methods from multiple threads if the listener class is annotated with `@RunListener.ThreadSafe`. In addition, the code in `RunNotifier` has been modified to not use locks.
+
+
+### [Pull request #684:](https://github.com/junit-team/junit/pull/684) Adding `AnnotationValidator` framework and validation checks for `@Category`.
+
+This allows for validation to be added to annotations. Validators should extend `AnnotationValidator` and be attached to annotations with the `@ValidateWith` annotation. `CategoryValidator` extends `AnnotationValidator` and ensures that incompatible annotations (`@BeforeClass`, `@AfterClass`, `@Before`, `@After`) are not used in conjunction with `@Category`.
+
+
+# Exception Testing
+
+
+### [Pull request #583:](https://github.com/junit-team/junit/pull/583) [Pull request #720:](https://github.com/junit-team/junit/pull/720) Fix handling of `AssertionError` and `AssumptionViolatedException` in `ExpectedException` rule.
+
+`ExpectedException` didn't handle `AssertionError`s and `AssumptionViolatedException` well. This has been fixed. The new documentation explains the usage of `ExpectedException` for testing these exceptions. The two methods `handleAssertionErrors()` and `handleAssumptionViolatedExceptions()` are not needed anymore. If you have used them, just remove it and read `ExpectedException`'s documentation.
+
+
+### [Pull request #818:](https://github.com/junit-team/junit/pull/818) [Pull request #993:](https://github.com/junit-team/junit/pull/993) External version of AssumptionViolatedException
+
+In JUnit 4.11 and earlier, if you wanted to write a custom runner that handled
+`AssumptionViolatedException` or you needed to create an instance of `AssumptionViolatedException`
+directly, you needed to import an internal class (`org.junit.internal.AssumptionViolatedException`).
+Now you can import `org.junit.AssumptionViolatedException` (which extends
+`org.junit.internal.AssumptionViolatedException`).
+
+The classes in `Assume` have been modified to throw `org.junit.AssumptionViolatedException`.
+
+The constructors in the external `AssumptionViolatedException` are also
+simpler than the ones in the internal version. That being said,
+it's recommended that you create `AssumptionViolatedException` via the methods in `Assume`.
+
+
+### [Pull request #985:](https://github.com/junit-team/junit/pull/985) Change AssumptionViolatedException to not set the cause to null; fixes issue #494
+
+Previously, the `AssumptionViolatedException` constructors would explicitly set the cause to `null`
+(unless you use a constructor where you provide a `Throwable`, in which case it would set that as
+the cause). This prevented code directly creating the exception from setting a cause.
+
+With this change, the cause is only set if you pass in a `Throwable`.
+
+It's recommended that you create `AssumptionViolatedException` via the methods in `Assume`.
+
+
+### [Pull request #542:](https://github.com/junit-team/junit/pull/542) Customized failure message for `ExpectedException`
+
+`ExpectedException` now allows customization of the failure message when the test does not throw the expected exception. For example:
+
+```java
+thrown.reportMissingExceptionWithMessage("FAIL: Expected exception to be thrown");
+```
+
+If a custom failure message is not provided, a default message is used.
+
+
+### [Pull request #1013:](https://github.com/junit-team/junit/pull/1013) Make ErrorCollector#checkSucceeds generic
+
+The method `ErrorCollector.checkSucceeds()` is now generic. Previously, you could only pass
+in a `Callable<Object>` and it returned `Object`. You can now pass any `Callable` and the
+return type will match the type of the callable.
+
+
+# Timeout for Tests
+*See also [Timeout for tests](https://github.com/junit-team/junit/wiki/Timeout-for-tests)*
+
+### [Pull request #823:](https://github.com/junit-team/junit/pull/823) Throw `TestFailedOnTimeoutException` instead of plain `Exception` on timeout
+
+When a test times out, a `org.junit.runners.model.TestTimedOutException` is now thrown instead of a plain `java.lang.Exception`.
+
+
+### [Pull request #742:](https://github.com/junit-team/junit/pull/742) [Pull request #986:](https://github.com/junit-team/junit/pull/986) `Timeout` exceptions now include stack trace from stuck thread (experimental)
+
+`Timeout` exceptions try to determine if there is a child thread causing the problem, and if so its stack trace is included in the exception in addition to the one of the main thread. This feature must be enabled with the timeout rule by creating it through the new `Timeout.builder()` method:
+
+```java
+public class HasGlobalTimeout {
+    @Rule public final TestRule timeout = Timeout.builder()
+            .withTimeout(10, TimeUnit.SECONDS)
+            .withLookingForStuckThread(true)
+            .build();
+
+    @Test
+    public void testInfiniteLoop() {
+        for (;;) {
+        }
+    }
+}
+```
+
+
+### [Pull request #544:](https://github.com/junit-team/junit/pull/544) New constructor and factories in `Timeout`
+
+`Timeout` deprecated the old constructor `Timeout(int millis)`.
+A new constructor is available: `Timeout(long timeout, TimeUnit unit)`. It enables you to use different granularities of time units like `NANOSECONDS`, `MICROSECONDS`, `MILLISECONDS`, and `SECONDS`. Examples:
+
+```java
+@Rule public final TestRule globalTimeout = new Timeout(50, TimeUnit.MILLISECONDS);
+```
+
+```java
+@Rule public final TestRule globalTimeout = new Timeout(10, TimeUnit.SECONDS);
+```
+
+and factory methods in `Timeout`:
+
+```java
+@Rule public final TestRule globalTimeout = Timeout.millis(50);
+```
+
+```java
+@Rule public final TestRule globalTimeout = Timeout.seconds(10);
+```
+
+This usage avoids the truncation, which was the problem in the deprecated constructor `Timeout(int millis)` when casting `long` to `int`.
+
+
+### [Pull request #549:](https://github.com/junit-team/junit/pull/549) fixes for #544 and #545
+
+The `Timeout` rule applies the same timeout to all test methods in a class:
+
+```java
+public class HasGlobalTimeout {
+    @Rule
+    public Timeout globalTimeout = new Timeout(10, TimeUnit.SECONDS);
+
+    @Test
+    public void testInfiniteLoop() {
+        for (;;) {
+        }
+    }
+
+    @Test
+    public synchronized void testInterruptableLock() throws InterruptedException {
+        wait();
+    }
+
+    @Test
+    public void testInterruptableIO() throws IOException {
+        for (;;) {
+            FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
+
+            // Interrupted thread closes channel and throws ClosedByInterruptException.
+            channel.write(buffer);
+            channel.close();
+        }
+    }
+}
+```
+Each test is run in a new _daemon_ thread. If the specified timeout elapses before the test completes, its execution is interrupted via `Thread#interrupt()`. This happens in interruptable I/O (operations throwing `java.io.InterruptedIOException` and `java.nio.channels.ClosedByInterruptException`), locks (package `java.util.concurrent`) and methods in `java.lang.Object` and `java.lang.Thread` throwing `java.lang.InterruptedException`.
+
+### [Pull request #876:](https://github.com/junit-team/junit/pull/876) The timeout rule never times out if you pass in a timeout of zero.
+
+
+# Parameterized Tests
+
+
+### [Pull request #702:](https://github.com/junit-team/junit/pull/702) Support more return types for the `@Parameters` method of the `Parameterized` runner
+
+The return types `Iterator<? extends Object>`, `Object[]` and `Object[][]` are now supported on methods annotated with `@Parameters`. You don't have to wrap arrays with `Iterable`s and single parameters with `Object` arrays.
+
+
+### [Pull request #773:](https://github.com/junit-team/junit/pull/773) Allow configurable creation of child runners of parameterized suites
+
+The factory for creating the `Runner` instance of a single set of parameters is now configurable. It can be specified by the `@UseParametersRunnerFactory` annotation.
+
+
+# Rules
+
+
+### [Pull request #552:](https://github.com/junit-team/junit/pull/552) [Pull request #937:](https://github.com/junit-team/junit/pull/937) `Stopwatch` rule
+
+The `Stopwatch` Rule notifies one of its own protected methods of the time spent by a test. Override them to get the time in nanoseconds. For example, this class will keep logging the time spent by each passed, failed, skipped, and finished test:
+
+```java
+public static class StopwatchTest {
+    private static final Logger logger = Logger.getLogger("");
+
+    private static void logInfo(String testName, String status, long nanos) {
+        logger.info(String.format("Test %s %s, spent %d microseconds",
+            testName, status, Stopwatch.toMicros(nanos)));
+    }
+
+    @Rule
+    public Stopwatch stopwatch = new Stopwatch() {
+        @Override
+        protected void succeeded(long nanos, Description description) {
+            logInfo(description.getMethodName(), "succeeded", nanos);
+        }
+
+        @Override
+        protected void failed(long nanos, Throwable e, Description description) {
+            logInfo(description.getMethodName(), "failed", nanos);
+        }
+
+        @Override
+        protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
+            logInfo(description.getMethodName(), "skipped", nanos);
+        }
+
+        @Override
+        protected void finished(long nanos, Description description) {
+            logInfo(description.getMethodName(), "finished", nanos);
+        }
+    };
+
+    @Test
+    public void succeeds() {
+    }
+
+    @Test
+    public void fails() {
+        fail();
+    }
+
+    @Test
+    public void skips() {
+        assumeTrue(false);
+    }
+}
+```
+
+An example to assert running time:
+
+```java
+@Test
+public void performanceTest() throws InterruptedException {
+    long delta = 30;
+    Thread.sleep(300L);
+    assertEquals(300D, stopwatch.runtime(MILLISECONDS), delta);
+    Thread.sleep(500L);
+    assertEquals(800D, stopwatch.runtime(MILLISECONDS), delta);
+}
+```
+
+### [Pull request #932:](https://github.com/junit-team/junit/pull/932) Allow static `@Rule`s also annotated with `@ClassRule`
+
+JUnit 4.11 introduced restrictions requiring `@Rule` members to be non-static and `@ClassRule` members to be static. These restrictions have been relaxed slightly, in that a static member annotated with both `@Rule` and `@ClassRule` is now considered valid. This means a single rule may be used to perform actions both before/after a class (e.g. setup/tear down an external resource) and between tests (e.g. reset the external resource), without the need for any workarounds mentioned in issue [#793](https://github.com/junit-team/junit/issues/793).
+
+Note that a non-static `@ClassRule` annotated member is still considered invalid, even if annotated with `@Rule`.
+
+```java
+public class CommonRuleTest {
+    @Rule
+    @ClassRule
+    public static MySetupResetAndTearDownRule rule = new MySetupResetAndTearDownRule();
+}
+```
+
+Be warned that if you have static methods or fields annotated with `@Rule` you will not be able to run your test methods in parallel.
+
+### [Pull request #956:](https://github.com/junit-team/junit/pull/956) `DisableOnDebug` rule
+
+The `DisableOnDebug` rule allows users to disable other rules when the JVM is launched in debug mode. Prior to this feature the common approach to disable rules that make debugging difficult was to comment them out and remember to revert the change. When using this feature users no longer have to modify their test code nor do they need to remember to revert changes.
+
+This rule is particularly useful in combination with the `Timeout` rule. 
+
+```
+@Rule
+public DisableOnDebug timeout = new DisableOnDebug(Timeout.seconds(1));
+```
+
+See the Javadoc for more detail and limitations. Related to https://github.com/junit-team/junit/issues/738
+
+### [Pull request #974:](https://github.com/junit-team/junit/pull/974) Updated `TemporaryFolder.newFolder()` to give an error message if a path contains a slash.
+
+If you call `TemporaryFolder.newFolder("foo/bar")` in JUnit 4.10 the method returns a `File` object for the new folder but actually fails to create it. That is contrary to the expected behaviour of the method which is to actually create the folder. In JUnit 4.11 the same call throws an exception. Nowhere in the documentation does it explain that the String(s) passed to that method can only be single path components.
+
+With this fix, folder names are validated to contain single path name. If the folder name consists of multiple path names, an exception is thrown stating that usage of multiple path components in a string containing folder name is disallowed.
+
+### [Pull request #1015:](https://github.com/junit-team/junit/pull/1015) Methods annotated with `Rule` can return a `MethodRule`.
+
+Methods annotated with `@Rule` can now return either a `TestRule` (or subclass) or a
+`MethodRule` (or subclass).
+
+Prior to this change, all public methods annotated with `@Rule` were called, but the
+return value was ignored if it could not be assigned to a `TestRule`. After this change,
+the method is only called if the return type could be assigned to `TestRule` or
+`MethodRule`. For methods annotated with `@Rule` that return other values, see the notes
+for pull request #1020.
+
+### [Pull request #1020:](https://github.com/junit-team/junit/pull/1020) Added validation that @ClassRule should only be implementation of TestRule.
+
+Prior to this change, fields annotated with `@ClassRule` that did not have a type of `TestRule`
+(or a class that implements `TestRule`) were ignored. With this change, the test will fail
+with a validation error.
+
+Prior to this change, methods annotated with `@ClassRule` that did specify a return type
+of `TestRule`(or a class that implements `TestRule`) were ignored. With this change, the test
+will fail with a validation error.
+
+### [Pull request #1021:](https://github.com/junit-team/junit/pull/1021) JavaDoc of TemporaryFolder: folder not guaranteed to be deleted.
+
+Adjusted JavaDoc of TemporaryFolder to reflect that temporary folders are not guaranteed to be
+deleted.
+
+# Theories
+
+
+### [Pull request #529:](https://github.com/junit-team/junit/pull/529) `@DataPoints`-annotated methods can now yield `null` values
+
+Up until JUnit 4.11 a `@DataPoints`-annotated array field could contain `null` values, but the array returned by a `@DataPoints`-annotated method could not. This asymmetry has been resolved: _both_ can now provide a `null` data point. 
+
+
+### [Pull request #572:](https://github.com/junit-team/junit/pull/572) Ensuring no-generic-type-parms validator called/tested for theories
+
+The `Theories` runner now disallows `Theory` methods with parameters that have "unresolved" generic type parameters (e.g. `List<T>` where `T` is a type variable). It is exceedingly difficult for the `DataPoint(s)` scraper or other `ParameterSupplier`s to correctly decide values that can legitimately be assigned to such parameters in a type-safe way, so JUnit now disallows them altogether. Theory parameters such as `List<String>` and `Iterable<? extends Number>` are still allowed.
+
+The machinery to perform this validation was in the code base for some time, but not used. It now is used.
+
+[junit.contrib](https://github.com/junit-team/junit.contrib)'s rendition of theories performs the same validation.
+
+
+### [Pull request #607:](https://github.com/junit-team/junit/pull/607) Improving theory failure messages
+
+Theory failure messages previously were of the form: `ParameterizedAssertionError: theoryTest(badDatapoint, allValues[1], otherVar)`, where allValues, badDatapoint and otherVar were the variables the datapoints was sourced from. These messages are now of the form: 
+
+```java
+ParameterizedAssertionError: theoryTest(null <from badDatapoint>, "good value" <from allValues[1]>, 
+                                  [toString() threw RuntimeException: Error message] <from otherVar>)
+```
+
+
+### [Pull request #601:](https://github.com/junit-team/junit/pull/601) Allow use of `Assume` in tests run by `Theories` runner
+
+If, in a theory, all parameters were "assumed" away, the `Theories` runner would properly fail, informing you that no parameters were found to actually test something. However, if you had another method in that same class, that was not a theory (annotated with `@Test` only,) you could not use Assume in that test. Now, the `Theories` runner will verify the method is annotated with `@Theory` before failing due to no parameters being found.
+
+```java
+@RunWith(Theories.class)
+public class TheoriesAndTestsTogether {
+    @DataPoint
+    public static Object o;
+
+    @Theory
+    public void theory(Object o) {
+        // this will still fail: java.lang.AssertionError: Never found parameters that satisfied method assumptions.
+        Assume.assumeTrue(false);
+    }
+
+    @Test
+    public void test() {
+        // this will no longer fail
+        Assume.assumeTrue(false);
+    }
+}
+```
+
+
+### [Pull request #623:](https://github.com/junit-team/junit/pull/623) Ensure data points array fields and methods are `public` and `static` in Theory classes.
+
+Previously if a data points array field or method was non-`static` or non-`public` it would be silently ignored and the data points not used. Now the `Theories` runner verifies that all `@DataPoint` or `@DataPoints` annotated fields or methods in classes are both `public` and `static`, and such classes will fail to run with `InitializationError`s if they are not.
+
+
+### [Pull request #621:](https://github.com/junit-team/junit/pull/621) Added mechanism for matching specific data points in theories to specific parameters, by naming data points.
+
+`@DataPoints` fields or methods can now be given (one or more) names in the annotation, and `@Theory` method parameters can be annotated with `@FromDataPoints(name)`, to limit the data points considered for that parameter to only the data points with that name:
+
+```java
+@DataPoints
+public static String[] unnamed = new String[] { ... };
+
+@DataPoints("regexes")
+public static String[] regexStrings = new String[] { ... };
+  
+@DataPoints({"forMatching", "alphanumeric"})
+public static String[] testStrings = new String[] { ... }; 
+  
+@Theory
+public void stringTheory(String param) {
+    // This will be called with every value in 'regexStrings',
+    // 'testStrings' and 'unnamed'.
+}
+  
+@Theory
+public void regexTheory(@FromDataPoints("regexes") String regex,
+                        @FromDataPoints("forMatching") String value) {
+    // This will be called with only the values in 'regexStrings' as 
+    // regex, only the values in 'testStrings' as value, and none 
+    // of the values in 'unnamed'.
+}
+```
+
+
+### [Pull request #654:](https://github.com/junit-team/junit/pull/654) Auto-generation of `enum` and `boolean` data points
+
+Any theory method parameters with `boolean` or `enum` types that cannot be supplied with values by any other sources will be automatically supplied with default values: `true` and `false`, or every value of the given `enum`. If other explicitly defined values are available (e.g. from a specified `ParameterSupplier` or some `DataPoints` method in the theory class), only those explicitly defined values will be used.
+
+
+### [Pull request #651:](https://github.com/junit-team/junit/pull/651) Improvements to Theory parameter and DataPoint type matching
+
+ * Validity of `DataPoints` for theory parameters for all field data points and multi-valued method data points (i.e. not single-valued method data points) is now done on runtime type, not field/method return type (previously this was the case for multi-valued array methods only).
+
+ * Validity of `DataPoints` for theory parameters for all data points now correctly handles boxing and unboxing for primitive and wrapper types; e.g. `int` values will be considered for theory parameters that are `Integer` assignable, and vice versa.
+
+
+### [Pull request #639:](https://github.com/junit-team/junit/pull/639) Failing theory datapoint methods now cause theory test failures
+
+Previously `@DataPoint(s)` methods that threw exceptions were quietly ignored and if another `DataPoint` source was available then those values alone were used, leaving the theory passing using only a subset of the (presumably) intended input values. Now, any data point method failures during invocation of a theory will cause the theory being tested to fail immediately.
+
+*This is a non-backward-compatible change*, and could potentially break theory tests that depended on failing methods. If that was desired behavior, then the expected exceptions can instead be specifically ignored using the new `ignoredExceptions` array attribute on `@DataPoint` and `@DataPoints` methods. Adding an exception to this `ignoredExceptions` array will stop theory methods from failing if the given exception, or subclasses of it, are thrown in the annotated method. This attribute has no effect on data point fields.
+
+
+### [Pull request #658:](https://github.com/junit-team/junit/pull/658) `Iterable`s can now be used as data points
+
+Previously, when building sets of data points for theory parameters, the only valid multi-valued `@DataPoints` types were arrays. This has now been extended to also take parameters from `Iterable` `@DataPoints` methods and fields.
+
+
+# Categories
+
+
+### [Pull request #566:](https://github.com/junit-team/junit/pull/566) Enables inheritance on `Category` by adding `@Inherited`
+
+`@interface Category` now is annotated with `@Inherited` itself. This enables inheritance of categories from ancestors (e.g. abstract test-classes). Note that you are able to "overwrite" `@Category` on inheritors and that this has no effect on method-level categories (see [@Inherited](http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/Inherited.html)).
+
+
+### [Pull request #503:](https://github.com/junit-team/junit/pull/503) Configurable Categories
+
+From a given set of test classes, the `Categories` runner runs only the classes and methods
+that are annotated with either the category given with the `@IncludeCategory` annotation, or a subtype of that category. Either classes or interfaces can be used as categories. Subtyping works, so if you say `@IncludeCategory(SuperClass.class)`, a test marked `@Category({SubClass.class})` will be run.
+
+You can also exclude categories by using the `@ExcludeCategory` annotation; see `SlowTestSuiteWithoutFast`.
+
+The suite `FastOrSmokeTestSuite` is an example to run multiple categories.
+
+To execute tests which match all categories, use `matchAny = false` in annotations. See `FastAndSmokeTestSuite`.
+ 
+Example:
+
+```java
+public static interface FastTests { /* category marker */ }
+public static interface SlowTests { /* category marker */ }
+public static interface SmokeTests { /* category marker */ }
+
+public static class A {
+    public void a() {
+        fail();
+    }
+
+    @Category(SlowTests.class)
+    @Test
+    public void b() {
+    }
+
+    @Category({FastTests.class, SmokeTests.class})
+    @Test
+    public void c() {
+    }
+}
+
+@Category({SlowTests.class, FastTests.class})
+public static class B {
+    @Test
+    public void d() {
+    }
+}
+
+@RunWith(Categories.class)
+@Categories.IncludeCategory(SlowTests.class)
+@Suite.SuiteClasses({A.class, B.class})
+public static class SlowTestSuite {
+    // Will run A.b and B.d, but not A.a and A.c
+}
+
+@RunWith(Categories.class)
+@Categories.IncludeCategory({FastTests.class, SmokeTests.class})
+@Suite.SuiteClasses({A.class, B.class})
+public static class FastOrSmokeTestSuite {
+    // Will run A.c and B.d, but not A.b because it is not any of FastTests or SmokeTests
+}
+
+@RunWith(Categories.class)
+@Categories.IncludeCategory(value = {FastTests.class, SmokeTests.class}, matchAny = false)
+@Suite.SuiteClasses({A.class, B.class})
+public static class FastAndSmokeTestSuite {
+    // Will run only A.c => match both FastTests AND SmokeTests
+}
+
+@RunWith(Categories.class)
+@Categories.IncludeCategory(SlowTests.class)
+@Categories.ExcludeCategory(FastTests.class)
+@Suite.SuiteClasses({A.class, B.class}) // Note that Categories is a kind of Suite
+public class SlowTestSuiteWithoutFast {
+	// Will run A.b, but not A.a, A.c or B.d
+}
+```
+
+
+# Use with Maven
+
+
+### [Pull request #879:] (https://github.com/junit-team/junit/pull/879) Add the default 'Implementation-*' headers to the manifest
+
+The default Maven-style 'Implementation-*' headers are now present in the manifest of `junit.jar`. Example:
+```
+Implementation-Vendor: JUnit
+Implementation-Title: JUnit
+Implementation-Version: 4.12
+Implementation-Vendor-Id: junit
+```
+
+
+### [Pull request #511:](https://github.com/junit-team/junit/pull/511) Maven project junit:junit:jar
+
+
+#### How to install Maven
+
+Download the Maven binary [http://www.us.apache.org/dist/maven/maven-3/3.0.4/binaries](http://www.us.apache.org/dist/maven/maven-3/3.0.4/binaries).
+
+(wget http://www.us.apache.org/dist/maven/maven-3/3.0.4/binaries/apache-maven-3.0.4-bin.tar.gz)
+
+If you are in the project root, extract the archive (tar xvzf apache-maven-3.0.4-bin.tar.gz).
+Create directory _.m2_ in your _user home_. Then the artifacts and plugins are stored in `~/.m2/repository`.
+( _~_ stands for user home)
+
+
+#### How to launch the build from the command line
+
+Clone the project (git clone https://github.com/junit-team/junit.git) and navigate to the project root on your local system (cd junit).
+Clean the previous build in _target_ directory, build the project, and install new artifacts in your local repository:
+
+`apache-maven-3.0.4/bin/mvn clean install`
+
+On Windows type the command `apache-maven-3.0.4\bin\mvn clean install`.
+
+Set the environment variables `M2_HOME` and `PATH` when frequently building via command line `mvn clean install`.
+
+[http://maven.apache.org/guides/development/guide-building-m2.html#Building_Maven_Without_Maven_Installed](http://maven.apache.org/guides/development/guide-building-m2.html#Building_Maven_Without_Maven_Installed)
+
+
+#### How to install and build the Maven project in Eclipse
+
+I made a clone of JUnit project from GitHub to local folder `C:\cygwin\usr\local\etc\junit`.
+
+In menu go to _File -> Import..._
+
+In the popup menu open section _Maven_, click on _Existing Maven Projects_ and click on _Next_. In _Import Maven Projects_ specify the project root, and next proceed further with installing maven support plugin in Eclipse.
+
+You have created the Maven project, and now build the project.
+
+In the Package Explorer click on _pom.xml_. In the menu _Run -> Run As -> 2 Maven build..._ open the popup _Edit Configuration_ and specify the build phase _clean install_ in section _Goals_. Click on _Run_ and build the project.
+
+#### How to install and build the Maven project in IntelliJ IDEA
+
+In IDEA menu create a new project _File -> New Project..._.
+
+Select _Create Java project from existing sources_, then click on Next and specify _Project file location_.
+
+On the right-hand side is the _Maven Projects_ tab. Click on + and add _pom.xml_ into the project. Then click on the icon _Maven Settings_, and set _Maven home directory_ as the location of extracted Maven archive on your system. Click on the green triangle and launch the build.
+
+See the IntelliJ IDEA Web help
+[http://www.jetbrains.com/idea/webhelp/maven-2.html](http://www.jetbrains.com/idea/webhelp/maven-2.html)
+
+#### How to install the Maven project with documentation
+Use the profile `generate-docs` to build _sources.jar_ and _javadoc.jar_. Building Maven site is not yeat supported.
+
+Example: `mvn -Pgenerate-docs install`
+
+#### How to activate and deactivate Maven profiles in Integrated Development Environments:
+
+In _Eclipse_, from the main menu navigate to Run -> Run As -> 2 Maven build..., open the popup _Edit Configuration_ and specify the profiles.
+
+Follow this link for _IntelliJ IDEA_: [http://www.jetbrains.com/idea/webhelp/activating-and-deactivating-maven-profiles.html](http://www.jetbrains.com/idea/webhelp/activating-and-deactivating-maven-profiles.html)
+
+
+# Miscellaneous
+
+
+### [Pull request #776:](https://github.com/junit-team/junit/pull/776) Add support for [Travis CI](http://travis-ci.org)
+
+Travis CI is a free CI server for public Github repositories. Every pull request is run by Travis CI and Github's web interface shows the CI result for each pull request. Every user can use Travis CI for testing her branches, too.
+
+### [Pull request #921:](https://github.com/junit-team/junit/pull/921) Apply Google Code Style
+
+JUnit is now using the well documented [Google Code Style](http://google-styleguide.googlecode.com/svn/trunk/javaguide.html)
+
+### [Pull request #939](https://github.com/junit-team/junit/pull/939) Renamed license file
+
+While using JUnit in Android apps, if any other referenced library has a file named `LICENSE.txt`, the APK generation failed with the following error -
+
+`Error generating final archive: Found duplicate file for APK: LICENSE.txt`
+
+To avoid this, the license file has been renamed to `LICENSE-junit.txt` 
+
+
+### [Pull request #962:](https://github.com/junit-team/junit/pull/962) Do not include thread start time in test timeout measurements.
+
+The time it takes to start a thread can be surprisingly large.
+Especially in virtualized cloud environments where noisy neighbours.
+This change reduces the probability of non-deterministic failures of
+tests with timeouts (@Test(timeout=…)) by not beginning the timeout
+clock until we have observed the starting of the task thread – the
+thread that runs the actual test. This should make tests with small
+timeout values more reliable in general, and especially in cloud CI
+environments.
+
+# Fixes to issues introduced in JUnit 4.12
+
+The following section lists fixes to problems introduced in the first
+release candidates for JUnit 4.12. You can ignore this section if you are
+trying to understand the changes between 4.11 and 4.12.
+
+### [Pull request #961:](https://github.com/junit-team/junit/pull/961) Restore field names with f prefix.
+
+In order to make the JUnit code more consistent with current coding practices, we changed
+a number of field names to not start with the prefix "f". Unfortunately, at least one IDE
+referenced a private field via reflection. This change reverts the field names for fields
+known to be read via reflection.
+
+### [Pull request #988:](https://github.com/junit-team/junit/pull/988) Revert "Delete classes that are deprecated for six years."
+
+In [745ca05](https://github.com/junit-team/junit/commit/745ca05dccf5cc907e43a58142bb8be97da2b78f)
+we removed classes that were deprecated for many releases. There was some concern that people
+might not expect classes to be removed in a 4.x release. Even though we are not aware of any
+problems from the deletion, we decided to add them back.
+
+These classes may be removed in JUnit 5.0 or later.
+
+### [Pull request #989:](https://github.com/junit-team/junit/pull/989) Add JUnitSystem.exit() back.
+
+In [917a88f](https://github.com/junit-team/junit/commit/917a88fad06ce108a596a8fdb4607b1a2fbb3f3e)
+the exit() method in JUnit was removed. This caused problems for at least one user. Even
+though this class is in an internal package, we decided to add it back, and deprecated it.
+
+This method may be removed in JUnit 5.0 or later.
+
+### [Pull request #994:](https://github.com/junit-team/junit/pull/994) [Pull request #1000:](https://github.com/junit-team/junit/pull/1000) Ensure serialization compatibility where possible.
+
+JUnit 4.12 RC1 introduced serilization incompatibilities with some of the classes. For example,
+these pre-release versions of JUnit could not read instances of `Result` that were serialized
+in JUnit 4.11 and earlier. These changes fix that problem.
+
diff --git a/doc/ReleaseNotes4.13.md b/doc/ReleaseNotes4.13.md
new file mode 100644
index 0000000..a8391ce
--- /dev/null
+++ b/doc/ReleaseNotes4.13.md
@@ -0,0 +1,6 @@
+## Summary of changes in version 4.13 [unreleased!]
+
+We collect release notes in the wiki:
+https://github.com/junit-team/junit/wiki/4.13-release-notes
+
+This file will be updated right before release.
diff --git a/doc/ReleaseNotes4.4.md b/doc/ReleaseNotes4.4.md
index 98d9ddd..bc1d54b 100644
--- a/doc/ReleaseNotes4.4.md
+++ b/doc/ReleaseNotes4.4.md
@@ -3,24 +3,28 @@
 ### Categories ###
 Each test method and test class can be annotated as belonging to a _category_:
 
-    public static class SomeUITests {
-        @Category(UserAvailable.class)
-        @Test
-        public void askUserToPressAKey() { }
-        
-        @Test
-        public void simulatePressingKey() { }
-    }
+```java
+public static class SomeUITests {
+    @Category(UserAvailable.class)
+    @Test
+    public void askUserToPressAKey() { }
     
-    @Category(InternetConnected.class)
-    public static class InternetTests {
-        @Test
-        public void pingServer() { }
-    } 
+    @Test
+    public void simulatePressingKey() { }
+}
+    
+@Category(InternetConnected.class)
+public static class InternetTests {
+    @Test
+    public void pingServer() { }
+}
+```
 
 To run all of the tests in a particular category, you must currently explicitly create a custom request:
 
-    new JUnitCore().run(Request.aClass(SomeUITests.class).inCategories(UserAvailable.class));
+```java
+new JUnitCore().run(Request.aClass(SomeUITests.class).inCategories(UserAvailable.class));
+```
   
 This feature will very likely be improved before the final release of JUnit 4.5
 
@@ -64,14 +68,18 @@
 [walnes]: http://joe.truemesh.com/blog/000511.html
 [JMock 1]: http://www.jmock.org/download.html
 
-    assertThat(x, is(3));
-    assertThat(x, is(not(4)));
-    assertThat(responseString, either(containsString("color")).or(containsString("colour")));
-    assertThat(myList, hasItem("3"));
+```java
+assertThat(x, is(3));
+assertThat(x, is(not(4)));
+assertThat(responseString, either(containsString("color")).or(containsString("colour")));
+assertThat(myList, hasItem("3"));
+```
 
 More generally:
 
-    assertThat([value], [matcher statement]);
+```java
+assertThat([value], [matcher statement]);
+```
 
 Advantages of this assertion syntax include:
 
@@ -83,15 +91,17 @@
 
 - Readable failure messages.  Compare
 
-        assertTrue(responseString.contains("color") || responseString.contains("colour"));
-        // ==> failure message: 
-        // java.lang.AssertionError:
+```java
+assertTrue(responseString.contains("color") || responseString.contains("colour"));
+// ==> failure message: 
+// java.lang.AssertionError:
 
-        assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
-        // ==> failure message:
-        // java.lang.AssertionError: 
-        // Expected: (a string containing "color" or a string containing "colour")
-        //      got: "Please choose a font"
+assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
+// ==> failure message:
+// java.lang.AssertionError: 
+// Expected: (a string containing "color" or a string containing "colour")
+//      got: "Please choose a font"
+```
 
 - Custom Matchers.  By implementing the `Matcher` interface yourself, you can get all of the
   above benefits for your own custom assertions.
@@ -113,11 +123,15 @@
 - The second parameter of an `assertThat` statement is a `Matcher`.
   We include the Matchers we want as static imports, like this:
 
-        import static org.hamcrest.CoreMatchers.is;
+```java
+import static org.hamcrest.CoreMatchers.is;
+```
 
   or:
 
-        import static org.hamcrest.CoreMatchers.*;
+```java
+import static org.hamcrest.CoreMatchers.*;
+```
 
 - Manually importing `Matcher` methods can be frustrating.  [Eclipse 3.3][] includes the ability to 
   define
@@ -158,17 +172,19 @@
 implicit assumptions and all, or to write a test that exposes a known bug.
 For these situations, JUnit now includes the ability to express "assumptions":
 
-    import static org.junit.Assume.*
+```java
+import static org.junit.Assume.*
 
-    @Test public void filenameIncludesUsername() {
-       assumeThat(File.separatorChar, is('/'));
-       assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg"));
-    }
+@Test public void filenameIncludesUsername() {
+    assumeThat(File.separatorChar, is('/'));
+    assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg"));
+}
 
-    @Test public void correctBehaviorWhenFilenameIsNull() {
-       assumeTrue(bugFixed("13356"));  // bugFixed is not included in JUnit
-       assertThat(parse(null), is(new NullDocument()));
-    }
+@Test public void correctBehaviorWhenFilenameIsNull() {
+    assumeTrue(bugFixed("13356"));  // bugFixed is not included in JUnit
+    assertThat(parse(null), is(new NullDocument()));
+}
+```
 
 With this release, a failed assumption will lead to the test being marked as passing,
 regardless of what the code below the assumption may assert.
@@ -194,16 +210,18 @@
 intended behavior in possibly
 infinite numbers of potential scenarios.  For example:
 
-    @RunWith(Theories.class)
-    public class UserTest {
-      @DataPoint public static String GOOD_USERNAME = "optimus";
-      @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";
+```java
+@RunWith(Theories.class)
+public class UserTest {
+    @DataPoint public static String GOOD_USERNAME = "optimus";
+    @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";
 
-      @Theory public void filenameIncludesUsername(String username) {
+    @Theory public void filenameIncludesUsername(String username) {
         assumeThat(username, not(containsString("/")));
         assertThat(new User(username).configFileName(), containsString(username));
-      }
     }
+}
+```
 
 This makes it clear that the user's filename should be included in the
 config file name, only if it doesn't contain a slash.  Another test
@@ -245,7 +263,9 @@
   native implementation of `equals`.  This assertion, which passed in
   4.3, will now fail:
 
-        assertEquals(new Integer(1), new Long(1));
+```java
+assertEquals(new Integer(1), new Long(1));
+```
 
   Non-integer Numbers (Floats, Doubles, BigDecimals, etc),
   which were compared incorrectly in 4.3, are now fixed.
@@ -254,7 +274,9 @@
   been re-introduced to the `Assert` class, to take advantage of
   Java's native widening conversions.  Therefore, this still passes:
 
-        assertEquals(1, 1L);
+```java
+assertEquals(1, 1L);
+```
 
 - The default runner for JUnit 4 test classes has been refactored.
   The old version was named `TestClassRunner`, and the new is named
@@ -286,9 +308,11 @@
 - Bug fix (1739095): Filters and Sorters work correctly on test
   classes that contain a `suite` method like:
 
-        public static junit.framework.Test suite() {
-          return new JUnit4TestAdapter(MyTest.class);
-        }
+```java
+public static junit.framework.Test suite() {
+    return new JUnit4TestAdapter(MyTest.class);
+}
+```
 
 - Bug fix (1745048): @After methods are now correctly called 
   after a test method times out.
diff --git a/doc/ReleaseNotes4.5.html b/doc/ReleaseNotes4.5.html
new file mode 100644
index 0000000..643a2e0
--- /dev/null
+++ b/doc/ReleaseNotes4.5.html
@@ -0,0 +1,320 @@
+<h2>Summary of Changes in version 4.5</h2>
+
+<h3>Installation</h3>
+
+<ul>
+<li>We are releasing <code>junit-4.5.jar</code>, which contains all the classes
+necessary to run JUnit, and <code>junit-dep-4.5.jar</code>, which leaves out
+hamcrest classes, for developers who already use hamcrest outside of
+JUnit.</li>
+</ul>
+
+<h3>Basic JUnit operation</h3>
+
+<ul>
+<li><p>JUnitCore now more often exits with the correct exit code (0 for
+success, 1 for failure)</p></li>
+<li><p>Badly formed test classes (exceptions in constructors, classes
+without tests, multiple constructors, Suite without @SuiteClasses)
+produce more helpful error messages</p></li>
+<li><p>Test classes whose only test methods are inherited from superclasses
+now run.</p></li>
+<li><p>Optimization to annotation processing can cut JUnit overhead by more than half
+on large test classes, especially when using Theories.  [Bug 1796847]</p></li>
+<li><p>A failing assumption in a constructor ignores the class</p></li>
+<li><p>Correct results when comparing the string "null" with potentially
+null values.  [Bug 1857283]</p></li>
+<li><p>Annotating a class with <code>@RunWith(JUnit4.class)</code> will always invoke the
+default JUnit 4 runner in the current version of JUnit.  This default changed
+from <code>JUnit4ClassRunner</code> in 4.4 to <code>BlockJUnit4ClassRunner</code> in 4.5 (see below),
+and may change again.</p></li>
+</ul>
+
+<h3>Extension</h3>
+
+<ul>
+<li><p><code>BlockJUnit4Runner</code> is a new implementation of the standard JUnit 4
+test class functionality.  In contrast to <code>JUnit4ClassRunner</code> (the old
+implementation):</p>
+
+<ul>
+<li><p><code>BlockJUnit4Runner</code> has a much simpler implementation based on
+Statements, allowing new operations to be inserted into the
+appropriate point in the execution flow.</p></li>
+<li><p><code>BlockJUnit4Runner</code> is published, and extension and reuse are
+encouraged, whereas <code>JUnit4ClassRunner</code> was in an internal package,
+and is now deprecated.</p></li>
+</ul></li>
+<li><p><code>ParentRunner</code> is a base class for runners that iterate over
+a list of "children", each an object representing a test or suite to run.
+<code>ParentRunner</code> provides filtering, sorting, <code>@BeforeClass</code>, <code>@AfterClass</code>,
+and method validation to subclasses.</p></li>
+<li><p><code>TestClass</code> wraps a class to be run, providing efficient, repeated access
+to all methods with a given annotation.</p></li>
+<li><p>The new <code>RunnerBuilder</code> API allows extending the behavior of
+Suite-like custom runners.</p></li>
+<li><p><code>AssumptionViolatedException.toString()</code> is more informative</p></li>
+</ul>
+
+<h3>Extra Runners</h3>
+
+<ul>
+<li><p><code>Parameterized.eachOne()</code> has been removed</p></li>
+<li><p>New runner <code>Enclosed</code> runs all static inner classes of an outer class.</p></li>
+</ul>
+
+<h3>Theories</h3>
+
+<ul>
+<li><p><code>@Before</code> and <code>@After</code> methods are run before and after each set of attempted parameters
+on a Theory, and each set of parameters is run on a new instance of the test class.</p></li>
+<li><p>Exposed API's <code>ParameterSignature.getType()</code> and <code>ParameterSignature.getAnnotations()</code></p></li>
+<li><p>An array of data points can be introduced by a field or method
+marked with the new annotation <code>@DataPoints</code></p></li>
+<li><p>The Theories custom runner has been refactored to make it faster and
+easier to extend</p></li>
+</ul>
+
+<h3>Development</h3>
+
+<ul>
+<li><p>Source has been split into directories <code>src/main/java</code> and
+<code>src/test/java</code>, making it easier to exclude tests from builds, and
+making JUnit more maven-friendly</p></li>
+<li><p>Test classes in <code>org.junit.tests</code> have been organized into
+subpackages, hopefully making finding tests easier.</p></li>
+<li><p><code>ResultMatchers</code> has more informative descriptions.</p></li>
+<li><p><code>TestSystem</code> allows testing return codes and other system-level interactions.</p></li>
+</ul>
+
+<h2>Summary of Changes in version 4.4</h2>
+
+<p>JUnit is designed to efficiently capture developers' intentions about
+their code, and quickly check their code matches those intentions.
+Over the last year, we've been talking about what things developers
+would like to say about their code that have been difficult in the
+past, and how we can make them easier.</p>
+
+<h3>assertThat</h3>
+
+<p>Two years ago, Joe Walnes built a <a href="http://joe.truemesh.com/blog/000511.html">new assertion mechanism</a> on top of what was 
+then <a href="http://www.jmock.org/download.html">JMock 1</a>.  The method name was <code>assertThat</code>, and the syntax looked like this:</p>
+
+<pre><code>assertThat(x, is(3));
+assertThat(x, is(not(4)));
+assertThat(responseString, either(containsString("color")).or(containsString("colour")));
+assertThat(myList, hasItem("3"));
+</code></pre>
+
+<p>More generally:</p>
+
+<pre><code>assertThat([value], [matcher statement]);
+</code></pre>
+
+<p>Advantages of this assertion syntax include:</p>
+
+<ul>
+<li><p>More readable and typeable: this syntax allows you to think in terms of subject, verb, object
+(assert "x is 3") rathern than <code>assertEquals</code>, which uses verb, object, subject (assert "equals 3 x")</p></li>
+<li><p>Combinations: any matcher statement <code>s</code> can be negated (<code>not(s)</code>), combined (<code>either(s).or(t)</code>),
+mapped to a collection (<code>each(s)</code>), or used in custom combinations (<code>afterFiveSeconds(s)</code>)</p></li>
+<li><p>Readable failure messages.  Compare</p>
+
+<pre><code>assertTrue(responseString.contains("color") || responseString.contains("colour"));
+// ==&gt; failure message: 
+// java.lang.AssertionError:
+
+
+assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
+// ==&gt; failure message:
+// java.lang.AssertionError: 
+// Expected: (a string containing "color" or a string containing "colour")
+//      got: "Please choose a font"
+</code></pre></li>
+<li><p>Custom Matchers.  By implementing the <code>Matcher</code> interface yourself, you can get all of the
+above benefits for your own custom assertions.</p></li>
+<li><p>For a more thorough description of these points, see <a href="http://joe.truemesh.com/blog/000511.html">Joe Walnes's
+original post</a>.:</p></li>
+</ul>
+
+<p>We have decided to include this API directly in JUnit.
+It's an extensible and readable syntax, and because it enables
+new features, like <a href="#assumptions">assumptions</a> and <a href="#theories">theories</a>.</p>
+
+<p>Some notes:</p>
+
+<ul>
+<li>The old assert methods are never, ever, going away. <br />
+Developers may continue using the old <code>assertEquals</code>, <code>assertTrue</code>, and
+so on.</li>
+<li><p>The second parameter of an <code>assertThat</code> statement is a <code>Matcher</code>.
+We include the Matchers we want as static imports, like this:</p>
+
+<pre><code>import static org.hamcrest.CoreMatchers.is;
+</code></pre>
+
+<p>or:</p>
+
+<pre><code>import static org.hamcrest.CoreMatchers.*;
+</code></pre></li>
+<li><p>Manually importing <code>Matcher</code> methods can be frustrating.  [Eclipse
+3.3][] includes the ability to 
+define
+"Favorite" classes to import static methods from, which makes it easier 
+(Search for "Favorites" in the Preferences dialog).
+We expect that support for static imports will improve in all Java IDEs in the future.</p></li>
+<li><p>To allow compatibility with a wide variety of possible matchers, 
+we have decided to include the classes from hamcrest-core,
+from the <a href="http://code.google.com/p/hamcrest/">Hamcrest</a> project.  This is the first time that
+third-party classes have been included in JUnit.  </p></li>
+<li><p>To allow developers to maintain full control of the classpath contents, the JUnit distribution also provides an unbundled junit-dep jar,
+ie without hamcrest-core classes included.  This is intended for situations when using other libraries that also depend on hamcrest-core, to
+avoid classloading conflicts or issues.  Developers using junit-dep should ensure a compatible version of hamcrest-core jar (ie 1.1+) is present in the classpath.</p></li>
+<li><p>JUnit currently ships with a few matchers, defined in 
+<code>org.hamcrest.CoreMatchers</code> and <code>org.junit.matchers.JUnitMatchers</code>. <br />
+To use many, many more, consider downloading the <a href="http://hamcrest.googlecode.com/files/hamcrest-all-1.1.jar">full hamcrest package</a>.</p></li>
+<li><p>JUnit contains special support for comparing string and array
+values, giving specific information on how they differ.  This is not
+yet available using the <code>assertThat</code> syntax, but we hope to bring
+the two assert methods into closer alignment in future releases.</p></li>
+</ul>
+
+<h3>assumeThat</h3>
+
+<p><a name="assumptions" />
+Ideally, the developer writing a test has control of all of the forces that might cause a test to fail.
+If this isn't immediately possible, making dependencies explicit can often improve a design. <br />
+For example, if a test fails when run in a different locale than the developer intended,
+it can be fixed by explicitly passing a locale to the domain code.</p>
+
+<p>However, sometimes this is not desirable or possible. <br />
+It's good to be able to run a test against the code as it is currently written, 
+implicit assumptions and all, or to write a test that exposes a known bug.
+For these situations, JUnit now includes the ability to express "assumptions":</p>
+
+<pre><code>import static org.junit.Assume.*
+
+@Test public void filenameIncludesUsername() {
+   assumeThat(File.separatorChar, is('/'));
+   assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg"));
+}
+
+@Test public void correctBehaviorWhenFilenameIsNull() {
+   assumeTrue(bugFixed("13356"));  // bugFixed is not included in JUnit
+   assertThat(parse(null), is(new NullDocument()));
+}
+</code></pre>
+
+<p>With this beta release, a failed assumption will lead to the test being marked as passing,
+regardless of what the code below the assumption may assert.
+In the future, this may change, and a failed assumption may lead to the test being ignored:
+however, third-party runners do not currently allow this option.</p>
+
+<p>We have included <code>assumeTrue</code> for convenience, but thanks to the
+inclusion of Hamcrest, we do not need to create <code>assumeEquals</code>,
+<code>assumeSame</code>, and other analogues to the <code>assert*</code> methods.  All of
+those functionalities are subsumed in assumeThat, with the appropriate
+matcher.</p>
+
+<p>A failing assumption in a <code>@Before</code> or <code>@BeforeClass</code> method will have the same effect
+as a failing assumption in each <code>@Test</code> method of the class.</p>
+
+<h3>Theories</h3>
+
+<p><a name="theories" />
+More flexible and expressive assertions, combined with the ability to
+state assumptions clearly, lead to a new kind of statement of intent, 
+which we call a "Theory".  A test captures the intended behavior in
+one particular scenario.  A theory allows a developer to be
+as precise as desired about the behavior of the code in possibly
+infinite numbers of possible scenarios.  For example:</p>
+
+<pre><code>@RunWith(Theories.class)
+public class UserTest {
+  @DataPoint public static String GOOD_USERNAME = "optimus";
+  @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";
+
+  @Theory public void filenameIncludesUsername(String username) {
+    assumeThat(username, not(containsString("/")));
+    assertThat(new User(username).configFileName(), containsString(username));
+  }
+}
+</code></pre>
+
+<p>This makes it clear that the user's filename should be included in the
+config file name, only if it doesn't contain a slash.  Another test
+or theory might define what happens when a username does contain a slash.</p>
+
+<p><code>UserTest</code> will attempt to run <code>filenameIncludesUsername</code> on 
+every compatible <code>DataPoint</code> defined in the class.  If any of the
+assumptions fail, the data point is silently ignored.  If all of the
+assumptions pass, but an assertion fails, the test fails.</p>
+
+<p>The support for Theories has been absorbed from the <a href="http://popper.tigris.org">Popper</a>
+project, and <a href="http://popper.tigris.org/tutorial.html">more complete documentation</a> can be found
+there.</p>
+
+<p>Defining general statements in this way can jog the developer's memory
+about other potential data points and tests, also allows <a href="http://www.junitfactory.org">automated
+tools</a> to <a href="http://shareandenjoy.saff.net/2007/04/popper-and-junitfactory.html">search</a> for new, unexpected data
+points that expose bugs.</p>
+
+<h3>Other changes</h3>
+
+<p>This release contains other bug fixes and new features.  Among them:</p>
+
+<ul>
+<li><p>Annotated descriptions</p>
+
+<p>Runner UIs, Filters, and Sorters operate on Descriptions of test
+methods and test classes.  These Descriptions now include the
+annotations on the original Java source element, allowing for richer
+display of test results, and easier development of annotation-based
+filters.</p></li>
+<li><p>Bug fix (1715326): assertEquals now compares all Numbers using their
+native implementation of <code>equals</code>.  This assertion, which passed in
+4.3, will now fail:</p>
+
+<p>assertEquals(new Integer(1), new Long(1));</p>
+
+<p>Non-integer Numbers (Floats, Doubles, BigDecimals, etc),
+which were compared incorrectly in 4.3, are now fixed.</p></li>
+<li><p><code>assertEquals(long, long)</code> and <code>assertEquals(double, double)</code> have
+been re-introduced to the <code>Assert</code> class, to take advantage of
+Java's native widening conversions.  Therefore, this still passes:</p>
+
+<p>assertEquals(1, 1L);</p></li>
+<li><p>The default runner for JUnit 4 test classes has been refactored.
+The old version was named <code>TestClassRunner</code>, and the new is named
+<code>JUnit4ClassRunner</code>.  Likewise, <code>OldTestClassRunner</code> is now
+<code>JUnit3ClassRunner</code>.  The new design allows variations in running
+individual test classes to be expressed with fewer custom classes.
+For a good example, see the source to
+<code>org.junit.experimental.theories.Theories</code>.</p></li>
+<li><p>The rules for determining which runner is applied by default to a
+test class have been simplified:</p>
+
+<ol>
+<li><p>If the class has a <code>@RunWith</code> annotation, the annotated runner
+class is used.</p></li>
+<li><p>If the class can be run with the JUnit 3 test runner (it
+subclasses <code>TestCase</code>, or contains a <code>public static Test suite()</code>
+method), JUnit38ClassRunner is used.</p></li>
+<li><p>Otherwise, JUnit4ClassRunner is used.</p></li>
+</ol>
+
+<p>This default guess can always be overridden by an explicit
+<code>@RunWith(JUnit4ClassRunner.class)</code> or
+<code>@RunWith(JUnit38ClassRunner.class)</code> annotation.</p>
+
+<p>The old class names <code>TestClassRunner</code> and <code>OldTestClassRunner</code>
+remain as deprecated.</p></li>
+<li><p>Bug fix (1739095): Filters and Sorters work correctly on test
+classes that contain a <code>suite</code> method like:</p>
+
+<p>public static junit.framework.Test suite() {
+  return new JUnit4TestAdapter(MyTest.class);
+}</p></li>
+<li><p>Bug fix (1745048): @After methods are now correctly called 
+after a test method times out.</p></li>
+</ul>
diff --git a/doc/ReleaseNotes4.6.md b/doc/ReleaseNotes4.6.md
index a5decac..f1f6a8e 100644
--- a/doc/ReleaseNotes4.6.md
+++ b/doc/ReleaseNotes4.6.md
@@ -14,31 +14,33 @@
 
 Example:
 
-	public static class TwoUnEqualTests {
-		@Test
-		public void slow() throws InterruptedException {
-			Thread.sleep(100);
-			fail();
-		}
-
-		@Test
-		public void fast() {
-			fail();
-		}
+```java
+public static class TwoUnEqualTests {
+	@Test
+	public void slow() throws InterruptedException {
+		Thread.sleep(100);
+		fail();
 	}
 
 	@Test
-	public void rememberOldRuns() {
-		File maxFile = new File("history.max");
-		MaxCore firstMax = MaxCore.storedLocally(maxFile);
-		firstMax.run(TwoUnEqualTests.class);
-
-		MaxCore useHistory= MaxCore.storedLocally(maxFile);
-		List<Failure> failures= useHistory.run(TwoUnEqualTests.class)
-				.getFailures();
-		assertEquals("fast", failures.get(0).getDescription().getMethodName());
-		assertEquals("slow", failures.get(1).getDescription().getMethodName());
+	public void fast() {
+		fail();
 	}
+}
+
+@Test
+public void rememberOldRuns() {
+	File maxFile = new File("history.max");
+	MaxCore firstMax = MaxCore.storedLocally(maxFile);
+	firstMax.run(TwoUnEqualTests.class);
+
+	MaxCore useHistory= MaxCore.storedLocally(maxFile);
+	List<Failure> failures= useHistory.run(TwoUnEqualTests.class)
+		.getFailures();
+	assertEquals("fast", failures.get(0).getDescription().getMethodName());
+	assertEquals("slow", failures.get(1).getDescription().getMethodName());
+}
+```
 
 ### Test scheduling strategies ###
 
@@ -54,32 +56,36 @@
 
 Example:
 
-	public static class Example {
-		@Test public void one() throws InterruptedException {
-			Thread.sleep(1000);
-		}
-		@Test public void two() throws InterruptedException {
-			Thread.sleep(1000);
-		}
+```java
+public static class Example {
+	@Test public void one() throws InterruptedException {
+		Thread.sleep(1000);
 	}
+	@Test public void two() throws InterruptedException {
+		Thread.sleep(1000);
+	}
+}
 	
-	@Test public void testsRunInParallel() {
-		long start= System.currentTimeMillis();
-		Result result= JUnitCore.runClasses(ParallelComputer.methods(),
-				Example.class);
-		assertTrue(result.wasSuccessful());
-		long end= System.currentTimeMillis();
-		assertThat(end - start, betweenInclusive(1000, 1500));
-	}
+@Test public void testsRunInParallel() {
+	long start= System.currentTimeMillis();
+	Result result= JUnitCore.runClasses(ParallelComputer.methods(),
+			Example.class);
+	assertTrue(result.wasSuccessful());
+	long end= System.currentTimeMillis();
+	assertThat(end - start, betweenInclusive(1000, 1500));
+}
+```
 
 ### Comparing double arrays ###
 
 Arrays of doubles can be compared, using a delta allowance for equality:
 
-	@Test
-	public void doubleArraysAreEqual() {
-		assertArrayEquals(new double[] {1.0, 2.0}, new double[] {1.0, 2.0}, 0.01);
-	}
+```java
+@Test
+public void doubleArraysAreEqual() {
+	assertArrayEquals(new double[] {1.0, 2.0}, new double[] {1.0, 2.0}, 0.01);
+}
+```
 	
 ### `Filter.matchDescription` API ###
 
diff --git a/doc/ReleaseNotes4.7.md b/doc/ReleaseNotes4.7.md
index 11b70c1..d33a501 100644
--- a/doc/ReleaseNotes4.7.md
+++ b/doc/ReleaseNotes4.7.md
@@ -12,166 +12,182 @@
   that are guaranteed to be deleted when the test method finishes
   (whether it passes or fails):
   
-  	public static class HasTempFolder {
-		@Rule
-		public TemporaryFolder folder= new TemporaryFolder();
+```java
+public static class HasTempFolder {
+	@Rule
+	public TemporaryFolder folder= new TemporaryFolder();
 
-		@Test
-		public void testUsingTempFolder() throws IOException {
-			File createdFile= folder.newFile("myfile.txt");
-			File createdFolder= folder.newFolder("subfolder");
-			// ...
-		}
+	@Test
+	public void testUsingTempFolder() throws IOException {
+		File createdFile= folder.newFile("myfile.txt");
+		File createdFolder= folder.newFolder("subfolder");
+		// ...
 	}
+}
+```
 
 - ExternalResource is a base class for Rules (like TemporaryFolder)
   that set up an external resource before a test (a file, socket, server,
   database connection, etc.), and guarantee to tear it down afterward:
   
-  	public static class UsesExternalResource {
-  		Server myServer = new Server();
+```java
+public static class UsesExternalResource {
+	Server myServer = new Server();
   		
-		@Rule public ExternalResource resource = new ExternalResource() {
-			@Override
-			protected void before() throws Throwable {
-				myServer.connect();
-			};
-			
-			@Override
-			protected void after() {
-				myServer.disconnect();
-			};
+	@Rule public ExternalResource resource = new ExternalResource() {
+		@Override
+		protected void before() throws Throwable {
+			myServer.connect();
 		};
+			
+		@Override
+		protected void after() {
+			myServer.disconnect();
+		};
+	};
 		
-		@Test public void testFoo() {
-			new Client().run(myServer);
-		}
+	@Test public void testFoo() {
+		new Client().run(myServer);
 	}
+}
+```
 
 - The ErrorCollector Rule allows execution of a test to continue
   after the first problem is found (for example, to collect _all_ the 
   incorrect rows in a table, and report them all at once):
 
-	public static class UsesErrorCollectorTwice {
-		@Rule
-		public ErrorCollector collector= new ErrorCollector();
+```java
+public static class UsesErrorCollectorTwice {
+	@Rule
+	public ErrorCollector collector= new ErrorCollector();
 		
-		@Test public void example() {
-			collector.addError(new Throwable("first thing went wrong"));
-			collector.addError(new Throwable("second thing went wrong"));
-		}
+	@Test public void example() {
+		collector.addError(new Throwable("first thing went wrong"));
+		collector.addError(new Throwable("second thing went wrong"));
 	}
+}
+```
 	
 - Verifier is a base class for Rules like ErrorCollector, which
   can turn otherwise passing test methods into failing tests if a verification
   check is failed
   
-    public static class ErrorLogVerifier() {
-       private ErrorLog errorLog = new ErrorLog();
+```java
+public static class ErrorLogVerifier() {
+	private ErrorLog errorLog = new ErrorLog();
     
-       @Rule
-       public MethodRule verifier = new Verifier() {
-          @Override public void verify() {
-             assertTrue(errorLog.isEmpty());
-          }
-       }
+	@Rule
+	public MethodRule verifier = new Verifier() {
+		@Override public void verify() {
+			assertTrue(errorLog.isEmpty());
+		}
+	}
        
-       @Test public void testThatMightWriteErrorLog() {
-          // ...
-       }
-    }
+	@Test public void testThatMightWriteErrorLog() {
+		// ...
+	}
+}
+```
 
 - TestWatchman is a base class for Rules that take note
   of the testing action, without modifying it.
   For example, this class will keep a log of each passing and failing 
   test:
   
-	public static class WatchmanTest {
-		private static String watchedLog;
+```java
+public static class WatchmanTest {
+	private static String watchedLog;
 
-		@Rule
-		public MethodRule watchman= new TestWatchman() {
-			@Override
-			public void failed(Throwable e, FrameworkMethod method) {
-				watchedLog+= method.getName() + " "
-						+ e.getClass().getSimpleName() + "\n";
-			}
-
-			@Override
-			public void succeeded(FrameworkMethod method) {
-				watchedLog+= method.getName() + " " + "success!\n";
-			}
-		};
-
-		@Test
-		public void fails() {
-			fail();
+	@Rule
+	public MethodRule watchman= new TestWatchman() {
+		@Override
+		public void failed(Throwable e, FrameworkMethod method) {
+			watchedLog+= method.getName() + " "
+					+ e.getClass().getSimpleName() + "\n";
 		}
 
-		@Test
-		public void succeeds() {
+		@Override
+		public void succeeded(FrameworkMethod method) {
+			watchedLog+= method.getName() + " " + "success!\n";
 		}
+	};
+
+	@Test
+	public void fails() {
+		fail();
 	}
 
+	@Test
+	public void succeeds() {
+	}
+}
+```
+
 - The TestName Rule makes the current test name available inside test methods:
 
-	public class NameRuleTest {
-		@Rule public TestName name = new TestName();
+```java
+public class NameRuleTest {
+	@Rule public TestName name = new TestName();
 		
-		@Test public void testA() {
-			assertEquals("testA", name.getMethodName());
-		}
-		
-		@Test public void testB() {
-			assertEquals("testB", name.getMethodName());
-		}
+	@Test public void testA() {
+		assertEquals("testA", name.getMethodName());
 	}
+		
+	@Test public void testB() {
+		assertEquals("testB", name.getMethodName());
+	}
+}
+```
 
 - The Timeout Rule applies the same timeout to all test methods in a class:
 
-	public static class HasGlobalTimeout {
-		public static String log;
+```java
+public static class HasGlobalTimeout {
+	public static String log;
 		
-		@Rule public MethodRule globalTimeout = new Timeout(20);
+	@Rule public MethodRule globalTimeout = new Timeout(20);
 		
-		@Test public void testInfiniteLoop1() {
-			log+= "ran1";
-			for(;;) {}
-		}
-		
-		@Test public void testInfiniteLoop2() {
-			log+= "ran2";
-			for(;;) {}
-		}
+	@Test public void testInfiniteLoop1() {
+		log+= "ran1";
+		for(;;) {}
 	}
+		
+	@Test public void testInfiniteLoop2() {
+		log+= "ran2";
+		for(;;) {}
+	}
+}
+```
 
 - The ExpectedException Rule allows in-test specification
   of expected exception types and messages:
-    
-	public static class HasExpectedException {
-		@Rule
-		public ExpectedException thrown= ExpectedException.none();
+   
+```java 
+public static class HasExpectedException {
+	@Rule
+	public ExpectedException thrown= ExpectedException.none();
 
-		@Test
-		public void throwsNothing() {
+	@Test
+	public void throwsNothing() {
 
-		}
-
-		@Test
-		public void throwsNullPointerException() {
-			thrown.expect(NullPointerException.class);
-			throw new NullPointerException();
-		}
-
-		@Test
-		public void throwsNullPointerExceptionWithMessage() {
-			thrown.expect(NullPointerException.class);
-			thrown.expectMessage("happened?");
-			thrown.expectMessage(startsWith("What"));
-			throw new NullPointerException("What happened?");
-		}
 	}
 
+	@Test
+	public void throwsNullPointerException() {
+		thrown.expect(NullPointerException.class);
+		throw new NullPointerException();
+	}
+
+	@Test
+	public void throwsNullPointerExceptionWithMessage() {
+		thrown.expect(NullPointerException.class);
+		thrown.expectMessage("happened?");
+		thrown.expectMessage(startsWith("What"));
+		throw new NullPointerException("What happened?");
+	}
+}
+```
+
 ### Timeouts ###
 - Tests that time out now show the stack trace of the test thread.
 
diff --git a/doc/ReleaseNotes4.8.md b/doc/ReleaseNotes4.8.md
index 4a30db6..cc429ea 100644
--- a/doc/ReleaseNotes4.8.md
+++ b/doc/ReleaseNotes4.8.md
@@ -13,44 +13,45 @@
  
 Example:
 
-	public interface FastTests { /* category marker */ }
-	public interface SlowTests { /* category marker */ }
+```java
+public interface FastTests { /* category marker */ }
+public interface SlowTests { /* category marker */ }
 
-	public class A {
-		@Test
-		public void a() {
-			fail();
-		}
-
-		@Category(SlowTests.class)
-		@Test
-		public void b() {
-		}
+public class A {
+	@Test
+	public void a() {
+		fail();
 	}
 
-	@Category({SlowTests.class, FastTests.class})
-	public class B {
-		@Test
-		public void c() {
-
-		}
+	@Category(SlowTests.class)
+	@Test
+	public void b() {
 	}
+}
 
-	@RunWith(Categories.class)
-	@IncludeCategory(SlowTests.class)
-	@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
-	public class SlowTestSuite {
-	  // Will run A.b and B.c, but not A.a
+@Category({SlowTests.class, FastTests.class})
+public class B {
+	@Test
+	public void c() {
 	}
+}
 
-	@RunWith(Categories.class)
-	@IncludeCategory(SlowTests.class)
-	@ExcludeCategory(FastTests.class)
-	@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
-	public class SlowTestSuite {
-	  // Will run A.b, but not A.a or B.c
-	}
+@RunWith(Categories.class)
+@IncludeCategory(SlowTests.class)
+@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
+public class SlowTestSuite {
+	// Will run A.b and B.c, but not A.a
+}
+
+@RunWith(Categories.class)
+@IncludeCategory(SlowTests.class)
+@ExcludeCategory(FastTests.class)
+@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
+public class SlowTestSuite {
+	// Will run A.b, but not A.a or B.c
+}
+```
 
 ### Bug fixes ###
 
-- github#16: thread safety of Result counting
\ No newline at end of file
+- github#16: thread safety of Result counting
diff --git a/doc/ReleaseNotes4.9.md b/doc/ReleaseNotes4.9.md
index 8b2a63d..5e62cea 100644
--- a/doc/ReleaseNotes4.9.md
+++ b/doc/ReleaseNotes4.9.md
@@ -12,24 +12,26 @@
 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:
 
-	@RunWith(Suite.class)
-	@SuiteClasses({A.class, B.class, C.class})
-	public class UsesExternalResource {
-		public static Server myServer= new Server();
-	
-		@ClassRule
-		public static ExternalResource resource= new ExternalResource() {
-			@Override
-			protected void before() throws Throwable {
-				myServer.connect();
-			};
-	
-			@Override
-			protected void after() {
-				myServer.disconnect();
-			};
+```java
+@RunWith(Suite.class)
+@SuiteClasses({A.class, B.class, C.class})
+public class UsesExternalResource {
+	public static Server myServer= new Server();
+
+	@ClassRule
+	public static ExternalResource resource= new ExternalResource() {
+		@Override
+		protected void before() throws Throwable {
+			myServer.connect();
 		};
-	}
+	
+		@Override
+		protected void after() {
+			myServer.disconnect();
+		};
+	};
+}
+```
 
 ### TestRule ###
 
diff --git a/doc/building-junit.txt b/doc/building-junit.txt
index dff42e6..325a27e 100644
--- a/doc/building-junit.txt
+++ b/doc/building-junit.txt
@@ -3,7 +3,7 @@
 - Must be manual
   - Write release notes
 - Not too tedious:
-  - Push to github (dsaff _and_ KentBeck)
+  - Push to github (junit-team)
   - Run the mvn clean install
   - If not done, update src/main/config/settings.xml in /private/.../settings.xml on CloudBees' webdav share.
   - If not done, copy GnuPG keys in to ${gpg.homedir}. See settings.xml.
@@ -95,4 +95,4 @@
         </profile>
     </profiles>
 </settings>
-===================================================================================
\ No newline at end of file
+===================================================================================
diff --git a/doc/cookbook/cookbook.htm b/doc/cookbook/cookbook.htm
deleted file mode 100644
index 2cf8eec..0000000
--- a/doc/cookbook/cookbook.htm
+++ /dev/null
@@ -1,143 +0,0 @@
-<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
-<html>
-<head>
-   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-   <meta name="GENERATOR" content="Microsoft FrontPage 4.0">
-   <meta name="Author" content="Erich Gamma">
-   <title>JUnit Cookbook</title>
-</head>
-<body>
-
-<h1>
-<font color="#33FF33">J</font><font color="#CC0000">U</font>nit Cookbook</h1>
-
-<p>
-Kent Beck, Erich Gamma</p>
-
-<hr WIDTH="100%">
-<br>Here is a short cookbook showing you the steps you can follow in writing
-and organizing your own tests using JUnit.
-<h2>
-Simple Test Case</h2>
-How do you write testing code?
-<p>The simplest way is as an expression in a debugger. You can change debug
-expressions without recompiling, and you can wait to decide what to write
-until you have seen the running objects. You can also write test expressions
-as statements which print to the standard output stream. Both styles of
-tests are limited because they require human judgment to analyze their
-results. Also, they don't compose nicely- you can only execute one debug
-expression at a time and a program with too many print statements causes
-the dreaded "Scroll Blindness".
-<p>JUnit tests do not require human judgment to interpret, and it is easy
-to run many of them at the same time. When you need to test something,
-here is what you do:
-<ol>
-<li>
-Annotate a method with @org.junit.Test
-
-<li>
-When you want to check a value, import org.junit.Assert.* statically, call <tt>assertTrue</tt>() and pass a boolean
-that is true if the test succeeds</li>
-</ol>
-For example, to test that the sum of two Moneys with the same currency
-contains a value which is the sum of the values of the two Moneys, write:
-<blockquote>
-<pre><tt>@Test public void simpleAdd() {
-&nbsp;&nbsp;&nbsp; Money m12CHF= new Money(12, &quot;CHF&quot;);&nbsp;
-&nbsp;&nbsp;&nbsp; Money m14CHF= new Money(14, &quot;CHF&quot;);&nbsp;
-&nbsp;&nbsp;&nbsp; Money expected= new Money(26, &quot;CHF&quot;);&nbsp;
-&nbsp;&nbsp;&nbsp; Money result= m12CHF.add(m14CHF);&nbsp;
-&nbsp;&nbsp;&nbsp; assertTrue(expected.equals(result));
-}</tt></pre>
-</blockquote>
-If you want to write a test similar to one you have already written, write
-a Fixture instead.
-<h2>
-Fixture</h2>
-What if you have two or more tests that operate on the same or similar
-sets of objects?
-<p>Tests need to run against the background of a known set of objects.
-This set of objects is called a test fixture. When you are writing tests
-you will often find that you spend more time writing the code to set up
-the fixture than you do in actually testing values.
-<p>To some extent, you can make writing the fixture code easier by paying
-careful attention to the constructors you write. However, a much bigger
-savings comes from sharing fixture code. Often, you will be able to use
-the same fixture for several different tests. Each case will send slightly
-different messages or parameters to the fixture and will check for different
-results.
-<p>When you have a common fixture, here is what you do:
-<ol>
-
-<li>
-Add a field for each part of the fixture</li>
-
-<li>
-Annotate a method with @org.junit.Before
-and initialize the variables in that method</li>
-
-<li>
-Annotate a method with @org.junit.After
-to release any permanent resources you allocated in setUp</li>
-</ol>
-For example, to write several test cases that want to work with different
-combinations of 12 Swiss Francs, 14 Swiss Francs, and 28 US Dollars, first
-create a fixture:
-<pre><tt>public class MoneyTest {&nbsp;
-&nbsp;&nbsp;&nbsp; private Money f12CHF;&nbsp;
-&nbsp;&nbsp;&nbsp; private Money f14CHF;&nbsp;
-&nbsp;&nbsp;&nbsp; private Money f28USD;&nbsp;
-&nbsp;&nbsp;&nbsp;&nbsp;
-&nbsp;&nbsp;&nbsp; @Before public void setUp() {&nbsp;
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f12CHF= new Money(12, &quot;CHF&quot;);&nbsp;
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f14CHF= new Money(14, &quot;CHF&quot;);&nbsp;
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f28USD= new Money(28, &quot;USD&quot;);&nbsp;
-&nbsp;&nbsp;&nbsp; }
-}</tt></pre>
-Once you have the Fixture in place, you can write as many Test Cases as
-you'd like. Add as many test methods (annotated with @Test) as you'd like.
-<h2>Running Tests</h2>
-How do you run your tests and collect their results?
-<p>Once you have tests, you'll want to run them. JUnit provides tools
-to define the suite to be run and to display its results. To run tests and see the
-results on the console, run this from a Java program:
-<blockquote>
-<pre>
-org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...);
-</pre>
-</blockquote>
-or this from the command line, with both your test class and junit on the classpath:
-<blockquote>
-<pre>
-java org.junit.runner.JUnitCore TestClass1.class [...other test classes...]
-</pre>
-</blockquote>
-
-You make your JUnit 4 test classes accessible to a TestRunner designed to work with earlier versions of JUnit,
-declare a static method <i>suite</i>
-that returns a test.
-<blockquote>
-<pre><tt>public static junit.framework.Test suite() {&nbsp;
-&nbsp;&nbsp;&nbsp; return new JUnit4TestAdapter(Example.class);&nbsp;
-}</tt></pre>
-</blockquote>
-<h2>
-Expected Exceptions</h2>
-How do you verify that code throws exceptions as expected?
-<p>Verifying that code completes normally is only part of programming. Making sure the code
-behaves as expected in exceptional situations is part of the craft of programming too. For example:
-<blockquote>
-<pre><tt>new ArrayList&lt;Object&gt;().get(0);&nbsp;
-</tt></pre>
-</blockquote>
-This code should throw an IndexOutOfBoundsException. The @Test annotation has an optional parameter "expected"
-that takes as values subclasses of Throwable. If we wanted to verify that ArrayList throws the correct exception,
-we would write:
-<blockquote>
-<pre><tt>@Test(expected= IndexOutOfBoundsException.class) public void empty() {&nbsp;
-&nbsp;&nbsp;&nbsp; new ArrayList&lt;Object&gt;().get(0);&nbsp;
-}</tt></pre>
-</blockquote>
-<hr WIDTH="100%">
-</body>
-</html>
diff --git a/doc/cookbook/logo.gif b/doc/cookbook/logo.gif
deleted file mode 100644
index d0e1547..0000000
--- a/doc/cookbook/logo.gif
+++ /dev/null
Binary files differ
diff --git a/doc/faq/faq.htm b/doc/faq/faq.htm
deleted file mode 100644
index 783557e..0000000
--- a/doc/faq/faq.htm
+++ /dev/null
@@ -1,2380 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
-<head>
-  <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
-  <title>JUnit FAQ</title>
-
-  <style type="text/css">
-
-    body {
-      font-style: normal;
-      font-weight: normal;
-      margin-left: 10pt;
-      margin-right: 10pt;
-    }
-
-    a {
-      text-decoration: none;
-    }
-
-    a:hover {
-      text-decoration: underline;
-    }
-
-    .header {
-      color: black;
-      font-size: 125%;
-      font-weight: bold;
-      background: #33ff33;
-      padding-top: 2px;
-      padding-bottom: 2px;
-      padding-left: 5px;
-      margin-top: 25px;
-    }
-
-    .code {
-      background: white;
-      border-left: 5px solid #33ff33;
-    }
-
-    .code-red {
-      background: white;
-      border-left: 5px solid #cc0000;
-    }
-
-  </style>
-
-</head>
-
-<body>
-
-<h1>
-  <font color="#33ff33">J</font><font color="#cc0000">U</font>nit FAQ
-</h1>
-<hr size="1"/>
-
-
-<!--
-
-    Summary
-
--->
-<p>
-<i>
-JUnit is a simple, open source framework to write and run repeatable
-tests. It is an instance of the xUnit architecture for unit testing
-frameworks.
-</i>
-</p>
-<hr size="1"/>
-<p>
-Edited by <a href="mailto:mike@clarkware.com">Mike Clark</a>
-(<a href="http://www.clarkware.com">http://clarkware.com</a>)
-</p>
-<p>
-Last modified on February 20, 2006
-</p>
-
-<hr/>
-
-<!-- 
-
-     Table of Contents 
-	
--->
-
-<div class="header">
-Table of Contents
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a href="#faqinfo">FAQ Info</a></b>
-    </p>
-    <ol>
-      <li><a href="#faqinfo_1">Who is responsible for this FAQ?</a></li>
-      <li><a href="#faqinfo_2">How can I contribute to this FAQ?</a></li>
-      <li><a href="#faqinfo_3">Where do I get the latest version of
-      this FAQ?</a></li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a href="#overview">Overview</a></b>
-    </p>
-    <ol>
-      <li><a href="#overview_1">What is JUnit?</a></li>
-      <li><a href="#overview_2">Where is the JUnit home page?</a></li>
-      <li><a href="#overview_3">Where are the JUnit mailing lists and
-      forums?</a></li>
-      <li><a href="#overview_4">Where is the JUnit documentation?</a></li>
-      <li><a href="#overview_5">Where can I find articles on JUnit?</a></li>
-      <li><a href="#overview_6">What's the latest news on JUnit?</a></li>
-      <li><a href="#overview_7">How is JUnit licensed?</a></li>
-      <li><a href="#overview_8">What awards has JUnit won?</a></li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a href="#started">Getting Started</a></b>
-    </p>
-    <ol>
-      <li><a href="#started_1">Where do I download JUnit?</a></li>
-      <li><a href="#started_2">How do I install JUnit?</a></li>
-      <li><a href="#started_3">How do I uninstall JUnit?</a></li>
-      <li><a href="#started_4">How do I ask questions?</a></li>
-      <li><a href="#started_5">How do I submit bugs, patches, or
-      feature requests?</a></li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a href="#tests">Writing Tests</a></b>
-    </p>
-    <ol>
-      <li><a href="#tests_1">How do I write and run a simple test?</a></li>
-      <li><a href="#tests_2">How do I use a test fixture?</a></li>
-      <li><a href="#tests_4">How do I test a method that doesn't
-      return anything?</a></li>
-      <li><a href="#tests_5">Under what conditions should I test get()
-      and set() methods?</a></li>
-      <li><a href="#tests_6">Under what conditions should I not test
-      get() and set() methods?</a></li>
-      <li><a href="#tests_7">How do I write a test that passes when an
-      expected exception is thrown?</a></li>
-      <li><a href="#tests_8">How do I write a test that fails when an
-      unexpected exception is thrown?</a></li>
-      <li><a href="#tests_10">How do I test protected methods?</a></li>
-      <li><a href="#tests_11">How do I test private methods?</a></li>
-      <li><a href="#tests_12">Why does JUnit only report the first
-      failure in a single test?</a></li>
-      <li><a href="#tests_13">In Java 1.4, 'assert' is a
-      keyword. Won't this conflict with JUnit's assert()
-      method?</a></li>
-      <li><a href="#tests_14">How do I test things that must be run in
-      a J2EE container (e.g. servlets, EJBs)?</a></li>
-      <li><a href="#tests_15">Do I need to write a test class for
-      every class I need to test?</a></li>
-      <li><a href="#tests_16">Is there a basic template I can use to
-      create a test?</a></li>
-      <li><a href="#tests_17">How do I write a test for an abstract
-      class?</a></li>
-      <li><a href="#tests_18">When are tests garbage collected?</a></li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a href="#organize">Organizing Tests</a></b>
-    </p>
-    <ol>
-      <li><a href="#organize_1">Where should I put my test files?</a></li>
-      <li><a href="#organize_3">How can I run setUp() and tearDown()
-      code once for all of my tests?</a></li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a href="#running">Running Tests</a></b>
-    </p>
-    <ol>
-      <li><a href="#running_1">What CLASSPATH settings are needed to
-      run JUnit?</a></li>
-      <li><a href="#running_2">Why do I get a NoClassDefFoundError 
-	  when trying to test JUnit or run the samples?</a>
-      </li>
-      <li><a href="#running_4">How do I run JUnit from my command window?</a>
-      </li>		
-      <li><a href="#running_5">How do I run JUnit using Ant?</a>
-      </li>		
-      <li><a href="#running_6">How do I use Ant to create HTML test reports?</a>
-      </li>				
-      <li><a href="#running_7">How do I pass command-line arguments to a test execution?</a>
-      </li>
-      <li><a href="#running_9">Why do I get a LinkageError when using 
-	  XML interfaces in my test class?</a>
-      </li>
-      <li><a href="#running_11">Why do I get the warning "AssertionFailedError: No 
-	  tests found in XXX" when I run my test?</a>
-      </li>
-      <li><a href="#running_12">Why do I see "Unknown Source" in the stack trace of
-	  a test failure, rather than the source file's line number?</a>
-      </li>
-      <li><a href="#running_15">How do I organize all test classes in a TestSuite 
-	  automatically and not use or manage a TestSuite explicitly?</a>
-      </li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a href="#best">Best Practices</a></b>
-    </p>
-    <ol>
-	<li><a href="#best_1">When should tests be written?</a></li>
-	<li><a href="#best_2">Do I have to write a test for
-	everything?</a></li>
-	<li><a href="#best_3">How simple is 'too simple to break'?</a></li>
-	<li><a href="#best_4">How often should I run my tests?</a></li>
-	<li><a href="#best_5">What do I do when a defect is reported?</a></li>
-	<li><a href="#best_6">Why not just use System.out.println()?</a></li>
-	<li><a href="#best_7">Why not just use a debugger?</a></li>
-      </ol>
-    </li>
-    <li>
-      <p>
-	<b><a href="#misc">Miscellaneous</a></b>
-      </p>
-      <ol>
-	<li><a href="#misc_1">How do I integrate JUnit with my IDE?</a></li>
-	<li><a href="#misc_2">How do I launch a debugger when a test
-	fails?</a></li>
-	<li><a href="#misc_3">Where can I find unit testing frameworks
-	similar to JUnit for other languages?</a></li>
-      </ol>
-    </li>
-  </ol>
-  
-<!--
-
-    FAQ Info
-
--->
-<div class="header">
-<a name="faqinfo">FAQ Info</a>
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a name="faqinfo_1">Who is responsible for this FAQ?</a></b>
-    </p>
-    <p>
-      The current version of this FAQ is maintained
-      by <a href="mailto:mike@clarkware.com">Mike Clark</a>.
-    </p>
-    <p>
-      Most of the wisdom contained in this FAQ comes from the
-      collective insights and hard-won experiences of the many good
-      folks who participate on the JUnit mailing list and the JUnit
-      community at large.
-    </p>
-    <p>
-      If you see your genius represented anywhere in this FAQ without
-      due credit to you, please send me an email and I'll make things
-      right.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="faqinfo_2">How can I contribute to this FAQ?</a></b>
-    </p>
-    <p>
-      Your contributions to this FAQ are greatly appreciated!  The
-      JUnit community thanks you in advance.
-    </p>
-    <p>
-      To contribute to this FAQ, simply write a JUnit-related question
-      and answer, then send the unformatted text
-      to <a href="mailto:mike@clarkware.com">Mike Clark</a>.
-      Corrections to this FAQ are always appreciated, as well.
-    </p>
-    <p>
-      No reasonable contribution will be denied.  Your name will
-      always appear along with any contribution you make.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="faqinfo_3">Where do I get the latest version of this
-      FAQ?</a></b>
-    </p>
-    <p>
-      The master copy of this FAQ is available
-      at <a
-      href="http://junit.sourceforge.net/doc/faq/faq.htm">http://junit.sourceforge.net/doc/faq/faq.htm</a>.
-    </p>
-    <p>
-      The JUnit distribution also includes this FAQ in
-      the <code>doc</code> directory.
-    </p>
-  </li>
-  
-</ol>
-
-
-<!--
-
-    Overview
-
--->
-<div class="header">
-<a name="overview">Overview</a>
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a name="overview_1">What is JUnit?</a></b>
-    </p>    
-    <p>
-      JUnit is a simple, open source framework to write and run
-      repeatable tests. It is an instance of the xUnit architecture
-      for unit testing frameworks.  JUnit features include:
-    </p>
-    <ul>
-      <li>Assertions for testing expected results</li>
-      <li>Test fixtures for sharing common test data</li>
-      <li>Test runners for running tests</li>
-    </ul>
-    <p>
-      JUnit was originally written by Erich Gamma and Kent Beck.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="overview_2">Where is the JUnit home page?</a></b>
-    </p>
-    <p>
-      The official JUnit home page is <a
-      href="http://junit.org">http://junit.org</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="overview_3">Where are the JUnit mailing lists and
-	  forums?</a></b>
-    </p>
-    <p>
-      There are 3 mailing lists dedicated to everything JUnit:
-    </p>
-    <ul>
-      <li>
-	<a href="http://groups.yahoo.com/group/junit/">JUnit user
-	list</a>.  (Search it for answers to frequently asked
-	questions not included here.)
-      </li>
-      <li>
-	<a
-	href="http://lists.sourceforge.net/lists/listinfo/junit-announce">JUnit
-	announcements</a>
-      </li>
-      <li>
-	<a
-	href="http://lists.sourceforge.net/lists/listinfo/junit-devel">JUnit
-	developer list</a>
-      </li>
-    </ul>
-  </li>
-  <li>
-    <p>
-      <b><a name="overview_4">Where is the JUnit
-      documentation?</a></b>
-    </p>
-    <p>
-      The following documents are included in the JUnit distribution
-      in the <code>doc</code> directory:
-    </p>
-    <ul>
-      <li>
-	<a
-	href="http://junit.sourceforge.net/doc/testinfected/testing.htm">JUnit
-	Test Infected: Programmers Love Writing Tests</a>
-      </li> 
-      <li>
-	<a
-	href="http://junit.sourceforge.net/doc/cookbook/cookbook.htm">JUnit
-	  Cookbook</a>
-      </li>
-      <li>
-	<a
-	href="http://junit.sourceforge.net/doc/cookstour/cookstour.htm">JUnit
-	- A Cook's Tour</a>
-      </li>
-      <li>
-	<a href="http://junit.sourceforge.net/doc/faq/faq.htm">JUnit
-	FAQ</a>
-      </li>
-    </ul>
-  </li>
-  <li>
-    <p>
-      <b><a name="overview_5">Where can I find articles on
-      JUnit?</a></b>
-    </p>
-    <p>
-      The JUnit home page maintains a list
-      of <a href="http://www.junit.org/news/article/index.htm">JUnit
-      articles</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="overview_6">What's the latest news on JUnit?</a></b>
-    </p>
-    <p>
-      The JUnit home page publishes
-      the <a href="http://www.junit.org/news/index.htm">latest JUnit
-      news</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="overview_7">How is JUnit licensed?</a></b>
-    </p>
-    <p>
-      JUnit is <a href="http://www.opensource.org/">Open Source
-      Software</a>, released
-      under <a
-      href="http://oss.software.ibm.com/developerworks/oss/license-cpl.html">IBM's
-      Common Public License Version 0.5</a> and hosted
-      on <a
-      href="http://sourceforge.net/projects/junit/">SourceForge</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="overview_8">What awards has JUnit won?</a></b>
-    </p>
-    <ul>
-      <li>
-	<p> <a
-	href="http://www.javaworld.com/javaworld/jw-03-2002/jw-0326-awards.html">2002
-	JavaWorld Editors' Choice Awards (ECA)</a>
-	</p>
-	<p>
-	  Best Java Performance Monitoring/Testing Tool
-	</p>
-      </li>
-      <li>
-	<p>
-	  <a
-	  href="http://www.javaworld.com/javaworld/jw-06-2001/j1-01-awards.html">2001
-	  JavaWorld Editors' Choice Awards (ECA)</a>
-	</p>
-	<p>
-	  Best Java Performance Monitoring/Testing Tool
-	</p>
-      </li>
-    </ul>
-  </li>
-</ol>
-
-
-<!--
-
-    Getting Started
-
--->
-<div class="header">
-<a name="started">Getting Started</a>
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a name="started_1">Where do I download JUnit?</a></b>
-    </p>
-    <p>
-      The latest version of JUnit is available
-      on <a
-      href="http://sourceforge.net/project/showfiles.php?group_id=15278">SourceForge</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="started_2">How do I install JUnit?</a></b>
-    </p>
-    <ol>
-      <li>
-	<p>
-	  First, <a
-		    href="http://sourceforge.net/project/showfiles.php?group_id=15278">download</a>
-	  the
-	  latest version of JUnit, referred to below
-	  as <code>junit.zip</code>. 
-	</p>
-      </li>
-      <li>
-	<p>
-	  Then install JUnit on your platform of choice:
-	</p>
-	<p>
-	  <u>Windows</u>
-	</p>
-	<p>
-	  To install JUnit on Windows, follow these steps:
-	</p>
-	<ol>
-	  <li>
-	    <p>
-	      Unzip the <code>junit.zip</code> distribution file to
-	      a directory referred to as <code>%JUNIT_HOME%</code>.
-	    </p>
-	  </li>
-	  <li>Add JUnit to the classpath:
-	    <p>
-	      <code>set CLASSPATH=%CLASSPATH%;%JUNIT_HOME%\junit.jar</code>
-	    </p>
-	  </li>
-	</ol>
-	<p>
-	  <u>Unix (bash)</u>
-	</p>
-	<p>
-	  To install JUnit on Unix, follow these steps:
-	</p>
-	<ol>
-	  <li>
-	    <p>
-	      Unzip the <code>junit.zip</code> distribution file to
-	      a directory referred to as <code>$JUNIT_HOME</code>.
-	    </p>	
-	  </li>
-	  <li>
-	    <p>
-	      Add JUnit to the classpath:
-	    </p>
-	    <p>
-	      <code>export CLASSPATH=$CLASSPATH:$JUNIT_HOME/junit.jar</code>
-	    </p>
-	  </li>
-	</ol>
-      </li>
-      <li>
-	<p>
-	  <i>(Optional)</i> Unzip
-	  the <code>$JUNIT_HOME/src.jar</code> file.
-	</p>
-      </li>
-      <li>
-	<p>
-	  Test the installation by running the sample tests
-	  distributed with JUnit.  Note that the sample tests are
-	  located in the installation directory directly, not
-	  the <code>junit.jar</code> file.  Therefore, make sure that
-	  the JUnit installation directory is on your CLASSPATH.  Then
-	  simply type:
-	</p>
-	<div>
-	  <blockquote><code>
-	  java org.junit.runner.JUnitCore org.junit.tests.AllTests 
-	  </code></blockquote>
-	</div>
-	<p>
-	  All the tests should pass with an "OK" message.
-	</p>
-	<p>
-	  <i> 
-	    If the tests don't pass, verify
-	    that <code>junit.jar</code> is in the CLASSPATH.
-	  </i>
-	</p>
-      </li>
-      <li>
-	<p>
-	  Finally, <a href="#overview_4">read</a> the documentation.
-	</p>
-      </li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a name="started_3">How do I uninstall JUnit?</a></b>
-    </p>
-    <ol>
-      <li>
-	<p> 
-	  Delete the directory structure where you unzipped the JUnit
-	  distribution.
-	</p>
-      </li>
-      <li>
-	<p>
-	  Remove <code>junit.jar</code> from the CLASSPATH.
-	</p>
-      </li>
-    </ol>
-    <p>
-      JUnit does not modify the registry so simply removing all the
-      files will fully uninstall it.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="started_4">How do I ask questions?</a></b>
-    </p>
-    <p>
-      Questions that are not answered in
-      the <a
-      href="http://junit.sourceforge.net/doc/faq/faq.htm">FAQ</a> or
-      in the <a href="#overview_4">documentation</a> should be posted
-      to
-      the <a
-      href="http://www.jguru.com/forums/home.jsp?topic=JUnit">jGuru
-	discussion forum</a> or the <a
-	href="http://groups.yahoo.com/group/junit/">JUnit user mailing
-	list</a>.
-    </p>
-    <p>
-      Please stick to technical issues on the discussion forum and
-      mailing lists. Keep in mind that these are public, so
-      do <b>not</b> include any confidental information in your
-      questions!
-    </p>
-    <p>
-      You should also
-      read <a
-      href="http://www.catb.org/~esr/faqs/smart-questions.html">"How
-      to ask questions the smart way"</a> by Eric Raymond before
-      participating in the discussion forum and mailing lists.
-    </p>
-    <p>
-      <i> 
-	NOTE: <br/> Please do NOT submit bugs, patches, or feature
-	requests to the discussion forum or mailing lists.  <br/>
-	Refer instead to <a href="#started_5">"How do I submit bugs,
-	patches, or feature requests?"</a>.
-      </i>
-    </p>
-  </li>
-  <li>
-    <p>
-       <b><a name="started_5">How do I submit bugs, patches, or
-       feature requests?</a></b>
-    </p>
-    <p>
-      JUnit celebrates programmers testing their own software. In this
-      spirit, bugs, patches, and feature requests that include JUnit
-      tests have a better chance of being addressed than those
-      without.
-    </p>
-    <p>
-      JUnit is hosted
-      on <a
-      href="http://sourceforge.net/projects/junit">SourceForge</a>.
-      Please use the tools provided by SourceForge for your
-      submissions.
-    </p>
-  </li>
-</ol>
-
-
-<!--
-
-    Writing Tests
-
--->
-<div class="header">
-<a name="tests">Writing Tests</a>
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a name="tests_1"></a>How do I write and run a simple test?</b>
-    </p>
-    <ol>
-      <li>
-	<p>
-	  Create a class:
-	</p>
-	<div class="code">
-	  <pre><code>
-	      
-  package junitfaq;
-	      
-  import org.junit.*;
-  import static org.junit.Assert.*;
-
-  import java.util.*;
-  
-  public class SimpleTest {
-	  </code></pre>
-	</div>      
-      </li>
-      <li>
-	<p>
-	  Write a test method (annotated with <code>@Test</code>) that
-	  asserts expected results on the object under test:
-	</p>
-	<div class="code">
-	  <pre><code>
-
-    @Test
-    public void testEmptyCollection() {
-        Collection collection = new ArrayList();
-        assertTrue(collection.isEmpty());
-    }
-	  </code></pre>
-	</div>
-      </li>
-      <li>
-	<p>
-	  If you are running your JUnit 4 tests with a JUnit 3.x runner,
-	  write a <code>suite()</code> method that uses the 
-	  <code>JUnit4TestAdapter</code> class to create a suite
-	  containing all of your test methods:
-	</p>
-	<div class="code">
-	  <pre><code>
-
-    public static junit.framework.Test suite() {
-        return new junit.framework.JUnit4TestAdapter(SimpleTest.class);
-    }
-	  </code></pre>
-	</div>
-      </li>
-      <li>
-	<p>
-	  Although writing a <code>main()</code> method to run the
-	  test is much less important with the advent of IDE runners,
-	  it's still possible:
-	</p>
-	<div class="code">
-	  <pre><code>
-
-    public static void main(String args[]) {
-      org.junit.runner.JUnitCore.main("junitfaq.SimpleTest");
-    }
-  }
-	  </code></pre>
-	</div>
-      </li>
-      <li>
-	<p>
-	  Run the test:
-	</p>
-	<ul>
-	  <li>
-	    <p>
-	      To run the test from the console, type:
-	    </p>
-	    <div>
-	      <blockquote><code>
-java org.junit.runner.JUnitCore junitfaq.SimpleTest
-	      </code></blockquote>
-	    </div>
-	  </li>
-	  <li>
-	    <p>
-	      To run the test with the test runner used
-	      in <code>main()</code>, type:
-	    </p>
-	    <div>
-	      <blockquote><code>
-java junitfaq.SimpleTest 
-	      </code></blockquote>
-	    </div>
-	  </li>
-	</ul>
-	<p>
-	  The passing test results in the following textual output:
-	</p>
-	<div>
-	  <blockquote>
-	    <pre><code>
-		.
-Time: 0
-
-OK (1 tests)
-	    </code></pre>
-	  </blockquote>
-	</div>
-      </li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_2"></a>How do I use a test fixture?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Jeff Nielsen)</i>
-    </p>
-    <p>
-      A test fixture is useful if you have two or more tests for a
-      common set of objects.  Using a test fixture avoids duplicating
-      the code necessary to initialize (and cleanup) the common
-      objects.
-    </p>
-    <p>
-      Tests can use the objects (variables) in a test fixture, with
-      each test invoking different methods on objects in the fixture
-      and asserting different expected results.  Each test runs in its
-      own test fixture to isolate tests from the changes made by other
-      tests.  That is, <em>tests don't share the state of objects in
-      the test fixture</em>.  Because the tests are isolated, they can
-      be run in any order.
-    </p>
-    <p>
-      To create a test fixture, declare instance variables for the
-      common objects.  Initialize these objects in a <code>public
-      void</code> method annotated with <code>@Before</code>.  The
-      JUnit framework automatically invokes any <code>@Before</code>
-      methods before each test is run.
-    </p>
-    <p>
-      The following example shows a test fixture with a common
-      <code>Collection</code> object.
-    </p>
-    <div class="code">
-      <pre><code>
-    package junitfaq;
-
-    import org.junit.*;
-    import static org.junit.Assert.*;
-    import java.util.*;
-
-    public class SimpleTest {
-
-        private Collection&lt;Object&gt; collection;
-
-        @Before
-        public void setUp() {
-            collection = new ArrayList&lt;Object&gt;();
-        }
-
-        @Test
-        public void testEmptyCollection() {
-            assertTrue(collection.isEmpty());
-        }
-
-
-        @Test
-        public void testOneItemCollection() {
-            collection.add("itemA");
-            assertEquals(1, collection.size());
-        }
-    }
-      </code></pre>
-    </div>
-
-    <p>
-      Given this test, the methods might execute in the following
-      order:
-    </p>
-      <blockquote>
-        <pre><code>setUp()
-testEmptyCollection()
-setUp()
-testOneItemCollection()</code></pre>
-      </blockquote>
-    <p>
-      The ordering of test-method invocations is not guaranteed, so
-      <code>testOneItemCollection()</code> might be executed before
-      <code>testEmptyCollection()</code>.  But it doesn't matter,
-      because each method gets its own instance of the
-      <code>collection</code>.
-    </p>
-
-    <p>
-      Although JUnit provides a new instance of the fixture objects
-      for each test method, if you allocate any <em>external</em>
-      resources in a <code>@Before</code> method, you should release
-      them after the test runs by annotating a method with
-      <code>@After</code>.  The JUnit framework automatically invokes
-      any <code>@After</code> methods after each test is run.  For
-      example:
-    </p>
-
-    <div class="code">
-      <pre><code>
-    package junitfaq;
-
-    import org.junit.*;
-    import static org.junit.Assert.*;
-    import java.io.*;
-
-    public class OutputTest {
-
-        private File output;
-
-        @Before
-        public void createOutputFile() {
-            output = new File(...);
-        }
-
-        @After
-        public void deleteOutputFile() {
-            output.delete();
-        }
-
-        @Test
-        public void testSomethingWithFile() {
-            ...
-        }
-    }
-      </code></pre>
-    </div>
-    <p>
-      With this test, the methods will execute in the following order:
-    </p>
-    <div>
-      <blockquote>
-        <pre><code>
-createOutputFile()
-testSomethingWithFile()
-deleteOutputFile()
-        </code></pre>
-      </blockquote>
-    </div>
-    
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_4"></a>How do I test a method that doesn't
-      return anything?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Dave Astels)</i>
-    </p>
-    <p>
-      Often if a method doesn't return a value, it will have some side
-      effect. Actually, if it doesn't return a value AND doesn't have
-      a side effect, it isn't doing anything.
-    </p>
-    <p>
-      There may be a way to verify that the side effect actually
-      occurred as expected. For example, consider
-      the <code>add()</code> method in the Collection classes. There
-      are ways of verifying that the side effect happened (i.e. the
-      object was added). You can check the size and assert that it is
-      what is expected:
-    </p>
-    <div class="code">
-      <pre><code>
-
-    @Test
-    public void testCollectionAdd() {
-        Collection collection = new ArrayList();
-        assertEquals(0, collection.size());
-        collection.add("itemA");
-        assertEquals(1, collection.size());
-        collection.add("itemB");
-        assertEquals(2, collection.size());
-    }
-      </code></pre>
-    </div>
-    <p>
-      Another approach is to make use of <a
-      href="http://www.mockobjects.com">MockObjects</a>.
-    </p>
-    <p>
-      A related issue is to design for testing. For example, if you
-      have a method that is meant to output to a file, don't pass in a
-      filename, or even a <code>FileWriter</code>. Instead, pass in
-      a <code>Writer</code>. That way you can pass in
-      a <code>StringWriter</code> to capture the output for testing
-      purposes. Then you can add a method
-      (e.g. <code>writeToFileNamed(String filename)</code>) to
-      encapsulate the <code>FileWriter</code> creation.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_5"></a>Under what conditions should I test
-      get() and set() methods?</b>
-    </p>
-    <p>
-      Unit tests are intended to alleviate fear that something might
-      break.  If you think a <code>get()</code> or <code>set()</code>
-      method could reasonably break, or has in fact contributed to a
-      defect, then by all means write a test.
-    </p>
-    <p>
-      In short, test until you're confident.  What you choose to test
-      is subjective, based on your experiences and confidence level.
-      Remember to be practical and maximize your testing investment.
-    </p>
-    <p>  
-      Refer also to <a href="#best_3">"How simple is 'too simple to
-      break'?"</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_6"></a>Under what conditions should I not test
-      get() and set() methods?</b>
-    </p>
-    <p>
-      <i>(Submitted by: J. B. Rainsberger)</i>
-    </p>
-    <p>
-      Most of the time, get/set methods just can't break, and if they
-      can't break, then why test them? While it is usually better to
-      test more, there is a definite curve of diminishing returns on
-      test effort versus "code coverage".  Remember the maxim: "Test
-      until fear turns to boredom."
-    </p>
-    <p>
-      Assume that the <code>getX()</code> method only does "return x;"
-      and that the <code>setX()</code> method only does "this.x =
-      x;". If you write this test:
-    </p>
-    <div>
-      <blockquote><pre>
-@Test
-public void testGetSetX() {
-    setX(23);
-    assertEquals(23, getX());
-}
-      </pre></blockquote>
-    </div>
-    <p>
-      then you are testing the equivalent of the following:
-    </p>
-    <div>
-      <blockquote><pre>
-@Test
-public void testGetSetX() {
-    x = 23;
-    assertEquals(23, x);
-}
-</pre></blockquote>
-    </div>
-    <p>
-      or, if you prefer,
-    </p>
-    <div>
-      <blockquote><pre>
-@Test
-public void testGetSetX() {
-    assertEquals(23, 23);
-}
-</pre></blockquote>
-    </div>
-    <p>
-      At this point, you are testing the Java compiler, or possibly
-      the interpreter, and not your component or application. There is
-      generally no need for you to do Java's testing for them.
-    </p>
-    <p>
-      If you are concerned about whether a property has already been
-      set at the point you wish to call <code>getX()</code>, then you
-      want to test the constructor, and not the <code>getX()</code>
-      method. This kind of test is especially useful if you have
-      multiple constructors:
-    </p>
-    <div>
-      <blockquote><pre>
-@Test
-public void testCreate() {
-    assertEquals(23, new MyClass(23).getX());
-}
-      </pre></blockquote>
-    </div>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_7"></a>How do I write a test that passes when
-      an expected exception is thrown?</b>
-    </p>
-    <p>
-      Add the optional <code>expected</code> attribute to
-      the <code>@Test</code> annotation.  The following is an example
-      test that passes when the
-      expected <code>IndexOutOfBoundsException</code> is raised:
-    </p>
-    <div class="code">
-      <pre><code>
-
-    @Test(expected=IndexOutOfBoundsException.class)
-    public void testIndexOutOfBoundsException() {
-        ArrayList emptyList = new ArrayList();
-	Object o = emptyList.get(0);
-    }
-      </code></pre>
-    </div>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_8"></a>How do I write a test that fails when
-      an unexpected exception is thrown?</b>
-    </p>
-    <p>
-      Declare the exception in the <code>throws</code> clause of the
-      test method and don't catch the exception within the test
-      method.  Uncaught exceptions will cause the test to fail with an
-      error.
-    </p>
-    <p>
-      The following is an example test that fails when
-      the <code>IndexOutOfBoundsException</code> is raised:
-    </p>
-    <div class="code-red">
-      <pre><code>
-
-    @Test
-    public void testIndexOutOfBoundsExceptionNotRaised() 
-        throws IndexOutOfBoundsException {
-    
-        ArrayList emptyList = new ArrayList();
-        Object o = emptyList.get(0);
-    }
-      </code></pre>
-    </div>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_10"></a>How do I test protected methods?</b>
-    </p>
-    <p>
-      Place your tests in the same package as the classes under test.
-    </p>
-    <p>
-      Refer to <a href="#organize_1">"Where should I put my test
-      files?"</a> for examples of how to organize tests for protected
-      method access.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_11"></a>How do I test private methods?</b>
-    </p>
-    <p>
-      Testing private methods may be an indication that those methods
-      should be moved into another class to promote reusability.
-    </p>
-    <p>
-      But if you must...
-    </p>
-    <p>
-      If you are using JDK 1.3 or higher, you can use reflection to
-      subvert the access control mechanism with the aid of
-      the <a
-      href="http://sourceforge.net/projects/privaccessor/">PrivilegedAccessor</a>.
-      For details on how to use it,
-      read <a
-      href="http://www.onjava.com/pub/a/onjava/2003/11/12/reflection.html">this
-      article</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_12"></a>Why does JUnit only report the first
-      failure in a single test?</b>
-    </p>
-    <p>
-      <i>(Submitted by: J. B. Rainsberger)</i>
-    </p>
-    <p>
-      Reporting multiple failures in a single test is generally a sign
-      that the test does too much, compared to what a unit test ought
-      to do. Usually this means either that the test is really a
-      functional/acceptance/customer test or, if it is a unit test,
-      then it is too big a unit test.
-    </p>
-    <p>
-      JUnit is designed to work best with a number of small tests. It
-      executes each test within a separate instance of the test
-      class. It reports failure on each test. Shared setup code is
-      most natural when sharing between tests. This is a design
-      decision that permeates JUnit, and when you decide to report
-      multiple failures per test, you begin to fight against
-      JUnit. This is not recommended.
-    </p>
-    <p>
-      Long tests are a design smell and indicate the likelihood of a
-      design problem. Kent Beck is fond of saying in this case that
-      "there is an opportunity to learn something about your design."
-      We would like to see a pattern language develop around these
-      problems, but it has not yet been written down.
-    </p>
-    <p>
-      Finally, note that a single test with multiple assertions is
-      isomorphic to a test case with multiple tests:
-    </p>
-    <p>
-      One test method, three assertions:
-    </p>
-    <div>
-      <blockquote><pre><code>
-public class MyTestCase {
-    @Test
-    public void testSomething() {
-        // Set up for the test, manipulating local variables
-        assertTrue(condition1);
-        assertTrue(condition2);
-        assertTrue(condition3);
-    }
-}
-      </code></pre></blockquote>
-    </div>
-    <p>
-      Three test methods, one assertion each:
-    </p>
-    <div>
-      <blockquote><pre><code>
-public class MyTestCase {
-    // Local variables become instance variables
-
-    @Before
-    public void setUp() {
-        // Set up for the test, manipulating instance variables
-    }
-    
-    @Test
-    public void testCondition1() {
-        assertTrue(condition1);
-    }
-
-    @Test
-    public void testCondition2() {
-        assertTrue(condition2);
-    }
-
-    @Test
-    public void testCondition3() {
-        assertTrue(condition3);
-    }
-}
-      </code></pre></blockquote>
-    </div>
-    <p>
-      The resulting tests use JUnit's natural execution and reporting
-      mechanism and, failure in one test does not affect the execution
-      of the other tests.  You generally want exactly one test to fail
-      for any given bug, if you can manage it.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_13"></a>In Java 1.4, <code>assert</code> is a
-	keyword. Won't this conflict
-	with JUnit's <code>assert()</code> method?</b>
-    </p>
-    <p>
-      JUnit 3.7 deprecated <code>assert()</code> and replaced it
-      with <code>assertTrue()</code>, which works exactly the same
-      way.
-    </p>
-    <p>
-      JUnit 4 is compatible with the <code>assert</code> keyword.  If
-      you run with the <code>-ea</code> JVM switch, assertions that
-      fail will be reported by JUnit.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_14"></a>How do I test things that must be run
-      in a J2EE container (e.g. servlets, EJBs)?</b>
-    </p>
-    <p>
-      Refactoring J2EE components to delegate functionality to other
-      objects that don't have to be run in a J2EE container will
-      improve the design and testability of the software.
-    </p>
-    <p>
-      <a href="http://jakarta.apache.org/cactus/index.html">Cactus</a>
-      is an open source JUnit extension that can be used to test J2EE
-      components in their natural environment.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_15"></a>Do I need to write
-      a test class for every class I need to
-      test?</b>
-    </p>
-    <p>
-      <i>(Submitted by: J. B. Rainsberger)</i>
-    </p>
-    <p>
-      No. It is a convention to start with one test
-      class per class under test, but it is not necessary.
-    </p>
-    <p>
-      Test classes only provide a way to organize tests, nothing more.
-      Generally you will start with one test class per class under
-      test, but then you may find that a small group of tests belong
-      together with their own common test fixture.[1] In this case,
-      you may move those tests to a new test class.  This is a simple
-      object-oriented refactoring: separating responsibilities of an
-      object that does too much.
-    </p>
-    <p>
-      Another point to consider is that the <code>TestSuite</code> is
-      the smallest execution unit in JUnit: you cannot execute
-      anything smaller than a TestSuite at one time without changing
-      source code. In this case, you probably do not want to put tests
-      in the same test class unless they somehow "belong together".
-      If you have two groups of tests that you think you'd like to
-      execute separately from one another, it is wise to place them in
-      separate test classes.
-    </p>
-    <p>
-      <i>
-	[1] A test fixture is a common set of test data and
-	collaborating objects shared by many tests. Generally they are
-	implemented as instance variables in the test class.
-      </i>
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_16"></a>Is there a basic template I can use to
-      create a test?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Eric Armstrong)</i>
-    </p>
-    <p>
-      The following templates are a good starting point.  Copy/paste
-      and edit these templates to suit your coding style.
-    </p>
-    <p>
-      SampleTest is a basic test template:
-    </p>
-    <div>
-      <blockquote><pre><code>
-import org.junit.*;
-import static org.junit.Assert.*;
-
-public class SampleTest {
-
-    private java.util.List emptyList;
-
-    /**
-     * Sets up the test fixture. 
-     * (Called before every test case method.)
-     */
-    @Before
-    public void setUp() {
-        emptyList = new java.util.ArrayList();
-    }
-
-    /**
-     * Tears down the test fixture. 
-     * (Called after every test case method.)
-     */
-    @After
-    public void tearDown() {
-        emptyList = null;
-    }
-    
-    @Test
-    public void testSomeBehavior() {
-        assertEquals("Empty list should have 0 elements", 0, emptyList.size());
-    }
-
-    @Test(expected=IndexOutOfBoundsException.class)
-    public void testForException() {
-        Object o = emptyList.get(0);
-    }
-}
-      </code></pre></blockquote>
-    </div>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_17"></a>How do I write a test for an abstract
-      class?</b>
-    </p>
-    <p>
-      Refer to <a
-      href="http://c2.com/cgi/wiki?AbstractTestCases">http://c2.com/cgi/wiki?AbstractTestCases</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="tests_18"></a>When are tests garbage collected?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Timothy Wall and Kent Beck)</i>
-    </p>
-    <p>
-      By design, the tree of Test instances is built in one pass, then
-      the tests are executed in a second pass.  The test runner holds
-      strong references to all Test instances for the duration of the
-      test execution.  This means that for a very long test run with
-      many Test instances, none of the tests may be garbage collected
-      until the end of the entire test run.
-    </p>
-    <p>
-      Therefore, if you allocate external or limited resources in a
-      test, you are responsible for freeing those resources.
-      Explicitly setting an object to <code>null</code> in
-      the <code>tearDown()</code> method, for example, allows it to be
-      garbage collected before the end of the entire test run.
-    </p>
-  </li>
-</ol>
-
-
-<!--
-
-    Organizing Tests
-
--->
-<div class="header">
-<a name="organize">Organizing Tests</a>
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a name="organize_1"></a>Where should I put my test files?</b>
-    </p>
-    <p>
-      You can place your tests in the same package and directory as
-      the classes under test.
-    </p>
-    <p>
-      For example:
-    </p>
-    <div>
-      <blockquote><pre>
-src
-   com
-      xyz
-         SomeClass.java
-         SomeClassTest.java	 
-      </pre></blockquote>
-    </div>
-    <p> 
-      While adequate for small projects, many developers feel that
-      this approach clutters the source directory, and makes it hard
-      to package up client deliverables without also including
-      unwanted test code, or writing unnecessarily complex packaging
-      tasks.
-    </p>
-    <p>
-      An arguably better way is to place the tests in a separate
-      parallel directory structure with package alignment.
-    </p>
-    <p>
-      For example:
-    </p>
-    <div>
-      <blockquote><pre>
-src
-   com
-      xyz
-         SomeClass.java
-test
-   com
-      xyz
-         SomeClassTest.java	 
-      </pre></blockquote>
-    </div>
-    <p>
-      These approaches allow the tests to access to all the public and
-      package visible methods of the classes under test.
-    </p>
-    <p>
-      Some developers have argued in favor of putting the tests in a
-      sub-package of the classes under test (e.g. com.xyz.test). The
-      author of this FAQ sees no clear advantage to adopting this
-      approach and believes that said developers also put their curly
-      braces on the wrong line.  :-)
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="organize_3"></a>How can I run setUp() and tearDown()
-      code once for all of my tests?</b>
-    </p>
-    <p>
-      The desire to do this is usually a symptom of excessive coupling
-      in your design.  If two or more tests must share the same test
-      fixture state, then the tests may be trying to tell you that the
-      classes under test have some undesirable dependencies.
-    </p>
-    <p>
-      Refactoring the design to further decouple the classes under
-      test and eliminate code duplication is usually a better
-      investment than setting up a shared test fixture.
-    </p>
-    <p>
-      But if you must...
-    </p>
-    <p>
-      You can add a <code>@BeforeClass</code> annotation to a method
-      to be run before all the tests in a class, and
-      a <code>@AfterClass</code> annotation to a method to be run
-      after all the tests in a class.  Here's an example:
-    </p>
-    <div class="code">
-      <pre><code>
-
-    package junitfaq;
-
-    import org.junit.*;
-    import static org.junit.Assert.*;
-    import java.util.*;
-    
-    public class SimpleTest {
-    
-        private Collection collection;
-	
-        @BeforeClass
-        public static void oneTimeSetUp() {
-            // one-time initialization code        
-        }
-
-        @AfterClass
-        public static void oneTimeTearDown() {
-            // one-time cleanup code
-        }
-
-        @Before
-        public void setUp() {
-            collection = new ArrayList();
-        }
-	
-        @After
-        public void tearDown() {
-            collection.clear();
-        }
-
-        @Test
-        public void testEmptyCollection() {
-            assertTrue(collection.isEmpty());
-        }
-	
-        @Test
-        public void testOneItemCollection() {
-            collection.add("itemA");
-            assertEquals(1, collection.size());
-        }
-    }
-      </code></pre>
-    </div>
-    <p>
-      Given this test, the methods will execute in the following
-      order:
-    </p>
-    <div>
-      <blockquote>
-	<pre><code>
-oneTimeSetUp()
-setUp()
-testEmptyCollection()
-tearDown()
-setUp()
-testOneItemCollection()
-tearDown()
-oneTimeTearDown()
-	</code></pre>
-      </blockquote>
-    </div>
-
-  </li>
-</ol>
-
-
-<!--
-
-    Running Tests
-
--->
-<div class="header">
-<a name="running">Running Tests</a>
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a name="running_1"></a>What CLASSPATH settings are needed to
-      run JUnit?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Eric Armstrong)</i>
-    </p>
-    <p>
-      To run your JUnit tests, you'll need the following elemements in
-      your CLASSPATH:
-    </p>
-    <ul>
-      <li>JUnit class files</li>
-      <li>Your class files, including your JUnit test classes</li>
-      <li>Libraries your class files depend on</li>
-    </ul>
-    <p>
-      If attempting to run your tests results in
-      a <code>NoClassDefFoundError</code>, then something is missing
-      from your CLASSPATH.
-    </p>
-    <p>
-      <u>Windows Example:</u>
-    </p>
-    <p>
-      <code>set
-      CLASSPATH=%JUNIT_HOME%\junit.jar;c:\myproject\classes;c:\myproject\lib\something.jar</code>
-    </p>
-    <p>
-      <u>Unix (bash) Example:</u>
-    </p>
-    <p>
-      <code>export CLASSPATH=$JUNIT_HOME/junit.jar:/myproject/classes:/myproject/lib/something.jar</code>
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="running_2"></a>Why do I get
-	a <code>NoClassDefFoundError</code> when trying to test JUnit
-	or run the samples?</b>
-    </p>
-    <p>
-      <i>(Submitted by: J.B. Rainsberger and Jason Rogers)</i>
-    </p>
-    <p>
-      Most likely your CLASSPATH doesn't include the JUnit
-      installation directory.
-    </p>
-    <p>
-      Refer to <a href="#running_1">"What CLASSPATH settings are
-      needed to run JUnit?"</a> for more guidance.
-    </p>
-    <p>
-      Also consider running <a
-			       href="http://www.clarkware.com/software/WhichJUnit.zip">WhichJunit</a>
-      to print the absolute location of the JUnit class files required
-      to run and test JUnit and its samples.
-    </p>
-    <p>
-      If the CLASSPATH seems mysterious, read <a
-      href="http://java.sun.com/j2se/1.4/docs/tooldocs/findingclasses.html">this</a>!
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="running_4"></a>How do I run JUnit from my command window?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Eric Armstrong)</i>
-    </p>
-    <ol>
-      <li>
-	<p>
-	  <a href="#running_1">Set your CLASSPATH</a>
-	</p>
-      </li>
-      <li>
-	<p>
-	  Invoke the runner:
-	</p>
-	<p>
-	  <code>
-	    java org.junit.runner.JUnitCore &lt;test class name&gt; 
-	  </code>
-	</p>
-      </li>
-    </ol>
-  </li>
-  <li>
-    <p>
-      <b><a name="running_5"></a>How do I run JUnit using Ant?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Eric Armstrong)</i>
-    </p>
-    <ol>
-      <li>
-	<p>
-	  Define any necessary Ant properties:
-	</p>
-	<div>
-	  <pre><code>
-&lt;property name="src" value="./src" /&gt;
-&lt;property name="lib" value="./lib" /&gt;
-&lt;property name="classes" value="./classes" /&gt;
-&lt;property name="test.class.name" value="com.xyz.MyTestSuite" /&gt;
-	  </code></pre>
-	</div>
-      </li>
-      <li>
-	<p>
-	  Set up the CLASSPATH to be used by JUnit:
-	</p>
-	<div>
-	  <pre><code>
-&lt;path id="test.classpath"&gt;
-  &lt;pathelement location="${classes}" /&gt;
-  &lt;pathelement location="/path/to/junit.jar" /&gt;
-  &lt;fileset dir="${lib}">
-    &lt;include name="**/*.jar"/&gt;
-  &lt;/fileset&gt;
-&lt;/path&gt;
-	  </code></pre>
-        </div>
-      </li>
-      <li>
-	<p>
-	  Define the Ant task for running JUnit:
-	</p>
-	<div>
-	  <pre><code>
-&lt;target name="test"&gt;
-  &lt;junit fork="yes" haltonfailure="yes"&gt;
-    &lt;test name="${test.class.name}" /&gt;
-    &lt;formatter type="plain" usefile="false" /&gt;
-    &lt;classpath refid="test.classpath" /&gt;
-  &lt;/junit&gt;
-&lt;/target&gt;
-	  </code></pre>
-	</div>
-      </li>
-      <li>
-	<p>
-	  Run the test:
-	</p>
-	<div>
-	  <code>
-	      ant test
-	  </code>
-	</div>
-      </li>
-    </ol>
-    <p>
-      Refer to the <a
-      href="http://jakarta.apache.org/ant/manual/OptionalTasks/junit.html">JUnit
-      Ant Task</a> for more information.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="running_6"></a>How do I use Ant to create HTML test
-      reports?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Eric Armstrong and Steffen Gemkow)</i>
-    </p>
-    <ol>
-      <li>
-	<p>
-	  Ensure that Ant's <code>optional.jar</code> file is either
-	  in your CLASSPATH or exists in
-	  your <code>$ANT_HOME/lib</code> directory.
-	</p>
-      </li>
-      <li>
-	<p>
-	  Add an ANT property for the directory containing the HTML reports:
-	</p>
-	<div>
-	  <code>
-&lt;property name="test.reports" value="./reports" /&gt;
-	  </code>
-	</div>
-      </li>
-      <li>
-	<p>
-	  Define the Ant task for running JUnit and generating reports:
-	</p>
-	<div>
-	  <pre><code>
-&lt;target name="test-html"&gt;
-  &lt;junit fork="yes" printsummary="no" haltonfailure="no"&gt;
-    &lt;batchtest fork="yes" todir="${test.reports}" &gt;
-      &lt;fileset dir="${classes}"&gt;
-        &lt;include name="**/*Test.class" /&gt;
-      &lt;/fileset&gt;
-    &lt;/batchtest&gt;
-    &lt;formatter type="xml" /&gt;
-    &lt;classpath refid="test.classpath" /&gt;
-  &lt;/junit&gt;
-
-  &lt;junitreport todir="${test.reports}"&gt;
-    &lt;fileset dir="${test.reports}"&gt;
-      &lt;include name="TEST-*.xml" /&gt;
-    &lt;/fileset&gt;
-    &lt;report todir="${test.reports}" /&gt;
-  &lt;/junitreport&gt;
-&lt;/target&gt;
-	  </code></pre>
-	</div>
-      </li>
-      <li>
-	<p>
-	  Run the test:
-	</p>
-	<div>
-	  <code>
-	    ant test-html
-	  </code>
-	</div>
-      </li>
-    </ol>
-    <p>
-      Refer to the 
-      <a href="http://jakarta.apache.org/ant/manual/OptionalTasks/junit.html">JUnit Ant Task</a>
-      for more information.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="running_7"></a>How do I pass command-line arguments
-      to a test execution?</b>
-    </p>
-    <p>
-      Use the <tt>-D</tt> JVM command-line options, as in:
-    </p>
-    <div>
-      <blockquote><code>
--DparameterName=parameterValue
-      </code></blockquote>
-    </div>
-    <p>
-      If the number of parameters on the command line gets unweildy,
-      pass in the location of a property file that defines a set of
-      parameters. Alternatively, the <a
-      href="http://junit-addons.sf.net">JUnit-addons package</a>
-      contains the <tt>XMLPropertyManager</tt>
-      and <tt>PropertyManager</tt> classes that allow you to define a
-      property file (or XML file) containing test parameters.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="running_9"></a>Why do I get
-      a <code>LinkageError</code> when using
-	XML interfaces in my test?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Scott Stirling)</i>
-    </p>
-    <p>
-      The workaround as of JUnit 3.7 is to
-      add <code>org.w3c.dom.*</code> and <code>org.xml.sax.*</code> to
-      your <code>excluded.properties</code>.
-    </p>
-    <p>
-      It's just a matter of time before this fix becomes incorporated
-      into the released version of
-      JUnit's <code>excluded.properties</code>, since JAXP is a
-      standard part of JDK 1.4. It will be just like
-      excluding <code>org.omg.*</code>. By the way, if you download
-      the JUnit source from its Sourceforge CVS, you will find that
-      these patterns have already been added to the default
-      excluded.properties and so has a pattern for JINI. In fact, here
-      is the current version in CVS, which demonstrates how to add
-      exclusions to the list too:
-    </p>
-    <div>
-      <blockquote><pre>
-#
-# The list of excluded package paths for the TestCaseClassLoader
-#
-excluded.0=sun.*
-excluded.1=com.sun.*
-excluded.2=org.omg.*
-excluded.3=javax.*
-excluded.4=sunw.*
-excluded.5=java.*
-excluded.6=org.w3c.dom.*
-excluded.7=org.xml.sax.*
-excluded.8=net.jini.*
-      </pre></blockquote>
-    </div>
-    <p>
-      This is the most common case where the
-      default <code>excluded.properties</code> list needs
-      modification. The cause of the <code>LinkageError</code> is
-      related to using JAXP in your test cases. By JAXP I mean the
-      whole set of <code>javax.xml.*</code> classes and the
-      supporting <code>org.w3c.dom.*</code>
-      and <code>org.xml.sax.*</code> classes.
-    </p>
-    <p>
-      As stated above, the JUnit GUI TestRunners' classloader relies
-      on the <code>excluded.properties</code> for classes it should
-      delegate to the system classloader. JAXP is an unusual case
-      because it is a standard Java extension library dependent on
-      classes whose package names (<code>org.w3c.dom.*</code>
-      and <code>org.xml.sax.*</code>) do not begin with a standard
-      Java or Sun prefix. This is similar to the relationship
-      between <code>javax.rmi.*</code> and the <code>org.omg.*</code>
-      classes, which have been excluded by default in
-      JUnit'ss <code>excluded.properties</code> for a while.
-    </p>
-    <p>
-      What can happen, and frequently does when using the JUnit Swing
-      or AWT UI with test cases that reference, use or depend on JAXP
-      classes, such as Log4J, Apache SOAP, Axis, Cocoon, etc., is that
-      the JUnit class loader (properly)
-      delegates <code>javax.xml.*</code> classes it &quot;sees&quot;
-      to the system loader. But then the system loader, in the process
-      of initializing and loading that JAXP class, links and loads up
-      a bunch of <code>org.w3c.dom</code>/<code>org.xml.sax</code>
-      classes. When it does so, the JUnit custom classloader is not
-      involved at all because the system classloader never delegates
-      &quot;down&quot; or checks with custom classloaders to see if a
-      class is already loaded. At any point after this, if the JUnit
-      loader is asked to load
-      an <code>org.w3c.dom</code>/<code>org.xml.sax</code> class that
-      it's never seen before, it will try to load it because the
-      class' name doesn't match any of the patterns in the default
-      exclude list.  That's when a <code>LinkageError</code>
-      occurs. This is really a flaw in the JUnit classloader design,
-      but there is the workaround given above.
-    </p>
-    <p>
-      Java 2 JVMs keep classes (remember, classes and objects, though
-      related, are different entities to the JVM - I'm talking
-      about classes here, not object instances) in namespaces,
-      identifying them by their fully qualified classname plus the
-      instance of their defining (not initiating) loader. The JVM will
-      attempt to assign all unloaded classes referenced by an already
-      defined and loaded class to that class's defining loader. The
-      JVM's classresolver routine (implemented as a C function in the
-      JVM source code) keeps track of all these class loading events
-      and &quot;sees&quot; if another classloader (such as the JUnit
-      custom loader) attempts to define a class that has already been
-      defined by the system loader. According to the rules of Java 2
-      loader constraints, in case a class has already been defined by
-      the system loader, any attempts to load a class should first be
-      delegated to the system loader. A &quot;proper&quot; way for
-      JUnit to handle this feature would be to load classes from a
-      repository other than the CLASSPATH that the system classloader
-      knows nothing about. And then the JUnit custom classloader could
-      follow the standard Java 2 delegation model, which is to always
-      delegate class loading to the system loader, and only attempt to
-      load if that fails. Since they both load from the CLASSPATH in
-      the current model, if the JUnit loader delegated like it's
-      supposed to, it would never get to load any classes since the
-      system loader would always find them.
-    </p>
-    <p>
-      You could try to hack around this in the JUnit source by
-      catching the <code>LinkageError</code> in
-      TestCaseClassLoader's <code>loadClass()</code> method and then
-      making a recovery call to <code>findSystemClass()</code> --
-      thereby delegating to the system loader after the violation has
-      been caught. But this hack only works some of the time, because
-      now you can have the reverse problem where the JUnit loader will
-      load a host of <code>org.w3c.dom</code>/<code>org.xml.sax</code>
-      classes, and then the system loader violates the loader
-      contraints at some point when it tries to do exactly what I
-      described above with JAXP because it doesn't ever delegate to
-      its logical child (the JUnit loader). Inevitably, if your test
-      cases use many JAXP and related XML classes, one or the other
-      classloader will end up violating the constraints whatever you
-      do.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="running_11"></a>Why do I get the warning
-      "AssertionFailedError: No
-	tests found in XXX" when I run my test?</b>
-    </p>
-    <p>
-      Make sure you have more or more method annotated with <code>@Test</code>.
-    </p>
-    <p>
-      For example:
-    </p>
-    <div>
-      <blockquote><pre>
-@Test
-public void testSomething() {
-}
-      </pre></blockquote>
-    </div>    
-  </li>
-  <li>
-    <p>
-      <b><a name="running_12"></a>Why do I see "Unknown Source" in the
-      stack trace of
-a test failure, rather than the source file's line number?</b>
-    </p>
-    <p>
-      The debug option for the Java compiler must be enabled in order
-      to see source file and line number information in a stack trace.
-    </p>
-    <p>
-      When invoking the Java compiler from the command line, use
-      the <code>-g</code> option to generate all debugging info.
-    </p>
-    <p>
-      When invoking the Java compiler from an 
-      <a href="http://jakarta.apache.org/ant/index.html">Ant</a> task, use the
-      <code>debug="on"</code> attribute.  For example:
-    </p>
-    <div>
-      <blockquote><code>
-&lt;javac srcdir="${src}" destdir="${build}" debug="on" /&gt;
-      </code></blockquote>
-    </div>
-    <p>
-      When using older JVMs pre-Hotspot (JDK 1.1 and most/all 1.2),
-      run JUnit with the <code>-DJAVA_COMPILER=none</code> JMV command
-      line argument to prevent runtime JIT compilation from obscuring
-      line number info.
-    </p>
-    <p>
-      Compiling the test source with debug enabled will show the line
-      where the assertion failed.  Compiling the non-test source with
-      debug enabled will show the line where an exception was raised
-      in the class under test.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="running_15"></a>How do I organize all test classes
-	in a TestSuite automatically and not use or manage a TestSuite
-	explicitly?</b>
-    </p>
-    <p>
-      <i>(Submitted by: Bill de hora)</i>
-    </p>
-    <p>
-      There are a number of ways to do this:
-    </p>
-    <ol>
-      <li>
-	<p>
-	  In Ant, use the <code>junit</code> task and
-	  the <code>batchtest</code> element:
-	</p>
-	<div>
-	  <pre><code>
-&lt;junit printsummary="yes" haltonfailure="yes"&gt;
-  ...
-  &lt;batchtest fork="yes"&gt;
-    &lt;fileset dir="${src.dir}"&gt;
-       &lt;include name="**/*Test.java" /&gt;
-       &lt;include name="**/Test*.java" /&gt;
-    &lt;/fileset&gt;
-  &lt;/batchtest&gt;
-&lt;/junit&gt; 
-	  </code></pre>
-	</div>
-	<p>
-	  Idiomatic naming patterns for unit tests
-	  are <code>Test*.java</code> and <code>*Test.java</code>.
-	  Documentation and examples are at <a
-					       href="http://ant.apache.org/manual/OptionalTasks/junit.html">http://ant.apache.org/manual/OptionalTasks/junit.html</a>.
-	</p>
-      </li>
-      <li>
-	<p>
-	  Use the <code>DirectorySuiteBuilder</code>
-	  and <code>ArchiveSuiteBuilder</code> (for jar/zip files)
-	  classes provided by JUnit-addons project:
-	</p>
-	<div>
-	  <blockquote><pre>
-DirectorySuiteBuilder builder = new DirectorySuiteBuilder();
-builder.setSuffix("Test");
-Test suite = builer.suite("/home/project/myproject/tests"); 
-	  </pre></blockquote>
-	</div>
-	<p>
-	  Documentation and examples are at <a
-					       href="http://junit-addons.sourceforge.net/">http://junit-addons.sourceforge.net</a>.
-	</p>
-      </li>
-      <li>
-	<p>
-	  Write your own custom suite builder. 
-	</p>
-	<p>
-	  Have your test classes implement an interface and write a
-	  treewalker to load each class in a directory, inspect the
-	  class, and add any classes that implement the interface to a
-	  TestSuite.
-	</p>
-	<p>
-	  You might only want to do this if you are <b>very</b>
-	  uncomfortable with using a naming convention for test
-	  classes. Aside from being slow for larger suites, ultimately
-	  it's arguable whether it's more effort to follow a naming
-	  convention that have test classes implement an interface!
-	</p>
-	<p>
-	  An example of this approach is at 
-	  <a href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html">http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html</a>.  
-	</p>
-      </li>
-    </ol>
-  </li>
-</ol>
-
-<!--
-
-    Best Practices
-
--->
-<div class="header">
-<a name="best">Best Practices</a>
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a name="best_1"></a>When should tests be written?</b>
-    </p>
-    <p>
-      Tests should be written before the code.  Test-first programming
-      is practiced by only writing new code when an automated test is
-      failing.
-    </p>
-    <p>
-      Good tests tell you how to best design the system for its
-      intended use.  They effectively communicate in an executable
-      format how to use the software.  They also prevent tendencies to
-      over-build the system based on speculation.  When all the tests
-      pass, you know you're done!
-    </p>
-    <p>
-      Whenever a customer test fails or a bug is reported, first write
-      the necessary unit test(s) to expose the bug(s), <em>then</em>
-      fix them. This makes it almost impossible for that particular
-      bug to resurface later.
-    </p>
-    <p>
-      Test-driven development is a lot more fun than writing tests
-      after the code seems to be working.  Give it a try!
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="best_2"></a>Do I have to write a test for
-	everything?</b>
-    </p>
-    <p>
-      No, just test everything that could reasonably break.  
-    </p>
-    <p>
-      Be practical and maximize your testing investment.  Remember
-      that investments in testing are equal investments in design.  If
-      defects aren't being reported and your design responds well to
-      change, then you're probably testing enough.  If you're spending
-      a lot of time fixing defects and your design is difficult to
-      grow, you should write more tests.
-    </p>
-    <p>
-      If something is difficult to test, it's usually an opportunity
-      for a design improvement.  Look to improve the design so that
-      it's easier to test, and by doing so a better design will
-      usually emerge.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="best_3"></a>How simple is 'too simple to break'?</b>
-    </p>
-    <p>
-      <i>(Submitted by: J. B. Rainsberger)</i>
-    </p>
-    <p>
-      The general philosophy is this: if it can't break <em>on its
-      own</em>, it's too simple to break.
-    </p>
-    <p>
-      First example is the <code>getX()</code> method. Suppose
-      the <code>getX()</code> method only answers the value of an
-      instance variable. In that case, <code>getX()</code> cannot
-      break unless either the compiler or the interpreter is also
-      broken. For that reason, don't test <code>getX()</code>; there
-      is no benefit.  The same is true of the <code>setX()</code>
-      method, although if your <code>setX()</code> method does any
-      parameter validation or has any side effects, you likely need to
-      test it.
-    </p>
-    <p>
-      Next example: suppose you have written a method that does
-      nothing but forward parameters into a method called on another
-      object. That method is too simple to break.
-    </p>
-    <div>
-      <blockquote><pre>
-public void myMethod(final int a, final String b) {
-    myCollaborator.anotherMethod(a, b);
-}
-      </pre></blockquote>
-    </div>
-    <p>
-      <code>myMethod</code> cannot possibly break because it does nothing: it 
-      forwards its input to another object and that's all. 
-    </p>
-    <p>
-      The only precondition for this method is "myCollaborator !=
-      null", but that is generally the responsibility of the
-      constructor, and not of myMethod. If you are concerned, add a
-      test to verify that myCollaborator is always set to something
-      non-null by every constructor.
-    </p>
-    <p>
-      The only way myMethod could break would be
-      if <code>myCollaborator.anotherMethod()</code> were broken. In
-      that case, test <code>myCollaborator</code>, and not the current
-      class.
-    </p>
-    <p>
-      It is true that adding tests for even these simple methods
-      guards against the possibility that someone refactors and makes
-      the methods "not-so-simple" anymore. In that case, though, the
-      refactorer needs to be aware that the method is now complex
-      enough to break, and should write tests for it -- and preferably
-      before the refactoring.
-    </p>
-    <p>
-      Another example: suppose you have a JSP and, like a good
-      programmer, you have removed all business logic from it. All it
-      does is provide a layout for a number of JavaBeans and never
-      does anything that could change the value of any object. That
-      JSP is too simple to break, and since JSPs are notoriously
-      annoying to test, you should strive to make all your JSPs too
-      simple to break.
-    </p>
-    <p>
-      Here's the way testing goes: 
-    </p>
-    <div>
-      <blockquote><pre>
-becomeTimidAndTestEverything
-while writingTheSameThingOverAndOverAgain
-    becomeMoreAggressive
-    writeFewerTests
-    writeTestsForMoreInterestingCases
-    if getBurnedByStupidDefect
-        feelStupid
-        becomeTimidAndTestEverything
-    end
-end
-      </pre></blockquote>
-    </div>
-    <p>
-      The loop, as you can see, never terminates.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="best_4"></a>How often should I run my tests?</b>
-    </p>
-    <p>
-      Run all your unit tests as often as possible, ideally every time
-      the code is changed.  Make sure all your unit tests always run
-      at 100%.  Frequent testing gives you confidence that your
-      changes didn't break anything and generally lowers the stress of
-      programming in the dark.
-    </p>
-    <p>
-      For larger systems, you may just run specific test suites that
-      are relevant to the code you're working on.
-    </p>
-    <p>
-      Run all your acceptance, integration, stress, and unit tests at
-      least once per day (or night).
-    </p>
-    <p>
-      If you're using Eclipse, be sure to check out David Saff's 
-      <a href="http://pag.csail.mit.edu/continuoustesting/">continuous
-      testing plug-in</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="best_5"></a>What do I do when a defect is reported?</b>
-    </p>
-    <p>
-      Test-driven development generally lowers the defect density of
-      software.  But we're all fallible, so sometimes a defect will
-      slip through.  When this happens, write a failing test that
-      exposes the defect.  When the test passes, you know the defect
-      is fixed!
-    </p>
-    <p>
-      Don't forget to use this as a learning opportunity.  Perhaps the
-      defect could have been prevented by being more aggressive about
-      testing everything that could reasonably break.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="best_6"></a>Why not just use <code>System.out.println()</code>?</b>
-    </p>
-    <p>
-      Inserting debug statements into code is a low-tech method for
-      debugging it.  It usually requires that output be scanned
-      manually every time the program is run to ensure that the code
-      is doing what's expected.
-    </p>
-    <p>
-      It generally takes less time in the long run to codify
-      expectations in the form of an automated JUnit test that retains
-      its value over time.  If it's difficult to write a test to
-      assert expectations, the tests may be telling you that shorter
-      and more cohesive methods would improve your design.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="best_7"></a>Why not just use a debugger?</b>
-    </p>
-    <p>
-      Debuggers are commonly used to step through code and inspect
-      that the variables along the way contain the expected values.
-      But stepping through a program in a debugger is a manual process
-      that requires tedious visual inspections.  In essence, the
-      debugging session is nothing more than a manual check of
-      expected vs. actual results.  Moreover, every time the program
-      changes we must manually step back through the program in the
-      debugger to ensure that nothing broke.
-    </p>
-    <p>
-      It generally takes less time to codify expectations in the form
-      of an automated JUnit test that retains its value over time.  If
-      it's difficult to write a test to assert expected values, the
-      tests may be telling you that shorter and more cohesive methods
-      would improve your design.
-    </p>
-  </li>
-</ol>
-
-<!--
-
-    Miscellaneous
-
--->
-<div class="header">
-<a name="misc">Miscellaneous</a>
-</div>
-<ol>
-  <li>
-    <p>
-      <b><a name="misc_1"></a>How do I integrate JUnit with my IDE?</b>
-    </p>
-    <p>
-      The JUnit home page maintains a list of <a
-      href="http://www.junit.org/news/ide/index.htm">IDE integration
-      instructions</a>.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="misc_2"></a>How do I launch a debugger when a test fails?</b>
-    </p>
-    <p>
-      Start the <code>TestRunner</code> under the debugger and
-      configure the debugger so that it catches
-      the <code>junit.framework.AssertionFailedError</code>.
-    </p>
-    <p>
-      How you configure this depends on the debugger you prefer to
-      use. Most Java debuggers provide support to stop the program
-      when a specific exception is raised.
-    </p>
-    <p>
-      Notice that this will only launch the debugger when an expected
-      failure occurs.
-    </p>
-  </li>
-  <li>
-    <p>
-      <b><a name="misc_3"></a>Where can I find unit testing frameworks
-      similar to JUnit for other languages?</b>
-    </p>
-    <p>
-      XProgramming.com maintains a complete list of available <a
-      href="http://www.xprogramming.com/software.htm">xUnit testing
-      frameworks</a>.
-    </p>
-  </li>
-</ol>
-
-<br/>
-
-<div align="right">
-  <a href="http://validator.w3.org/check?uri=referer">
-    <img src="http://www.w3.org/Icons/valid-xhtml10"
-         alt="Valid XHTML 1.0!" height="31" width="88" /></a>
-</div>
-
-</body>
-</html>
diff --git a/doc/homepage.html b/doc/homepage.html
index ff2a027..69c6248 100644
--- a/doc/homepage.html
+++ b/doc/homepage.html
@@ -56,7 +56,7 @@
 
 <br><a href="README.html">Release notes</a>
 <br>&nbsp;&nbsp;&nbsp; Latest JUnit release notes
-<br><a href="cpl-v10.html">License</a>
+<br><a href="epl-v10.html">License</a>
 <br>&nbsp;&nbsp;&nbsp; The terms of the common public license used for JUnit.<br>
 </blockquote>
 The following documents still describe JUnit 3.8.
@@ -104,7 +104,7 @@
       href="http://sf.net/projects/junit">provided</A> for your submissions.
 
       <br/>
-      JUnit source code is now hosted on <a href="http://github.com/KentBeck/junit">GitHub</a>.
+      JUnit source code is now hosted on <a href="http://github.com/junit-team/junit">GitHub</a>.
 
 <hr WIDTH="100%">
 <font size="1">
diff --git a/done.txt b/done.txt
deleted file mode 100644
index 0a89d46..0000000
--- a/done.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-* name space of JUnit4 is org.junit
-* JUnit4 requires J2SE 5.0
-	leverage J2SE 5.0 features
-* @Test annotation
-	@Test(expected=IndexOutOfBoundsException.class)
-	@Test(timeout= 1000)
-* @Ignore(reason= "...")
-* @Before, @After setup/teardown
-* @BeforeClass, @AfterClass one-time setup/teardown
-* provide ForwardCompatibility so that existing test Runners can 
-  run JUnit4 tests:
-	public static junit.framework.Test suite() {
-		return new JUnit4TestAdapter(ListTest.class);
-	}
-* add assertEquals(Object[], Object[])
-* Add backward compatibility for old JUnit tests in the new Runner
-* support the assert keyword and use AssertionError 
-* remove the old graphical runners
-* simplify: get rid of failures and errors distinction
-* Annotation for runner strategy
-* Parameterized test
-* Should RunNotifier be API?
-* Runner should be abstract class.
-* Run single method with @BeforeClass and @AfterClass
-* Stopping a test run (there was support for this in 3.8 - TestResult.shouldStop())
-
-* Suite annotation example:
-	@Suite(tests={MoneyTest.class, SimpleTest.class})
-	or with filters
-	@Suite(pattern="*Test"}
-	@Suite(package="org.junit.test.*")
-	@Suite
-	
-* be able to run all tests simply from the command line
-* get rid of JUnit4TestCaseAdapter (use JUnit4RunnerStrategy in JUnit4TestAdapter)
-* enable tighter and more flexible IDE integration
-	* enable test reordering/prioritization
-	* test categorization & filtering (<- seems like a runner issue) @Category(short, integration)  @Test(category=windowsOnly)
-* make sure TestListener is symmetric and meets needs of runner developers
-	* TestRunEvent
-* Decide how we ship JUnit-- 1.5 only or hybrid
-	* README.html
-* add  javadoc to API interfaces and Annotations
-	http://java.sun.com/j2se/javadoc/writingapispecs/index.html
-* Merge branch back into head
-* review Ant scripts
-* make suites simpler for both the IDE providers and the users
-* ClassRequest should search up the hierarchy for the requested Class to look for @RunWith
-
-	
\ No newline at end of file
diff --git a/epl-v10.html b/epl-v10.html
new file mode 100644
index 0000000..3998fce
--- /dev/null
+++ b/epl-v10.html
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Public License - Version 1.0</title>
+<style type="text/css">
+  body {
+    size: 8.5in 11.0in;
+    margin: 0.25in 0.5in 0.25in 0.5in;
+    tab-interval: 0.5in;
+    }
+  p {  	
+    margin-left: auto;
+    margin-top:  0.5em;
+    margin-bottom: 0.5em;
+    }
+  p.list {
+  	margin-left: 0.5in;
+    margin-top:  0.05em;
+    margin-bottom: 0.05em;
+    }
+  </style>
+
+</head>
+
+<body lang="EN-US">
+
+<h2>Eclipse Public License - v 1.0</h2>
+
+<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR
+DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
+AGREEMENT.</p>
+
+<p><b>1. DEFINITIONS</b></p>
+
+<p>&quot;Contribution&quot; means:</p>
+
+<p class="list">a) in the case of the initial Contributor, the initial
+code and documentation distributed under this Agreement, and</p>
+<p class="list">b) in the case of each subsequent Contributor:</p>
+<p class="list">i) changes to the Program, and</p>
+<p class="list">ii) additions to the Program;</p>
+<p class="list">where such changes and/or additions to the Program
+originate from and are distributed by that particular Contributor. A
+Contribution 'originates' from a Contributor if it was added to the
+Program by such Contributor itself or anyone acting on such
+Contributor's behalf. Contributions do not include additions to the
+Program which: (i) are separate modules of software distributed in
+conjunction with the Program under their own license agreement, and (ii)
+are not derivative works of the Program.</p>
+
+<p>&quot;Contributor&quot; means any person or entity that distributes
+the Program.</p>
+
+<p>&quot;Licensed Patents&quot; mean patent claims licensable by a
+Contributor which are necessarily infringed by the use or sale of its
+Contribution alone or when combined with the Program.</p>
+
+<p>&quot;Program&quot; means the Contributions distributed in accordance
+with this Agreement.</p>
+
+<p>&quot;Recipient&quot; means anyone who receives the Program under
+this Agreement, including all Contributors.</p>
+
+<p><b>2. GRANT OF RIGHTS</b></p>
+
+<p class="list">a) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works
+of, publicly display, publicly perform, distribute and sublicense the
+Contribution of such Contributor, if any, and such derivative works, in
+source code and object code form.</p>
+
+<p class="list">b) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell,
+offer to sell, import and otherwise transfer the Contribution of such
+Contributor, if any, in source code and object code form. This patent
+license shall apply to the combination of the Contribution and the
+Program if, at the time the Contribution is added by the Contributor,
+such addition of the Contribution causes such combination to be covered
+by the Licensed Patents. The patent license shall not apply to any other
+combinations which include the Contribution. No hardware per se is
+licensed hereunder.</p>
+
+<p class="list">c) Recipient understands that although each Contributor
+grants the licenses to its Contributions set forth herein, no assurances
+are provided by any Contributor that the Program does not infringe the
+patent or other intellectual property rights of any other entity. Each
+Contributor disclaims any liability to Recipient for claims brought by
+any other entity based on infringement of intellectual property rights
+or otherwise. As a condition to exercising the rights and licenses
+granted hereunder, each Recipient hereby assumes sole responsibility to
+secure any other intellectual property rights needed, if any. For
+example, if a third party patent license is required to allow Recipient
+to distribute the Program, it is Recipient's responsibility to acquire
+that license before distributing the Program.</p>
+
+<p class="list">d) Each Contributor represents that to its knowledge it
+has sufficient copyright rights in its Contribution, if any, to grant
+the copyright license set forth in this Agreement.</p>
+
+<p><b>3. REQUIREMENTS</b></p>
+
+<p>A Contributor may choose to distribute the Program in object code
+form under its own license agreement, provided that:</p>
+
+<p class="list">a) it complies with the terms and conditions of this
+Agreement; and</p>
+
+<p class="list">b) its license agreement:</p>
+
+<p class="list">i) effectively disclaims on behalf of all Contributors
+all warranties and conditions, express and implied, including warranties
+or conditions of title and non-infringement, and implied warranties or
+conditions of merchantability and fitness for a particular purpose;</p>
+
+<p class="list">ii) effectively excludes on behalf of all Contributors
+all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;</p>
+
+<p class="list">iii) states that any provisions which differ from this
+Agreement are offered by that Contributor alone and not by any other
+party; and</p>
+
+<p class="list">iv) states that source code for the Program is available
+from such Contributor, and informs licensees how to obtain it in a
+reasonable manner on or through a medium customarily used for software
+exchange.</p>
+
+<p>When the Program is made available in source code form:</p>
+
+<p class="list">a) it must be made available under this Agreement; and</p>
+
+<p class="list">b) a copy of this Agreement must be included with each
+copy of the Program.</p>
+
+<p>Contributors may not remove or alter any copyright notices contained
+within the Program.</p>
+
+<p>Each Contributor must identify itself as the originator of its
+Contribution, if any, in a manner that reasonably allows subsequent
+Recipients to identify the originator of the Contribution.</p>
+
+<p><b>4. COMMERCIAL DISTRIBUTION</b></p>
+
+<p>Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use of
+the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create
+potential liability for other Contributors. Therefore, if a Contributor
+includes the Program in a commercial product offering, such Contributor
+(&quot;Commercial Contributor&quot;) hereby agrees to defend and
+indemnify every other Contributor (&quot;Indemnified Contributor&quot;)
+against any losses, damages and costs (collectively &quot;Losses&quot;)
+arising from claims, lawsuits and other legal actions brought by a third
+party against the Indemnified Contributor to the extent caused by the
+acts or omissions of such Commercial Contributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In
+order to qualify, an Indemnified Contributor must: a) promptly notify
+the Commercial Contributor in writing of such claim, and b) allow the
+Commercial Contributor to control, and cooperate with the Commercial
+Contributor in, the defense and any related settlement negotiations. The
+Indemnified Contributor may participate in any such claim at its own
+expense.</p>
+
+<p>For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those
+performance claims and warranties, and if a court requires any other
+Contributor to pay any damages as a result, the Commercial Contributor
+must pay those damages.</p>
+
+<p><b>5. NO WARRANTY</b></p>
+
+<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
+ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to
+the risks and costs of program errors, compliance with applicable laws,
+damage to or loss of data, programs or equipment, and unavailability or
+interruption of operations.</p>
+
+<p><b>6. DISCLAIMER OF LIABILITY</b></p>
+
+<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
+NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>
+
+<p><b>7. GENERAL</b></p>
+
+<p>If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further action
+by the parties hereto, such provision shall be reformed to the minimum
+extent necessary to make such provision valid and enforceable.</p>
+
+<p>If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other
+software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the
+date such litigation is filed.</p>
+
+<p>All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of time
+after becoming aware of such noncompliance. If all Recipient's rights
+under this Agreement terminate, Recipient agrees to cease use and
+distribution of the Program as soon as reasonably practicable. However,
+Recipient's obligations under this Agreement and any licenses granted by
+Recipient relating to the Program shall continue and survive.</p>
+
+<p>Everyone is permitted to copy and distribute copies of this
+Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The
+Agreement Steward reserves the right to publish new versions (including
+revisions) of this Agreement from time to time. No one other than the
+Agreement Steward has the right to modify this Agreement. The Eclipse
+Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a
+suitable separate entity. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new version
+of the Agreement is published, Contributor may elect to distribute the
+Program (including its Contributions) under the new version. Except as
+expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
+rights or licenses to the intellectual property of any Contributor under
+this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this
+Agreement are reserved.</p>
+
+<p>This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No party
+to this Agreement will bring a legal action under this Agreement more
+than one year after the cause of action arose. Each party waives its
+rights to a jury trial in any resulting litigation.</p>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 6b8c475..29b6370 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
 
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
-    <version>4.12-SNAPSHOT</version>
+    <version>4.13-SNAPSHOT</version>
 
     <name>JUnit</name>
     <description>JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.</description>
@@ -16,8 +16,8 @@
     </organization>
     <licenses>
         <license>
-            <name>Common Public License Version 1.0</name>
-            <url>http://www.opensource.org/licenses/cpl1.0.txt</url>
+            <name>Eclipse Public License 1.0</name>
+            <url>http://www.eclipse.org/legal/epl-v10.html</url>
             <distribution>repo</distribution>
         </license>
     </licenses>
@@ -28,13 +28,28 @@
             <name>David Saff</name>
             <email>david@saff.net</email>
         </developer>
+        <developer>
+            <id>kcooney</id>
+            <name>Kevin Cooney</name>
+            <email>kcooney@google.com</email>
+        </developer>
+        <developer>
+            <id>stefanbirkner</id>
+            <name>Stefan Birkner</name>
+            <email>mail@stefan-birkner.de</email>
+        </developer>
+        <developer>
+            <id>marcphilipp</id>
+            <name>Marc Philipp</name>
+            <email>mail@marcphilipp.de</email>
+        </developer>
     </developers>
     <contributors>
         <contributor>
             <name>JUnit contributors</name>
             <organization>JUnit</organization>
             <email>junit@yahoogroups.com</email>
-            <url>https://github.com/KentBeck/junit/graphs/contributors</url>
+            <url>https://github.com/junit-team/junit/graphs/contributors</url>
             <roles>
                 <role>developers</role>
             </roles>
@@ -45,7 +60,7 @@
         <mailingList>
             <name>JUnit Mailing List</name>
             <post>junit@yahoogroups.com</post>
-            <archive>http://tech.groups.yahoo.com/group/junit/</archive>
+            <archive>https://groups.yahoo.com/neo/groups/junit/info</archive>
         </mailingList>
     </mailingLists>
 
@@ -54,20 +69,21 @@
     </prerequisites>
 
     <scm>
-        <connection>scm:git:git://github.com/KentBeck/junit.git</connection>
-        <developerConnection>scm:git:git@github.com:KentBeck/junit.git</developerConnection>
-        <url>http://github.com/KentBeck/junit/tree/master</url>
-    </scm>
+        <connection>scm:git:git://github.com/junit-team/junit.git</connection>
+        <developerConnection>scm:git:git@github.com:junit-team/junit.git</developerConnection>
+        <url>http://github.com/junit-team/junit/tree/master</url>
+      <tag>HEAD</tag>
+  </scm>
     <issueManagement>
         <system>github</system>
-        <url>https://github.com/KentBeck/junit/issues</url>
+        <url>https://github.com/junit-team/junit/issues</url>
     </issueManagement>
     <ciManagement>
         <system>jenkins</system>
         <url>https://junit.ci.cloudbees.com/</url>
     </ciManagement>
     <distributionManagement>
-        <downloadUrl>https://github.com/KentBeck/junit/wiki/Download-and-Install</downloadUrl>
+        <downloadUrl>https://github.com/junit-team/junit/wiki/Download-and-Install</downloadUrl>
         <snapshotRepository>
             <id>junit-snapshot-repo</id>
             <name>Nexus Snapshot Repository</name>
@@ -78,12 +94,16 @@
             <name>Nexus Release Repository</name>
             <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
         </repository>
+        <site>
+            <id>junit.github.io</id>
+            <url>gitsite:git@github.com/junit-team/junit.git</url>
+        </site>
     </distributionManagement>
 
     <properties>
         <jdkVersion>1.5</jdkVersion>
         <project.build.sourceEncoding>ISO-8859-1</project.build.sourceEncoding>
-        <arguments/>
+        <arguments />
         <gpg.keyname>67893CC4</gpg.keyname>
     </properties>
 
@@ -103,7 +123,7 @@
             <resource>
                 <directory>${project.basedir}</directory>
                 <includes>
-                    <include>LICENSE.txt</include>
+                    <include>LICENSE-junit.txt</include>
                 </includes>
             </resource>
         </resources>
@@ -126,7 +146,7 @@
                 the project, requires only release versions of dependencies of other artifacts.
                 -->
                 <artifactId>maven-enforcer-plugin</artifactId>
-                <version>1.1.1</version>
+                <version>1.4</version>
                 <executions>
                     <execution>
                         <id>enforce-versions</id>
@@ -139,15 +159,20 @@
                             <rules>
                                 <requireMavenVersion>
                                     <!-- Some plugin features require a recent Maven runtime to work properly -->
-                                    <message>Current version of Maven ${maven.version} required to build the project should be ${project.prerequisites.maven}, or higher!</message>
+                                    <message>Current version of Maven ${maven.version} required to build the project
+                                        should be ${project.prerequisites.maven}, or higher!
+                                    </message>
                                     <version>[${project.prerequisites.maven},)</version>
                                 </requireMavenVersion>
                                 <requireJavaVersion>
-                                    <message>Current JDK version ${java.version} should be ${jdkVersion}, or higher!</message>
+                                    <message>Current JDK version ${java.version} should be ${jdkVersion}, or higher!
+                                    </message>
                                     <version>${jdkVersion}</version>
                                 </requireJavaVersion>
                                 <requireNoRepositories>
-                                    <message>Best Practice is to never define repositories in pom.xml (use a repository manager instead).</message>
+                                    <message>Best Practice is to never define repositories in pom.xml (use a repository
+                                        manager instead).
+                                    </message>
                                 </requireNoRepositories>
                                 <requireReleaseDeps>
                                     <message>No Snapshots Dependencies Allowed!</message>
@@ -162,8 +187,8 @@
                 Updates Version#id().
                 -->
                 <groupId>com.google.code.maven-replacer-plugin</groupId>
-                <artifactId>maven-replacer-plugin</artifactId>
-                <version>1.3.8</version>
+                <artifactId>replacer</artifactId>
+                <version>1.5.3</version>
                 <executions>
                     <execution>
                         <phase>process-sources</phase>
@@ -174,8 +199,8 @@
                 </executions>
                 <configuration>
                     <ignoreMissingFile>false</ignoreMissingFile>
-                    <file>src/main/java/junit/runner/Version.java.template</file>
-                    <outputFile>src/main/java/junit/runner/Version.java</outputFile>
+                    <file>${project.build.sourceDirectory}/junit/runner/Version.java.template</file>
+                    <outputFile>${project.build.sourceDirectory}/junit/runner/Version.java</outputFile>
                     <regex>false</regex>
                     <token>@version@</token>
                     <value>${project.version}</value>
@@ -186,27 +211,52 @@
                 java compiler plugin forked in extra process
                 -->
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>2.5.1</version>
+                <version>3.3</version>
                 <configuration>
                     <encoding>${project.build.sourceEncoding}</encoding>
                     <source>${jdkVersion}</source>
                     <target>${jdkVersion}</target>
+                    <testSource>${jdkVersion}</testSource>
+                    <testTarget>${jdkVersion}</testTarget>
                     <compilerVersion>1.5</compilerVersion>
                     <showDeprecation>true</showDeprecation>
                     <showWarnings>true</showWarnings>
                     <debug>true</debug>
                     <fork>true</fork>
-                    <compilerArgument>-Xlint:unchecked</compilerArgument>
+                    <compilerArgs>
+                        <arg>-Xlint:unchecked</arg>
+                    </compilerArgs>
                     <maxmem>128m</maxmem>
                 </configuration>
             </plugin>
             <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>animal-sniffer-maven-plugin</artifactId>
+                <version>1.14</version>
+                <executions>
+                    <execution>
+                        <id>signature-check</id>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java15</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
                 <!--
                 A plugin which uses the JUnit framework in order to start
                 our junit suite "AllTests" after the sources are compiled.
                 -->
                 <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.12.3</version>
+                <version>2.18.1</version>
                 <configuration>
                     <test>org/junit/tests/AllTests.java</test>
                     <useSystemClassLoader>true</useSystemClassLoader>
@@ -219,7 +269,7 @@
                 in to jar archive. See target/junit-*-sources.jar.
                 -->
                 <artifactId>maven-source-plugin</artifactId>
-                <version>2.2</version>
+                <version>2.4</version>
             </plugin>
             <plugin>
                 <!--
@@ -228,7 +278,7 @@
                 in jar archive target/junit-*-javadoc.jar.
                 -->
                 <artifactId>maven-javadoc-plugin</artifactId>
-                <version>2.8.1</version>
+                <version>2.10.3</version>
                 <configuration>
                     <stylesheetfile>${basedir}/src/main/javadoc/stylesheet.css</stylesheetfile>
                     <show>protected</show>
@@ -237,18 +287,18 @@
                     <detectLinks>false</detectLinks>
                     <linksource>true</linksource>
                     <keywords>true</keywords>
-                    <use>false</use>
+                    <use>true</use>
                     <windowtitle>JUnit API</windowtitle>
                     <encoding>UTF-8</encoding>
                     <locale>en</locale>
-                    <javadocVersion>1.5</javadocVersion>
+                    <javadocVersion>${jdkVersion}</javadocVersion>
                     <javaApiLinks>
                         <property>
-                            <name>api_1.5</name>
-                            <value>http://docs.oracle.com/javase/1.5.0/docs/api/index.html</value>
+                            <name>api_${jdkVersion}</name>
+                            <value>http://docs.oracle.com/javase/${jdkVersion}.0/docs/api/</value>
                         </property>
                     </javaApiLinks>
-                    <excludePackageNames>junit.*,*.internal,*.internal.*</excludePackageNames>
+                    <excludePackageNames>junit.*,*.internal.*</excludePackageNames>
                     <verbose>true</verbose>
                     <minmemory>32m</minmemory>
                     <maxmemory>128m</maxmemory>
@@ -261,7 +311,7 @@
             </plugin>
             <plugin>
                 <artifactId>maven-release-plugin</artifactId>
-                <version>2.3.2</version>
+                <version>2.5.2</version>
                 <configuration>
                     <mavenExecutorId>forked-path</mavenExecutorId>
                     <useReleaseProfile>false</useReleaseProfile>
@@ -269,9 +319,126 @@
                     <tagNameFormat>r@{project.version}</tagNameFormat>
                 </configuration>
             </plugin>
+            <plugin>
+                <artifactId>maven-site-plugin</artifactId>
+                <version>3.4</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>com.github.stephenc.wagon</groupId>
+                        <artifactId>wagon-gitsite</artifactId>
+                        <version>0.4.1</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.maven.doxia</groupId>
+                        <artifactId>doxia-module-markdown</artifactId>
+                        <version>1.5</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.6</version>
+                <configuration>
+                    <archive>
+                        <addMavenDescriptor>false</addMavenDescriptor>
+                        <manifest>
+                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+                <version>2.6.1</version>
+            </plugin>
+            <plugin>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <version>2.8.2</version>
+            </plugin>
+            <plugin>
+                <artifactId>maven-install-plugin</artifactId>
+                <version>2.5.2</version>
+            </plugin>
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>2.7</version>
+            </plugin>
         </plugins>
     </build>
 
+    <reporting>
+        <plugins>
+            <plugin>
+                <artifactId>maven-project-info-reports-plugin</artifactId>
+                <version>2.8</version>
+                <configuration>
+                    <dependencyLocationsEnabled>false</dependencyLocationsEnabled>
+                    <!-- waiting for MPIR-267 -->
+                </configuration>
+                <reportSets>
+                    <reportSet>
+                        <reports>
+                            <report>index</report>
+                            <report>dependency-info</report>
+                            <report>modules</report>
+                            <report>license</report>
+                            <report>project-team</report>
+                            <report>scm</report>
+                            <report>issue-tracking</report>
+                            <report>mailing-list</report>
+                            <report>dependency-management</report>
+                            <report>dependencies</report>
+                            <report>dependency-convergence</report>
+                            <report>cim</report>
+                            <report>distribution-management</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+            </plugin>
+            <plugin>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.10.1</version>
+                <configuration>
+                    <destDir>javadoc/latest</destDir>
+                    <stylesheetfile>${basedir}/src/main/javadoc/stylesheet.css</stylesheetfile>
+                    <show>protected</show>
+                    <author>false</author>
+                    <version>false</version>
+                    <detectLinks>false</detectLinks>
+                    <linksource>true</linksource>
+                    <keywords>true</keywords>
+                    <use>true</use>
+                    <windowtitle>JUnit API</windowtitle>
+                    <encoding>UTF-8</encoding>
+                    <locale>en</locale>
+                    <javadocVersion>${jdkVersion}</javadocVersion>
+                    <javaApiLinks>
+                        <property>
+                            <name>api_${jdkVersion}</name>
+                            <value>http://docs.oracle.com/javase/${jdkVersion}.0/docs/api/</value>
+                        </property>
+                    </javaApiLinks>
+                    <excludePackageNames>junit.*,*.internal.*</excludePackageNames>
+                    <verbose>true</verbose>
+                    <minmemory>32m</minmemory>
+                    <maxmemory>128m</maxmemory>
+                    <failOnError>true</failOnError>
+                    <includeDependencySources>true</includeDependencySources>
+                    <dependencySourceIncludes>
+                        <dependencySourceInclude>org.hamcrest:hamcrest-core:*</dependencySourceInclude>
+                    </dependencySourceIncludes>
+                </configuration>
+                <reportSets>
+                    <reportSet>
+                        <reports>
+                            <report>javadoc</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+            </plugin>
+        </plugins>
+    </reporting>
+
     <profiles>
         <profile>
             <id>junit-release</id>
@@ -289,7 +456,7 @@
                         (&ndash;&ndash; stands for double dash)
                         -->
                         <artifactId>maven-gpg-plugin</artifactId>
-                        <version>1.4</version>
+                        <version>1.6</version>
                         <executions>
                             <execution>
                                 <id>gpg-sign</id>
@@ -339,5 +506,62 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>restrict-doclint</id>
+            <!-- doclint is only supported by JDK 8 -->
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <compilerArgs>
+                                <arg>-Xlint:unchecked</arg>
+                                <arg>-Xdoclint:accessibility,reference,syntax</arg>
+                            </compilerArgs>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <configuration>
+                            <additionalparam>-Xdoclint:accessibility -Xdoclint:reference</additionalparam>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+            <reporting>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <configuration>
+                            <additionalparam>-Xdoclint:accessibility -Xdoclint:reference</additionalparam>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </reporting>
+        </profile>
+        <profile>
+            <id>fast-tests</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <parallel>classes</parallel>
+                            <threadCountClasses>2</threadCountClasses>
+                        </configuration>
+                        <dependencies>
+                            <dependency>
+                                <groupId>org.apache.maven.surefire</groupId>
+                                <artifactId>surefire-junit47</artifactId>
+                                <version>2.18</version>
+                            </dependency>
+                        </dependencies>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
-</project>
\ No newline at end of file
+</project>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
new file mode 100644
index 0000000..e2631b1
--- /dev/null
+++ b/src/changes/changes.xml
@@ -0,0 +1,38 @@
+<document xmlns="http://maven.apache.org/changes/1.0.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 http://maven.apache.org/xsd/changes-1.0.0.xsd">
+  <body>
+    <release version="4.12">
+    </release>
+
+    <release version="4.11" date="2012-11-14">
+    </release>
+
+    <release version="4.10">
+    </release>
+
+    <release version="4.9.1">
+    </release>
+
+    <release version="4.9">
+    </release>
+
+    <release version="4.8.2">
+    </release>
+
+    <release version="4.8.1">
+    </release>
+
+    <release version="4.8">
+    </release>
+
+    <release version="4.7">
+    </release>
+
+    <release version="4.6">
+    </release>
+
+    <release version="4.5">
+    </release>
+  </body>
+</document>
\ No newline at end of file
diff --git a/src/main/java/junit/extensions/TestDecorator.java b/src/main/java/junit/extensions/TestDecorator.java
index 2b74f30..a3c5e08 100644
--- a/src/main/java/junit/extensions/TestDecorator.java
+++ b/src/main/java/junit/extensions/TestDecorator.java
@@ -9,6 +9,7 @@
  * test decorators. Test decorator subclasses can be introduced to add behaviour
  * before or after a test is run.
  */
+@SuppressWarnings("deprecation")
 public class TestDecorator extends Assert implements Test {
     protected Test fTest;
 
diff --git a/src/main/java/junit/framework/Assert.java b/src/main/java/junit/framework/Assert.java
index c15dce1..663461c 100644
--- a/src/main/java/junit/framework/Assert.java
+++ b/src/main/java/junit/framework/Assert.java
@@ -156,7 +156,7 @@
      * an AssertionFailedError is thrown with the given message.
      */
     static public void assertEquals(String message, long expected, long actual) {
-        assertEquals(message, new Long(expected), new Long(actual));
+        assertEquals(message, Long.valueOf(expected), Long.valueOf(actual));
     }
 
     /**
@@ -186,7 +186,7 @@
      * an AssertionFailedError is thrown with the given message.
      */
     static public void assertEquals(String message, byte expected, byte actual) {
-        assertEquals(message, new Byte(expected), new Byte(actual));
+        assertEquals(message, Byte.valueOf(expected), Byte.valueOf(actual));
     }
 
     /**
@@ -201,7 +201,7 @@
      * an AssertionFailedError is thrown with the given message.
      */
     static public void assertEquals(String message, char expected, char actual) {
-        assertEquals(message, new Character(expected), new Character(actual));
+        assertEquals(message, Character.valueOf(expected), Character.valueOf(actual));
     }
 
     /**
@@ -216,7 +216,7 @@
      * an AssertionFailedError is thrown with the given message.
      */
     static public void assertEquals(String message, short expected, short actual) {
-        assertEquals(message, new Short(expected), new Short(actual));
+        assertEquals(message, Short.valueOf(expected), Short.valueOf(actual));
     }
 
     /**
@@ -231,7 +231,7 @@
      * an AssertionFailedError is thrown with the given message.
      */
     static public void assertEquals(String message, int expected, int actual) {
-        assertEquals(message, new Integer(expected), new Integer(actual));
+        assertEquals(message, Integer.valueOf(expected), Integer.valueOf(actual));
     }
 
     /**
diff --git a/src/main/java/junit/framework/AssertionFailedError.java b/src/main/java/junit/framework/AssertionFailedError.java
index 4db094d..e11fbec 100644
--- a/src/main/java/junit/framework/AssertionFailedError.java
+++ b/src/main/java/junit/framework/AssertionFailedError.java
@@ -6,10 +6,19 @@
 public class AssertionFailedError extends AssertionError {
 
     private static final long serialVersionUID = 1L;
-
+    
+    /**
+     * Constructs a new AssertionFailedError without a detail message.
+     */
     public AssertionFailedError() {
     }
 
+    /**
+     * Constructs a new AssertionFailedError with the specified detail message.
+     * A null message is replaced by an empty String.
+     * @param message the detail message. The detail message is saved for later 
+     * retrieval by the {@code Throwable.getMessage()} method.
+     */
     public AssertionFailedError(String message) {
         super(defaultString(message));
     }
diff --git a/src/main/java/junit/framework/ComparisonCompactor.java b/src/main/java/junit/framework/ComparisonCompactor.java
index fa20a8e..81ddd5b 100644
--- a/src/main/java/junit/framework/ComparisonCompactor.java
+++ b/src/main/java/junit/framework/ComparisonCompactor.java
@@ -18,6 +18,7 @@
         fActual = actual;
     }
 
+    @SuppressWarnings("deprecation")
     public String compact(String message) {
         if (fExpected == null || fActual == null || areStringsEqual()) {
             return Assert.format(message, fExpected, fActual);
diff --git a/src/main/java/junit/framework/TestCase.java b/src/main/java/junit/framework/TestCase.java
index b89ce71..e428570 100644
--- a/src/main/java/junit/framework/TestCase.java
+++ b/src/main/java/junit/framework/TestCase.java
@@ -73,6 +73,7 @@
  * @see TestResult
  * @see TestSuite
  */
+@SuppressWarnings("deprecation")
 public abstract class TestCase extends Assert implements Test {
     /**
      * the name of the test case
@@ -187,7 +188,6 @@
      * Asserts that a condition is true. If it isn't it throws
      * an AssertionFailedError with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertTrue(String message, boolean condition) {
         Assert.assertTrue(message, condition);
     }
@@ -196,7 +196,6 @@
      * Asserts that a condition is true. If it isn't it throws
      * an AssertionFailedError.
      */
-    @SuppressWarnings("deprecation")
     public static void assertTrue(boolean condition) {
         Assert.assertTrue(condition);
     }
@@ -205,7 +204,6 @@
      * Asserts that a condition is false. If it isn't it throws
      * an AssertionFailedError with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertFalse(String message, boolean condition) {
         Assert.assertFalse(message, condition);
     }
@@ -214,7 +212,6 @@
      * Asserts that a condition is false. If it isn't it throws
      * an AssertionFailedError.
      */
-    @SuppressWarnings("deprecation")
     public static void assertFalse(boolean condition) {
         Assert.assertFalse(condition);
     }
@@ -222,7 +219,6 @@
     /**
      * Fails a test with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void fail(String message) {
         Assert.fail(message);
     }
@@ -230,7 +226,6 @@
     /**
      * Fails a test with no message.
      */
-    @SuppressWarnings("deprecation")
     public static void fail() {
         Assert.fail();
     }
@@ -239,7 +234,6 @@
      * Asserts that two objects are equal. If they are not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, Object expected, Object actual) {
         Assert.assertEquals(message, expected, actual);
     }
@@ -248,7 +242,6 @@
      * Asserts that two objects are equal. If they are not
      * an AssertionFailedError is thrown.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(Object expected, Object actual) {
         Assert.assertEquals(expected, actual);
     }
@@ -256,7 +249,6 @@
     /**
      * Asserts that two Strings are equal.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, String expected, String actual) {
         Assert.assertEquals(message, expected, actual);
     }
@@ -264,7 +256,6 @@
     /**
      * Asserts that two Strings are equal.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String expected, String actual) {
         Assert.assertEquals(expected, actual);
     }
@@ -274,7 +265,6 @@
      * an AssertionFailedError is thrown with the given message.  If the expected
      * value is infinity then the delta value is ignored.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, double expected, double actual, double delta) {
         Assert.assertEquals(message, expected, actual, delta);
     }
@@ -283,7 +273,6 @@
      * Asserts that two doubles are equal concerning a delta. If the expected
      * value is infinity then the delta value is ignored.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(double expected, double actual, double delta) {
         Assert.assertEquals(expected, actual, delta);
     }
@@ -293,7 +282,6 @@
      * are not an AssertionFailedError is thrown with the given message. If the
      * expected value is infinity then the delta value is ignored.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, float expected, float actual, float delta) {
         Assert.assertEquals(message, expected, actual, delta);
     }
@@ -302,7 +290,6 @@
      * Asserts that two floats are equal concerning a delta. If the expected
      * value is infinity then the delta value is ignored.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(float expected, float actual, float delta) {
         Assert.assertEquals(expected, actual, delta);
     }
@@ -311,7 +298,6 @@
      * Asserts that two longs are equal. If they are not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, long expected, long actual) {
         Assert.assertEquals(message, expected, actual);
     }
@@ -319,7 +305,6 @@
     /**
      * Asserts that two longs are equal.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(long expected, long actual) {
         Assert.assertEquals(expected, actual);
     }
@@ -328,7 +313,6 @@
      * Asserts that two booleans are equal. If they are not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, boolean expected, boolean actual) {
         Assert.assertEquals(message, expected, actual);
     }
@@ -336,7 +320,6 @@
     /**
      * Asserts that two booleans are equal.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(boolean expected, boolean actual) {
         Assert.assertEquals(expected, actual);
     }
@@ -345,7 +328,6 @@
      * Asserts that two bytes are equal. If they are not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, byte expected, byte actual) {
         Assert.assertEquals(message, expected, actual);
     }
@@ -353,7 +335,6 @@
     /**
      * Asserts that two bytes are equal.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(byte expected, byte actual) {
         Assert.assertEquals(expected, actual);
     }
@@ -362,7 +343,6 @@
      * Asserts that two chars are equal. If they are not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, char expected, char actual) {
         Assert.assertEquals(message, expected, actual);
     }
@@ -370,7 +350,6 @@
     /**
      * Asserts that two chars are equal.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(char expected, char actual) {
         Assert.assertEquals(expected, actual);
     }
@@ -379,7 +358,6 @@
      * Asserts that two shorts are equal. If they are not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, short expected, short actual) {
         Assert.assertEquals(message, expected, actual);
     }
@@ -387,7 +365,6 @@
     /**
      * Asserts that two shorts are equal.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(short expected, short actual) {
         Assert.assertEquals(expected, actual);
     }
@@ -396,7 +373,6 @@
      * Asserts that two ints are equal. If they are not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(String message, int expected, int actual) {
         Assert.assertEquals(message, expected, actual);
     }
@@ -404,7 +380,6 @@
     /**
      * Asserts that two ints are equal.
      */
-    @SuppressWarnings("deprecation")
     public static void assertEquals(int expected, int actual) {
         Assert.assertEquals(expected, actual);
     }
@@ -412,7 +387,6 @@
     /**
      * Asserts that an object isn't null.
      */
-    @SuppressWarnings("deprecation")
     public static void assertNotNull(Object object) {
         Assert.assertNotNull(object);
     }
@@ -421,7 +395,6 @@
      * Asserts that an object isn't null. If it is
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertNotNull(String message, Object object) {
         Assert.assertNotNull(message, object);
     }
@@ -433,7 +406,6 @@
      *
      * @param object Object to check or <code>null</code>
      */
-    @SuppressWarnings("deprecation")
     public static void assertNull(Object object) {
         Assert.assertNull(object);
     }
@@ -442,7 +414,6 @@
      * Asserts that an object is null.  If it is not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertNull(String message, Object object) {
         Assert.assertNull(message, object);
     }
@@ -451,7 +422,6 @@
      * Asserts that two objects refer to the same object. If they are not
      * an AssertionFailedError is thrown with the given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertSame(String message, Object expected, Object actual) {
         Assert.assertSame(message, expected, actual);
     }
@@ -460,7 +430,6 @@
      * Asserts that two objects refer to the same object. If they are not
      * the same an AssertionFailedError is thrown.
      */
-    @SuppressWarnings("deprecation")
     public static void assertSame(Object expected, Object actual) {
         Assert.assertSame(expected, actual);
     }
@@ -470,7 +439,6 @@
      * refer to the same object an AssertionFailedError is thrown with the
      * given message.
      */
-    @SuppressWarnings("deprecation")
     public static void assertNotSame(String message, Object expected, Object actual) {
         Assert.assertNotSame(message, expected, actual);
     }
@@ -479,27 +447,22 @@
      * Asserts that two objects do not refer to the same object. If they do
      * refer to the same object an AssertionFailedError is thrown.
      */
-    @SuppressWarnings("deprecation")
     public static void assertNotSame(Object expected, Object actual) {
         Assert.assertNotSame(expected, actual);
     }
 
-    @SuppressWarnings("deprecation")
     public static void failSame(String message) {
         Assert.failSame(message);
     }
 
-    @SuppressWarnings("deprecation")
     public static void failNotSame(String message, Object expected, Object actual) {
         Assert.failNotSame(message, expected, actual);
     }
 
-    @SuppressWarnings("deprecation")
     public static void failNotEquals(String message, Object expected, Object actual) {
         Assert.failNotEquals(message, expected, actual);
     }
 
-    @SuppressWarnings("deprecation")
     public static String format(String message, Object expected, Object actual) {
         return Assert.format(message, expected, actual);
     }
diff --git a/src/main/java/junit/framework/TestFailure.java b/src/main/java/junit/framework/TestFailure.java
index 42f8b05..6168b58 100644
--- a/src/main/java/junit/framework/TestFailure.java
+++ b/src/main/java/junit/framework/TestFailure.java
@@ -5,16 +5,15 @@
 
 
 /**
- * A <code>TestFailure</code> collects a failed test together with
+ * A {@code TestFailure} collects a failed test together with
  * the caught exception.
  *
  * @see TestResult
  */
-public class TestFailure extends Object {
+public class TestFailure {
     protected Test fFailedTest;
     protected Throwable fThrownException;
 
-
     /**
      * Constructs a TestFailure with the given test and exception.
      */
@@ -42,23 +41,32 @@
      */
     @Override
     public String toString() {
-        StringBuffer buffer = new StringBuffer();
-        buffer.append(fFailedTest + ": " + fThrownException.getMessage());
-        return buffer.toString();
+        return fFailedTest + ": " + fThrownException.getMessage();
     }
-
+    
+    /**
+     * Returns a String containing the stack trace of the error
+     * thrown by TestFailure.
+     */
     public String trace() {
         StringWriter stringWriter = new StringWriter();
         PrintWriter writer = new PrintWriter(stringWriter);
         thrownException().printStackTrace(writer);
-        StringBuffer buffer = stringWriter.getBuffer();
-        return buffer.toString();
+        return stringWriter.toString();
     }
 
+    /**
+     * Returns a String containing the message from the thrown exception.
+     */
     public String exceptionMessage() {
         return thrownException().getMessage();
     }
 
+    /**
+     * Returns {@code true} if the error is considered a failure
+     * (i.e. if it is an instance of {@code AssertionFailedError}),
+     * {@code false} otherwise.
+     */
     public boolean isFailure() {
         return thrownException() instanceof AssertionFailedError;
     }
diff --git a/src/main/java/junit/framework/TestListener.java b/src/main/java/junit/framework/TestListener.java
index 980613a..32d1a7f 100644
--- a/src/main/java/junit/framework/TestListener.java
+++ b/src/main/java/junit/framework/TestListener.java
@@ -7,12 +7,12 @@
     /**
      * An error occurred.
      */
-    public void addError(Test test, Throwable t);
+    public void addError(Test test, Throwable e);
 
     /**
      * A failure occurred.
      */
-    public void addFailure(Test test, AssertionFailedError t);
+    public void addFailure(Test test, AssertionFailedError e);
 
     /**
      * A test ended.
diff --git a/src/main/java/junit/framework/TestResult.java b/src/main/java/junit/framework/TestResult.java
index 498478b..8332542 100644
--- a/src/main/java/junit/framework/TestResult.java
+++ b/src/main/java/junit/framework/TestResult.java
@@ -14,7 +14,7 @@
  *
  * @see Test
  */
-public class TestResult extends Object {
+public class TestResult {
     protected List<TestFailure> fFailures;
     protected List<TestFailure> fErrors;
     protected List<TestListener> fListeners;
@@ -33,10 +33,10 @@
      * Adds an error to the list of errors. The passed in exception
      * caused the error.
      */
-    public synchronized void addError(Test test, Throwable t) {
-        fErrors.add(new TestFailure(test, t));
+    public synchronized void addError(Test test, Throwable e) {
+        fErrors.add(new TestFailure(test, e));
         for (TestListener each : cloneListeners()) {
-            each.addError(test, t);
+            each.addError(test, e);
         }
     }
 
@@ -44,10 +44,10 @@
      * Adds a failure to the list of failures. The passed in exception
      * caused the failure.
      */
-    public synchronized void addFailure(Test test, AssertionFailedError t) {
-        fFailures.add(new TestFailure(test, t));
+    public synchronized void addFailure(Test test, AssertionFailedError e) {
+        fFailures.add(new TestFailure(test, e));
         for (TestListener each : cloneListeners()) {
-            each.addFailure(test, t);
+            each.addFailure(test, e);
         }
     }
 
@@ -182,4 +182,4 @@
     public synchronized boolean wasSuccessful() {
         return failureCount() == 0 && errorCount() == 0;
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/junit/framework/TestSuite.java b/src/main/java/junit/framework/TestSuite.java
index 0c629da..366f1cf 100644
--- a/src/main/java/junit/framework/TestSuite.java
+++ b/src/main/java/junit/framework/TestSuite.java
@@ -14,7 +14,7 @@
 import org.junit.internal.MethodSorter;
 
 /**
- * <p>A <code>TestSuite</code> is a <code>Composite</code> of Tests.
+ * A <code>TestSuite</code> is a <code>Composite</code> of Tests.
  * It runs a collection of test cases. Here is an example using
  * the dynamic test definition.
  * <pre>
@@ -22,25 +22,22 @@
  * suite.addTest(new MathTest("testAdd"));
  * suite.addTest(new MathTest("testDivideByZero"));
  * </pre>
- * </p>
- *
- * <p>Alternatively, a TestSuite can extract the tests to be run automatically.
+ * <p>
+ * Alternatively, a TestSuite can extract the tests to be run automatically.
  * To do so you pass the class of your TestCase class to the
  * TestSuite constructor.
  * <pre>
  * TestSuite suite= new TestSuite(MathTest.class);
  * </pre>
- * </p>
- *
- * <p>This constructor creates a suite with all the methods
- * starting with "test" that take no arguments.</p>
- *
- * <p>A final option is to do the same for a large array of test classes.
+ * <p>
+ * This constructor creates a suite with all the methods
+ * starting with "test" that take no arguments.
+ * <p>
+ * A final option is to do the same for a large array of test classes.
  * <pre>
  * Class[] testClasses = { MathTest.class, AnotherTest.class }
  * TestSuite suite= new TestSuite(testClasses);
  * </pre>
- * </p>
  *
  * @see Test
  */
@@ -105,10 +102,10 @@
     /**
      * Converts the stack trace into a string
      */
-    private static String exceptionToString(Throwable t) {
+    private static String exceptionToString(Throwable e) {
         StringWriter stringWriter = new StringWriter();
         PrintWriter writer = new PrintWriter(stringWriter);
-        t.printStackTrace(writer);
+        e.printStackTrace(writer);
         return stringWriter.toString();
     }
 
diff --git a/src/main/java/junit/runner/BaseTestRunner.java b/src/main/java/junit/runner/BaseTestRunner.java
index ced137e..8268323 100644
--- a/src/main/java/junit/runner/BaseTestRunner.java
+++ b/src/main/java/junit/runner/BaseTestRunner.java
@@ -70,12 +70,12 @@
         testEnded(test.toString());
     }
 
-    public synchronized void addError(final Test test, final Throwable t) {
-        testFailed(TestRunListener.STATUS_ERROR, test, t);
+    public synchronized void addError(final Test test, final Throwable e) {
+        testFailed(TestRunListener.STATUS_ERROR, test, e);
     }
 
-    public synchronized void addFailure(final Test test, final AssertionFailedError t) {
-        testFailed(TestRunListener.STATUS_FAILURE, test, t);
+    public synchronized void addFailure(final Test test, final AssertionFailedError e) {
+        testFailed(TestRunListener.STATUS_FAILURE, test, e);
     }
 
     // TestRunListener implementation
@@ -84,7 +84,7 @@
 
     public abstract void testEnded(String testName);
 
-    public abstract void testFailed(int status, Test test, Throwable t);
+    public abstract void testFailed(int status, Test test, Throwable e);
 
     /**
      * Returns the Test corresponding to the given suite. This is
@@ -232,7 +232,8 @@
             is = new FileInputStream(getPreferencesFile());
             setPreferences(new Properties(getPreferences()));
             getPreferences().load(is);
-        } catch (IOException e) {
+        } catch (IOException ignored) {
+        } finally {
             try {
                 if (is != null) {
                     is.close();
@@ -262,12 +263,11 @@
     /**
      * Returns a filtered stack trace
      */
-    public static String getFilteredTrace(Throwable t) {
+    public static String getFilteredTrace(Throwable e) {
         StringWriter stringWriter = new StringWriter();
         PrintWriter writer = new PrintWriter(stringWriter);
-        t.printStackTrace(writer);
-        StringBuffer buffer = stringWriter.getBuffer();
-        String trace = buffer.toString();
+        e.printStackTrace(writer);
+        String trace = stringWriter.toString();
         return BaseTestRunner.getFilteredTrace(trace);
     }
 
diff --git a/src/main/java/junit/runner/Version.java b/src/main/java/junit/runner/Version.java
index eaf3db7..975ef7c 100644
--- a/src/main/java/junit/runner/Version.java
+++ b/src/main/java/junit/runner/Version.java
@@ -9,7 +9,7 @@
 	}
 
 	public static String id() {
-		return "4.12-SNAPSHOT";
+		return "4.13-SNAPSHOT";
 	}
 	
 	public static void main(String[] args) {
diff --git a/src/main/java/junit/textui/ResultPrinter.java b/src/main/java/junit/textui/ResultPrinter.java
index 310ab3f..95f10f4 100644
--- a/src/main/java/junit/textui/ResultPrinter.java
+++ b/src/main/java/junit/textui/ResultPrinter.java
@@ -106,7 +106,7 @@
     /**
      * @see junit.framework.TestListener#addError(Test, Throwable)
      */
-    public void addError(Test test, Throwable t) {
+    public void addError(Test test, Throwable e) {
         getWriter().print("E");
     }
 
diff --git a/src/main/java/junit/textui/TestRunner.java b/src/main/java/junit/textui/TestRunner.java
index 8714881..913020a 100644
--- a/src/main/java/junit/textui/TestRunner.java
+++ b/src/main/java/junit/textui/TestRunner.java
@@ -15,17 +15,17 @@
  * <pre>
  * java junit.textui.TestRunner [-wait] TestCaseClass
  * </pre>
- *
- * <p>TestRunner expects the name of a TestCase class as argument.
+ * <p>
+ * TestRunner expects the name of a TestCase class as argument.
  * If this class defines a static <code>suite</code> method it
  * will be invoked and the returned test is run. Otherwise all
- * the methods starting with "test" having no arguments are run.</p>
- *
- * <p> When the wait command line argument is given TestRunner
- * waits until the users types RETURN.</p>
- *
- * <p>TestRunner prints a trace as the tests are executed followed by a
- * summary at the end.</p>
+ * the methods starting with "test" having no arguments are run.
+ * <p>
+ * When the wait command line argument is given TestRunner
+ * waits until the users types RETURN.
+ * <p>
+ * TestRunner prints a trace as the tests are executed followed by a
+ * summary at the end.
  */
 public class TestRunner extends BaseTestRunner {
     private ResultPrinter fPrinter;
@@ -87,7 +87,7 @@
     }
 
     @Override
-    public void testFailed(int status, Test test, Throwable t) {
+    public void testFailed(int status, Test test, Throwable e) {
     }
 
     @Override
@@ -131,7 +131,7 @@
         }
     }
 
-    public static void main(String args[]) {
+    public static void main(String[] args) {
         TestRunner aTestRunner = new TestRunner();
         try {
             TestResult r = aTestRunner.start(args);
@@ -149,7 +149,7 @@
      * Starts a test run. Analyzes the command line arguments and runs the given
      * test suite.
      */
-    public TestResult start(String args[]) throws Exception {
+    public TestResult start(String[] args) throws Exception {
         String testCase = "";
         String method = "";
         boolean wait = false;
diff --git a/src/main/java/org/junit/After.java b/src/main/java/org/junit/After.java
index d4896fc..eae7e3a 100644
--- a/src/main/java/org/junit/After.java
+++ b/src/main/java/org/junit/After.java
@@ -6,13 +6,13 @@
 import java.lang.annotation.Target;
 
 /**
- * <p>If you allocate external resources in a {@link org.junit.Before} method you need to release them
+ * If you allocate external resources in a {@link org.junit.Before} method you need to release them
  * after the test runs. Annotating a <code>public void</code> method
  * with <code>&#064;After</code> causes that method to be run after the {@link org.junit.Test} method. All <code>&#064;After</code>
  * methods are guaranteed to run even if a {@link org.junit.Before} or {@link org.junit.Test} method throws an
  * exception. The <code>&#064;After</code> methods declared in superclasses will be run after those of the current
- * class, unless they are overridden in the current class.</p>
- *
+ * class, unless they are overridden in the current class.
+ * <p>
  * Here is a simple example:
  * <pre>
  * public class Example {
diff --git a/src/main/java/org/junit/AfterClass.java b/src/main/java/org/junit/AfterClass.java
index 126464b..dba4109 100644
--- a/src/main/java/org/junit/AfterClass.java
+++ b/src/main/java/org/junit/AfterClass.java
@@ -6,13 +6,13 @@
 import java.lang.annotation.Target;
 
 /**
- * <p>If you allocate expensive external resources in a {@link org.junit.BeforeClass} method you need to release them
+ * If you allocate expensive external resources in a {@link org.junit.BeforeClass} method you need to release them
  * after all the tests in the class have run. Annotating a <code>public static void</code> method
  * with <code>&#064;AfterClass</code> causes that method to be run after all the tests in the class have been run. All <code>&#064;AfterClass</code>
  * methods are guaranteed to run even if a {@link org.junit.BeforeClass} method throws an
  * exception. The <code>&#064;AfterClass</code> methods declared in superclasses will be run after those of the current
- * class, unless they are shadowed in the current class.</p>
- *
+ * class, unless they are shadowed in the current class.
+ * <p>
  * Here is a simple example:
  * <pre>
  * public class Example {
diff --git a/src/main/java/org/junit/Assert.java b/src/main/java/org/junit/Assert.java
index 8946076..c775035 100755
--- a/src/main/java/org/junit/Assert.java
+++ b/src/main/java/org/junit/Assert.java
@@ -10,7 +10,7 @@
  * A set of assertion methods useful for writing tests. Only failed assertions
  * are recorded. These methods can be used directly:
  * <code>Assert.assertEquals(...)</code>, however, they read better if they
- * are referenced through static import:<br/>
+ * are referenced through static import:
  *
  * <pre>
  * import static org.junit.Assert.*;
@@ -36,7 +36,7 @@
      * okay)
      * @param condition condition to be checked
      */
-    static public void assertTrue(String message, boolean condition) {
+    public static void assertTrue(String message, boolean condition) {
         if (!condition) {
             fail(message);
         }
@@ -48,7 +48,7 @@
      *
      * @param condition condition to be checked
      */
-    static public void assertTrue(boolean condition) {
+    public static void assertTrue(boolean condition) {
         assertTrue(null, condition);
     }
 
@@ -60,7 +60,7 @@
      * okay)
      * @param condition condition to be checked
      */
-    static public void assertFalse(String message, boolean condition) {
+    public static void assertFalse(String message, boolean condition) {
         assertTrue(message, !condition);
     }
 
@@ -70,7 +70,7 @@
      *
      * @param condition condition to be checked
      */
-    static public void assertFalse(boolean condition) {
+    public static void assertFalse(boolean condition) {
         assertFalse(null, condition);
     }
 
@@ -81,7 +81,7 @@
      * okay)
      * @see AssertionError
      */
-    static public void fail(String message) {
+    public static void fail(String message) {
         if (message == null) {
             throw new AssertionError();
         }
@@ -91,7 +91,7 @@
     /**
      * Fails a test with no message.
      */
-    static public void fail() {
+    public static void fail() {
         fail(null);
     }
 
@@ -106,11 +106,12 @@
      * @param expected expected value
      * @param actual actual value
      */
-    static public void assertEquals(String message, Object expected,
+    public static void assertEquals(String message, Object expected,
             Object actual) {
         if (equalsRegardingNull(expected, actual)) {
             return;
-        } else if (expected instanceof String && actual instanceof String) {
+        }
+        if (expected instanceof String && actual instanceof String) {
             String cleanMessage = message == null ? "" : message;
             throw new ComparisonFailure(cleanMessage, (String) expected,
                     (String) actual);
@@ -140,7 +141,7 @@
      * @param expected expected value
      * @param actual the value to check against <code>expected</code>
      */
-    static public void assertEquals(Object expected, Object actual) {
+    public static void assertEquals(Object expected, Object actual) {
         assertEquals(null, expected, actual);
     }
 
@@ -155,7 +156,7 @@
      * @param unexpected unexpected value to check
      * @param actual the value to check against <code>unexpected</code>
      */
-    static public void assertNotEquals(String message, Object unexpected,
+    public static void assertNotEquals(String message, Object unexpected,
             Object actual) {
         if (equalsRegardingNull(unexpected, actual)) {
             failEquals(message, actual);
@@ -171,7 +172,7 @@
      * @param unexpected unexpected value to check
      * @param actual the value to check against <code>unexpected</code>
      */
-    static public void assertNotEquals(Object unexpected, Object actual) {
+    public static void assertNotEquals(Object unexpected, Object actual) {
         assertNotEquals(null, unexpected, actual);
     }
 
@@ -194,8 +195,10 @@
      * @param unexpected unexpected value to check
      * @param actual the value to check against <code>unexpected</code>
      */
-    static public void assertNotEquals(String message, long unexpected, long actual) {
-        assertNotEquals(message, (Long) unexpected, (Long) actual);
+    public static void assertNotEquals(String message, long unexpected, long actual) {
+        if (unexpected == actual) {
+            failEquals(message, Long.valueOf(actual));
+        }
     }
 
     /**
@@ -205,7 +208,7 @@
      * @param unexpected unexpected value to check
      * @param actual the value to check against <code>unexpected</code>
      */
-    static public void assertNotEquals(long unexpected, long actual) {
+    public static void assertNotEquals(long unexpected, long actual) {
         assertNotEquals(null, unexpected, actual);
     }
 
@@ -224,10 +227,10 @@
      * <code>actual</code> for which both numbers are still
      * considered equal.
      */
-    static public void assertNotEquals(String message, double unexpected,
+    public static void assertNotEquals(String message, double unexpected,
             double actual, double delta) {
         if (!doubleIsDifferent(unexpected, actual, delta)) {
-            failEquals(message, new Double(actual));
+            failEquals(message, Double.valueOf(actual));
         }
     }
 
@@ -243,7 +246,7 @@
      * <code>actual</code> for which both numbers are still
      * considered equal.
      */
-    static public void assertNotEquals(double unexpected, double actual, double delta) {
+    public static void assertNotEquals(double unexpected, double actual, double delta) {
         assertNotEquals(null, unexpected, actual, delta);
     }
 
@@ -259,7 +262,7 @@
      * <code>actual</code> for which both numbers are still
      * considered equal.
      */
-    static public void assertNotEquals(float unexpected, float actual, float delta) {
+    public static void assertNotEquals(float unexpected, float actual, float delta) {
         assertNotEquals(null, unexpected, actual, delta);
     }
 
@@ -295,6 +298,35 @@
     public static void assertArrayEquals(Object[] expecteds, Object[] actuals) {
         assertArrayEquals(null, expecteds, actuals);
     }
+    
+    /**
+     * Asserts that two boolean arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown with the given message. If
+     * <code>expecteds</code> and <code>actuals</code> are <code>null</code>,
+     * they are considered equal.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     * okay)
+     * @param expecteds boolean array with expected values.
+     * @param actuals boolean array with expected values.
+     */
+    public static void assertArrayEquals(String message, boolean[] expecteds,
+            boolean[] actuals) throws ArrayComparisonFailure {
+        internalArrayEquals(message, expecteds, actuals);
+    }    
+    
+    /**
+     * Asserts that two boolean arrays are equal. If they are not, an
+     * {@link AssertionError} is thrown. If <code>expected</code> and
+     * <code>actual</code> are <code>null</code>, they are considered
+     * equal.
+     *
+     * @param expecteds boolean array with expected values.
+     * @param actuals boolean array with expected values.
+     */
+    public static void assertArrayEquals(boolean[] expecteds, boolean[] actuals) {
+        assertArrayEquals(null, expecteds, actuals);
+    }
 
     /**
      * Asserts that two byte arrays are equal. If they are not, an
@@ -429,6 +461,9 @@
      * okay)
      * @param expecteds double array with expected values.
      * @param actuals double array with actual values
+     * @param delta the maximum delta between <code>expecteds[i]</code> and
+     * <code>actuals[i]</code> for which both numbers are still
+     * considered equal.
      */
     public static void assertArrayEquals(String message, double[] expecteds,
             double[] actuals, double delta) throws ArrayComparisonFailure {
@@ -441,6 +476,9 @@
      *
      * @param expecteds double array with expected values.
      * @param actuals double array with actual values
+     * @param delta the maximum delta between <code>expecteds[i]</code> and
+     * <code>actuals[i]</code> for which both numbers are still
+     * considered equal.
      */
     public static void assertArrayEquals(double[] expecteds, double[] actuals, double delta) {
         assertArrayEquals(null, expecteds, actuals, delta);
@@ -454,6 +492,9 @@
      * okay)
      * @param expecteds float array with expected values.
      * @param actuals float array with actual values
+     * @param delta the maximum delta between <code>expecteds[i]</code> and
+     * <code>actuals[i]</code> for which both numbers are still
+     * considered equal.
      */
     public static void assertArrayEquals(String message, float[] expecteds,
             float[] actuals, float delta) throws ArrayComparisonFailure {
@@ -466,6 +507,9 @@
      *
      * @param expecteds float array with expected values.
      * @param actuals float array with actual values
+     * @param delta the maximum delta between <code>expecteds[i]</code> and
+     * <code>actuals[i]</code> for which both numbers are still
+     * considered equal.
      */
     public static void assertArrayEquals(float[] expecteds, float[] actuals, float delta) {
         assertArrayEquals(null, expecteds, actuals, delta);
@@ -504,10 +548,10 @@
      * <code>actual</code> for which both numbers are still
      * considered equal.
      */
-    static public void assertEquals(String message, double expected,
+    public static void assertEquals(String message, double expected,
             double actual, double delta) {
         if (doubleIsDifferent(expected, actual, delta)) {
-            failNotEquals(message, new Double(expected), new Double(actual));
+            failNotEquals(message, Double.valueOf(expected), Double.valueOf(actual));
         }
     }
 
@@ -526,10 +570,10 @@
      * <code>actual</code> for which both numbers are still
      * considered equal.
      */
-    static public void assertEquals(String message, float expected,
+    public static void assertEquals(String message, float expected,
             float actual, float delta) {
         if (floatIsDifferent(expected, actual, delta)) {
-            failNotEquals(message, new Float(expected), new Float(actual));
+            failNotEquals(message, Float.valueOf(expected), Float.valueOf(actual));
         }
     }
 
@@ -548,14 +592,14 @@
      * <code>actual</code> for which both numbers are still
      * considered equal.
      */
-    static public void assertNotEquals(String message, float unexpected,
+    public static void assertNotEquals(String message, float unexpected,
             float actual, float delta) {
         if (!floatIsDifferent(unexpected, actual, delta)) {
-            failEquals(message, new Float(actual));
+            failEquals(message, actual);
         }
     }
 
-    static private boolean doubleIsDifferent(double d1, double d2, double delta) {
+    private static boolean doubleIsDifferent(double d1, double d2, double delta) {
         if (Double.compare(d1, d2) == 0) {
             return false;
         }
@@ -566,7 +610,7 @@
         return true;
     }
 
-    static private boolean floatIsDifferent(float f1, float f2, float delta) {
+    private static boolean floatIsDifferent(float f1, float f2, float delta) {
         if (Float.compare(f1, f2) == 0) {
             return false;
         }
@@ -584,7 +628,7 @@
      * @param expected expected long value.
      * @param actual actual long value
      */
-    static public void assertEquals(long expected, long actual) {
+    public static void assertEquals(long expected, long actual) {
         assertEquals(null, expected, actual);
     }
 
@@ -597,8 +641,10 @@
      * @param expected long expected value.
      * @param actual long actual value
      */
-    static public void assertEquals(String message, long expected, long actual) {
-        assertEquals(message, (Long) expected, (Long) actual);
+    public static void assertEquals(String message, long expected, long actual) {
+        if (expected != actual) {
+            failNotEquals(message, Long.valueOf(expected), Long.valueOf(actual));
+        }
     }
 
     /**
@@ -607,7 +653,7 @@
      *             instead
      */
     @Deprecated
-    static public void assertEquals(double expected, double actual) {
+    public static void assertEquals(double expected, double actual) {
         assertEquals(null, expected, actual);
     }
 
@@ -617,7 +663,7 @@
      *             instead
      */
     @Deprecated
-    static public void assertEquals(String message, double expected,
+    public static void assertEquals(String message, double expected,
             double actual) {
         fail("Use assertEquals(expected, actual, delta) to compare floating-point numbers");
     }
@@ -634,7 +680,7 @@
      * <code>actual</code> for which both numbers are still
      * considered equal.
      */
-    static public void assertEquals(double expected, double actual, double delta) {
+    public static void assertEquals(double expected, double actual, double delta) {
         assertEquals(null, expected, actual, delta);
     }
 
@@ -650,8 +696,7 @@
      * <code>actual</code> for which both numbers are still
      * considered equal.
      */
-
-    static public void assertEquals(float expected, float actual, float delta) {
+    public static void assertEquals(float expected, float actual, float delta) {
         assertEquals(null, expected, actual, delta);
     }
 
@@ -663,7 +708,7 @@
      * okay)
      * @param object Object to check or <code>null</code>
      */
-    static public void assertNotNull(String message, Object object) {
+    public static void assertNotNull(String message, Object object) {
         assertTrue(message, object != null);
     }
 
@@ -673,7 +718,7 @@
      *
      * @param object Object to check or <code>null</code>
      */
-    static public void assertNotNull(Object object) {
+    public static void assertNotNull(Object object) {
         assertNotNull(null, object);
     }
 
@@ -685,7 +730,7 @@
      * okay)
      * @param object Object to check or <code>null</code>
      */
-    static public void assertNull(String message, Object object) {
+    public static void assertNull(String message, Object object) {
         if (object == null) {
             return;
         }
@@ -698,11 +743,11 @@
      *
      * @param object Object to check or <code>null</code>
      */
-    static public void assertNull(Object object) {
+    public static void assertNull(Object object) {
         assertNull(null, object);
     }
 
-    static private void failNotNull(String message, Object actual) {
+    private static void failNotNull(String message, Object actual) {
         String formatted = "";
         if (message != null) {
             formatted = message + " ";
@@ -719,7 +764,7 @@
      * @param expected the expected object
      * @param actual the object to compare to <code>expected</code>
      */
-    static public void assertSame(String message, Object expected, Object actual) {
+    public static void assertSame(String message, Object expected, Object actual) {
         if (expected == actual) {
             return;
         }
@@ -733,7 +778,7 @@
      * @param expected the expected object
      * @param actual the object to compare to <code>expected</code>
      */
-    static public void assertSame(Object expected, Object actual) {
+    public static void assertSame(Object expected, Object actual) {
         assertSame(null, expected, actual);
     }
 
@@ -747,7 +792,7 @@
      * @param unexpected the object you don't expect
      * @param actual the object to compare to <code>unexpected</code>
      */
-    static public void assertNotSame(String message, Object unexpected,
+    public static void assertNotSame(String message, Object unexpected,
             Object actual) {
         if (unexpected == actual) {
             failSame(message);
@@ -762,11 +807,11 @@
      * @param unexpected the object you don't expect
      * @param actual the object to compare to <code>unexpected</code>
      */
-    static public void assertNotSame(Object unexpected, Object actual) {
+    public static void assertNotSame(Object unexpected, Object actual) {
         assertNotSame(null, unexpected, actual);
     }
 
-    static private void failSame(String message) {
+    private static void failSame(String message) {
         String formatted = "";
         if (message != null) {
             formatted = message + " ";
@@ -774,7 +819,7 @@
         fail(formatted + "expected not same");
     }
 
-    static private void failNotSame(String message, Object expected,
+    private static void failNotSame(String message, Object expected,
             Object actual) {
         String formatted = "";
         if (message != null) {
@@ -784,14 +829,14 @@
                 + ">");
     }
 
-    static private void failNotEquals(String message, Object expected,
+    private static void failNotEquals(String message, Object expected,
             Object actual) {
         fail(format(message, expected, actual));
     }
 
     static String format(String message, Object expected, Object actual) {
         String formatted = "";
-        if (message != null && !message.equals("")) {
+        if (message != null && !"".equals(message)) {
             formatted = message + " ";
         }
         String expectedString = String.valueOf(expected);
diff --git a/src/main/java/org/junit/Assume.java b/src/main/java/org/junit/Assume.java
index 73f8b5a..69fac45 100644
--- a/src/main/java/org/junit/Assume.java
+++ b/src/main/java/org/junit/Assume.java
@@ -7,22 +7,19 @@
 import static org.hamcrest.CoreMatchers.nullValue;
 
 import org.hamcrest.Matcher;
-import org.junit.internal.AssumptionViolatedException;
 
 /**
  * A set of methods useful for stating assumptions about the conditions in which a test is meaningful.
- * A failed assumption does not mean the code is broken, but that the test provides no useful information.
- * The default JUnit runner treats tests with failing assumptions as ignored.  Custom runners may behave differently.
+ * A failed assumption does not mean the code is broken, but that the test provides no useful information. Assume
+ * basically means "don't run this test if these conditions don't apply". The default JUnit runner skips tests with
+ * failing assumptions. Custom runners may behave differently.
+ * <p>
+ *     A good example of using assumptions is in <a href="https://github.com/junit-team/junit/wiki/Theories">Theories</a> where they are needed to exclude certain datapoints that aren't suitable or allowed for a certain test case.
+ * </p>
+ * Failed assumptions are usually not logged, because there may be many tests that don't apply to certain
+ * configurations.
  *
- * For example:
- * <pre>
- * // only provides information if database is reachable.
- * \@Test public void calculateTotalSalary() {
- *    DBConnection dbc = Database.connect();
- *    assumeNotNull(dbc);
- *    // ...
- * }
- * </pre>
+ * <p>
  * These methods can be used directly: <code>Assume.assumeTrue(...)</code>, however, they
  * read better if they are referenced through static import:<br/>
  * <pre>
@@ -30,10 +27,22 @@
  *    ...
  *    assumeTrue(...);
  * </pre>
+ * </p>
+ *
+ * @see <a href="https://github.com/junit-team/junit/wiki/Theories">Theories</a>
  *
  * @since 4.4
  */
 public class Assume {
+
+    /**
+     * Do not instantiate.
+     * @deprecated since 4.13.
+     */
+    @Deprecated
+    public Assume() {
+    }
+
     /**
      * If called with an expression evaluating to {@code false}, the test will halt and be ignored.
      */
@@ -101,9 +110,9 @@
      * If not, the test halts and is ignored.
      * Example:
      * <pre>:
-     *   assumeThat(1, is(1)); // passes
+     *   assumeThat("alwaysPasses", 1, is(1)); // passes
      *   foo(); // will execute
-     *   assumeThat(0, is(1)); // assumption failure! test halts
+     *   assumeThat("alwaysFails", 0, is(1)); // assumption failure! test halts
      *   int x = 1 / 0; // will never execute
      * </pre>
      *
@@ -120,7 +129,7 @@
     }
 
     /**
-     * Use to assume that an operation completes normally.  If {@code t} is non-null, the test will halt and be ignored.
+     * Use to assume that an operation completes normally.  If {@code e} is non-null, the test will halt and be ignored.
      *
      * For example:
      * <pre>
@@ -136,23 +145,23 @@
      * }
      * </pre>
      *
-     * @param t if non-null, the offending exception
+     * @param e if non-null, the offending exception
      */
-    public static void assumeNoException(Throwable t) {
-        assumeThat(t, nullValue());
+    public static void assumeNoException(Throwable e) {
+        assumeThat(e, nullValue());
     }
 
     /**
-     * Attempts to halt the test and ignore it if Throwable <code>t</code> is
+     * Attempts to halt the test and ignore it if Throwable <code>e</code> is
      * not <code>null</code>. Similar to {@link #assumeNoException(Throwable)},
      * but provides an additional message that can explain the details
      * concerning the assumption.
      *
-     * @param t if non-null, the offending exception
+     * @param e if non-null, the offending exception
      * @param message Additional message to pass to {@link AssumptionViolatedException}.
      * @see #assumeNoException(Throwable)
      */
-    public static void assumeNoException(String message, Throwable t) {
-        assumeThat(message, t, nullValue());
+    public static void assumeNoException(String message, Throwable e) {
+        assumeThat(message, e, nullValue());
     }
 }
diff --git a/src/main/java/org/junit/AssumptionViolatedException.java b/src/main/java/org/junit/AssumptionViolatedException.java
new file mode 100644
index 0000000..e48ddf0
--- /dev/null
+++ b/src/main/java/org/junit/AssumptionViolatedException.java
@@ -0,0 +1,46 @@
+package org.junit;
+
+import org.hamcrest.Matcher;
+
+/**
+ * An exception class used to implement <i>assumptions</i> (state in which a given test
+ * is meaningful and should or should not be executed). A test for which an assumption
+ * fails should not generate a test case failure.
+ *
+ * @see org.junit.Assume
+ * @since 4.12
+ */
+@SuppressWarnings("deprecation")
+public class AssumptionViolatedException extends org.junit.internal.AssumptionViolatedException {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * An assumption exception with the given <i>actual</i> value and a <i>matcher</i> describing 
+     * the expectation that failed.
+     */
+    public <T> AssumptionViolatedException(T actual, Matcher<T> matcher) {
+        super(actual, matcher);
+    }
+
+    /**
+     * An assumption exception with a message with the given <i>actual</i> value and a
+     * <i>matcher</i> describing the expectation that failed.
+     */
+    public <T> AssumptionViolatedException(String message, T expected, Matcher<T> matcher) {
+        super(message, expected, matcher);
+    }
+
+    /**
+     * An assumption exception with the given message only.
+     */
+    public AssumptionViolatedException(String message) {
+        super(message);
+    }
+
+    /**
+     * An assumption exception with the given message and a cause.
+     */
+    public AssumptionViolatedException(String assumption, Throwable t) {
+        super(assumption, t);
+    }
+}
diff --git a/src/main/java/org/junit/Before.java b/src/main/java/org/junit/Before.java
index 2fb63f2..def8adb 100644
--- a/src/main/java/org/junit/Before.java
+++ b/src/main/java/org/junit/Before.java
@@ -6,13 +6,12 @@
 import java.lang.annotation.Target;
 
 /**
- * <p>When writing tests, it is common to find that several tests need similar
+ * When writing tests, it is common to find that several tests need similar
  * objects created before they can run. Annotating a <code>public void</code> method
  * with <code>&#064;Before</code> causes that method to be run before the {@link org.junit.Test} method.
  * The <code>&#064;Before</code> methods of superclasses will be run before those of the current class,
  * unless they are overridden in the current class. No other ordering is defined.
- * </p>
- *
+ * <p>
  * Here is a simple example:
  * <pre>
  * public class Example {
diff --git a/src/main/java/org/junit/BeforeClass.java b/src/main/java/org/junit/BeforeClass.java
index b0479de..8183fa0 100644
--- a/src/main/java/org/junit/BeforeClass.java
+++ b/src/main/java/org/junit/BeforeClass.java
@@ -6,13 +6,13 @@
 import java.lang.annotation.Target;
 
 /**
- * <p>Sometimes several tests need to share computationally expensive setup
+ * Sometimes several tests need to share computationally expensive setup
  * (like logging into a database). While this can compromise the independence of
  * tests, sometimes it is a necessary optimization. Annotating a <code>public static void</code> no-arg method
  * with <code>@BeforeClass</code> causes it to be run once before any of
  * the test methods in the class. The <code>@BeforeClass</code> methods of superclasses
- * will be run before those the current class, unless they are shadowed in the current class.</p>
- *
+ * will be run before those of the current class, unless they are shadowed in the current class.
+ * <p>
  * For example:
  * <pre>
  * public class Example {
diff --git a/src/main/java/org/junit/ClassRule.java b/src/main/java/org/junit/ClassRule.java
index 586fb84..02c40a7 100644
--- a/src/main/java/org/junit/ClassRule.java
+++ b/src/main/java/org/junit/ClassRule.java
@@ -8,14 +8,14 @@
 /**
  * Annotates static fields that reference 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}.<p>
- *
+ * a subtype of {@link org.junit.rules.TestRule}.
+ * <p>
  * 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
  * a standard JUnit test class, or all contained classes, if it is a
  * {@link org.junit.runners.Suite}), and finally any {@link AfterClass} methods.
- *
+ * <p>
  * The statement passed to the {@link org.junit.rules.TestRule} will never throw an exception,
  * and throwing an exception from the {@link org.junit.rules.TestRule} will result in undefined
  * behavior.  This means that some {@link org.junit.rules.TestRule}s, such as
@@ -23,16 +23,15 @@
  * {@link org.junit.rules.ExpectedException},
  * and {@link org.junit.rules.Timeout},
  * have undefined behavior when used as {@link ClassRule}s.
- *
+ * <p>
  * 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. However, Rules defined by fields will always be applied
  * before Rules defined by methods.
- *
+ * <p>
  * 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})
@@ -53,9 +52,8 @@
  *   };
  * }
  * </pre>
- *
+ * <p>
  * and the same using a method
- *
  * <pre>
  * &#064;RunWith(Suite.class)
  * &#064;SuiteClasses({A.class, B.class, C.class})
@@ -78,7 +76,7 @@
  *     }
  * }
  * </pre>
- *
+ * <p>
  * For more information and more examples, see {@link org.junit.rules.TestRule}.
  *
  * @since 4.9
diff --git a/src/main/java/org/junit/ComparisonFailure.java b/src/main/java/org/junit/ComparisonFailure.java
index b179663..9563e61 100644
--- a/src/main/java/org/junit/ComparisonFailure.java
+++ b/src/main/java/org/junit/ComparisonFailure.java
@@ -1,23 +1,28 @@
 package org.junit;
 
 /**
- * Thrown when an {@link org.junit.Assert#assertEquals(Object, Object) assertEquals(String, String)} fails. Create and throw
- * a <code>ComparisonFailure</code> manually if you want to show users the difference between two complex
- * strings.
- *
+ * Thrown when an {@link org.junit.Assert#assertEquals(Object, Object) assertEquals(String, String)} fails.
+ * Create and throw a <code>ComparisonFailure</code> manually if you want to show users the
+ * difference between two complex strings.
+ * <p/>
  * Inspired by a patch from Alex Chaffee (alex@purpletech.com)
  *
  * @since 4.0
  */
 public class ComparisonFailure extends AssertionError {
     /**
-     * The maximum length for fExpected and fActual. If it is exceeded, the strings should be shortened.
+     * The maximum length for expected and actual strings. If it is exceeded, the strings should be shortened.
      *
      * @see ComparisonCompactor
      */
     private static final int MAX_CONTEXT_LENGTH = 20;
     private static final long serialVersionUID = 1L;
 
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
     private String fExpected;
     private String fActual;
 
@@ -30,13 +35,12 @@
      */
     public ComparisonFailure(String message, String expected, String actual) {
         super(message);
-        fExpected = expected;
-        fActual = actual;
+        this.fExpected = expected;
+        this.fActual = actual;
     }
 
     /**
-     * Returns "..." in place of common prefix and "..." in
-     * place of common suffix between expected and actual.
+     * Returns "..." in place of common prefix and "..." in place of common suffix between expected and actual.
      *
      * @see Throwable#getMessage()
      */
@@ -65,86 +69,103 @@
 
     private static class ComparisonCompactor {
         private static final String ELLIPSIS = "...";
-        private static final String DELTA_END = "]";
-        private static final String DELTA_START = "[";
+        private static final String DIFF_END = "]";
+        private static final String DIFF_START = "[";
 
         /**
-         * The maximum length for <code>expected</code> and <code>actual</code>. When <code>contextLength</code>
-         * is exceeded, the Strings are shortened
+         * The maximum length for <code>expected</code> and <code>actual</code> strings to show. When
+         * <code>contextLength</code> is exceeded, the Strings are shortened.
          */
-        private int fContextLength;
-        private String fExpected;
-        private String fActual;
-        private int fPrefix;
-        private int fSuffix;
+        private final int contextLength;
+        private final String expected;
+        private final String actual;
 
         /**
-         * @param contextLength the maximum length for <code>expected</code> and <code>actual</code>. When contextLength
-         * is exceeded, the Strings are shortened
+         * @param contextLength the maximum length of context surrounding the difference between the compared strings.
+         * When context length is exceeded, the prefixes and suffixes are compacted.
          * @param expected the expected string value
          * @param actual the actual string value
          */
         public ComparisonCompactor(int contextLength, String expected, String actual) {
-            fContextLength = contextLength;
-            fExpected = expected;
-            fActual = actual;
+            this.contextLength = contextLength;
+            this.expected = expected;
+            this.actual = actual;
         }
 
-        private String compact(String message) {
-            if (fExpected == null || fActual == null || areStringsEqual()) {
-                return Assert.format(message, fExpected, fActual);
+        public String compact(String message) {
+            if (expected == null || actual == null || expected.equals(actual)) {
+                return Assert.format(message, expected, actual);
+            } else {
+                DiffExtractor extractor = new DiffExtractor();
+                String compactedPrefix = extractor.compactPrefix();
+                String compactedSuffix = extractor.compactSuffix();
+                return Assert.format(message,
+                        compactedPrefix + extractor.expectedDiff() + compactedSuffix,
+                        compactedPrefix + extractor.actualDiff() + compactedSuffix);
             }
-
-            findCommonPrefix();
-            findCommonSuffix();
-            String expected = compactString(fExpected);
-            String actual = compactString(fActual);
-            return Assert.format(message, expected, actual);
         }
 
-        private String compactString(String source) {
-            String result = DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END;
-            if (fPrefix > 0) {
-                result = computeCommonPrefix() + result;
+        private String sharedPrefix() {
+            int end = Math.min(expected.length(), actual.length());
+            for (int i = 0; i < end; i++) {
+                if (expected.charAt(i) != actual.charAt(i)) {
+                    return expected.substring(0, i);
+                }
             }
-            if (fSuffix > 0) {
-                result = result + computeCommonSuffix();
-            }
-            return result;
+            return expected.substring(0, end);
         }
 
-        private void findCommonPrefix() {
-            fPrefix = 0;
-            int end = Math.min(fExpected.length(), fActual.length());
-            for (; fPrefix < end; fPrefix++) {
-                if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix)) {
+        private String sharedSuffix(String prefix) {
+            int suffixLength = 0;
+            int maxSuffixLength = Math.min(expected.length() - prefix.length(),
+                    actual.length() - prefix.length()) - 1;
+            for (; suffixLength <= maxSuffixLength; suffixLength++) {
+                if (expected.charAt(expected.length() - 1 - suffixLength)
+                        != actual.charAt(actual.length() - 1 - suffixLength)) {
                     break;
                 }
             }
+            return expected.substring(expected.length() - suffixLength);
         }
 
-        private void findCommonSuffix() {
-            int expectedSuffix = fExpected.length() - 1;
-            int actualSuffix = fActual.length() - 1;
-            for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) {
-                if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix)) {
-                    break;
-                }
+        private class DiffExtractor {
+            private final String sharedPrefix;
+            private final String sharedSuffix;
+
+            /**
+             * Can not be instantiated outside {@link org.junit.ComparisonFailure.ComparisonCompactor}.
+             */
+            private DiffExtractor() {
+                sharedPrefix = sharedPrefix();
+                sharedSuffix = sharedSuffix(sharedPrefix);
             }
-            fSuffix = fExpected.length() - expectedSuffix;
-        }
 
-        private String computeCommonPrefix() {
-            return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix);
-        }
+            public String expectedDiff() {
+                return extractDiff(expected);
+            }
 
-        private String computeCommonSuffix() {
-            int end = Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length());
-            return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 < fExpected.length() - fContextLength ? ELLIPSIS : "");
-        }
+            public String actualDiff() {
+                return extractDiff(actual);
+            }
 
-        private boolean areStringsEqual() {
-            return fExpected.equals(fActual);
+            public String compactPrefix() {
+                if (sharedPrefix.length() <= contextLength) {
+                    return sharedPrefix;
+                }
+                return ELLIPSIS + sharedPrefix.substring(sharedPrefix.length() - contextLength);
+            }
+
+            public String compactSuffix() {
+                if (sharedSuffix.length() <= contextLength) {
+                    return sharedSuffix;
+                }
+                return sharedSuffix.substring(0, contextLength) + ELLIPSIS;
+            }
+
+            private String extractDiff(String source) {
+                return DIFF_START + source.substring(sharedPrefix.length(), source.length() - sharedSuffix.length())
+                        + DIFF_END;
+            }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/FixMethodOrder.java b/src/main/java/org/junit/FixMethodOrder.java
index 8d9955c..aaa0313 100644
--- a/src/main/java/org/junit/FixMethodOrder.java
+++ b/src/main/java/org/junit/FixMethodOrder.java
@@ -9,17 +9,16 @@
 
 /**
  * This class allows the user to choose the order of execution of the methods within a test class.
- * <br/>
- * <br/>
- * The default order of execution of JUnit tests within a class is deterministic but not predictable.
+ *
+ * <p>The default order of execution of JUnit tests within a class is deterministic but not predictable.
  * The order of execution is not guaranteed for Java 7 (and some previous versions), and can even change
  * from run to run, so the order of execution was changed to be deterministic (in JUnit 4.11)
- * <br/>
- * It is recommended that test methods be written so that they are independent of the order that they are executed.
+ *
+ * <p>It is recommended that test methods be written so that they are independent of the order that they are executed.
  * However, there may be a number of dependent tests either through error or by design.
  * This class allows the user to specify the order of execution of test methods.
- * <br/>
- * For possibilities, see {@link MethodSorters}
+ *
+ * <p>For possibilities, see {@link MethodSorters}
  *
  * Here is an example:
  *
diff --git a/src/main/java/org/junit/Ignore.java b/src/main/java/org/junit/Ignore.java
index 0353e80..db23581 100644
--- a/src/main/java/org/junit/Ignore.java
+++ b/src/main/java/org/junit/Ignore.java
@@ -6,21 +6,21 @@
 import java.lang.annotation.Target;
 
 /**
- * <p>Sometimes you want to temporarily disable a test or a group of tests. Methods annotated with
+ * Sometimes you want to temporarily disable a test or a group of tests. Methods annotated with
  * {@link org.junit.Test} that are also annotated with <code>&#064;Ignore</code> will not be executed as tests.
  * Also, you can annotate a class containing test methods with <code>&#064;Ignore</code> and none of the containing
  * tests will be executed. Native JUnit 4 test runners should report the number of ignored tests along with the
- * number of tests that ran and the number of tests that failed.</p>
+ * number of tests that ran and the number of tests that failed.
  *
- * For example:
+ * <p>For example:
  * <pre>
  *    &#064;Ignore &#064;Test public void something() { ...
  * </pre>
- * &#064;Ignore takes an optional default parameter if you want to record why a test is being ignored:<br/>
+ * &#064;Ignore takes an optional default parameter if you want to record why a test is being ignored:
  * <pre>
  *    &#064;Ignore("not ready yet") &#064;Test public void something() { ...
  * </pre>
- * &#064;Ignore can also be applied to the test class:<br/>
+ * &#064;Ignore can also be applied to the test class:
  * <pre>
  *      &#064;Ignore public class IgnoreMe {
  *          &#064;Test public void test1() { ... }
diff --git a/src/main/java/org/junit/Rule.java b/src/main/java/org/junit/Rule.java
index 429821a..711235c 100644
--- a/src/main/java/org/junit/Rule.java
+++ b/src/main/java/org/junit/Rule.java
@@ -10,21 +10,21 @@
  * static, and a subtype of {@link org.junit.rules.TestRule} (preferred) or
  * {@link org.junit.rules.MethodRule}. A method must be public, not static,
  * and must return a subtype of {@link org.junit.rules.TestRule} (preferred) or
- * {@link org.junit.rules.MethodRule}.<p>
- *
+ * {@link org.junit.rules.MethodRule}.
+ * <p>
  * 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 order of fields first, then methods.
- * However, if there are mutliple fields (or methods) they will be applied in an order
+ * However, if there are multiple 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. Rules defined by fields will always be applied
- * before Rules defined by methods.<p>
- *
+ * before Rules defined by methods. You can use a {@link org.junit.rules.RuleChain} if you want
+ * to have control over the order in which the Rules are applied.
+ * <p>
  * For example, here is a test class that creates a temporary folder before
  * each test method, and deletes it after each:
- *
  * <pre>
  * public static class HasTempFolder {
  *     &#064;Rule
@@ -38,9 +38,8 @@
  *     }
  * }
  * </pre>
- *
+ * <p>
  * And the same using a method.
- *
  * <pre>
  * public static class HasTempFolder {
  *     private TemporaryFolder folder= new TemporaryFolder();
@@ -58,7 +57,7 @@
  *     }
  * }
  * </pre>
- *
+ * <p>
  * For more information and more examples, see
  * {@link org.junit.rules.TestRule}.
  *
diff --git a/src/main/java/org/junit/Test.java b/src/main/java/org/junit/Test.java
index 2ba5a53..1d178ec 100644
--- a/src/main/java/org/junit/Test.java
+++ b/src/main/java/org/junit/Test.java
@@ -6,14 +6,14 @@
 import java.lang.annotation.Target;
 
 /**
- * <p>The <code>Test</code> annotation tells JUnit that the <code>public void</code> method
+ * The <code>Test</code> annotation tells JUnit that the <code>public void</code> method
  * to which it is attached can be run as a test case. To run the method,
  * JUnit first constructs a fresh instance of the class then invokes the
  * annotated method. Any exceptions thrown by the test will be reported
  * by JUnit as a failure. If no exceptions are thrown, the test is assumed
- * to have succeeded.</p>
- *
- * <p>A simple test looks like this:
+ * to have succeeded.
+ * <p>
+ * A simple test looks like this:
  * <pre>
  * public class Example {
  *    <b>&#064;Test</b>
@@ -22,9 +22,8 @@
  *    }
  * }
  * </pre>
- * </p>
- *
- * <p>The <code>Test</code> annotation supports two optional parameters.
+ * <p>
+ * The <code>Test</code> annotation supports two optional parameters.
  * The first, <code>expected</code>, declares that a test method should throw
  * an exception. If it doesn't throw an exception or if it throws a different exception
  * than the one declared, the test fails. For example, the following test succeeds:
@@ -32,15 +31,33 @@
  *    &#064;Test(<b>expected=IndexOutOfBoundsException.class</b>) public void outOfBounds() {
  *       new ArrayList&lt;Object&gt;().get(1);
  *    }
- * </pre></p>
- *
- * <p>The second optional parameter, <code>timeout</code>, causes a test to fail if it takes
+ * </pre>
+ * If the exception's message or one of its properties should be verified, the
+ * {@link org.junit.rules.ExpectedException ExpectedException} rule can be used. Further
+ * information about exception testing can be found at the
+ * <a href="https://github.com/junit-team/junit/wiki/Exception-testing">JUnit Wiki</a>.
+ * <p>
+ * The second optional parameter, <code>timeout</code>, causes a test to fail if it takes
  * longer than a specified amount of clock time (measured in milliseconds). The following test fails:
  * <pre>
  *    &#064;Test(<b>timeout=100</b>) public void infinity() {
  *       while(true);
  *    }
- * </pre></p>
+ * </pre>
+ * <b>Warning</b>: while <code>timeout</code> is useful to catch and terminate
+ * infinite loops, it should <em>not</em> be considered deterministic. The
+ * following test may or may not fail depending on how the operating system
+ * schedules threads:
+ * <pre>
+ *    &#064;Test(<b>timeout=100</b>) public void sleep100() {
+ *       Thread.sleep(100);
+ *    }
+ * </pre>
+ * <b>THREAD SAFETY WARNING:</b> Test methods with a timeout parameter are run in a thread other than the
+ * thread which runs the fixture's @Before and @After methods. This may yield different behavior for
+ * code that is not thread safe when compared to the same test method without a timeout parameter.
+ * <b>Consider using the {@link org.junit.rules.Timeout} rule instead</b>, which ensures a test method is run on the
+ * same thread as the fixture's @Before and @After methods.
  *
  * @since 4.0
  */
@@ -49,7 +66,7 @@
 public @interface Test {
 
     /**
-     * Default empty exception
+     * Default empty exception.
      */
     static class None extends Throwable {
         private static final long serialVersionUID = 1L;
@@ -60,13 +77,22 @@
 
     /**
      * Optionally specify <code>expected</code>, a Throwable, to cause a test method to succeed if
-     * and only if an exception of the specified class is thrown by the method.
+     * and only if an exception of the specified class is thrown by the method. If the Throwable's
+     * message or one of its properties should be verified, the
+     * {@link org.junit.rules.ExpectedException ExpectedException} rule can be used instead.
      */
     Class<? extends Throwable> expected() default None.class;
 
     /**
      * Optionally specify <code>timeout</code> in milliseconds to cause a test method to fail if it
      * takes longer than that number of milliseconds.
+     * <p>
+     * <b>THREAD SAFETY WARNING:</b> Test methods with a timeout parameter are run in a thread other than the
+     * thread which runs the fixture's @Before and @After methods. This may yield different behavior for
+     * code that is not thread safe when compared to the same test method without a timeout parameter.
+     * <b>Consider using the {@link org.junit.rules.Timeout} rule instead</b>, which ensures a test method is run on the
+     * same thread as the fixture's @Before and @After methods.
+     * </p>
      */
     long timeout() default 0L;
 }
diff --git a/src/main/java/org/junit/experimental/ParallelComputer.java b/src/main/java/org/junit/experimental/ParallelComputer.java
index 96271e7..97da0f7 100644
--- a/src/main/java/org/junit/experimental/ParallelComputer.java
+++ b/src/main/java/org/junit/experimental/ParallelComputer.java
@@ -12,13 +12,13 @@
 import org.junit.runners.model.RunnerScheduler;
 
 public class ParallelComputer extends Computer {
-    private final boolean fClasses;
+    private final boolean classes;
 
-    private final boolean fMethods;
+    private final boolean methods;
 
     public ParallelComputer(boolean classes, boolean methods) {
-        fClasses = classes;
-        fMethods = methods;
+        this.classes = classes;
+        this.methods = methods;
     }
 
     public static Computer classes() {
@@ -55,13 +55,13 @@
     public Runner getSuite(RunnerBuilder builder, java.lang.Class<?>[] classes)
             throws InitializationError {
         Runner suite = super.getSuite(builder, classes);
-        return fClasses ? parallelize(suite) : suite;
+        return this.classes ? parallelize(suite) : suite;
     }
 
     @Override
     protected Runner getRunner(RunnerBuilder builder, Class<?> testClass)
             throws Throwable {
         Runner runner = super.getRunner(builder, testClass);
-        return fMethods ? parallelize(runner) : runner;
+        return methods ? parallelize(runner) : runner;
     }
 }
diff --git a/src/main/java/org/junit/experimental/categories/Categories.java b/src/main/java/org/junit/experimental/categories/Categories.java
index 4d43685..e4d6eb1 100644
--- a/src/main/java/org/junit/experimental/categories/Categories.java
+++ b/src/main/java/org/junit/experimental/categories/Categories.java
@@ -2,9 +2,10 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Set;
+
 import org.junit.runner.Description;
 import org.junit.runner.manipulation.Filter;
 import org.junit.runner.manipulation.NoTestsRemainException;
@@ -63,7 +64,7 @@
  *     // Will run A.b and B.d, but not A.a and A.c
  * }
  * </pre>
- *
+ * <p>
  * Example to run multiple categories:
  * <pre>
  * &#064;RunWith(Categories.class)
@@ -75,13 +76,9 @@
  * </pre>
  *
  * @version 4.12
- * @see <a href="https://github.com/KentBeck/junit/wiki/Categories">Categories at JUnit wiki</a>
+ * @see <a href="https://github.com/junit-team/junit/wiki/Categories">Categories at JUnit wiki</a>
  */
 public class Categories extends Suite {
-    // the way filters are implemented makes this unnecessarily complicated,
-    // buggy, and difficult to specify.  A new way of handling filters could
-    // someday enable a better new implementation.
-    // https://github.com/KentBeck/junit/issues/issue/172
 
     @Retention(RetentionPolicy.RUNTIME)
     public @interface IncludeCategory {
@@ -89,13 +86,13 @@
          * Determines the tests to run that are annotated with categories specified in
          * the value of this annotation or their subtypes unless excluded with {@link ExcludeCategory}.
          */
-        public Class<?>[] value() default {};
+        Class<?>[] value() default {};
 
         /**
          * If <tt>true</tt>, runs tests annotated with <em>any</em> of the categories in
          * {@link IncludeCategory#value()}. Otherwise, runs tests only if annotated with <em>all</em> of the categories.
          */
-        public boolean matchAny() default true;
+        boolean matchAny() default true;
     }
 
     @Retention(RetentionPolicy.RUNTIME)
@@ -104,20 +101,20 @@
          * Determines the tests which do not run if they are annotated with categories specified in the
          * value of this annotation or their subtypes regardless of being included in {@link IncludeCategory#value()}.
          */
-        public Class<?>[] value() default {};
+        Class<?>[] value() default {};
 
         /**
          * If <tt>true</tt>, the tests annotated with <em>any</em> of the categories in {@link ExcludeCategory#value()}
          * do not run. Otherwise, the tests do not run if and only if annotated with <em>all</em> categories.
          */
-        public boolean matchAny() default true;
+        boolean matchAny() default true;
     }
 
     public static class CategoryFilter extends Filter {
-        private final Set<Class<?>> fIncluded;
-        private final Set<Class<?>> fExcluded;
-        private final boolean fIncludedAny;
-        private final boolean fExcludedAny;
+        private final Set<Class<?>> included;
+        private final Set<Class<?>> excluded;
+        private final boolean includedAny;
+        private final boolean excludedAny;
 
         public static CategoryFilter include(boolean matchAny, Class<?>... categories) {
             if (hasNull(categories)) {
@@ -154,12 +151,12 @@
             return new CategoryFilter(matchAnyInclusions, inclusions, matchAnyExclusions, exclusions);
         }
 
-        private CategoryFilter(boolean matchAnyIncludes, Set<Class<?>> includes,
+        protected CategoryFilter(boolean matchAnyIncludes, Set<Class<?>> includes,
                                boolean matchAnyExcludes, Set<Class<?>> excludes) {
-            fIncludedAny= matchAnyIncludes;
-            fExcludedAny= matchAnyExcludes;
-            fIncluded= copyAndRefine(includes);
-            fExcluded= copyAndRefine(excludes);
+            includedAny = matchAnyIncludes;
+            excludedAny = matchAnyExcludes;
+            included = copyAndRefine(includes);
+            excluded = copyAndRefine(excludes);
         }
 
         /**
@@ -185,9 +182,9 @@
          */
         @Override public String toString() {
             StringBuilder description= new StringBuilder("categories ")
-                .append(fIncluded.isEmpty() ? "[all]" : fIncluded);
-            if (!fExcluded.isEmpty()) {
-                description.append(" - ").append(fExcluded);
+                .append(included.isEmpty() ? "[all]" : included);
+            if (!excluded.isEmpty()) {
+                description.append(" - ").append(excluded);
             }
             return description.toString();
         }
@@ -212,29 +209,29 @@
 
             // If a child has no categories, immediately return.
             if (childCategories.isEmpty()) {
-                return fIncluded.isEmpty();
+                return included.isEmpty();
             }
 
-            if (!fExcluded.isEmpty()) {
-                if (fExcludedAny) {
-                    if (matchesAnyParentCategories(childCategories, fExcluded)) {
+            if (!excluded.isEmpty()) {
+                if (excludedAny) {
+                    if (matchesAnyParentCategories(childCategories, excluded)) {
                         return false;
                     }
                 } else {
-                    if (matchesAllParentCategories(childCategories, fExcluded)) {
+                    if (matchesAllParentCategories(childCategories, excluded)) {
                         return false;
                     }
                 }
             }
-            
-            if (fIncluded.isEmpty()) {
+
+            if (included.isEmpty()) {
                 // Couldn't be excluded, and with no suite's included categories treated as should run.
                 return true;
             } else {
-                if (fIncludedAny) {
-                    return matchesAnyParentCategories(childCategories, fIncluded);
+                if (includedAny) {
+                    return matchesAnyParentCategories(childCategories, included);
                 } else {
-                    return matchesAllParentCategories(childCategories, fIncluded);
+                    return matchesAllParentCategories(childCategories, included);
                 }
             }
         }
@@ -287,7 +284,7 @@
         }
 
         private static Set<Class<?>> copyAndRefine(Set<Class<?>> classes) {
-            HashSet<Class<?>> c= new HashSet<Class<?>>();
+            Set<Class<?>> c= new HashSet<Class<?>>();
             if (classes != null) {
                 c.addAll(classes);
             }
@@ -317,13 +314,10 @@
             filter(CategoryFilter.categoryFilter(isAnyIncluded, included, isAnyExcluded, excluded));
         } catch (NoTestsRemainException e) {
             throw new InitializationError(e);
-        } catch (ClassNotFoundException e) {
-            throw new InitializationError(e);
         }
-        assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription());
     }
 
-    private static Set<Class<?>> getIncludedCategory(Class<?> klass) throws ClassNotFoundException {
+    private static Set<Class<?>> getIncludedCategory(Class<?> klass) {
         IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class);
         return createSet(annotation == null ? null : annotation.value());
     }
@@ -333,7 +327,7 @@
         return annotation == null || annotation.matchAny();
     }
 
-    private static Set<Class<?>> getExcludedCategory(Class<?> klass) throws ClassNotFoundException {
+    private static Set<Class<?>> getExcludedCategory(Class<?> klass) {
         ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class);
         return createSet(annotation == null ? null : annotation.value());
     }
@@ -343,34 +337,6 @@
         return annotation == null || annotation.matchAny();
     }
 
-    private static void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError {
-        if (!canHaveCategorizedChildren(description)) {
-            assertNoDescendantsHaveCategoryAnnotations(description);
-        }
-        for (Description each : description.getChildren()) {
-            assertNoCategorizedDescendentsOfUncategorizeableParents(each);
-        }
-    }
-
-    private static void assertNoDescendantsHaveCategoryAnnotations(Description description) throws InitializationError {
-        for (Description each : description.getChildren()) {
-            if (each.getAnnotation(Category.class) != null) {
-                throw new InitializationError("Category annotations on Parameterized classes are not supported on individual methods.");
-            }
-            assertNoDescendantsHaveCategoryAnnotations(each);
-        }
-    }
-
-    // If children have names like [0], our current magical category code can't determine their parentage.
-    private static boolean canHaveCategorizedChildren(Description description) {
-        for (Description each : description.getChildren()) {
-            if (each.getTestClass() == null) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     private static boolean hasAssignableTo(Set<Class<?>> assigns, Class<?> to) {
         for (final Class<?> from : assigns) {
             if (to.isAssignableFrom(from)) {
@@ -387,4 +353,4 @@
         }
         return set;
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/experimental/categories/Category.java b/src/main/java/org/junit/experimental/categories/Category.java
index 0144051..8eae836 100644
--- a/src/main/java/org/junit/experimental/categories/Category.java
+++ b/src/main/java/org/junit/experimental/categories/Category.java
@@ -4,6 +4,8 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+import org.junit.validator.ValidateWith;
+
 /**
  * Marks a test class or test method as belonging to one or more categories of tests.
  * The value is an array of arbitrary classes.
@@ -40,6 +42,7 @@
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Inherited
+@ValidateWith(CategoryValidator.class)
 public @interface Category {
     Class<?>[] value();
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java b/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java
new file mode 100644
index 0000000..cee1ae7
--- /dev/null
+++ b/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java
@@ -0,0 +1,47 @@
+package org.junit.experimental.categories;

+

+import java.util.ArrayList;

+import java.util.List;

+

+import org.junit.internal.Classes;

+import org.junit.runner.FilterFactory;

+import org.junit.runner.FilterFactoryParams;

+import org.junit.runner.manipulation.Filter;

+

+/**

+ * Implementation of FilterFactory for Category filtering.

+ */

+abstract class CategoryFilterFactory implements FilterFactory {

+    /**

+     * Creates a {@link org.junit.experimental.categories.Categories.CategoryFilter} given a

+     * {@link FilterFactoryParams} argument.

+     *

+     * @param params Parameters needed to create the {@link Filter}

+     */

+    public Filter createFilter(FilterFactoryParams params) throws FilterNotCreatedException {

+        try {

+            return createFilter(parseCategories(params.getArgs()));

+        } catch (ClassNotFoundException e) {

+            throw new FilterNotCreatedException(e);

+        }

+    }

+

+    /**

+     * Creates a {@link org.junit.experimental.categories.Categories.CategoryFilter} given an array of classes.

+     *

+     * @param categories Category classes.

+     */

+    protected abstract Filter createFilter(List<Class<?>> categories);

+

+    private List<Class<?>> parseCategories(String categories) throws ClassNotFoundException {

+        List<Class<?>> categoryClasses = new ArrayList<Class<?>>();

+

+        for (String category : categories.split(",")) {

+            Class<?> categoryClass = Classes.getClass(category);

+

+            categoryClasses.add(categoryClass);

+        }

+

+        return categoryClasses;

+    }

+}

diff --git a/src/main/java/org/junit/experimental/categories/CategoryValidator.java b/src/main/java/org/junit/experimental/categories/CategoryValidator.java
new file mode 100644
index 0000000..491d8ac
--- /dev/null
+++ b/src/main/java/org/junit/experimental/categories/CategoryValidator.java
@@ -0,0 +1,62 @@
+package org.junit.experimental.categories;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableList;
+import static java.util.Collections.unmodifiableSet;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.validator.AnnotationValidator;
+
+/**
+ * Validates that there are no errors in the use of the {@code Category}
+ * annotation. If there is, a {@code Throwable} object will be added to the list
+ * of errors.
+ *
+ * @since 4.12
+ */
+public final class CategoryValidator extends AnnotationValidator {
+
+    @SuppressWarnings("unchecked")
+    private static final Set<Class<? extends Annotation>> INCOMPATIBLE_ANNOTATIONS = unmodifiableSet(new HashSet<Class<? extends Annotation>>(
+            asList(BeforeClass.class, AfterClass.class, Before.class, After.class)));
+
+    /**
+     * Adds to {@code errors} a throwable for each problem detected. Looks for
+     * {@code BeforeClass}, {@code AfterClass}, {@code Before} and {@code After}
+     * annotations.
+     *
+     * @param method the method that is being validated
+     * @return A list of exceptions detected
+     *
+     * @since 4.12
+     */
+    @Override
+    public List<Exception> validateAnnotatedMethod(FrameworkMethod method) {
+        List<Exception> errors = new ArrayList<Exception>();
+        Annotation[] annotations = method.getAnnotations();
+        for (Annotation annotation : annotations) {
+            for (Class<?> clazz : INCOMPATIBLE_ANNOTATIONS) {
+                if (annotation.annotationType().isAssignableFrom(clazz)) {
+                    addErrorMessage(errors, clazz);
+                }
+            }
+        }
+        return unmodifiableList(errors);
+    }
+
+    private void addErrorMessage(List<Exception> errors, Class<?> clazz) {
+        String message = String.format("@%s can not be combined with @Category",
+                clazz.getSimpleName());
+        errors.add(new Exception(message));
+    }
+}
diff --git a/src/main/java/org/junit/experimental/categories/ExcludeCategories.java b/src/main/java/org/junit/experimental/categories/ExcludeCategories.java
new file mode 100644
index 0000000..8ccb6b5
--- /dev/null
+++ b/src/main/java/org/junit/experimental/categories/ExcludeCategories.java
@@ -0,0 +1,52 @@
+package org.junit.experimental.categories;

+

+import java.util.HashSet;

+import java.util.List;

+import java.util.Set;

+

+import org.junit.experimental.categories.Categories.CategoryFilter;

+import org.junit.runner.manipulation.Filter;

+

+/**

+ * {@link org.junit.runner.FilterFactory} to exclude categories.

+ *

+ * The {@link Filter} that is created will filter out tests that are categorized with any of the

+ * given categories.

+ *

+ * Usage from command line:

+ * <code>

+ *     --filter=org.junit.experimental.categories.ExcludeCategories=pkg.of.Cat1,pkg.of.Cat2

+ * </code>

+ *

+ * Usage from API:

+ * <code>

+ *     new ExcludeCategories().createFilter(Cat1.class, Cat2.class);

+ * </code>

+ */

+public final class ExcludeCategories extends CategoryFilterFactory {

+    /**

+     * Creates a {@link Filter} which is only passed by tests that are

+     * not categorized with any of the specified categories.

+     *

+     * @param categories Category classes.

+     */

+    @Override

+    protected Filter createFilter(List<Class<?>> categories) {

+        return new ExcludesAny(categories);

+    }

+

+    private static class ExcludesAny extends CategoryFilter {

+        public ExcludesAny(List<Class<?>> categories) {

+            this(new HashSet<Class<?>>(categories));

+        }

+

+        public ExcludesAny(Set<Class<?>> categories) {

+            super(true, null, true, categories);

+        }

+

+        @Override

+        public String describe() {

+            return "excludes " + super.describe();

+        }

+    }

+}

diff --git a/src/main/java/org/junit/experimental/categories/IncludeCategories.java b/src/main/java/org/junit/experimental/categories/IncludeCategories.java
new file mode 100644
index 0000000..38eb693
--- /dev/null
+++ b/src/main/java/org/junit/experimental/categories/IncludeCategories.java
@@ -0,0 +1,52 @@
+package org.junit.experimental.categories;

+

+import java.util.HashSet;

+import java.util.List;

+import java.util.Set;

+

+import org.junit.experimental.categories.Categories.CategoryFilter;

+import org.junit.runner.manipulation.Filter;

+

+/**

+ * {@link org.junit.runner.FilterFactory} to include categories.

+ *

+ * The {@link Filter} that is created will filter out tests that are categorized with any of the

+ * given categories.

+ *

+ * Usage from command line:

+ * <code>

+ *     --filter=org.junit.experimental.categories.IncludeCategories=pkg.of.Cat1,pkg.of.Cat2

+ * </code>

+ *

+ * Usage from API:

+ * <code>

+ *     new IncludeCategories().createFilter(Cat1.class, Cat2.class);

+ * </code>

+ */

+public final class IncludeCategories extends CategoryFilterFactory {

+    /**

+     * Creates a {@link Filter} which is only passed by tests that are

+     * categorized with any of the specified categories.

+     *

+     * @param categories Category classes.

+     */

+    @Override

+    protected Filter createFilter(List<Class<?>> categories) {

+        return new IncludesAny(categories);

+    }

+

+    private static class IncludesAny extends CategoryFilter {

+        public IncludesAny(List<Class<?>> categories) {

+            this(new HashSet<Class<?>>(categories));

+        }

+

+        public IncludesAny(Set<Class<?>> categories) {

+            super(true, categories, true, null);

+        }

+

+        @Override

+        public String describe() {

+            return "includes " + super.describe();

+        }

+    }

+}

diff --git a/src/main/java/org/junit/experimental/max/MaxCore.java b/src/main/java/org/junit/experimental/max/MaxCore.java
index 8e55a9d..625cade 100644
--- a/src/main/java/org/junit/experimental/max/MaxCore.java
+++ b/src/main/java/org/junit/experimental/max/MaxCore.java
@@ -49,10 +49,10 @@
         return new MaxCore(storedResults);
     }
 
-    private final MaxHistory fHistory;
+    private final MaxHistory history;
 
     private MaxCore(File storedResults) {
-        fHistory = MaxHistory.forFolder(storedResults);
+        history = MaxHistory.forFolder(storedResults);
     }
 
     /**
@@ -85,7 +85,7 @@
      * @return a {@link Result} describing the details of the test run and the failed tests.
      */
     public Result run(Request request, JUnitCore core) {
-        core.addListener(fHistory.listener());
+        core.addListener(history.listener());
         return core.run(sortRequest(request).getRunner());
     }
 
@@ -98,7 +98,7 @@
             return request;
         }
         List<Description> leaves = findLeaves(request);
-        Collections.sort(leaves, fHistory.testComparator());
+        Collections.sort(leaves, history.testComparator());
         return constructLeafRequest(leaves);
     }
 
diff --git a/src/main/java/org/junit/experimental/max/MaxHistory.java b/src/main/java/org/junit/experimental/max/MaxHistory.java
index 94d20c6..45a4033 100644
--- a/src/main/java/org/junit/experimental/max/MaxHistory.java
+++ b/src/main/java/org/junit/experimental/max/MaxHistory.java
@@ -61,10 +61,13 @@
         }
     }
 
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
     private final Map<String, Long> fDurations = new HashMap<String, Long>();
-
     private final Map<String, Long> fFailureTimestamps = new HashMap<String, Long>();
-
     private final File fHistoryStore;
 
     private MaxHistory(File storedResults) {
diff --git a/src/main/java/org/junit/experimental/results/ResultMatchers.java b/src/main/java/org/junit/experimental/results/ResultMatchers.java
index cf58f1b..98778a9 100644
--- a/src/main/java/org/junit/experimental/results/ResultMatchers.java
+++ b/src/main/java/org/junit/experimental/results/ResultMatchers.java
@@ -14,6 +14,15 @@
  * </pre>
  */
 public class ResultMatchers {
+
+    /**
+     * Do not instantiate.
+     * @deprecated will be private soon.
+     */
+    @Deprecated
+    public ResultMatchers() {
+    }
+
     /**
      * Matches if the tests are all successful
      */
diff --git a/src/main/java/org/junit/experimental/runners/Enclosed.java b/src/main/java/org/junit/experimental/runners/Enclosed.java
index c5dd4e4..610b970 100644
--- a/src/main/java/org/junit/experimental/runners/Enclosed.java
+++ b/src/main/java/org/junit/experimental/runners/Enclosed.java
@@ -22,8 +22,6 @@
  *     abstract public static class Ignored {...}
  * }
  * </pre>
- *
- * @see org.junit.tests.manipulation.SortableTest
  */
 public class Enclosed extends Suite {
     /**
diff --git a/src/main/java/org/junit/experimental/theories/DataPoint.java b/src/main/java/org/junit/experimental/theories/DataPoint.java
index 2aaba6a..0a017bb 100644
--- a/src/main/java/org/junit/experimental/theories/DataPoint.java
+++ b/src/main/java/org/junit/experimental/theories/DataPoint.java
@@ -1,9 +1,56 @@
 package org.junit.experimental.theories;
 
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
+/**
+ * Annotating an field or method with &#064;DataPoint will cause the field value
+ * or the value returned by the method to be used as a potential parameter for
+ * theories in that class, when run with the
+ * {@link org.junit.experimental.theories.Theories Theories} runner.
+ * <p>
+ * A DataPoint is only considered as a potential value for parameters for
+ * which its type is assignable. When multiple {@code DataPoint}s exist 
+ * with overlapping types more control can be obtained by naming each DataPoint 
+ * using the value of this annotation, e.g. with
+ * <code>&#064;DataPoint({"dataset1", "dataset2"})</code>, and then specifying
+ * which named set to consider as potential values for each parameter using the
+ * {@link org.junit.experimental.theories.FromDataPoints &#064;FromDataPoints}
+ * annotation.
+ * <p>
+ * Parameters with no specified source (i.e. without &#064;FromDataPoints or
+ * other {@link org.junit.experimental.theories.ParametersSuppliedBy
+ * &#064;ParameterSuppliedBy} annotations) will use all {@code DataPoint}s that are
+ * assignable to the parameter type as potential values, including named sets of
+ * {@code DataPoint}s.
+ * 
+ * <pre>
+ * &#064;DataPoint
+ * public static String dataPoint = "value";
+ * 
+ * &#064;DataPoint("generated")
+ * public static String generatedDataPoint() {
+ *     return "generated value";
+ * }
+ * 
+ * &#064;Theory
+ * public void theoryMethod(String param) {
+ *     ...
+ * }
+ * </pre>
+ * 
+ * @see org.junit.experimental.theories.Theories
+ * @see org.junit.experimental.theories.Theory
+ * @see org.junit.experimental.theories.DataPoint
+ * @see org.junit.experimental.theories.FromDataPoints
+ */
 @Retention(RetentionPolicy.RUNTIME)
+@Target({FIELD, METHOD})
 public @interface DataPoint {
-
-}
+    String[] value() default {};
+    Class<? extends Throwable>[] ignoredExceptions() default {};
+}
\ No newline at end of file
diff --git a/src/main/java/org/junit/experimental/theories/DataPoints.java b/src/main/java/org/junit/experimental/theories/DataPoints.java
index 42145e3..b47461b 100644
--- a/src/main/java/org/junit/experimental/theories/DataPoints.java
+++ b/src/main/java/org/junit/experimental/theories/DataPoints.java
@@ -1,9 +1,64 @@
 package org.junit.experimental.theories;
 
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
+/**
+ * Annotating an array or iterable-typed field or method with &#064;DataPoints
+ * will cause the values in the array or iterable given to be used as potential
+ * parameters for theories in that class when run with the
+ * {@link org.junit.experimental.theories.Theories Theories} runner.
+ * <p>
+ * DataPoints will only be considered as potential values for parameters for
+ * which their types are assignable. When multiple sets of DataPoints exist with
+ * overlapping types more control can be obtained by naming the DataPoints using
+ * the value of this annotation, e.g. with
+ * <code>&#064;DataPoints({"dataset1", "dataset2"})</code>, and then specifying
+ * which named set to consider as potential values for each parameter using the
+ * {@link org.junit.experimental.theories.FromDataPoints &#064;FromDataPoints}
+ * annotation.
+ * <p>
+ * Parameters with no specified source (i.e. without &#064;FromDataPoints or
+ * other {@link org.junit.experimental.theories.ParametersSuppliedBy
+ * &#064;ParameterSuppliedBy} annotations) will use all DataPoints that are
+ * assignable to the parameter type as potential values, including named sets of
+ * DataPoints.
+ * <p>
+ * DataPoints methods whose array types aren't assignable from the target
+ * parameter type (and so can't possibly return relevant values) will not be
+ * called when generating values for that parameter. Iterable-typed datapoints
+ * methods must always be called though, as this information is not available
+ * here after generic type erasure, so expensive methods returning iterable
+ * datapoints are a bad idea.
+ * 
+ * <pre>
+ * &#064;DataPoints
+ * public static String[] dataPoints = new String[] { ... };
+ * 
+ * &#064;DataPoints
+ * public static String[] generatedDataPoints() {
+ *     return new String[] { ... };
+ * }
+ * 
+ * &#064;Theory
+ * public void theoryMethod(String param) {
+ *     ...
+ * }
+ * </pre>
+ * 
+ * @see org.junit.experimental.theories.Theories
+ * @see org.junit.experimental.theories.Theory
+ * @see org.junit.experimental.theories.DataPoint
+ * @see org.junit.experimental.theories.FromDataPoints
+ */
 @Retention(RetentionPolicy.RUNTIME)
+@Target({ FIELD, METHOD })
 public @interface DataPoints {
+    String[] value() default {};
 
+    Class<? extends Throwable>[] ignoredExceptions() default {};
 }
diff --git a/src/main/java/org/junit/experimental/theories/FromDataPoints.java b/src/main/java/org/junit/experimental/theories/FromDataPoints.java
new file mode 100644
index 0000000..2b149ca
--- /dev/null
+++ b/src/main/java/org/junit/experimental/theories/FromDataPoints.java
@@ -0,0 +1,54 @@
+package org.junit.experimental.theories;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.experimental.theories.internal.SpecificDataPointsSupplier;
+
+/**
+ * Annotating a parameter of a {@link org.junit.experimental.theories.Theory
+ * &#064;Theory} method with <code>&#064;FromDataPoints</code> will limit the
+ * datapoints considered as potential values for that parameter to just the
+ * {@link org.junit.experimental.theories.DataPoints DataPoints} with the given
+ * name. DataPoint names can be given as the value parameter of the
+ * &#064;DataPoints annotation.
+ * <p>
+ * DataPoints without names will not be considered as values for any parameters
+ * annotated with &#064;FromDataPoints.
+ * <pre>
+ * &#064;DataPoints
+ * public static String[] unnamed = new String[] { ... };
+ * 
+ * &#064;DataPoints("regexes")
+ * public static String[] regexStrings = new String[] { ... };
+ * 
+ * &#064;DataPoints({"forMatching", "alphanumeric"})
+ * public static String[] testStrings = new String[] { ... }; 
+ * 
+ * &#064;Theory
+ * public void stringTheory(String param) {
+ *     // This will be called with every value in 'regexStrings',
+ *     // 'testStrings' and 'unnamed'.
+ * }
+ * 
+ * &#064;Theory
+ * public void regexTheory(&#064;FromDataPoints("regexes") String regex,
+ *                         &#064;FromDataPoints("forMatching") String value) {
+ *     // This will be called with only the values in 'regexStrings' as 
+ *     // regex, only the values in 'testStrings' as value, and none 
+ *     // of the values in 'unnamed'.
+ * }
+ * </pre>
+ * 
+ * @see org.junit.experimental.theories.Theory
+ * @see org.junit.experimental.theories.DataPoint
+ * @see org.junit.experimental.theories.DataPoints
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+@ParametersSuppliedBy(SpecificDataPointsSupplier.class)
+public @interface FromDataPoints {
+    String value();
+}
diff --git a/src/main/java/org/junit/experimental/theories/ParameterSignature.java b/src/main/java/org/junit/experimental/theories/ParameterSignature.java
index 2be72b2..cf22583 100644
--- a/src/main/java/org/junit/experimental/theories/ParameterSignature.java
+++ b/src/main/java/org/junit/experimental/theories/ParameterSignature.java
@@ -5,9 +5,35 @@
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class ParameterSignature {
+    
+    private static final Map<Class<?>, Class<?>> CONVERTABLE_TYPES_MAP = buildConvertableTypesMap();
+    
+    private static Map<Class<?>, Class<?>> buildConvertableTypesMap() {
+        Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();
+
+        putSymmetrically(map, boolean.class, Boolean.class);
+        putSymmetrically(map, byte.class, Byte.class);
+        putSymmetrically(map, short.class, Short.class);
+        putSymmetrically(map, char.class, Character.class);
+        putSymmetrically(map, int.class, Integer.class);
+        putSymmetrically(map, long.class, Long.class);
+        putSymmetrically(map, float.class, Float.class);
+        putSymmetrically(map, double.class, Double.class);
+
+        return Collections.unmodifiableMap(map);
+    }
+    
+    private static <T> void putSymmetrically(Map<T, T> map, T a, T b) {
+        map.put(a, b);
+        map.put(b, a);
+    }
+    
     public static ArrayList<ParameterSignature> signatures(Method method) {
         return signatures(method.getParameterTypes(), method
                 .getParameterAnnotations());
@@ -42,7 +68,23 @@
     }
 
     public boolean canAcceptType(Class<?> candidate) {
-        return type.isAssignableFrom(candidate);
+        return type.isAssignableFrom(candidate) ||
+                isAssignableViaTypeConversion(type, candidate);
+    }
+    
+    public boolean canPotentiallyAcceptType(Class<?> candidate) {
+        return candidate.isAssignableFrom(type) ||
+                isAssignableViaTypeConversion(candidate, type) ||
+                canAcceptType(candidate);
+    }
+
+    private boolean isAssignableViaTypeConversion(Class<?> targetType, Class<?> candidate) {
+        if (CONVERTABLE_TYPES_MAP.containsKey(candidate)) {
+            Class<?> wrapperClass = CONVERTABLE_TYPES_MAP.get(candidate);
+            return targetType.isAssignableFrom(wrapperClass);
+        } else {
+            return false;
+        }
     }
 
     public Class<?> getType() {
@@ -53,10 +95,6 @@
         return Arrays.asList(annotations);
     }
 
-    public boolean canAcceptArrayType(Class<?> type) {
-        return type.isArray() && canAcceptType(type.getComponentType());
-    }
-
     public boolean hasAnnotation(Class<? extends Annotation> type) {
         return getAnnotation(type) != null;
     }
diff --git a/src/main/java/org/junit/experimental/theories/ParameterSupplier.java b/src/main/java/org/junit/experimental/theories/ParameterSupplier.java
index c2981ee..bac8b34 100644
--- a/src/main/java/org/junit/experimental/theories/ParameterSupplier.java
+++ b/src/main/java/org/junit/experimental/theories/ParameterSupplier.java
@@ -2,6 +2,42 @@
 
 import java.util.List;
 
+/**
+ * Abstract parent class for suppliers of input data points for theories. Extend this class to customize how {@link
+ * org.junit.experimental.theories.Theories Theories} runner
+ * finds accepted data points. Then use your class together with <b>&#064;ParametersSuppliedBy</b> on input
+ * parameters for theories.
+ *
+ * <p>
+ * For example, here is a supplier for values between two integers, and an annotation that references it:
+ *
+ * <pre>
+ *     &#064;Retention(RetentionPolicy.RUNTIME)
+ *     <b>&#064;ParametersSuppliedBy</b>(BetweenSupplier.class)
+ *     public @interface Between {
+ *         int first();
+ *
+ *         int last();
+ *     }
+ *
+ *     public static class BetweenSupplier extends <b>ParameterSupplier</b> {
+ *         &#064;Override
+ *         public List&lt;<b>PotentialAssignment</b>&gt; getValueSources(<b>ParameterSignature</b> sig) {
+ *             List&lt;<b>PotentialAssignment</b>&gt; list = new ArrayList&lt;PotentialAssignment&gt;();
+ *             Between annotation = (Between) sig.getSupplierAnnotation();
+ *
+ *             for (int i = annotation.first(); i &lt;= annotation.last(); i++)
+ *                 list.add(<b>PotentialAssignment</b>.forValue("ints", i));
+ *             return list;
+ *         }
+ *     }
+ * </pre>
+ * </p>
+ *
+ * @see org.junit.experimental.theories.ParametersSuppliedBy
+ * @see org.junit.experimental.theories.Theories
+ * @see org.junit.experimental.theories.FromDataPoints
+ */
 public abstract class ParameterSupplier {
-    public abstract List<PotentialAssignment> getValueSources(ParameterSignature sig);
+    public abstract List<PotentialAssignment> getValueSources(ParameterSignature sig) throws Throwable;
 }
diff --git a/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java b/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java
index 4f1efee..15b5d95 100644
--- a/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java
+++ b/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java
@@ -1,10 +1,46 @@
 package org.junit.experimental.theories;
 
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.PARAMETER;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
-
+/**
+ * Annotating a {@link org.junit.experimental.theories.Theory Theory} method
+ * parameter with &#064;ParametersSuppliedBy causes it to be supplied with
+ * values from the named
+ * {@link org.junit.experimental.theories.ParameterSupplier ParameterSupplier}
+ * when run as a theory by the {@link org.junit.experimental.theories.Theories
+ * Theories} runner.
+ * 
+ * In addition, annotations themselves can be annotated with
+ * &#064;ParametersSuppliedBy, and then used similarly. ParameterSuppliedBy
+ * annotations on parameters are detected by searching up this heirarchy such
+ * that these act as syntactic sugar, making:
+ * 
+ * <pre>
+ * &#064;ParametersSuppliedBy(Supplier.class)
+ * public &#064;interface SpecialParameter { }
+ * 
+ * &#064;Theory
+ * public void theoryMethod(&#064;SpecialParameter String param) {
+ *   ...
+ * }
+ * </pre>
+ * 
+ * equivalent to:
+ * 
+ * <pre>
+ * &#064;Theory
+ * public void theoryMethod(&#064;ParametersSuppliedBy(Supplier.class) String param) {
+ *   ...
+ * }
+ * </pre>
+ */
 @Retention(RetentionPolicy.RUNTIME)
+@Target({ ANNOTATION_TYPE, PARAMETER })
 public @interface ParametersSuppliedBy {
 
     Class<? extends ParameterSupplier> value();
diff --git a/src/main/java/org/junit/experimental/theories/PotentialAssignment.java b/src/main/java/org/junit/experimental/theories/PotentialAssignment.java
index d4e4010..18ca07a 100644
--- a/src/main/java/org/junit/experimental/theories/PotentialAssignment.java
+++ b/src/main/java/org/junit/experimental/theories/PotentialAssignment.java
@@ -5,6 +5,13 @@
 public abstract class PotentialAssignment {
     public static class CouldNotGenerateValueException extends Exception {
         private static final long serialVersionUID = 1L;
+        
+        public CouldNotGenerateValueException() {
+        }
+        
+        public CouldNotGenerateValueException(Throwable e) {
+            super(e);
+        }
     }
 
     public static PotentialAssignment forValue(final String name, final Object value) {
diff --git a/src/main/java/org/junit/experimental/theories/Theories.java b/src/main/java/org/junit/experimental/theories/Theories.java
index dc577dc..8c955c3 100644
--- a/src/main/java/org/junit/experimental/theories/Theories.java
+++ b/src/main/java/org/junit/experimental/theories/Theories.java
@@ -1,14 +1,14 @@
 package org.junit.experimental.theories;
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.junit.Assert;
-import org.junit.experimental.theories.PotentialAssignment.CouldNotGenerateValueException;
+import org.junit.Assume;
 import org.junit.experimental.theories.internal.Assignments;
 import org.junit.experimental.theories.internal.ParameterizedAssertionError;
 import org.junit.internal.AssumptionViolatedException;
@@ -18,6 +18,56 @@
 import org.junit.runners.model.Statement;
 import org.junit.runners.model.TestClass;
 
+/**
+ * The Theories runner allows to test a certain functionality against a subset of an infinite set of data points.
+ * <p>
+ * A Theory is a piece of functionality (a method) that is executed against several data inputs called data points.
+ * To make a test method a theory you mark it with <b>&#064;Theory</b>. To create a data point you create a public
+ * field in your test class and mark it with <b>&#064;DataPoint</b>. The Theories runner then executes your test
+ * method as many times as the number of data points declared, providing a different data point as
+ * the input argument on each invocation.
+ * </p>
+ * <p>
+ * A Theory differs from standard test method in that it captures some aspect of the intended behavior in possibly
+ * infinite numbers of scenarios which corresponds to the number of data points declared. Using assumptions and
+ * assertions properly together with covering multiple scenarios with different data points can make your tests more
+ * flexible and bring them closer to scientific theories (hence the name).
+ * </p>
+ * <p>
+ * For example:
+ * <pre>
+ *
+ * &#064;RunWith(<b>Theories.class</b>)
+ * public class UserTest {
+ *      <b>&#064;DataPoint</b>
+ *      public static String GOOD_USERNAME = "optimus";
+ *      <b>&#064;DataPoint</b>
+ *      public static String USERNAME_WITH_SLASH = "optimus/prime";
+ *
+ *      <b>&#064;Theory</b>
+ *      public void filenameIncludesUsername(String username) {
+ *          assumeThat(username, not(containsString("/")));
+ *          assertThat(new User(username).configFileName(), containsString(username));
+ *      }
+ * }
+ * </pre>
+ * This makes it clear that the username should be included in the config file name,
+ * only if it doesn't contain a slash. Another test or theory might define what happens when a username does contain
+ * a slash. <code>UserTest</code> will attempt to run <code>filenameIncludesUsername</code> on every compatible data
+ * point defined in the class. If any of the assumptions fail, the data point is silently ignored. If all of the
+ * assumptions pass, but an assertion fails, the test fails.
+ * <p>
+ * Defining general statements as theories allows data point reuse across a bunch of functionality tests and also
+ * allows automated tools to search for new, unexpected data points that expose bugs.
+ * </p>
+ * <p>
+ * The support for Theories has been absorbed from the Popper project, and more complete documentation can be found
+ * from that projects archived documentation.
+ * </p>
+ *
+ * @see <a href="http://web.archive.org/web/20071012143326/popper.tigris.org/tutorial.html">Archived Popper project documentation</a>
+ * @see <a href="http://web.archive.org/web/20110608210825/http://shareandenjoy.saff.net/tdd-specifications.pdf">Paper on Theories</a>
+ */
 public class Theories extends BlockJUnit4ClassRunner {
     public Theories(Class<?> klass) throws InitializationError {
         super(klass);
@@ -76,12 +126,34 @@
             } else {
                 each.validatePublicVoidNoArg(false, errors);
             }
+            
+            for (ParameterSignature signature : ParameterSignature.signatures(each.getMethod())) {
+                ParametersSuppliedBy annotation = signature.findDeepAnnotation(ParametersSuppliedBy.class);
+                if (annotation != null) {
+                    validateParameterSupplier(annotation.value(), errors);
+                }
+            }
+        }
+    }
+
+    private void validateParameterSupplier(Class<? extends ParameterSupplier> supplierClass, List<Throwable> errors) {
+        Constructor<?>[] constructors = supplierClass.getConstructors();
+        
+        if (constructors.length != 1) {
+            errors.add(new Error("ParameterSupplier " + supplierClass.getName() + 
+                                 " must have only one constructor (either empty or taking only a TestClass)"));
+        } else {
+            Class<?>[] paramTypes = constructors[0].getParameterTypes();
+            if (!(paramTypes.length == 0) && !paramTypes[0].equals(TestClass.class)) {
+                errors.add(new Error("ParameterSupplier " + supplierClass.getName() + 
+                                     " constructor must take either nothing or a single TestClass instance"));
+            }
         }
     }
 
     @Override
     protected List<FrameworkMethod> computeTestMethods() {
-        List<FrameworkMethod> testMethods = super.computeTestMethods();
+        List<FrameworkMethod> testMethods = new ArrayList<FrameworkMethod>(super.computeTestMethods());
         List<FrameworkMethod> theoryMethods = getTestClass().getAnnotatedMethods(Theory.class);
         testMethods.removeAll(theoryMethods);
         testMethods.addAll(theoryMethods);
@@ -96,27 +168,27 @@
     public static class TheoryAnchor extends Statement {
         private int successes = 0;
 
-        private FrameworkMethod fTestMethod;
-        private TestClass fTestClass;
+        private final FrameworkMethod testMethod;
+        private final TestClass testClass;
 
         private List<AssumptionViolatedException> fInvalidParameters = new ArrayList<AssumptionViolatedException>();
 
-        public TheoryAnchor(FrameworkMethod method, TestClass testClass) {
-            fTestMethod = method;
-            fTestClass = testClass;
+        public TheoryAnchor(FrameworkMethod testMethod, TestClass testClass) {
+            this.testMethod = testMethod;
+            this.testClass = testClass;
         }
 
         private TestClass getTestClass() {
-            return fTestClass;
+            return testClass;
         }
 
         @Override
         public void evaluate() throws Throwable {
             runWithAssignment(Assignments.allUnassigned(
-                    fTestMethod.getMethod(), getTestClass()));
+                    testMethod.getMethod(), getTestClass()));
             
             //if this test method is not annotated with Theory, then no successes is a valid case
-            boolean hasTheoryAnnotation = fTestMethod.getAnnotation(Theory.class) != null;
+            boolean hasTheoryAnnotation = testMethod.getAnnotation(Theory.class) != null;
             if (successes == 0 && hasTheoryAnnotation) {
                 Assert
                         .fail("Never found parameters that satisfied method assumptions.  Violated assumptions: "
@@ -134,8 +206,7 @@
         }
 
         protected void runWithIncompleteAssignment(Assignments incomplete)
-                throws InstantiationException, IllegalAccessException,
-                Throwable {
+                throws Throwable {
             for (PotentialAssignment source : incomplete
                     .potentialsForNextUnassigned()) {
                 runWithAssignment(incomplete.assignNext(source));
@@ -143,8 +214,7 @@
         }
 
         protected void runWithCompleteAssignment(final Assignments complete)
-                throws InstantiationException, IllegalAccessException,
-                InvocationTargetException, NoSuchMethodException, Throwable {
+                throws Throwable {
             new BlockJUnit4ClassRunner(getTestClass().getJavaClass()) {
                 @Override
                 protected void collectInitializationErrors(
@@ -179,10 +249,15 @@
 
                 @Override
                 public Object createTest() throws Exception {
-                    return getTestClass().getOnlyConstructor().newInstance(
-                            complete.getConstructorArguments(nullsOk()));
+                    Object[] params = complete.getConstructorArguments();
+                    
+                    if (!nullsOk()) {
+                        Assume.assumeNotNull(params);
+                    }
+                    
+                    return getTestClass().getOnlyConstructor().newInstance(params);
                 }
-            }.methodBlock(fTestMethod).evaluate();
+            }.methodBlock(testMethod).evaluate();
         }
 
         private Statement methodCompletesWithParameters(
@@ -190,13 +265,13 @@
             return new Statement() {
                 @Override
                 public void evaluate() throws Throwable {
-                    try {
-                        final Object[] values = complete.getMethodArguments(
-                                nullsOk());
-                        method.invokeExplosively(freshInstance, values);
-                    } catch (CouldNotGenerateValueException e) {
-                        // ignore
+                    final Object[] values = complete.getMethodArguments();
+                    
+                    if (!nullsOk()) {
+                        Assume.assumeNotNull(values);
                     }
+                    
+                    method.invokeExplosively(freshInstance, values);
                 }
             };
         }
@@ -210,12 +285,12 @@
             if (params.length == 0) {
                 throw e;
             }
-            throw new ParameterizedAssertionError(e, fTestMethod.getName(),
+            throw new ParameterizedAssertionError(e, testMethod.getName(),
                     params);
         }
 
         private boolean nullsOk() {
-            Theory annotation = fTestMethod.getMethod().getAnnotation(
+            Theory annotation = testMethod.getMethod().getAnnotation(
                     Theory.class);
             if (annotation == null) {
                 return false;
diff --git a/src/main/java/org/junit/experimental/theories/Theory.java b/src/main/java/org/junit/experimental/theories/Theory.java
index 7537941..0b9f2c4 100644
--- a/src/main/java/org/junit/experimental/theories/Theory.java
+++ b/src/main/java/org/junit/experimental/theories/Theory.java
@@ -1,9 +1,18 @@
 package org.junit.experimental.theories;
 
+import static java.lang.annotation.ElementType.METHOD;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
+/**
+ * Marks test methods that should be read as theories by the {@link org.junit.experimental.theories.Theories Theories} runner.
+ *
+ * @see org.junit.experimental.theories.Theories
+ */
 @Retention(RetentionPolicy.RUNTIME)
+@Target(METHOD)
 public @interface Theory {
     boolean nullsAccepted() default true;
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java b/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java
index 3a54a49..f15fb28 100644
--- a/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java
+++ b/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java
@@ -2,15 +2,18 @@
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 
+import org.junit.Assume;
 import org.junit.experimental.theories.DataPoint;
 import org.junit.experimental.theories.DataPoints;
 import org.junit.experimental.theories.ParameterSignature;
 import org.junit.experimental.theories.ParameterSupplier;
 import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.runners.model.FrameworkField;
 import org.junit.runners.model.FrameworkMethod;
 import org.junit.runners.model.TestClass;
 
@@ -19,109 +22,131 @@
  */
 public class AllMembersSupplier extends ParameterSupplier {
     static class MethodParameterValue extends PotentialAssignment {
-        private final FrameworkMethod fMethod;
+        private final FrameworkMethod method;
 
         private MethodParameterValue(FrameworkMethod dataPointMethod) {
-            fMethod = dataPointMethod;
+            method = dataPointMethod;
         }
 
         @Override
         public Object getValue() throws CouldNotGenerateValueException {
             try {
-                return fMethod.invokeExplosively(null);
+                return method.invokeExplosively(null);
             } catch (IllegalArgumentException e) {
                 throw new RuntimeException(
                         "unexpected: argument length is checked");
             } catch (IllegalAccessException e) {
                 throw new RuntimeException(
                         "unexpected: getMethods returned an inaccessible method");
-            } catch (Throwable e) {
-                throw new CouldNotGenerateValueException();
-                // do nothing, just look for more values
+            } catch (Throwable throwable) {
+                DataPoint annotation = method.getAnnotation(DataPoint.class);
+                Assume.assumeTrue(annotation == null || !isAssignableToAnyOf(annotation.ignoredExceptions(), throwable));
+                
+                throw new CouldNotGenerateValueException(throwable);
             }
         }
 
         @Override
         public String getDescription() throws CouldNotGenerateValueException {
-            return fMethod.getName();
+            return method.getName();
         }
     }
-
-    private final TestClass fClass;
+    
+    private final TestClass clazz;
 
     /**
      * Constructs a new supplier for {@code type}
      */
     public AllMembersSupplier(TestClass type) {
-        fClass = type;
+        clazz = type;
     }
 
     @Override
-    public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+    public List<PotentialAssignment> getValueSources(ParameterSignature sig) throws Throwable {
         List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
 
-        addFields(sig, list);
+        addSinglePointFields(sig, list);
+        addMultiPointFields(sig, list);
         addSinglePointMethods(sig, list);
         addMultiPointMethods(sig, list);
 
         return list;
     }
 
-    private void addMultiPointMethods(ParameterSignature sig, List<PotentialAssignment> list) {
-        for (FrameworkMethod dataPointsMethod : fClass
-                .getAnnotatedMethods(DataPoints.class)) {
-            try {
-                addMultiPointArrayValues(sig, dataPointsMethod.getName(), list, dataPointsMethod.invokeExplosively(null));
-            } catch (Throwable e) {
-                // ignore and move on
-            }
-        }
-    }
-
-    private void addSinglePointMethods(ParameterSignature sig,
-            List<PotentialAssignment> list) {
-        for (FrameworkMethod dataPointMethod : fClass
-                .getAnnotatedMethods(DataPoint.class)) {
-            if (sig.canAcceptType(dataPointMethod.getType())) {
-                list.add(new MethodParameterValue(dataPointMethod));
-            }
-        }
-    }
-
-    private void addFields(ParameterSignature sig,
-            List<PotentialAssignment> list) {
-        for (final Field field : fClass.getJavaClass().getFields()) {
-            if (Modifier.isStatic(field.getModifiers())) {
-                Class<?> type = field.getType();
-                if (sig.canAcceptArrayType(type)
-                        && field.getAnnotation(DataPoints.class) != null) {
-                    try {
-                        addArrayValues(field.getName(), list, getStaticFieldValue(field));
-                    } catch (Throwable e) {
-                        // ignore and move on
+    private void addMultiPointMethods(ParameterSignature sig, List<PotentialAssignment> list) throws Throwable {
+        for (FrameworkMethod dataPointsMethod : getDataPointsMethods(sig)) {
+            Class<?> returnType = dataPointsMethod.getReturnType();
+            
+            if ((returnType.isArray() && sig.canPotentiallyAcceptType(returnType.getComponentType())) ||
+                    Iterable.class.isAssignableFrom(returnType)) {
+                try {
+                    addDataPointsValues(returnType, sig, dataPointsMethod.getName(), list, 
+                            dataPointsMethod.invokeExplosively(null));
+                } catch (Throwable throwable) {
+                    DataPoints annotation = dataPointsMethod.getAnnotation(DataPoints.class);
+                    if (annotation != null && isAssignableToAnyOf(annotation.ignoredExceptions(), throwable)) {
+                        return;
+                    } else {
+                        throw throwable;
                     }
-                } else if (sig.canAcceptType(type)
-                        && field.getAnnotation(DataPoint.class) != null) {
-                    list.add(PotentialAssignment
-                            .forValue(field.getName(), getStaticFieldValue(field)));
                 }
             }
         }
     }
 
-    private void addArrayValues(String name, List<PotentialAssignment> list, Object array) {
-        for (int i = 0; i < Array.getLength(array); i++) {
-            list.add(PotentialAssignment.forValue(name + "[" + i + "]", Array.get(array, i)));
+    private void addSinglePointMethods(ParameterSignature sig, List<PotentialAssignment> list) {
+        for (FrameworkMethod dataPointMethod : getSingleDataPointMethods(sig)) {
+            if (sig.canAcceptType(dataPointMethod.getType())) {
+                list.add(new MethodParameterValue(dataPointMethod));
+            }
+        }
+    }
+    
+    private void addMultiPointFields(ParameterSignature sig, List<PotentialAssignment> list) {
+        for (final Field field : getDataPointsFields(sig)) {
+            Class<?> type = field.getType();
+            addDataPointsValues(type, sig, field.getName(), list, getStaticFieldValue(field));
         }
     }
 
-    private void addMultiPointArrayValues(ParameterSignature sig, String name, List<PotentialAssignment> list,
-            Object array) throws Throwable {
-        for (int i = 0; i < Array.getLength(array); i++) {
-            if (!sig.canAcceptValue(Array.get(array, i))) {
-                return;
+    private void addSinglePointFields(ParameterSignature sig, List<PotentialAssignment> list) {
+        for (final Field field : getSingleDataPointFields(sig)) {
+            Object value = getStaticFieldValue(field);
+            
+            if (sig.canAcceptValue(value)) {
+                list.add(PotentialAssignment.forValue(field.getName(), value));
             }
-            list.add(PotentialAssignment.forValue(name + "[" + i + "]", Array.get(array, i)));
+        }
+    }
+    
+    private void addDataPointsValues(Class<?> type, ParameterSignature sig, String name, 
+            List<PotentialAssignment> list, Object value) {
+        if (type.isArray()) {
+            addArrayValues(sig, name, list, value);
+        }
+        else if (Iterable.class.isAssignableFrom(type)) {
+            addIterableValues(sig, name, list, (Iterable<?>) value);
+        }
+    }
+
+    private void addArrayValues(ParameterSignature sig, String name, List<PotentialAssignment> list, Object array) {
+        for (int i = 0; i < Array.getLength(array); i++) {
+            Object value = Array.get(array, i);
+            if (sig.canAcceptValue(value)) {
+                list.add(PotentialAssignment.forValue(name + "[" + i + "]", value));
+            }
+        }
+    }
+    
+    private void addIterableValues(ParameterSignature sig, String name, List<PotentialAssignment> list, Iterable<?> iterable) {
+        Iterator<?> iterator = iterable.iterator();
+        int i = 0;
+        while (iterator.hasNext()) {
+            Object value = iterator.next();
+            if (sig.canAcceptValue(value)) {
+                list.add(PotentialAssignment.forValue(name + "[" + i + "]", value));
+            }
+            i += 1;
         }
     }
 
@@ -136,4 +161,44 @@
                     "unexpected: getFields returned an inaccessible field");
         }
     }
+    
+    private static boolean isAssignableToAnyOf(Class<?>[] typeArray, Object target) {
+        for (Class<?> type : typeArray) {
+            if (type.isAssignableFrom(target.getClass())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected Collection<FrameworkMethod> getDataPointsMethods(ParameterSignature sig) {
+        return clazz.getAnnotatedMethods(DataPoints.class);
+    }
+    
+    protected Collection<Field> getSingleDataPointFields(ParameterSignature sig) {
+        List<FrameworkField> fields = clazz.getAnnotatedFields(DataPoint.class);
+        Collection<Field> validFields = new ArrayList<Field>();
+
+        for (FrameworkField frameworkField : fields) {
+            validFields.add(frameworkField.getField());
+        }
+
+        return validFields;
+    }
+    
+    protected Collection<Field> getDataPointsFields(ParameterSignature sig) {
+        List<FrameworkField> fields = clazz.getAnnotatedFields(DataPoints.class);
+        Collection<Field> validFields = new ArrayList<Field>();
+
+        for (FrameworkField frameworkField : fields) {
+            validFields.add(frameworkField.getField());
+        }
+
+        return validFields;
+    }
+    
+    protected Collection<FrameworkMethod> getSingleDataPointMethods(ParameterSignature sig) {
+        return clazz.getAnnotatedMethods(DataPoint.class);
+    }
+
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/experimental/theories/internal/Assignments.java b/src/main/java/org/junit/experimental/theories/internal/Assignments.java
index 17d2e5d..6626797 100644
--- a/src/main/java/org/junit/experimental/theories/internal/Assignments.java
+++ b/src/main/java/org/junit/experimental/theories/internal/Assignments.java
@@ -1,5 +1,8 @@
 package org.junit.experimental.theories.internal;
 
+import static java.util.Collections.emptyList;
+
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
@@ -16,17 +19,17 @@
  * parameters
  */
 public class Assignments {
-    private List<PotentialAssignment> fAssigned;
+    private final List<PotentialAssignment> assigned;
 
-    private final List<ParameterSignature> fUnassigned;
+    private final List<ParameterSignature> unassigned;
 
-    private final TestClass fClass;
+    private final TestClass clazz;
 
     private Assignments(List<PotentialAssignment> assigned,
-            List<ParameterSignature> unassigned, TestClass testClass) {
-        fUnassigned = unassigned;
-        fAssigned = assigned;
-        fClass = testClass;
+            List<ParameterSignature> unassigned, TestClass clazz) {
+        this.unassigned = unassigned;
+        this.assigned = assigned;
+        this.clazz = clazz;
     }
 
     /**
@@ -34,7 +37,7 @@
      * assigned.
      */
     public static Assignments allUnassigned(Method testMethod,
-            TestClass testClass) throws Exception {
+            TestClass testClass) {
         List<ParameterSignature> signatures;
         signatures = ParameterSignature.signatures(testClass
                 .getOnlyConstructor());
@@ -44,89 +47,106 @@
     }
 
     public boolean isComplete() {
-        return fUnassigned.size() == 0;
+        return unassigned.isEmpty();
     }
 
     public ParameterSignature nextUnassigned() {
-        return fUnassigned.get(0);
+        return unassigned.get(0);
     }
 
     public Assignments assignNext(PotentialAssignment source) {
-        List<PotentialAssignment> assigned = new ArrayList<PotentialAssignment>(
-                fAssigned);
-        assigned.add(source);
+        List<PotentialAssignment> potentialAssignments = new ArrayList<PotentialAssignment>(assigned);
+        potentialAssignments.add(source);
 
-        return new Assignments(assigned, fUnassigned.subList(1, fUnassigned
-                .size()), fClass);
+        return new Assignments(potentialAssignments, unassigned.subList(1,
+                unassigned.size()), clazz);
     }
 
-    public Object[] getActualValues(int start, int stop, boolean nullsOk)
+    public Object[] getActualValues(int start, int stop) 
             throws CouldNotGenerateValueException {
         Object[] values = new Object[stop - start];
         for (int i = start; i < stop; i++) {
-            Object value = fAssigned.get(i).getValue();
-            if (value == null && !nullsOk) {
-                throw new CouldNotGenerateValueException();
-            }
-            values[i - start] = value;
+            values[i - start] = assigned.get(i).getValue();
         }
         return values;
     }
 
     public List<PotentialAssignment> potentialsForNextUnassigned()
-            throws InstantiationException, IllegalAccessException {
+            throws Throwable {
         ParameterSignature unassigned = nextUnassigned();
-        return getSupplier(unassigned).getValueSources(unassigned);
-    }
-
-    public ParameterSupplier getSupplier(ParameterSignature unassigned)
-            throws InstantiationException, IllegalAccessException {
-        ParameterSupplier supplier = getAnnotatedSupplier(unassigned);
-        if (supplier != null) {
-            return supplier;
+        List<PotentialAssignment> assignments = getSupplier(unassigned).getValueSources(unassigned);
+        
+        if (assignments.isEmpty()) {
+            assignments = generateAssignmentsFromTypeAlone(unassigned);
         }
-
-        return new AllMembersSupplier(fClass);
+        
+        return assignments;
     }
 
-    public ParameterSupplier getAnnotatedSupplier(ParameterSignature unassigned)
-            throws InstantiationException, IllegalAccessException {
+    private List<PotentialAssignment> generateAssignmentsFromTypeAlone(ParameterSignature unassigned) {
+        Class<?> paramType = unassigned.getType();
+        
+        if (paramType.isEnum()) {
+            return new EnumSupplier(paramType).getValueSources(unassigned);  
+        } else if (paramType.equals(Boolean.class) || paramType.equals(boolean.class)) {
+            return new BooleanSupplier().getValueSources(unassigned);
+        } else {
+            return emptyList();
+        }
+    }
+
+    private ParameterSupplier getSupplier(ParameterSignature unassigned)
+            throws Exception {
         ParametersSuppliedBy annotation = unassigned
                 .findDeepAnnotation(ParametersSuppliedBy.class);
-        if (annotation == null) {
-            return null;
+        
+        if (annotation != null) {
+            return buildParameterSupplierFromClass(annotation.value());
+        } else {
+            return new AllMembersSupplier(clazz);
         }
-        return annotation.value().newInstance();
     }
 
-    public Object[] getConstructorArguments(boolean nullsOk)
-            throws CouldNotGenerateValueException {
-        return getActualValues(0, getConstructorParameterCount(), nullsOk);
+    private ParameterSupplier buildParameterSupplierFromClass(
+            Class<? extends ParameterSupplier> cls) throws Exception {
+        Constructor<?>[] supplierConstructors = cls.getConstructors();
+
+        for (Constructor<?> constructor : supplierConstructors) {
+            Class<?>[] parameterTypes = constructor.getParameterTypes();
+            if (parameterTypes.length == 1
+                    && parameterTypes[0].equals(TestClass.class)) {
+                return (ParameterSupplier) constructor.newInstance(clazz);
+            }
+        }
+
+        return cls.newInstance();
     }
 
-    public Object[] getMethodArguments(boolean nullsOk)
+    public Object[] getConstructorArguments()
             throws CouldNotGenerateValueException {
-        return getActualValues(getConstructorParameterCount(),
-                fAssigned.size(), nullsOk);
+        return getActualValues(0, getConstructorParameterCount());
     }
 
-    public Object[] getAllArguments(boolean nullsOk)
-            throws CouldNotGenerateValueException {
-        return getActualValues(0, fAssigned.size(), nullsOk);
+    public Object[] getMethodArguments() throws CouldNotGenerateValueException {
+        return getActualValues(getConstructorParameterCount(), assigned.size());
+    }
+
+    public Object[] getAllArguments() throws CouldNotGenerateValueException {
+        return getActualValues(0, assigned.size());
     }
 
     private int getConstructorParameterCount() {
         List<ParameterSignature> signatures = ParameterSignature
-                .signatures(fClass.getOnlyConstructor());
+                .signatures(clazz.getOnlyConstructor());
         int constructorParameterCount = signatures.size();
         return constructorParameterCount;
     }
 
     public Object[] getArgumentStrings(boolean nullsOk)
             throws CouldNotGenerateValueException {
-        Object[] values = new Object[fAssigned.size()];
+        Object[] values = new Object[assigned.size()];
         for (int i = 0; i < values.length; i++) {
-            values[i] = fAssigned.get(i).getDescription();
+            values[i] = assigned.get(i).getDescription();
         }
         return values;
     }
diff --git a/src/main/java/org/junit/experimental/theories/internal/BooleanSupplier.java b/src/main/java/org/junit/experimental/theories/internal/BooleanSupplier.java
new file mode 100644
index 0000000..5f7032f
--- /dev/null
+++ b/src/main/java/org/junit/experimental/theories/internal/BooleanSupplier.java
@@ -0,0 +1,18 @@
+package org.junit.experimental.theories.internal;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.ParameterSupplier;
+import org.junit.experimental.theories.PotentialAssignment;
+
+public class BooleanSupplier extends ParameterSupplier {
+
+    @Override
+    public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+        return Arrays.asList(PotentialAssignment.forValue("true", true),
+                             PotentialAssignment.forValue("false", false));
+    }
+
+}
diff --git a/src/main/java/org/junit/experimental/theories/internal/EnumSupplier.java b/src/main/java/org/junit/experimental/theories/internal/EnumSupplier.java
new file mode 100644
index 0000000..1f3ab90
--- /dev/null
+++ b/src/main/java/org/junit/experimental/theories/internal/EnumSupplier.java
@@ -0,0 +1,30 @@
+package org.junit.experimental.theories.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.ParameterSupplier;
+import org.junit.experimental.theories.PotentialAssignment;
+
+public class EnumSupplier extends ParameterSupplier {
+
+    private Class<?> enumType;
+
+    public EnumSupplier(Class<?> enumType) {
+        this.enumType = enumType;
+    }
+
+    @Override
+    public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+        Object[] enumValues = enumType.getEnumConstants();
+        
+        List<PotentialAssignment> assignments = new ArrayList<PotentialAssignment>();
+        for (Object value : enumValues) {
+            assignments.add(PotentialAssignment.forValue(value.toString(), value));
+        }
+        
+        return assignments;
+    }
+
+}
diff --git a/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java b/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java
index 52938ee..5b9e947 100644
--- a/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java
+++ b/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java
@@ -4,36 +4,40 @@
 import java.util.Collection;
 import java.util.Iterator;
 
-public class ParameterizedAssertionError extends RuntimeException {
+public class ParameterizedAssertionError extends AssertionError {
     private static final long serialVersionUID = 1L;
 
     public ParameterizedAssertionError(Throwable targetException,
             String methodName, Object... params) {
-        super(String.format("%s(%s)", methodName, join(", ", params)),
-                targetException);
+        super(String.format("%s(%s)", methodName, join(", ", params)));
+        this.initCause(targetException);
     }
 
     @Override
     public boolean equals(Object obj) {
-        return toString().equals(obj.toString());
+        return obj instanceof ParameterizedAssertionError && toString().equals(obj.toString());
+    }
+
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
     }
 
     public static String join(String delimiter, Object... params) {
         return join(delimiter, Arrays.asList(params));
     }
 
-    public static String join(String delimiter,
-            Collection<Object> values) {
-        StringBuffer buffer = new StringBuffer();
+    public static String join(String delimiter, Collection<Object> values) {
+        StringBuilder sb = new StringBuilder();
         Iterator<Object> iter = values.iterator();
         while (iter.hasNext()) {
             Object next = iter.next();
-            buffer.append(stringValueOf(next));
+            sb.append(stringValueOf(next));
             if (iter.hasNext()) {
-                buffer.append(delimiter);
+                sb.append(delimiter);
             }
         }
-        return buffer.toString();
+        return sb.toString();
     }
 
     private static String stringValueOf(Object next) {
diff --git a/src/main/java/org/junit/experimental/theories/internal/SpecificDataPointsSupplier.java b/src/main/java/org/junit/experimental/theories/internal/SpecificDataPointsSupplier.java
new file mode 100644
index 0000000..7b571e3
--- /dev/null
+++ b/src/main/java/org/junit/experimental/theories/internal/SpecificDataPointsSupplier.java
@@ -0,0 +1,90 @@
+package org.junit.experimental.theories.internal;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.FromDataPoints;
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.TestClass;
+
+public class SpecificDataPointsSupplier extends AllMembersSupplier {
+
+    public SpecificDataPointsSupplier(TestClass testClass) {
+        super(testClass);
+    }
+    
+    @Override
+    protected Collection<Field> getSingleDataPointFields(ParameterSignature sig) {
+        Collection<Field> fields = super.getSingleDataPointFields(sig);        
+        String requestedName = sig.getAnnotation(FromDataPoints.class).value();
+
+        List<Field> fieldsWithMatchingNames = new ArrayList<Field>();
+        
+        for (Field field : fields) {
+            String[] fieldNames = field.getAnnotation(DataPoint.class).value();
+            if (Arrays.asList(fieldNames).contains(requestedName)) {
+                fieldsWithMatchingNames.add(field);
+            }
+        }
+        
+        return fieldsWithMatchingNames;
+    }
+    
+    @Override
+    protected Collection<Field> getDataPointsFields(ParameterSignature sig) {
+        Collection<Field> fields = super.getDataPointsFields(sig);        
+        String requestedName = sig.getAnnotation(FromDataPoints.class).value();
+        
+        List<Field> fieldsWithMatchingNames = new ArrayList<Field>();
+        
+        for (Field field : fields) {
+            String[] fieldNames = field.getAnnotation(DataPoints.class).value();
+            if (Arrays.asList(fieldNames).contains(requestedName)) {
+                fieldsWithMatchingNames.add(field);
+            }
+        }
+        
+        return fieldsWithMatchingNames;
+    }
+    
+    @Override
+    protected Collection<FrameworkMethod> getSingleDataPointMethods(ParameterSignature sig) {
+        Collection<FrameworkMethod> methods = super.getSingleDataPointMethods(sig);
+        String requestedName = sig.getAnnotation(FromDataPoints.class).value();
+        
+        List<FrameworkMethod> methodsWithMatchingNames = new ArrayList<FrameworkMethod>();
+        
+        for (FrameworkMethod method : methods) {
+            String[] methodNames = method.getAnnotation(DataPoint.class).value();
+            if (Arrays.asList(methodNames).contains(requestedName)) {
+                methodsWithMatchingNames.add(method);
+            }
+        }
+        
+        return methodsWithMatchingNames;
+    }
+    
+    @Override
+    protected Collection<FrameworkMethod> getDataPointsMethods(ParameterSignature sig) {
+        Collection<FrameworkMethod> methods = super.getDataPointsMethods(sig);
+        String requestedName = sig.getAnnotation(FromDataPoints.class).value();
+        
+        List<FrameworkMethod> methodsWithMatchingNames = new ArrayList<FrameworkMethod>();
+        
+        for (FrameworkMethod method : methods) {
+            String[] methodNames = method.getAnnotation(DataPoints.class).value();
+            if (Arrays.asList(methodNames).contains(requestedName)) {
+                methodsWithMatchingNames.add(method);
+            }
+        }
+        
+        return methodsWithMatchingNames;
+    }
+
+}
diff --git a/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java b/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java
index 36d7738..a19f20a 100644
--- a/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java
+++ b/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java
@@ -1,12 +1,31 @@
 package org.junit.experimental.theories.suppliers;
 
+import static java.lang.annotation.ElementType.PARAMETER;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 import org.junit.experimental.theories.ParametersSuppliedBy;
 
+/**
+ * Annotating a {@link org.junit.experimental.theories.Theory Theory} method int
+ * parameter with &#064;TestedOn causes it to be supplied with values from the
+ * ints array given when run as a theory by the
+ * {@link org.junit.experimental.theories.Theories Theories} runner. For
+ * example, the below method would be called three times by the Theories runner,
+ * once with each of the int parameters specified.
+ * 
+ * <pre>
+ * &#064;Theory
+ * public void shouldPassForSomeInts(&#064;TestedOn(ints={1, 2, 3}) int param) {
+ *     ...
+ * }
+ * </pre>
+ */
 @ParametersSuppliedBy(TestedOnSupplier.class)
 @Retention(RetentionPolicy.RUNTIME)
+@Target(PARAMETER)
 public @interface TestedOn {
     int[] ints();
 }
diff --git a/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java b/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java
index d540f76..dc3d0c9 100644
--- a/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java
+++ b/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java
@@ -7,6 +7,10 @@
 import org.junit.experimental.theories.ParameterSupplier;
 import org.junit.experimental.theories.PotentialAssignment;
 
+/**
+ * @see org.junit.experimental.theories.suppliers.TestedOn
+ * @see org.junit.experimental.theories.ParameterSupplier
+ */
 public class TestedOnSupplier extends ParameterSupplier {
     @Override
     public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
diff --git a/src/main/java/org/junit/internal/ArrayComparisonFailure.java b/src/main/java/org/junit/internal/ArrayComparisonFailure.java
index c6a351a..8627d6e 100644
--- a/src/main/java/org/junit/internal/ArrayComparisonFailure.java
+++ b/src/main/java/org/junit/internal/ArrayComparisonFailure.java
@@ -14,9 +14,13 @@
 
     private static final long serialVersionUID = 1L;
 
-    private List<Integer> fIndices = new ArrayList<Integer>();
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
+    private final List<Integer> fIndices = new ArrayList<Integer>();
     private final String fMessage;
-    private final AssertionError fCause;
 
     /**
      * Construct a new <code>ArrayComparisonFailure</code> with an error text and the array's
@@ -27,8 +31,8 @@
      * @see Assert#assertArrayEquals(String, Object[], Object[])
      */
     public ArrayComparisonFailure(String message, AssertionError cause, int index) {
-        fMessage = message;
-        fCause = cause;
+        this.fMessage = message;
+        initCause(cause);
         addDimension(index);
     }
 
@@ -38,19 +42,19 @@
 
     @Override
     public String getMessage() {
-        StringBuilder builder = new StringBuilder();
+        StringBuilder sb = new StringBuilder();
         if (fMessage != null) {
-            builder.append(fMessage);
+            sb.append(fMessage);
         }
-        builder.append("arrays first differed at element ");
+        sb.append("arrays first differed at element ");
         for (int each : fIndices) {
-            builder.append("[");
-            builder.append(each);
-            builder.append("]");
+            sb.append("[");
+            sb.append(each);
+            sb.append("]");
         }
-        builder.append("; ");
-        builder.append(fCause.getMessage());
-        return builder.toString();
+        sb.append("; ");
+        sb.append(getCause().getMessage());
+        return sb.toString();
     }
 
     /**
diff --git a/src/main/java/org/junit/internal/AssumptionViolatedException.java b/src/main/java/org/junit/internal/AssumptionViolatedException.java
index 8196cd1..880d73f 100644
--- a/src/main/java/org/junit/internal/AssumptionViolatedException.java
+++ b/src/main/java/org/junit/internal/AssumptionViolatedException.java
@@ -10,30 +10,43 @@
  * is meaningful and should or should not be executed). A test for which an assumption
  * fails should not generate a test case failure.
  *
- * @see Assume
+ * @see org.junit.Assume
  */
 public class AssumptionViolatedException extends RuntimeException implements SelfDescribing {
     private static final long serialVersionUID = 2L;
 
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
     private final String fAssumption;
-
     private final boolean fValueMatcher;
     private final Object fValue;
-
     private final Matcher<?> fMatcher;
 
-    public AssumptionViolatedException(String assumption, boolean valueMatcher, Object value, Matcher<?> matcher) {
-        super(value instanceof Throwable ? (Throwable) value : null);
-        fAssumption = assumption;
-        fValue = value;
-        fMatcher = matcher;
-        fValueMatcher = valueMatcher;
+    /**
+     * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead.
+     */
+    @Deprecated
+    public AssumptionViolatedException(String assumption, boolean hasValue, Object value, Matcher<?> matcher) {
+        this.fAssumption = assumption;
+        this.fValue = value;
+        this.fMatcher = matcher;
+        this.fValueMatcher = hasValue;
+
+        if (value instanceof Throwable) {
+          initCause((Throwable) value);
+        }
     }
 
     /**
      * An assumption exception with the given <i>value</i> (String or
      * Throwable) and an additional failing {@link Matcher}.
+     *
+     * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead.
      */
+    @Deprecated
     public AssumptionViolatedException(Object value, Matcher<?> matcher) {
         this(null, true, value, matcher);
     }
@@ -41,23 +54,33 @@
     /**
      * An assumption exception with the given <i>value</i> (String or
      * Throwable) and an additional failing {@link Matcher}.
+     *
+     * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead.
      */
+    @Deprecated
     public AssumptionViolatedException(String assumption, Object value, Matcher<?> matcher) {
         this(assumption, true, value, matcher);
     }
 
     /**
      * An assumption exception with the given message only.
+     *
+     * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead.
      */
+    @Deprecated
     public AssumptionViolatedException(String assumption) {
         this(assumption, false, null, null);
     }
 
     /**
      * An assumption exception with the given message and a cause.
+     *
+     * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead.
      */
-    public AssumptionViolatedException(String assumption, Throwable t) {
-        this(assumption, false, t, null);
+    @Deprecated
+    public AssumptionViolatedException(String assumption, Throwable e) {
+        this(assumption, false, null, null);
+        initCause(e);
     }
 
     @Override
@@ -71,6 +94,7 @@
         }
 
         if (fValueMatcher) {
+            // a value was passed in when this instance was constructed; print it
             if (fAssumption != null) {
                 description.appendText(": ");
             }
@@ -84,4 +108,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/internal/Classes.java b/src/main/java/org/junit/internal/Classes.java
new file mode 100644
index 0000000..beca445
--- /dev/null
+++ b/src/main/java/org/junit/internal/Classes.java
@@ -0,0 +1,27 @@
+package org.junit.internal;

+

+import static java.lang.Thread.currentThread;

+

+/**

+ * Miscellaneous functions dealing with classes.

+ */

+public class Classes {

+

+    /**

+     * Do not instantiate.

+     * @deprecated will be private soon.

+     */

+    @Deprecated

+    public Classes() {

+    }

+

+    /**

+     * Returns Class.forName for {@code className} using the current thread's class loader.

+     *

+     * @param className Name of the class.

+     * @throws ClassNotFoundException

+     */

+    public static Class<?> getClass(String className) throws ClassNotFoundException {

+        return Class.forName(className, true, currentThread().getContextClassLoader());

+    }

+}

diff --git a/src/main/java/org/junit/internal/ComparisonCriteria.java b/src/main/java/org/junit/internal/ComparisonCriteria.java
index a589bee..3a0ca1f 100644
--- a/src/main/java/org/junit/internal/ComparisonCriteria.java
+++ b/src/main/java/org/junit/internal/ComparisonCriteria.java
@@ -1,6 +1,7 @@
 package org.junit.internal;
 
 import java.lang.reflect.Array;
+import java.util.Arrays;
 
 import org.junit.Assert;
 
@@ -24,13 +25,23 @@
      */
     public void arrayEquals(String message, Object expecteds, Object actuals)
             throws ArrayComparisonFailure {
-        if (expecteds == actuals) {
+        arrayEquals(message, expecteds, actuals, true);
+    }
+
+    private void arrayEquals(String message, Object expecteds, Object actuals, boolean outer)
+            throws ArrayComparisonFailure {
+        if (expecteds == actuals
+            || Arrays.deepEquals(new Object[] {expecteds}, new Object[] {actuals})) {
+            // The reflection-based loop below is potentially very slow, especially for primitive
+            // arrays. The deepEquals check allows us to circumvent it in the usual case where
+            // the arrays are exactly equal.
             return;
         }
         String header = message == null ? "" : message + ": ";
 
-        int expectedsLength = assertArraysAreSameLength(expecteds,
-                actuals, header);
+        // Only include the user-provided message in the outer exception.
+        String exceptionMessage = outer ? header : "";
+        int expectedsLength = assertArraysAreSameLength(expecteds, actuals, exceptionMessage);
 
         for (int i = 0; i < expectedsLength; i++) {
             Object expected = Array.get(expecteds, i);
@@ -38,10 +49,13 @@
 
             if (isArray(expected) && isArray(actual)) {
                 try {
-                    arrayEquals(message, expected, actual);
+                    arrayEquals(message, expected, actual, false);
                 } catch (ArrayComparisonFailure e) {
                     e.addDimension(i);
                     throw e;
+                } catch (AssertionError e) {
+                    // Array lengths differed.
+                    throw new ArrayComparisonFailure(header, e, i);
                 }
             } else {
                 try {
diff --git a/src/main/java/org/junit/internal/JUnitSystem.java b/src/main/java/org/junit/internal/JUnitSystem.java
index 975ab9c..cf0f2c0 100644
--- a/src/main/java/org/junit/internal/JUnitSystem.java
+++ b/src/main/java/org/junit/internal/JUnitSystem.java
@@ -3,5 +3,12 @@
 import java.io.PrintStream;
 
 public interface JUnitSystem {
+
+    /**
+     * Will be removed in the next major release
+     */
+    @Deprecated
+    void exit(int code);
+
     PrintStream out();
 }
diff --git a/src/main/java/org/junit/internal/MethodSorter.java b/src/main/java/org/junit/internal/MethodSorter.java
index 221ebc5..d8e661a 100644
--- a/src/main/java/org/junit/internal/MethodSorter.java
+++ b/src/main/java/org/junit/internal/MethodSorter.java
@@ -10,7 +10,7 @@
     /**
      * DEFAULT sort order
      */
-    public static Comparator<Method> DEFAULT = new Comparator<Method>() {
+    public static final Comparator<Method> DEFAULT = new Comparator<Method>() {
         public int compare(Method m1, Method m2) {
             int i1 = m1.getName().hashCode();
             int i2 = m2.getName().hashCode();
@@ -24,7 +24,7 @@
     /**
      * Method name ascending lexicographic sort order, with {@link Method#toString()} as a tiebreaker
      */
-    public static Comparator<Method> NAME_ASCENDING = new Comparator<Method>() {
+    public static final Comparator<Method> NAME_ASCENDING = new Comparator<Method>() {
         public int compare(Method m1, Method m2) {
             final int comparison = m1.getName().compareTo(m2.getName());
             if (comparison != 0) {
diff --git a/src/main/java/org/junit/internal/RealSystem.java b/src/main/java/org/junit/internal/RealSystem.java
index 9fb9e0e..e64e1fe 100644
--- a/src/main/java/org/junit/internal/RealSystem.java
+++ b/src/main/java/org/junit/internal/RealSystem.java
@@ -3,6 +3,15 @@
 import java.io.PrintStream;
 
 public class RealSystem implements JUnitSystem {
+
+    /**
+     * Will be removed in the next major release
+     */
+    @Deprecated
+    public void exit(int code) {
+        System.exit(code);
+    }
+
     public PrintStream out() {
         return System.out;
     }
diff --git a/src/main/java/org/junit/internal/TextListener.java b/src/main/java/org/junit/internal/TextListener.java
index 7bfe2d8..a75e80d 100644
--- a/src/main/java/org/junit/internal/TextListener.java
+++ b/src/main/java/org/junit/internal/TextListener.java
@@ -11,14 +11,14 @@
 
 public class TextListener extends RunListener {
 
-    private final PrintStream fWriter;
+    private final PrintStream writer;
 
     public TextListener(JUnitSystem system) {
         this(system.out());
     }
 
     public TextListener(PrintStream writer) {
-        this.fWriter = writer;
+        this.writer = writer;
     }
 
     @Override
@@ -30,17 +30,17 @@
 
     @Override
     public void testStarted(Description description) {
-        fWriter.append('.');
+        writer.append('.');
     }
 
     @Override
     public void testFailure(Failure failure) {
-        fWriter.append('E');
+        writer.append('E');
     }
 
     @Override
     public void testIgnored(Description description) {
-        fWriter.append('I');
+        writer.append('I');
     }
 
     /*
@@ -48,7 +48,7 @@
       */
 
     private PrintStream getWriter() {
-        return fWriter;
+        return writer;
     }
 
     protected void printHeader(long runTime) {
@@ -58,7 +58,7 @@
 
     protected void printFailures(Result result) {
         List<Failure> failures = result.getFailures();
-        if (failures.size() == 0) {
+        if (failures.isEmpty()) {
             return;
         }
         if (failures.size() == 1) {
diff --git a/src/main/java/org/junit/internal/Throwables.java b/src/main/java/org/junit/internal/Throwables.java
new file mode 100644
index 0000000..86dceef
--- /dev/null
+++ b/src/main/java/org/junit/internal/Throwables.java
@@ -0,0 +1,42 @@
+package org.junit.internal;
+
+/**
+ * Miscellaneous functions dealing with {@code Throwable}.
+ *
+ * @author kcooney@google.com (Kevin Cooney)
+ * @since 4.12
+ */
+public final class Throwables {
+
+    private Throwables() {
+    }
+
+    /**
+     * Rethrows the given {@code Throwable}, allowing the caller to
+     * declare that it throws {@code Exception}. This is useful when
+     * your callers have nothing reasonable they can do when a
+     * {@code Throwable} is thrown. This is declared to return {@code Exception}
+     * so it can be used in a {@code throw} clause:
+     * <pre>
+     * try {
+     *   doSomething();
+     * } catch (Throwable e} {
+     *   throw Throwables.rethrowAsException(e);
+     * }
+     * doSomethingLater();
+     * </pre>
+     *
+     * @param e exception to rethrow
+     * @return does not return anything
+     * @since 4.12
+     */
+    public static Exception rethrowAsException(Throwable e) throws Exception {
+        Throwables.<Exception>rethrow(e);
+        return null; // we never get here
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends Throwable> void rethrow(Throwable e) throws T {
+        throw (T) e;
+    }
+}
diff --git a/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java b/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java
index de2125a..d86ec95 100644
--- a/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java
+++ b/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java
@@ -7,10 +7,10 @@
 import org.junit.runners.model.RunnerBuilder;
 
 public class AllDefaultPossibilitiesBuilder extends RunnerBuilder {
-    private final boolean fCanUseSuiteMethod;
+    private final boolean canUseSuiteMethod;
 
     public AllDefaultPossibilitiesBuilder(boolean canUseSuiteMethod) {
-        fCanUseSuiteMethod = canUseSuiteMethod;
+        this.canUseSuiteMethod = canUseSuiteMethod;
     }
 
     @Override
@@ -48,7 +48,7 @@
     }
 
     protected RunnerBuilder suiteMethodBuilder() {
-        if (fCanUseSuiteMethod) {
+        if (canUseSuiteMethod) {
             return new SuiteMethodBuilder();
         }
         return new NullBuilder();
diff --git a/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java b/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java
index bdb6b2c..04d7a68 100644
--- a/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java
+++ b/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java
@@ -5,34 +5,107 @@
 import org.junit.runners.model.InitializationError;
 import org.junit.runners.model.RunnerBuilder;
 
+import java.lang.reflect.Modifier;
+
+
+/**
+ * The {@code AnnotatedBuilder} is a strategy for constructing runners for test class that have been annotated with the
+ * {@code @RunWith} annotation. All tests within this class will be executed using the runner that was specified within
+ * the annotation.
+ * <p>
+ * If a runner supports inner member classes, the member classes will inherit the runner from the enclosing class, e.g.:
+ * <pre>
+ * &#064;RunWith(MyRunner.class)
+ * public class MyTest {
+ *     // some tests might go here
+ *
+ *     public class MyMemberClass {
+ *         &#064;Test
+ *         public void thisTestRunsWith_MyRunner() {
+ *             // some test logic
+ *         }
+ *
+ *         // some more tests might go here
+ *     }
+ *
+ *     &#064;RunWith(AnotherRunner.class)
+ *     public class AnotherMemberClass {
+ *         // some tests might go here
+ *
+ *         public class DeepInnerClass {
+ *             &#064;Test
+ *             public void thisTestRunsWith_AnotherRunner() {
+ *                 // some test logic
+ *             }
+ *         }
+ *
+ *         public class DeepInheritedClass extends SuperTest {
+ *             &#064;Test
+ *             public void thisTestRunsWith_SuperRunner() {
+ *                 // some test logic
+ *             }
+ *         }
+ *     }
+ * }
+ *
+ * &#064;RunWith(SuperRunner.class)
+ * public class SuperTest {
+ *     // some tests might go here
+ * }
+ * </pre>
+ * The key points to note here are:
+ * <ul>
+ *     <li>If there is no RunWith annotation, no runner will be created.</li>
+ *     <li>The resolve step is inside-out, e.g. the closest RunWith annotation wins</li>
+ *     <li>RunWith annotations are inherited and work as if the class was annotated itself.</li>
+ *     <li>The default JUnit runner does not support inner member classes,
+ *         so this is only valid for custom runners that support inner member classes.</li>
+ *     <li>Custom runners with support for inner classes may or may not support RunWith annotations for member
+ *         classes. Please refer to the custom runner documentation.</li>
+ * </ul>
+ *
+ * @see org.junit.runners.model.RunnerBuilder
+ * @see org.junit.runner.RunWith
+ * @since 4.0
+ */
 public class AnnotatedBuilder extends RunnerBuilder {
     private static final String CONSTRUCTOR_ERROR_FORMAT = "Custom runner class %s should have a public constructor with signature %s(Class testClass)";
 
-    private RunnerBuilder fSuiteBuilder;
+    private final RunnerBuilder suiteBuilder;
 
     public AnnotatedBuilder(RunnerBuilder suiteBuilder) {
-        fSuiteBuilder = suiteBuilder;
+        this.suiteBuilder = suiteBuilder;
     }
 
     @Override
     public Runner runnerForClass(Class<?> testClass) throws Exception {
-        RunWith annotation = testClass.getAnnotation(RunWith.class);
-        if (annotation != null) {
-            return buildRunner(annotation.value(), testClass);
+        for (Class<?> currentTestClass = testClass; currentTestClass != null;
+             currentTestClass = getEnclosingClassForNonStaticMemberClass(currentTestClass)) {
+            RunWith annotation = currentTestClass.getAnnotation(RunWith.class);
+            if (annotation != null) {
+                return buildRunner(annotation.value(), testClass);
+            }
         }
+
         return null;
     }
 
+    private Class<?> getEnclosingClassForNonStaticMemberClass(Class<?> currentTestClass) {
+        if (currentTestClass.isMemberClass() && !Modifier.isStatic(currentTestClass.getModifiers())) {
+            return currentTestClass.getEnclosingClass();
+        } else {
+            return null;
+        }
+    }
+
     public Runner buildRunner(Class<? extends Runner> runnerClass,
             Class<?> testClass) throws Exception {
         try {
-            return runnerClass.getConstructor(Class.class).newInstance(
-                    new Object[]{testClass});
+            return runnerClass.getConstructor(Class.class).newInstance(testClass);
         } catch (NoSuchMethodException e) {
             try {
                 return runnerClass.getConstructor(Class.class,
-                        RunnerBuilder.class).newInstance(
-                        new Object[]{testClass, fSuiteBuilder});
+                        RunnerBuilder.class).newInstance(testClass, suiteBuilder);
             } catch (NoSuchMethodException e2) {
                 String simpleName = runnerClass.getSimpleName();
                 throw new InitializationError(String.format(
diff --git a/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java b/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java
index d579012..7c8926b 100644
--- a/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java
+++ b/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java
@@ -5,10 +5,10 @@
 import org.junit.runner.notification.RunNotifier;
 
 public class IgnoredClassRunner extends Runner {
-    private final Class<?> fTestClass;
+    private final Class<?> clazz;
 
     public IgnoredClassRunner(Class<?> testClass) {
-        fTestClass = testClass;
+        clazz = testClass;
     }
 
     @Override
@@ -18,6 +18,6 @@
 
     @Override
     public Description getDescription() {
-        return Description.createSuiteDescription(fTestClass);
+        return Description.createSuiteDescription(clazz);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java
index 83589e4..5d45ba3 100644
--- a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java
+++ b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java
@@ -14,24 +14,24 @@
 public class StacktracePrintingMatcher<T extends Throwable> extends
         org.hamcrest.TypeSafeMatcher<T> {
 
-    private final Matcher<T> fThrowableMatcher;
+    private final Matcher<T> throwableMatcher;
 
     public StacktracePrintingMatcher(Matcher<T> throwableMatcher) {
-        fThrowableMatcher = throwableMatcher;
+        this.throwableMatcher = throwableMatcher;
     }
 
     public void describeTo(Description description) {
-        fThrowableMatcher.describeTo(description);
+        throwableMatcher.describeTo(description);
     }
 
     @Override
     protected boolean matchesSafely(T item) {
-        return fThrowableMatcher.matches(item);
+        return throwableMatcher.matches(item);
     }
 
     @Override
     protected void describeMismatchSafely(T item, Description description) {
-        fThrowableMatcher.describeMismatch(item, description);
+        throwableMatcher.describeMismatch(item, description);
         description.appendText("\nStacktrace was: ");
         description.appendText(readStacktrace(item));
     }
diff --git a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java
index d4e1dec..22ce8bd 100644
--- a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java
+++ b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java
@@ -5,33 +5,46 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 
+/**
+ * A matcher that applies a delegate matcher to the cause of the current Throwable, returning the result of that
+ * match.
+ *
+ * @param <T> the type of the throwable being matched
+ */
 public class ThrowableCauseMatcher<T extends Throwable> extends
         TypeSafeMatcher<T> {
 
-    private final Matcher<T> fMatcher;
+    private final Matcher<? extends Throwable> causeMatcher;
 
-    public ThrowableCauseMatcher(Matcher<T> matcher) {
-        fMatcher = matcher;
+    public ThrowableCauseMatcher(Matcher<? extends Throwable> causeMatcher) {
+        this.causeMatcher = causeMatcher;
     }
 
     public void describeTo(Description description) {
         description.appendText("exception with cause ");
-        description.appendDescriptionOf(fMatcher);
+        description.appendDescriptionOf(causeMatcher);
     }
 
     @Override
     protected boolean matchesSafely(T item) {
-        return fMatcher.matches(item.getCause());
+        return causeMatcher.matches(item.getCause());
     }
 
     @Override
     protected void describeMismatchSafely(T item, Description description) {
         description.appendText("cause ");
-        fMatcher.describeMismatch(item.getCause(), description);
+        causeMatcher.describeMismatch(item.getCause(), description);
     }
 
+    /**
+     * Returns a matcher that verifies that the outer exception has a cause for which the supplied matcher
+     * evaluates to true.
+     *
+     * @param matcher to apply to the cause of the outer exception
+     * @param <T> type of the outer exception
+     */
     @Factory
-    public static <T extends Throwable> Matcher<T> hasCause(final Matcher<T> matcher) {
+    public static <T extends Throwable> Matcher<T> hasCause(final Matcher<? extends Throwable> matcher) {
         return new ThrowableCauseMatcher<T>(matcher);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java b/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java
index 26436dc..74386a8 100644
--- a/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java
+++ b/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java
@@ -8,26 +8,26 @@
 public class ThrowableMessageMatcher<T extends Throwable> extends
         TypeSafeMatcher<T> {
 
-    private final Matcher<String> fMatcher;
+    private final Matcher<String> matcher;
 
     public ThrowableMessageMatcher(Matcher<String> matcher) {
-        fMatcher = matcher;
+        this.matcher = matcher;
     }
 
     public void describeTo(Description description) {
         description.appendText("exception with message ");
-        description.appendDescriptionOf(fMatcher);
+        description.appendDescriptionOf(matcher);
     }
 
     @Override
     protected boolean matchesSafely(T item) {
-        return fMatcher.matches(item.getMessage());
+        return matcher.matches(item.getMessage());
     }
 
     @Override
     protected void describeMismatchSafely(T item, Description description) {
         description.appendText("message ");
-        fMatcher.describeMismatch(item.getMessage(), description);
+        matcher.describeMismatch(item.getMessage(), description);
     }
 
     @Factory
diff --git a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java
index 4e2cc12..fb25982 100644
--- a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java
+++ b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java
@@ -40,7 +40,7 @@
     }
 
     private static boolean isMatchesSafelyMethod(Method method) {
-        return method.getName().equals("matchesSafely")
+        return "matchesSafely".equals(method.getName())
                 && method.getParameterTypes().length == 1
                 && !method.isSynthetic();
     }
diff --git a/src/main/java/org/junit/internal/requests/ClassRequest.java b/src/main/java/org/junit/internal/requests/ClassRequest.java
index c0de065..3d6b100 100644
--- a/src/main/java/org/junit/internal/requests/ClassRequest.java
+++ b/src/main/java/org/junit/internal/requests/ClassRequest.java
@@ -5,14 +5,20 @@
 import org.junit.runner.Runner;
 
 public class ClassRequest extends Request {
-    private final Object fRunnerLock = new Object();
+    private final Object runnerLock = new Object();
+
+    /*
+     * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses
+     * reflection to access this field. See
+     * https://github.com/junit-team/junit/issues/960
+     */
     private final Class<?> fTestClass;
-    private final boolean fCanUseSuiteMethod;
-    private Runner fRunner;
+    private final boolean canUseSuiteMethod;
+    private volatile Runner runner;
 
     public ClassRequest(Class<?> testClass, boolean canUseSuiteMethod) {
-        fTestClass = testClass;
-        fCanUseSuiteMethod = canUseSuiteMethod;
+        this.fTestClass = testClass;
+        this.canUseSuiteMethod = canUseSuiteMethod;
     }
 
     public ClassRequest(Class<?> testClass) {
@@ -21,11 +27,13 @@
 
     @Override
     public Runner getRunner() {
-        synchronized (fRunnerLock) {
-            if (fRunner == null) {
-                fRunner = new AllDefaultPossibilitiesBuilder(fCanUseSuiteMethod).safeRunnerForClass(fTestClass);
+        if (runner == null) {
+            synchronized (runnerLock) {
+                if (runner == null) {
+                    runner = new AllDefaultPossibilitiesBuilder(canUseSuiteMethod).safeRunnerForClass(fTestClass);
+                }
             }
-            return fRunner;
         }
+        return runner;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/requests/FilterRequest.java b/src/main/java/org/junit/internal/requests/FilterRequest.java
index b5826bd..066cba3 100644
--- a/src/main/java/org/junit/internal/requests/FilterRequest.java
+++ b/src/main/java/org/junit/internal/requests/FilterRequest.java
@@ -10,31 +10,36 @@
  * A filtered {@link Request}.
  */
 public final class FilterRequest extends Request {
-    private final Request fRequest;
+    private final Request request;
+    /*
+     * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses
+     * reflection to access this field. See
+     * https://github.com/junit-team/junit/issues/960
+     */
     private final Filter fFilter;
 
     /**
      * Creates a filtered Request
      *
-     * @param classRequest a {@link Request} describing your Tests
+     * @param request a {@link Request} describing your Tests
      * @param filter {@link Filter} to apply to the Tests described in
-     * <code>classRequest</code>
+     * <code>request</code>
      */
-    public FilterRequest(Request classRequest, Filter filter) {
-        fRequest = classRequest;
-        fFilter = filter;
+    public FilterRequest(Request request, Filter filter) {
+        this.request = request;
+        this.fFilter = filter;
     }
 
     @Override
     public Runner getRunner() {
         try {
-            Runner runner = fRequest.getRunner();
+            Runner runner = request.getRunner();
             fFilter.apply(runner);
             return runner;
         } catch (NoTestsRemainException e) {
             return new ErrorReportingRunner(Filter.class, new Exception(String
                     .format("No tests found matching %s from %s", fFilter
-                            .describe(), fRequest.toString())));
+                            .describe(), request.toString())));
         }
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/requests/SortingRequest.java b/src/main/java/org/junit/internal/requests/SortingRequest.java
index f4628d3..77061da 100644
--- a/src/main/java/org/junit/internal/requests/SortingRequest.java
+++ b/src/main/java/org/junit/internal/requests/SortingRequest.java
@@ -8,18 +8,18 @@
 import org.junit.runner.manipulation.Sorter;
 
 public class SortingRequest extends Request {
-    private final Request fRequest;
-    private final Comparator<Description> fComparator;
+    private final Request request;
+    private final Comparator<Description> comparator;
 
     public SortingRequest(Request request, Comparator<Description> comparator) {
-        fRequest = request;
-        fComparator = comparator;
+        this.request = request;
+        this.comparator = comparator;
     }
 
     @Override
     public Runner getRunner() {
-        Runner runner = fRequest.getRunner();
-        new Sorter(fComparator).apply(runner);
+        Runner runner = request.getRunner();
+        new Sorter(comparator).apply(runner);
         return runner;
     }
 }
diff --git a/src/main/java/org/junit/internal/runners/ClassRoadie.java b/src/main/java/org/junit/internal/runners/ClassRoadie.java
index 0e2694a..df1b453 100644
--- a/src/main/java/org/junit/internal/runners/ClassRoadie.java
+++ b/src/main/java/org/junit/internal/runners/ClassRoadie.java
@@ -4,6 +4,7 @@
 import java.lang.reflect.Method;
 import java.util.List;
 
+import org.junit.internal.AssumptionViolatedException;
 import org.junit.runner.Description;
 import org.junit.runner.notification.Failure;
 import org.junit.runner.notification.RunNotifier;
@@ -11,32 +12,30 @@
 
 /**
  * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
- *             removed in the next release. Please use
+ *             removed in the next major release. Please use
  *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
  */
 @Deprecated
 public class ClassRoadie {
-    private RunNotifier fNotifier;
-    private TestClass fTestClass;
-    private Description fDescription;
-    private final Runnable fRunnable;
+    private RunNotifier notifier;
+    private TestClass testClass;
+    private Description description;
+    private final Runnable runnable;
 
     public ClassRoadie(RunNotifier notifier, TestClass testClass,
             Description description, Runnable runnable) {
-        fNotifier = notifier;
-        fTestClass = testClass;
-        fDescription = description;
-        fRunnable = runnable;
+        this.notifier = notifier;
+        this.testClass = testClass;
+        this.description = description;
+        this.runnable = runnable;
     }
 
     protected void runUnprotected() {
-        fRunnable.run();
+        runnable.run();
     }
 
-    ;
-
     protected void addFailure(Throwable targetException) {
-        fNotifier.fireTestFailure(new Failure(fDescription, targetException));
+        notifier.fireTestFailure(new Failure(description, targetException));
     }
 
     public void runProtected() {
@@ -52,14 +51,14 @@
     private void runBefores() throws FailedBefore {
         try {
             try {
-                List<Method> befores = fTestClass.getBefores();
+                List<Method> befores = testClass.getBefores();
                 for (Method before : befores) {
                     before.invoke(null);
                 }
             } catch (InvocationTargetException e) {
                 throw e.getTargetException();
             }
-        } catch (org.junit.internal.AssumptionViolatedException e) {
+        } catch (AssumptionViolatedException e) {
             throw new FailedBefore();
         } catch (Throwable e) {
             addFailure(e);
@@ -68,7 +67,7 @@
     }
 
     private void runAfters() {
-        List<Method> afters = fTestClass.getAfters();
+        List<Method> afters = testClass.getAfters();
         for (Method after : afters) {
             try {
                 after.invoke(null);
@@ -79,4 +78,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java b/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java
index 1d1f680..41af786 100644
--- a/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java
+++ b/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java
@@ -11,19 +11,31 @@
 import org.junit.runners.model.InitializationError;
 
 public class ErrorReportingRunner extends Runner {
-    private final List<Throwable> fCauses;
+    private final List<Throwable> causes;
 
-    private final Class<?> fTestClass;
+    private final String classNames;
 
     public ErrorReportingRunner(Class<?> testClass, Throwable cause) {
-        fTestClass = testClass;
-        fCauses = getCauses(cause);
+        this(cause, new Class<?>[] { testClass });
     }
-
+    
+    public ErrorReportingRunner(Throwable cause, Class<?>... testClasses) {
+        if (testClasses == null || testClasses.length == 0) {
+            throw new NullPointerException("Test classes cannot be null or empty");
+        }
+        for (Class<?> testClass : testClasses) {
+            if (testClass == null) {
+                throw new NullPointerException("Test class cannot be null");
+            }
+        }
+        classNames = getClassNames(testClasses);
+        causes = getCauses(cause);
+    }
+    
     @Override
     public Description getDescription() {
-        Description description = Description.createSuiteDescription(fTestClass);
-        for (Throwable each : fCauses) {
+        Description description = Description.createSuiteDescription(classNames);
+        for (Throwable each : causes) {
             description.addChild(describeCause(each));
         }
         return description;
@@ -31,11 +43,22 @@
 
     @Override
     public void run(RunNotifier notifier) {
-        for (Throwable each : fCauses) {
+        for (Throwable each : causes) {
             runCause(each, notifier);
         }
     }
 
+    private String getClassNames(Class<?>... testClasses) {
+        final StringBuilder builder = new StringBuilder();
+        for (Class<?> testClass : testClasses) {
+            if (builder.length() != 0) {
+                builder.append(", ");
+            }
+            builder.append(testClass.getName());
+        }
+        return builder.toString();
+    }
+
     @SuppressWarnings("deprecation")
     private List<Throwable> getCauses(Throwable cause) {
         if (cause instanceof InvocationTargetException) {
@@ -52,8 +75,7 @@
     }
 
     private Description describeCause(Throwable child) {
-        return Description.createTestDescription(fTestClass,
-                "initializationError");
+        return Description.createTestDescription(classNames, "initializationError");
     }
 
     private void runCause(Throwable child, RunNotifier notifier) {
@@ -62,4 +84,4 @@
         notifier.fireTestFailure(new Failure(description, child));
         notifier.fireTestFinished(description);
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/internal/runners/FailedBefore.java b/src/main/java/org/junit/internal/runners/FailedBefore.java
index ed1fa6b..1036cb6 100644
--- a/src/main/java/org/junit/internal/runners/FailedBefore.java
+++ b/src/main/java/org/junit/internal/runners/FailedBefore.java
@@ -4,7 +4,7 @@
 
 /**
  * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
- *             removed in the next release. Please use
+ *             removed in the next major release. Please use
  *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
  */
 @Deprecated
diff --git a/src/main/java/org/junit/internal/runners/InitializationError.java b/src/main/java/org/junit/internal/runners/InitializationError.java
index e81e773..52065ec 100644
--- a/src/main/java/org/junit/internal/runners/InitializationError.java
+++ b/src/main/java/org/junit/internal/runners/InitializationError.java
@@ -4,16 +4,23 @@
 import java.util.List;
 
 /**
- * Use the published version: {@link org.junit.runners.InitializationError}
+ * Use the published version:
+ * {@link org.junit.runners.model.InitializationError}
  * This may disappear as soon as 1 April 2009
  */
 @Deprecated
 public class InitializationError extends Exception {
     private static final long serialVersionUID = 1L;
+
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
     private final List<Throwable> fErrors;
 
     public InitializationError(List<Throwable> errors) {
-        fErrors = errors;
+        this.fErrors = errors;
     }
 
     public InitializationError(Throwable... errors) {
diff --git a/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java b/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java
index 0945a9f..631fcf2 100644
--- a/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java
+++ b/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java
@@ -17,28 +17,30 @@
 import org.junit.runner.manipulation.Sorter;
 import org.junit.runner.notification.Failure;
 import org.junit.runner.notification.RunNotifier;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
 
 public class JUnit38ClassRunner extends Runner implements Filterable, Sortable {
-    private final class OldTestClassAdaptingListener implements
+    private static final class OldTestClassAdaptingListener implements
             TestListener {
-        private final RunNotifier fNotifier;
+        private final RunNotifier notifier;
 
         private OldTestClassAdaptingListener(RunNotifier notifier) {
-            fNotifier = notifier;
+            this.notifier = notifier;
         }
 
         public void endTest(Test test) {
-            fNotifier.fireTestFinished(asDescription(test));
+            notifier.fireTestFinished(asDescription(test));
         }
 
         public void startTest(Test test) {
-            fNotifier.fireTestStarted(asDescription(test));
+            notifier.fireTestStarted(asDescription(test));
         }
 
         // Implement junit.framework.TestListener
-        public void addError(Test test, Throwable t) {
-            Failure failure = new Failure(asDescription(test), t);
-            fNotifier.fireTestFailure(failure);
+        public void addError(Test test, Throwable e) {
+            Failure failure = new Failure(asDescription(test), e);
+            notifier.fireTestFailure(failure);
         }
 
         private Description asDescription(Test test) {
@@ -66,7 +68,7 @@
         }
     }
 
-    private Test fTest;
+    private volatile Test test;
 
     public JUnit38ClassRunner(Class<?> klass) {
         this(new TestSuite(klass.asSubclass(TestCase.class)));
@@ -96,7 +98,8 @@
     private static Description makeDescription(Test test) {
         if (test instanceof TestCase) {
             TestCase tc = (TestCase) test;
-            return Description.createTestDescription(tc.getClass(), tc.getName());
+            return Description.createTestDescription(tc.getClass(), tc.getName(),
+                    getAnnotations(tc));
         } else if (test instanceof TestSuite) {
             TestSuite ts = (TestSuite) test;
             String name = ts.getName() == null ? createSuiteDescription(ts) : ts.getName();
@@ -119,6 +122,20 @@
         }
     }
 
+    /**
+     * Get the annotations associated with given TestCase.
+     * @param test the TestCase.
+     */
+    private static Annotation[] getAnnotations(TestCase test) {
+        try {
+            Method m = test.getClass().getMethod(test.getName());
+            return m.getDeclaredAnnotations();
+        } catch (SecurityException e) {
+        } catch (NoSuchMethodException e) {
+        }
+        return new Annotation[0];
+    }
+
     private static String createSuiteDescription(TestSuite ts) {
         int count = ts.countTestCases();
         String example = count == 0 ? "" : String.format(" [example: %s]", ts.testAt(0));
@@ -140,6 +157,9 @@
                 }
             }
             setTest(filtered);
+            if (filtered.testCount() == 0) {
+                throw new NoTestsRemainException();
+            }
         }
     }
 
@@ -151,10 +171,10 @@
     }
 
     private void setTest(Test test) {
-        fTest = test;
+        this.test = test;
     }
 
     private Test getTest() {
-        return fTest;
+        return test;
     }
 }
diff --git a/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java b/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java
index 8e3480b..69a23c4 100644
--- a/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java
+++ b/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java
@@ -21,35 +21,33 @@
 
 /**
  * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
- *             removed in the next release. Please use
+ *             removed in the next major release. Please use
  *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
- *
- *             This may disappear as soon as 1 April 2009
  */
 @Deprecated
 public class JUnit4ClassRunner extends Runner implements Filterable, Sortable {
-    private final List<Method> fTestMethods;
-    private TestClass fTestClass;
+    private final List<Method> testMethods;
+    private TestClass testClass;
 
     public JUnit4ClassRunner(Class<?> klass) throws InitializationError {
-        fTestClass = new TestClass(klass);
-        fTestMethods = getTestMethods();
+        testClass = new TestClass(klass);
+        testMethods = getTestMethods();
         validate();
     }
 
     protected List<Method> getTestMethods() {
-        return fTestClass.getTestMethods();
+        return testClass.getTestMethods();
     }
 
     protected void validate() throws InitializationError {
-        MethodValidator methodValidator = new MethodValidator(fTestClass);
+        MethodValidator methodValidator = new MethodValidator(testClass);
         methodValidator.validateMethodsForDefaultRunner();
         methodValidator.assertValid();
     }
 
     @Override
     public void run(final RunNotifier notifier) {
-        new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable() {
+        new ClassRoadie(notifier, testClass, getDescription(), new Runnable() {
             public void run() {
                 runMethods(notifier);
             }
@@ -57,7 +55,7 @@
     }
 
     protected void runMethods(final RunNotifier notifier) {
-        for (Method method : fTestMethods) {
+        for (Method method : testMethods) {
             invokeTestMethod(method, notifier);
         }
     }
@@ -65,7 +63,7 @@
     @Override
     public Description getDescription() {
         Description spec = Description.createSuiteDescription(getName(), classAnnotations());
-        List<Method> testMethods = fTestMethods;
+        List<Method> testMethods = this.testMethods;
         for (Method method : testMethods) {
             spec.addChild(methodDescription(method));
         }
@@ -73,7 +71,7 @@
     }
 
     protected Annotation[] classAnnotations() {
-        return fTestClass.getJavaClass().getAnnotations();
+        return testClass.getJavaClass().getAnnotations();
     }
 
     protected String getName() {
@@ -108,7 +106,7 @@
     }
 
     protected TestMethod wrapMethod(Method method) {
-        return new TestMethod(method, fTestClass);
+        return new TestMethod(method, testClass);
     }
 
     protected String testName(Method method) {
@@ -124,19 +122,19 @@
     }
 
     public void filter(Filter filter) throws NoTestsRemainException {
-        for (Iterator<Method> iter = fTestMethods.iterator(); iter.hasNext(); ) {
+        for (Iterator<Method> iter = testMethods.iterator(); iter.hasNext(); ) {
             Method method = iter.next();
             if (!filter.shouldRun(methodDescription(method))) {
                 iter.remove();
             }
         }
-        if (fTestMethods.isEmpty()) {
+        if (testMethods.isEmpty()) {
             throw new NoTestsRemainException();
         }
     }
 
     public void sort(final Sorter sorter) {
-        Collections.sort(fTestMethods, new Comparator<Method>() {
+        Collections.sort(testMethods, new Comparator<Method>() {
             public int compare(Method o1, Method o2) {
                 return sorter.compare(methodDescription(o1), methodDescription(o2));
             }
@@ -144,6 +142,6 @@
     }
 
     protected TestClass getTestClass() {
-        return fTestClass;
+        return testClass;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/runners/MethodRoadie.java b/src/main/java/org/junit/internal/runners/MethodRoadie.java
index d1c1e48..01a476b 100644
--- a/src/main/java/org/junit/internal/runners/MethodRoadie.java
+++ b/src/main/java/org/junit/internal/runners/MethodRoadie.java
@@ -15,41 +15,42 @@
 import org.junit.runner.notification.Failure;
 import org.junit.runner.notification.RunNotifier;
 import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.TestTimedOutException;
 
 /**
  * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
- *             removed in the next release. Please use
+ *             removed in the next major release. Please use
  *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
  */
 @Deprecated
 public class MethodRoadie {
-    private final Object fTest;
-    private final RunNotifier fNotifier;
-    private final Description fDescription;
-    private TestMethod fTestMethod;
+    private final Object test;
+    private final RunNotifier notifier;
+    private final Description description;
+    private TestMethod testMethod;
 
     public MethodRoadie(Object test, TestMethod method, RunNotifier notifier, Description description) {
-        fTest = test;
-        fNotifier = notifier;
-        fDescription = description;
-        fTestMethod = method;
+        this.test = test;
+        this.notifier = notifier;
+        this.description = description;
+        testMethod = method;
     }
 
     public void run() {
-        if (fTestMethod.isIgnored()) {
-            fNotifier.fireTestIgnored(fDescription);
+        if (testMethod.isIgnored()) {
+            notifier.fireTestIgnored(description);
             return;
         }
-        fNotifier.fireTestStarted(fDescription);
+        notifier.fireTestStarted(description);
         try {
-            long timeout = fTestMethod.getTimeout();
+            long timeout = testMethod.getTimeout();
             if (timeout > 0) {
                 runWithTimeout(timeout);
             } else {
                 runTest();
             }
         } finally {
-            fNotifier.fireTestFinished(fDescription);
+            notifier.fireTestFinished(description);
         }
     }
 
@@ -74,7 +75,7 @@
                     }
                     result.get(0, TimeUnit.MILLISECONDS); // throws the exception if one occurred during the invocation
                 } catch (TimeoutException e) {
-                    addFailure(new Exception(String.format("test timed out after %d milliseconds", timeout)));
+                    addFailure(new TestTimedOutException(timeout, TimeUnit.MILLISECONDS));
                 } catch (Exception e) {
                     addFailure(e);
                 }
@@ -104,18 +105,18 @@
 
     protected void runTestMethod() {
         try {
-            fTestMethod.invoke(fTest);
-            if (fTestMethod.expectsException()) {
-                addFailure(new AssertionError("Expected exception: " + fTestMethod.getExpectedException().getName()));
+            testMethod.invoke(test);
+            if (testMethod.expectsException()) {
+                addFailure(new AssertionError("Expected exception: " + testMethod.getExpectedException().getName()));
             }
         } catch (InvocationTargetException e) {
             Throwable actual = e.getTargetException();
             if (actual instanceof AssumptionViolatedException) {
                 return;
-            } else if (!fTestMethod.expectsException()) {
+            } else if (!testMethod.expectsException()) {
                 addFailure(actual);
-            } else if (fTestMethod.isUnexpected(actual)) {
-                String message = "Unexpected exception, expected<" + fTestMethod.getExpectedException().getName() + "> but was<"
+            } else if (testMethod.isUnexpected(actual)) {
+                String message = "Unexpected exception, expected<" + testMethod.getExpectedException().getName() + "> but was<"
                         + actual.getClass().getName() + ">";
                 addFailure(new Exception(message, actual));
             }
@@ -127,9 +128,9 @@
     private void runBefores() throws FailedBefore {
         try {
             try {
-                List<Method> befores = fTestMethod.getBefores();
+                List<Method> befores = testMethod.getBefores();
                 for (Method before : befores) {
-                    before.invoke(fTest);
+                    before.invoke(test);
                 }
             } catch (InvocationTargetException e) {
                 throw e.getTargetException();
@@ -143,10 +144,10 @@
     }
 
     private void runAfters() {
-        List<Method> afters = fTestMethod.getAfters();
+        List<Method> afters = testMethod.getAfters();
         for (Method after : afters) {
             try {
-                after.invoke(fTest);
+                after.invoke(test);
             } catch (InvocationTargetException e) {
                 addFailure(e.getTargetException());
             } catch (Throwable e) {
@@ -156,7 +157,7 @@
     }
 
     protected void addFailure(Throwable e) {
-        fNotifier.fireTestFailure(new Failure(fDescription, e));
+        notifier.fireTestFailure(new Failure(description, e));
     }
 }
 
diff --git a/src/main/java/org/junit/internal/runners/MethodValidator.java b/src/main/java/org/junit/internal/runners/MethodValidator.java
index 3bec0cf..e656ee5 100644
--- a/src/main/java/org/junit/internal/runners/MethodValidator.java
+++ b/src/main/java/org/junit/internal/runners/MethodValidator.java
@@ -15,18 +15,18 @@
 
 /**
  * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
- *             removed in the next release. Please use
+ *             removed in the next major release. Please use
  *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
  */
 @Deprecated
 public class MethodValidator {
 
-    private final List<Throwable> fErrors = new ArrayList<Throwable>();
+    private final List<Throwable> errors = new ArrayList<Throwable>();
 
-    private TestClass fTestClass;
+    private TestClass testClass;
 
     public MethodValidator(TestClass testClass) {
-        fTestClass = testClass;
+        this.testClass = testClass;
     }
 
     public void validateInstanceMethods() {
@@ -34,9 +34,9 @@
         validateTestMethods(Before.class, false);
         validateTestMethods(Test.class, false);
 
-        List<Method> methods = fTestClass.getAnnotatedMethods(Test.class);
+        List<Method> methods = testClass.getAnnotatedMethods(Test.class);
         if (methods.size() == 0) {
-            fErrors.add(new Exception("No runnable methods"));
+            errors.add(new Exception("No runnable methods"));
         }
     }
 
@@ -49,48 +49,48 @@
         validateNoArgConstructor();
         validateStaticMethods();
         validateInstanceMethods();
-        return fErrors;
+        return errors;
     }
 
     public void assertValid() throws InitializationError {
-        if (!fErrors.isEmpty()) {
-            throw new InitializationError(fErrors);
+        if (!errors.isEmpty()) {
+            throw new InitializationError(errors);
         }
     }
 
     public void validateNoArgConstructor() {
         try {
-            fTestClass.getConstructor();
+            testClass.getConstructor();
         } catch (Exception e) {
-            fErrors.add(new Exception("Test class should have public zero-argument constructor", e));
+            errors.add(new Exception("Test class should have public zero-argument constructor", e));
         }
     }
 
     private void validateTestMethods(Class<? extends Annotation> annotation,
             boolean isStatic) {
-        List<Method> methods = fTestClass.getAnnotatedMethods(annotation);
+        List<Method> methods = testClass.getAnnotatedMethods(annotation);
 
         for (Method each : methods) {
             if (Modifier.isStatic(each.getModifiers()) != isStatic) {
                 String state = isStatic ? "should" : "should not";
-                fErrors.add(new Exception("Method " + each.getName() + "() "
-                        + state + " be static"));
+                errors.add(new Exception("Method " + each.getName() + "() "
+						+ state + " be static"));
             }
             if (!Modifier.isPublic(each.getDeclaringClass().getModifiers())) {
-                fErrors.add(new Exception("Class " + each.getDeclaringClass().getName()
-                        + " should be public"));
+                errors.add(new Exception("Class " + each.getDeclaringClass().getName()
+						+ " should be public"));
             }
             if (!Modifier.isPublic(each.getModifiers())) {
-                fErrors.add(new Exception("Method " + each.getName()
-                        + " should be public"));
+                errors.add(new Exception("Method " + each.getName()
+						+ " should be public"));
             }
             if (each.getReturnType() != Void.TYPE) {
-                fErrors.add(new Exception("Method " + each.getName()
-                        + " should be void"));
+                errors.add(new Exception("Method " + each.getName()
+						+ "should have a return type of void"));
             }
             if (each.getParameterTypes().length != 0) {
-                fErrors.add(new Exception("Method " + each.getName()
-                        + " should have no parameters"));
+                errors.add(new Exception("Method " + each.getName()
+						+ " should have no parameters"));
             }
         }
     }
diff --git a/src/main/java/org/junit/internal/runners/TestClass.java b/src/main/java/org/junit/internal/runners/TestClass.java
index 9d2e108..6d24f4f 100644
--- a/src/main/java/org/junit/internal/runners/TestClass.java
+++ b/src/main/java/org/junit/internal/runners/TestClass.java
@@ -16,15 +16,15 @@
 
 /**
  * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
- *             removed in the next release. Please use
+ *             removed in the next major release. Please use
  *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
  */
 @Deprecated
 public class TestClass {
-    private final Class<?> fClass;
+    private final Class<?> klass;
 
     public TestClass(Class<?> klass) {
-        fClass = klass;
+        this.klass = klass;
     }
 
     public List<Method> getTestMethods() {
@@ -41,7 +41,7 @@
 
     public List<Method> getAnnotatedMethods(Class<? extends Annotation> annotationClass) {
         List<Method> results = new ArrayList<Method>();
-        for (Class<?> eachClass : getSuperClasses(fClass)) {
+        for (Class<?> eachClass : getSuperClasses(klass)) {
             Method[] methods = MethodSorter.getDeclaredMethods(eachClass);
             for (Method eachMethod : methods) {
                 Annotation annotation = eachMethod.getAnnotation(annotationClass);
@@ -85,7 +85,7 @@
     }
 
     private List<Class<?>> getSuperClasses(Class<?> testClass) {
-        ArrayList<Class<?>> results = new ArrayList<Class<?>>();
+        List<Class<?>> results = new ArrayList<Class<?>>();
         Class<?> current = testClass;
         while (current != null) {
             results.add(current);
@@ -95,15 +95,15 @@
     }
 
     public Constructor<?> getConstructor() throws SecurityException, NoSuchMethodException {
-        return fClass.getConstructor();
+        return klass.getConstructor();
     }
 
     public Class<?> getJavaClass() {
-        return fClass;
+        return klass;
     }
 
     public String getName() {
-        return fClass.getName();
+        return klass.getName();
     }
 
 }
diff --git a/src/main/java/org/junit/internal/runners/TestMethod.java b/src/main/java/org/junit/internal/runners/TestMethod.java
index c957bc8..821e193 100644
--- a/src/main/java/org/junit/internal/runners/TestMethod.java
+++ b/src/main/java/org/junit/internal/runners/TestMethod.java
@@ -13,25 +13,25 @@
 
 /**
  * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
- *             removed in the next release. Please use
+ *             removed in the next major release. Please use
  *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
  */
 @Deprecated
 public class TestMethod {
-    private final Method fMethod;
-    private TestClass fTestClass;
+    private final Method method;
+    private TestClass testClass;
 
     public TestMethod(Method method, TestClass testClass) {
-        fMethod = method;
-        fTestClass = testClass;
+        this.method = method;
+        this.testClass = testClass;
     }
 
     public boolean isIgnored() {
-        return fMethod.getAnnotation(Ignore.class) != null;
+        return method.getAnnotation(Ignore.class) != null;
     }
 
     public long getTimeout() {
-        Test annotation = fMethod.getAnnotation(Test.class);
+        Test annotation = method.getAnnotation(Test.class);
         if (annotation == null) {
             return 0;
         }
@@ -40,7 +40,7 @@
     }
 
     protected Class<? extends Throwable> getExpectedException() {
-        Test annotation = fMethod.getAnnotation(Test.class);
+        Test annotation = method.getAnnotation(Test.class);
         if (annotation == null || annotation.expected() == None.class) {
             return null;
         } else {
@@ -57,15 +57,15 @@
     }
 
     List<Method> getBefores() {
-        return fTestClass.getAnnotatedMethods(Before.class);
+        return testClass.getAnnotatedMethods(Before.class);
     }
 
     List<Method> getAfters() {
-        return fTestClass.getAnnotatedMethods(After.class);
+        return testClass.getAnnotatedMethods(After.class);
     }
 
     public void invoke(Object test) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
-        fMethod.invoke(test);
+        method.invoke(test);
     }
 
 }
diff --git a/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java b/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java
index cb31c19..e094809 100644
--- a/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java
+++ b/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java
@@ -7,21 +7,20 @@
 import org.junit.runners.model.MultipleFailureException;
 
 public class EachTestNotifier {
-    private final RunNotifier fNotifier;
+    private final RunNotifier notifier;
 
-    private final Description fDescription;
+    private final Description description;
 
     public EachTestNotifier(RunNotifier notifier, Description description) {
-        fNotifier = notifier;
-        fDescription = description;
+        this.notifier = notifier;
+        this.description = description;
     }
 
     public void addFailure(Throwable targetException) {
         if (targetException instanceof MultipleFailureException) {
             addMultipleFailureException((MultipleFailureException) targetException);
         } else {
-            fNotifier
-                    .fireTestFailure(new Failure(fDescription, targetException));
+            notifier.fireTestFailure(new Failure(description, targetException));
         }
     }
 
@@ -32,18 +31,18 @@
     }
 
     public void addFailedAssumption(AssumptionViolatedException e) {
-        fNotifier.fireTestAssumptionFailed(new Failure(fDescription, e));
+        notifier.fireTestAssumptionFailed(new Failure(description, e));
     }
 
     public void fireTestFinished() {
-        fNotifier.fireTestFinished(fDescription);
+        notifier.fireTestFinished(description);
     }
 
     public void fireTestStarted() {
-        fNotifier.fireTestStarted(fDescription);
+        notifier.fireTestStarted(description);
     }
 
     public void fireTestIgnored() {
-        fNotifier.fireTestIgnored(fDescription);
+        notifier.fireTestIgnored(description);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java b/src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java
deleted file mode 100644
index 93100f6..0000000
--- a/src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java
+++ /dev/null
@@ -1,118 +0,0 @@
-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));
-    }
-}
diff --git a/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java b/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java
new file mode 100644
index 0000000..36de4f1
--- /dev/null
+++ b/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java
@@ -0,0 +1,279 @@
+package org.junit.internal.runners.rules;
+
+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;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A RuleMemberValidator validates the rule fields/methods of a
+ * {@link org.junit.runners.model.TestClass}. All reasons for rejecting the
+ * {@code TestClass} are written to a list of errors.
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ */
+public class RuleMemberValidator {
+    /**
+     * Validates fields with a {@link ClassRule} annotation.
+     */
+    public static final RuleMemberValidator CLASS_RULE_VALIDATOR =
+            classRuleValidatorBuilder()
+            .withValidator(new DeclaringClassMustBePublic())
+            .withValidator(new MemberMustBeStatic())
+            .withValidator(new MemberMustBePublic())
+            .withValidator(new FieldMustBeATestRule())
+            .build();
+    /**
+     * Validates fields with a {@link Rule} annotation.
+     */
+    public static final RuleMemberValidator RULE_VALIDATOR =
+            testRuleValidatorBuilder()
+            .withValidator(new MemberMustBeNonStaticOrAlsoClassRule())
+            .withValidator(new MemberMustBePublic())
+            .withValidator(new FieldMustBeARule())
+            .build();
+    /**
+     * Validates methods with a {@link ClassRule} annotation.
+     */
+    public static final RuleMemberValidator CLASS_RULE_METHOD_VALIDATOR =
+            classRuleValidatorBuilder()
+            .forMethods()
+            .withValidator(new DeclaringClassMustBePublic())
+            .withValidator(new MemberMustBeStatic())
+            .withValidator(new MemberMustBePublic())
+            .withValidator(new MethodMustBeATestRule())
+            .build();
+
+    /**
+     * Validates methods with a {@link Rule} annotation.
+     */
+    public static final RuleMemberValidator RULE_METHOD_VALIDATOR =
+            testRuleValidatorBuilder()
+            .forMethods()
+            .withValidator(new MemberMustBeNonStaticOrAlsoClassRule())
+            .withValidator(new MemberMustBePublic())
+            .withValidator(new MethodMustBeARule())
+            .build();
+
+    private final Class<? extends Annotation> annotation;
+    private final boolean methods;
+    private final List<RuleValidator> validatorStrategies;
+
+    RuleMemberValidator(Builder builder) {
+        this.annotation = builder.annotation;
+        this.methods = builder.methods;
+        this.validatorStrategies = builder.validators;
+    }
+
+    /**
+     * 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 = methods ? target.getAnnotatedMethods(annotation)
+                : target.getAnnotatedFields(annotation);
+
+        for (FrameworkMember<?> each : members) {
+            validateMember(each, errors);
+        }
+    }
+
+    private void validateMember(FrameworkMember<?> member, List<Throwable> errors) {
+        for (RuleValidator strategy : validatorStrategies) {
+            strategy.validate(member, annotation, errors);
+        }
+    }
+
+    private static Builder classRuleValidatorBuilder() {
+        return new Builder(ClassRule.class);
+    }
+
+    private static Builder testRuleValidatorBuilder() {
+        return new Builder(Rule.class);
+    }
+
+    private static class Builder {
+        private final Class<? extends Annotation> annotation;
+        private boolean methods;
+        private final List<RuleValidator> validators;
+
+        private Builder(Class<? extends Annotation> annotation) {
+            this.annotation = annotation;
+            this.methods = false;
+            this.validators = new ArrayList<RuleValidator>();
+        }
+
+        Builder forMethods() {
+            methods = true;
+            return this;
+        }
+
+        Builder withValidator(RuleValidator validator) {
+            validators.add(validator);
+            return this;
+        }
+
+        RuleMemberValidator build() {
+            return new RuleMemberValidator(this);
+        }
+    }
+
+    private static boolean isRuleType(FrameworkMember<?> member) {
+        return isMethodRule(member) || isTestRule(member);
+    }
+
+    private static boolean isTestRule(FrameworkMember<?> member) {
+        return TestRule.class.isAssignableFrom(member.getType());
+    }
+
+    private static boolean isMethodRule(FrameworkMember<?> member) {
+        return MethodRule.class.isAssignableFrom(member.getType());
+    }
+
+    /**
+     * Encapsulates a single piece of validation logic, used to determine if {@link org.junit.Rule} and
+     * {@link org.junit.ClassRule} annotations have been used correctly
+     */
+    interface RuleValidator {
+        /**
+         * Examine the given member and add any violations of the strategy's validation logic to the given list of errors
+         * @param member The member (field or member) to examine
+         * @param annotation The type of rule annotation on the member
+         * @param errors The list of errors to add validation violations to
+         */
+        void validate(FrameworkMember<?> member, Class<? extends Annotation> annotation, List<Throwable> errors);
+    }
+
+    /**
+     * Requires the validated member to be non-static
+     */
+    private static final class MemberMustBeNonStaticOrAlsoClassRule implements RuleValidator {
+        public void validate(FrameworkMember<?> member, Class<? extends Annotation> annotation, List<Throwable> errors) {
+            boolean isMethodRuleMember = isMethodRule(member);
+            boolean isClassRuleAnnotated = (member.getAnnotation(ClassRule.class) != null);
+
+            // We disallow:
+            //  - static MethodRule members
+            //  - static @Rule annotated members
+            //    - UNLESS they're also @ClassRule annotated
+            // Note that MethodRule cannot be annotated with @ClassRule
+            if (member.isStatic() && (isMethodRuleMember || !isClassRuleAnnotated)) {
+                String message;
+                if (isMethodRule(member)) {
+                    message = "must not be static.";
+                } else {
+                    message = "must not be static or it must be annotated with @ClassRule.";
+                }
+                errors.add(new ValidationError(member, annotation, message));
+            }
+        }
+    }
+
+    /**
+     * Requires the member to be static
+     */
+    private static final class MemberMustBeStatic implements RuleValidator {
+        public void validate(FrameworkMember<?> member, Class<? extends Annotation> annotation, List<Throwable> errors) {
+            if (!member.isStatic()) {
+                errors.add(new ValidationError(member, annotation,
+                        "must be static."));
+            }
+        }
+    }
+
+    /**
+     * Requires the member's declaring class to be public
+     */
+    private static final class DeclaringClassMustBePublic implements RuleValidator {
+        public void validate(FrameworkMember<?> member, Class<? extends Annotation> annotation, List<Throwable> errors) {
+            if (!isDeclaringClassPublic(member)) {
+                errors.add(new ValidationError(member, annotation,
+                        "must be declared in a public class."));
+            }
+        }
+
+        private boolean isDeclaringClassPublic(FrameworkMember<?> member) {
+            return Modifier.isPublic(member.getDeclaringClass().getModifiers());
+        }
+    }
+
+    /**
+     * Requires the member to be public
+     */
+    private static final class MemberMustBePublic implements RuleValidator {
+        public void validate(FrameworkMember<?> member, Class<? extends Annotation> annotation, List<Throwable> errors) {
+            if (!member.isPublic()) {
+                errors.add(new ValidationError(member, annotation,
+                        "must be public."));
+            }
+        }
+    }
+
+    /**
+     * Requires the member is a field implementing {@link org.junit.rules.MethodRule} or {@link org.junit.rules.TestRule}
+     */
+    private static final class FieldMustBeARule implements RuleValidator {
+        public void validate(FrameworkMember<?> member, Class<? extends Annotation> annotation, List<Throwable> errors) {
+            if (!isRuleType(member)) {
+                errors.add(new ValidationError(member, annotation,
+                        "must implement MethodRule or TestRule."));
+            }
+        }
+    }
+
+    /**
+     * Require the member to return an implementation of {@link org.junit.rules.MethodRule} or
+     * {@link org.junit.rules.TestRule}
+     */
+    private static final class MethodMustBeARule implements RuleValidator {
+        public void validate(FrameworkMember<?> member, Class<? extends Annotation> annotation, List<Throwable> errors) {
+            if (!isRuleType(member)) {
+                errors.add(new ValidationError(member, annotation,
+                        "must return an implementation of MethodRule or TestRule."));
+            }
+        }
+    }
+    
+    /**
+     * Require the member to return an implementation of {@link org.junit.rules.TestRule}
+     */
+    private static final class MethodMustBeATestRule implements RuleValidator {
+        public void validate(FrameworkMember<?> member,
+                Class<? extends Annotation> annotation, List<Throwable> errors) {
+            if (!isTestRule(member)) {
+                errors.add(new ValidationError(member, annotation, 
+                        "must return an implementation of TestRule."));
+            }
+        }
+    }
+    
+    /**
+     * Requires the member is a field implementing {@link org.junit.rules.TestRule}
+     */
+    private static final class FieldMustBeATestRule implements RuleValidator {
+
+        public void validate(FrameworkMember<?> member,
+                Class<? extends Annotation> annotation, List<Throwable> errors) {
+            if (!isTestRule(member)) {
+                errors.add(new ValidationError(member, annotation,
+                        "must implement TestRule."));
+            }
+        }
+    }
+}
diff --git a/src/main/java/org/junit/internal/runners/rules/ValidationError.java b/src/main/java/org/junit/internal/runners/rules/ValidationError.java
new file mode 100644
index 0000000..31bd660
--- /dev/null
+++ b/src/main/java/org/junit/internal/runners/rules/ValidationError.java
@@ -0,0 +1,14 @@
+package org.junit.internal.runners.rules;
+
+import org.junit.runners.model.FrameworkMember;
+
+import java.lang.annotation.Annotation;
+
+class ValidationError extends Exception {
+
+    private static final long serialVersionUID = 3176511008672645574L;
+
+    public ValidationError(FrameworkMember<?> member, Class<? extends Annotation> annotation, String suffix) {
+        super(String.format("The @%s '%s' %s", annotation.getSimpleName(), member.getName(), suffix));
+    }
+}
diff --git a/src/main/java/org/junit/internal/runners/statements/ExpectException.java b/src/main/java/org/junit/internal/runners/statements/ExpectException.java
index b4b7172..d0636bd 100644
--- a/src/main/java/org/junit/internal/runners/statements/ExpectException.java
+++ b/src/main/java/org/junit/internal/runners/statements/ExpectException.java
@@ -4,33 +4,33 @@
 import org.junit.runners.model.Statement;
 
 public class ExpectException extends Statement {
-    private Statement fNext;
-    private final Class<? extends Throwable> fExpected;
+    private final Statement next;
+    private final Class<? extends Throwable> expected;
 
     public ExpectException(Statement next, Class<? extends Throwable> expected) {
-        fNext = next;
-        fExpected = expected;
+        this.next = next;
+        this.expected = expected;
     }
 
     @Override
     public void evaluate() throws Exception {
         boolean complete = false;
         try {
-            fNext.evaluate();
+            next.evaluate();
             complete = true;
         } catch (AssumptionViolatedException e) {
             throw e;
         } catch (Throwable e) {
-            if (!fExpected.isAssignableFrom(e.getClass())) {
+            if (!expected.isAssignableFrom(e.getClass())) {
                 String message = "Unexpected exception, expected<"
-                        + fExpected.getName() + "> but was<"
+                        + expected.getName() + "> but was<"
                         + e.getClass().getName() + ">";
                 throw new Exception(message, e);
             }
         }
         if (complete) {
             throw new AssertionError("Expected exception: "
-                    + fExpected.getName());
+                    + expected.getName());
         }
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/runners/statements/Fail.java b/src/main/java/org/junit/internal/runners/statements/Fail.java
index 5d6c0fe..e55875c 100644
--- a/src/main/java/org/junit/internal/runners/statements/Fail.java
+++ b/src/main/java/org/junit/internal/runners/statements/Fail.java
@@ -3,14 +3,14 @@
 import org.junit.runners.model.Statement;
 
 public class Fail extends Statement {
-    private final Throwable fError;
+    private final Throwable error;
 
     public Fail(Throwable e) {
-        fError = e;
+        error = e;
     }
 
     @Override
     public void evaluate() throws Throwable {
-        throw fError;
+        throw error;
     }
 }
diff --git a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
index 42e0918..922c969 100644
--- a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
+++ b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
@@ -1,110 +1,287 @@
 package org.junit.internal.runners.statements;
 
-import org.junit.runners.model.Statement;
-
-import java.io.InterruptedIOException;
-import java.nio.channels.ClosedByInterruptException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadMXBean;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.runners.model.MultipleFailureException;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestTimedOutException;
 
 public class FailOnTimeout extends Statement {
-    private final Statement fOriginalStatement;
-    private final TimeUnit fTimeUnit;
-    private final long fTimeout;
+    private final Statement originalStatement;
+    private final TimeUnit timeUnit;
+    private final long timeout;
+    private final boolean lookForStuckThread;
 
-    public FailOnTimeout(Statement originalStatement, long millis) {
-        this(originalStatement, millis, TimeUnit.MILLISECONDS);
+    /**
+     * Returns a new builder for building an instance.
+     *
+     * @since 4.12
+     */
+    public static Builder builder() {
+        return new Builder();
     }
 
-    public FailOnTimeout(Statement originalStatement, long timeout, TimeUnit unit) {
-        fOriginalStatement = originalStatement;
-        fTimeout = timeout;
-        fTimeUnit = unit;
+    /**
+     * Creates an instance wrapping the given statement with the given timeout in milliseconds.
+     *
+     * @param statement the statement to wrap
+     * @param timeoutMillis the timeout in milliseconds
+     * @deprecated use {@link #builder()} instead.
+     */
+    @Deprecated
+    public FailOnTimeout(Statement statement, long timeoutMillis) {
+        this(builder().withTimeout(timeoutMillis, TimeUnit.MILLISECONDS), statement);
+    }
+
+    private FailOnTimeout(Builder builder, Statement statement) {
+        originalStatement = statement;
+        timeout = builder.timeout;
+        timeUnit = builder.unit;
+        lookForStuckThread = builder.lookForStuckThread;
+    }
+
+    /**
+     * Builder for {@link FailOnTimeout}.
+     *
+     * @since 4.12
+     */
+    public static class Builder {
+        private boolean lookForStuckThread = false;
+        private long timeout = 0;
+        private TimeUnit unit = TimeUnit.SECONDS;
+
+        private Builder() {
+        }
+
+        /**
+         * Specifies the time to wait before timing out the test.
+         *
+         * <p>If this is not called, or is called with a {@code timeout} of
+         * {@code 0}, the returned {@code Statement} will wait forever for the
+         * test to complete, however the test will still launch from a separate
+         * thread. This can be useful for disabling timeouts in environments
+         * where they are dynamically set based on some property.
+         *
+         * @param timeout the maximum time to wait
+         * @param unit the time unit of the {@code timeout} argument
+         * @return {@code this} for method chaining.
+         */
+        public Builder withTimeout(long timeout, TimeUnit unit) {
+            if (timeout < 0) {
+                throw new IllegalArgumentException("timeout must be non-negative");
+            }
+            if (unit == null) {
+                throw new NullPointerException("TimeUnit cannot be null");
+            }
+            this.timeout = timeout;
+            this.unit = unit;
+            return this;
+        }
+
+        /**
+         * Specifies whether to look for a stuck thread.  If a timeout occurs and this
+         * feature is enabled, the test will look for a thread that appears to be stuck
+         * and dump its backtrace.  This feature is experimental.  Behavior may change
+         * after the 4.12 release in response to feedback.
+         *
+         * @param enable {@code true} to enable the feature
+         * @return {@code this} for method chaining.
+         */
+        public Builder withLookingForStuckThread(boolean enable) {
+            this.lookForStuckThread = enable;
+            return this;
+        }
+
+        /**
+         * Builds a {@link FailOnTimeout} instance using the values in this builder,
+         * wrapping the given statement.
+         *
+         * @param statement
+         */
+        public FailOnTimeout build(Statement statement) {
+            if (statement == null) {
+                throw new NullPointerException("statement cannot be null");
+            }
+            return new FailOnTimeout(this, statement);
+        }
     }
 
     @Override
     public void evaluate() throws Throwable {
-        StatementThread thread = evaluateStatement();
-        if (!thread.fFinished) {
-            throwExceptionForUnfinishedThread(thread);
-        }
-    }
-
-    private StatementThread evaluateStatement() throws InterruptedException {
-        StatementThread thread = new StatementThread(fOriginalStatement);
-        // Let the process/application complete after timeout expired.
+        CallableStatement callable = new CallableStatement();
+        FutureTask<Throwable> task = new FutureTask<Throwable>(callable);
+        ThreadGroup threadGroup = new ThreadGroup("FailOnTimeoutGroup");
+        Thread thread = new Thread(threadGroup, task, "Time-limited test");
         thread.setDaemon(true);
         thread.start();
-        fTimeUnit.timedJoin(thread, fTimeout);
-        if (!thread.fFinished) {
-            thread.recordStackTrace();
+        callable.awaitStarted();
+        Throwable throwable = getResult(task, thread);
+        if (throwable != null) {
+            throw throwable;
         }
-        thread.interrupt();
-        return thread;
     }
 
-    private void throwExceptionForUnfinishedThread(StatementThread thread)
-            throws Throwable {
-        if (thread.fExceptionThrownByOriginalStatement != null) {
-            throw thread.fExceptionThrownByOriginalStatement;
+    /**
+     * Wait for the test task, returning the exception thrown by the test if the
+     * test failed, an exception indicating a timeout if the test timed out, or
+     * {@code null} if the test passed.
+     */
+    private Throwable getResult(FutureTask<Throwable> task, Thread thread) {
+        try {
+            if (timeout > 0) {
+                return task.get(timeout, timeUnit);
+            } else {
+                return task.get();
+            }
+        } catch (InterruptedException e) {
+            return e; // caller will re-throw; no need to call Thread.interrupt()
+        } catch (ExecutionException e) {
+            // test failed; have caller re-throw the exception thrown by the test
+            return e.getCause();
+        } catch (TimeoutException e) {
+            return createTimeoutException(thread);
+        }
+    }
+
+    private Exception createTimeoutException(Thread thread) {
+        StackTraceElement[] stackTrace = thread.getStackTrace();
+        final Thread stuckThread = lookForStuckThread ? getStuckThread(thread) : null;
+        Exception currThreadException = new TestTimedOutException(timeout, timeUnit);
+        if (stackTrace != null) {
+            currThreadException.setStackTrace(stackTrace);
+            thread.interrupt();
+        }
+        if (stuckThread != null) {
+            Exception stuckThreadException = 
+                new Exception("Appears to be stuck in thread " +
+                               stuckThread.getName());
+            stuckThreadException.setStackTrace(getStackTrace(stuckThread));
+            return new MultipleFailureException(
+                Arrays.<Throwable>asList(currThreadException, stuckThreadException));
         } else {
-            throwTimeoutException(thread);
+            return currThreadException;
         }
     }
 
-    private void throwTimeoutException(StatementThread thread) throws Exception {
-        Exception exception = new Exception(String.format(
-                "test timed out after %d %s", fTimeout, fTimeUnit.name().toLowerCase()));
-        exception.setStackTrace(thread.getRecordedStackTrace());
-        throw exception;
+    /**
+     * Retrieves the stack trace for a given thread.
+     * @param thread The thread whose stack is to be retrieved.
+     * @return The stack trace; returns a zero-length array if the thread has 
+     * terminated or the stack cannot be retrieved for some other reason.
+     */
+    private StackTraceElement[] getStackTrace(Thread thread) {
+        try {
+            return thread.getStackTrace();
+        } catch (SecurityException e) {
+            return new StackTraceElement[0];
+        }
     }
 
-    private static class StatementThread extends Thread {
-        /**
-         * This is final variable because the statement is set once.
-         * Final makes sure that the statement is immediately visible in
-         * #run() (other than current thread) after constructor finished.
-         */
-        private final Statement fStatement;
-
-        /**
-         * These two variables are volatile to make sure that the Thread calling #evaluate()
-         * can immediately read their values set by this thread.
-         * */
-        private volatile boolean fFinished;
-        private volatile Throwable fExceptionThrownByOriginalStatement;
-
-        // No need for volatile, because written and read by one thread.
-        private StackTraceElement[] fRecordedStackTrace;
-
-        public StatementThread(Statement statement) {
-            fFinished = false;
-            fExceptionThrownByOriginalStatement = null;
-            fRecordedStackTrace = null;
-            fStatement = statement;
+    /**
+     * Determines whether the test appears to be stuck in some thread other than
+     * the "main thread" (the one created to run the test).  This feature is experimental.
+     * Behavior may change after the 4.12 release in response to feedback.
+     * @param mainThread The main thread created by {@code evaluate()}
+     * @return The thread which appears to be causing the problem, if different from
+     * {@code mainThread}, or {@code null} if the main thread appears to be the
+     * problem or if the thread cannot be determined.  The return value is never equal 
+     * to {@code mainThread}.
+     */
+    private Thread getStuckThread(Thread mainThread) {
+        List<Thread> threadsInGroup = getThreadsInGroup(mainThread.getThreadGroup());
+        if (threadsInGroup.isEmpty()) {
+            return null;
         }
 
-        public void recordStackTrace() {
-            fRecordedStackTrace = getStackTrace();
+        // Now that we have all the threads in the test's thread group: Assume that
+        // any thread we're "stuck" in is RUNNABLE.  Look for all RUNNABLE threads. 
+        // If just one, we return that (unless it equals threadMain).  If there's more
+        // than one, pick the one that's using the most CPU time, if this feature is
+        // supported.
+        Thread stuckThread = null;
+        long maxCpuTime = 0;
+        for (Thread thread : threadsInGroup) {
+            if (thread.getState() == Thread.State.RUNNABLE) {
+                long threadCpuTime = cpuTime(thread);
+                if (stuckThread == null || threadCpuTime > maxCpuTime) {
+                    stuckThread = thread;
+                    maxCpuTime = threadCpuTime;
+                }
+            }               
         }
+        return (stuckThread == mainThread) ? null : stuckThread;
+    }
 
-        public StackTraceElement[] getRecordedStackTrace() {
-            return fRecordedStackTrace;
+    /**
+     * Returns all active threads belonging to a thread group.  
+     * @param group The thread group.
+     * @return The active threads in the thread group.  The result should be a
+     * complete list of the active threads at some point in time.  Returns an empty list
+     * if this cannot be determined, e.g. because new threads are being created at an
+     * extremely fast rate.
+     */
+    private List<Thread> getThreadsInGroup(ThreadGroup group) {
+        final int activeThreadCount = group.activeCount(); // this is just an estimate
+        int threadArraySize = Math.max(activeThreadCount * 2, 100);
+        for (int loopCount = 0; loopCount < 5; loopCount++) {
+            Thread[] threads = new Thread[threadArraySize];
+            int enumCount = group.enumerate(threads);
+            if (enumCount < threadArraySize) {
+                return Arrays.asList(threads).subList(0, enumCount);
+            }
+            // if there are too many threads to fit into the array, enumerate's result
+            // is >= the array's length; therefore we can't trust that it returned all
+            // the threads.  Try again.
+            threadArraySize += 100;
         }
+        // threads are proliferating too fast for us.  Bail before we get into 
+        // trouble.
+        return Collections.emptyList();
+    }
 
-        @Override
-        public void run() {
+    /**
+     * Returns the CPU time used by a thread, if possible.
+     * @param thr The thread to query.
+     * @return The CPU time used by {@code thr}, or 0 if it cannot be determined.
+     */
+    private long cpuTime(Thread thr) {
+        ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
+        if (mxBean.isThreadCpuTimeSupported()) {
             try {
-                fStatement.evaluate();
-                fFinished = true;
-            } catch (InterruptedException e) {
-                // don't log the InterruptedException
-            } catch (InterruptedIOException e) {
-                // don't log the InterruptedIOException
-            } catch (ClosedByInterruptException e) {
-                // don't log the ClosedByInterruptException
-            } catch (Throwable e) {
-                fExceptionThrownByOriginalStatement = e;
+                return mxBean.getThreadCpuTime(thr.getId());
+            } catch (UnsupportedOperationException e) {
             }
         }
+        return 0;
     }
-}
\ No newline at end of file
+
+    private class CallableStatement implements Callable<Throwable> {
+        private final CountDownLatch startLatch = new CountDownLatch(1);
+
+        public Throwable call() throws Exception {
+            try {
+                startLatch.countDown();
+                originalStatement.evaluate();
+            } catch (Exception e) {
+                throw e;
+            } catch (Throwable e) {
+                return e;
+            }
+            return null;
+        }
+
+        public void awaitStarted() throws InterruptedException {
+            startLatch.await();
+        }
+    }
+}
diff --git a/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java b/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java
index 2896c64..68c0545 100644
--- a/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java
+++ b/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java
@@ -4,16 +4,16 @@
 import org.junit.runners.model.Statement;
 
 public class InvokeMethod extends Statement {
-    private final FrameworkMethod fTestMethod;
-    private Object fTarget;
+    private final FrameworkMethod testMethod;
+    private final Object target;
 
     public InvokeMethod(FrameworkMethod testMethod, Object target) {
-        fTestMethod = testMethod;
-        fTarget = target;
+        this.testMethod = testMethod;
+        this.target = target;
     }
 
     @Override
     public void evaluate() throws Throwable {
-        fTestMethod.invokeExplosively(fTarget);
+        testMethod.invokeExplosively(target);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/internal/runners/statements/RunAfters.java b/src/main/java/org/junit/internal/runners/statements/RunAfters.java
index f4c559a..7512a7d 100644
--- a/src/main/java/org/junit/internal/runners/statements/RunAfters.java
+++ b/src/main/java/org/junit/internal/runners/statements/RunAfters.java
@@ -8,29 +8,29 @@
 import org.junit.runners.model.Statement;
 
 public class RunAfters extends Statement {
-    private final Statement fNext;
+    private final Statement next;
 
-    private final Object fTarget;
+    private final Object target;
 
-    private final List<FrameworkMethod> fAfters;
+    private final List<FrameworkMethod> afters;
 
     public RunAfters(Statement next, List<FrameworkMethod> afters, Object target) {
-        fNext = next;
-        fAfters = afters;
-        fTarget = target;
+        this.next = next;
+        this.afters = afters;
+        this.target = target;
     }
 
     @Override
     public void evaluate() throws Throwable {
         List<Throwable> errors = new ArrayList<Throwable>();
         try {
-            fNext.evaluate();
+            next.evaluate();
         } catch (Throwable e) {
             errors.add(e);
         } finally {
-            for (FrameworkMethod each : fAfters) {
+            for (FrameworkMethod each : afters) {
                 try {
-                    each.invokeExplosively(fTarget);
+                    each.invokeExplosively(target);
                 } catch (Throwable e) {
                     errors.add(e);
                 }
diff --git a/src/main/java/org/junit/internal/runners/statements/RunBefores.java b/src/main/java/org/junit/internal/runners/statements/RunBefores.java
index 60fbb39..238fbe7 100644
--- a/src/main/java/org/junit/internal/runners/statements/RunBefores.java
+++ b/src/main/java/org/junit/internal/runners/statements/RunBefores.java
@@ -6,23 +6,23 @@
 import org.junit.runners.model.Statement;
 
 public class RunBefores extends Statement {
-    private final Statement fNext;
+    private final Statement next;
 
-    private final Object fTarget;
+    private final Object target;
 
-    private final List<FrameworkMethod> fBefores;
+    private final List<FrameworkMethod> befores;
 
     public RunBefores(Statement next, List<FrameworkMethod> befores, Object target) {
-        fNext = next;
-        fBefores = befores;
-        fTarget = target;
+        this.next = next;
+        this.befores = befores;
+        this.target = target;
     }
 
     @Override
     public void evaluate() throws Throwable {
-        for (FrameworkMethod before : fBefores) {
-            before.invokeExplosively(fTarget);
+        for (FrameworkMethod before : befores) {
+            before.invokeExplosively(target);
         }
-        fNext.evaluate();
+        next.evaluate();
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/rules/DisableOnDebug.java b/src/main/java/org/junit/rules/DisableOnDebug.java
new file mode 100644
index 0000000..afa6dee
--- /dev/null
+++ b/src/main/java/org/junit/rules/DisableOnDebug.java
@@ -0,0 +1,127 @@
+package org.junit.rules;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * The {@code DisableOnDebug} Rule allows you to label certain rules to be
+ * disabled when debugging.
+ * <p>
+ * The most illustrative use case is for tests that make use of the
+ * {@link Timeout} rule, when ran in debug mode the test may terminate on
+ * timeout abruptly during debugging. Developers may disable the timeout, or
+ * increase the timeout by making a code change on tests that need debugging and
+ * remember revert the change afterwards or rules such as {@link Timeout} that
+ * may be disabled during debugging may be wrapped in a {@code DisableOnDebug}.
+ * <p>
+ * The important benefit of this feature is that you can disable such rules
+ * without any making any modifications to your test class to remove them during
+ * debugging.
+ * <p>
+ * This does nothing to tackle timeouts or time sensitive code under test when
+ * debugging and may make this less useful in such circumstances.
+ * <p>
+ * Example usage:
+ * 
+ * <pre>
+ * public static class DisableTimeoutOnDebugSampleTest {
+ * 
+ *     &#064;Rule
+ *     public TestRule timeout = new DisableOnDebug(new Timeout(20));
+ * 
+ *     &#064;Test
+ *     public void myTest() {
+ *         int i = 0;
+ *         assertEquals(0, i); // suppose you had a break point here to inspect i
+ *     }
+ * }
+ * </pre>
+ * 
+ * @since 4.12
+ */
+public class DisableOnDebug implements TestRule {
+    private final TestRule rule;
+    private final boolean debugging;
+
+    /**
+     * Create a {@code DisableOnDebug} instance with the timeout specified in
+     * milliseconds.
+     * 
+     * @param rule to disable during debugging
+     */
+    public DisableOnDebug(TestRule rule) {
+        this(rule, ManagementFactory.getRuntimeMXBean()
+                .getInputArguments());
+    }
+
+    /**
+     * Visible for testing purposes only.
+     * 
+     * @param rule the rule to disable during debugging
+     * @param inputArguments
+     *            arguments provided to the Java runtime
+     */
+    DisableOnDebug(TestRule rule, List<String> inputArguments) {
+        this.rule = rule;
+        debugging = isDebugging(inputArguments);
+    }
+
+    /**
+     * @see TestRule#apply(Statement, Description)
+     */
+    public Statement apply(Statement base, Description description) {
+        if (debugging) {
+            return base;
+        } else {
+            return rule.apply(base, description);
+        }
+    }
+
+    /**
+     * Parses arguments passed to the runtime environment for debug flags
+     * <p>
+     * Options specified in:
+     * <ul>
+     * <li>
+     * <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/conninv.html#Invocation"
+     * >javase-6</a></li>
+     * <li><a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/conninv.html#Invocation"
+     * >javase-7</a></li>
+     * <li><a href="http://docs.oracle.com/javase/8/docs/technotes/guides/jpda/conninv.html#Invocation"
+     * >javase-8</a></li>
+     * 
+     * 
+     * @param arguments
+     *            the arguments passed to the runtime environment, usually this
+     *            will be {@link RuntimeMXBean#getInputArguments()}
+     * @return true if the current JVM was started in debug mode, false
+     *         otherwise.
+     */
+    private static boolean isDebugging(List<String> arguments) {
+        for (final String argument : arguments) {
+            if ("-Xdebug".equals(argument)) {
+                return true;
+            } else if (argument.startsWith("-agentlib:jdwp")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the JVM is in debug mode. This method may be used
+     * by test classes to take additional action to disable code paths that
+     * interfere with debugging if required.
+     * 
+     * @return {@code true} if the current JVM is in debug mode, {@code false}
+     *         otherwise
+     */
+    public boolean isDebugging() {
+        return debugging;
+    }
+
+}
diff --git a/src/main/java/org/junit/rules/ErrorCollector.java b/src/main/java/org/junit/rules/ErrorCollector.java
index 57be4d7..8c6600e 100644
--- a/src/main/java/org/junit/rules/ErrorCollector.java
+++ b/src/main/java/org/junit/rules/ErrorCollector.java
@@ -73,7 +73,7 @@
      * Execution continues, but the test will fail at the end if
      * {@code callable} threw an exception.
      */
-    public Object checkSucceeds(Callable<Object> callable) {
+    public <T> T checkSucceeds(Callable<T> callable) {
         try {
             return callable.call();
         } catch (Throwable e) {
@@ -81,4 +81,4 @@
             return null;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/rules/ExpectedException.java b/src/main/java/org/junit/rules/ExpectedException.java
index e559bc5..4d61712 100644
--- a/src/main/java/org/junit/rules/ExpectedException.java
+++ b/src/main/java/org/junit/rules/ExpectedException.java
@@ -1,5 +1,6 @@
 package org.junit.rules;
 
+import static java.lang.String.format;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.junit.Assert.assertThat;
@@ -9,114 +10,144 @@
 
 import org.hamcrest.Matcher;
 import org.hamcrest.StringDescription;
-import org.junit.internal.AssumptionViolatedException;
+import org.junit.AssumptionViolatedException;
 import org.junit.runners.model.Statement;
 
 /**
- * The ExpectedException rule allows in-test specification of expected exception
- * types and messages:
+ * The {@code ExpectedException} rule allows you to verify that your code
+ * throws a specific exception.
  *
- * <pre>
- * // These tests all pass.
- * public static class HasExpectedException {
- * 	&#064;Rule
- * 	public ExpectedException thrown= ExpectedException.none();
+ * <h3>Usage</h3>
  *
- * 	&#064;Test
- * 	public void throwsNothing() {
- * 		// no exception expected, none thrown: passes.
+ * <pre> public class SimpleExpectedExceptionTest {
+ *     &#064;Rule
+ *     public ExpectedException thrown= ExpectedException.none();
+ *
+ *     &#064;Test
+ *     public void throwsNothing() {
+ *         // no exception expected, none thrown: passes.
  *     }
  *
- * 	&#064;Test
- * 	public void throwsNullPointerException() {
- * 		thrown.expect(NullPointerException.class);
- * 		throw new NullPointerException();
+ *     &#064;Test
+ *     public void throwsExceptionWithSpecificType() {
+ *         thrown.expect(NullPointerException.class);
+ *         throw new NullPointerException();
  *     }
+ * }</pre>
+ * 
+ * <p>
+ * You have to add the {@code ExpectedException} rule to your test.
+ * This doesn't affect your existing tests (see {@code throwsNothing()}).
+ * After specifiying the type of the expected exception your test is
+ * successful when such an exception is thrown and it fails if a
+ * different or no exception is thrown.
  *
- * 	&#064;Test
- * 	public void throwsNullPointerExceptionWithMessage() {
- * 		thrown.expect(NullPointerException.class);
- * 		thrown.expectMessage(&quot;happened?&quot;);
- * 		thrown.expectMessage(startsWith(&quot;What&quot;));
- * 		throw new NullPointerException(&quot;What happened?&quot;);
- *     }
+ * <p>
+ * Instead of specifying the exception's type you can characterize the
+ * expected exception based on other criterias, too:
  *
- * 	&#064;Test
- * 	public void throwsIllegalArgumentExceptionWithMessageAndCause() {
- * 		NullPointerException expectedCause = new NullPointerException();
- * 		thrown.expect(IllegalArgumentException.class);
- * 		thrown.expectMessage(&quot;What&quot;);
- * 		thrown.expectCause(is(expectedCause));
- * 		throw new IllegalArgumentException(&quot;What happened?&quot;, cause);
- *     }
- * }
- * </pre>
+ * <ul>
+ *   <li>The exception's message contains a specific text: {@link #expectMessage(String)}</li>
+ *   <li>The exception's message complies with a Hamcrest matcher: {@link #expectMessage(Matcher)}</li>
+ *   <li>The exception's cause complies with a Hamcrest matcher: {@link #expectCause(Matcher)}</li>
+ *   <li>The exception itself complies with a Hamcrest matcher: {@link #expect(Matcher)}</li>
+ * </ul>
  *
- * By default ExpectedException rule doesn't handle AssertionErrors and
- * AssumptionViolatedExceptions, because such exceptions are used by JUnit. If
- * you want to handle such exceptions you have to call @link
- * {@link #handleAssertionErrors()} or @link
- * {@link #handleAssumptionViolatedExceptions()}.
+ * <p>
+ * You can combine any of the presented expect-methods. The test is
+ * successful if all specifications are met.
+ * <pre> &#064;Test
+ * public void throwsException() {
+ *     thrown.expect(NullPointerException.class);
+ *     thrown.expectMessage(&quot;happened&quot;);
+ *     throw new NullPointerException(&quot;What happened?&quot;);
+ * }</pre>
  *
- * <pre>
- * // These tests all pass.
- * public static class HasExpectedException {
- * 	&#064;Rule
- * 	public ExpectedException thrown= ExpectedException.none();
+ * <h3>AssumptionViolatedExceptions</h3>
+ * <p>
+ * JUnit uses {@link AssumptionViolatedException}s for indicating that a test
+ * provides no useful information. (See {@link org.junit.Assume} for more
+ * information.) You have to call {@code assume} methods before you set
+ * expectations of the {@code ExpectedException} rule. In this case the rule
+ * will not handle consume the exceptions and it can be handled by the
+ * framework. E.g. the following test is ignored by JUnit's default runner.
  *
- * 	&#064;Test
- * 	public void throwExpectedAssertionError() {
- * 		thrown.handleAssertionErrors();
- * 		thrown.expect(AssertionError.class);
- * 		throw new AssertionError();
- *     }
+ * <pre> &#064;Test
+ * public void ignoredBecauseOfFailedAssumption() {
+ *     assumeTrue(false); // throws AssumptionViolatedException
+ *     thrown.expect(NullPointerException.class);
+ * }</pre>
  *
- *  &#064;Test
- *  public void throwExpectAssumptionViolatedException() {
- *      thrown.handleAssumptionViolatedExceptions();
- *      thrown.expect(AssumptionViolatedException.class);
- *      throw new AssumptionViolatedException(&quot;&quot;);
- *     }
- * }
- * </pre>
+ * <h3>AssertionErrors</h3>
+ *
+ * <p>
+ * JUnit uses {@link AssertionError}s for indicating that a test is failing. You
+ * have to call {@code assert} methods before you set expectations of the
+ * {@code ExpectedException} rule, if they should be handled by the framework.
+ * E.g. the following test fails because of the {@code assertTrue} statement.
+ *
+ * <pre> &#064;Test
+ * public void throwsUnhandled() {
+ *     assertTrue(false); // throws AssertionError
+ *     thrown.expect(NullPointerException.class);
+ * }</pre>
+ *
+ * <h3>Missing Exceptions</h3>
+ * <p>
+ * By default missing exceptions are reported with an error message
+ * like "Expected test to throw an instance of foo". You can configure a different
+ * message by means of {@link #reportMissingExceptionWithMessage(String)}. You
+ * can use a {@code %s} placeholder for the description of the expected
+ * exception. E.g. "Test doesn't throw %s." will fail with the error message
+ * "Test doesn't throw an instance of foo.".
  *
  * @since 4.7
  */
 public class ExpectedException implements TestRule {
     /**
-     * @return a Rule that expects no exception to be thrown (identical to
-     *         behavior without this Rule)
+     * Returns a {@linkplain TestRule rule} that expects no exception to
+     * be thrown (identical to behavior without this rule).
      */
     public static ExpectedException none() {
         return new ExpectedException();
     }
 
-    private final ExpectedExceptionMatcherBuilder fMatcherBuilder = new ExpectedExceptionMatcherBuilder();
+    private final ExpectedExceptionMatcherBuilder matcherBuilder = new ExpectedExceptionMatcherBuilder();
 
-    private boolean handleAssumptionViolatedExceptions = false;
-
-    private boolean handleAssertionErrors = false;
-    
-    private String missingExceptionMessage;
+    private String missingExceptionMessage= "Expected test to throw %s";
 
     private ExpectedException() {
     }
 
+    /**
+     * This method does nothing. Don't use it.
+     * @deprecated AssertionErrors are handled by default since JUnit 4.12. Just
+     *             like in JUnit &lt;= 4.10.
+     */
+    @Deprecated
     public ExpectedException handleAssertionErrors() {
-        handleAssertionErrors = true;
         return this;
     }
 
+    /**
+     * This method does nothing. Don't use it.
+     * @deprecated AssumptionViolatedExceptions are handled by default since
+     *             JUnit 4.12. Just like in JUnit &lt;= 4.10.
+     */
+    @Deprecated
     public ExpectedException handleAssumptionViolatedExceptions() {
-        handleAssumptionViolatedExceptions = true;
         return this;
     }
-    
+
     /**
      * Specifies the failure message for tests that are expected to throw 
-     * an exception but do not throw any.
+     * an exception but do not throw any. You can use a {@code %s} placeholder for
+     * the description of the expected exception. E.g. "Test doesn't throw %s."
+     * will fail with the error message
+     * "Test doesn't throw an instance of foo.".
+     *
      * @param message exception detail message
-     * @return self
+     * @return the rule itself
      */
     public ExpectedException reportMissingExceptionWithMessage(String message) {
         missingExceptionMessage = message;
@@ -129,87 +160,103 @@
     }
 
     /**
-     * Adds {@code matcher} to the list of requirements for any thrown
-     * exception.
+     * Verify that your code throws an exception that is matched by
+     * a Hamcrest matcher.
+     * <pre> &#064;Test
+     * public void throwsExceptionThatCompliesWithMatcher() {
+     *     NullPointerException e = new NullPointerException();
+     *     thrown.expect(is(e));
+     *     throw e;
+     * }</pre>
      */
     public void expect(Matcher<?> matcher) {
-        fMatcherBuilder.add(matcher);
+        matcherBuilder.add(matcher);
     }
 
     /**
-     * Adds to the list of requirements for any thrown exception that it should
-     * be an instance of {@code type}
+     * Verify that your code throws an exception that is an
+     * instance of specific {@code type}.
+     * <pre> &#064;Test
+     * public void throwsExceptionWithSpecificType() {
+     *     thrown.expect(NullPointerException.class);
+     *     throw new NullPointerException();
+     * }</pre>
      */
     public void expect(Class<? extends Throwable> type) {
         expect(instanceOf(type));
     }
 
     /**
-     * Adds to the list of requirements for any thrown exception that it should
-     * <em>contain</em> string {@code substring}
+     * Verify that your code throws an exception whose message contains
+     * a specific text.
+     * <pre> &#064;Test
+     * public void throwsExceptionWhoseMessageContainsSpecificText() {
+     *     thrown.expectMessage(&quot;happened&quot;);
+     *     throw new NullPointerException(&quot;What happened?&quot;);
+     * }</pre>
      */
     public void expectMessage(String substring) {
         expectMessage(containsString(substring));
     }
 
     /**
-     * Adds {@code matcher} to the list of requirements for the message returned
-     * from any thrown exception.
+     * Verify that your code throws an exception whose message is matched 
+     * by a Hamcrest matcher.
+     * <pre> &#064;Test
+     * public void throwsExceptionWhoseMessageCompliesWithMatcher() {
+     *     thrown.expectMessage(startsWith(&quot;What&quot;));
+     *     throw new NullPointerException(&quot;What happened?&quot;);
+     * }</pre>
      */
     public void expectMessage(Matcher<String> matcher) {
         expect(hasMessage(matcher));
     }
 
     /**
-     * Adds {@code matcher} to the list of requirements for the cause of
-     * any thrown exception.
+     * Verify that your code throws an exception whose cause is matched by 
+     * a Hamcrest matcher.
+     * <pre> &#064;Test
+     * public void throwsExceptionWhoseCauseCompliesWithMatcher() {
+     *     NullPointerException expectedCause = new NullPointerException();
+     *     thrown.expectCause(is(expectedCause));
+     *     throw new IllegalArgumentException(&quot;What happened?&quot;, cause);
+     * }</pre>
      */
     public void expectCause(Matcher<? extends Throwable> expectedCause) {
         expect(hasCause(expectedCause));
     }
 
     private class ExpectedExceptionStatement extends Statement {
-        private final Statement fNext;
+        private final Statement next;
 
         public ExpectedExceptionStatement(Statement base) {
-            fNext = base;
+            next = base;
         }
 
         @Override
         public void evaluate() throws Throwable {
             try {
-                fNext.evaluate();
-            } catch (AssumptionViolatedException e) {
-                optionallyHandleException(e, handleAssumptionViolatedExceptions);
-                return;
-            } catch (AssertionError e) {
-                optionallyHandleException(e, handleAssertionErrors);
-                return;
+                next.evaluate();
             } catch (Throwable e) {
                 handleException(e);
                 return;
             }
-            if (fMatcherBuilder.expectsThrowable()) {
+            if (isAnyExceptionExpected()) {
                 failDueToMissingException();
             }
         }
     }
 
-    private void optionallyHandleException(Throwable e, boolean handleException)
-            throws Throwable {
-        if (handleException) {
-            handleException(e);
+    private void handleException(Throwable e) throws Throwable {
+        if (isAnyExceptionExpected()) {
+            assertThat(e, matcherBuilder.build());
         } else {
             throw e;
         }
     }
 
-    private void handleException(Throwable e) throws Throwable {
-        if (fMatcherBuilder.expectsThrowable()) {
-            assertThat(e, fMatcherBuilder.build());
-        } else {
-            throw e;
-        }
+    private boolean isAnyExceptionExpected() {
+        return matcherBuilder.expectsThrowable();
     }
 
     private void failDueToMissingException() throws AssertionError {
@@ -217,15 +264,7 @@
     }
     
     private String missingExceptionMessage() {
-        if (isMissingExceptionMessageEmpty()) {
-            String expectation = StringDescription.toString(fMatcherBuilder.build());
-            return "Expected test to throw " + expectation;
-        } else {
-            return missingExceptionMessage;
-        }        
-    }
-    
-    private boolean isMissingExceptionMessageEmpty() {
-        return missingExceptionMessage == null || missingExceptionMessage.length() == 0;
+        String expectation= StringDescription.toString(matcherBuilder.build());
+        return format(missingExceptionMessage, expectation);
     }
 }
diff --git a/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java b/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java
index f083a4d..e7d94c4 100644
--- a/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java
+++ b/src/main/java/org/junit/rules/ExpectedExceptionMatcherBuilder.java
@@ -13,14 +13,14 @@
  */
 class ExpectedExceptionMatcherBuilder {
 
-    private final List<Matcher<?>> fMatchers = new ArrayList<Matcher<?>>();
+    private final List<Matcher<?>> matchers = new ArrayList<Matcher<?>>();
 
     void add(Matcher<?> matcher) {
-        fMatchers.add(matcher);
+        matchers.add(matcher);
     }
 
     boolean expectsThrowable() {
-        return !fMatchers.isEmpty();
+        return !matchers.isEmpty();
     }
 
     Matcher<Throwable> build() {
@@ -28,15 +28,15 @@
     }
 
     private Matcher<Throwable> allOfTheMatchers() {
-        if (fMatchers.size() == 1) {
-            return cast(fMatchers.get(0));
+        if (matchers.size() == 1) {
+            return cast(matchers.get(0));
         }
         return allOf(castedMatchers());
     }
 
     @SuppressWarnings({"unchecked", "rawtypes"})
     private List<Matcher<? super Throwable>> castedMatchers() {
-        return new ArrayList<Matcher<? super Throwable>>((List) fMatchers);
+        return new ArrayList<Matcher<? super Throwable>>((List) matchers);
     }
 
     @SuppressWarnings("unchecked")
diff --git a/src/main/java/org/junit/rules/ExternalResource.java b/src/main/java/org/junit/rules/ExternalResource.java
index 6ac4310..71ca287 100644
--- a/src/main/java/org/junit/rules/ExternalResource.java
+++ b/src/main/java/org/junit/rules/ExternalResource.java
@@ -56,7 +56,7 @@
     /**
      * Override to set up your specific external resource.
      *
-     * @throws if setup fails (which will disable {@code after}
+     * @throws Throwable if setup fails (which will disable {@code after}
      */
     protected void before() throws Throwable {
         // do nothing
diff --git a/src/main/java/org/junit/rules/MethodRule.java b/src/main/java/org/junit/rules/MethodRule.java
index f6a8dd4..94608f5 100644
--- a/src/main/java/org/junit/rules/MethodRule.java
+++ b/src/main/java/org/junit/rules/MethodRule.java
@@ -10,21 +10,9 @@
  * {@link Statement} that executes the method is passed to each annotated
  * {@link Rule} in turn, and each may return a substitute or modified
  * {@link Statement}, which is passed to the next {@link Rule}, if any. For
- * examples of how this can be useful, see these provided MethodRules,
- * or write your own:
+ * an example of how this can be useful, see {@link TestWatchman}.
  *
- * <ul>
- *   <li>{@link ErrorCollector}: collect multiple errors in one test method</li>
- *   <li>{@link ExpectedException}: make flexible assertions about thrown exceptions</li>
- *   <li>{@link ExternalResource}: start and stop a server, for example</li>
- *   <li>{@link TemporaryFolder}: create fresh files, and delete after test</li>
- *   <li>{@link TestName}: remember the test name for use during the method</li>
- *   <li>{@link TestWatchman}: add logic at events during method execution</li>
- *   <li>{@link Timeout}: cause test to fail after a set time</li>
- *   <li>{@link Verifier}: fail test if object state ends up incorrect</li>
- * </ul>
- *
- * Note that {@link MethodRule} has been replaced by {@link TestRule},
+ * <p>Note that {@link MethodRule} has been replaced by {@link TestRule},
  * which has the added benefit of supporting class rules.
  *
  * @since 4.7
@@ -36,9 +24,9 @@
      *
      * @param base The {@link Statement} to be modified
      * @param method The method to be run
-     * @param target The object on with the method will be run.
+     * @param target The object on which the method will be run.
      * @return a new statement, which may be the same as {@code base},
      *         a wrapper around {@code base}, or a completely new Statement.
      */
     Statement apply(Statement base, FrameworkMethod method, Object target);
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/rules/Stopwatch.java b/src/main/java/org/junit/rules/Stopwatch.java
index 2434071..6900a48 100644
--- a/src/main/java/org/junit/rules/Stopwatch.java
+++ b/src/main/java/org/junit/rules/Stopwatch.java
@@ -1,44 +1,47 @@
 package org.junit.rules;
 
-import org.junit.internal.AssumptionViolatedException;
+import org.junit.AssumptionViolatedException;
 import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
 
 import java.util.concurrent.TimeUnit;
 
 /**
- * The Stopwatch Rule notifies one of its own protected methods of the time spent by a test.<p/>
- * Override them to get the time in nanoseconds. For example, this class will keep logging the
+ * The Stopwatch Rule notifies one of its own protected methods of the time spent by a test.
+ *
+ * <p>Override them to get the time in nanoseconds. For example, this class will keep logging the
  * time spent by each passed, failed, skipped, and finished test:
  *
  * <pre>
  * public static class StopwatchTest {
- *     private static final Logger logger= Logger.getLogger(&quot;&quot;);
+ *     private static final Logger logger = Logger.getLogger(&quot;&quot;);
  *
- *     private static void logInfo(String testName, String status, long nanos) {
+ *     private static void logInfo(Description description, String status, long nanos) {
+ *         String testName = description.getMethodName();
  *         logger.info(String.format(&quot;Test %s %s, spent %d microseconds&quot;,
- *                                     testName, status, Stopwatch.toMicros(nanos)));
+ *                                   testName, status, TimeUnit.NANOSECONDS.toMicros(nanos)));
  *     }
  *
  *     &#064;Rule
- *     public Stopwatch stopwatch= new Stopwatch() {
+ *     public Stopwatch stopwatch = new Stopwatch() {
  *         &#064;Override
  *         protected void succeeded(long nanos, Description description) {
- *             logInfo(description.getMethodName(), &quot;succeeded&quot;, nanos);
+ *             logInfo(description, &quot;succeeded&quot;, nanos);
  *         }
  *
  *         &#064;Override
  *         protected void failed(long nanos, Throwable e, Description description) {
- *             logInfo(description.getMethodName(), &quot;failed&quot;, nanos);
+ *             logInfo(description, &quot;failed&quot;, nanos);
  *         }
  *
  *         &#064;Override
  *         protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
- *             logInfo(description.getMethodName(), &quot;skipped&quot;, nanos);
+ *             logInfo(description, &quot;skipped&quot;, nanos);
  *         }
  *
  *         &#064;Override
  *         protected void finished(long nanos, Description description) {
- *             logInfo(description.getMethodName(), &quot;finished&quot;, nanos);
+ *             logInfo(description, &quot;finished&quot;, nanos);
  *         }
  *     };
  *
@@ -62,7 +65,7 @@
  * <pre>
  * &#064;Test
  * public void performanceTest() throws InterruptedException {
- *     long delta= 30;
+ *     long delta = 30;
  *     Thread.sleep(300L);
  *     assertEquals(300d, stopwatch.runtime(MILLISECONDS), delta);
  *     Thread.sleep(500L);
@@ -73,16 +76,27 @@
  * @author tibor17
  * @since 4.12
  */
-public class Stopwatch extends TestWatcher {
-    private long fStartNanos;
-    private long fEndNanos;
+public class Stopwatch implements TestRule {
+    private final Clock clock;
+    private volatile long startNanos;
+    private volatile long endNanos;
+
+    public Stopwatch() {
+        this(new Clock());
+    }
+
+    Stopwatch(Clock clock) {
+        this.clock = clock;
+    }
 
     /**
+     * Gets the runtime for the test.
+     *
      * @param unit time unit for returned runtime
      * @return runtime measured during the test
      */
     public long runtime(TimeUnit unit) {
-        return unit.convert(currentNanoTime() - fStartNanos, TimeUnit.NANOSECONDS);
+        return unit.convert(getNanos(), TimeUnit.NANOSECONDS);
     }
 
     /**
@@ -109,66 +123,61 @@
     protected void finished(long nanos, Description description) {
     }
 
-    /**
-     * @param nanos time in nanoseconds
-     * @return time converted to microseconds
-     */
-    public static long toMicros(long nanos) {
-        return TimeUnit.NANOSECONDS.toMicros(nanos);
-    }
-
-    /**
-     * @param nanos time in nanoseconds
-     * @return time converted to milliseconds
-     */
-    public static long toMillis(long nanos) {
-        return TimeUnit.NANOSECONDS.toMillis(nanos);
-    }
-
-    /**
-     * @param nanos time in nanoseconds
-     * @return time converted to seconds
-     */
-    public static long toSeconds(long nanos) {
-        return TimeUnit.NANOSECONDS.toSeconds(nanos);
-    }
-
     private long getNanos() {
-        return fEndNanos - fStartNanos;
+        if (startNanos == 0) {
+            throw new IllegalStateException("Test has not started");
+        }
+        long currentEndNanos = endNanos; // volatile read happens here
+        if (currentEndNanos == 0) {
+          currentEndNanos = clock.nanoTime();
+        }
+
+        return currentEndNanos - startNanos;
     }
 
     private void starting() {
-        fStartNanos= currentNanoTime();
+        startNanos = clock.nanoTime();
+        endNanos = 0;
     }
 
     private void stopping() {
-        fEndNanos= currentNanoTime();
+        endNanos = clock.nanoTime();
     }
 
-    private long currentNanoTime() {
-        return System.nanoTime();
+    public final Statement apply(Statement base, Description description) {
+        return new InternalWatcher().apply(base, description);
     }
 
-    @Override final protected void succeeded(Description description) {
-        stopping();
-        succeeded(getNanos(), description);
+    private class InternalWatcher extends TestWatcher {
+
+        @Override protected void starting(Description description) {
+            Stopwatch.this.starting();
+        }
+
+        @Override protected void finished(Description description) {
+            Stopwatch.this.finished(getNanos(), description);
+        }
+
+        @Override protected void succeeded(Description description) {
+            Stopwatch.this.stopping();
+            Stopwatch.this.succeeded(getNanos(), description);
+        }
+
+        @Override protected void failed(Throwable e, Description description) {
+            Stopwatch.this.stopping();
+            Stopwatch.this.failed(getNanos(), e, description);
+        }
+
+        @Override protected void skipped(AssumptionViolatedException e, Description description) {
+            Stopwatch.this.stopping();
+            Stopwatch.this.skipped(getNanos(), e, description);
+        }
     }
 
-    @Override final protected void failed(Throwable e, Description description) {
-        stopping();
-        failed(getNanos(), e, description);
-    }
+    static class Clock {
 
-    @Override final protected void skipped(AssumptionViolatedException e, Description description) {
-        stopping();
-        skipped(getNanos(), e, description);
-    }
-
-    @Override final protected void starting(Description description) {
-        starting();
-    }
-
-    @Override final protected void finished(Description description) {
-        finished(getNanos(), description);
+        public long nanoTime() {
+            return System.nanoTime();
+        }
     }
 }
diff --git a/src/main/java/org/junit/rules/TemporaryFolder.java b/src/main/java/org/junit/rules/TemporaryFolder.java
index 2bf9b03..fd0f30f 100644
--- a/src/main/java/org/junit/rules/TemporaryFolder.java
+++ b/src/main/java/org/junit/rules/TemporaryFolder.java
@@ -1,15 +1,19 @@
 package org.junit.rules;
 
+import static org.junit.Assert.fail;
+
 import java.io.File;
 import java.io.IOException;
 
 import org.junit.Rule;
 
 /**
- * The TemporaryFolder Rule allows creation of files and folders that are
- * guaranteed to be deleted when the test method finishes (whether it passes or
- * fails):
+ * The TemporaryFolder Rule allows creation of files and folders that should
+ * be deleted when the test method finishes (whether it passes or
+ * fails).
+ * By default no exception will be thrown in case the deletion fails.
  *
+ * <p>Example of usage:
  * <pre>
  * public static class HasTempFolder {
  *  &#064;Rule
@@ -24,18 +28,101 @@
  * }
  * </pre>
  *
+ * <p>TemporaryFolder rule supports assured deletion mode, which
+ * will fail the test in case deletion fails with {@link AssertionError}.
+ *
+ * <p>Creating TemporaryFolder with assured deletion:
+ * <pre>
+ *  &#064;Rule
+ *  public TemporaryFolder folder= TemporaryFolder.builder().assureDeletion().build();
+ * </pre>
+ *
  * @since 4.7
  */
 public class TemporaryFolder extends ExternalResource {
     private final File parentFolder;
+    private final boolean assureDeletion;
     private File folder;
 
+    /**
+     * Create a temporary folder which uses system default temporary-file 
+     * directory to create temporary resources.
+     */
     public TemporaryFolder() {
-        this(null);
+        this((File) null);
     }
 
+    /**
+     * Create a temporary folder which uses the specified directory to create
+     * temporary resources.
+     *
+     * @param parentFolder folder where temporary resources will be created.
+     * If {@code null} then system default temporary-file directory is used.
+     */
     public TemporaryFolder(File parentFolder) {
         this.parentFolder = parentFolder;
+        this.assureDeletion = false;
+    }
+
+    /**
+     * Create a {@link TemporaryFolder} initialized with
+     * values from a builder.
+     */
+    protected TemporaryFolder(Builder builder) {
+        this.parentFolder = builder.parentFolder;
+        this.assureDeletion = builder.assureDeletion;
+    }
+
+    /**
+     * Returns a new builder for building an instance of {@link TemporaryFolder}.
+     *
+     * @since 4.13
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builds an instance of {@link TemporaryFolder}.
+     * 
+     * @since 4.13
+     */
+    public static class Builder {
+        private File parentFolder;
+        private boolean assureDeletion;
+
+        protected Builder() {}
+
+        /**
+         * Specifies which folder to use for creating temporary resources.
+         * If {@code null} then system default temporary-file directory is
+         * used.
+         *
+         * @return this
+         */
+        public Builder parentFolder(File parentFolder) {
+            this.parentFolder = parentFolder;
+            return this;
+        }
+
+        /**
+         * Setting this flag assures that no resources are left undeleted. Failure
+         * to fulfill the assurance results in failure of tests with an
+         * {@link IllegalStateException}.
+         *
+         * @return this
+         */
+        public Builder assureDeletion() {
+            this.assureDeletion = true;
+            return this;
+        }
+
+        /**
+         * Builds a {@link TemporaryFolder} instance using the values in this builder.
+         */
+        public TemporaryFolder build() {
+            return new TemporaryFolder(this);
+        }
     }
 
     @Override
@@ -92,6 +179,7 @@
         File file = getRoot();
         for (int i = 0; i < folderNames.length; i++) {
             String folderName = folderNames[i];
+            validateFolderName(folderName);
             file = new File(file, folderName);
             if (!file.mkdir() && isLastElementInArray(i, folderNames)) {
                 throw new IOException(
@@ -100,6 +188,21 @@
         }
         return file;
     }
+    
+    /**
+     * Validates if multiple path components were used while creating a folder.
+     * 
+     * @param folderName
+     *            Name of the folder being created
+     */
+    private void validateFolderName(String folderName) throws IOException {
+        File tempFile = new File(folderName);
+        if (tempFile.getParent() != null) {
+            String errorMsg = "Folder name cannot consist of multiple path components separated by a file separator."
+                    + " Please use newFolder('MyParentFolder','MyFolder') to create hierarchies of folders";
+            throw new IOException(errorMsg);
+        }
+    }
 
     private boolean isLastElementInArray(int index, String[] array) {
         return index == array.length - 1;
@@ -132,21 +235,42 @@
 
     /**
      * Delete all files and folders under the temporary folder. Usually not
-     * called directly, since it is automatically applied by the {@link Rule}
+     * called directly, since it is automatically applied by the {@link Rule}.
+     *
+     * @throws IllegalStateException if unable to clean up resources
+     * and deletion of resources is assured.
      */
     public void delete() {
-        if (folder != null) {
-            recursiveDelete(folder);
+        if (!tryDelete()) {
+            if (assureDeletion) {
+                fail("Unable to clean up temporary folder " + folder);
+            }
         }
     }
 
-    private void recursiveDelete(File file) {
+    /**
+     * Tries to delete all files and folders under the temporary folder and
+     * returns whether deletion was successful or not.
+     *
+     * @return {@code true} if all resources are deleted successfully,
+     *         {@code false} otherwise.
+     */
+    protected boolean tryDelete() {
+        if (folder == null) {
+            return true;
+        }
+        
+        return recursiveDelete(folder);
+    }
+    
+    private boolean recursiveDelete(File file) {
+        boolean result = true;
         File[] files = file.listFiles();
         if (files != null) {
             for (File each : files) {
-                recursiveDelete(each);
+                result = result && recursiveDelete(each);
             }
         }
-        file.delete();
+        return result && file.delete();
     }
 }
diff --git a/src/main/java/org/junit/rules/TestName.java b/src/main/java/org/junit/rules/TestName.java
index 00d7c29..e2ebc2e 100644
--- a/src/main/java/org/junit/rules/TestName.java
+++ b/src/main/java/org/junit/rules/TestName.java
@@ -25,17 +25,17 @@
  * @since 4.7
  */
 public class TestName extends TestWatcher {
-    private String fName;
+    private volatile String name;
 
     @Override
     protected void starting(Description d) {
-        fName = d.getMethodName();
+        name = d.getMethodName();
     }
 
     /**
      * @return the name of the currently-running test method
      */
     public String getMethodName() {
-        return fName;
+        return name;
     }
 }
diff --git a/src/main/java/org/junit/rules/TestWatcher.java b/src/main/java/org/junit/rules/TestWatcher.java
index 46f7280..b790dd3 100644
--- a/src/main/java/org/junit/rules/TestWatcher.java
+++ b/src/main/java/org/junit/rules/TestWatcher.java
@@ -3,7 +3,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.junit.internal.AssumptionViolatedException;
+import org.junit.AssumptionViolatedException;
 import org.junit.runner.Description;
 import org.junit.runners.model.MultipleFailureException;
 import org.junit.runners.model.Statement;
@@ -54,12 +54,12 @@
                 try {
                     base.evaluate();
                     succeededQuietly(description, errors);
-                } catch (AssumptionViolatedException e) {
+                } catch (org.junit.internal.AssumptionViolatedException  e) {
                     errors.add(e);
                     skippedQuietly(e, description, errors);
-                } catch (Throwable t) {
-                    errors.add(t);
-                    failedQuietly(t, description, errors);
+                } catch (Throwable e) {
+                    errors.add(e);
+                    failedQuietly(e, description, errors);
                 } finally {
                     finishedQuietly(description, errors);
                 }
@@ -73,26 +73,31 @@
             List<Throwable> errors) {
         try {
             succeeded(description);
-        } catch (Throwable t) {
-            errors.add(t);
+        } catch (Throwable e) {
+            errors.add(e);
         }
     }
 
-    private void failedQuietly(Throwable t, Description description,
+    private void failedQuietly(Throwable e, Description description,
             List<Throwable> errors) {
         try {
-            failed(t, description);
-        } catch (Throwable t1) {
-            errors.add(t1);
+            failed(e, description);
+        } catch (Throwable e1) {
+            errors.add(e1);
         }
     }
 
-    private void skippedQuietly(AssumptionViolatedException e, Description description,
+    private void skippedQuietly(
+            org.junit.internal.AssumptionViolatedException e, Description description,
             List<Throwable> errors) {
         try {
-            skipped(e, description);
-        } catch (Throwable t) {
-            errors.add(t);
+            if (e instanceof AssumptionViolatedException) {
+                skipped((AssumptionViolatedException) e, description);
+            } else {
+                skipped(e, description);
+            }
+        } catch (Throwable e1) {
+            errors.add(e1);
         }
     }
 
@@ -100,8 +105,8 @@
             List<Throwable> errors) {
         try {
             starting(description);
-        } catch (Throwable t) {
-            errors.add(t);
+        } catch (Throwable e) {
+            errors.add(e);
         }
     }
 
@@ -109,8 +114,8 @@
             List<Throwable> errors) {
         try {
             finished(description);
-        } catch (Throwable t) {
-            errors.add(t);
+        } catch (Throwable e) {
+            errors.add(e);
         }
     }
 
@@ -130,6 +135,19 @@
      * Invoked when a test is skipped due to a failed assumption.
      */
     protected void skipped(AssumptionViolatedException e, Description description) {
+        // For backwards compatibility with JUnit 4.11 and earlier, call the legacy version
+        org.junit.internal.AssumptionViolatedException asInternalException = e;
+        skipped(asInternalException, description);
+    }
+
+    /**
+     * Invoked when a test is skipped due to a failed assumption.
+     *
+     * @deprecated use {@link #skipped(AssumptionViolatedException, Description)}
+     */
+    @Deprecated
+    protected void skipped(
+            org.junit.internal.AssumptionViolatedException e, Description description) {
     }
 
     /**
diff --git a/src/main/java/org/junit/rules/TestWatchman.java b/src/main/java/org/junit/rules/TestWatchman.java
index 57b8394..c8d6c71 100644
--- a/src/main/java/org/junit/rules/TestWatchman.java
+++ b/src/main/java/org/junit/rules/TestWatchman.java
@@ -54,9 +54,9 @@
                     succeeded(method);
                 } catch (AssumptionViolatedException e) {
                     throw e;
-                } catch (Throwable t) {
-                    failed(t, method);
-                    throw t;
+                } catch (Throwable e) {
+                    failed(e, method);
+                    throw e;
                 } finally {
                     finished(method);
                 }
diff --git a/src/main/java/org/junit/rules/Timeout.java b/src/main/java/org/junit/rules/Timeout.java
index 40af54e..334a923 100644
--- a/src/main/java/org/junit/rules/Timeout.java
+++ b/src/main/java/org/junit/rules/Timeout.java
@@ -8,7 +8,6 @@
 
 /**
  * The Timeout Rule applies the same timeout to all test methods in a class:
- *
  * <pre>
  * public static class HasGlobalLongTimeout {
  *
@@ -26,23 +25,39 @@
  *  }
  * }
  * </pre>
- *
+ * <p>
  * Each test is run in a new thread. If the specified timeout elapses before
  * the test completes, its execution is interrupted via {@link Thread#interrupt()}.
  * This happens in interruptable I/O and locks, and methods in {@link Object}
  * and {@link Thread} throwing {@link InterruptedException}.
+ * <p>
+ * A specified timeout of 0 will be interpreted as not set, however tests will
+ * still launch from separate threads. This can be useful for disabling timeouts
+ * in environments where they are dynamically set based on some property.
  *
  * @since 4.7
  */
 public class Timeout implements TestRule {
-    private final long fTimeout;
-    private final TimeUnit fTimeUnit;
+    private final long timeout;
+    private final TimeUnit timeUnit;
+    private final boolean lookForStuckThread;
+
+    /**
+     * Returns a new builder for building an instance.
+     *
+     * @since 4.12
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
 
     /**
      * Create a {@code Timeout} instance with the timeout specified
      * in milliseconds.
-     * <p> This constructor is deprecated.
-     * <p> Instead use {@link #Timeout(long, java.util.concurrent.TimeUnit)},
+     * <p>
+     * This constructor is deprecated.
+     * <p>
+     * Instead use {@link #Timeout(long, java.util.concurrent.TimeUnit)},
      * {@link Timeout#millis(long)}, or {@link Timeout#seconds(long)}.
      *
      * @param millis the maximum time in milliseconds to allow the
@@ -55,20 +70,35 @@
 
     /**
      * Create a {@code Timeout} instance with the timeout specified
-     * at the unit of granularity of the provided {@code TimeUnit}.
+     * at the timeUnit of granularity of the provided {@code TimeUnit}.
      *
      * @param timeout the maximum time to allow the test to run
      * before it should timeout
-     * @param unit the time unit for the {@code timeout}
+     * @param timeUnit the time unit for the {@code timeout}
      * @since 4.12
      */
-    public Timeout(long timeout, TimeUnit unit) {
-        fTimeout = timeout;
-        fTimeUnit = unit;
+    public Timeout(long timeout, TimeUnit timeUnit) {
+        this.timeout = timeout;
+        this.timeUnit = timeUnit;
+        lookForStuckThread = false;
     }
 
     /**
-     * @param millis the timeout in milliseconds
+     * Create a {@code Timeout} instance initialized with values from
+     * a builder.
+     *
+     * @since 4.12
+     */
+    protected Timeout(Builder builder) {
+        timeout = builder.getTimeout();
+        timeUnit = builder.getTimeUnit();
+        lookForStuckThread = builder.getLookingForStuckThread();
+    }
+
+    /**
+     * Creates a {@link Timeout} that will timeout a test after the
+     * given duration, in milliseconds.
+     *
      * @since 4.12
      */
     public static Timeout millis(long millis) {
@@ -76,15 +106,128 @@
     }
 
     /**
-     * @param seconds the timeout in seconds
+     * Creates a {@link Timeout} that will timeout a test after the
+     * given duration, in seconds.
+     *
      * @since 4.12
      */
     public static Timeout seconds(long seconds) {
         return new Timeout(seconds, TimeUnit.SECONDS);
     }
 
+    /**
+     * Gets the timeout configured for this rule, in the given units.
+     *
+     * @since 4.12
+     */
+    protected final long getTimeout(TimeUnit unit) {
+        return unit.convert(timeout, timeUnit);
+    }
+
+    /**
+     * Gets whether this {@code Timeout} will look for a stuck thread
+     * when the test times out.
+     *
+     * @since 4.12
+     */
+    protected final boolean getLookingForStuckThread() {
+        return lookForStuckThread;
+    }
+
+    /**
+     * Creates a {@link Statement} that will run the given
+     * {@code statement}, and timeout the operation based
+     * on the values configured in this rule. Subclasses
+     * can override this method for different behavior.
+     *
+     * @since 4.12
+     */
+    protected Statement createFailOnTimeoutStatement(
+            Statement statement) throws Exception {
+        return FailOnTimeout.builder()
+            .withTimeout(timeout, timeUnit)
+            .withLookingForStuckThread(lookForStuckThread)
+            .build(statement);
+    }
 
     public Statement apply(Statement base, Description description) {
-        return new FailOnTimeout(base, fTimeout, fTimeUnit);
+        try {
+            return createFailOnTimeoutStatement(base);
+        } catch (final Exception e) {
+            return new Statement() {
+                @Override public void evaluate() throws Throwable {
+                    throw new RuntimeException("Invalid parameters for Timeout", e);
+                }
+            };
+        }
+    }
+
+    /**
+     * Builder for {@link Timeout}.
+     *
+     * @since 4.12
+     */
+    public static class Builder {
+        private boolean lookForStuckThread = false;
+        private long timeout = 0;
+        private TimeUnit timeUnit = TimeUnit.SECONDS;
+
+        protected Builder() {
+        }
+
+        /**
+         * Specifies the time to wait before timing out the test.
+         *
+         * <p>If this is not called, or is called with a
+         * {@code timeout} of {@code 0}, the returned {@code Timeout}
+         * rule instance will cause the tests to wait forever to
+         * complete, however the tests will still launch from a
+         * separate thread. This can be useful for disabling timeouts
+         * in environments where they are dynamically set based on
+         * some property.
+         *
+         * @param timeout the maximum time to wait
+         * @param unit the time unit of the {@code timeout} argument
+         * @return {@code this} for method chaining.
+         */
+        public Builder withTimeout(long timeout, TimeUnit unit) {
+            this.timeout = timeout;
+            this.timeUnit = unit;
+            return this;
+        }
+
+        protected long getTimeout() {
+            return timeout;
+        }
+
+        protected TimeUnit getTimeUnit()  {
+            return timeUnit;
+        }
+
+        /**
+         * Specifies whether to look for a stuck thread.  If a timeout occurs and this
+         * feature is enabled, the rule will look for a thread that appears to be stuck
+         * and dump its backtrace.  This feature is experimental.  Behavior may change
+         * after the 4.12 release in response to feedback.
+         *
+         * @param enable {@code true} to enable the feature
+         * @return {@code this} for method chaining.
+         */
+        public Builder withLookingForStuckThread(boolean enable) {
+            this.lookForStuckThread = enable;
+            return this;
+        }
+
+        protected boolean getLookingForStuckThread() {
+            return lookForStuckThread;
+        }
+
+
+        /**
+         * Builds a {@link Timeout} instance using the values in this builder.,
+         */
+        public Timeout build() {
+            return new Timeout(this);
+        }
     }
 }
diff --git a/src/main/java/org/junit/runner/Describable.java b/src/main/java/org/junit/runner/Describable.java
index 1514141..293fdb3 100644
--- a/src/main/java/org/junit/runner/Describable.java
+++ b/src/main/java/org/junit/runner/Describable.java
@@ -10,5 +10,5 @@
     /**
      * @return a {@link Description} showing the tests to be run by the receiver
      */
-    public abstract Description getDescription();
+    Description getDescription();
 }
\ No newline at end of file
diff --git a/src/main/java/org/junit/runner/Description.java b/src/main/java/org/junit/runner/Description.java
index bc888bd..fe47eac 100644
--- a/src/main/java/org/junit/runner/Description.java
+++ b/src/main/java/org/junit/runner/Description.java
@@ -5,22 +5,23 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
- * <p>A <code>Description</code> describes a test which is to be run or has been run. <code>Descriptions</code>
+ * A <code>Description</code> describes a test which is to be run or has been run. <code>Descriptions</code>
  * can be atomic (a single test) or compound (containing children tests). <code>Descriptions</code> are used
  * to provide feedback about the tests that are about to run (for example, the tree view
- * visible in many IDEs) or tests that have been run (for example, the failures view).</p>
- *
- * <p><code>Descriptions</code> are implemented as a single class rather than a Composite because
- * they are entirely informational. They contain no logic aside from counting their tests.</p>
- *
- * <p>In the past, we used the raw {@link junit.framework.TestCase}s and {@link junit.framework.TestSuite}s
+ * visible in many IDEs) or tests that have been run (for example, the failures view).
+ * <p>
+ * <code>Descriptions</code> are implemented as a single class rather than a Composite because
+ * they are entirely informational. They contain no logic aside from counting their tests.
+ * <p>
+ * In the past, we used the raw {@link junit.framework.TestCase}s and {@link junit.framework.TestSuite}s
  * to display the tree of tests. This was no longer viable in JUnit 4 because atomic tests no longer have
  * a superclass below {@link Object}. We needed a way to pass a class and name together. Description
- * emerged from this.</p>
+ * emerged from this.
  *
  * @see org.junit.runner.Request
  * @see org.junit.runner.Runner
@@ -30,7 +31,7 @@
     private static final long serialVersionUID = 1L;
 
     private static final Pattern METHOD_AND_CLASS_NAME_PATTERN = Pattern
-            .compile("(.*)\\((.*)\\)");
+            .compile("([\\s\\S]*)\\((.*)\\)");
 
     /**
      * Create a <code>Description</code> named <code>name</code>.
@@ -135,17 +136,22 @@
      */
     public static final Description TEST_MECHANISM = new Description(null, "Test mechanism");
 
-    private final ArrayList<Description> fChildren = new ArrayList<Description>();
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
+    private final Collection<Description> fChildren = new ConcurrentLinkedQueue<Description>();
     private final String fDisplayName;
     private final Serializable fUniqueId;
     private final Annotation[] fAnnotations;
-    private /* write-once */ Class<?> fTestClass;
+    private volatile /* write-once */ Class<?> fTestClass;
 
     private Description(Class<?> clazz, String displayName, Annotation... annotations) {
         this(clazz, displayName, displayName, annotations);
     }
 
-    private Description(Class<?> clazz, String displayName, Serializable uniqueId, Annotation... annotations) {
+    private Description(Class<?> testClass, String displayName, Serializable uniqueId, Annotation... annotations) {
         if ((displayName == null) || (displayName.length() == 0)) {
             throw new IllegalArgumentException(
                     "The display name must not be empty.");
@@ -154,10 +160,10 @@
             throw new IllegalArgumentException(
                     "The unique id must not be null.");
         }
-        fTestClass = clazz;
-        fDisplayName = displayName;
-        fUniqueId = uniqueId;
-        fAnnotations = annotations;
+        this.fTestClass = testClass;
+        this.fDisplayName = displayName;
+        this.fUniqueId = uniqueId;
+        this.fAnnotations = annotations;
     }
 
     /**
@@ -173,14 +179,15 @@
      * @param description the soon-to-be child.
      */
     public void addChild(Description description) {
-        getChildren().add(description);
+        fChildren.add(description);
     }
 
     /**
-     * @return the receiver's children, if any
+     * Gets the copy of the children of this {@code Description}.
+     * Returns an empty list if there are no children.
      */
     public ArrayList<Description> getChildren() {
-        return fChildren;
+        return new ArrayList<Description>(fChildren);
     }
 
     /**
@@ -194,7 +201,7 @@
      * @return <code>true</code> if the receiver is an atomic test
      */
     public boolean isTest() {
-        return getChildren().isEmpty();
+        return fChildren.isEmpty();
     }
 
     /**
@@ -205,7 +212,7 @@
             return 1;
         }
         int result = 0;
-        for (Description child : getChildren()) {
+        for (Description child : fChildren) {
             result += child.testCount();
         }
         return result;
diff --git a/src/main/java/org/junit/runner/FilterFactories.java b/src/main/java/org/junit/runner/FilterFactories.java
new file mode 100644
index 0000000..020d394
--- /dev/null
+++ b/src/main/java/org/junit/runner/FilterFactories.java
@@ -0,0 +1,82 @@
+package org.junit.runner;

+

+import org.junit.internal.Classes;

+import org.junit.runner.FilterFactory.FilterNotCreatedException;

+import org.junit.runner.manipulation.Filter;

+

+/**

+ * Utility class whose methods create a {@link FilterFactory}.

+ */

+class FilterFactories {

+    /**

+     * Creates a {@link Filter}.

+     *

+     * A filter specification is of the form "package.of.FilterFactory=args-to-filter-factory" or

+     * "package.of.FilterFactory".

+     *

+     * @param request the request that will be filtered

+     * @param filterSpec the filter specification

+     * @throws org.junit.runner.FilterFactory.FilterNotCreatedException

+     */

+    public static Filter createFilterFromFilterSpec(Request request, String filterSpec)

+            throws FilterFactory.FilterNotCreatedException {

+        Description topLevelDescription = request.getRunner().getDescription();

+        String[] tuple;

+

+        if (filterSpec.contains("=")) {

+            tuple = filterSpec.split("=", 2);

+        } else {

+            tuple = new String[]{ filterSpec, "" };

+        }

+

+        return createFilter(tuple[0], new FilterFactoryParams(topLevelDescription, tuple[1]));

+    }

+

+    /**

+     * Creates a {@link Filter}.

+     *

+     * @param filterFactoryFqcn The fully qualified class name of the {@link FilterFactory}

+     * @param params The arguments to the {@link FilterFactory}

+     */

+    public static Filter createFilter(String filterFactoryFqcn, FilterFactoryParams params)

+            throws FilterFactory.FilterNotCreatedException {

+        FilterFactory filterFactory = createFilterFactory(filterFactoryFqcn);

+

+        return filterFactory.createFilter(params);

+    }

+

+    /**

+     * Creates a {@link Filter}.

+     *

+     * @param filterFactoryClass The class of the {@link FilterFactory}

+     * @param params             The arguments to the {@link FilterFactory}

+     *

+     */

+    public static Filter createFilter(Class<? extends FilterFactory> filterFactoryClass, FilterFactoryParams params)

+            throws FilterFactory.FilterNotCreatedException {

+        FilterFactory filterFactory = createFilterFactory(filterFactoryClass);

+

+        return filterFactory.createFilter(params);

+    }

+

+    static FilterFactory createFilterFactory(String filterFactoryFqcn) throws FilterNotCreatedException {

+        Class<? extends FilterFactory> filterFactoryClass;

+

+        try {

+            filterFactoryClass = Classes.getClass(filterFactoryFqcn).asSubclass(FilterFactory.class);

+        } catch (Exception e) {

+            throw new FilterNotCreatedException(e);

+        }

+

+        return createFilterFactory(filterFactoryClass);

+    }

+

+    static FilterFactory createFilterFactory(Class<? extends FilterFactory> filterFactoryClass)

+            throws FilterNotCreatedException {

+        try {

+            return filterFactoryClass.getConstructor().newInstance();

+        } catch (Exception e) {

+            throw new FilterNotCreatedException(e);

+        }

+    }

+}

diff --git a/src/main/java/org/junit/runner/FilterFactory.java b/src/main/java/org/junit/runner/FilterFactory.java
new file mode 100644
index 0000000..e2bfb73
--- /dev/null
+++ b/src/main/java/org/junit/runner/FilterFactory.java
@@ -0,0 +1,25 @@
+package org.junit.runner;

+

+import org.junit.runner.manipulation.Filter;

+

+/**

+ * Extend this class to create a factory that creates {@link Filter}.

+ */

+public interface FilterFactory {

+    /**

+     * Creates a {@link Filter} given a {@link FilterFactoryParams} argument.

+     *

+     * @param params Parameters needed to create the {@link Filter}

+     */

+    Filter createFilter(FilterFactoryParams params) throws FilterNotCreatedException;

+

+    /**

+     * Exception thrown if the {@link Filter} cannot be created.

+     */

+    @SuppressWarnings("serial")

+    class FilterNotCreatedException extends Exception {

+        public FilterNotCreatedException(Exception exception) {

+            super(exception.getMessage(), exception);

+        }

+    }

+}

diff --git a/src/main/java/org/junit/runner/FilterFactoryParams.java b/src/main/java/org/junit/runner/FilterFactoryParams.java
new file mode 100644
index 0000000..1e74ab9
--- /dev/null
+++ b/src/main/java/org/junit/runner/FilterFactoryParams.java
@@ -0,0 +1,23 @@
+package org.junit.runner;

+

+public final class FilterFactoryParams {

+    private final Description topLevelDescription;

+    private final String args;

+

+    public FilterFactoryParams(Description topLevelDescription, String args) {

+        if (args == null || topLevelDescription == null) {

+            throw new NullPointerException();

+        }

+

+        this.topLevelDescription = topLevelDescription;

+        this.args = args;

+    }

+

+    public String getArgs() {

+        return args;

+    }

+

+    public Description getTopLevelDescription() {

+        return topLevelDescription;

+    }

+}

diff --git a/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java b/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java
new file mode 100644
index 0000000..434157c
--- /dev/null
+++ b/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java
@@ -0,0 +1,149 @@
+package org.junit.runner;

+

+import java.util.ArrayList;

+import java.util.Collections;

+import java.util.List;

+

+import org.junit.internal.Classes;

+import org.junit.runner.FilterFactory.FilterNotCreatedException;

+import org.junit.runner.manipulation.Filter;

+import org.junit.runners.model.InitializationError;

+

+class JUnitCommandLineParseResult {

+    private final List<String> filterSpecs = new ArrayList<String>();

+    private final List<Class<?>> classes = new ArrayList<Class<?>>();

+    private final List<Throwable> parserErrors = new ArrayList<Throwable>();

+

+    /**

+     * Do not use. Testing purposes only.

+     */

+    JUnitCommandLineParseResult() {}

+

+    /**

+     * Returns filter specs parsed from command line.

+     */

+    public List<String> getFilterSpecs() {

+        return Collections.unmodifiableList(filterSpecs);

+    }

+

+    /**

+     * Returns test classes parsed from command line.

+     */

+    public List<Class<?>> getClasses() {

+        return Collections.unmodifiableList(classes);

+    }

+

+    /**

+     * Parses the arguments.

+     *

+     * @param args Arguments

+     */

+    public static JUnitCommandLineParseResult parse(String[] args) {

+        JUnitCommandLineParseResult result = new JUnitCommandLineParseResult();

+

+        result.parseArgs(args);

+

+        return result;

+    }

+

+    private void parseArgs(String[] args) {

+        parseParameters(parseOptions(args));

+    }

+

+    String[] parseOptions(String... args) {

+        for (int i = 0; i != args.length; ++i) {

+            String arg = args[i];

+

+            if (arg.equals("--")) {

+                return copyArray(args, i + 1, args.length);

+            } else if (arg.startsWith("--")) {

+                if (arg.startsWith("--filter=") || arg.equals("--filter")) {

+                    String filterSpec;

+                    if (arg.equals("--filter")) {

+                        ++i;

+

+                        if (i < args.length) {

+                            filterSpec = args[i];

+                        } else {

+                            parserErrors.add(new CommandLineParserError(arg + " value not specified"));

+                            break;

+                        }

+                    } else {

+                        filterSpec = arg.substring(arg.indexOf('=') + 1);

+                    }

+

+                    filterSpecs.add(filterSpec);

+                } else {

+                    parserErrors.add(new CommandLineParserError("JUnit knows nothing about the " + arg + " option"));

+                }

+            } else {

+                return copyArray(args, i, args.length);

+            }

+        }

+

+        return new String[]{};

+    }

+

+    private String[] copyArray(String[] args, int from, int to) {

+        ArrayList<String> result = new ArrayList<String>();

+

+        for (int j = from; j != to; ++j) {

+            result.add(args[j]);

+        }

+

+        return result.toArray(new String[result.size()]);

+    }

+

+    void parseParameters(String[] args) {

+        for (String arg : args) {

+            try {

+                classes.add(Classes.getClass(arg));

+            } catch (ClassNotFoundException e) {

+                parserErrors.add(new IllegalArgumentException("Could not find class [" + arg + "]", e));

+            }

+        }

+    }

+

+    private Request errorReport(Throwable cause) {

+        return Request.errorReport(JUnitCommandLineParseResult.class, cause);

+    }

+

+    /**

+     * Creates a {@link Request}.

+     *

+     * @param computer {@link Computer} to be used.

+     */

+    public Request createRequest(Computer computer) {

+        if (parserErrors.isEmpty()) {

+            Request request = Request.classes(

+                    computer, classes.toArray(new Class<?>[classes.size()]));

+            return applyFilterSpecs(request);

+        } else {

+            return errorReport(new InitializationError(parserErrors));

+        }

+    }

+

+    private Request applyFilterSpecs(Request request) {

+        try {

+            for (String filterSpec : filterSpecs) {

+                Filter filter = FilterFactories.createFilterFromFilterSpec(

+                        request, filterSpec);

+                request = request.filterWith(filter);

+            }

+            return request;

+        } catch (FilterNotCreatedException e) {

+            return errorReport(e);

+        }

+    }

+

+    /**

+     * Exception used if there's a problem parsing the command line.

+     */

+    public static class CommandLineParserError extends Exception {

+        private static final long serialVersionUID= 1L;

+

+        public CommandLineParserError(String message) {

+            super(message);

+        }

+    }

+}

diff --git a/src/main/java/org/junit/runner/JUnitCore.java b/src/main/java/org/junit/runner/JUnitCore.java
index 90bf037..c1479e0 100644
--- a/src/main/java/org/junit/runner/JUnitCore.java
+++ b/src/main/java/org/junit/runner/JUnitCore.java
@@ -1,14 +1,10 @@
 package org.junit.runner;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import junit.runner.Version;
 import org.junit.internal.JUnitSystem;
 import org.junit.internal.RealSystem;
 import org.junit.internal.TextListener;
 import org.junit.internal.runners.JUnit38ClassRunner;
-import org.junit.runner.notification.Failure;
 import org.junit.runner.notification.RunListener;
 import org.junit.runner.notification.RunNotifier;
 
@@ -26,7 +22,7 @@
  * @since 4.0
  */
 public class JUnitCore {
-    private final RunNotifier fNotifier = new RunNotifier();
+    private final RunNotifier notifier = new RunNotifier();
 
     /**
      * Run the tests contained in the classes named in the <code>args</code>.
@@ -37,14 +33,7 @@
      * @param args names of classes in which to find tests to run
      */
     public static void main(String... args) {
-        runMainAndExit(new RealSystem(), args);
-    }
-
-    /**
-     * Runs main and exits
-     */
-    private static void runMainAndExit(JUnitSystem system, String... args) {
-        Result result = new JUnitCore().runMain(system, args);
+        Result result = new JUnitCore().runMain(new RealSystem(), args);
         System.exit(result.wasSuccessful() ? 0 : 1);
     }
 
@@ -53,51 +42,39 @@
      * are running and write stack traces for all failed tests after all tests complete. This is
      * similar to {@link #main(String[])}, but intended to be used programmatically.
      *
-     * @param computer Helps construct Runners from classes
-     * @param classes Classes in which to find tests
-     * @return a {@link Result} describing the details of the test run and the failed tests.
-     */
-    public static Result runClasses(Computer computer, Class<?>... classes) {
-        return new JUnitCore().run(computer, classes);
-    }
-
-    /**
-     * Run the tests contained in <code>classes</code>. Write feedback while the tests
-     * are running and write stack traces for all failed tests after all tests complete. This is
-     * similar to {@link #main(String[])}, but intended to be used programmatically.
-     *
      * @param classes Classes in which to find tests
      * @return a {@link Result} describing the details of the test run and the failed tests.
      */
     public static Result runClasses(Class<?>... classes) {
-        return new JUnitCore().run(defaultComputer(), classes);
+        return runClasses(defaultComputer(), classes);
+    }
+
+    /**
+     * Run the tests contained in <code>classes</code>. Write feedback while the tests
+     * are running and write stack traces for all failed tests after all tests complete. This is
+     * similar to {@link #main(String[])}, but intended to be used programmatically.
+     *
+     * @param computer Helps construct Runners from classes
+     * @param classes  Classes in which to find tests
+     * @return a {@link Result} describing the details of the test run and the failed tests.
+     */
+    public static Result runClasses(Computer computer, Class<?>... classes) {
+        return new JUnitCore().run(computer, classes);
     }
 
     /**
      * @param system
-     * @args args from main()
+     * @param args from main()
      */
-    private Result runMain(JUnitSystem system, String... args) {
+    Result runMain(JUnitSystem system, String... args) {
         system.out().println("JUnit version " + Version.id());
-        List<Class<?>> classes = new ArrayList<Class<?>>();
-        List<Failure> missingClasses = new ArrayList<Failure>();
-        for (String each : args) {
-            try {
-                classes.add(Class.forName(each));
-            } catch (ClassNotFoundException e) {
-                system.out().println("Could not find class: " + each);
-                Description description = Description.createSuiteDescription(each);
-                Failure failure = new Failure(description, e);
-                missingClasses.add(failure);
-            }
-        }
+
+        JUnitCommandLineParseResult jUnitCommandLineParseResult = JUnitCommandLineParseResult.parse(args);
+
         RunListener listener = new TextListener(system);
         addListener(listener);
-        Result result = run(classes.toArray(new Class<?>[0]));
-        for (Failure each : missingClasses) {
-            result.getFailures().add(each);
-        }
-        return result;
+
+        return run(jUnitCommandLineParseResult.createRequest(defaultComputer()));
     }
 
     /**
@@ -114,7 +91,7 @@
      * @return a {@link Result} describing the details of the test run and the failed tests.
      */
     public Result run(Class<?>... classes) {
-        return run(Request.classes(defaultComputer(), classes));
+        return run(defaultComputer(), classes);
     }
 
     /**
@@ -154,11 +131,11 @@
     public Result run(Runner runner) {
         Result result = new Result();
         RunListener listener = result.createListener();
-        fNotifier.addFirstListener(listener);
+        notifier.addFirstListener(listener);
         try {
-            fNotifier.fireTestRunStarted(runner.getDescription());
-            runner.run(fNotifier);
-            fNotifier.fireTestRunFinished(result);
+            notifier.fireTestRunStarted(runner.getDescription());
+            runner.run(notifier);
+            notifier.fireTestRunFinished(result);
         } finally {
             removeListener(listener);
         }
@@ -172,7 +149,7 @@
      * @see org.junit.runner.notification.RunListener
      */
     public void addListener(RunListener listener) {
-        fNotifier.addListener(listener);
+        notifier.addListener(listener);
     }
 
     /**
@@ -181,11 +158,10 @@
      * @param listener the listener to remove
      */
     public void removeListener(RunListener listener) {
-        fNotifier.removeListener(listener);
+        notifier.removeListener(listener);
     }
 
     static Computer defaultComputer() {
         return new Computer();
     }
-
 }
diff --git a/src/main/java/org/junit/runner/Request.java b/src/main/java/org/junit/runner/Request.java
index 1d31519..fcb29e7 100644
--- a/src/main/java/org/junit/runner/Request.java
+++ b/src/main/java/org/junit/runner/Request.java
@@ -11,16 +11,16 @@
 import org.junit.runners.model.InitializationError;
 
 /**
- * <p>A <code>Request</code> is an abstract description of tests to be run. Older versions of
+ * A <code>Request</code> is an abstract description of tests to be run. Older versions of
  * JUnit did not need such a concept--tests to be run were described either by classes containing
  * tests or a tree of {@link  org.junit.Test}s. However, we want to support filtering and sorting,
  * so we need a more abstract specification than the tests themselves and a richer
- * specification than just the classes.</p>
+ * specification than just the classes.
  *
- * <p>The flow when JUnit runs tests is that a <code>Request</code> specifies some tests to be run ->
- * a {@link org.junit.runner.Runner} is created for each class implied by the <code>Request</code> ->
+ * <p>The flow when JUnit runs tests is that a <code>Request</code> specifies some tests to be run -&gt;
+ * a {@link org.junit.runner.Runner} is created for each class implied by the <code>Request</code> -&gt;
  * the {@link org.junit.runner.Runner} returns a detailed {@link org.junit.runner.Description}
- * which is a tree structure of the tests to be run.</p>
+ * which is a tree structure of the tests to be run.
  *
  * @since 4.0
  */
@@ -75,8 +75,7 @@
             Runner suite = computer.getSuite(builder, classes);
             return runner(suite);
         } catch (InitializationError e) {
-            throw new RuntimeException(
-                    "Bug in saff's brain: Suite constructor, called as above, should always complete");
+            return runner(new ErrorReportingRunner(e, classes));
         }
     }
 
@@ -93,9 +92,9 @@
 
 
     /**
-     * Not used within JUnit.  Clients should simply instantiate ErrorReportingRunner themselves
+     * Creates a {@link Request} that, when processed, will report an error for the given
+     * test class with the given cause.
      */
-    @Deprecated
     public static Request errorReport(Class<?> klass, Throwable cause) {
         return runner(new ErrorReportingRunner(klass, cause));
     }
@@ -145,12 +144,11 @@
     /**
      * Returns a Request whose Tests can be run in a certain order, defined by
      * <code>comparator</code>
-     *
+     * <p>
      * For example, here is code to run a test suite in alphabetical order:
-     *
      * <pre>
-     * private static Comparator<Description> forward() {
-     * return new Comparator<Description>() {
+     * private static Comparator&lt;Description&gt; forward() {
+     * return new Comparator&lt;Description&gt;() {
      * public int compare(Description o1, Description o2) {
      * return o1.getDisplayName().compareTo(o2.getDisplayName());
      * }
diff --git a/src/main/java/org/junit/runner/Result.java b/src/main/java/org/junit/runner/Result.java
index 34ffac76..73ad059 100644
--- a/src/main/java/org/junit/runner/Result.java
+++ b/src/main/java/org/junit/runner/Result.java
@@ -1,14 +1,21 @@
 package org.junit.runner;
 
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunListener;
-
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.ObjectStreamField;
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
 /**
  * A <code>Result</code> collects and summarizes information from running multiple tests.
  * All tests are counted -- additional information is collected from tests that fail.
@@ -16,46 +23,67 @@
  * @since 4.0
  */
 public class Result implements Serializable {
-    private static final long serialVersionUID = 2L;
-    private final AtomicInteger fCount = new AtomicInteger();
-    private final AtomicInteger fIgnoreCount = new AtomicInteger();
-    private final CopyOnWriteArrayList<Failure> fFailures = new CopyOnWriteArrayList<Failure>();
-    private final AtomicLong fRunTime = new AtomicLong();
-    private final AtomicLong fStartTime = new AtomicLong();
+    private static final long serialVersionUID = 1L;
+    private static final ObjectStreamField[] serialPersistentFields =
+            ObjectStreamClass.lookup(SerializedForm.class).getFields();
+    private final AtomicInteger count;
+    private final AtomicInteger ignoreCount;
+    private final CopyOnWriteArrayList<Failure> failures;
+    private final AtomicLong runTime;
+    private final AtomicLong startTime;
+
+    /** Only set during deserialization process. */
+    private SerializedForm serializedForm;
+
+    public Result() {
+        count = new AtomicInteger();
+        ignoreCount = new AtomicInteger();
+        failures = new CopyOnWriteArrayList<Failure>();
+        runTime = new AtomicLong();
+        startTime = new AtomicLong();
+    }
+
+    private Result(SerializedForm serializedForm) {
+        count = serializedForm.fCount;
+        ignoreCount = serializedForm.fIgnoreCount;
+        failures = new CopyOnWriteArrayList<Failure>(serializedForm.fFailures);
+        runTime = new AtomicLong(serializedForm.fRunTime);
+        startTime = new AtomicLong(serializedForm.fStartTime);
+    }
 
     /**
      * @return the number of tests run
      */
     public int getRunCount() {
-        return fCount.get();
+        return count.get();
     }
 
     /**
      * @return the number of tests that failed during the run
      */
     public int getFailureCount() {
-        return fFailures.size();
+        return failures.size();
     }
 
     /**
      * @return the number of milliseconds it took to run the entire suite to run
      */
     public long getRunTime() {
-        return fRunTime.get();
+        return runTime.get();
     }
 
     /**
      * @return the {@link Failure}s describing tests that failed and the problems they encountered
      */
     public List<Failure> getFailures() {
-        return fFailures;
+        return failures;
     }
 
     /**
      * @return the number of tests ignored during the run
      */
     public int getIgnoreCount() {
-        return fIgnoreCount.get();
+        return ignoreCount.get();
     }
 
     /**
@@ -65,31 +93,46 @@
         return getFailureCount() == 0;
     }
 
+    private void writeObject(ObjectOutputStream s) throws IOException {
+        SerializedForm serializedForm = new SerializedForm(this);
+        serializedForm.serialize(s);
+    }
+
+    private void readObject(ObjectInputStream s)
+            throws ClassNotFoundException, IOException {
+        serializedForm = SerializedForm.deserialize(s);
+    }
+
+    private Object readResolve()  {
+        return new Result(serializedForm);
+    }
+
+    @RunListener.ThreadSafe
     private class Listener extends RunListener {
         @Override
         public void testRunStarted(Description description) throws Exception {
-            fStartTime.set(System.currentTimeMillis());
+            startTime.set(System.currentTimeMillis());
         }
 
         @Override
         public void testRunFinished(Result result) throws Exception {
             long endTime = System.currentTimeMillis();
-            fRunTime.addAndGet(endTime - fStartTime.get());
+            runTime.addAndGet(endTime - startTime.get());
         }
 
         @Override
         public void testFinished(Description description) throws Exception {
-            fCount.getAndIncrement();
+            count.getAndIncrement();
         }
 
         @Override
         public void testFailure(Failure failure) throws Exception {
-            fFailures.add(failure);
+            failures.add(failure);
         }
 
         @Override
         public void testIgnored(Description description) throws Exception {
-            fIgnoreCount.getAndIncrement();
+            ignoreCount.getAndIncrement();
         }
 
         @Override
@@ -104,4 +147,50 @@
     public RunListener createListener() {
         return new Listener();
     }
+
+    /**
+     * Represents the serialized output of {@code Result}. The fields on this
+     * class match the files that {@code Result} had in JUnit 4.11.
+     */
+    private static class SerializedForm implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private final AtomicInteger fCount;
+        private final AtomicInteger fIgnoreCount;
+        private final List<Failure> fFailures;
+        private final long fRunTime;
+        private final long fStartTime;
+
+        public SerializedForm(Result result) {
+            fCount = result.count;
+            fIgnoreCount = result.ignoreCount;
+            fFailures = Collections.synchronizedList(new ArrayList<Failure>(result.failures));
+            fRunTime = result.runTime.longValue();
+            fStartTime = result.startTime.longValue();
+        }
+
+        @SuppressWarnings("unchecked")
+        private SerializedForm(ObjectInputStream.GetField fields) throws IOException {
+            fCount = (AtomicInteger) fields.get("fCount", null);
+            fIgnoreCount = (AtomicInteger) fields.get("fIgnoreCount", null);
+            fFailures = (List<Failure>) fields.get("fFailures", null);
+            fRunTime = fields.get("fRunTime", 0L);
+            fStartTime = fields.get("fStartTime", 0L);
+        }
+
+        public void serialize(ObjectOutputStream s) throws IOException {
+            ObjectOutputStream.PutField fields = s.putFields();
+            fields.put("fCount", fCount);
+            fields.put("fIgnoreCount", fIgnoreCount);
+            fields.put("fFailures", fFailures);
+            fields.put("fRunTime", fRunTime);
+            fields.put("fStartTime", fStartTime);
+            s.writeFields();
+        }
+
+        public static SerializedForm deserialize(ObjectInputStream s)
+                throws ClassNotFoundException, IOException {
+            ObjectInputStream.GetField fields = s.readFields();
+            return new SerializedForm(fields);
+        }
+    }
 }
diff --git a/src/main/java/org/junit/runner/Runner.java b/src/main/java/org/junit/runner/Runner.java
index e4bd981..d728dd8 100644
--- a/src/main/java/org/junit/runner/Runner.java
+++ b/src/main/java/org/junit/runner/Runner.java
@@ -9,8 +9,8 @@
  * a custom runner, in addition to implementing the abstract methods here you must
  * also provide a constructor that takes as an argument the {@link Class} containing
  * the tests.
- * <p/>
- * The default runner implementation guarantees that the instances of the test case
+ *
+ * <p>The default runner implementation guarantees that the instances of the test case
  * class will be constructed immediately before running the test and that the runner
  * will retain no reference to the test case instances, generally making them
  * available for garbage collection.
@@ -40,4 +40,4 @@
     public int testCount() {
         return getDescription().testCount();
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/runner/manipulation/Filter.java b/src/main/java/org/junit/runner/manipulation/Filter.java
index 14be6b3..0287351 100644
--- a/src/main/java/org/junit/runner/manipulation/Filter.java
+++ b/src/main/java/org/junit/runner/manipulation/Filter.java
@@ -18,7 +18,7 @@
     /**
      * A null <code>Filter</code> that passes all tests through.
      */
-    public static Filter ALL = new Filter() {
+    public static final Filter ALL = new Filter() {
         @Override
         public boolean shouldRun(Description description) {
             return true;
diff --git a/src/main/java/org/junit/runner/manipulation/Sortable.java b/src/main/java/org/junit/runner/manipulation/Sortable.java
index 9ac864c..0c59f33 100644
--- a/src/main/java/org/junit/runner/manipulation/Sortable.java
+++ b/src/main/java/org/junit/runner/manipulation/Sortable.java
@@ -15,6 +15,6 @@
      *
      * @param sorter the {@link Sorter} to use for sorting the tests
      */
-    public void sort(Sorter sorter);
+    void sort(Sorter sorter);
 
 }
diff --git a/src/main/java/org/junit/runner/manipulation/Sorter.java b/src/main/java/org/junit/runner/manipulation/Sorter.java
index 0bf5534..20192d0 100644
--- a/src/main/java/org/junit/runner/manipulation/Sorter.java
+++ b/src/main/java/org/junit/runner/manipulation/Sorter.java
@@ -20,7 +20,7 @@
         }
     });
 
-    private final Comparator<Description> fComparator;
+    private final Comparator<Description> comparator;
 
     /**
      * Creates a <code>Sorter</code> that uses <code>comparator</code>
@@ -29,7 +29,7 @@
      * @param comparator the {@link Comparator} to use when sorting tests
      */
     public Sorter(Comparator<Description> comparator) {
-        fComparator = comparator;
+        this.comparator = comparator;
     }
 
     /**
@@ -43,6 +43,6 @@
     }
 
     public int compare(Description o1, Description o2) {
-        return fComparator.compare(o1, o2);
+        return comparator.compare(o1, o2);
     }
 }
diff --git a/src/main/java/org/junit/runner/notification/Failure.java b/src/main/java/org/junit/runner/notification/Failure.java
index c7bd888..c03b4c1 100644
--- a/src/main/java/org/junit/runner/notification/Failure.java
+++ b/src/main/java/org/junit/runner/notification/Failure.java
@@ -17,6 +17,12 @@
  */
 public class Failure implements Serializable {
     private static final long serialVersionUID = 1L;
+
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
     private final Description fDescription;
     private final Throwable fThrownException;
 
@@ -27,8 +33,8 @@
      * @param thrownException the exception that was thrown while running the test
      */
     public Failure(Description description, Throwable thrownException) {
-        fThrownException = thrownException;
-        fDescription = description;
+        this.fThrownException = thrownException;
+        this.fDescription = description;
     }
 
     /**
@@ -55,9 +61,7 @@
 
     @Override
     public String toString() {
-        StringBuffer buffer = new StringBuffer();
-        buffer.append(getTestHeader() + ": " + fThrownException.getMessage());
-        return buffer.toString();
+        return getTestHeader() + ": " + fThrownException.getMessage();
     }
 
     /**
@@ -69,8 +73,7 @@
         StringWriter stringWriter = new StringWriter();
         PrintWriter writer = new PrintWriter(stringWriter);
         getException().printStackTrace(writer);
-        StringBuffer buffer = stringWriter.getBuffer();
-        return buffer.toString();
+        return stringWriter.toString();
     }
 
     /**
diff --git a/src/main/java/org/junit/runner/notification/RunListener.java b/src/main/java/org/junit/runner/notification/RunListener.java
index e4edadc..db9d8c1 100644
--- a/src/main/java/org/junit/runner/notification/RunListener.java
+++ b/src/main/java/org/junit/runner/notification/RunListener.java
@@ -1,15 +1,21 @@
 package org.junit.runner.notification;
 
-import org.junit.internal.AssumptionViolatedException;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
 import org.junit.runner.Description;
 import org.junit.runner.Result;
 
 /**
- * <p>If you need to respond to the events during a test run, extend <code>RunListener</code>
- * and override the appropriate methods. If a listener throws an exception while processing a
- * test event, it will be removed for the remainder of the test run.</p>
- *
- * <p>For example, suppose you have a <code>Cowbell</code>
+ * Register an instance of this class with {@link RunNotifier} to be notified
+ * of events that occur during a test run. All of the methods in this class
+ * are abstract and have no implementation; override one or more methods to
+ * receive events.
+ * <p>
+ * For example, suppose you have a <code>Cowbell</code>
  * class that you want to make a noise whenever a test fails. You could write:
  * <pre>
  * public class RingingListener extends RunListener {
@@ -18,9 +24,8 @@
  *    }
  * }
  * </pre>
- * </p>
- *
- * <p>To invoke your listener, you need to run your tests through <code>JUnitCore</code>.
+ * <p>
+ * To invoke your listener, you need to run your tests through <code>JUnitCore</code>.
  * <pre>
  * public void main(String... args) {
  *    JUnitCore core= new JUnitCore();
@@ -28,7 +33,18 @@
  *    core.run(MyTestClass.class);
  * }
  * </pre>
- * </p>
+ * <p>
+ * If a listener throws an exception for a test event, the other listeners will
+ * have their {@link RunListener#testFailure(Failure)} called with a {@code Description}
+ * of {@link Description#TEST_MECHANISM} to indicate the failure.
+ * <p>
+ * By default, JUnit will synchronize calls to your listener. If your listener
+ * is thread-safe and you want to allow JUnit to call your listener from
+ * multiple threads when tests are run in parallel, you can annotate your
+ * test class with {@link RunListener.ThreadSafe}.
+ * <p>
+ * Listener methods will be called from the same thread as is running
+ * the test, unless otherwise indicated by the method Javadoc
  *
  * @see org.junit.runner.JUnitCore
  * @since 4.0
@@ -36,7 +52,8 @@
 public class RunListener {
 
     /**
-     * Called before any tests have been run.
+     * Called before any tests have been run. This may be called on an
+     * arbitrary thread.
      *
      * @param description describes the tests to be run
      */
@@ -44,7 +61,8 @@
     }
 
     /**
-     * Called when all tests have finished
+     * Called when all tests have finished. This may be called on an
+     * arbitrary thread.
      *
      * @param result the summary of the test run, including all the tests that failed
      */
@@ -69,7 +87,16 @@
     }
 
     /**
-     * Called when an atomic test fails.
+     * Called when an atomic test fails, or when a listener throws an exception.
+     *
+     * <p>In the case of a failure of an atomic test, this method will be called
+     * with the same {@code Description} passed to
+     * {@link #testStarted(Description)}, from the same thread that called
+     * {@link #testStarted(Description)}.
+     *
+     * <p>In the case of a listener throwing an exception, this will be called with
+     * a {@code Description} of {@link Description#TEST_MECHANISM}, and may be called
+     * on an arbitrary thread.
      *
      * @param failure describes the test that failed and the exception that was thrown
      */
@@ -81,7 +108,7 @@
      * false
      *
      * @param failure describes the test that failed and the
-     * {@link AssumptionViolatedException} that was thrown
+     * {@link org.junit.AssumptionViolatedException} that was thrown
      */
     public void testAssumptionFailure(Failure failure) {
     }
@@ -94,6 +121,20 @@
      */
     public void testIgnored(Description description) throws Exception {
     }
+
+
+    /**
+     * Indicates a {@code RunListener} that can have its methods called
+     * concurrently. This implies that the class is thread-safe (i.e. no set of
+     * listener calls can put the listener into an invalid state, even if those
+     * listener calls are being made by multiple threads without
+     * synchronization).
+     *
+     * @since 4.12
+     */
+    @Documented
+    @Target(ElementType.TYPE)
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface ThreadSafe {
+    }
 }
-
-
diff --git a/src/main/java/org/junit/runner/notification/RunNotifier.java b/src/main/java/org/junit/runner/notification/RunNotifier.java
index b2546ad..8bd2dc4 100644
--- a/src/main/java/org/junit/runner/notification/RunNotifier.java
+++ b/src/main/java/org/junit/runner/notification/RunNotifier.java
@@ -3,11 +3,9 @@
 import static java.util.Arrays.asList;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
 
-import org.junit.internal.AssumptionViolatedException;
 import org.junit.runner.Description;
 import org.junit.runner.Result;
 
@@ -21,51 +19,63 @@
  * @since 4.0
  */
 public class RunNotifier {
-    private final List<RunListener> fListeners =
-            Collections.synchronizedList(new ArrayList<RunListener>());
-    private volatile boolean fPleaseStop = false;
+    private final List<RunListener> listeners = new CopyOnWriteArrayList<RunListener>();
+    private volatile boolean pleaseStop = false;
 
     /**
      * Internal use only
      */
     public void addListener(RunListener listener) {
-        fListeners.add(listener);
+        if (listener == null) {
+            throw new NullPointerException("Cannot add a null listener");
+        }
+        listeners.add(wrapIfNotThreadSafe(listener));
     }
 
     /**
      * Internal use only
      */
     public void removeListener(RunListener listener) {
-        fListeners.remove(listener);
+        if (listener == null) {
+            throw new NullPointerException("Cannot remove a null listener");
+        }
+        listeners.remove(wrapIfNotThreadSafe(listener));
     }
 
+    /**
+     * Wraps the given listener with {@link SynchronizedRunListener} if
+     * it is not annotated with {@link RunListener.ThreadSafe}.
+     */
+    RunListener wrapIfNotThreadSafe(RunListener listener) {
+        return listener.getClass().isAnnotationPresent(RunListener.ThreadSafe.class) ?
+                listener : new SynchronizedRunListener(listener, this);
+    }
+
+
     private abstract class SafeNotifier {
-        private final List<RunListener> fCurrentListeners;
+        private final List<RunListener> currentListeners;
 
         SafeNotifier() {
-            this(fListeners);
+            this(listeners);
         }
 
         SafeNotifier(List<RunListener> currentListeners) {
-            fCurrentListeners = currentListeners;
+            this.currentListeners = currentListeners;
         }
 
         void run() {
-            synchronized (fListeners) {
-                List<RunListener> safeListeners = new ArrayList<RunListener>();
-                List<Failure> failures = new ArrayList<Failure>();
-                for (Iterator<RunListener> all = fCurrentListeners.iterator(); all
-                        .hasNext(); ) {
-                    try {
-                        RunListener listener = all.next();
-                        notifyListener(listener);
-                        safeListeners.add(listener);
-                    } catch (Exception e) {
-                        failures.add(new Failure(Description.TEST_MECHANISM, e));
-                    }
+            int capacity = currentListeners.size();
+            List<RunListener> safeListeners = new ArrayList<RunListener>(capacity);
+            List<Failure> failures = new ArrayList<Failure>(capacity);
+            for (RunListener listener : currentListeners) {
+                try {
+                    notifyListener(listener);
+                    safeListeners.add(listener);
+                } catch (Exception e) {
+                    failures.add(new Failure(Description.TEST_MECHANISM, e));
                 }
-                fireTestFailures(safeListeners, failures);
             }
+            fireTestFailures(safeListeners, failures);
         }
 
         abstract protected void notifyListener(RunListener each) throws Exception;
@@ -80,8 +90,6 @@
             protected void notifyListener(RunListener each) throws Exception {
                 each.testRunStarted(description);
             }
-
-            ;
         }.run();
     }
 
@@ -94,8 +102,6 @@
             protected void notifyListener(RunListener each) throws Exception {
                 each.testRunFinished(result);
             }
-
-            ;
         }.run();
     }
 
@@ -106,7 +112,7 @@
      * @throws StoppedByUserException thrown if a user has requested that the test run stop
      */
     public void fireTestStarted(final Description description) throws StoppedByUserException {
-        if (fPleaseStop) {
+        if (pleaseStop) {
             throw new StoppedByUserException();
         }
         new SafeNotifier() {
@@ -114,8 +120,6 @@
             protected void notifyListener(RunListener each) throws Exception {
                 each.testStarted(description);
             }
-
-            ;
         }.run();
     }
 
@@ -125,7 +129,7 @@
      * @param failure the description of the test that failed and the exception thrown
      */
     public void fireTestFailure(Failure failure) {
-        fireTestFailures(fListeners, asList(failure));
+        fireTestFailures(listeners, asList(failure));
     }
 
     private void fireTestFailures(List<RunListener> listeners,
@@ -133,14 +137,11 @@
         if (!failures.isEmpty()) {
             new SafeNotifier(listeners) {
                 @Override
-                protected void notifyListener(RunListener listener)
-                        throws Exception {
+                protected void notifyListener(RunListener listener) throws Exception {
                     for (Failure each : failures) {
                         listener.testFailure(each);
                     }
                 }
-
-                ;
             }.run();
         }
     }
@@ -150,7 +151,7 @@
      * something false.
      *
      * @param failure the description of the test that failed and the
-     * {@link AssumptionViolatedException} thrown
+     * {@link org.junit.AssumptionViolatedException} thrown
      */
     public void fireTestAssumptionFailed(final Failure failure) {
         new SafeNotifier() {
@@ -158,8 +159,6 @@
             protected void notifyListener(RunListener each) throws Exception {
                 each.testAssumptionFailure(failure);
             }
-
-            ;
         }.run();
     }
 
@@ -179,7 +178,7 @@
 
     /**
      * Invoke to tell listeners that an atomic test finished. Always invoke
-     * {@link #fireTestFinished(Description)} if you invoke {@link #fireTestStarted(Description)}
+     * this method if you invoke {@link #fireTestStarted(Description)}
      * as listeners are likely to expect them to come in pairs.
      *
      * @param description the description of the test that finished
@@ -190,8 +189,6 @@
             protected void notifyListener(RunListener each) throws Exception {
                 each.testFinished(description);
             }
-
-            ;
         }.run();
     }
 
@@ -202,13 +199,16 @@
      * to be shared amongst the many runners involved.
      */
     public void pleaseStop() {
-        fPleaseStop = true;
+        pleaseStop = true;
     }
 
     /**
      * Internal use only. The Result's listener must be first.
      */
     public void addFirstListener(RunListener listener) {
-        fListeners.add(0, listener);
+        if (listener == null) {
+            throw new NullPointerException("Cannot add a null listener");
+        }
+        listeners.add(0, wrapIfNotThreadSafe(listener));
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/runner/notification/SynchronizedRunListener.java b/src/main/java/org/junit/runner/notification/SynchronizedRunListener.java
new file mode 100644
index 0000000..c53c1ee
--- /dev/null
+++ b/src/main/java/org/junit/runner/notification/SynchronizedRunListener.java
@@ -0,0 +1,103 @@
+package org.junit.runner.notification;
+
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+
+/**
+ * Thread-safe decorator for {@link RunListener} implementations that synchronizes
+ * calls to the delegate.
+ *
+ * <p>This class synchronizes all listener calls on a RunNotifier instance. This is done because
+ * prior to JUnit 4.12, all listeners were called in a synchronized block in RunNotifier,
+ * so no two listeners were ever called concurrently. If we instead made the methods here
+ * sychronized, clients that added multiple listeners that called common code might see
+ * issues due to the reduced synchronization.
+ *
+ * @author Tibor Digana (tibor17)
+ * @author Kevin Cooney (kcooney)
+ * @since 4.12
+ *
+ * @see RunNotifier
+ */
+@RunListener.ThreadSafe
+final class SynchronizedRunListener extends RunListener {
+    private final RunListener listener;
+    private final Object monitor;
+
+    SynchronizedRunListener(RunListener listener, Object monitor) {
+        this.listener = listener;
+        this.monitor = monitor;
+    }
+
+    @Override
+    public void testRunStarted(Description description) throws Exception {
+        synchronized (monitor) {
+            listener.testRunStarted(description);
+        }
+    }
+
+    @Override
+    public void testRunFinished(Result result) throws Exception {
+        synchronized (monitor) {
+            listener.testRunFinished(result);
+        }
+    }
+
+    @Override
+    public void testStarted(Description description) throws Exception {
+        synchronized (monitor) {
+            listener.testStarted(description);
+        }
+    }
+
+    @Override
+    public void testFinished(Description description) throws Exception {
+        synchronized (monitor) {
+            listener.testFinished(description);
+        }
+    }
+
+    @Override
+    public void testFailure(Failure failure) throws Exception {
+        synchronized (monitor) {
+            listener.testFailure(failure);
+        }
+    }
+
+    @Override
+    public void testAssumptionFailure(Failure failure) {
+        synchronized (monitor) {
+            listener.testAssumptionFailure(failure);
+        }
+    }
+
+    @Override
+    public void testIgnored(Description description) throws Exception {
+        synchronized (monitor) {
+            listener.testIgnored(description);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return listener.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof SynchronizedRunListener)) {
+            return false;
+        }
+        SynchronizedRunListener that = (SynchronizedRunListener) other;
+        
+        return listener.equals(that.listener);
+    }
+
+    @Override
+    public String toString() {
+        return listener.toString() + " (with synchronization wrapper)";
+    }
+}
diff --git a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
index fdbf82f..822f8dc 100644
--- a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
+++ b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
@@ -1,9 +1,12 @@
 package org.junit.runners;
 
-import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_METHOD_VALIDATOR;
-import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_METHOD_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_VALIDATOR;
 
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
 
 import org.junit.After;
 import org.junit.Before;
@@ -18,6 +21,7 @@
 import org.junit.internal.runners.statements.InvokeMethod;
 import org.junit.internal.runners.statements.RunAfters;
 import org.junit.internal.runners.statements.RunBefores;
+import org.junit.rules.MethodRule;
 import org.junit.rules.RunRules;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
@@ -32,7 +36,7 @@
  * annotations in the org.junit package. Many users will never notice this
  * class: it is now the default test class runner, but it should have exactly
  * the same behavior as the old test class runner ({@code JUnit4ClassRunner}).
- *
+ * <p>
  * BlockJUnit4ClassRunner has advantages for writers of custom JUnit runners
  * that are slight changes to the default behavior, however:
  *
@@ -44,17 +48,24 @@
  * <li>It is published, and extension and reuse are encouraged, whereas {@code
  * JUnit4ClassRunner} was in an internal package, and is now deprecated.
  * </ul>
+ * <p>
+ * In turn, in 2009 we introduced {@link Rule}s.  In many cases where extending
+ * BlockJUnit4ClassRunner was necessary to add new behavior, {@link Rule}s can
+ * be used, which makes the extension more reusable and composable.
  *
  * @since 4.5
  */
 public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
+
+    private final ConcurrentMap<FrameworkMethod, Description> methodDescriptions = new ConcurrentHashMap<FrameworkMethod, Description>();
+
     /**
-     * Creates a BlockJUnit4ClassRunner to run {@code klass}
+     * Creates a BlockJUnit4ClassRunner to run {@code testClass}
      *
      * @throws InitializationError if the test class is malformed.
      */
-    public BlockJUnit4ClassRunner(Class<?> klass) throws InitializationError {
-        super(klass);
+    public BlockJUnit4ClassRunner(Class<?> testClass) throws InitializationError {
+        super(testClass);
     }
 
     //
@@ -64,17 +75,40 @@
     @Override
     protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
         Description description = describeChild(method);
-        if (method.getAnnotation(Ignore.class) != null) {
+        if (isIgnored(method)) {
             notifier.fireTestIgnored(description);
         } else {
-            runLeaf(methodBlock(method), description, notifier);
+            Statement statement;
+            try {
+                statement = methodBlock(method);
+            }
+            catch (Throwable ex) {
+                statement = new Fail(ex);
+            }
+            runLeaf(statement, description, notifier);
         }
     }
 
+    /**
+     * Evaluates whether {@link FrameworkMethod}s are ignored based on the
+     * {@link Ignore} annotation.
+     */
+    @Override
+    protected boolean isIgnored(FrameworkMethod child) {
+        return child.getAnnotation(Ignore.class) != null;
+    }
+
     @Override
     protected Description describeChild(FrameworkMethod method) {
-        return Description.createTestDescription(getTestClass().getJavaClass(),
-                testName(method), method.getAnnotations());
+        Description description = methodDescriptions.get(method);
+
+        if (description == null) {
+            description = Description.createTestDescription(getTestClass().getJavaClass(),
+                    testName(method), method.getAnnotations());
+            methodDescriptions.putIfAbsent(method, description);
+        }
+
+        return description;
     }
 
     @Override
@@ -156,8 +190,7 @@
      * Adds to {@code errors} for each method annotated with {@code @Test},
      * {@code @Before}, or {@code @After} that is not a public, void instance
      * method with no arguments.
-     *
-     * @deprecated unused API, will go away in future version
+     * @deprecated
      */
     @Deprecated
     protected void validateInstanceMethods(List<Throwable> errors) {
@@ -165,7 +198,7 @@
         validatePublicVoidNoArgMethods(Before.class, false, errors);
         validateTestMethods(errors);
 
-        if (computeTestMethods().size() == 0) {
+        if (computeTestMethods().isEmpty()) {
             errors.add(new Exception("No runnable methods"));
         }
     }
@@ -196,6 +229,16 @@
     }
 
     /**
+     * Returns a new fixture to run a particular test {@code method} against.
+     * Default implementation executes the no-argument {@link #createTest()} method.
+     *
+     * @since 4.13
+     */
+    protected Object createTest(FrameworkMethod method) throws Exception {
+        return createTest();
+    }
+
+    /**
      * Returns the name that describes {@code method} for {@link Description}s.
      * Default implementation is the method's name
      */
@@ -210,7 +253,7 @@
      * Here is an outline of the default implementation:
      *
      * <ul>
-     * <li>Invoke {@code method} on the result of {@code createTest()}, and
+     * <li>Invoke {@code method} on the result of {@link #createTest(org.junit.runners.model.FrameworkMethod)}, and
      * throw any exceptions thrown by either operation.
      * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code
      * expecting} attribute, return normally only if the previous step threw an
@@ -235,13 +278,13 @@
      * This can be overridden in subclasses, either by overriding this method,
      * or the implementations creating each sub-statement.
      */
-    protected Statement methodBlock(FrameworkMethod method) {
+    protected Statement methodBlock(final FrameworkMethod method) {
         Object test;
         try {
             test = new ReflectiveCallable() {
                 @Override
                 protected Object runReflectiveCall() throws Throwable {
-                    return createTest();
+                    return createTest(method);
                 }
             }.run();
         } catch (Throwable e) {
@@ -273,10 +316,7 @@
      * has the {@code expecting} attribute, return normally only if {@code next}
      * throws an exception of the correct type, and throw an exception
      * otherwise.
-     *
-     * @deprecated Will be private soon: use Rules instead
      */
-    @Deprecated
     protected Statement possiblyExpectingExceptions(FrameworkMethod method,
             Object test, Statement next) {
         Test annotation = method.getAnnotation(Test.class);
@@ -288,14 +328,18 @@
      * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation
      * has the {@code timeout} attribute, throw an exception if {@code next}
      * takes more than the specified number of milliseconds.
-     *
-     * @deprecated Will be private soon: use Rules instead
+     * @deprecated
      */
     @Deprecated
     protected Statement withPotentialTimeout(FrameworkMethod method,
             Object test, Statement next) {
         long timeout = getTimeout(method.getAnnotation(Test.class));
-        return timeout > 0 ? new FailOnTimeout(next, timeout) : next;
+        if (timeout <= 0) {
+            return next;
+        }
+        return FailOnTimeout.builder()
+               .withTimeout(timeout, TimeUnit.MILLISECONDS)
+               .build(next);
     }
 
     /**
@@ -338,12 +382,13 @@
 
     private Statement withMethodRules(FrameworkMethod method, List<TestRule> testRules,
             Object target, Statement result) {
+        Statement withMethodRules = result;
         for (org.junit.rules.MethodRule each : getMethodRules(target)) {
-            if (!testRules.contains(each)) {
-                result = each.apply(result, method, target);
+            if (!(each instanceof TestRule && testRules.contains(each))) {
+                withMethodRules = each.apply(withMethodRules, method, target);
             }
         }
-        return result;
+        return withMethodRules;
     }
 
     private List<org.junit.rules.MethodRule> getMethodRules(Object target) {
@@ -355,13 +400,18 @@
      * @return a list of MethodRules that should be applied when executing this
      *         test
      */
-    protected List<org.junit.rules.MethodRule> rules(Object target) {
-        return getTestClass().getAnnotatedFieldValues(target, Rule.class,
-                org.junit.rules.MethodRule.class);
+    protected List<MethodRule> rules(Object target) {
+        List<MethodRule> rules = getTestClass().getAnnotatedMethodValues(target, 
+                Rule.class, MethodRule.class);
+
+        rules.addAll(getTestClass().getAnnotatedFieldValues(target,
+                Rule.class, MethodRule.class));
+
+        return rules;
     }
 
     /**
-     * Returns a {@link Statement}: apply all non-static {@link Value} fields
+     * Returns a {@link Statement}: apply all non-static fields
      * annotated with {@link Rule}.
      *
      * @param statement The base statement
@@ -407,4 +457,4 @@
         }
         return annotation.timeout();
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/runners/MethodSorters.java b/src/main/java/org/junit/runners/MethodSorters.java
index 4900f88..5821892 100644
--- a/src/main/java/org/junit/runners/MethodSorters.java
+++ b/src/main/java/org/junit/runners/MethodSorters.java
@@ -29,13 +29,13 @@
      */
     DEFAULT(MethodSorter.DEFAULT);
 
-    private final Comparator<Method> fComparator;
+    private final Comparator<Method> comparator;
 
     private MethodSorters(Comparator<Method> comparator) {
-        this.fComparator = comparator;
+        this.comparator = comparator;
     }
 
     public Comparator<Method> getComparator() {
-        return fComparator;
+        return comparator;
     }
 }
diff --git a/src/main/java/org/junit/runners/Parameterized.java b/src/main/java/org/junit/runners/Parameterized.java
index db85a63..cc7c804 100644
--- a/src/main/java/org/junit/runners/Parameterized.java
+++ b/src/main/java/org/junit/runners/Parameterized.java
@@ -1,62 +1,60 @@
 package org.junit.runners;
 
-import java.lang.annotation.Annotation;
 import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.reflect.Field;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
 import org.junit.runner.Runner;
-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.Statement;
+import org.junit.runners.model.TestClass;
+import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParametersFactory;
+import org.junit.runners.parameterized.ParametersRunnerFactory;
+import org.junit.runners.parameterized.TestWithParameters;
 
 /**
- * <p>
  * The custom runner <code>Parameterized</code> implements parameterized tests.
  * When running a parameterized test class, instances are created for the
  * cross-product of the test methods and the test data elements.
- * </p>
- *
- * For example, to test a Fibonacci function, write:
- *
+ * <p>
+ * For example, to test the <code>+</code> operator, write:
  * <pre>
  * &#064;RunWith(Parameterized.class)
- * public class FibonacciTest {
- *     &#064;Parameters(name= &quot;{index}: fib[{0}]={1}&quot;)
+ * public class AdditionTest {
+ *     &#064;Parameters(name = &quot;{index}: {0} + {1} = {2}&quot;)
  *     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 } });
+ *         return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 },
+ *                 { 3, 2, 5 }, { 4, 3, 7 } });
  *     }
  *
- *     private int fInput;
+ *     private int firstSummand;
  *
- *     private int fExpected;
+ *     private int secondSummand;
  *
- *     public FibonacciTest(int input, int expected) {
- *         fInput= input;
- *         fExpected= expected;
+ *     private int sum;
+ *
+ *     public AdditionTest(int firstSummand, int secondSummand, int sum) {
+ *         this.firstSummand = firstSummand;
+ *         this.secondSummand = secondSummand;
+ *         this.sum = sum;
  *     }
  *
  *     &#064;Test
  *     public void test() {
- *         assertEquals(fExpected, Fibonacci.compute(fInput));
+ *         assertEquals(sum, firstSummand + secondSummand);
  *     }
  * }
  * </pre>
- *
  * <p>
- * Each instance of <code>FibonacciTest</code> will be constructed using the
- * two-argument constructor and the data values in the
+ * Each instance of <code>AdditionTest</code> will be constructed using the
+ * three-argument constructor and the data values in the
  * <code>&#064;Parameters</code> method.
- *
  * <p>
  * In order that you can easily identify the individual tests, you may provide a
  * name for the <code>&#064;Parameters</code> annotation. This name is allowed
@@ -69,60 +67,118 @@
  * <dt>{1}</dt>
  * <dd>the second parameter value</dd>
  * <dt>...</dt>
- * <dd></dd>
+ * <dd>...</dd>
  * </dl>
+ * <p>
  * In the example given above, the <code>Parameterized</code> runner creates
- * names like <code>[1: fib(3)=2]</code>. If you don't use the name parameter,
+ * names like <code>[2: 3 + 2 = 5]</code>. If you don't use the name parameter,
  * then the current parameter index is used as name.
- * </p>
- *
+ * <p>
  * You can also write:
- *
  * <pre>
  * &#064;RunWith(Parameterized.class)
- * public class FibonacciTest {
- *  &#064;Parameters
- *  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 } });
- *  }
- *  
- *  &#064;Parameter(0)
- *  public int fInput;
+ * public class AdditionTest {
+ *     &#064;Parameters(name = &quot;{index}: {0} + {1} = {2}&quot;)
+ *     public static Iterable&lt;Object[]&gt; data() {
+ *         return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 },
+ *                 { 3, 2, 5 }, { 4, 3, 7 } });
+ *     }
  *
- *  &#064;Parameter(1)
- *  public int fExpected;
+ *     &#064;Parameter(0)
+ *     public int firstSummand;
  *
- *  &#064;Test
- *  public void test() {
- *      assertEquals(fExpected, Fibonacci.compute(fInput));
- *  }
+ *     &#064;Parameter(1)
+ *     public int secondSummand;
+ *
+ *     &#064;Parameter(2)
+ *     public int sum;
+ *
+ *     &#064;Test
+ *     public void test() {
+ *         assertEquals(sum, firstSummand + secondSummand);
+ *     }
+ * }
+ * </pre>
+ * <p>
+ * Each instance of <code>AdditionTest</code> will be constructed with the default constructor
+ * and fields annotated by <code>&#064;Parameter</code>  will be initialized
+ * with the data values in the <code>&#064;Parameters</code> method.
+ *
+ * <p>
+ * The parameters can be provided as an array, too:
+ * 
+ * <pre>
+ * &#064;Parameters
+ * public static Object[][] data() {
+ * 	return new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, { 3, 2, 5 }, { 4, 3, 7 } } };
+ * }
+ * </pre>
+ * 
+ * <h3>Tests with single parameter</h3>
+ * <p>
+ * If your test needs a single parameter only, you don't have to wrap it with an
+ * array. Instead you can provide an <code>Iterable</code> or an array of
+ * objects.
+ * <pre>
+ * &#064;Parameters
+ * public static Iterable&lt;? extends Object&gt; data() {
+ * 	return Arrays.asList(&quot;first test&quot;, &quot;second test&quot;);
+ * }
+ * </pre>
+ * <p>
+ * or
+ * <pre>
+ * &#064;Parameters
+ * public static Object[] data() {
+ * 	return new Object[] { &quot;first test&quot;, &quot;second test&quot; };
  * }
  * </pre>
  *
+ * <h3>Create different runners</h3>
  * <p>
- * Each instance of <code>FibonacciTest</code> will be constructed with the default constructor
- * and fields annotated by <code>&#064;Parameter</code>  will be initialized
- * with the data values in the <code>&#064;Parameters</code> method.
- * </p>
+ * By default the {@code Parameterized} runner creates a slightly modified
+ * {@link BlockJUnit4ClassRunner} for each set of parameters. You can build an
+ * own {@code Parameterized} runner that creates another runner for each set of
+ * parameters. Therefore you have to build a {@link ParametersRunnerFactory}
+ * that creates a runner for each {@link TestWithParameters}. (
+ * {@code TestWithParameters} are bundling the parameters and the test name.)
+ * The factory must have a public zero-arg constructor.
+ *
+ * <pre>
+ * public class YourRunnerFactory implements ParametersRunnerFactory {
+ *     public Runner createRunnerForTestWithParameters(TestWithParameters test)
+ *             throws InitializationError {
+ *         return YourRunner(test);
+ *     }
+ * }
+ * </pre>
+ * <p>
+ * Use the {@link UseParametersRunnerFactory} to tell the {@code Parameterized}
+ * runner that it should use your factory.
+ *
+ * <pre>
+ * &#064;RunWith(Parameterized.class)
+ * &#064;UseParametersRunnerFactory(YourRunnerFactory.class)
+ * public class YourTest {
+ *     ...
+ * }
+ * </pre>
  *
  * @since 4.0
  */
 public class Parameterized extends Suite {
     /**
      * Annotation for a method which provides parameters to be injected into the
-     * test class constructor by <code>Parameterized</code>
+     * test class constructor by <code>Parameterized</code>. The method has to
+     * be public and static.
      */
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.METHOD)
-    public static @interface Parameters {
+    public @interface Parameters {
         /**
-         * <p>
          * Optional pattern to derive the test's name from the parameters. Use
          * numbers in braces to refer to the parameters or the additional data
          * as follows:
-         * </p>
-         *
          * <pre>
          * {index} - the current parameter index
          * {0} - the first parameter value
@@ -132,7 +188,6 @@
          * <p>
          * Default value is "{index}" for compatibility with previous JUnit
          * versions.
-         * </p>
          *
          * @return {@link MessageFormat} pattern string, except the index
          *         placeholder.
@@ -143,17 +198,17 @@
 
     /**
      * Annotation for fields of the test class which will be initialized by the
-     * method annotated by <code>Parameters</code><br/>
-     * By using directly this annotation, the test class constructor isn't needed.<br/>
+     * method annotated by <code>Parameters</code>.
+     * By using directly this annotation, the test class constructor isn't needed.
      * Index range must start at 0.
      * Default value is 0.
      */
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
-    public static @interface Parameter {
+    public @interface Parameter {
         /**
          * Method that returns the index of the parameter in the array
-         * returned by the method annotated by <code>Parameters</code>.<br/>
+         * returned by the method annotated by <code>Parameters</code>.
          * Index range must start at 0.
          * Default value is 0.
          *
@@ -162,189 +217,144 @@
         int value() default 0;
     }
 
-    protected class TestClassRunnerForParameters extends BlockJUnit4ClassRunner {
-        private final Object[] fParameters;
-
-        private String fName;
-
-        protected TestClassRunnerForParameters(Class<?> type, String pattern, int index, Object[] parameters) throws InitializationError {
-            super(type);
-
-            fParameters = parameters;
-            fName = nameFor(pattern, index, parameters);
-        }
-
-        @Override
-        public Object createTest() throws Exception {
-            if (fieldsAreAnnotated()) {
-                return createTestUsingFieldInjection();
-            } else {
-                return createTestUsingConstructorInjection();
-            }
-        }
-
-        private Object createTestUsingConstructorInjection() throws Exception {
-            return getTestClass().getOnlyConstructor().newInstance(fParameters);
-        }
-
-        private Object createTestUsingFieldInjection() throws Exception {
-            List<FrameworkField> annotatedFieldsByParameter = getAnnotatedFieldsByParameter();
-            if (annotatedFieldsByParameter.size() != fParameters.length) {
-                throw new Exception("Wrong number of parameters and @Parameter fields." +
-                        " @Parameter fields counted: " + annotatedFieldsByParameter.size() + ", available parameters: " + fParameters.length + ".");
-            }
-            Object testClassInstance = getTestClass().getJavaClass().newInstance();
-            for (FrameworkField each : annotatedFieldsByParameter) {
-                Field field = each.getField();
-                Parameter annotation = field.getAnnotation(Parameter.class);
-                int index = annotation.value();
-                try {
-                    field.set(testClassInstance, fParameters[index]);
-                } catch (IllegalArgumentException iare) {
-                    throw new Exception(getTestClass().getName() + ": Trying to set " + field.getName() +
-                            " with the value " + fParameters[index] +
-                            " that is not the right type (" + fParameters[index].getClass().getSimpleName() + " instead of " +
-                            field.getType().getSimpleName() + ").", iare);
-                }
-            }
-            return testClassInstance;
-        }
-
-        protected String nameFor(String pattern, int index, Object[] parameters) {
-            String finalPattern = pattern.replaceAll("\\{index\\}", Integer.toString(index));
-            String name = MessageFormat.format(finalPattern, parameters);
-            return "[" + name + "]";
-        }
-
-        @Override
-        protected String getName() {
-            return fName;
-        }
-
-        @Override
-        protected String testName(FrameworkMethod method) {
-            return method.getName() + getName();
-        }
-
-        @Override
-        protected void validateConstructor(List<Throwable> errors) {
-            validateOnlyOneConstructor(errors);
-            if (fieldsAreAnnotated()) {
-                validateZeroArgConstructor(errors);
-            }
-        }
-
-        @Override
-        protected void validateFields(List<Throwable> errors) {
-            super.validateFields(errors);
-            if (fieldsAreAnnotated()) {
-                List<FrameworkField> annotatedFieldsByParameter = getAnnotatedFieldsByParameter();
-                int[] usedIndices = new int[annotatedFieldsByParameter.size()];
-                for (FrameworkField each : annotatedFieldsByParameter) {
-                    int index = each.getField().getAnnotation(Parameter.class).value();
-                    if (index < 0 || index > annotatedFieldsByParameter.size() - 1) {
-                        errors.add(
-                                new Exception("Invalid @Parameter value: " + index + ". @Parameter fields counted: " +
-                                        annotatedFieldsByParameter.size() + ". Please use an index between 0 and " +
-                                        (annotatedFieldsByParameter.size() - 1) + ".")
-                        );
-                    } else {
-                        usedIndices[index]++;
-                    }
-                }
-                for (int index = 0; index < usedIndices.length; index++) {
-                    int numberOfUse = usedIndices[index];
-                    if (numberOfUse == 0) {
-                        errors.add(new Exception("@Parameter(" + index + ") is never used."));
-                    } else if (numberOfUse > 1) {
-                        errors.add(new Exception("@Parameter(" + index + ") is used more than once (" + numberOfUse + ")."));
-                    }
-                }
-            }
-        }
-
-        @Override
-        protected Statement classBlock(RunNotifier notifier) {
-            return childrenInvoker(notifier);
-        }
-
-        @Override
-        protected Annotation[] getRunnerAnnotations() {
-            return new Annotation[0];
-        }
+    /**
+     * Add this annotation to your test class if you want to generate a special
+     * runner. You have to specify a {@link ParametersRunnerFactory} class that
+     * creates such runners. The factory must have a public zero-arg
+     * constructor.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Inherited
+    @Target(ElementType.TYPE)
+    public @interface UseParametersRunnerFactory {
+        /**
+         * @return a {@link ParametersRunnerFactory} class (must have a default
+         *         constructor)
+         */
+        Class<? extends ParametersRunnerFactory> value() default BlockJUnit4ClassRunnerWithParametersFactory.class;
     }
 
-    private static final List<Runner> NO_RUNNERS = Collections.<Runner>emptyList();
-
-    private final ArrayList<Runner> runners = new ArrayList<Runner>();
-
     /**
      * Only called reflectively. Do not use programmatically.
      */
     public Parameterized(Class<?> klass) throws Throwable {
-        super(klass, NO_RUNNERS);
-        Parameters parameters = getParametersMethod().getAnnotation(
-                Parameters.class);
-        createRunnersForParameters(allParameters(), parameters.name());
+        super(klass, RunnersFactory.createRunnersForClass(klass));
     }
 
-    @Override
-    protected List<Runner> getChildren() {
-        return runners;
-    }
+    private static class RunnersFactory {
+        private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory();
 
-    protected Runner createRunner(String pattern, int index, Object[] parameters) throws InitializationError {
-        return new TestClassRunnerForParameters(getTestClass().getJavaClass(), pattern, index, parameters);
-    }
+        private final TestClass testClass;
 
-    @SuppressWarnings("unchecked")
-    private Iterable<Object[]> allParameters() throws Throwable {
-        Object parameters = getParametersMethod().invokeExplosively(null);
-        if (parameters instanceof Iterable) {
-            return (Iterable<Object[]>) parameters;
-        } else {
-            throw parametersMethodReturnedWrongType();
+        static List<Runner> createRunnersForClass(Class<?> klass)
+                throws Throwable {
+            return new RunnersFactory(klass).createRunners();
         }
-    }
 
-    private FrameworkMethod getParametersMethod() throws Exception {
-        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(
-                Parameters.class);
-        for (FrameworkMethod each : methods) {
-            if (each.isStatic() && each.isPublic()) {
-                return each;
+        private RunnersFactory(Class<?> klass) {
+            testClass = new TestClass(klass);
+        }
+
+        private List<Runner> createRunners() throws Throwable {
+            Parameters parameters = getParametersMethod().getAnnotation(
+                    Parameters.class);
+            return Collections.unmodifiableList(createRunnersForParameters(
+                    allParameters(), parameters.name(),
+                    getParametersRunnerFactory()));
+        }
+
+        private ParametersRunnerFactory getParametersRunnerFactory()
+                throws InstantiationException, IllegalAccessException {
+            UseParametersRunnerFactory annotation = testClass
+                    .getAnnotation(UseParametersRunnerFactory.class);
+            if (annotation == null) {
+                return DEFAULT_FACTORY;
+            } else {
+                Class<? extends ParametersRunnerFactory> factoryClass = annotation
+                        .value();
+                return factoryClass.newInstance();
             }
         }
 
-        throw new Exception("No public static parameters method on class "
-                + getTestClass().getName());
-    }
+        private TestWithParameters createTestWithNotNormalizedParameters(
+                String pattern, int index, Object parametersOrSingleParameter) {
+            Object[] parameters = (parametersOrSingleParameter instanceof Object[]) ? (Object[]) parametersOrSingleParameter
+                    : new Object[] { parametersOrSingleParameter };
+            return createTestWithParameters(testClass, pattern, index,
+                    parameters);
+        }
 
-    private void createRunnersForParameters(Iterable<Object[]> allParameters, String namePattern) throws Exception {
-        try {
+        @SuppressWarnings("unchecked")
+        private Iterable<Object> allParameters() throws Throwable {
+            Object parameters = getParametersMethod().invokeExplosively(null);
+            if (parameters instanceof Iterable) {
+                return (Iterable<Object>) parameters;
+            } else if (parameters instanceof Object[]) {
+                return Arrays.asList((Object[]) parameters);
+            } else {
+                throw parametersMethodReturnedWrongType();
+            }
+        }
+
+        private FrameworkMethod getParametersMethod() throws Exception {
+            List<FrameworkMethod> methods = testClass
+                    .getAnnotatedMethods(Parameters.class);
+            for (FrameworkMethod each : methods) {
+                if (each.isStatic() && each.isPublic()) {
+                    return each;
+                }
+            }
+
+            throw new Exception("No public static parameters method on class "
+                    + testClass.getName());
+        }
+
+        private List<Runner> createRunnersForParameters(
+                Iterable<Object> allParameters, String namePattern,
+                ParametersRunnerFactory runnerFactory) throws Exception {
+            try {
+                List<TestWithParameters> tests = createTestsForParameters(
+                        allParameters, namePattern);
+                List<Runner> runners = new ArrayList<Runner>();
+                for (TestWithParameters test : tests) {
+                    runners.add(runnerFactory
+                            .createRunnerForTestWithParameters(test));
+                }
+                return runners;
+            } catch (ClassCastException e) {
+                throw parametersMethodReturnedWrongType();
+            }
+        }
+
+        private List<TestWithParameters> createTestsForParameters(
+                Iterable<Object> allParameters, String namePattern)
+                throws Exception {
             int i = 0;
-            for (Object[] parametersOfSingleTest : allParameters) {
-                runners.add(createRunner(namePattern, i++, parametersOfSingleTest));
+            List<TestWithParameters> children = new ArrayList<TestWithParameters>();
+            for (Object parametersOfSingleTest : allParameters) {
+                children.add(createTestWithNotNormalizedParameters(namePattern,
+                        i++, parametersOfSingleTest));
             }
-        } catch (ClassCastException e) {
-            throw parametersMethodReturnedWrongType();
+            return children;
+        }
+
+        private Exception parametersMethodReturnedWrongType() throws Exception {
+            String className = testClass.getName();
+            String methodName = getParametersMethod().getName();
+            String message = MessageFormat.format(
+                    "{0}.{1}() must return an Iterable of arrays.", className,
+                    methodName);
+            return new Exception(message);
+        }
+
+        private TestWithParameters createTestWithParameters(
+                TestClass testClass, String pattern, int index,
+                Object[] parameters) {
+            String finalPattern = pattern.replaceAll("\\{index\\}",
+                    Integer.toString(index));
+            String name = MessageFormat.format(finalPattern, parameters);
+            return new TestWithParameters("[" + name + "]", testClass,
+                    Arrays.asList(parameters));
         }
     }
-
-    private Exception parametersMethodReturnedWrongType() throws Exception {
-        String className = getTestClass().getName();
-        String methodName = getParametersMethod().getName();
-        String message = MessageFormat.format(
-                "{0}.{1}() must return an Iterable of arrays.",
-                className, methodName);
-        return new Exception(message);
-    }
-
-    private List<FrameworkField> getAnnotatedFieldsByParameter() {
-        return getTestClass().getAnnotatedFields(Parameter.class);
-    }
-
-    private boolean fieldsAreAnnotated() {
-        return !getAnnotatedFieldsByParameter().isEmpty();
-    }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/junit/runners/ParentRunner.java b/src/main/java/org/junit/runners/ParentRunner.java
old mode 100644
new mode 100755
index b965575..92641bf
--- a/src/main/java/org/junit/runners/ParentRunner.java
+++ b/src/main/java/org/junit/runners/ParentRunner.java
@@ -1,11 +1,13 @@
 package org.junit.runners;
 
-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.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
@@ -14,6 +16,7 @@
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.internal.AssumptionViolatedException;
 import org.junit.internal.runners.model.EachTestNotifier;
@@ -32,10 +35,12 @@
 import org.junit.runner.notification.StoppedByUserException;
 import org.junit.runners.model.FrameworkMethod;
 import org.junit.runners.model.InitializationError;
-import org.junit.runners.model.MultipleFailureException;
 import org.junit.runners.model.RunnerScheduler;
 import org.junit.runners.model.Statement;
 import org.junit.runners.model.TestClass;
+import org.junit.validator.AnnotationsValidator;
+import org.junit.validator.PublicClassValidator;
+import org.junit.validator.TestClassValidator;
 
 /**
  * Provides most of the functionality specific to a Runner that implements a
@@ -52,13 +57,16 @@
  */
 public abstract class ParentRunner<T> extends Runner implements Filterable,
         Sortable {
-    private final TestClass fTestClass;
+    private static final List<TestClassValidator> VALIDATORS = Arrays.asList(
+            new AnnotationsValidator(), new PublicClassValidator());
 
-    private Sorter fSorter = Sorter.NULL;
+    private final Object childrenLock = new Object();
+    private final TestClass testClass;
 
-    private List<T> fFilteredChildren = null;
+    // Guarded by childrenLock
+    private volatile Collection<T> filteredChildren = null;
 
-    private RunnerScheduler fScheduler = new RunnerScheduler() {
+    private volatile RunnerScheduler scheduler = new RunnerScheduler() {
         public void schedule(Runnable childStatement) {
             childStatement.run();
         }
@@ -72,10 +80,14 @@
      * Constructs a new {@code ParentRunner} that will run {@code @TestClass}
      */
     protected ParentRunner(Class<?> testClass) throws InitializationError {
-        fTestClass = new TestClass(testClass);
+        this.testClass = createTestClass(testClass);
         validate();
     }
 
+    protected TestClass createTestClass(Class<?> testClass) {
+        return new TestClass(testClass);
+    }
+
     //
     // Must be overridden
     //
@@ -113,6 +125,15 @@
         validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
         validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
         validateClassRules(errors);
+        applyValidators(errors);
+    }
+
+    private void applyValidators(List<Throwable> errors) {
+        if (getTestClass().getJavaClass() != null) {
+            for (TestClassValidator each : VALIDATORS) {
+                errors.addAll(each.validateTestClass(getTestClass()));
+            }
+        }
     }
 
     /**
@@ -124,6 +145,7 @@
      * <li>returns something other than void, or
      * <li>is static (given {@code isStatic is false}), or
      * <li>is not static (given {@code isStatic is true}).
+     * </ul>
      */
     protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation,
             boolean isStatic, List<Throwable> errors) {
@@ -140,37 +162,56 @@
     }
 
     /**
-     * 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:
-     * <ul>
-     * <li>Call {@link #runChild(Object, RunNotifier)} on each object returned by {@link #getChildren()} (subject to any imposed filter and sort).</li>
-     * <li>ALWAYS run all non-overridden {@code @BeforeClass} methods on this class
-     * and superclasses before the previous step; if any throws an
-     * Exception, stop execution and pass the exception on.
-     * <li>ALWAYS run all non-overridden {@code @AfterClass} methods on this class
-     * and superclasses before any of the previous steps; all AfterClass methods are
-     * always executed: exceptions thrown by previous steps are combined, if
+     * 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:
+     * <ol>
+     * <li>Determine the children to be run using {@link #getChildren()}
+     * (subject to any imposed filter and sort).</li>
+     * <li>If there are any children remaining after filtering and ignoring,
+     * construct a statement that will:
+     * <ol>
+     * <li>Apply all {@code ClassRule}s on the test-class and superclasses.</li>
+     * <li>Run all non-overridden {@code @BeforeClass} methods on the test-class
+     * and superclasses; if any throws an Exception, stop execution and pass the
+     * exception on.</li>
+     * <li>Run all remaining tests on the test-class.</li>
+     * <li>Run all non-overridden {@code @AfterClass} methods on the test-class
+     * and superclasses: exceptions thrown by previous steps are combined, if
      * necessary, with exceptions from AfterClass methods into a
-     * {@link MultipleFailureException}.
-     * </ul>
+     * {@link org.junit.runners.model.MultipleFailureException}.</li>
+     * </ol>
+     * </li>
+     * </ol>
      *
      * @return {@code Statement}
      */
     protected Statement classBlock(final RunNotifier notifier) {
         Statement statement = childrenInvoker(notifier);
-        statement = withBeforeClasses(statement);
-        statement = withAfterClasses(statement);
-        statement = withClassRules(statement);
+        if (!areAllChildrenIgnored()) {
+            statement = withBeforeClasses(statement);
+            statement = withAfterClasses(statement);
+            statement = withClassRules(statement);
+        }
         return statement;
     }
 
+    private boolean areAllChildrenIgnored() {
+        for (T child : getFilteredChildren()) {
+            if (!isIgnored(child)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * Returns a {@link Statement}: run all non-overridden {@code @BeforeClass} methods on this class
      * and superclasses before executing {@code statement}; if any throws an
      * Exception, stop execution and pass the exception on.
      */
     protected Statement withBeforeClasses(Statement statement) {
-        List<FrameworkMethod> befores = fTestClass
+        List<FrameworkMethod> befores = testClass
                 .getAnnotatedMethods(BeforeClass.class);
         return befores.isEmpty() ? statement :
                 new RunBefores(statement, befores, null);
@@ -181,10 +222,10 @@
      * and superclasses before executing {@code statement}; all AfterClass methods are
      * always executed: exceptions thrown by previous steps are combined, if
      * necessary, with exceptions from AfterClass methods into a
-     * {@link MultipleFailureException}.
+     * {@link org.junit.runners.model.MultipleFailureException}.
      */
     protected Statement withAfterClasses(Statement statement) {
-        List<FrameworkMethod> afters = fTestClass
+        List<FrameworkMethod> afters = testClass
                 .getAnnotatedMethods(AfterClass.class);
         return afters.isEmpty() ? statement :
                 new RunAfters(statement, afters, null);
@@ -210,10 +251,8 @@
      *         each method in the tested class.
      */
     protected List<TestRule> classRules() {
-        List<TestRule> result = fTestClass.getAnnotatedMethodValues(null, ClassRule.class, TestRule.class);
-
-        result.addAll(fTestClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class));
-
+        List<TestRule> result = testClass.getAnnotatedMethodValues(null, ClassRule.class, TestRule.class);
+        result.addAll(testClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class));
         return result;
     }
 
@@ -231,22 +270,37 @@
         };
     }
 
+    /**
+     * Evaluates whether a child is ignored. The default implementation always
+     * returns <code>false</code>.
+     * 
+     * <p>{@link BlockJUnit4ClassRunner}, for example, overrides this method to
+     * filter tests based on the {@link Ignore} annotation.
+     */
+    protected boolean isIgnored(T child) {
+        return false;
+    }
+
     private void runChildren(final RunNotifier notifier) {
-        for (final T each : getFilteredChildren()) {
-            fScheduler.schedule(new Runnable() {
-                public void run() {
-                    ParentRunner.this.runChild(each, notifier);
-                }
-            });
+        final RunnerScheduler currentScheduler = scheduler;
+        try {
+            for (final T each : getFilteredChildren()) {
+                currentScheduler.schedule(new Runnable() {
+                    public void run() {
+                        ParentRunner.this.runChild(each, notifier);
+                    }
+                });
+            }
+        } finally {
+            currentScheduler.finished();
         }
-        fScheduler.finished();
     }
 
     /**
      * Returns a name used to describe this Runner
      */
     protected String getName() {
-        return fTestClass.getName();
+        return testClass.getName();
     }
 
     //
@@ -257,7 +311,7 @@
      * Returns a {@link TestClass} object wrapping the class to be executed.
      */
     public final TestClass getTestClass() {
-        return fTestClass;
+        return testClass;
     }
 
     /**
@@ -283,7 +337,7 @@
      *         description.
      */
     protected Annotation[] getRunnerAnnotations() {
-        return fTestClass.getAnnotations();
+        return testClass.getAnnotations();
     }
 
     //
@@ -308,7 +362,7 @@
             Statement statement = classBlock(notifier);
             statement.evaluate();
         } catch (AssumptionViolatedException e) {
-            testNotifier.fireTestIgnored();
+            testNotifier.addFailedAssumption(e);
         } catch (StoppedByUserException e) {
             throw e;
         } catch (Throwable e) {
@@ -321,29 +375,36 @@
     //
 
     public void filter(Filter filter) throws NoTestsRemainException {
-        for (Iterator<T> iter = getFilteredChildren().iterator(); iter.hasNext(); ) {
-            T each = iter.next();
-            if (shouldRun(filter, each)) {
-                try {
-                    filter.apply(each);
-                } catch (NoTestsRemainException e) {
+        synchronized (childrenLock) {
+            List<T> children = new ArrayList<T>(getFilteredChildren());
+            for (Iterator<T> iter = children.iterator(); iter.hasNext(); ) {
+                T each = iter.next();
+                if (shouldRun(filter, each)) {
+                    try {
+                        filter.apply(each);
+                    } catch (NoTestsRemainException e) {
+                        iter.remove();
+                    }
+                } else {
                     iter.remove();
                 }
-            } else {
-                iter.remove();
             }
-        }
-        if (getFilteredChildren().isEmpty()) {
-            throw new NoTestsRemainException();
+            filteredChildren = Collections.unmodifiableCollection(children);
+            if (filteredChildren.isEmpty()) {
+                throw new NoTestsRemainException();
+            }
         }
     }
 
     public void sort(Sorter sorter) {
-        fSorter = sorter;
-        for (T each : getFilteredChildren()) {
-            sortChild(each);
+        synchronized (childrenLock) {
+            for (T each : getFilteredChildren()) {
+                sorter.apply(each);
+            }
+            List<T> sortedChildren = new ArrayList<T>(getFilteredChildren());
+            Collections.sort(sortedChildren, comparator(sorter));
+            filteredChildren = Collections.unmodifiableCollection(sortedChildren);
         }
-        Collections.sort(getFilteredChildren(), comparator());
     }
 
     //
@@ -358,25 +419,25 @@
         }
     }
 
-    private List<T> getFilteredChildren() {
-        if (fFilteredChildren == null) {
-            fFilteredChildren = new ArrayList<T>(getChildren());
+    private Collection<T> getFilteredChildren() {
+        if (filteredChildren == null) {
+            synchronized (childrenLock) {
+                if (filteredChildren == null) {
+                    filteredChildren = Collections.unmodifiableCollection(getChildren());
+                }
+            }
         }
-        return fFilteredChildren;
-    }
-
-    private void sortChild(T child) {
-        fSorter.apply(child);
+        return filteredChildren;
     }
 
     private boolean shouldRun(Filter filter, T each) {
         return filter.shouldRun(describeChild(each));
     }
 
-    private Comparator<? super T> comparator() {
+    private Comparator<? super T> comparator(final Sorter sorter) {
         return new Comparator<T>() {
             public int compare(T o1, T o2) {
-                return fSorter.compare(describeChild(o1), describeChild(o2));
+                return sorter.compare(describeChild(o1), describeChild(o2));
             }
         };
     }
@@ -386,6 +447,6 @@
      * of children.  Highly experimental feature that may change.
      */
     public void setScheduler(RunnerScheduler scheduler) {
-        this.fScheduler = scheduler;
+        this.scheduler = scheduler;
     }
 }
diff --git a/src/main/java/org/junit/runners/Suite.java b/src/main/java/org/junit/runners/Suite.java
index f5dd03f..6652bbc 100644
--- a/src/main/java/org/junit/runners/Suite.java
+++ b/src/main/java/org/junit/runners/Suite.java
@@ -5,6 +5,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.Collections;
 import java.util.List;
 
 import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
@@ -46,7 +47,7 @@
         /**
          * @return the classes to be run
          */
-        public Class<?>[] value();
+        Class<?>[] value();
     }
 
     private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError {
@@ -57,7 +58,7 @@
         return annotation.value();
     }
 
-    private final List<Runner> fRunners;
+    private final List<Runner> runners;
 
     /**
      * Called reflectively on classes annotated with <code>@RunWith(Suite.class)</code>
@@ -109,12 +110,12 @@
      */
     protected Suite(Class<?> klass, List<Runner> runners) throws InitializationError {
         super(klass);
-        fRunners = runners;
+        this.runners = Collections.unmodifiableList(runners);
     }
 
     @Override
     protected List<Runner> getChildren() {
-        return fRunners;
+        return runners;
     }
 
     @Override
diff --git a/src/main/java/org/junit/runners/model/Annotatable.java b/src/main/java/org/junit/runners/model/Annotatable.java
new file mode 100644
index 0000000..8eff6fd
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/Annotatable.java
@@ -0,0 +1,20 @@
+package org.junit.runners.model;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A model element that may have annotations.
+ * 
+ * @since 4.12
+ */
+public interface Annotatable {
+    /**
+     * Returns the model elements' annotations.
+     */
+    Annotation[] getAnnotations();
+
+    /**
+     * Returns the annotation on the model element of the given type, or @code{null}
+     */
+    <T extends Annotation> T getAnnotation(Class<T> annotationType);
+}
diff --git a/src/main/java/org/junit/runners/model/FrameworkField.java b/src/main/java/org/junit/runners/model/FrameworkField.java
index 105d195..945e389 100644
--- a/src/main/java/org/junit/runners/model/FrameworkField.java
+++ b/src/main/java/org/junit/runners/model/FrameworkField.java
@@ -2,7 +2,6 @@
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 
 import org.junit.runners.BlockJUnit4ClassRunner;
 
@@ -13,10 +12,14 @@
  * @since 4.7
  */
 public class FrameworkField extends FrameworkMember<FrameworkField> {
-    private final Field fField;
+    private final Field field;
 
     FrameworkField(Field field) {
-        fField = field;
+        if (field == null) {
+            throw new NullPointerException(
+                    "FrameworkField cannot be created without an underlying field.");
+        }
+        this.field = field;
     }
 
     @Override
@@ -24,15 +27,12 @@
         return getField().getName();
     }
 
-    @Override
     public Annotation[] getAnnotations() {
-        return fField.getAnnotations();
+        return field.getAnnotations();
     }
 
-    @Override
-    public boolean isPublic() {
-        int modifiers = fField.getModifiers();
-        return Modifier.isPublic(modifiers);
+    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+        return field.getAnnotation(annotationType);
     }
 
     @Override
@@ -41,16 +41,15 @@
     }
 
     @Override
-    public boolean isStatic() {
-        int modifiers = fField.getModifiers();
-        return Modifier.isStatic(modifiers);
+    protected int getModifiers() {
+        return field.getModifiers();
     }
 
     /**
      * @return the underlying java Field
      */
     public Field getField() {
-        return fField;
+        return field;
     }
 
     /**
@@ -59,13 +58,23 @@
      */
     @Override
     public Class<?> getType() {
-        return fField.getType();
+        return field.getType();
+    }
+    
+    @Override
+    public Class<?> getDeclaringClass() {
+        return field.getDeclaringClass();
     }
 
     /**
      * Attempts to retrieve the value of this field on {@code target}
      */
     public Object get(Object target) throws IllegalArgumentException, IllegalAccessException {
-        return fField.get(target);
+        return field.get(target);
+    }
+
+    @Override
+    public String toString() {
+        return field.toString();
     }
 }
diff --git a/src/main/java/org/junit/runners/model/FrameworkMember.java b/src/main/java/org/junit/runners/model/FrameworkMember.java
index 71a8a1f..724f096 100644
--- a/src/main/java/org/junit/runners/model/FrameworkMember.java
+++ b/src/main/java/org/junit/runners/model/FrameworkMember.java
@@ -1,6 +1,6 @@
 package org.junit.runners.model;
 
-import java.lang.annotation.Annotation;
+import java.lang.reflect.Modifier;
 import java.util.List;
 
 /**
@@ -8,12 +8,8 @@
  *
  * @since 4.7
  */
-public abstract class FrameworkMember<T extends FrameworkMember<T>> {
-    /**
-     * Returns the annotations on this method
-     */
-    abstract Annotation[] getAnnotations();
-
+public abstract class FrameworkMember<T extends FrameworkMember<T>> implements
+        Annotatable {
     abstract boolean isShadowedBy(T otherMember);
 
     boolean isShadowedBy(List<T> members) {
@@ -25,11 +21,25 @@
         return false;
     }
 
-    public abstract boolean isPublic();
+    protected abstract int getModifiers();
 
-    public abstract boolean isStatic();
+    /**
+     * Returns true if this member is static, false if not.
+     */
+    public boolean isStatic() {
+        return Modifier.isStatic(getModifiers());
+    }
+
+    /**
+     * Returns true if this member is public, false if not.
+     */
+    public boolean isPublic() {
+        return Modifier.isPublic(getModifiers());
+    }
 
     public abstract String getName();
 
     public abstract Class<?> getType();
+
+    public abstract Class<?> getDeclaringClass();
 }
diff --git a/src/main/java/org/junit/runners/model/FrameworkMethod.java b/src/main/java/org/junit/runners/model/FrameworkMethod.java
index 7ae6da0..3580052 100644
--- a/src/main/java/org/junit/runners/model/FrameworkMethod.java
+++ b/src/main/java/org/junit/runners/model/FrameworkMethod.java
@@ -3,7 +3,6 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.util.List;
 
@@ -18,20 +17,24 @@
  * @since 4.5
  */
 public class FrameworkMethod extends FrameworkMember<FrameworkMethod> {
-    final Method fMethod;
+    private final Method method;
 
     /**
      * Returns a new {@code FrameworkMethod} for {@code method}
      */
     public FrameworkMethod(Method method) {
-        fMethod = method;
+        if (method == null) {
+            throw new NullPointerException(
+                    "FrameworkMethod cannot be created without an underlying method.");
+        }
+        this.method = method;
     }
 
     /**
      * Returns the underlying Java method
      */
     public Method getMethod() {
-        return fMethod;
+        return method;
     }
 
     /**
@@ -44,7 +47,7 @@
         return new ReflectiveCallable() {
             @Override
             protected Object runReflectiveCall() throws Throwable {
-                return fMethod.invoke(target, params);
+                return method.invoke(target, params);
             }
         }.run();
     }
@@ -54,7 +57,7 @@
      */
     @Override
     public String getName() {
-        return fMethod.getName();
+        return method.getName();
     }
 
     /**
@@ -65,11 +68,12 @@
      * <li>returns something other than void, or
      * <li>is static (given {@code isStatic is false}), or
      * <li>is not static (given {@code isStatic is true}).
+     * </ul>
      */
     public void validatePublicVoidNoArg(boolean isStatic, List<Throwable> errors) {
         validatePublicVoid(isStatic, errors);
-        if (fMethod.getParameterTypes().length != 0) {
-            errors.add(new Exception("Method " + fMethod.getName() + " should have no parameters"));
+        if (method.getParameterTypes().length != 0) {
+            errors.add(new Exception("Method " + method.getName() + " should have no parameters"));
         }
     }
 
@@ -81,44 +85,31 @@
      * <li>returns something other than void, or
      * <li>is static (given {@code isStatic is false}), or
      * <li>is not static (given {@code isStatic is true}).
+     * </ul>
      */
     public void validatePublicVoid(boolean isStatic, List<Throwable> errors) {
-        if (Modifier.isStatic(fMethod.getModifiers()) != isStatic) {
+        if (isStatic() != isStatic) {
             String state = isStatic ? "should" : "should not";
-            errors.add(new Exception("Method " + fMethod.getName() + "() " + state + " be static"));
+            errors.add(new Exception("Method " + method.getName() + "() " + state + " be static"));
         }
-        if (!Modifier.isPublic(fMethod.getDeclaringClass().getModifiers())) {
-            errors.add(new Exception("Class " + fMethod.getDeclaringClass().getName() + " should be public"));
+        if (!isPublic()) {
+            errors.add(new Exception("Method " + method.getName() + "() should be public"));
         }
-        if (!Modifier.isPublic(fMethod.getModifiers())) {
-            errors.add(new Exception("Method " + fMethod.getName() + "() should be public"));
-        }
-        if (fMethod.getReturnType() != Void.TYPE) {
-            errors.add(new Exception("Method " + fMethod.getName() + "() should be void"));
+        if (method.getReturnType() != Void.TYPE) {
+            errors.add(new Exception("Method " + method.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());
+    protected int getModifiers() {
+        return method.getModifiers();
     }
 
     /**
      * Returns the return type of the method
      */
     public Class<?> getReturnType() {
-        return fMethod.getReturnType();
+        return method.getReturnType();
     }
 
     /**
@@ -129,8 +120,16 @@
         return getReturnType();
     }
 
+    /**
+     * Returns the class where the method is actually declared
+     */
+    @Override
+    public Class<?> getDeclaringClass() {
+        return method.getDeclaringClass();
+    }
+
     public void validateNoTypeParametersOnArgs(List<Throwable> errors) {
-        new NoGenericTypeParametersValidator(fMethod).validate(errors);
+        new NoGenericTypeParametersValidator(method).validate(errors);
     }
 
     @Override
@@ -154,12 +153,12 @@
         if (!FrameworkMethod.class.isInstance(obj)) {
             return false;
         }
-        return ((FrameworkMethod) obj).fMethod.equals(fMethod);
+        return ((FrameworkMethod) obj).method.equals(method);
     }
 
     @Override
     public int hashCode() {
-        return fMethod.hashCode();
+        return method.hashCode();
     }
 
     /**
@@ -174,19 +173,18 @@
     @Deprecated
     public boolean producesType(Type type) {
         return getParameterTypes().length == 0 && type instanceof Class<?>
-                && ((Class<?>) type).isAssignableFrom(fMethod.getReturnType());
+                && ((Class<?>) type).isAssignableFrom(method.getReturnType());
     }
 
     private Class<?>[] getParameterTypes() {
-        return fMethod.getParameterTypes();
+        return method.getParameterTypes();
     }
 
     /**
      * Returns the annotations on this method
      */
-    @Override
     public Annotation[] getAnnotations() {
-        return fMethod.getAnnotations();
+        return method.getAnnotations();
     }
 
     /**
@@ -194,6 +192,11 @@
      * one exists.
      */
     public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
-        return fMethod.getAnnotation(annotationType);
+        return method.getAnnotation(annotationType);
+    }
+
+    @Override
+    public String toString() {
+        return method.toString();
     }
 }
diff --git a/src/main/java/org/junit/runners/model/InitializationError.java b/src/main/java/org/junit/runners/model/InitializationError.java
index f3fb184..841b565 100644
--- a/src/main/java/org/junit/runners/model/InitializationError.java
+++ b/src/main/java/org/junit/runners/model/InitializationError.java
@@ -10,6 +10,12 @@
  */
 public class InitializationError extends Exception {
     private static final long serialVersionUID = 1L;
+
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
     private final List<Throwable> fErrors;
 
     /**
@@ -17,7 +23,7 @@
      * errors {@code errors} as causes
      */
     public InitializationError(List<Throwable> errors) {
-        fErrors = errors;
+        this.fErrors = errors;
     }
 
     public InitializationError(Throwable error) {
diff --git a/src/main/java/org/junit/runners/model/MultipleFailureException.java b/src/main/java/org/junit/runners/model/MultipleFailureException.java
index 8f82edc..325c645 100644
--- a/src/main/java/org/junit/runners/model/MultipleFailureException.java
+++ b/src/main/java/org/junit/runners/model/MultipleFailureException.java
@@ -1,11 +1,11 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
-
 package org.junit.runners.model;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.junit.internal.Throwables;
+
 /**
  * Collects multiple {@code Throwable}s into one exception.
  *
@@ -14,10 +14,15 @@
 public class MultipleFailureException extends Exception {
     private static final long serialVersionUID = 1L;
 
+    /*
+     * We have to use the f prefix until the next major release to ensure
+     * serialization compatibility. 
+     * See https://github.com/junit-team/junit/issues/976
+     */
     private final List<Throwable> fErrors;
 
     public MultipleFailureException(List<Throwable> errors) {
-        fErrors = new ArrayList<Throwable>(errors);
+        this.fErrors = new ArrayList<Throwable>(errors);
     }
 
     public List<Throwable> getFailures() {
@@ -41,15 +46,15 @@
      * (if there is only one element).
      *
      * @param errors list to check
-     * @throws Throwable if the list is not empty
+     * @throws Exception or Error if the list is not empty
      */
     @SuppressWarnings("deprecation")
-    public static void assertEmpty(List<Throwable> errors) throws Throwable {
+    public static void assertEmpty(List<Throwable> errors) throws Exception {
         if (errors.isEmpty()) {
             return;
         }
         if (errors.size() == 1) {
-            throw errors.get(0);
+            throw Throwables.rethrowAsException(errors.get(0));
         }
 
         /*
diff --git a/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java b/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
index d73c1a8..386b7ff 100644
--- a/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
+++ b/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
@@ -9,21 +9,21 @@
 import java.util.List;
 
 class NoGenericTypeParametersValidator {
-    private final Method fMethod;
+    private final Method method;
 
     NoGenericTypeParametersValidator(Method method) {
-        this.fMethod = method;
+        this.method = method;
     }
 
     void validate(List<Throwable> errors) {
-        for (Type each : fMethod.getGenericParameterTypes()) {
+        for (Type each : method.getGenericParameterTypes()) {
             validateNoTypeParameterOnType(each, errors);
         }
     }
 
     private void validateNoTypeParameterOnType(Type type, List<Throwable> errors) {
         if (type instanceof TypeVariable<?>) {
-            errors.add(new Exception("Method " + fMethod.getName()
+            errors.add(new Exception("Method " + method.getName()
                     + "() contains unresolved type variable " + type));
         } else if (type instanceof ParameterizedType) {
             validateNoTypeParameterOnParameterizedType((ParameterizedType) type, errors);
diff --git a/src/main/java/org/junit/runners/model/RunnerBuilder.java b/src/main/java/org/junit/runners/model/RunnerBuilder.java
index 7d3eee3..42da6f3 100644
--- a/src/main/java/org/junit/runners/model/RunnerBuilder.java
+++ b/src/main/java/org/junit/runners/model/RunnerBuilder.java
@@ -96,7 +96,7 @@
     }
 
     private List<Runner> runners(Class<?>[] children) {
-        ArrayList<Runner> runners = new ArrayList<Runner>();
+        List<Runner> runners = new ArrayList<Runner>();
         for (Class<?> each : children) {
             Runner childRunner = safeRunnerForClass(each);
             if (childRunner != null) {
diff --git a/src/main/java/org/junit/runners/model/TestClass.java b/src/main/java/org/junit/runners/model/TestClass.java
old mode 100644
new mode 100755
index 93209ea..679c642
--- a/src/main/java/org/junit/runners/model/TestClass.java
+++ b/src/main/java/org/junit/runners/model/TestClass.java
@@ -1,15 +1,22 @@
 package org.junit.runners.model;
 
 import static java.lang.reflect.Modifier.isStatic;
+import static org.junit.internal.MethodSorter.NAME_ASCENDING;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -21,43 +28,62 @@
  *
  * @since 4.5
  */
-public class TestClass {
-    private final Class<?> fClass;
+public class TestClass implements Annotatable {
+    private static final FieldComparator FIELD_COMPARATOR = new FieldComparator();
+    private static final MethodComparator METHOD_COMPARATOR = new MethodComparator();
 
-    private Map<Class<?>, List<FrameworkMethod>> fMethodsForAnnotations = new HashMap<Class<?>, List<FrameworkMethod>>();
-
-    private Map<Class<?>, List<FrameworkField>> fFieldsForAnnotations = new HashMap<Class<?>, List<FrameworkField>>();
+    private final Class<?> clazz;
+    private final Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations;
+    private final Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations;
 
     /**
-     * Creates a {@code TestClass} wrapping {@code klass}. Each time this
+     * Creates a {@code TestClass} wrapping {@code clazz}. Each time this
      * constructor executes, the class is scanned for annotations, which can be
      * an expensive process (we hope in future JDK's it will not be.) Therefore,
      * try to share instances of {@code TestClass} where possible.
      */
-    public TestClass(Class<?> klass) {
-        fClass = klass;
-        if (klass != null && klass.getConstructors().length > 1) {
+    public TestClass(Class<?> clazz) {
+        this.clazz = clazz;
+        if (clazz != null && clazz.getConstructors().length > 1) {
             throw new IllegalArgumentException(
                     "Test class can only have one constructor");
         }
 
-        for (Class<?> eachClass : getSuperClasses(fClass)) {
+        Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations =
+                new LinkedHashMap<Class<? extends Annotation>, List<FrameworkMethod>>();
+        Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations =
+                new LinkedHashMap<Class<? extends Annotation>, List<FrameworkField>>();
+
+        scanAnnotatedMembers(methodsForAnnotations, fieldsForAnnotations);
+
+        this.methodsForAnnotations = makeDeeplyUnmodifiable(methodsForAnnotations);
+        this.fieldsForAnnotations = makeDeeplyUnmodifiable(fieldsForAnnotations);
+    }
+
+    protected void scanAnnotatedMembers(Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations, Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations) {
+        for (Class<?> eachClass : getSuperClasses(clazz)) {
             for (Method eachMethod : MethodSorter.getDeclaredMethods(eachClass)) {
-                addToAnnotationLists(new FrameworkMethod(eachMethod),
-                        fMethodsForAnnotations);
+                addToAnnotationLists(new FrameworkMethod(eachMethod), methodsForAnnotations);
             }
-            for (Field eachField : eachClass.getDeclaredFields()) {
-                addToAnnotationLists(new FrameworkField(eachField),
-                        fFieldsForAnnotations);
+            // ensuring fields are sorted to make sure that entries are inserted
+            // and read from fieldForAnnotations in a deterministic order
+            for (Field eachField : getSortedDeclaredFields(eachClass)) {
+                addToAnnotationLists(new FrameworkField(eachField), fieldsForAnnotations);
             }
         }
     }
 
-    private <T extends FrameworkMember<T>> void addToAnnotationLists(T member,
-            Map<Class<?>, List<T>> map) {
+    private static Field[] getSortedDeclaredFields(Class<?> clazz) {
+        Field[] declaredFields = clazz.getDeclaredFields();
+        Arrays.sort(declaredFields, FIELD_COMPARATOR);
+        return declaredFields;
+    }
+
+    protected static <T extends FrameworkMember<T>> void addToAnnotationLists(T member,
+            Map<Class<? extends Annotation>, List<T>> map) {
         for (Annotation each : member.getAnnotations()) {
             Class<? extends Annotation> type = each.annotationType();
-            List<T> members = getAnnotatedMembers(map, type);
+            List<T> members = getAnnotatedMembers(map, type, true);
             if (member.isShadowedBy(members)) {
                 return;
             }
@@ -69,13 +95,45 @@
         }
     }
 
+    private static <T extends FrameworkMember<T>> Map<Class<? extends Annotation>, List<T>>
+            makeDeeplyUnmodifiable(Map<Class<? extends Annotation>, List<T>> source) {
+        Map<Class<? extends Annotation>, List<T>> copy =
+                new LinkedHashMap<Class<? extends Annotation>, List<T>>();
+        for (Map.Entry<Class<? extends Annotation>, List<T>> entry : source.entrySet()) {
+            copy.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
+        }
+        return Collections.unmodifiableMap(copy);
+    }
+
+    /**
+     * Returns, efficiently, all the non-overridden methods in this class and
+     * its superclasses that are annotated}.
+     * 
+     * @since 4.12
+     */
+    public List<FrameworkMethod> getAnnotatedMethods() {
+        List<FrameworkMethod> methods = collectValues(methodsForAnnotations);
+        Collections.sort(methods, METHOD_COMPARATOR);
+        return methods;
+    }
+
     /**
      * Returns, efficiently, all the non-overridden methods in this class and
      * its superclasses that are annotated with {@code annotationClass}.
      */
     public List<FrameworkMethod> getAnnotatedMethods(
             Class<? extends Annotation> annotationClass) {
-        return getAnnotatedMembers(fMethodsForAnnotations, annotationClass);
+        return Collections.unmodifiableList(getAnnotatedMembers(methodsForAnnotations, annotationClass, false));
+    }
+
+    /**
+     * Returns, efficiently, all the non-overridden fields in this class and its
+     * superclasses that are annotated.
+     * 
+     * @since 4.12
+     */
+    public List<FrameworkField> getAnnotatedFields() {
+        return collectValues(fieldsForAnnotations);
     }
 
     /**
@@ -84,24 +142,33 @@
      */
     public List<FrameworkField> getAnnotatedFields(
             Class<? extends Annotation> annotationClass) {
-        return getAnnotatedMembers(fFieldsForAnnotations, annotationClass);
+        return Collections.unmodifiableList(getAnnotatedMembers(fieldsForAnnotations, annotationClass, false));
     }
 
-    private <T> List<T> getAnnotatedMembers(Map<Class<?>, List<T>> map,
-            Class<? extends Annotation> type) {
-        if (!map.containsKey(type)) {
+    private <T> List<T> collectValues(Map<?, List<T>> map) {
+        Set<T> values = new LinkedHashSet<T>();
+        for (List<T> additionalValues : map.values()) {
+            values.addAll(additionalValues);
+        }
+        return new ArrayList<T>(values);
+    }
+
+    private static <T> List<T> getAnnotatedMembers(Map<Class<? extends Annotation>, List<T>> map,
+            Class<? extends Annotation> type, boolean fillIfAbsent) {
+        if (!map.containsKey(type) && fillIfAbsent) {
             map.put(type, new ArrayList<T>());
         }
-        return map.get(type);
+        List<T> members = map.get(type);
+        return members == null ? Collections.<T>emptyList() : members;
     }
 
-    private boolean runsTopToBottom(Class<? extends Annotation> annotation) {
+    private static boolean runsTopToBottom(Class<? extends Annotation> annotation) {
         return annotation.equals(Before.class)
                 || annotation.equals(BeforeClass.class);
     }
 
-    private List<Class<?>> getSuperClasses(Class<?> testClass) {
-        ArrayList<Class<?>> results = new ArrayList<Class<?>>();
+    private static List<Class<?>> getSuperClasses(Class<?> testClass) {
+        List<Class<?>> results = new ArrayList<Class<?>>();
         Class<?> current = testClass;
         while (current != null) {
             results.add(current);
@@ -114,17 +181,17 @@
      * Returns the underlying Java class.
      */
     public Class<?> getJavaClass() {
-        return fClass;
+        return clazz;
     }
 
     /**
      * Returns the class's name.
      */
     public String getName() {
-        if (fClass == null) {
+        if (clazz == null) {
             return "null";
         }
-        return fClass.getName();
+        return clazz.getName();
     }
 
     /**
@@ -133,7 +200,7 @@
      */
 
     public Constructor<?> getOnlyConstructor() {
-        Constructor<?>[] constructors = fClass.getConstructors();
+        Constructor<?>[] constructors = clazz.getConstructors();
         Assert.assertEquals(1, constructors.length);
         return constructors[0];
     }
@@ -142,10 +209,17 @@
      * Returns the annotations on this class
      */
     public Annotation[] getAnnotations() {
-        if (fClass == null) {
+        if (clazz == null) {
             return new Annotation[0];
         }
-        return fClass.getAnnotations();
+        return clazz.getAnnotations();
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+        if (clazz == null) {
+            return null;
+        }
+        return clazz.getAnnotation(annotationType);
     }
 
     public <T> List<T> getAnnotatedFieldValues(Object test,
@@ -170,8 +244,16 @@
         List<T> results = new ArrayList<T>();
         for (FrameworkMethod each : getAnnotatedMethods(annotationClass)) {
             try {
-                Object fieldValue = each.invokeExplosively(test, new Object[]{});
-                if (valueClass.isInstance(fieldValue)) {
+                /*
+                 * A method annotated with @Rule may return a @TestRule or a @MethodRule,
+                 * we cannot call the method to check whether the return type matches our
+                 * expectation i.e. subclass of valueClass. If we do that then the method 
+                 * will be invoked twice and we do not want to do that. So we first check
+                 * whether return type matches our expectation and only then call the method
+                 * to fetch the MethodRule
+                 */
+                if (valueClass.isAssignableFrom(each.getReturnType())) {
+                    Object fieldValue = each.invokeExplosively(test);
                     results.add(valueClass.cast(fieldValue));
                 }
             } catch (Throwable e) {
@@ -182,7 +264,50 @@
         return results;
     }
 
+    public boolean isPublic() {
+        return Modifier.isPublic(clazz.getModifiers());
+    }
+
     public boolean isANonStaticInnerClass() {
-        return fClass.isMemberClass() && !isStatic(fClass.getModifiers());
+        return clazz.isMemberClass() && !isStatic(clazz.getModifiers());
+    }
+
+    @Override
+    public int hashCode() {
+        return (clazz == null) ? 0 : clazz.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        TestClass other = (TestClass) obj;
+        return clazz == other.clazz;
+    }
+
+    /**
+     * Compares two fields by its name.
+     */
+    private static class FieldComparator implements Comparator<Field> {
+        public int compare(Field left, Field right) {
+            return left.getName().compareTo(right.getName());
+        }
+    }
+
+    /**
+     * Compares two methods by its name.
+     */
+    private static class MethodComparator implements
+            Comparator<FrameworkMethod> {
+        public int compare(FrameworkMethod left, FrameworkMethod right) {
+            return NAME_ASCENDING.compare(left.getMethod(), right.getMethod());
+        }
     }
 }
diff --git a/src/main/java/org/junit/runners/model/TestTimedOutException.java b/src/main/java/org/junit/runners/model/TestTimedOutException.java
new file mode 100644
index 0000000..60e1a8a
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/TestTimedOutException.java
@@ -0,0 +1,44 @@
+package org.junit.runners.model;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Exception thrown when a test fails on timeout.
+ * 
+ * @since 4.12
+ * 
+ */
+public class TestTimedOutException extends Exception {
+
+    private static final long serialVersionUID = 31935685163547539L;
+
+    private final TimeUnit timeUnit;
+    private final long timeout;
+
+    /**
+     * Creates exception with a standard message "test timed out after [timeout] [timeUnit]"
+     * 
+     * @param timeout the amount of time passed before the test was interrupted
+     * @param timeUnit the time unit for the timeout value
+     */
+    public TestTimedOutException(long timeout, TimeUnit timeUnit) {
+        super(String.format("test timed out after %d %s", 
+                timeout, timeUnit.name().toLowerCase()));
+        this.timeUnit = timeUnit;
+        this.timeout = timeout;
+    }
+
+    /**
+     * Gets the time passed before the test was interrupted
+     */
+    public long getTimeout() {
+        return timeout;
+    }
+
+    /**
+     * Gets the time unit for the timeout value
+     */
+    public TimeUnit getTimeUnit() {
+        return timeUnit;
+    }
+}
diff --git a/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java b/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java
new file mode 100644
index 0000000..ffed4be
--- /dev/null
+++ b/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java
@@ -0,0 +1,170 @@
+package org.junit.runners.parameterized;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.List;
+
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.model.FrameworkField;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+/**
+ * A {@link BlockJUnit4ClassRunner} with parameters support. Parameters can be
+ * injected via constructor or into annotated fields.
+ */
+public class BlockJUnit4ClassRunnerWithParameters extends
+        BlockJUnit4ClassRunner {
+    private enum InjectionType {
+        CONSTRUCTOR, FIELD
+    }
+
+    private final Object[] parameters;
+
+    private final String name;
+
+    public BlockJUnit4ClassRunnerWithParameters(TestWithParameters test)
+            throws InitializationError {
+        super(test.getTestClass().getJavaClass());
+        parameters = test.getParameters().toArray(
+                new Object[test.getParameters().size()]);
+        name = test.getName();
+    }
+
+    @Override
+    public Object createTest() throws Exception {
+        InjectionType injectionType = getInjectionType();
+        switch (injectionType) {
+            case CONSTRUCTOR:
+                return createTestUsingConstructorInjection();
+            case FIELD:
+                return createTestUsingFieldInjection();
+            default:
+                throw new IllegalStateException("The injection type "
+                        + injectionType + " is not supported.");
+        }
+    }
+
+    private Object createTestUsingConstructorInjection() throws Exception {
+        return getTestClass().getOnlyConstructor().newInstance(parameters);
+    }
+
+    private Object createTestUsingFieldInjection() throws Exception {
+        List<FrameworkField> annotatedFieldsByParameter = getAnnotatedFieldsByParameter();
+        if (annotatedFieldsByParameter.size() != parameters.length) {
+            throw new Exception(
+                    "Wrong number of parameters and @Parameter fields."
+                            + " @Parameter fields counted: "
+                            + annotatedFieldsByParameter.size()
+                            + ", available parameters: " + parameters.length
+                            + ".");
+        }
+        Object testClassInstance = getTestClass().getJavaClass().newInstance();
+        for (FrameworkField each : annotatedFieldsByParameter) {
+            Field field = each.getField();
+            Parameter annotation = field.getAnnotation(Parameter.class);
+            int index = annotation.value();
+            try {
+                field.set(testClassInstance, parameters[index]);
+            } catch (IllegalArgumentException iare) {
+                throw new Exception(getTestClass().getName()
+                        + ": Trying to set " + field.getName()
+                        + " with the value " + parameters[index]
+                        + " that is not the right type ("
+                        + parameters[index].getClass().getSimpleName()
+                        + " instead of " + field.getType().getSimpleName()
+                        + ").", iare);
+            }
+        }
+        return testClassInstance;
+    }
+
+    @Override
+    protected String getName() {
+        return name;
+    }
+
+    @Override
+    protected String testName(FrameworkMethod method) {
+        return method.getName() + getName();
+    }
+
+    @Override
+    protected void validateConstructor(List<Throwable> errors) {
+        validateOnlyOneConstructor(errors);
+        if (getInjectionType() != InjectionType.CONSTRUCTOR) {
+            validateZeroArgConstructor(errors);
+        }
+    }
+
+    @Override
+    protected void validateFields(List<Throwable> errors) {
+        super.validateFields(errors);
+        if (getInjectionType() == InjectionType.FIELD) {
+            List<FrameworkField> annotatedFieldsByParameter = getAnnotatedFieldsByParameter();
+            int[] usedIndices = new int[annotatedFieldsByParameter.size()];
+            for (FrameworkField each : annotatedFieldsByParameter) {
+                int index = each.getField().getAnnotation(Parameter.class)
+                        .value();
+                if (index < 0 || index > annotatedFieldsByParameter.size() - 1) {
+                    errors.add(new Exception("Invalid @Parameter value: "
+                            + index + ". @Parameter fields counted: "
+                            + annotatedFieldsByParameter.size()
+                            + ". Please use an index between 0 and "
+                            + (annotatedFieldsByParameter.size() - 1) + "."));
+                } else {
+                    usedIndices[index]++;
+                }
+            }
+            for (int index = 0; index < usedIndices.length; index++) {
+                int numberOfUse = usedIndices[index];
+                if (numberOfUse == 0) {
+                    errors.add(new Exception("@Parameter(" + index
+                            + ") is never used."));
+                } else if (numberOfUse > 1) {
+                    errors.add(new Exception("@Parameter(" + index
+                            + ") is used more than once (" + numberOfUse + ")."));
+                }
+            }
+        }
+    }
+
+    @Override
+    protected Statement classBlock(RunNotifier notifier) {
+        return childrenInvoker(notifier);
+    }
+
+    @Override
+    protected Annotation[] getRunnerAnnotations() {
+        Annotation[] allAnnotations = super.getRunnerAnnotations();
+        Annotation[] annotationsWithoutRunWith = new Annotation[allAnnotations.length - 1];
+        int i = 0;
+        for (Annotation annotation: allAnnotations) {
+            if (!annotation.annotationType().equals(RunWith.class)) {
+                annotationsWithoutRunWith[i] = annotation;
+                ++i;
+            }
+        }
+        return annotationsWithoutRunWith;
+    }
+
+    private List<FrameworkField> getAnnotatedFieldsByParameter() {
+        return getTestClass().getAnnotatedFields(Parameter.class);
+    }
+
+    private InjectionType getInjectionType() {
+        if (fieldsAreAnnotated()) {
+            return InjectionType.FIELD;
+        } else {
+            return InjectionType.CONSTRUCTOR;
+        }
+    }
+
+    private boolean fieldsAreAnnotated() {
+        return !getAnnotatedFieldsByParameter().isEmpty();
+    }
+}
diff --git a/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersFactory.java b/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersFactory.java
new file mode 100644
index 0000000..ae49ef4
--- /dev/null
+++ b/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersFactory.java
@@ -0,0 +1,18 @@
+package org.junit.runners.parameterized;
+
+import org.junit.runner.Runner;
+import org.junit.runners.model.InitializationError;
+
+/**
+ * A {@link ParametersRunnerFactory} that creates
+ * {@link BlockJUnit4ClassRunnerWithParameters}.
+ * 
+ * @since 4.12
+ */
+public class BlockJUnit4ClassRunnerWithParametersFactory implements
+        ParametersRunnerFactory {
+    public Runner createRunnerForTestWithParameters(TestWithParameters test)
+            throws InitializationError {
+        return new BlockJUnit4ClassRunnerWithParameters(test);
+    }
+}
diff --git a/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java b/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java
new file mode 100644
index 0000000..8123e83
--- /dev/null
+++ b/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java
@@ -0,0 +1,21 @@
+package org.junit.runners.parameterized;
+
+import org.junit.runner.Runner;
+import org.junit.runners.model.InitializationError;
+
+/**
+ * A {@code ParametersRunnerFactory} creates a runner for a single
+ * {@link TestWithParameters}.
+ * 
+ * @since 4.12
+ */
+public interface ParametersRunnerFactory {
+    /**
+     * Returns a runner for the specified {@link TestWithParameters}.
+     * 
+     * @throws InitializationError
+     *             if the runner could not be created.
+     */
+    Runner createRunnerForTestWithParameters(TestWithParameters test)
+            throws InitializationError;
+}
diff --git a/src/main/java/org/junit/runners/parameterized/TestWithParameters.java b/src/main/java/org/junit/runners/parameterized/TestWithParameters.java
new file mode 100644
index 0000000..1b86644
--- /dev/null
+++ b/src/main/java/org/junit/runners/parameterized/TestWithParameters.java
@@ -0,0 +1,82 @@
+package org.junit.runners.parameterized;
+
+import static java.util.Collections.unmodifiableList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.runners.model.TestClass;
+
+/**
+ * A {@code TestWithParameters} keeps the data together that are needed for
+ * creating a runner for a single data set of a parameterized test. It has a
+ * name, the test class and a list of parameters.
+ * 
+ * @since 4.12
+ */
+public class TestWithParameters {
+    private final String name;
+
+    private final TestClass testClass;
+
+    private final List<Object> parameters;
+
+    public TestWithParameters(String name, TestClass testClass,
+            List<Object> parameters) {
+        notNull(name, "The name is missing.");
+        notNull(testClass, "The test class is missing.");
+        notNull(parameters, "The parameters are missing.");
+        this.name = name;
+        this.testClass = testClass;
+        this.parameters = unmodifiableList(new ArrayList<Object>(parameters));
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public TestClass getTestClass() {
+        return testClass;
+    }
+
+    public List<Object> getParameters() {
+        return parameters;
+    }
+
+    @Override
+    public int hashCode() {
+        int prime = 14747;
+        int result = prime + name.hashCode();
+        result = prime * result + testClass.hashCode();
+        return prime * result + parameters.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        TestWithParameters other = (TestWithParameters) obj;
+        return name.equals(other.name)
+                && parameters.equals(other.parameters)
+                && testClass.equals(other.testClass);
+    }
+
+    @Override
+    public String toString() {
+        return testClass.getName() + " '" + name + "' with parameters "
+                + parameters;
+    }
+
+    private static void notNull(Object value, String message) {
+        if (value == null) {
+            throw new NullPointerException(message);
+        }
+    }
+}
diff --git a/src/main/java/org/junit/validator/AnnotationValidator.java b/src/main/java/org/junit/validator/AnnotationValidator.java
new file mode 100644
index 0000000..8a53adf
--- /dev/null
+++ b/src/main/java/org/junit/validator/AnnotationValidator.java
@@ -0,0 +1,60 @@
+package org.junit.validator;
+
+import org.junit.runners.model.FrameworkField;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.TestClass;
+
+import static java.util.Collections.emptyList;
+
+import java.util.List;
+
+/**
+ * Validates annotations on classes and methods. To be validated,
+ * an annotation should be annotated with {@link ValidateWith}
+ *
+ * Instances of this class are shared by multiple test runners, so they should
+ * be immutable and thread-safe.
+ *
+ * @since 4.12
+ */
+public abstract class AnnotationValidator {
+
+    private static final List<Exception> NO_VALIDATION_ERRORS = emptyList();
+
+    /**
+     * Validates annotation on the given class.
+     *
+     * @param testClass that is being validated
+     * @return A list of exceptions. Default behavior is to return an empty list.
+     *
+     * @since 4.12
+     */
+    public List<Exception> validateAnnotatedClass(TestClass testClass) {
+        return NO_VALIDATION_ERRORS;
+    }
+
+    /**
+     * Validates annotation on the given field.
+     *
+     * @param field that is being validated
+     * @return A list of exceptions. Default behavior is to return an empty list.
+     *
+     * @since 4.12
+     */
+    public List<Exception> validateAnnotatedField(FrameworkField field) {
+        return NO_VALIDATION_ERRORS;
+
+    }
+
+    /**
+     * Validates annotation on the given method.
+     *
+     * @param method that is being validated
+     * @return A list of exceptions. Default behavior is to return an empty list.
+     *
+     * @since 4.12
+     */
+    public List<Exception> validateAnnotatedMethod(FrameworkMethod method) {
+        return NO_VALIDATION_ERRORS;
+    }
+}
diff --git a/src/main/java/org/junit/validator/AnnotationValidatorFactory.java b/src/main/java/org/junit/validator/AnnotationValidatorFactory.java
new file mode 100644
index 0000000..fb2460d
--- /dev/null
+++ b/src/main/java/org/junit/validator/AnnotationValidatorFactory.java
@@ -0,0 +1,39 @@
+package org.junit.validator;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Creates instances of Annotation Validators.
+ *
+ * @since 4.12
+ */
+public class AnnotationValidatorFactory {
+    private static final ConcurrentHashMap<ValidateWith, AnnotationValidator> VALIDATORS_FOR_ANNOTATION_TYPES =
+            new ConcurrentHashMap<ValidateWith, AnnotationValidator>();
+
+    /**
+     * Creates the AnnotationValidator specified by the value in
+     * {@link org.junit.validator.ValidateWith}. Instances are
+     * cached.
+     *
+     * @return An instance of the AnnotationValidator.
+     *
+     * @since 4.12
+     */
+    public AnnotationValidator createAnnotationValidator(ValidateWith validateWithAnnotation) {
+        AnnotationValidator validator = VALIDATORS_FOR_ANNOTATION_TYPES.get(validateWithAnnotation);
+        if (validator != null) {
+            return validator;
+        }
+
+        Class<? extends AnnotationValidator> clazz = validateWithAnnotation.value();
+        try {
+            AnnotationValidator annotationValidator = clazz.newInstance();
+            VALIDATORS_FOR_ANNOTATION_TYPES.putIfAbsent(validateWithAnnotation, annotationValidator);
+            return VALIDATORS_FOR_ANNOTATION_TYPES.get(validateWithAnnotation);
+        } catch (Exception e) {
+            throw new RuntimeException("Exception received when creating AnnotationValidator class " + clazz.getName(), e);
+        }
+    }
+
+}
diff --git a/src/main/java/org/junit/validator/AnnotationsValidator.java b/src/main/java/org/junit/validator/AnnotationsValidator.java
new file mode 100644
index 0000000..44d99d2
--- /dev/null
+++ b/src/main/java/org/junit/validator/AnnotationsValidator.java
@@ -0,0 +1,120 @@
+package org.junit.validator;
+
+import static java.util.Collections.singletonList;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.runners.model.Annotatable;
+import org.junit.runners.model.FrameworkField;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.TestClass;
+
+/**
+ * An {@code AnnotationsValidator} validates all annotations of a test class,
+ * including its annotated fields and methods.
+ * 
+ * @since 4.12
+ */
+public final class AnnotationsValidator implements TestClassValidator {
+    private static final List<AnnotatableValidator<?>> VALIDATORS = Arrays.<AnnotatableValidator<?>>asList(
+            new ClassValidator(), new MethodValidator(), new FieldValidator());
+
+    /**
+     * Validate all annotations of the specified test class that are be
+     * annotated with {@link ValidateWith}.
+     * 
+     * @param testClass
+     *            the {@link TestClass} that is validated.
+     * @return the errors found by the validator.
+     */
+    public List<Exception> validateTestClass(TestClass testClass) {
+        List<Exception> validationErrors= new ArrayList<Exception>();
+        for (AnnotatableValidator<?> validator : VALIDATORS) {
+            List<Exception> additionalErrors= validator
+                    .validateTestClass(testClass);
+            validationErrors.addAll(additionalErrors);
+        }
+        return validationErrors;
+    }
+
+    private static abstract class AnnotatableValidator<T extends Annotatable> {
+        private static final AnnotationValidatorFactory ANNOTATION_VALIDATOR_FACTORY = new AnnotationValidatorFactory();
+
+        abstract Iterable<T> getAnnotatablesForTestClass(TestClass testClass);
+
+        abstract List<Exception> validateAnnotatable(
+                AnnotationValidator validator, T annotatable);
+
+        public List<Exception> validateTestClass(TestClass testClass) {
+            List<Exception> validationErrors= new ArrayList<Exception>();
+            for (T annotatable : getAnnotatablesForTestClass(testClass)) {
+                List<Exception> additionalErrors= validateAnnotatable(annotatable);
+                validationErrors.addAll(additionalErrors);
+            }
+            return validationErrors;
+        }
+
+        private List<Exception> validateAnnotatable(T annotatable) {
+            List<Exception> validationErrors= new ArrayList<Exception>();
+            for (Annotation annotation : annotatable.getAnnotations()) {
+                Class<? extends Annotation> annotationType = annotation
+                        .annotationType();
+                ValidateWith validateWith = annotationType
+                        .getAnnotation(ValidateWith.class);
+                if (validateWith != null) {
+                    AnnotationValidator annotationValidator = ANNOTATION_VALIDATOR_FACTORY
+                            .createAnnotationValidator(validateWith);
+                    List<Exception> errors= validateAnnotatable(
+                            annotationValidator, annotatable);
+                    validationErrors.addAll(errors);
+                }
+            }
+            return validationErrors;
+        }
+    }
+
+    private static class ClassValidator extends AnnotatableValidator<TestClass> {
+        @Override
+        Iterable<TestClass> getAnnotatablesForTestClass(TestClass testClass) {
+            return singletonList(testClass);
+        }
+
+        @Override
+        List<Exception> validateAnnotatable(
+                AnnotationValidator validator, TestClass testClass) {
+            return validator.validateAnnotatedClass(testClass);
+        }
+    }
+
+    private static class MethodValidator extends
+            AnnotatableValidator<FrameworkMethod> {
+        @Override
+        Iterable<FrameworkMethod> getAnnotatablesForTestClass(
+                TestClass testClass) {
+            return testClass.getAnnotatedMethods();
+        }
+
+        @Override
+        List<Exception> validateAnnotatable(
+                AnnotationValidator validator, FrameworkMethod method) {
+            return validator.validateAnnotatedMethod(method);
+        }
+    }
+
+    private static class FieldValidator extends
+            AnnotatableValidator<FrameworkField> {
+        @Override
+        Iterable<FrameworkField> getAnnotatablesForTestClass(TestClass testClass) {
+            return testClass.getAnnotatedFields();
+        }
+
+        @Override
+        List<Exception> validateAnnotatable(
+                AnnotationValidator validator, FrameworkField field) {
+            return validator.validateAnnotatedField(field);
+        }
+    }
+}
diff --git a/src/main/java/org/junit/validator/PublicClassValidator.java b/src/main/java/org/junit/validator/PublicClassValidator.java
new file mode 100644
index 0000000..fe3f185
--- /dev/null
+++ b/src/main/java/org/junit/validator/PublicClassValidator.java
@@ -0,0 +1,33 @@
+package org.junit.validator;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
+import java.util.List;
+
+import org.junit.runners.model.TestClass;
+
+/**
+ * Validates that a {@link TestClass} is public.
+ * 
+ * @since 4.12
+ */
+public class PublicClassValidator implements TestClassValidator {
+    private static final List<Exception> NO_VALIDATION_ERRORS = emptyList();
+
+    /**
+     * Validate that the specified {@link TestClass} is public.
+     * 
+     * @param testClass the {@link TestClass} that is validated.
+     * @return an empty list if the class is public or a list with a single
+     *         exception otherwise.
+     */
+    public List<Exception> validateTestClass(TestClass testClass) {
+        if (testClass.isPublic()) {
+            return NO_VALIDATION_ERRORS;
+        } else {
+            return singletonList(new Exception("The class "
+                    + testClass.getName() + " is not public."));
+        }
+    }
+}
diff --git a/src/main/java/org/junit/validator/TestClassValidator.java b/src/main/java/org/junit/validator/TestClassValidator.java
new file mode 100644
index 0000000..ba5e892
--- /dev/null
+++ b/src/main/java/org/junit/validator/TestClassValidator.java
@@ -0,0 +1,21 @@
+package org.junit.validator;
+
+import java.util.List;
+
+import org.junit.runners.model.TestClass;
+
+/**
+ * Validates a single facet of a test class.
+ * 
+ * @since 4.12
+ */
+public interface TestClassValidator {
+    /**
+     * Validate a single facet of a test class.
+     * 
+     * @param testClass
+     *            the {@link TestClass} that is validated.
+     * @return the validation errors found by the validator.
+     */
+    List<Exception> validateTestClass(TestClass testClass);
+}
diff --git a/src/main/java/org/junit/validator/ValidateWith.java b/src/main/java/org/junit/validator/ValidateWith.java
new file mode 100644
index 0000000..03d7906
--- /dev/null
+++ b/src/main/java/org/junit/validator/ValidateWith.java
@@ -0,0 +1,19 @@
+package org.junit.validator;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Allows for an {@link AnnotationValidator} to be attached to an annotation.
+ *
+ * <p>When attached to an annotation, the validator will be instantiated and invoked
+ * by the {@link org.junit.runners.ParentRunner}.</p>
+ *
+ * @since 4.12
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ValidateWith {
+    Class<? extends AnnotationValidator> value();
+}
diff --git a/src/site/fml/faq.fml b/src/site/fml/faq.fml
new file mode 100644
index 0000000..dcf28ee
--- /dev/null
+++ b/src/site/fml/faq.fml
@@ -0,0 +1,1749 @@
+<faqs title="Frequently Asked Questions" xmlns="http://maven.apache.org/FML/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/FML/1.0 http://maven.apache.org/xsd/fml-1.0.xsd">
+    <part id="faqinfo">
+        <title>About this frequently asked questions list</title>
+        <faq id="faqinfo_1">
+            <question>Who is responsible for this FAQ?</question>
+            <answer>
+                <p>The current version of this FAQ is maintained
+      by <a href="mailto:mike@clarkware.com">Mike Clark</a>.</p>
+                <p>Most of the wisdom contained in this FAQ comes from the
+      collective insights and hard-won experiences of the many good
+      folks who participate on the JUnit mailing list and the JUnit
+      community at large.</p>
+                <p>If you see your genius represented anywhere in this FAQ without
+      due credit to you, please send me an email and I'll make things
+      right.</p>
+            </answer>
+        </faq>
+        <faq id="faqinfo_2">
+            <question>How can I contribute to this FAQ?</question>
+            <answer>
+                <p>Your contributions to this FAQ are greatly appreciated!  The
+      JUnit community thanks you in advance.</p>
+                <p>To contribute to this FAQ, simply write a JUnit-related question
+      and answer, then send the unformatted text
+      to 
+                    
+                    <a href="mailto:mike@clarkware.com">
+                        Mike Clark</a>.
+      Corrections to this FAQ are always appreciated, as well.</p>
+                <p>No reasonable contribution will be denied.  Your name will
+      always appear along with any contribution you make.</p>
+            </answer>
+        </faq>
+        <faq id="faqinfo_3">
+            <question>Where do I get the latest version of this
+      FAQ?</question>
+            <answer>
+                <p>The master copy of this FAQ is available
+      at 
+                    
+                    <a href="http://junit.sourceforge.net/doc/faq/faq.htm">
+                        http://junit.sourceforge.net/doc/faq/faq.htm</a>.</p>
+                <p>The JUnit distribution also includes this FAQ in
+      the 
+                    
+                    <code>
+                        doc</code>directory.</p>
+            </answer>
+        </faq>
+    </part>
+    <part id="overview">
+        <title>Overview</title>
+  <faq id="overview_1"><question>What is JUnit?</question>    
+    <answer><p>
+      JUnit is a simple, open source framework to write and run
+      repeatable tests. It is an instance of the xUnit architecture
+      for unit testing frameworks.  JUnit features include:
+    </p>
+    <ul>
+      <li>Assertions for testing expected results</li>
+      <li>Test fixtures for sharing common test data</li>
+      <li>Test runners for running tests</li>
+    </ul>
+    <p>
+      JUnit was originally written by Erich Gamma and Kent Beck.
+    </p>
+</answer>
+  </faq>
+  <faq id="overview_2"><question>Where is the JUnit home page?</question>
+  <answer>
+    <p>
+      The official JUnit home page is <a
+      href="http://junit.org">http://junit.org</a>.
+    </p>
+</answer>
+</faq>
+<faq id="overview_3"><question>Where are the JUnit mailing lists and
+      forums?</question>
+    <answer>
+    <p>
+      There are 3 mailing lists dedicated to everything JUnit:
+    </p>
+    <ul>
+      <li>
+    <a href="http://groups.yahoo.com/group/junit/">JUnit user
+    list</a>.  (Search it for answers to frequently asked
+    questions not included here.)
+      </li>
+      <li>
+    <a
+    href="http://lists.sourceforge.net/lists/listinfo/junit-announce">JUnit
+    announcements</a>
+      </li>
+      <li>
+    <a
+    href="http://lists.sourceforge.net/lists/listinfo/junit-devel">JUnit
+    developer list</a>
+      </li>
+    </ul>
+</answer>
+</faq>
+<faq id="overview_4"><question>Where is the JUnit
+      documentation?</question>
+<answer>
+    <p>
+      The following documents are included in the JUnit distribution
+      in the <code>doc</code> directory:
+    </p>
+    <ul>
+      <li>
+    <a
+    href="http://junit.sourceforge.net/doc/testinfected/testing.htm">JUnit
+    Test Infected: Programmers Love Writing Tests</a>
+      </li> 
+      <li>
+    <a
+    href="http://junit.sourceforge.net/doc/cookbook/cookbook.htm">JUnit
+      Cookbook</a>
+      </li>
+      <li>
+    <a
+    href="http://junit.sourceforge.net/doc/cookstour/cookstour.htm">JUnit
+    - A Cook's Tour</a>
+      </li>
+      <li>
+    <a href="http://junit.sourceforge.net/doc/faq/faq.htm">JUnit
+    FAQ</a>
+      </li>
+    </ul>
+</answer>
+</faq>
+<faq id="overview_5"><question>Where can I find articles on
+      JUnit?</question><answer>
+    <p>
+      The JUnit home page maintains a list
+      of <a href="http://www.junit.org/news/article/index.htm">JUnit
+      articles</a>.
+    </p>
+</answer>
+</faq>
+  <faq id="overview_6"><question>What's the latest news on JUnit?</question>
+  <answer>
+    <p>
+      The JUnit home page publishes
+      the <a href="http://www.junit.org/news/index.htm">latest JUnit
+      news</a>.
+    </p>
+</answer>
+</faq>
+      <faq id="overview_7"><question>How is JUnit licensed?</question>
+      <answer>
+    <p>
+      JUnit is <a href="http://www.opensource.org/">Open Source
+      Software</a>, released
+      under the <a
+      href="http://opensource.org/licenses/eclipse-1.0.html">
+      Eclipse Public License Version 1.0</a> and hosted
+      on <a
+      href="http://sourceforge.net/projects/junit/">SourceForge</a>.
+    </p>
+</answer>
+</faq>
+  <faq id="overview_8"><question>What awards has JUnit won?</question>
+<answer>
+    <ul>
+      <li>
+    <p> <a
+    href="http://www.javaworld.com/javaworld/jw-03-2002/jw-0326-awards.html">2002
+    JavaWorld Editors' Choice Awards (ECA)</a>
+    </p>
+    <p>
+      Best Java Performance Monitoring/Testing Tool
+    </p>
+      </li>
+      <li>
+    <p>
+      <a
+      href="http://www.javaworld.com/javaworld/jw-06-2001/j1-01-awards.html">2001
+      JavaWorld Editors' Choice Awards (ECA)</a>
+    </p>
+    <p>
+      Best Java Performance Monitoring/Testing Tool
+    </p>
+      </li>
+    </ul>
+</answer>
+</faq>
+    </part>
+    <part id="started">
+        <title>Getting Started</title>
+        <faq id="started_1">
+            <question>Where do I download JUnit?</question>
+            <answer><p>
+      The latest version of JUnit is available
+      on <a
+      href="http://sourceforge.net/project/showfiles.php?group_id=15278">SourceForge</a>.
+    </p></answer>
+        </faq>
+        <faq id="started_2">
+            <question>How do I install JUnit?</question>
+            <answer><ol>
+      <li>
+    <p>
+      First, <a
+            href="http://sourceforge.net/project/showfiles.php?group_id=15278">download</a>
+      the
+      latest version of JUnit, referred to below
+      as <code>junit.zip</code>. 
+    </p>
+      </li>
+      <li>
+    <p>
+      Then install JUnit on your platform of choice:
+    </p>
+    <p>
+      <u>Windows</u>
+    </p>
+    <p>
+      To install JUnit on Windows, follow these steps:
+    </p>
+    <ol>
+      <li>
+        <p>
+          Unzip the <code>junit.zip</code> distribution file to
+          a directory referred to as <code>%JUNIT_HOME%</code>.
+        </p>
+      </li>
+      <li>Add JUnit to the classpath:
+        <p>
+          <code>set CLASSPATH=%CLASSPATH%;%JUNIT_HOME%\junit.jar</code>
+        </p>
+      </li>
+    </ol>
+    <p>
+      <u>Unix (bash)</u>
+    </p>
+    <p>
+      To install JUnit on Unix, follow these steps:
+    </p>
+    <ol>
+      <li>
+        <p>
+          Unzip the <code>junit.zip</code> distribution file to
+          a directory referred to as <code>$JUNIT_HOME</code>.
+        </p>    
+      </li>
+      <li>
+        <p>
+          Add JUnit to the classpath:
+        </p>
+        <p>
+          <code>export CLASSPATH=$CLASSPATH:$JUNIT_HOME/junit.jar</code>
+        </p>
+      </li>
+    </ol>
+      </li>
+      <li>
+    <p>
+      <i>(Optional)</i> Unzip
+      the <code>$JUNIT_HOME/src.jar</code> file.
+    </p>
+      </li>
+      <li>
+    <p>
+      Test the installation by running the sample tests
+      distributed with JUnit.  Note that the sample tests are
+      located in the installation directory directly, not
+      the <code>junit.jar</code> file.  Therefore, make sure that
+      the JUnit installation directory is on your CLASSPATH.  Then
+      simply type:
+    </p>
+    <pre>java org.junit.runner.JUnitCore org.junit.tests.AllTests</pre>
+    <p>
+      All the tests should pass with an "OK" message.
+    </p>
+    <p>
+      <i> 
+        If the tests don't pass, verify
+        that <code>junit.jar</code> is in the CLASSPATH.
+      </i>
+    </p>
+      </li>
+      <li>
+    <p>
+      Finally, <a href="#overview_4">read</a> the documentation.
+    </p>
+      </li>
+    </ol></answer>
+        </faq>
+        <faq id="started_3">
+            <question>How do I uninstall JUnit?</question>
+            <answer><ol>
+      <li>
+    <p> 
+      Delete the directory structure where you unzipped the JUnit
+      distribution.
+    </p>
+      </li>
+      <li>
+    <p>
+      Remove <code>junit.jar</code> from the CLASSPATH.
+    </p>
+      </li>
+    </ol>
+    <p>
+      JUnit does not modify the registry so simply removing all the
+      files will fully uninstall it.
+    </p></answer>
+        </faq>
+        <faq id="started_4">
+            <question>How do I ask questions?</question>
+            <answer><p>
+      Questions that are not answered in
+      the <a
+      href="http://junit.sourceforge.net/doc/faq/faq.htm">FAQ</a> or
+      in the <a href="#overview_4">documentation</a> should be posted
+      to
+      the <a
+      href="http://www.jguru.com/forums/home.jsp?topic=JUnit">jGuru
+    discussion forum</a> or the <a
+    href="http://groups.yahoo.com/group/junit/">JUnit user mailing
+    list</a>.
+    </p>
+    <p>
+      Please stick to technical issues on the discussion forum and
+      mailing lists. Keep in mind that these are public, so
+      do <b>not</b> include any confidental information in your
+      questions!
+    </p>
+    <p>
+      You should also
+      read <a
+      href="http://www.catb.org/~esr/faqs/smart-questions.html">"How
+      to ask questions the smart way"</a> by Eric Raymond before
+      participating in the discussion forum and mailing lists.
+    </p>
+    <p>
+      <i> 
+    NOTE: <br/> Please do NOT submit bugs, patches, or feature
+    requests to the discussion forum or mailing lists.  <br/>
+    Refer instead to <a href="#started_5">"How do I submit bugs,
+    patches, or feature requests?"</a>.
+      </i>
+    </p></answer>
+        </faq>
+        <faq id="started_5">
+            <question>How do I submit bugs, patches, or
+       feature requests?</question>
+            <answer>    <p>
+      JUnit celebrates programmers testing their own software. In this
+      spirit, bugs, patches, and feature requests that include JUnit
+      tests have a better chance of being addressed than those
+      without.
+    </p>
+    <p>
+      JUnit is hosted
+      on <a
+      href="http://github/junit-team/junit">GitHub</a>.
+      Please use the tools provided by GitHub for your
+      submissions.
+    </p>
+</answer>
+        </faq>
+    </part>
+    <part id="tests">
+        <title>Writing Tests</title>
+      <faq id="#tests_1"><question>How do I write and run a simple test?</question><answer>    <ol>
+      <li>
+    <p>
+      Create a class:
+    </p>
+<pre class="prettyprint linenums">package junitfaq;
+      
+import org.junit.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+public class SimpleTest {</pre>      
+      </li>
+      <li>
+    <p>
+      Write a test method (annotated with <code>@Test</code>) that
+      asserts expected results on the object under test:
+    </p>
+    <pre class="prettyprint linenums">    @Test
+    public void testEmptyCollection() {
+        Collection collection = new ArrayList();
+        assertTrue(collection.isEmpty());
+    }</pre>
+      </li>
+      <li>
+    <p>
+      If you are running your JUnit 4 tests with a JUnit 3.x runner,
+      write a <code>suite()</code> method that uses the 
+      <code>JUnit4TestAdapter</code> class to create a suite
+      containing all of your test methods:
+    </p>
+    <pre class="prettyprint linenums">    public static junit.framework.Test suite() {
+        return new junit.framework.JUnit4TestAdapter(SimpleTest.class);
+    }</pre>
+      </li>
+      <li>
+    <p>
+      Although writing a <code>main()</code> method to run the
+      test is much less important with the advent of IDE runners,
+      it's still possible:
+    </p>
+    <pre class="prettyprint linenums">    public static void main(String args[]) {
+      org.junit.runner.JUnitCore.main("junitfaq.SimpleTest");
+    }
+}</pre>
+      </li>
+      <li>
+    <p>
+      Run the test:
+    </p>
+    <ul>
+      <li>
+        <p>
+          To run the test from the console, type:
+        </p>
+        <pre>java org.junit.runner.JUnitCore junitfaq.SimpleTest</pre>
+      </li>
+      <li>
+        <p>
+          To run the test with the test runner used
+          in <code>main()</code>, type:
+        </p>
+        <pre>java junitfaq.SimpleTest</pre> 
+      </li>
+    </ul>
+    <p>
+      The passing test results in the following textual output:
+    </p>
+    <pre>.
+Time: 0
+
+OK (1 tests)</pre>
+      </li>
+    </ol>
+</answer></faq>
+      <faq id="#tests_2"><question>How do I use a test fixture?</question><answer><p>
+      <i>(Submitted by: Jeff Nielsen)</i>
+    </p>
+    <p>
+      A test fixture is useful if you have two or more tests for a
+      common set of objects.  Using a test fixture avoids duplicating
+      the code necessary to initialize (and cleanup) the common
+      objects.
+    </p>
+    <p>
+      Tests can use the objects (variables) in a test fixture, with
+      each test invoking different methods on objects in the fixture
+      and asserting different expected results.  Each test runs in its
+      own test fixture to isolate tests from the changes made by other
+      tests.  That is, <em>tests don't share the state of objects in
+      the test fixture</em>.  Because the tests are isolated, they can
+      be run in any order.
+    </p>
+    <p>
+      To create a test fixture, declare instance variables for the
+      common objects.  Initialize these objects in a <code>public
+      void</code> method annotated with <code>@Before</code>.  The
+      JUnit framework automatically invokes any <code>@Before</code>
+      methods before each test is run.
+    </p>
+    <p>
+      The following example shows a test fixture with a common
+      <code>Collection</code> object.
+    </p>
+    <pre class="prettyprint linenums">package junitfaq;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+import java.util.*;
+
+public class SimpleTest {
+
+    private Collection&lt;Object&gt; collection;
+
+    @Before
+    public void setUp() {
+        collection = new ArrayList&lt;Object&gt;();
+    }
+
+    @Test
+    public void testEmptyCollection() {
+        assertTrue(collection.isEmpty());
+    }
+
+
+    @Test
+    public void testOneItemCollection() {
+        collection.add("itemA");
+        assertEquals(1, collection.size());
+    }
+}</pre>
+
+    <p>
+      Given this test, the methods might execute in the following
+      order:
+    </p>
+      <pre class="prettyprint linenums">setUp()
+testEmptyCollection()
+setUp()
+testOneItemCollection()</pre>
+    <p>
+      The ordering of test-method invocations is not guaranteed, so
+      <code>testOneItemCollection()</code> might be executed before
+      <code>testEmptyCollection()</code>.  But it doesn't matter,
+      because each method gets its own instance of the
+      <code>collection</code>.
+    </p>
+
+    <p>
+      Although JUnit provides a new instance of the fixture objects
+      for each test method, if you allocate any <em>external</em>
+      resources in a <code>@Before</code> method, you should release
+      them after the test runs by annotating a method with
+      <code>@After</code>.  The JUnit framework automatically invokes
+      any <code>@After</code> methods after each test is run.  For
+      example:
+    </p>
+
+    <pre class="prettyprint linenums">package junitfaq;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+import java.io.*;
+
+public class OutputTest {
+
+    private File output;
+
+    @Before
+    public void createOutputFile() {
+        output = new File(...);
+    }
+
+    @After
+    public void deleteOutputFile() {
+        output.delete();
+    }
+
+    @Test
+    public void testSomethingWithFile() {
+        ...
+    }
+}</pre>
+    <p>
+      With this test, the methods will execute in the following order:
+    </p>
+    <pre class="prettyprint linenums">
+createOutputFile()
+testSomethingWithFile()
+deleteOutputFile()</pre></answer></faq>
+      <faq id="#tests_4"><question>How do I test a method that doesn't
+      return anything?</question><answer><p>
+      <i>(Submitted by: Dave Astels)</i>
+    </p>
+    <p>
+      Often if a method doesn't return a value, it will have some side
+      effect. Actually, if it doesn't return a value AND doesn't have
+      a side effect, it isn't doing anything.
+    </p>
+    <p>
+      There may be a way to verify that the side effect actually
+      occurred as expected. For example, consider
+      the <code>add()</code> method in the Collection classes. There
+      are ways of verifying that the side effect happened (i.e. the
+      object was added). You can check the size and assert that it is
+      what is expected:
+    </p>
+    <pre class="prettyprint linenums">
+    @Test
+    public void testCollectionAdd() {
+        Collection collection = new ArrayList();
+        assertEquals(0, collection.size());
+        collection.add("itemA");
+        assertEquals(1, collection.size());
+        collection.add("itemB");
+        assertEquals(2, collection.size());
+    }</pre>
+    <p>
+      Another approach is to make use of <a
+      href="http://www.mockobjects.com">MockObjects</a>.
+    </p>
+    <p>
+      A related issue is to design for testing. For example, if you
+      have a method that is meant to output to a file, don't pass in a
+      filename, or even a <code>FileWriter</code>. Instead, pass in
+      a <code>Writer</code>. That way you can pass in
+      a <code>StringWriter</code> to capture the output for testing
+      purposes. Then you can add a method
+      (e.g. <code>writeToFileNamed(String filename)</code>) to
+      encapsulate the <code>FileWriter</code> creation.
+    </p></answer></faq>
+      <faq id="#tests_5"><question>Under what conditions should I test get()
+      and set() methods?</question><answer><p>
+      Unit tests are intended to alleviate fear that something might
+      break.  If you think a <code>get()</code> or <code>set()</code>
+      method could reasonably break, or has in fact contributed to a
+      defect, then by all means write a test.
+    </p>
+    <p>
+      In short, test until you're confident.  What you choose to test
+      is subjective, based on your experiences and confidence level.
+      Remember to be practical and maximize your testing investment.
+    </p>
+    <p>  
+      Refer also to <a href="#best_3">"How simple is 'too simple to
+      break'?"</a>.
+    </p></answer></faq>
+      <faq id="#tests_6"><question>Under what conditions should I not test
+      get() and set() methods?</question><answer><p>
+      <i>(Submitted by: J. B. Rainsberger)</i>
+    </p>
+    <p>
+      Most of the time, get/set methods just can't break, and if they
+      can't break, then why test them? While it is usually better to
+      test more, there is a definite curve of diminishing returns on
+      test effort versus "code coverage".  Remember the maxim: "Test
+      until fear turns to boredom."
+    </p>
+    <p>
+      Assume that the <code>getX()</code> method only does "return x;"
+      and that the <code>setX()</code> method only does "this.x =
+      x;". If you write this test:
+    </p>
+    <pre class="prettyprint linenums">@Test
+public void testGetSetX() {
+    setX(23);
+    assertEquals(23, getX());
+}</pre>
+    <p>
+      then you are testing the equivalent of the following:
+    </p>
+    <pre class="prettyprint linenums">
+@Test
+public void testGetSetX() {
+    x = 23;
+    assertEquals(23, x);
+}</pre>
+    <p>
+      or, if you prefer,
+    </p>
+    <pre class="prettyprint linenums">@Test
+public void testGetSetX() {
+    assertEquals(23, 23);
+}</pre>
+    <p>
+      At this point, you are testing the Java compiler, or possibly
+      the interpreter, and not your component or application. There is
+      generally no need for you to do Java's testing for them.
+    </p>
+    <p>
+      If you are concerned about whether a property has already been
+      set at the point you wish to call <code>getX()</code>, then you
+      want to test the constructor, and not the <code>getX()</code>
+      method. This kind of test is especially useful if you have
+      multiple constructors:
+    </p>
+    <pre class="prettyprint linenums">@Test
+public void testCreate() {
+    assertEquals(23, new MyClass(23).getX());
+}</pre>
+</answer></faq>
+      <faq id="#tests_7"><question>How do I write a test that passes when an
+      expected exception is thrown?</question><answer><p>
+      Add the optional <code>expected</code> attribute to
+      the <code>@Test</code> annotation.  The following is an example
+      test that passes when the
+      expected <code>IndexOutOfBoundsException</code> is raised:
+    </p>
+    <pre class="prettyprint linenums">@Test(expected=IndexOutOfBoundsException.class)
+public void testIndexOutOfBoundsException() {
+    ArrayList emptyList = new ArrayList();
+    Object o = emptyList.get(0);
+}</pre>
+    </answer></faq>
+      <faq id="#tests_8"><question>How do I write a test that fails when an
+      unexpected exception is thrown?</question><answer><p>
+      Declare the exception in the <code>throws</code> clause of the
+      test method and don't catch the exception within the test
+      method.  Uncaught exceptions will cause the test to fail with an
+      error.
+    </p>
+    <p>
+      The following is an example test that fails when
+      the <code>IndexOutOfBoundsException</code> is raised:
+    </p>
+    <pre class="prettyprint linenums">@Test
+public void testIndexOutOfBoundsExceptionNotRaised() 
+    throws IndexOutOfBoundsException {
+
+    ArrayList emptyList = new ArrayList();
+    Object o = emptyList.get(0);
+}</pre></answer></faq>
+      <faq id="#tests_10"><question>How do I test protected methods?</question><answer><p>
+      Place your tests in the same package as the classes under test.
+    </p>
+    <p>
+      Refer to <a href="#organize_1">"Where should I put my test
+      files?"</a> for examples of how to organize tests for protected
+      method access.
+    </p></answer></faq>
+      <faq id="#tests_11"><question>How do I test private methods?</question><answer><p>
+      Testing private methods may be an indication that those methods
+      should be moved into another class to promote reusability.
+    </p>
+    <p>
+      But if you must...
+    </p>
+    <p>
+      If you are using JDK 1.3 or higher, you can use reflection to
+      subvert the access control mechanism with the aid of
+      the <a
+      href="http://sourceforge.net/projects/privaccessor/">PrivilegedAccessor</a>.
+      For details on how to use it,
+      read <a
+      href="http://www.onjava.com/pub/a/onjava/2003/11/12/reflection.html">this
+      article</a>.
+    </p></answer></faq>
+      <faq id="#tests_12"><question>Why does JUnit only report the first
+      failure in a single test?</question><answer><p>
+      <i>(Submitted by: J. B. Rainsberger)</i>
+    </p>
+    <p>
+      Reporting multiple failures in a single test is generally a sign
+      that the test does too much, compared to what a unit test ought
+      to do. Usually this means either that the test is really a
+      functional/acceptance/customer test or, if it is a unit test,
+      then it is too big a unit test.
+    </p>
+    <p>
+      JUnit is designed to work best with a number of small tests. It
+      executes each test within a separate instance of the test
+      class. It reports failure on each test. Shared setup code is
+      most natural when sharing between tests. This is a design
+      decision that permeates JUnit, and when you decide to report
+      multiple failures per test, you begin to fight against
+      JUnit. This is not recommended.
+    </p>
+    <p>
+      Long tests are a design smell and indicate the likelihood of a
+      design problem. Kent Beck is fond of saying in this case that
+      "there is an opportunity to learn something about your design."
+      We would like to see a pattern language develop around these
+      problems, but it has not yet been written down.
+    </p>
+    <p>
+      Finally, note that a single test with multiple assertions is
+      isomorphic to a test case with multiple tests:
+    </p>
+    <p>
+      One test method, three assertions:
+    </p>
+    <pre class="prettyprint linenums">public class MyTestCase {
+    @Test
+    public void testSomething() {
+        // Set up for the test, manipulating local variables
+        assertTrue(condition1);
+        assertTrue(condition2);
+        assertTrue(condition3);
+    }
+}</pre>
+    <p>
+      Three test methods, one assertion each:
+    </p>
+    <pre class="prettyprint linenums">
+public class MyTestCase {
+    // Local variables become instance variables
+
+    @Before
+    public void setUp() {
+        // Set up for the test, manipulating instance variables
+    }
+    
+    @Test
+    public void testCondition1() {
+        assertTrue(condition1);
+    }
+
+    @Test
+    public void testCondition2() {
+        assertTrue(condition2);
+    }
+
+    @Test
+    public void testCondition3() {
+        assertTrue(condition3);
+    }
+}</pre>
+    <p>
+      The resulting tests use JUnit's natural execution and reporting
+      mechanism and, failure in one test does not affect the execution
+      of the other tests.  You generally want exactly one test to fail
+      for any given bug, if you can manage it.
+    </p></answer></faq>
+      <faq id="#tests_13"><question>In Java 1.4, 'assert' is a
+      keyword. Won't this conflict with JUnit's assert()
+      method?</question><answer><p>
+      JUnit 3.7 deprecated <code>assert()</code> and replaced it
+      with <code>assertTrue()</code>, which works exactly the same
+      way.
+    </p>
+    <p>
+      JUnit 4 is compatible with the <code>assert</code> keyword.  If
+      you run with the <code>-ea</code> JVM switch, assertions that
+      fail will be reported by JUnit.
+    </p></answer></faq>
+      <faq id="#tests_14"><question>How do I test things that must be run in
+      a J2EE container (e.g. servlets, EJBs)?</question><answer><p>
+      Refactoring J2EE components to delegate functionality to other
+      objects that don't have to be run in a J2EE container will
+      improve the design and testability of the software.
+    </p>
+    <p>
+      <a href="http://jakarta.apache.org/cactus/index.html">Cactus</a>
+      is an open source JUnit extension that can be used to test J2EE
+      components in their natural environment.
+    </p></answer></faq>
+      <faq id="#tests_15"><question>Do I need to write a test class for
+      every class I need to test?</question><answer><p>
+      <i>(Submitted by: J. B. Rainsberger)</i>
+    </p>
+    <p>
+      No. It is a convention to start with one test
+      class per class under test, but it is not necessary.
+    </p>
+    <p>
+      Test classes only provide a way to organize tests, nothing more.
+      Generally you will start with one test class per class under
+      test, but then you may find that a small group of tests belong
+      together with their own common test fixture.[1] In this case,
+      you may move those tests to a new test class.  This is a simple
+      object-oriented refactoring: separating responsibilities of an
+      object that does too much.
+    </p>
+    <p>
+      Another point to consider is that the <code>TestSuite</code> is
+      the smallest execution unit in JUnit: you cannot execute
+      anything smaller than a TestSuite at one time without changing
+      source code. In this case, you probably do not want to put tests
+      in the same test class unless they somehow "belong together".
+      If you have two groups of tests that you think you'd like to
+      execute separately from one another, it is wise to place them in
+      separate test classes.
+    </p>
+    <p>
+      <i>
+    [1] A test fixture is a common set of test data and
+    collaborating objects shared by many tests. Generally they are
+    implemented as instance variables in the test class.
+      </i>
+    </p></answer></faq>
+      <faq id="#tests_16"><question>Is there a basic template I can use to
+      create a test?</question><answer><p>
+      <i>(Submitted by: Eric Armstrong)</i>
+    </p>
+    <p>
+      The following templates are a good starting point.  Copy/paste
+      and edit these templates to suit your coding style.
+    </p>
+    <p>
+      SampleTest is a basic test template:
+    </p>
+    <pre class="prettyprint linenums">import org.junit.*;
+import static org.junit.Assert.*;
+
+public class SampleTest {
+
+    private java.util.List emptyList;
+
+    /**
+     * Sets up the test fixture. 
+     * (Called before every test case method.)
+     */
+    @Before
+    public void setUp() {
+        emptyList = new java.util.ArrayList();
+    }
+
+    /**
+     * Tears down the test fixture. 
+     * (Called after every test case method.)
+     */
+    @After
+    public void tearDown() {
+        emptyList = null;
+    }
+    
+    @Test
+    public void testSomeBehavior() {
+        assertEquals("Empty list should have 0 elements", 0, emptyList.size());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testForException() {
+        Object o = emptyList.get(0);
+    }
+}</pre></answer></faq>
+      <faq id="#tests_17"><question>How do I write a test for an abstract
+      class?</question><answer><p>
+      Refer to <a
+      href="http://c2.com/cgi/wiki?AbstractTestCases">http://c2.com/cgi/wiki?AbstractTestCases</a>.
+    </p></answer></faq>
+      <faq id="#tests_18"><question>When are tests garbage collected?</question><answer><p>
+      <i>(Submitted by: Timothy Wall and Kent Beck)</i>
+    </p>
+    <p>
+      By design, the tree of Test instances is built in one pass, then
+      the tests are executed in a second pass.  The test runner holds
+      strong references to all Test instances for the duration of the
+      test execution.  This means that for a very long test run with
+      many Test instances, none of the tests may be garbage collected
+      until the end of the entire test run.
+    </p>
+    <p>
+      Therefore, if you allocate external or limited resources in a
+      test, you are responsible for freeing those resources.
+      Explicitly setting an object to <code>null</code> in
+      the <code>tearDown()</code> method, for example, allows it to be
+      garbage collected before the end of the entire test run.
+    </p></answer></faq>
+    </part>
+    <part id="organize">
+        <title>Organizing Tests</title>
+        <faq id="organize_1">
+            <question>Where should I put my test files?</question>
+            <answer><p>
+      You can place your tests in the same package and directory as
+      the classes under test.
+    </p>
+    <p>
+      For example:
+    </p>
+    <pre>src
+   com
+      xyz
+         SomeClass.java
+         SomeClassTest.java</pre>
+    <p> 
+      While adequate for small projects, many developers feel that
+      this approach clutters the source directory, and makes it hard
+      to package up client deliverables without also including
+      unwanted test code, or writing unnecessarily complex packaging
+      tasks.
+    </p>
+    <p>
+      An arguably better way is to place the tests in a separate
+      parallel directory structure with package alignment.
+    </p>
+    <p>
+      For example:
+    </p>
+    <pre>src
+   com
+      xyz
+         SomeClass.java
+test
+   com
+      xyz
+         SomeClassTest.java</pre>
+    <p>
+      These approaches allow the tests to access to all the public and
+      package visible methods of the classes under test.
+    </p>
+    <p>
+      Some developers have argued in favor of putting the tests in a
+      sub-package of the classes under test (e.g. com.xyz.test). The
+      author of this FAQ sees no clear advantage to adopting this
+      approach and believes that said developers also put their curly
+      braces on the wrong line.  :-)
+    </p></answer>
+        </faq>
+        <faq id="organize_3">
+            <question>How can I run setUp() and tearDown()
+      code once for all of my tests?</question>
+            <answer><p>
+      The desire to do this is usually a symptom of excessive coupling
+      in your design.  If two or more tests must share the same test
+      fixture state, then the tests may be trying to tell you that the
+      classes under test have some undesirable dependencies.
+    </p>
+    <p>
+      Refactoring the design to further decouple the classes under
+      test and eliminate code duplication is usually a better
+      investment than setting up a shared test fixture.
+    </p>
+    <p>
+      But if you must...
+    </p>
+    <p>
+      You can add a <code>@BeforeClass</code> annotation to a method
+      to be run before all the tests in a class, and
+      a <code>@AfterClass</code> annotation to a method to be run
+      after all the tests in a class.  Here's an example:
+    </p>
+    <pre class="prettyprint linenums">package junitfaq;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+import java.util.*;
+
+public class SimpleTest {
+
+    private Collection collection;
+    
+    @BeforeClass
+    public static void oneTimeSetUp() {
+        // one-time initialization code        
+    }
+
+    @AfterClass
+    public static void oneTimeTearDown() {
+        // one-time cleanup code
+    }
+
+    @Before
+    public void setUp() {
+        collection = new ArrayList();
+    }
+    
+    @After
+    public void tearDown() {
+        collection.clear();
+    }
+
+    @Test
+    public void testEmptyCollection() {
+        assertTrue(collection.isEmpty());
+    }
+    
+    @Test
+    public void testOneItemCollection() {
+        collection.add("itemA");
+        assertEquals(1, collection.size());
+    }
+}</pre>
+    <p>
+      Given this test, the methods will execute in the following
+      order:
+    </p>
+    <pre class="prettyprint linenums">oneTimeSetUp()
+setUp()
+testEmptyCollection()
+tearDown()
+setUp()
+testOneItemCollection()
+tearDown()
+oneTimeTearDown()</pre>
+</answer>
+        </faq>
+    </part>
+    <part id="running-tests">
+        <title>Running Tests</title>
+        <faq id="running_1">
+            <question>What CLASSPATH settings are needed to
+      run JUnit?</question>
+            <answer><p>
+      <i>(Submitted by: Eric Armstrong)</i>
+    </p>
+    <p>
+      To run your JUnit tests, you'll need the following elemements in
+      your CLASSPATH:
+    </p>
+    <ul>
+      <li>JUnit class files</li>
+      <li>Your class files, including your JUnit test classes</li>
+      <li>Libraries your class files depend on</li>
+    </ul>
+    <p>
+      If attempting to run your tests results in
+      a <code>NoClassDefFoundError</code>, then something is missing
+      from your CLASSPATH.
+    </p>
+    <p>
+      <u>Windows Example:</u>
+    </p>
+    <pre>set CLASSPATH=%JUNIT_HOME%\junit.jar;c:\myproject\classes;c:\myproject\lib\something.jar</pre>
+    <p>
+      <u>Unix (bash) Example:</u>
+    </p>
+    <pre>export CLASSPATH=$JUNIT_HOME/junit.jar:/myproject/classes:/myproject/lib/something.jar</pre>
+</answer>
+        </faq>
+        <faq id="running_2">
+            <question>Why do I get
+        a <code>NoClassDefFoundError</code> when trying to test JUnit
+        or run the samples?</question>
+            <answer><p>
+      <i>(Submitted by: J.B. Rainsberger and Jason Rogers)</i>
+    </p>
+    <p>
+      Most likely your CLASSPATH doesn't include the JUnit
+      installation directory.
+    </p>
+    <p>
+      Refer to <a href="#running_1">"What CLASSPATH settings are
+      needed to run JUnit?"</a> for more guidance.
+    </p>
+    <p>
+      Also consider running <a
+                               href="http://www.clarkware.com/software/WhichJUnit.zip">WhichJunit</a>
+      to print the absolute location of the JUnit class files required
+      to run and test JUnit and its samples.
+    </p>
+    <p>
+      If the CLASSPATH seems mysterious, read <a
+      href="http://java.sun.com/j2se/1.4/docs/tooldocs/findingclasses.html">this</a>!
+    </p></answer>
+        </faq>
+        <faq id="running_4">
+            <question>How do I run JUnit from my command window?</question>
+            <answer><p>
+      <i>(Submitted by: Eric Armstrong)</i>
+    </p>
+    <ol>
+      <li>
+        <p>
+          <a href="#running_1">Set your CLASSPATH</a>
+        </p>
+      </li>
+      <li>
+        <p>
+          Invoke the runner:
+        </p>
+        <p>
+          <code>
+            java org.junit.runner.JUnitCore &lt;test class name&gt; 
+          </code>
+        </p>
+      </li>
+    </ol></answer>
+        </faq>
+        <faq id="running_5">
+            <question>How do I run JUnit using Ant?</question>
+            <answer><p>
+      <i>(Submitted by: Eric Armstrong)</i>
+    </p>
+    <ol>
+      <li>
+        <p>
+          Define any necessary Ant properties:
+        </p>
+          <pre class="prettyprint linenums">&lt;property name="src" value="./src" /&gt;
+&lt;property name="lib" value="./lib" /&gt;
+&lt;property name="classes" value="./classes" /&gt;
+&lt;property name="test.class.name" value="com.xyz.MyTestSuite" /&gt;</pre>
+      </li>
+      <li>
+        <p>
+          Set up the CLASSPATH to be used by JUnit:
+        </p>
+          <pre class="prettyprint linenums">&lt;path id="test.classpath"&gt;
+  &lt;pathelement location="${classes}" /&gt;
+  &lt;pathelement location="/path/to/junit.jar" /&gt;
+  &lt;fileset dir="${lib}">
+    &lt;include name="**/*.jar"/&gt;
+  &lt;/fileset&gt;
+&lt;/path&gt;</pre>
+      </li>
+      <li>
+        <p>
+          Define the Ant task for running JUnit:
+        </p>
+          <pre class="prettyprint linenums">&lt;target name="test"&gt;
+  &lt;junit fork="yes" haltonfailure="yes"&gt;
+    &lt;test name="${test.class.name}" /&gt;
+    &lt;formatter type="plain" usefile="false" /&gt;
+    &lt;classpath refid="test.classpath" /&gt;
+  &lt;/junit&gt;
+&lt;/target&gt;</pre>
+      </li>
+      <li>
+        <p>
+          Run the test:
+        </p>
+        <pre>ant test</pre>
+      </li>
+    </ol>
+    <p>
+      Refer to the <a
+      href="http://jakarta.apache.org/ant/manual/OptionalTasks/junit.html">JUnit
+      Ant Task</a> for more information.
+    </p></answer>
+        </faq>
+        <faq id="running_6">
+            <question>How do I use Ant to create HTML test
+      reports?</question>
+            <answer><p>
+      <i>(Submitted by: Eric Armstrong and Steffen Gemkow)</i>
+    </p>
+    <ol>
+      <li>
+        <p>
+          Ensure that Ant's <code>optional.jar</code> file is either
+          in your CLASSPATH or exists in
+          your <code>$ANT_HOME/lib</code> directory.
+        </p>
+      </li>
+      <li>
+        <p>
+          Add an ANT property for the directory containing the HTML reports:
+        </p>
+        <pre class="prettyprint linenums">&lt;property name="test.reports" value="./reports" /&gt;</pre>
+      </li>
+      <li>
+        <p>
+          Define the Ant task for running JUnit and generating reports:
+        </p>
+          <pre class="prettyprint linenums">&lt;target name="test-html"&gt;
+  &lt;junit fork="yes" printsummary="no" haltonfailure="no"&gt;
+    &lt;batchtest fork="yes" todir="${test.reports}" &gt;
+      &lt;fileset dir="${classes}"&gt;
+        &lt;include name="**/*Test.class" /&gt;
+      &lt;/fileset&gt;
+    &lt;/batchtest&gt;
+    &lt;formatter type="xml" /&gt;
+    &lt;classpath refid="test.classpath" /&gt;
+  &lt;/junit&gt;
+
+  &lt;junitreport todir="${test.reports}"&gt;
+    &lt;fileset dir="${test.reports}"&gt;
+      &lt;include name="TEST-*.xml" /&gt;
+    &lt;/fileset&gt;
+    &lt;report todir="${test.reports}" /&gt;
+  &lt;/junitreport&gt;
+&lt;/target&gt;</pre>
+      </li>
+      <li>
+        <p>
+          Run the test:
+        </p>
+        <div>
+          <code>
+            ant test-html
+          </code>
+        </div>
+      </li>
+    </ol>
+    <p>
+      Refer to the 
+      <a href="http://jakarta.apache.org/ant/manual/OptionalTasks/junit.html">JUnit Ant Task</a>
+      for more information.
+    </p></answer>
+        </faq>
+        <faq id="running_7">
+            <question>How do I pass command-line arguments
+      to a test execution?</question>
+            <answer><p>
+      Use the <tt>-D</tt> JVM command-line options, as in:
+    </p>
+    <pre class="prettyprint">-DparameterName=parameterValue</pre>
+    <p>
+      If the number of parameters on the command line gets unweildy,
+      pass in the location of a property file that defines a set of
+      parameters. Alternatively, the <a
+      href="http://junit-addons.sf.net">JUnit-addons package</a>
+      contains the <tt>XMLPropertyManager</tt>
+      and <tt>PropertyManager</tt> classes that allow you to define a
+      property file (or XML file) containing test parameters.
+    </p></answer>
+        </faq>
+        <faq id="running_9">
+            <question>Why do I get
+      a <code>LinkageError</code> when using
+        XML interfaces in my test?</question>
+            <answer><p>
+      <i>(Submitted by: Scott Stirling)</i>
+    </p>
+    <p>
+      The workaround as of JUnit 3.7 is to
+      add <code>org.w3c.dom.*</code> and <code>org.xml.sax.*</code> to
+      your <code>excluded.properties</code>.
+    </p>
+    <p>
+      It's just a matter of time before this fix becomes incorporated
+      into the released version of
+      JUnit's <code>excluded.properties</code>, since JAXP is a
+      standard part of JDK 1.4. It will be just like
+      excluding <code>org.omg.*</code>. By the way, if you download
+      the JUnit source from its Sourceforge CVS, you will find that
+      these patterns have already been added to the default
+      excluded.properties and so has a pattern for JINI. In fact, here
+      is the current version in CVS, which demonstrates how to add
+      exclusions to the list too:
+    </p>
+    <pre class="prettyprint linenums">#
+# The list of excluded package paths for the TestCaseClassLoader
+#
+excluded.0=sun.*
+excluded.1=com.sun.*
+excluded.2=org.omg.*
+excluded.3=javax.*
+excluded.4=sunw.*
+excluded.5=java.*
+excluded.6=org.w3c.dom.*
+excluded.7=org.xml.sax.*
+excluded.8=net.jini.*</pre>
+    <p>
+      This is the most common case where the
+      default <code>excluded.properties</code> list needs
+      modification. The cause of the <code>LinkageError</code> is
+      related to using JAXP in your test cases. By JAXP I mean the
+      whole set of <code>javax.xml.*</code> classes and the
+      supporting <code>org.w3c.dom.*</code>
+      and <code>org.xml.sax.*</code> classes.
+    </p>
+    <p>
+      As stated above, the JUnit GUI TestRunners' classloader relies
+      on the <code>excluded.properties</code> for classes it should
+      delegate to the system classloader. JAXP is an unusual case
+      because it is a standard Java extension library dependent on
+      classes whose package names (<code>org.w3c.dom.*</code>
+      and <code>org.xml.sax.*</code>) do not begin with a standard
+      Java or Sun prefix. This is similar to the relationship
+      between <code>javax.rmi.*</code> and the <code>org.omg.*</code>
+      classes, which have been excluded by default in
+      JUnit'ss <code>excluded.properties</code> for a while.
+    </p>
+    <p>
+      What can happen, and frequently does when using the JUnit Swing
+      or AWT UI with test cases that reference, use or depend on JAXP
+      classes, such as Log4J, Apache SOAP, Axis, Cocoon, etc., is that
+      the JUnit class loader (properly)
+      delegates <code>javax.xml.*</code> classes it &quot;sees&quot;
+      to the system loader. But then the system loader, in the process
+      of initializing and loading that JAXP class, links and loads up
+      a bunch of <code>org.w3c.dom</code>/<code>org.xml.sax</code>
+      classes. When it does so, the JUnit custom classloader is not
+      involved at all because the system classloader never delegates
+      &quot;down&quot; or checks with custom classloaders to see if a
+      class is already loaded. At any point after this, if the JUnit
+      loader is asked to load
+      an <code>org.w3c.dom</code>/<code>org.xml.sax</code> class that
+      it's never seen before, it will try to load it because the
+      class' name doesn't match any of the patterns in the default
+      exclude list.  That's when a <code>LinkageError</code>
+      occurs. This is really a flaw in the JUnit classloader design,
+      but there is the workaround given above.
+    </p>
+    <p>
+      Java 2 JVMs keep classes (remember, classes and objects, though
+      related, are different entities to the JVM - I'm talking
+      about classes here, not object instances) in namespaces,
+      identifying them by their fully qualified classname plus the
+      instance of their defining (not initiating) loader. The JVM will
+      attempt to assign all unloaded classes referenced by an already
+      defined and loaded class to that class's defining loader. The
+      JVM's classresolver routine (implemented as a C function in the
+      JVM source code) keeps track of all these class loading events
+      and &quot;sees&quot; if another classloader (such as the JUnit
+      custom loader) attempts to define a class that has already been
+      defined by the system loader. According to the rules of Java 2
+      loader constraints, in case a class has already been defined by
+      the system loader, any attempts to load a class should first be
+      delegated to the system loader. A &quot;proper&quot; way for
+      JUnit to handle this feature would be to load classes from a
+      repository other than the CLASSPATH that the system classloader
+      knows nothing about. And then the JUnit custom classloader could
+      follow the standard Java 2 delegation model, which is to always
+      delegate class loading to the system loader, and only attempt to
+      load if that fails. Since they both load from the CLASSPATH in
+      the current model, if the JUnit loader delegated like it's
+      supposed to, it would never get to load any classes since the
+      system loader would always find them.
+    </p>
+    <p>
+      You could try to hack around this in the JUnit source by
+      catching the <code>LinkageError</code> in
+      TestCaseClassLoader's <code>loadClass()</code> method and then
+      making a recovery call to <code>findSystemClass()</code> --
+      thereby delegating to the system loader after the violation has
+      been caught. But this hack only works some of the time, because
+      now you can have the reverse problem where the JUnit loader will
+      load a host of <code>org.w3c.dom</code>/<code>org.xml.sax</code>
+      classes, and then the system loader violates the loader
+      contraints at some point when it tries to do exactly what I
+      described above with JAXP because it doesn't ever delegate to
+      its logical child (the JUnit loader). Inevitably, if your test
+      cases use many JAXP and related XML classes, one or the other
+      classloader will end up violating the constraints whatever you
+      do.
+    </p></answer>
+        </faq>
+        <faq id="running_11">
+            <question>Why do I get the warning
+      "AssertionFailedError: No
+        tests found in XXX" when I run my test?</question>
+            <answer><p>
+      Make sure you have more or more method annotated with <code>@Test</code>.
+    </p>
+    <p>
+      For example:
+    </p>
+<pre class="prettyprint linenums">@Test
+public void testSomething() {
+}</pre></answer>
+        </faq>
+        <faq id="running_12">
+            <question>Why do I see "Unknown Source" in the
+      stack trace of
+a test failure, rather than the source file's line number?</question>
+            <answer><p>
+      The debug option for the Java compiler must be enabled in order
+      to see source file and line number information in a stack trace.
+    </p>
+    <p>
+      When invoking the Java compiler from the command line, use
+      the <code>-g</code> option to generate all debugging info.
+    </p>
+    <p>
+      When invoking the Java compiler from an 
+      <a href="http://jakarta.apache.org/ant/index.html">Ant</a> task, use the
+      <code>debug="on"</code> attribute.  For example:
+    </p>
+      <pre>&lt;javac srcdir="${src}" destdir="${build}" debug="on" /&gt;</pre>
+    <p>
+      When using older JVMs pre-Hotspot (JDK 1.1 and most/all 1.2),
+      run JUnit with the <code>-DJAVA_COMPILER=none</code> JMV command
+      line argument to prevent runtime JIT compilation from obscuring
+      line number info.
+    </p>
+    <p>
+      Compiling the test source with debug enabled will show the line
+      where the assertion failed.  Compiling the non-test source with
+      debug enabled will show the line where an exception was raised
+      in the class under test.
+    </p></answer>
+        </faq>
+        <faq id="running_15">
+            <question>How do I organize all test classes
+        in a TestSuite automatically and not use or manage a TestSuite
+        explicitly?</question>
+            <answer><p>
+      <i>(Submitted by: Bill de hora)</i>
+    </p>
+    <p>
+      There are a number of ways to do this:
+    </p>
+    <ol>
+      <li>
+        <p>
+          In Ant, use the <code>junit</code> task and
+          the <code>batchtest</code> element:
+        </p>
+        <div>
+          <pre class="prettyprint linenums">
+&lt;junit printsummary="yes" haltonfailure="yes"&gt;
+  ...
+  &lt;batchtest fork="yes"&gt;
+    &lt;fileset dir="${src.dir}"&gt;
+       &lt;include name="**/*Test.java" /&gt;
+       &lt;include name="**/Test*.java" /&gt;
+    &lt;/fileset&gt;
+  &lt;/batchtest&gt;
+&lt;/junit&gt; 
+          </pre>
+        </div>
+        <p>
+          Idiomatic naming patterns for unit tests
+          are <code>Test*.java</code> and <code>*Test.java</code>.
+          Documentation and examples are at <a
+                                               href="http://ant.apache.org/manual/OptionalTasks/junit.html">http://ant.apache.org/manual/OptionalTasks/junit.html</a>.
+        </p>
+      </li>
+      <li>
+        <p>
+          Use the <code>DirectorySuiteBuilder</code>
+          and <code>ArchiveSuiteBuilder</code> (for jar/zip files)
+          classes provided by JUnit-addons project:
+        </p>
+<pre class="prettyprint linenums">DirectorySuiteBuilder builder = new DirectorySuiteBuilder();
+builder.setSuffix("Test");
+Test suite = builer.suite("/home/project/myproject/tests");</pre>
+        <p>
+          Documentation and examples are at <a
+                                               href="http://junit-addons.sourceforge.net/">http://junit-addons.sourceforge.net</a>.
+        </p>
+      </li>
+      <li>
+        <p>
+          Write your own custom suite builder. 
+        </p>
+        <p>
+          Have your test classes implement an interface and write a
+          treewalker to load each class in a directory, inspect the
+          class, and add any classes that implement the interface to a
+          TestSuite.
+        </p>
+        <p>
+          You might only want to do this if you are <b>very</b>
+          uncomfortable with using a naming convention for test
+          classes. Aside from being slow for larger suites, ultimately
+          it's arguable whether it's more effort to follow a naming
+          convention that have test classes implement an interface!
+        </p>
+        <p>
+          An example of this approach is at 
+          <a href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html">http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html</a>.  
+        </p>
+    </li>
+</ol>
+    </answer>
+        </faq>
+    </part>
+    <part id="best">
+        <title>Best Practices</title>
+        <faq id="best_1">
+            <question>When should tests be written?</question>
+            <answer><p>
+      Tests should be written before the code.  Test-first programming
+      is practiced by only writing new code when an automated test is
+      failing.
+    </p>
+    <p>
+      Good tests tell you how to best design the system for its
+      intended use.  They effectively communicate in an executable
+      format how to use the software.  They also prevent tendencies to
+      over-build the system based on speculation.  When all the tests
+      pass, you know you're done!
+    </p>
+    <p>
+      Whenever a customer test fails or a bug is reported, first write
+      the necessary unit test(s) to expose the bug(s), <em>then</em>
+      fix them. This makes it almost impossible for that particular
+      bug to resurface later.
+    </p>
+    <p>
+      Test-driven development is a lot more fun than writing tests
+      after the code seems to be working.  Give it a try!
+    </p></answer>
+        </faq>
+        <faq id="best_2">
+            <question>Do I have to write a test for
+        everything?</question>
+            <answer><p>
+      No, just test everything that could reasonably break.  
+    </p>
+    <p>
+      Be practical and maximize your testing investment.  Remember
+      that investments in testing are equal investments in design.  If
+      defects aren't being reported and your design responds well to
+      change, then you're probably testing enough.  If you're spending
+      a lot of time fixing defects and your design is difficult to
+      grow, you should write more tests.
+    </p>
+    <p>
+      If something is difficult to test, it's usually an opportunity
+      for a design improvement.  Look to improve the design so that
+      it's easier to test, and by doing so a better design will
+      usually emerge.
+    </p></answer>
+        </faq>
+        <faq id="best_3">
+            <question>How simple is 'too simple to break'?</question>
+            <answer><p>
+      <i>(Submitted by: J. B. Rainsberger)</i>
+    </p>
+    <p>
+      The general philosophy is this: if it can't break <em>on its
+      own</em>, it's too simple to break.
+    </p>
+    <p>
+      First example is the <code>getX()</code> method. Suppose
+      the <code>getX()</code> method only answers the value of an
+      instance variable. In that case, <code>getX()</code> cannot
+      break unless either the compiler or the interpreter is also
+      broken. For that reason, don't test <code>getX()</code>; there
+      is no benefit.  The same is true of the <code>setX()</code>
+      method, although if your <code>setX()</code> method does any
+      parameter validation or has any side effects, you likely need to
+      test it.
+    </p>
+    <p>
+      Next example: suppose you have written a method that does
+      nothing but forward parameters into a method called on another
+      object. That method is too simple to break.
+    </p>
+<pre class="prettyprint linenums">public void myMethod(final int a, final String b) {
+    myCollaborator.anotherMethod(a, b);
+}</pre>
+    <p>
+      <code>myMethod</code> cannot possibly break because it does nothing: it 
+      forwards its input to another object and that's all. 
+    </p>
+    <p>
+      The only precondition for this method is "myCollaborator !=
+      null", but that is generally the responsibility of the
+      constructor, and not of myMethod. If you are concerned, add a
+      test to verify that myCollaborator is always set to something
+      non-null by every constructor.
+    </p>
+    <p>
+      The only way myMethod could break would be
+      if <code>myCollaborator.anotherMethod()</code> were broken. In
+      that case, test <code>myCollaborator</code>, and not the current
+      class.
+    </p>
+    <p>
+      It is true that adding tests for even these simple methods
+      guards against the possibility that someone refactors and makes
+      the methods "not-so-simple" anymore. In that case, though, the
+      refactorer needs to be aware that the method is now complex
+      enough to break, and should write tests for it -- and preferably
+      before the refactoring.
+    </p>
+    <p>
+      Another example: suppose you have a JSP and, like a good
+      programmer, you have removed all business logic from it. All it
+      does is provide a layout for a number of JavaBeans and never
+      does anything that could change the value of any object. That
+      JSP is too simple to break, and since JSPs are notoriously
+      annoying to test, you should strive to make all your JSPs too
+      simple to break.
+    </p>
+    <p>
+      Here's the way testing goes: 
+    </p>
+    <pre class="prettyprint linenums">becomeTimidAndTestEverything
+while writingTheSameThingOverAndOverAgain
+    becomeMoreAggressive
+    writeFewerTests
+    writeTestsForMoreInterestingCases
+    if getBurnedByStupidDefect
+        feelStupid
+        becomeTimidAndTestEverything
+    end
+end</pre>
+    <p>
+      The loop, as you can see, never terminates.
+    </p></answer>
+        </faq>
+        <faq id="best_4">
+            <question>How often should I run my tests?</question>
+            <answer><p>
+      Run all your unit tests as often as possible, ideally every time
+      the code is changed.  Make sure all your unit tests always run
+      at 100%.  Frequent testing gives you confidence that your
+      changes didn't break anything and generally lowers the stress of
+      programming in the dark.
+    </p>
+    <p>
+      For larger systems, you may just run specific test suites that
+      are relevant to the code you're working on.
+    </p>
+    <p>
+      Run all your acceptance, integration, stress, and unit tests at
+      least once per day (or night).
+    </p>
+    <p>
+      If you're using Eclipse, be sure to check out David Saff's 
+      <a href="http://pag.csail.mit.edu/continuoustesting/">continuous
+      testing plug-in</a>.
+    </p></answer>
+        </faq>
+        <faq id="best_5">
+            <question>What do I do when a defect is reported?</question>
+            <answer><p>
+      Test-driven development generally lowers the defect density of
+      software.  But we're all fallible, so sometimes a defect will
+      slip through.  When this happens, write a failing test that
+      exposes the defect.  When the test passes, you know the defect
+      is fixed!
+    </p>
+    <p>
+      Don't forget to use this as a learning opportunity.  Perhaps the
+      defect could have been prevented by being more aggressive about
+      testing everything that could reasonably break.
+    </p></answer>
+        </faq>
+        <faq id="best_6">
+            <question>Why not just use <code>System.out.println()</code>?</question>
+            <answer><p>
+      Inserting debug statements into code is a low-tech method for
+      debugging it.  It usually requires that output be scanned
+      manually every time the program is run to ensure that the code
+      is doing what's expected.
+    </p>
+    <p>
+      It generally takes less time in the long run to codify
+      expectations in the form of an automated JUnit test that retains
+      its value over time.  If it's difficult to write a test to
+      assert expectations, the tests may be telling you that shorter
+      and more cohesive methods would improve your design.
+    </p></answer>
+        </faq>
+        <faq id="best_7">
+            <question>Why not just use a debugger?</question>
+            <answer><p>
+      Debuggers are commonly used to step through code and inspect
+      that the variables along the way contain the expected values.
+      But stepping through a program in a debugger is a manual process
+      that requires tedious visual inspections.  In essence, the
+      debugging session is nothing more than a manual check of
+      expected vs. actual results.  Moreover, every time the program
+      changes we must manually step back through the program in the
+      debugger to ensure that nothing broke.
+    </p>
+    <p>
+      It generally takes less time to codify expectations in the form
+      of an automated JUnit test that retains its value over time.  If
+      it's difficult to write a test to assert expected values, the
+      tests may be telling you that shorter and more cohesive methods
+      would improve your design.
+    </p></answer>
+        </faq>
+   </part>
+    <part id="misc">
+        <title>Miscellaneous</title>
+        <faq id="misc_1">
+            <question>How do I integrate JUnit with my IDE?</question>
+            <answer><p>
+      The JUnit home page maintains a list of <a
+      href="http://www.junit.org/news/ide/index.htm">IDE integration
+      instructions</a>.
+    </p></answer>
+        </faq>
+        <faq id="misc_2">
+            <question>How do I launch a debugger when a test fails?</question>
+            <answer>    <p>
+      Start the <code>TestRunner</code> under the debugger and
+      configure the debugger so that it catches
+      the <code>junit.framework.AssertionFailedError</code>.
+    </p>
+    <p>
+      How you configure this depends on the debugger you prefer to
+      use. Most Java debuggers provide support to stop the program
+      when a specific exception is raised.
+    </p>
+    <p>
+      Notice that this will only launch the debugger when an expected
+      failure occurs.
+    </p></answer>
+        </faq>
+        <faq id="misc_3">
+            <question>Where can I find unit testing frameworks
+      similar to JUnit for other languages?</question>
+            <answer><p>
+      XProgramming.com maintains a complete list of available <a
+      href="http://www.xprogramming.com/software.htm">xUnit testing
+      frameworks</a>.
+    </p></answer>
+        </faq>
+    </part>
+</faqs>
\ No newline at end of file
diff --git a/src/site/markdown/cookbook.md b/src/site/markdown/cookbook.md
new file mode 100644
index 0000000..3c13c5c
--- /dev/null
+++ b/src/site/markdown/cookbook.md
@@ -0,0 +1,127 @@
+Title: JUnit Cookbook
+Author: Kent Beck, Erich Gamma
+
+
+Here is a short cookbook showing you the steps you can follow in writing
+and organizing your own tests using JUnit.
+
+## Simple Test Case
+
+How do you write testing code?
+
+The simplest way is as an expression in a debugger. You can change debug
+expressions without recompiling, and you can wait to decide what to write
+until you have seen the running objects. You can also write test expressions
+as statements which print to the standard output stream. Both styles of
+tests are limited because they require human judgment to analyze their
+results. Also, they don't compose nicely- you can only execute one debug
+expression at a time and a program with too many print statements causes
+the dreaded "Scroll Blindness".
+
+JUnit tests do not require human judgment to interpret, and it is easy
+to run many of them at the same time. When you need to test something,
+here is what you do:
+
+1.  Annotate a method with `@org.junit.Test`
+
+1. When you want to check a value, import `org.junit.Assert.*` statically, call `assertTrue()` and pass a boolean
+that is true if the test succeeds
+
+For example, to test that the sum of two Moneys with the same currency
+contains a value which is the sum of the values of the two Moneys, write:
+
+    @Test
+    public void simpleAdd() {
+        Money m12CHF= new Money(12, "CHF");
+        Money m14CHF= new Money(14, "CHF");
+        Money expected= new Money(26, "CHF");
+        Money result= m12CHF.add(m14CHF);
+        assertTrue(expected.equals(result));
+    }
+
+If you want to write a test similar to one you have already written, write
+a Fixture instead.
+
+## Fixture
+
+What if you have two or more tests that operate on the same or similar
+sets of objects?
+
+Tests need to run against the background of a known set of objects.
+This set of objects is called a test fixture. When you are writing tests
+you will often find that you spend more time writing the code to set up
+the fixture than you do in actually testing values.
+
+To some extent, you can make writing the fixture code easier by paying
+careful attention to the constructors you write. However, a much bigger
+savings comes from sharing fixture code. Often, you will be able to use
+the same fixture for several different tests. Each case will send slightly
+different messages or parameters to the fixture and will check for different
+results.
+
+When you have a common fixture, here is what you do:
+
+1.  Add a field for each part of the fixture
+2.  Annotate a method with `@org.junit.Before` and initialize the variables in that method
+3.  Annotate a method with `@org.junit.After` to release any permanent resources you allocated in `setUp`
+
+For example, to write several test cases that want to work with different
+combinations of 12 Swiss Francs, 14 Swiss Francs, and 28 US Dollars, first
+create a fixture:
+
+    public class MoneyTest {
+        private Money f12CHF;
+        private Money f14CHF;
+        private Money f28USD;
+
+        @Before public void setUp() {
+            f12CHF= new Money(12, "CHF");
+            f14CHF= new Money(14, "CHF");
+            f28USD= new Money(28, "USD");
+        }
+    }
+
+Once you have the Fixture in place, you can write as many Test Cases as
+you'd like. Add as many test methods (annotated with `@Test`) as you'd like.
+
+## Running Tests
+
+How do you run your tests and collect their results?
+
+Once you have tests, you'll want to run them. JUnit provides tools
+to define the suite to be run and to display its results. To run tests and see the
+results on the console, run this from a Java program:
+
+    org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...);
+
+or this from the command line, with both your test class and junit on the classpath:
+
+    java org.junit.runner.JUnitCore TestClass1.class [...other test classes...]
+
+You make your JUnit 4 test classes accessible to a TestRunner designed to work with earlier versions of JUnit,
+declare a static method _suite_
+that returns a test.
+
+    public static junit.framework.Test suite() {
+        return new JUnit4TestAdapter(Example.class);
+    }
+
+## Expected Exceptions
+
+How do you verify that code throws exceptions as expected?
+
+Verifying that code completes normally is only part of programming. Making sure the code
+behaves as expected in exceptional situations is part of the craft of programming too. For example:
+
+    new ArrayList<Object>().get(0);
+
+This code should throw an `IndexOutOfBoundsException`. The `@Test` annotation has an optional parameter `expected`
+that takes as values subclasses of `Throwable`. If we wanted to verify that `ArrayList` throws the correct exception,
+we would write:
+
+    @Test(expected= IndexOutOfBoundsException.class)
+    public void empty() {
+        new ArrayList<Object>().get(0);
+    }
+
+* * *
diff --git a/src/site/resources/css/hopscotch-0.1.2.min.css b/src/site/resources/css/hopscotch-0.1.2.min.css
new file mode 100644
index 0000000..a8ebce9
--- /dev/null
+++ b/src/site/resources/css/hopscotch-0.1.2.min.css
@@ -0,0 +1,17 @@
+/**!
+*
+* Copyright 2013 LinkedIn Corp. All rights reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+.animated{-webkit-animation-fill-mode:both;-moz-animation-fill-mode:both;-ms-animation-fill-mode:both;-o-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:1s;-moz-animation-duration:1s;-ms-animation-duration:1s;-o-animation-duration:1s;animation-duration:1s}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translateY(20px)}100%{opacity:1;-webkit-transform:translateY(0)}}@-moz-keyframes fadeInUp{0%{opacity:0;-moz-transform:translateY(20px)}100%{opacity:1;-moz-transform:translateY(0)}}@-o-keyframes fadeInUp{0%{opacity:0;-o-transform:translateY(20px)}100%{opacity:1;-o-transform:translateY(0)}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.fade-in-up{-webkit-animation-name:fadeInUp;-moz-animation-name:fadeInUp;-o-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translateY(-20px)}100%{opacity:1;-webkit-transform:translateY(0)}}@-moz-keyframes fadeInDown{0%{opacity:0;-moz-transform:translateY(-20px)}100%{opacity:1;-moz-transform:translateY(0)}}@-o-keyframes fadeInDown{0%{opacity:0;-ms-transform:translateY(-20px)}100%{opacity:1;-ms-transform:translateY(0)}}@keyframes fadeInDown{0%{opacity:0;transform:translateY(-20px)}100%{opacity:1;transform:translateY(0)}}.fade-in-down{-webkit-animation-name:fadeInDown;-moz-animation-name:fadeInDown;-o-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translateX(-20px)}100%{opacity:1;-webkit-transform:translateX(0)}}@-moz-keyframes fadeInRight{0%{opacity:0;-moz-transform:translateX(-20px)}100%{opacity:1;-moz-transform:translateX(0)}}@-o-keyframes fadeInRight{0%{opacity:0;-o-transform:translateX(-20px)}100%{opacity:1;-o-transform:translateX(0)}}@keyframes fadeInRight{0%{opacity:0;transform:translateX(-20px)}100%{opacity:1;transform:translateX(0)}}.fade-in-right{-webkit-animation-name:fadeInRight;-moz-animation-name:fadeInRight;-o-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translateX(20px)}100%{opacity:1;-webkit-transform:translateX(0)}}@-moz-keyframes fadeInLeft{0%{opacity:0;-moz-transform:translateX(20px)}100%{opacity:1;-moz-transform:translateX(0)}}@-o-keyframes fadeInLeft{0%{opacity:0;-o-transform:translateX(20px)}100%{opacity:1;-o-transform:translateX(0)}}@keyframes fadeInLeft{0%{opacity:0;transform:translateX(20px)}100%{opacity:1;transform:translateX(0)}}.fade-in-left{-webkit-animation-name:fadeInLeft;-moz-animation-name:fadeInLeft;-o-animation-name:fadeInLeft;animation-name:fadeInLeft}div.hopscotch-bubble .hopscotch-nav-button{font-weight:bold;border-width:1px;border-style:solid;cursor:pointer;margin:0;overflow:visible;text-decoration:none!important;width:auto;padding:0 10px;height:26px;line-height:24px;font-size:12px;*zoom:1;white-space:nowrap;display:-moz-inline-stack;display:inline-block;*vertical-align:auto;zoom:1;*display:inline;vertical-align:middle;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}div.hopscotch-bubble .hopscotch-nav-button:hover{*zoom:1;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.25);box-shadow:0 1px 3px rgba(0,0,0,0.25)}div.hopscotch-bubble .hopscotch-nav-button:active{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.25) inset;-moz-box-shadow:0 1px 2px rgba(0,0,0,0.25) inset;box-shadow:0 1px 2px rgba(0,0,0,0.25) inset}div.hopscotch-bubble .hopscotch-nav-button.next{border-color:#1b5480;color:#fff;margin:0 0 0 10px;text-shadow:0 1px 1px rgba(0,0,0,0.35);background-color:#287bbc;filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#287bbc',endColorstr='#23639a');background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0%,#287bbc),color-stop(100%,#23639a));background-image:-webkit-linear-gradient(top,#287bbc 0,#23639a 100%);background-image:-moz-linear-gradient(top,#287bbc 0,#23639a 100%);background-image:-o-linear-gradient(top,#287bbc 0,#23639a 100%);background-image:linear-gradient(top,#287bbc 0,#23639a 100%)}div.hopscotch-bubble .hopscotch-nav-button.next:hover{background-color:#2672ae;filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#2672ae',endColorstr='#1e4f7e');background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0%,#2672ae),color-stop(100%,#1e4f7e));background-image:-webkit-linear-gradient(top,#2672ae 0,#1e4f7e 100%);background-image:-moz-linear-gradient(top,#2672ae 0,#1e4f7e 100%);background-image:-o-linear-gradient(top,#2672ae 0,#1e4f7e 100%);background-image:linear-gradient(top,#2672ae 0,#1e4f7e 100%)}div.hopscotch-bubble .hopscotch-nav-button.prev{border-color:#a7a7a7;color:#444;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f2f2f2;filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#f2f2f2',endColorstr='#e9e9e9');background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0%,#f2f2f2),color-stop(100%,#e9e9e9));background-image:-webkit-linear-gradient(top,#f2f2f2 0,#e9e9e9 100%);background-image:-moz-linear-gradient(top,#f2f2f2 0,#e9e9e9 100%);background-image:-o-linear-gradient(top,#f2f2f2 0,#e9e9e9 100%);background-image:linear-gradient(top,#f2f2f2 0,#e9e9e9 100%)}div.hopscotch-bubble .hopscotch-nav-button.prev:hover{background-color:#e8e8e8;filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#FFE8E8E8',endColorstr='#FFA9A9A9');background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0%,#e8e8e8),color-stop(13%,#e3e3e3),color-stop(32%,#d7d7d7),color-stop(71%,#b9b9b9),color-stop(100%,#a9a9a9));background-image:-webkit-linear-gradient(top,#e8e8e8 0,#e3e3e3 13%,#d7d7d7 32%,#b9b9b9 71%,#a9a9a9 100%);background-image:-moz-linear-gradient(top,#e8e8e8 0,#e3e3e3 13%,#d7d7d7 32%,#b9b9b9 71%,#a9a9a9 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#e3e3e3 13%,#d7d7d7 32%,#b9b9b9 71%,#a9a9a9 100%);background-image:linear-gradient(top,#e8e8e8 0,#e3e3e3 13%,#d7d7d7 32%,#b9b9b9 71%,#a9a9a9 100%)}div.hopscotch-bubble{background-color:#fff;border:5px solid #000;border:5px solid rgba(0,0,0,0.5);color:#333;font-family:Helvetica,Arial;font-size:13px;position:absolute;z-index:999999;-moz-background-clip:padding;-webkit-background-clip:padding;background-clip:padding-box}div.hopscotch-bubble.animate{-moz-transition-property:top,left;-moz-transition-duration:1s;-moz-transition-timing-function:ease-in-out;-ms-transition-property:top,left;-ms-transition-duration:1s;-ms-transition-timing-function:ease-in-out;-o-transition-property:top,left;-o-transition-duration:1s;-o-transition-timing-function:ease-in-out;-webkit-transition-property:top,left;-webkit-transition-duration:1s;-webkit-transition-timing-function:ease-in-out;transition-property:top,left;transition-duration:1s;transition-timing-function:ease-in-out}div.hopscotch-bubble.invisible{opacity:0}div.hopscotch-bubble.hide,div.hopscotch-bubble .hide,div.hopscotch-bubble .hide-all{display:none}div.hopscotch-bubble h3{color:#000;font-family:Helvetica,Arial;font-size:16px;font-weight:bold;line-height:19px;margin:-1px 15px 0 0;padding:0}div.hopscotch-bubble .hopscotch-bubble-container{padding:15px;position:relative;text-align:left;-webkit-font-smoothing:antialiased}div.hopscotch-bubble .hopscotch-content{font-family:Helvetica,Arial;font-weight:normal;line-height:17px;margin:-5px 0 11px;padding-top:8px}div.hopscotch-bubble .hopscotch-bubble-content{margin:0 0 0 40px}div.hopscotch-bubble.no-number .hopscotch-bubble-content{margin:0}div.hopscotch-bubble .hopscotch-bubble-close{color:#000;background:transparent url(../img/sprite-green-0.3.png) -192px -92px no-repeat;display:block;padding:8px;position:absolute;text-decoration:none;text-indent:-9999px;width:8px;height:8px;top:0;right:0}div.hopscotch-bubble .hopscotch-bubble-close.hide,div.hopscotch-bubble .hopscotch-bubble-close.hide-all{display:none}div.hopscotch-bubble .hopscotch-bubble-number{background:transparent url(../img/sprite-green-0.3.png) 0 0 no-repeat;color:#fff;display:block;float:left;font-size:17px;font-weight:bold;line-height:31px;padding:0 10px 0 0;text-align:center;width:30px;height:30px}div.hopscotch-bubble .hopscotch-bubble-arrow-container{position:absolute;width:34px;height:34px}div.hopscotch-bubble .hopscotch-bubble-arrow-container .hopscotch-bubble-arrow,div.hopscotch-bubble .hopscotch-bubble-arrow-container .hopscotch-bubble-arrow-border{width:0;height:0}div.hopscotch-bubble .hopscotch-bubble-arrow-container.up{top:-22px;left:10px}div.hopscotch-bubble .hopscotch-bubble-arrow-container.up .hopscotch-bubble-arrow{border-bottom:17px solid #fff;border-left:17px solid transparent;border-right:17px solid transparent;position:relative;top:-10px}div.hopscotch-bubble .hopscotch-bubble-arrow-container.up .hopscotch-bubble-arrow-border{border-bottom:17px solid #000;border-bottom:17px solid rgba(0,0,0,0.5);border-left:17px solid transparent;border-right:17px solid transparent}div.hopscotch-bubble .hopscotch-bubble-arrow-container.down{bottom:-39px;left:10px}div.hopscotch-bubble .hopscotch-bubble-arrow-container.down .hopscotch-bubble-arrow{border-top:17px solid #fff;border-left:17px solid transparent;border-right:17px solid transparent;position:relative;top:-24px}div.hopscotch-bubble .hopscotch-bubble-arrow-container.down .hopscotch-bubble-arrow-border{border-top:17px solid #000;border-top:17px solid rgba(0,0,0,0.5);border-left:17px solid transparent;border-right:17px solid transparent}div.hopscotch-bubble .hopscotch-bubble-arrow-container.left{top:10px;left:-22px}div.hopscotch-bubble .hopscotch-bubble-arrow-container.left .hopscotch-bubble-arrow{border-bottom:17px solid transparent;border-right:17px solid #fff;border-top:17px solid transparent;position:relative;left:7px;top:-34px}div.hopscotch-bubble .hopscotch-bubble-arrow-container.left .hopscotch-bubble-arrow-border{border-right:17px solid #000;border-right:17px solid rgba(0,0,0,0.5);border-bottom:17px solid transparent;border-top:17px solid transparent}div.hopscotch-bubble .hopscotch-bubble-arrow-container.right{top:10px;right:-39px}div.hopscotch-bubble .hopscotch-bubble-arrow-container.right .hopscotch-bubble-arrow{border-bottom:17px solid transparent;border-left:17px solid #fff;border-top:17px solid transparent;position:relative;left:-7px;top:-34px}div.hopscotch-bubble .hopscotch-bubble-arrow-container.right .hopscotch-bubble-arrow-border{border-left:17px solid #000;border-left:17px solid rgba(0,0,0,0.5);border-bottom:17px solid transparent;border-top:17px solid transparent}div.hopscotch-bubble .hopscotch-actions{margin:10px 0 0;text-align:right}
\ No newline at end of file
diff --git a/src/site/resources/css/plain-links.css b/src/site/resources/css/plain-links.css
new file mode 100644
index 0000000..2e876c4
--- /dev/null
+++ b/src/site/resources/css/plain-links.css
@@ -0,0 +1,4 @@
+a.externalLink {
+	background: none !important;
+	padding-right: 0 !important;
+}
\ No newline at end of file
diff --git a/src/site/resources/images/junit-logo.png b/src/site/resources/images/junit-logo.png
new file mode 100644
index 0000000..9b514f3
--- /dev/null
+++ b/src/site/resources/images/junit-logo.png
Binary files differ
diff --git a/src/site/resources/images/junit-logo.svg b/src/site/resources/images/junit-logo.svg
new file mode 100644
index 0000000..e542034
--- /dev/null
+++ b/src/site/resources/images/junit-logo.svg
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   width="160"
+   height="64"
+   id="svg2"
+   version="1.1">
+  <defs
+     id="defs4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     transform="translate(-357.84542,-237.65072)">
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2985"
+       style="font-size:72px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Century Schoolbook;-inkscape-font-specification:Century Schoolbook Bold"
+       transform="translate(282.8005,86.096824)"><flowRegion
+         id="flowRegion2987"><rect
+           id="rect2989"
+           width="520"
+           height="117.14286"
+           x="80"
+           y="135.21933"
+           style="font-size:72px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Century Schoolbook;-inkscape-font-specification:Century Schoolbook Bold" /></flowRegion><flowPara
+         id="flowPara2991"><flowSpan
+           style="letter-spacing:-8px;fill:#4e9a06"
+           id="flowSpan3058">J</flowSpan><flowSpan
+           style="fill:#cc0000"
+           id="flowSpan3060"><flowSpan
+             style="font-size:64px;letter-spacing:-7px"
+             id="flowSpan3064">U</flowSpan><flowSpan
+             style="font-size:48px;font-weight:normal;-inkscape-font-specification:Century Schoolbook"
+             id="flowSpan3062"><flowSpan
+   style="letter-spacing:0px"
+   id="flowSpan3066">n</flowSpan>it</flowSpan></flowSpan></flowPara></flowRoot>  </g>
+</svg>
diff --git a/src/site/resources/scripts/hopscotch-0.1.2.min.js b/src/site/resources/scripts/hopscotch-0.1.2.min.js
new file mode 100644
index 0000000..1d149d8
--- /dev/null
+++ b/src/site/resources/scripts/hopscotch-0.1.2.min.js
@@ -0,0 +1,17 @@
+/**!
+*
+* Copyright 2013 LinkedIn Corp. All rights reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+!function(a,b){var c,d,e,f,g,h,i,j,k,l,m=window.Sizzle||null,n=a[b],o="undefined",p=!1,q=typeof window.jQuery!==o,r=!1,s=window.document;try{r=typeof window.sessionStorage!==o}catch(t){}l={smoothScroll:!0,scrollDuration:1e3,scrollTopMargin:200,showCloseButton:!0,showPrevButton:!1,showNextButton:!0,bubbleWidth:280,bubblePadding:15,arrowWidth:20,skipIfNoElement:!0,cookieName:"hopscotch.tour.state"},n||(Array.isArray||(Array.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)}),k=function(){p&&n.startTour()},h={addClass:function(a,b){var c,d,e,f;if(a.className){for(d=b.split(/\s+/),c=" "+a.className+" ",e=0,f=d.length;f>e;++e)c.indexOf(" "+d[e]+" ")<0&&(c+=d[e]+" ");a.className=c.replace(/^\s+|\s+$/g,"")}else a.className=b},removeClass:function(a,b){var c,d,e,f;for(d=b.split(/\s+/),c=" "+a.className+" ",e=0,f=d.length;f>e;++e)c=c.replace(" "+d[e]+" "," ");a.className=c.replace(/^\s+|\s+$/g,"")},getPixelValue:function(a){var b=typeof a;return"number"===b?a:"string"===b?parseInt(a,10):0},valOrDefault:function(a,b){return typeof a!==o?a:b},invokeCallbackArrayHelper:function(a){var b;return Array.isArray(a)&&(b=j[a[0]],"function"==typeof b)?b.apply(this,a.slice(1)):void 0},invokeCallbackArray:function(a){var b,c;if(Array.isArray(a)){if("string"==typeof a[0])return h.invokeCallbackArrayHelper(a);for(b=0,c=a.length;c>b;++b)h.invokeCallback(a[b])}},invokeCallback:function(a){return"function"==typeof a?a():"string"==typeof a&&j[a]?j[a]():h.invokeCallbackArray(a)},invokeEventCallbacks:function(a,b){var c,d,e=i[a];if(b)return this.invokeCallback(b);for(c=0,d=e.length;d>c;++c)this.invokeCallback(e[c].cb)},getScrollTop:function(){var a;return a=typeof window.pageYOffset!==o?window.pageYOffset:s.documentElement.scrollTop},getScrollLeft:function(){var a;return a=typeof window.pageXOffset!==o?window.pageXOffset:s.documentElement.scrollLeft},getWindowHeight:function(){return window.innerHeight||s.documentElement.clientHeight},getWindowWidth:function(){return window.innerWidth||s.documentElement.clientWidth},addEvtListener:function(a,b,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)},removeEvtListener:function(a,b,c){return a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c)},documentIsReady:function(){return"complete"===s.readyState||"interactive"===s.readyState},evtPreventDefault:function(a){a.preventDefault?a.preventDefault():event&&(event.returnValue=!1)},extend:function(a,b){var c;for(c in b)b.hasOwnProperty(c)&&(a[c]=b[c])},getStepTargetHelper:function(a){var b;return/^[#\.]/.test(a)?s.querySelector?s.querySelector(a):q?(b=jQuery(a),b.length?b[0]:null):m?(b=new m(a),b.length?b[0]:null):/^#[a-zA-Z][\w-_:.]*$/.test(a)?s.getElementById(a.substring(1)):null:s.getElementById(a)},getStepTarget:function(a){var b;if(!a||!a.target)return null;if("string"==typeof a.target)return a.target=h.getStepTargetHelper(a.target),a.target;if(Array.isArray(a.target)){var c,d;for(c=0,d=a.target.length;d>c;c++)if("string"==typeof a.target[c]&&(b=h.getStepTargetHelper(a.target[c])))return a.target=b,b;return null}return a.target},getI18NString:function(a){return g[a]||f[a]},setState:function(a,b,c){var d,e="";r?sessionStorage.setItem(a,b):(c&&(d=new Date,d.setTime(d.getTime()+24*c*60*60*1e3),e="; expires="+d.toGMTString()),s.cookie=a+"="+b+e+"; path=/")},getState:function(a){var b,c,d,e=a+"=",f=s.cookie.split(";");if(r)d=sessionStorage.getItem(a);else for(b=0;b<f.length;b++){for(c=f[b];" "===c.charAt(0);)c=c.substring(1,c.length);if(0===c.indexOf(e)){d=c.substring(e.length,c.length);break}}return d},clearState:function(a){r?sessionStorage.removeItem(a):this.setState(a,"",-1)}},h.addEvtListener(window,"load",k),i={next:[],prev:[],start:[],end:[],show:[],error:[],close:[]},j={},f={stepNums:null,nextBtn:"Next",prevBtn:"Back",doneBtn:"Done",skipBtn:"Skip",closeTooltip:"Close"},g={},d=function(a){this.init(a)},d.prototype={isShowing:!1,currStep:void 0,_createButton:function(a,b){var c=s.createElement("button"),d="hopscotch-nav-button";return c.id=a,b&&(c.innerHTML=b),d+=a.indexOf("prev")>=0?" prev":" next",h.addClass(c,d),c},setPosition:function(a){var b,c,d,e,f,g,i,j=6,k=h.getStepTarget(a),l=this.element,m=this.arrowEl;b=h.getPixelValue(a.width)||this.opt.bubbleWidth,d=h.valOrDefault(a.padding,this.opt.bubblePadding),h.removeClass(l,"fade-in-down fade-in-up fade-in-left fade-in-right"),!a.placement&&a.orientation&&(a.placement=a.orientation),e=k.getBoundingClientRect(),"top"===a.placement?(c=l.offsetHeight,f=e.top-c-this.opt.arrowWidth,g=e.left):"bottom"===a.placement?(f=e.bottom+this.opt.arrowWidth,g=e.left):"left"===a.placement?(f=e.top,g=e.left-b-2*d-2*j-this.opt.arrowWidth):"right"===a.placement&&(f=e.top,g=e.right+this.opt.arrowWidth),i="center"!==a.arrowOffset?h.getPixelValue(a.arrowOffset):a.arrowOffset,i?"top"===a.placement||"bottom"===a.placement?(m.style.top="",m.style.left="center"===i?b/2+d-m.offsetWidth/2+"px":i+"px"):("left"===a.placement||"right"===a.placement)&&(m.style.left="","center"===i?(c=c||l.offsetHeight,m.style.top=c/2+d-m.offsetHeight/2+"px"):m.style.top=i+"px"):(m.style.top="",m.style.left=""),"center"===a.xOffset?g=e.left+k.offsetWidth/2-b/2-d:g+=h.getPixelValue(a.xOffset),"center"===a.yOffset?(c=c||l.offsetHeight,f=e.top+k.offsetHeight/2-c/2-d):f+=h.getPixelValue(a.yOffset),a.fixedElement||(f+=h.getScrollTop(),g+=h.getScrollLeft()),l.style.position=a.fixedElement?"fixed":"absolute",l.style.top=f+"px",l.style.left=g+"px"},_initNavButtons:function(){var a=s.createElement("div");return this.prevBtnEl=this._createButton("hopscotch-prev",h.getI18NString("prevBtn")),this.nextBtnEl=this._createButton("hopscotch-next",h.getI18NString("nextBtn")),this.doneBtnEl=this._createButton("hopscotch-done",h.getI18NString("doneBtn")),this.ctaBtnEl=this._createButton("hopscotch-cta"),h.addClass(this.doneBtnEl,"hide"),a.appendChild(this.prevBtnEl),a.appendChild(this.ctaBtnEl),a.appendChild(this.nextBtnEl),a.appendChild(this.doneBtnEl),h.addEvtListener(this.prevBtnEl,"click",function(){n.prevStep(!0)}),h.addEvtListener(this.nextBtnEl,"click",function(){n.nextStep(!0)}),h.addEvtListener(this.doneBtnEl,"click",function(){n.endTour()}),a.className="hopscotch-actions",this.buttonsEl=a,this.containerEl.appendChild(a),this},_getCloseFn:function(){var a=this;return this.closeFn||(this.closeFn=function(b){a.opt.onClose&&h.invokeCallback(a.opt.onClose),a.opt.id&&!a.opt.isTourBubble?n.getCalloutManager().removeCallout(a.opt.id):a.destroy(),h.evtPreventDefault(b)}),this.closeFn},initCloseButton:function(){var a=s.createElement("a");return a.className="hopscotch-bubble-close",a.href="#",a.title=h.getI18NString("closeTooltip"),a.innerHTML=h.getI18NString("closeTooltip"),this.opt.isTourBubble?h.addEvtListener(a,"click",function(a){var b=n.getCurrStepNum(),c=n.getCurrTour(),d=b===c.steps.length-1;h.invokeEventCallbacks("close"),n.endTour(!0,d),a.preventDefault?a.preventDefault():event&&(event.returnValue=!1)}):h.addEvtListener(a,"click",this._getCloseFn()),h.valOrDefault(this.opt.showCloseButton,!0)||h.addClass(a,"hide"),this.closeBtnEl=a,this.containerEl.appendChild(a),this},_initArrow:function(){var a,b;return this.arrowEl=s.createElement("div"),this.arrowEl.className="hopscotch-bubble-arrow-container",b=s.createElement("div"),b.className="hopscotch-bubble-arrow-border",a=s.createElement("div"),a.className="hopscotch-bubble-arrow",this.arrowEl.appendChild(b),this.arrowEl.appendChild(a),this.element.appendChild(this.arrowEl),this},_setupCTAButton:function(a){var b=this;this._showButton(this.ctaBtnEl,!!a.showCTAButton),a.showCTAButton&&a.ctaLabel&&(this.ctaBtnEl.innerHTML=a.ctaLabel,this._ctaFn=function(){b.opt.isTourBubble||n.getCalloutManager().removeCallout(a.id),a.onCTA&&"function"==typeof a.onCTA&&a.onCTA()},h.addEvtListener(this.ctaBtnEl,"click",this._ctaFn))},_removeCTACallback:function(){this.ctaBtnEl&&this._ctaFn&&(h.removeEvtListener(this.ctaBtnEl,"click",this._ctaFn),this._ctaFn=null)},render:function(a,b,c,d){var e,f,g,i,j=this.element;return a?this.currStep=a:this.currStep&&(a=this.currStep),!a.placement&&a.orientation&&(a.placement=a.orientation),e=h.valOrDefault(a.showNextButton,this.opt.showNextButton),f=h.valOrDefault(a.showPrevButton,this.opt.showPrevButton),this.setTitle(a.title||""),this.setContent(a.content||""),this.opt.isTourBubble&&this.setNum(b),this.placement=a.placement,this.showPrevButton(this.prevBtnEl&&f&&b>0),this.showNextButton(this.nextBtnEl&&e&&!c),this.nextBtnEl.innerHTML=a.showSkip?h.getI18NString("skipBtn"):h.getI18NString("nextBtn"),c?h.removeClass(this.doneBtnEl,"hide"):h.addClass(this.doneBtnEl,"hide"),this._setupCTAButton(a),this._setArrow(a.placement),g=h.getPixelValue(a.width)||this.opt.bubbleWidth,i=h.valOrDefault(a.padding,this.opt.bubblePadding),this.containerEl.style.width=g+"px",this.containerEl.style.padding=i+"px",j.style.zIndex=a.zindex||"","top"===a.placement?(j.style.top="-9999px",j.style.left="-9999px",h.removeClass(j,"hide"),this.setPosition(a),h.addClass(j,"hide")):this.setPosition(a),d&&d(!a.fixedElement),this},setTitle:function(a){return a?(this.titleEl.innerHTML=a,h.removeClass(this.titleEl,"hide")):h.addClass(this.titleEl,"hide"),this},setContent:function(a){return a?(this.contentEl.innerHTML=a,h.removeClass(this.contentEl,"hide")):h.addClass(this.contentEl,"hide"),this},setNum:function(a){var b=h.getI18NString("stepNums");b&&a<b.length?a=b[a]:a+=1,this.numberEl.innerHTML=a},_setArrow:function(a){h.removeClass(this.arrowEl,"down up right left"),"top"===a?h.addClass(this.arrowEl,"down"):"bottom"===a?h.addClass(this.arrowEl,"up"):"left"===a?h.addClass(this.arrowEl,"right"):"right"===a&&h.addClass(this.arrowEl,"left")},_getArrowDirection:function(){return"top"===this.placement?"down":"bottom"===this.placement?"up":"left"===this.placement?"right":"right"===this.placement?"left":void 0},show:function(){var a=this,b="fade-in-"+this._getArrowDirection(),c=1e3;return h.removeClass(this.element,"hide"),h.addClass(this.element,b),setTimeout(function(){h.removeClass(a.element,"invisible")},50),setTimeout(function(){h.removeClass(a.element,b)},c),this.isShowing=!0,this},hide:function(a){var b=this.element;return a=h.valOrDefault(a,!0),b.style.top="",b.style.left="",a?(h.addClass(b,"hide"),h.removeClass(b,"invisible")):(h.removeClass(b,"hide"),h.addClass(b,"invisible")),h.removeClass(b,"animate fade-in-up fade-in-down fade-in-right fade-in-left"),this.isShowing=!1,this},_showButton:function(a,b,c){var d="hide";c&&(d="hide-all"),typeof b===o&&(b=!0),b?h.removeClass(a,d):h.addClass(a,d)},showPrevButton:function(a){this._showButton(this.prevBtnEl,a)},showNextButton:function(a){this._showButton(this.nextBtnEl,a)},showCloseButton:function(a){this._showButton(this.closeBtnEl,a)},destroy:function(){var a=this.element;a&&a.parentNode.removeChild(a),this.closeBtnEl&&h.removeEvtListener(this.closeBtnEl,"click",this._getCloseFn()),this.ctaBtnEl&&this.onCTA&&this._removeCTACallback()},updateButtons:function(){this.showPrevButton(this.opt.showPrevButton),this.showNextButton(this.opt.showNextButton),this.showCloseButton(this.opt.showCloseButton),this.prevBtnEl.innerHTML=h.getI18NString("prevBtn"),this.nextBtnEl.innerHTML=h.getI18NString("nextBtn"),this.doneBtnEl.innerHTML=h.getI18NString("doneBtn")},init:function(a){var b,c,d,e=s.createElement("div"),f=s.createElement("div"),g=s.createElement("div"),i=this,j=!1;this.element=e,this.containerEl=f,this.titleEl=s.createElement("h3"),this.contentEl=s.createElement("div"),h.addClass(this.titleEl,"hopscotch-title"),h.addClass(this.contentEl,"hopscotch-content"),d={showPrevButton:l.showPrevButton,showNextButton:l.showNextButton,bubbleWidth:l.bubbleWidth,bubblePadding:l.bubblePadding,arrowWidth:l.arrowWidth,showNumber:!0,isTourBubble:!0},a=typeof a===o?{}:a,h.extend(d,a),this.opt=d,e.className="hopscotch-bubble animated",f.className="hopscotch-bubble-container",d.isTourBubble||(e.className+=" hopscotch-callout"),d.isTourBubble?(this.numberEl=s.createElement("span"),this.numberEl.className="hopscotch-bubble-number",f.appendChild(this.numberEl)):h.addClass(e,"no-number"),g.appendChild(this.titleEl),g.appendChild(this.contentEl),g.className="hopscotch-bubble-content",f.appendChild(g),e.appendChild(f),this._initNavButtons(),this.initCloseButton(),this._initArrow(),b=function(){!j&&i.isShowing&&(j=!0,setTimeout(function(){i.setPosition(i.currStep),j=!1},100))},h.addEvtListener(window,"resize",b),this.hide(),h.documentIsReady()?s.body.appendChild(e):(s.addEventListener?(c=function(){s.removeEventListener("DOMContentLoaded",c),window.removeEventListener("load",c),s.body.appendChild(e)},s.addEventListener("DOMContentLoaded",c,!1)):(c=function(){"complete"===s.readyState&&(s.detachEvent("onreadystatechange",c),window.detachEvent("onload",c),s.body.appendChild(e))},s.attachEvent("onreadystatechange",c)),h.addEvtListener(window,"load",c))}},e=function(){var a={};this.createCallout=function(b){var c;if(!b.id)throw"Must specify a callout id.";if(a[b.id])throw"Callout by that id already exists. Please choose a unique id.";return b.showNextButton=b.showPrevButton=!1,b.isTourBubble=!1,c=new d(b),a[b.id]=c,b.target&&c.render(b,null,null,function(){c.show()}),c},this.getCallout=function(b){return a[b]},this.removeAllCallouts=function(){var b;for(b in a)a.hasOwnProperty(b)&&this.removeCallout(b)},this.removeCallout=function(b){var c=a[b];a[b]=null,c&&c.destroy()}},c=function(a){var b,c,f,k,m,n,r,t,u=this,v=function(a){return b||(b=new d(f)),a&&(h.extend(b.opt,{bubblePadding:w("bubblePadding"),bubbleWidth:w("bubbleWidth"),showNextButton:w("showNextButton"),showPrevButton:w("showPrevButton"),showCloseButton:w("showCloseButton"),arrowWidth:w("arrowWidth")}),b.updateButtons()),b},w=function(a){return"undefined"==typeof f?l[a]:h.valOrDefault(f[a],l[a])},x=function(){var a;return a=0>m||m>=k.steps.length?null:k.steps[m]},y=function(){u.nextStep()},z=function(a){var b,c,d,e,f,g,i=v(),j=i.element,k=h.getPixelValue(j.style.top),l=k+h.getPixelValue(j.offsetHeight),m=h.getStepTarget(x()),n=m.getBoundingClientRect(),p=n.top+h.getScrollTop(),r=n.bottom+h.getScrollTop(),t=p>k?k:p,u=l>r?l:r,y=h.getScrollTop(),z=y+h.getWindowHeight(),A=t-w("scrollTopMargin");t>=y&&(t<=y+w("scrollTopMargin")||z>=u)?a&&a():w("smoothScroll")?typeof YAHOO!==o&&typeof YAHOO.env!==o&&typeof YAHOO.env.ua!==o&&typeof YAHOO.util!==o&&typeof YAHOO.util.Scroll!==o?(b=YAHOO.env.ua.webkit?s.body:s.documentElement,d=YAHOO.util.Easing?YAHOO.util.Easing.easeOut:void 0,c=new YAHOO.util.Scroll(b,{scroll:{to:[0,A]}},w("scrollDuration")/1e3,d),c.onComplete.subscribe(a),c.animate()):q?jQuery("body, html").animate({scrollTop:A},w("scrollDuration"),a):(0>A&&(A=0),e=y>t?-1:1,f=Math.abs(y-A)/(w("scrollDuration")/10),g=function(){var b=h.getScrollTop(),c=b+e*f;return e>0&&c>=A||0>e&&A>=c?(c=A,a&&a(),window.scrollTo(0,c),void 0):(window.scrollTo(0,c),h.getScrollTop()===b?(a&&a(),void 0):(setTimeout(g,10),void 0))},g()):(window.scrollTo(0,A),a&&a())},A=function(a,b){var c,d,e;m+a>=0&&m+a<k.steps.length?(m+=a,d=x(),e=function(){c=h.getStepTarget(d),c?b(m):(h.invokeEventCallbacks("error"),A(a,b))},d.delay?setTimeout(e,d.delay):e()):b(-1)},B=function(a,b){var c,d,e,f,g=v(),i=this;if(g.hide()._removeCTACallback(),a=h.valOrDefault(a,!0),c=x(),d=c,e=b>0?d.multipage:m>0&&k.steps[m-1].multipage,f=function(c){var f;if(-1===c)return this.endTour(!0);if(a&&(f=b>0?h.invokeEventCallbacks("next",d.onNext):h.invokeEventCallbacks("prev",d.onPrev)),c===m){if(e)return h.setState(w("cookieName"),k.id+":"+m,1),void 0;f=h.valOrDefault(f,!0),f?this.showStep(c):this.endTour(!1)}},!e&&w("skipIfNoElement"))A(b,function(a){f.call(i,a)});else if(m+b>=0&&m+b<k.steps.length){if(m+=b,c=x(),!h.getStepTarget(c)&&!e)return h.invokeEventCallbacks("error"),this.endTour(!0,!1);f.call(this,m)}return this},C=function(a){var b,c,d,e={};for(b in a)a.hasOwnProperty(b)&&"id"!==b&&"steps"!==b&&(e[b]=a[b]);return t.call(this,e,!0),c=h.getState(w("cookieName")),c&&(d=c.split(":"),n=d[0],r=d[1],r=parseInt(r,10)),this},D=function(a,b){var c,d;if(m=a||0,c=x(),d=h.getStepTarget(c))return b(m),void 0;if(!d){if(h.invokeEventCallbacks("error"),w("skipIfNoElement"))return A(1,b),void 0;m=-1,b(m)}},E=function(a){var b,c,d=k.steps[a],e=k.steps,f=e.length,g=k.id+":"+a,i=v(),j=h.getStepTarget(d);c=function(){i.show(),h.invokeEventCallbacks("show",d.onShow)},m=a,i.hide(!1),b=a===f-1,i.render(d,a,b,function(a){a?z(c):c(),d.nextOnTargetClick&&h.addEvtListener(j,"click",y)}),h.setState(w("cookieName"),g,1)},F=function(a){a&&this.configure(a)};this.getCalloutManager=function(){return typeof c===o&&(c=new e),c},this.startTour=function(a,b){var c,d=this;if(k||(k=a,C.call(this,a)),typeof b!==o){if(b>=k.steps.length)throw"Specified step number out of bounds.";m=b}return h.documentIsReady()?(m||k.id!==n||typeof r===o?m||(m=0):m=r,D(m,function(a){var b=-1!==a&&h.getStepTarget(k.steps[a]);return b?(h.invokeEventCallbacks("start"),c=v(),c.hide(!1),d.isActive=!0,h.getStepTarget(x())?d.showStep(a):(h.invokeEventCallbacks("error"),w("skipIfNoElement")&&d.nextStep(!1)),void 0):(d.endTour(!1,!1),void 0)}),this):(p=!0,this)},this.showStep=function(a){var b=k.steps[a];return b.delay?setTimeout(function(){E(a)},b.delay):E(a),this},this.prevStep=function(a){return B.call(this,a,-1),this},this.nextStep=function(a){var b=x(),c=h.getStepTarget(b);return b.nextOnTargetClick&&h.removeEvtListener(c,"click",y),B.call(this,a,1),this},this.endTour=function(a,b){var c=v();return a=h.valOrDefault(a,!0),b=h.valOrDefault(b,!0),m=0,r=void 0,c.hide(),a&&h.clearState(w("cookieName")),this.isActive&&(this.isActive=!1,k&&b&&h.invokeEventCallbacks("end")),this.removeCallbacks(null,!0),this.resetDefaultOptions(),k=null,this},this.getCurrTour=function(){return k},this.getCurrTarget=function(){return h.getStepTarget(x())},this.getCurrStepNum=function(){return m},this.listen=function(a,b,c){return a&&i[a].push({cb:b,fromTour:c}),this},this.unlisten=function(a,b){var c,d,e=i[a];for(c=0,d=e.length;d>c;++c)e[c]===b&&e.splice(c,1);return this},this.removeCallbacks=function(a,b){var c,d,e,f;for(f in i)if(!a||a===f)if(b)for(c=i[f],d=0,e=c.length;e>d;++d)c[d].fromTour&&(c.splice(d--,1),--e);else i[f]=[];return this},this.registerHelper=function(a,b){"string"==typeof a&&"function"==typeof b&&(j[a]=b)},this.unregisterHelper=function(a){j[a]=null},this.invokeHelper=function(a){var b,c,d=[];for(b=1,c=arguments.length;c>b;++b)d.push(arguments[b]);j[a]&&j[a].call(null,d)},this.setCookieName=function(a){return f.cookieName=a,this},this.resetDefaultOptions=function(){return f={},this},this.resetDefaultI18N=function(){return g={},this},this.getState=function(){return h.getState(w("cookieName"))},t=function(a,b){var c,d,e,i,j=["next","prev","start","end","show","error","close"];for(f||this.resetDefaultOptions(),h.extend(f,a),a&&h.extend(g,a.i18n),e=0,i=j.length;i>e;++e)d="on"+j[e].charAt(0).toUpperCase()+j[e].substring(1),a[d]&&this.listen(j[e],a[d],b);return c=v(!0),this},this.configure=function(a){return t.call(this,a,!1)},F.call(this,a)},n=new c,a[b]=n)}(window,"hopscotch");
diff --git a/src/site/resources/scripts/index.js b/src/site/resources/scripts/index.js
new file mode 100644
index 0000000..9e1486e
--- /dev/null
+++ b/src/site/resources/scripts/index.js
@@ -0,0 +1,13 @@
+$(document).ready(function(){
+    $('#main-carousel').carousel({
+        interval:5000
+    });
+
+    $('#main-carousel-prev').on("click", function () {
+        $('#main-carousel').carousel('prev');
+    });
+
+    $('#main-carousel-next').on("click", function () {
+        $('#main-carousel').carousel('next');
+    });
+});
\ No newline at end of file
diff --git a/src/site/site.xml b/src/site/site.xml
new file mode 100644
index 0000000..323f6eb
--- /dev/null
+++ b/src/site/site.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project xmlns="http://maven.apache.org/DECORATION/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd">
+  <bannerLeft>
+    <name>${project.name}</name>
+    <src>http://junit.org/images/junit-logo.png</src>
+    <href>http://junit.org/</href>
+  </bannerLeft>
+
+  <publishDate format="yyyy-MM-dd" position="right" />
+  <version position="right" />
+
+  <poweredBy>
+    <logo name="Built by Maven" href="http://maven.apache.org/" img="images/logos/maven-feather.png" />
+    <logo name="Built on CloudBees" href="https://junit.ci.cloudbees.com/" img="http://www.cloudbees.com/sites/default/files/Button-Built-on-CB-1.png" />
+  </poweredBy>
+
+  <skin>
+    <groupId>org.apache.maven.skins</groupId>
+    <artifactId>maven-fluido-skin</artifactId>
+    <version>1.3.0</version>
+  </skin>
+
+  <body>
+    <head>
+      <link rel="stylesheet" href="@relativePath@/css/plain-links.css" />
+    </head>
+    <breadcrumbs>
+      <item name="JUnit" href="http://junit.org/" />
+    </breadcrumbs>
+
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Frequently asked questions" href="faq.html"/>
+      <item name="Cookbook" href="cookbook.html"/>
+    </menu>
+
+    <menu ref="reports" inherit="bottom" />
+
+  </body>
+
+  <custom>
+    <fluidoSkin>
+      <topBarEnabled>true</topBarEnabled>
+      <sideBarEnabled>false</sideBarEnabled>
+      <sourceLineNumbersEnabled>true</sourceLineNumbersEnabled>
+      <gitHub>
+        <projectId>junit-team/junit</projectId>
+        <ribbonOrientation>right</ribbonOrientation>
+      </gitHub>
+    </fluidoSkin>
+  </custom>
+</project>
diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml
new file mode 100644
index 0000000..d143883
--- /dev/null
+++ b/src/site/xdoc/index.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="utf-8"?>
+<document>
+  <properties>
+    <title>About</title>
+  </properties>
+  <head>
+    <link rel="stylesheet" href="./css/hopscotch-0.1.2.min.css" />
+    <script src="scripts/index.js" type="text/javascript" ></script>
+  </head>
+  <body>
+       <p>
+        JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks.
+      </p>
+     <div id="carousel-main">
+        <div id="main-carousel" class="carousel slide">
+          <div class="carousel-inner">
+            <div class="item active">
+              <div style="height:20em" >
+              <pre class="prettyprint">
+    @Test
+    public void newArrayListsHaveNoElements() {
+        assertThat(new ArrayList&lt;Integer&gt;().size(), is(0));
+    }
+
+    @Test
+    public void sizeReturnsNumberOfElements() {
+        List&lt;Object&gt; instance = new ArrayList&lt;Object&gt;();
+        instance.add(new Object());
+        instance.add(new Object());
+        assertThat(instance.size(), is(2));
+    }
+
+              </pre>
+              </div>
+              <div class="carousel-caption">
+                <p><strong>Annotations</strong></p>
+                <p>Start by marking your tests with <code>@Test</code>.</p>
+              </div>
+            </div>
+            <div class="item">
+              <div style="height:20em">
+              <pre class="prettyprint lang-java">
+    @Test
+    public void lookupEmailAddresses() {
+        assertThat(new CartoonCharacterEmailLookupService().getResults("looney"), allOf(
+            not(empty()), 
+            containsInAnyOrder(
+                allOf(instanceOf(Map.class), hasEntry("id", "56"), hasEntry("email", "roadrunner@fast.org")),
+                allOf(instanceOf(Map.class), hasEntry("id", "76"), hasEntry("email", "wiley@acme.com"))
+            )
+        ));
+    }
+
+
+
+              </pre>
+              </div>
+              <div class="carousel-caption">
+                <p><strong>Hamcrest matchers</strong></p>
+                <p>Make your assertions more expressive and get better failure reports in return. </p>
+              </div>
+            </div>
+          </div>
+          <a id="main-carousel-prev" class="carousel-control left" name="main-carousel-prev" data-slide="prev">&#8249;</a>
+          <a id="main-carousel-next" class="carousel-control right" name="main-carousel-next" data-slide="next">&#8250;</a>
+        </div>
+      </div>
+      <p  class="pagination-centered">
+        <a class="btn btn-primary btn-large" href="javascript:startSiteTour()">Let's take a tour »</a>
+      </p>
+
+      <div class="container">
+      <div class="row">
+        <div class="span4" id="welcome-section">
+          <p><b>Welcome</b></p>
+          <ul>
+            <li><a href="https://github.com/junit-team/junit/wiki/Download-and-Install">Download and install</a></li>
+            <li><a href="https://github.com/junit-team/junit/wiki/Getting-started">Getting started</a></li>
+            <li>Release Notes
+              <ul>
+<li><a href="https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.12.md">4.12</a></li>
+<li><a href="https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md">4.11</a></li>
+<li><a href="https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.10.md">4.10</a></li>
+<li><a href="https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.9.1.md">4.9.1</a></li>
+<li><a href="https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.9.md">4.9</a></li>
+              </ul>
+            </li>
+            <li><a href="https://github.com/junit-team/junit/wiki/Maintainer-documentation">Maintainer Documentation</a></li>
+            <li><a href="https://github.com/junit-team/junit/wiki/I-want-to-help%21">I want to help!</a></li>
+            <li><a href="http://stackoverflow.com/questions/tagged/junit">Latest JUnit Questions on StackOverflow</a></li>
+            <li><a href="javadoc/latest/index.html">JavaDocs</a></li>
+            <li><a href="./faq.html">Frequently asked questions</a></li>
+            <li><a href="https://github.com/junit-team/junit/wiki">Wiki</a></li>
+          </ul>
+        </div>
+        <div class="span4" id="concepts-section">
+          <p><b>Usage and Idioms</b></p>
+          <ul>
+<li><a href="https://github.com/junit-team/junit/wiki/Assertions">Assertions</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Test-runners">Test Runners</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Aggregating-tests-in-suites">Aggregating tests in Suites</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Test-execution-order">Test Execution Order</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Exception-testing">Exception Testing</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Matchers-and-assertthat">Matchers and assertThat</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Ignoring-tests">Ignoring Tests</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Timeout-for-tests">Timeout for Tests</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Parameterized-tests">Parameterized Tests</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Assumptions-with-assume">Assumptions with Assume</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Rules">Rules</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Theories">Theories</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Test-fixtures">Test Fixtures</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Categories">Categories</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Use-with-Maven">Use with Maven</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Multithreaded-code-and-concurrency">Multithreaded code and Concurrency</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Java-contract-test-helpers">Java contract test helpers</a></li>
+<li><a href="https://github.com/junit-team/junit/wiki/Continuous-testing">Continuous Testing</a></li>          </ul>
+        </div>
+        <div class="span4" id="thirdparty-section">
+          <p><b>Third-party extensions</b></p>
+          <ul>
+<li><a href="https://github.com/junit-team/junit/wiki/Custom-runners">Custom Runners</a></li>
+<li>
+<a href="http://site.trajano.net/commons-testing/">net.trajano.commons:commons-testing for UtilityClassTestUtil</a> per #646</li>
+<li>
+<a href="http://stefanbirkner.github.io/system-rules">System Rules</a> – A collection of JUnit rules for testing code that uses java.lang.System.</li>
+<li>
+<a href="https://junit-toolbox.googlecode.com/">JUnit Toolbox</a> - Provides runners for parallel testing, a <code>PoolingWait</code> class to ease asynchronous testing, and a <code>WildcardPatternSuite</code> which allow you to specify wildcard patterns instead of explicitly listing all classes when you create a suite class.</li>
+<li>
+<a href="https://github.com/pholser/junit-quickcheck">junit-quickcheck</a> - QuickCheck-style parameter suppliers for JUnit theories. Uses <a href="https://github.com/junit-team/junit.contrib/tree/master/theories">junit.contrib's version of the theories machinery</a>, which respects generics on theory parameters.</li>          </ul>
+        </div>
+      </div>
+    </div>
+    <script src="scripts/hopscotch-0.1.2.min.js" type="text/javascript" ></script>
+    <script>//<![CDATA[
+        var tour = {
+          id: "welcome_tour",
+          steps:[
+            {
+              target: "welcome-section",
+              placement: "right",
+              title: "First things first",
+              content: "Here are the links to the most important information"
+            },
+            {
+              target: $('ul.nav')[0],
+              fixedElement: true,
+              placement: "bottom",
+              title: "Maven site documentation",
+              content: "Don't forget that the documentation generated by Maven is hiding up here"
+            },
+            {
+              target: $('body a[href="http://github.com/junit-team/junit"] img')[0],
+              placement: "left",
+              title: "Source code",
+              content: "The source code for JUnit is hosted on GitHub"
+            },
+            {
+              target: "concepts-section",
+              placement: "right",
+              title: "Understanding JUnit",
+              content: "Find out more about how to do things with JUnit"
+            },
+            {
+              target: "thirdparty-section",
+              placement: "left",
+              title: "Extending JUnit",
+              content: "Find out about third party extensions to the JUnit framework"
+            }
+          ]
+        }
+        window.startSiteTour = function(){
+            hopscotch.startTour(tour);
+            return undefined;
+        };
+    //]]></script>
+  </body>
+</document>
diff --git a/src/test/java/junit/samples/ListTest.java b/src/test/java/junit/samples/ListTest.java
index 6b6de38..182027f 100644
--- a/src/test/java/junit/samples/ListTest.java
+++ b/src/test/java/junit/samples/ListTest.java
@@ -8,7 +8,7 @@
 import junit.framework.TestSuite;
 
 /**
- * A sample test case, testing {@link java.util.Vector}.
+ * A sample test case, testing {@link java.util.ArrayList}.
  */
 public class ListTest extends TestCase {
     protected List<Integer> fEmpty;
diff --git a/src/test/java/junit/samples/money/IMoney.java b/src/test/java/junit/samples/money/IMoney.java
index b6fd1c5..d48757a 100644
--- a/src/test/java/junit/samples/money/IMoney.java
+++ b/src/test/java/junit/samples/money/IMoney.java
@@ -7,39 +7,39 @@
     /**
      * Adds a money to this money.
      */
-    public abstract IMoney add(IMoney m);
+    IMoney add(IMoney m);
 
     /**
      * Adds a simple Money to this money. This is a helper method for
      * implementing double dispatch
      */
-    public abstract IMoney addMoney(Money m);
+    IMoney addMoney(Money m);
 
     /**
      * Adds a MoneyBag to this money. This is a helper method for
      * implementing double dispatch
      */
-    public abstract IMoney addMoneyBag(MoneyBag s);
+    IMoney addMoneyBag(MoneyBag s);
 
     /**
      * Tests whether this money is zero
      */
-    public abstract boolean isZero();
+    boolean isZero();
 
     /**
      * Multiplies a money by the given factor.
      */
-    public abstract IMoney multiply(int factor);
+    IMoney multiply(int factor);
 
     /**
      * Negates this money.
      */
-    public abstract IMoney negate();
+    IMoney negate();
 
     /**
      * Subtracts a money from this money.
      */
-    public abstract IMoney subtract(IMoney m);
+    IMoney subtract(IMoney m);
 
     /**
      * Append this to a MoneyBag m.
@@ -47,5 +47,5 @@
      * polymorphically, but it should not be used by clients
      * because it modifies the argument m.
      */
-    public abstract void appendTo(MoneyBag m);
-}
\ No newline at end of file
+    void appendTo(MoneyBag m);
+}
diff --git a/src/test/java/junit/samples/money/Money.java b/src/test/java/junit/samples/money/Money.java
index 45123da..de6525b 100644
--- a/src/test/java/junit/samples/money/Money.java
+++ b/src/test/java/junit/samples/money/Money.java
@@ -83,9 +83,7 @@
 
     @Override
     public String toString() {
-        StringBuffer buffer = new StringBuffer();
-        buffer.append("[" + amount() + " " + currency() + "]");
-        return buffer.toString();
+        return "[" + amount() + " " + currency() + "]";
     }
 
     public /*this makes no sense*/ void appendTo(MoneyBag m) {
diff --git a/src/test/java/junit/samples/money/MoneyBag.java b/src/test/java/junit/samples/money/MoneyBag.java
index f9ba235..e02bb51 100644
--- a/src/test/java/junit/samples/money/MoneyBag.java
+++ b/src/test/java/junit/samples/money/MoneyBag.java
@@ -140,13 +140,13 @@
 
     @Override
     public String toString() {
-        StringBuffer buffer = new StringBuffer();
-        buffer.append("{");
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
         for (Money each : fMonies) {
-            buffer.append(each);
+            sb.append(each);
         }
-        buffer.append("}");
-        return buffer.toString();
+        sb.append("}");
+        return sb.toString();
     }
 
     public void appendTo(MoneyBag m) {
diff --git a/src/test/java/junit/tests/extensions/ExtensionTest.java b/src/test/java/junit/tests/extensions/ExtensionTest.java
index bfe1ecc..155a478 100644
--- a/src/test/java/junit/tests/extensions/ExtensionTest.java
+++ b/src/test/java/junit/tests/extensions/ExtensionTest.java
@@ -71,6 +71,7 @@
         WasRun test = new WasRun();
 
         TornDown wrapper = new TornDown(test) {
+            @SuppressWarnings("deprecation")
             @Override
             public void setUp() {
                 fail();
@@ -87,6 +88,7 @@
         WasRun test = new WasRun();
 
         TestSetup wrapper = new TestSetup(test) {
+            @SuppressWarnings("deprecation")
             @Override
             public void setUp() {
                 fail();
diff --git a/src/test/java/junit/tests/framework/ComparisonCompactorTest.java b/src/test/java/junit/tests/framework/ComparisonCompactorTest.java
index ee74f7d..16e0b4e 100644
--- a/src/test/java/junit/tests/framework/ComparisonCompactorTest.java
+++ b/src/test/java/junit/tests/framework/ComparisonCompactorTest.java
@@ -55,22 +55,22 @@
         assertEquals("expected:<[]bc> but was:<[a]bc>", failure);
     }
 
-    public void testComparisonErrorOverlapingMatches() {
+    public void testComparisonErrorOverlappingMatches() {
         String failure = new ComparisonCompactor(0, "abc", "abbc").compact(null);
         assertEquals("expected:<...[]...> but was:<...[b]...>", failure);
     }
 
-    public void testComparisonErrorOverlapingMatchesContext() {
+    public void testComparisonErrorOverlappingMatchesContext() {
         String failure = new ComparisonCompactor(2, "abc", "abbc").compact(null);
         assertEquals("expected:<ab[]c> but was:<ab[b]c>", failure);
     }
 
-    public void testComparisonErrorOverlapingMatches2() {
+    public void testComparisonErrorOverlappingMatches2() {
         String failure = new ComparisonCompactor(0, "abcdde", "abcde").compact(null);
         assertEquals("expected:<...[d]...> but was:<...[]...>", failure);
     }
 
-    public void testComparisonErrorOverlapingMatches2Context() {
+    public void testComparisonErrorOverlappingMatches2Context() {
         String failure = new ComparisonCompactor(2, "abcdde", "abcde").compact(null);
         assertEquals("expected:<...cd[d]e> but was:<...cd[]e>", failure);
     }
diff --git a/src/test/java/junit/tests/framework/TestListenerTest.java b/src/test/java/junit/tests/framework/TestListenerTest.java
index b057074..d59ba26 100644
--- a/src/test/java/junit/tests/framework/TestListenerTest.java
+++ b/src/test/java/junit/tests/framework/TestListenerTest.java
@@ -16,7 +16,7 @@
     private int fFailureCount;
     private int fErrorCount;
 
-    public void addError(Test test, Throwable t) {
+    public void addError(Test test, Throwable e) {
         fErrorCount++;
     }
 
diff --git a/src/test/java/junit/tests/runner/BaseTestRunnerTest.java b/src/test/java/junit/tests/runner/BaseTestRunnerTest.java
index c9883c8..ea38bea 100644
--- a/src/test/java/junit/tests/runner/BaseTestRunnerTest.java
+++ b/src/test/java/junit/tests/runner/BaseTestRunnerTest.java
@@ -19,7 +19,7 @@
         }
 
         @Override
-        public void testFailed(int status, Test test, Throwable t) {
+        public void testFailed(int status, Test test, Throwable e) {
         }
 
         @Override
diff --git a/src/test/java/junit/tests/runner/ResultTest.java b/src/test/java/junit/tests/runner/ResultTest.java
index 0b8cca7..5cf7743 100644
--- a/src/test/java/junit/tests/runner/ResultTest.java
+++ b/src/test/java/junit/tests/runner/ResultTest.java
@@ -3,13 +3,16 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.util.List;
 
 import junit.framework.TestCase;
 import junit.tests.framework.Success;
 import org.junit.runner.JUnitCore;
 import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
 import org.junit.tests.running.methods.AnnotationTest;
 
 public class ResultTest extends TestCase {
@@ -32,6 +35,76 @@
         byte[] bytes = byteArrayOutputStream.toByteArray();
         ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
         Result fromStream = (Result) objectInputStream.readObject();
+        assertSerializedCorrectly(result, fromStream);
+
+        InputStream resource = getClass().getResourceAsStream(getName());
+        assertNotNull("Could not read resource " + getName(), resource);
+        objectInputStream = new ObjectInputStream(resource);
+        fromStream = (Result) objectInputStream.readObject();
+        
+        assertSerializedCorrectly(new ResultWithFixedRunTime(result), fromStream);
+    }
+
+    /**
+     * A version of {@code Result} that returns a hard-coded runtime.
+     * This makes values returned by the methods deterministic.
+     */
+    private static class ResultWithFixedRunTime extends Result {
+
+        private static final long serialVersionUID = 1L;
+
+        private final Result delegate;
+
+        public ResultWithFixedRunTime(Result delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public int getRunCount() {
+            return delegate.getRunCount();
+        }
+
+        @Override
+        public int getFailureCount() {
+            return delegate.getFailureCount();
+        }
+
+        @Override
+        public long getRunTime() {
+            return 2;
+        }
+
+        @Override
+        public List<Failure> getFailures() {
+            return delegate.getFailures();
+        }
+
+        @Override
+        public int getIgnoreCount() {
+            return delegate.getIgnoreCount();
+        }
+    }
+
+    private void assertSerializedCorrectly(Result result, Result fromStream) {
         assertNotNull(fromStream);
+
+        // Exceptions don't implement equals() so we need to compare field by field
+        assertEquals("failureCount", result.getFailureCount(), fromStream.getFailureCount());
+        assertEquals("ignoreCount", result.getIgnoreCount(), fromStream.getIgnoreCount());
+        assertEquals("runTime", result.getRunTime(), fromStream.getRunTime());
+        assertEquals("failures", result.getFailures().size(), fromStream.getFailures().size());
+        int index = 0;
+        for (Failure failure : result.getFailures()) {
+            Failure failureFromStream = fromStream.getFailures().get(index);
+            String messagePrefix = String.format("failures[%d]", index++);
+            assertEquals(messagePrefix + ".description",
+                    failure.getDescription(), failureFromStream.getDescription());
+            Throwable exception = failure.getException();
+            Throwable exceptionFromStream = failureFromStream.getException();
+            assertEquals(messagePrefix + ".exception",
+                    exception.getClass(), exceptionFromStream.getClass());
+            assertEquals(messagePrefix + ".exception",
+                    exception.getMessage(), exceptionFromStream.getMessage());
+        }
     }
 }
diff --git a/src/test/java/org/junit/AssumptionViolatedExceptionTest.java b/src/test/java/org/junit/AssumptionViolatedExceptionTest.java
new file mode 100644
index 0000000..b082933
--- /dev/null
+++ b/src/test/java/org/junit/AssumptionViolatedExceptionTest.java
@@ -0,0 +1,95 @@
+package org.junit;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import org.hamcrest.Matcher;
+import org.hamcrest.StringDescription;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class AssumptionViolatedExceptionTest {
+    @DataPoint
+    public static Integer TWO = 2;
+
+    @DataPoint
+    public static Matcher<Integer> IS_THREE = is(3);
+
+    @DataPoint
+    public static Matcher<Integer> NULL = null;
+
+    @Theory
+    public void toStringReportsMatcher(Integer actual, Matcher<Integer> matcher) {
+        assumeThat(matcher, notNullValue());
+        assertThat(new AssumptionViolatedException(actual, matcher).toString(),
+                containsString(matcher.toString()));
+    }
+
+    @Theory
+    public void toStringReportsValue(Integer actual, Matcher<Integer> matcher) {
+        assertThat(new AssumptionViolatedException(actual, matcher).toString(),
+                containsString(String.valueOf(actual)));
+    }
+
+    @Test
+    public void assumptionViolatedExceptionWithMatcherDescribesItself() {
+        AssumptionViolatedException e = new AssumptionViolatedException(3, is(2));
+        assertThat(StringDescription.asString(e), is("got: <3>, expected: is <2>"));
+    }
+
+    @Test
+    public void simpleAssumptionViolatedExceptionDescribesItself() {
+        AssumptionViolatedException e = new AssumptionViolatedException("not enough money");
+        assertThat(StringDescription.asString(e), is("not enough money"));
+    }
+
+    @Test
+    public void canInitCauseWithInstanceCreatedWithString() {
+      AssumptionViolatedException e = new AssumptionViolatedException("invalid number");
+      Throwable cause = new RuntimeException("cause");
+      e.initCause(cause);
+      assertThat(e.getCause(), is(cause));
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void canSetCauseWithInstanceCreatedWithObjectAndMatcher() {
+      Throwable testObject = new Exception();
+      org.junit.internal.AssumptionViolatedException e
+              = new org.junit.internal.AssumptionViolatedException(
+                      testObject, containsString("test matcher"));
+      assertThat(e.getCause(), is(testObject));
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void canSetCauseWithInstanceCreatedWithAssumptionObjectAndMatcher() {
+      Throwable testObject = new Exception();
+      org.junit.internal.AssumptionViolatedException e
+              = new org.junit.internal.AssumptionViolatedException(
+                      "sample assumption", testObject, containsString("test matcher"));
+      assertThat(e.getCause(), is(testObject));
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void canSetCauseWithInstanceCreatedWithMainConstructor() {
+      Throwable testObject = new Exception();
+      org.junit.internal.AssumptionViolatedException e
+              = new org.junit.internal.AssumptionViolatedException(
+                      "sample assumption", false, testObject, containsString("test matcher"));
+      assertThat(e.getCause(), is(testObject));
+    }
+
+    @Test
+    public void canSetCauseWithInstanceCreatedWithExplicitThrowableConstructor() {
+      Throwable cause = new Exception();
+      AssumptionViolatedException e = new AssumptionViolatedException("invalid number", cause);
+      assertThat(e.getCause(), is(cause));
+    }
+}
diff --git a/src/test/java/org/junit/experimental/categories/CategoryFilterFactoryTest.java b/src/test/java/org/junit/experimental/categories/CategoryFilterFactoryTest.java
new file mode 100644
index 0000000..7efb667
--- /dev/null
+++ b/src/test/java/org/junit/experimental/categories/CategoryFilterFactoryTest.java
@@ -0,0 +1,66 @@
+package org.junit.experimental.categories;

+

+import static org.hamcrest.CoreMatchers.instanceOf;

+import static org.hamcrest.MatcherAssert.assertThat;

+import static org.junit.runner.Description.createSuiteDescription;

+

+import java.util.List;

+

+import org.junit.Rule;

+import org.junit.Test;

+import org.junit.rules.ExpectedException;

+import org.junit.rules.TestName;

+import org.junit.runner.Description;

+import org.junit.runner.FilterFactory;

+import org.junit.runner.FilterFactoryParams;

+import org.junit.runner.manipulation.Filter;

+

+public class CategoryFilterFactoryTest {

+    @Rule

+    public ExpectedException expectedException = ExpectedException.none();

+

+    @Rule

+    public TestName testName = new TestName();

+

+    private final CategoryFilterFactory categoryFilterFactory = new CategoryFilterFactoryStub();

+

+    @Test

+    public void shouldCreateFilter() throws Exception {

+        FilterFactoryParams params = new FilterFactoryParams(

+                createSuiteDescription(testName.getMethodName()),

+                CategoryFilterFactoryStub.class.getName());

+        Filter filter = categoryFilterFactory.createFilter(params);

+

+        assertThat(filter, instanceOf(DummyFilter.class));

+    }

+

+    @Test

+    public void shouldThrowException() throws Exception {

+        FilterFactoryParams params = new FilterFactoryParams(

+                createSuiteDescription(testName.getMethodName()),

+                "NonExistentFilter");

+

+        expectedException.expect(FilterFactory.FilterNotCreatedException.class);

+

+        categoryFilterFactory.createFilter(params);

+    }

+

+    private static class CategoryFilterFactoryStub extends CategoryFilterFactory {

+        @Override

+        protected Filter createFilter(List<Class<?>> categories) {

+            return new DummyFilter();

+        }

+    }

+

+    private static class DummyFilter extends Filter {

+        @Override

+        public boolean shouldRun(Description description) {

+            return false;

+        }

+

+        @Override

+        public String describe() {

+            return null;

+        }

+    }

+}

diff --git a/src/test/java/org/junit/internal/builders/AnnotatedBuilderTest.java b/src/test/java/org/junit/internal/builders/AnnotatedBuilderTest.java
new file mode 100644
index 0000000..9879d3a
--- /dev/null
+++ b/src/test/java/org/junit/internal/builders/AnnotatedBuilderTest.java
@@ -0,0 +1,105 @@
+package org.junit.internal.builders;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runner.RunnerSpy;
+import org.junit.runners.model.RunnerBuilder;
+import org.junit.runners.model.RunnerBuilderStub;
+
+public class AnnotatedBuilderTest {
+    private AnnotatedBuilder builder = new AnnotatedBuilder(new RunnerBuilderStub());
+
+    @Test
+    public void topLevelTestClassWithoutAnnotation_isRunWithDefaultRunner() throws Exception {
+        Runner runner = builder.runnerForClass(Object.class);
+        assertThat(runner, is(nullValue()));
+    }
+
+    @Test
+    public void topLevelTestClassWithAnnotation_isRunWithAnnotatedRunner() throws Exception {
+        Runner runner = builder.runnerForClass(OuterClass.class);
+        assertThat(runner, is(instanceOf(RunnerSpy.class)));
+
+        RunnerSpy runnerSpy = (RunnerSpy) runner;
+        assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.class));
+    }
+
+    @Test
+    public void memberClassInsideAnnotatedTopLevelClass_isRunWithTopLevelRunner() throws Exception {
+        Runner runner = builder.runnerForClass(OuterClass.InnerClassWithoutOwnRunWith.class);
+        assertThat(runner, is(instanceOf(RunnerSpy.class)));
+
+        RunnerSpy runnerSpy = (RunnerSpy) runner;
+        assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.InnerClassWithoutOwnRunWith.class));
+    }
+
+    @Test
+    public void memberClassDeepInsideAnnotatedTopLevelClass_isRunWithTopLevelRunner() throws Exception {
+        Runner runner = builder.runnerForClass(OuterClass.InnerClassWithoutOwnRunWith.MostInnerClass.class);
+        assertThat(runner, is(instanceOf(RunnerSpy.class)));
+
+        RunnerSpy runnerSpy = (RunnerSpy) runner;
+        assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.InnerClassWithoutOwnRunWith.MostInnerClass.class));
+    }
+
+    @Test
+    public void annotatedMemberClassInsideAnnotatedTopLevelClass_isRunWithOwnRunner() throws Exception {
+        Runner runner = builder.runnerForClass(OuterClass.InnerClassWithOwnRunWith.class);
+        assertThat(runner, is(instanceOf(InnerRunner.class)));
+
+        RunnerSpy runnerSpy = (RunnerSpy) runner;
+        assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.InnerClassWithOwnRunWith.class));
+    }
+
+    @Test
+    public void memberClassDeepInsideAnnotatedMemberClass_isRunWithParentMemberClassRunner() throws Exception {
+        Runner runner = builder.runnerForClass(OuterClass.InnerClassWithOwnRunWith.MostInnerClass.class);
+        assertThat(runner, is(instanceOf(InnerRunner.class)));
+
+        RunnerSpy runnerSpy = (RunnerSpy) runner;
+        assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.InnerClassWithOwnRunWith.MostInnerClass.class));
+    }
+
+    @RunWith(RunnerSpy.class)
+    public static class OuterClass {
+        public class InnerClassWithoutOwnRunWith {
+            @Test
+            public void test() {
+            }
+
+            public class MostInnerClass {
+                @Test
+                public void test() {
+                }
+            }
+        }
+
+        @RunWith(InnerRunner.class)
+        public class InnerClassWithOwnRunWith {
+            @Test
+            public void test() {
+            }
+
+            public class MostInnerClass {
+                @Test
+                public void test() {
+                }
+            }
+        }
+    }
+
+    public static class InnerRunner extends RunnerSpy {
+        public InnerRunner(Class<?> testClass) {
+            super(testClass);
+        }
+
+        public InnerRunner(Class<?> testClass, RunnerBuilder runnerBuilder) {
+            super(testClass, runnerBuilder);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java b/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java
new file mode 100644
index 0000000..dba1f7b
--- /dev/null
+++ b/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java
@@ -0,0 +1,18 @@
+package org.junit.internal.matchers;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;
+
+public class ThrowableCauseMatcherTest {
+
+    @Test
+    public void shouldAllowCauseOfDifferentClassFromRoot() throws Exception {
+        NullPointerException expectedCause = new NullPointerException("expected");
+        Exception actual = new Exception(expectedCause);
+
+        assertThat(actual, hasCause(is(expectedCause)));
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/rules/DisableOnDebugTest.java b/src/test/java/org/junit/rules/DisableOnDebugTest.java
new file mode 100644
index 0000000..d61db9e
--- /dev/null
+++ b/src/test/java/org/junit/rules/DisableOnDebugTest.java
@@ -0,0 +1,164 @@
+package org.junit.rules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runners.model.Statement;
+
+public class DisableOnDebugTest {
+    private static final List<String> WITHOUT_DEBUG_ARGUMENTS = Collections
+            .emptyList();
+
+    private static final List<String> PRE_JAVA5_DEBUG_ARGUMENTS = Arrays
+            .asList("-Xdebug",
+                    "-Xrunjdwp:transport=dt_socket,server=y,address=8000");
+
+    private static final List<String> PRE_JAVA5_DEBUG_ARGUMENTS_IN_REVERSE_ORDER = Arrays
+            .asList("-Xrunjdwp:transport=dt_socket,server=y,address=8000",
+                    "-Xdebug");
+
+    private static final List<String> POST_JAVA5_DEBUG_ARGUMENTS = Arrays
+            .asList("-agentlib:jdwp=transport=dt_socket,server=y,address=8000");
+
+    /**
+     * Nasty rule that always fails
+     */
+    private static class FailOnExecution implements TestRule {
+
+        public Statement apply(Statement base,
+                Description description) {
+            return new Statement() {
+
+                @Override
+                public void evaluate() throws Throwable {
+                    throw new AssertionError();
+                }
+            };
+        }
+
+    }
+
+    public static abstract class AbstractDisableOnDebugTest {
+
+        @Rule
+        public TestRule failOnExecution;
+
+        public AbstractDisableOnDebugTest(List<String> arguments) {
+            this.failOnExecution = new DisableOnDebug(new FailOnExecution(),
+                    arguments);
+        }
+
+        @Test
+        public void test() {
+        }
+    }
+
+    public static class PreJava5DebugArgumentsTest extends
+            AbstractDisableOnDebugTest {
+
+        public PreJava5DebugArgumentsTest() {
+            super(PRE_JAVA5_DEBUG_ARGUMENTS);
+        }
+
+    }
+
+    public static class PreJava5DebugArgumentsReversedTest extends
+            AbstractDisableOnDebugTest {
+
+        public PreJava5DebugArgumentsReversedTest() {
+            super(PRE_JAVA5_DEBUG_ARGUMENTS_IN_REVERSE_ORDER);
+        }
+
+    }
+
+    public static class PostJava5DebugArgumentsTest extends
+            AbstractDisableOnDebugTest {
+
+        public PostJava5DebugArgumentsTest() {
+            super(POST_JAVA5_DEBUG_ARGUMENTS);
+        }
+
+    }
+
+    public static class WithoutDebugArgumentsTest extends
+            AbstractDisableOnDebugTest {
+
+        public WithoutDebugArgumentsTest() {
+            super(WITHOUT_DEBUG_ARGUMENTS);
+        }
+
+    }
+
+    @Test
+    public void givenPreJava5DebugArgumentsIsDebuggingShouldReturnTrue() {
+        DisableOnDebug subject = new DisableOnDebug(
+                new FailOnExecution(), PRE_JAVA5_DEBUG_ARGUMENTS);
+        assertTrue("Should be debugging", subject.isDebugging());
+    }
+
+    @Test
+    public void givenPreJava5DebugArgumentsInReverseIsDebuggingShouldReturnTrue() {
+        DisableOnDebug subject = new DisableOnDebug(
+                new FailOnExecution(),
+                PRE_JAVA5_DEBUG_ARGUMENTS_IN_REVERSE_ORDER);
+        assertTrue("Should be debugging", subject.isDebugging());
+    }
+
+    @Test
+    public void givenPostJava5DebugArgumentsIsDebuggingShouldReturnTrue() {
+        DisableOnDebug subject = new DisableOnDebug(
+                new FailOnExecution(), POST_JAVA5_DEBUG_ARGUMENTS);
+        assertTrue("Should be debugging", subject.isDebugging());
+    }
+
+    @Test
+    public void givenArgumentsWithoutDebugFlagsIsDebuggingShouldReturnFalse() {
+        DisableOnDebug subject = new DisableOnDebug(
+                new FailOnExecution(), WITHOUT_DEBUG_ARGUMENTS);
+        Assert.assertFalse("Should not be debugging", subject.isDebugging());
+    }
+
+    @Test
+    public void whenRunWithPreJava5DebugArgumentsTestShouldFail() {
+        JUnitCore core = new JUnitCore();
+        Result result = core.run(PreJava5DebugArgumentsTest.class);
+        assertEquals("Should run the test", 1, result.getRunCount());
+        assertEquals("Test should not have failed", 0, result.getFailureCount());
+    }
+
+    @Test
+    public void whenRunWithPreJava5DebugArgumentsInReverseOrderTestShouldFail() {
+        JUnitCore core = new JUnitCore();
+        Result result = core
+                .run(PreJava5DebugArgumentsReversedTest.class);
+        assertEquals("Should run the test", 1, result.getRunCount());
+        assertEquals("Test should not have failed", 0, result.getFailureCount());
+    }
+
+    @Test
+    public void whenRunWithPostJava5DebugArgumentsTestShouldFail() {
+        JUnitCore core = new JUnitCore();
+        Result result = core.run(PostJava5DebugArgumentsTest.class);
+        assertEquals("Should run the test", 1, result.getRunCount());
+        assertEquals("Test should not have failed", 0, result.getFailureCount());
+    }
+
+    @Test
+    public void whenRunWithoutDebugFlagsTestShouldPass() {
+        JUnitCore core = new JUnitCore();
+        Result result = core.run(WithoutDebugArgumentsTest.class);
+        assertEquals("Should run the test", 1, result.getRunCount());
+        assertEquals("Test should have failed", 1, result.getFailureCount());
+    }
+
+}
diff --git a/src/test/java/org/junit/rules/StopwatchTest.java b/src/test/java/org/junit/rules/StopwatchTest.java
new file mode 100644
index 0000000..18893dd
--- /dev/null
+++ b/src/test/java/org/junit/rules/StopwatchTest.java
@@ -0,0 +1,212 @@
+package org.junit.rules;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+
+/**
+ * @author tibor17
+ * @since 4.12
+ */
+public class StopwatchTest {
+    private static enum TestStatus { SUCCEEDED, FAILED, SKIPPED }
+    private static Record record;
+    private static Record finishedRecord;
+    private static long fakeTimeNanos = 1234;
+
+    private static class Record {
+        final long duration;
+        final String name;
+        final TestStatus status;
+
+        Record() {
+            this(0, null, null);
+        }
+
+        Record(long duration, Description description) {
+            this(duration, null, description);
+        }
+
+        Record(long duration, TestStatus status, Description description) {
+            this.duration = duration;
+            this.status = status;
+            this.name = description == null ? null : description.getMethodName();
+        }
+    }
+
+    public static abstract class AbstractStopwatchTest {
+
+        /**
+         * Fake implementation of {@link Stopwatch.Clock} that increments the time
+         * every time it is asked.
+         */
+        private final Stopwatch.Clock fakeClock = new Stopwatch.Clock() {
+            @Override
+            public long nanoTime() {
+                return fakeTimeNanos++;
+            }
+        };
+
+        protected final Stopwatch stopwatch = new Stopwatch(fakeClock) {
+            @Override
+            protected void succeeded(long nanos, Description description) {
+                StopwatchTest.record = new Record(nanos, TestStatus.SUCCEEDED, description);
+                simulateTimePassing(1);
+            }
+
+            @Override
+            protected void failed(long nanos, Throwable e, Description description) {
+                StopwatchTest.record = new Record(nanos, TestStatus.FAILED, description);
+                simulateTimePassing(1);
+            }
+
+            @Override
+            protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
+                StopwatchTest.record = new Record(nanos, TestStatus.SKIPPED, description);
+                simulateTimePassing(1);
+            }
+
+            @Override
+            protected void finished(long nanos, Description description) {
+                StopwatchTest.finishedRecord = new Record(nanos, description);
+            }
+        };
+
+        private final TestWatcher watcher = new TestWatcher() {
+            @Override
+            protected void finished(Description description) {
+                afterStopwatchRule();
+            }
+        };
+
+        @Rule
+        public final RuleChain chain = RuleChain
+            .outerRule(watcher)
+            .around(stopwatch);
+
+        protected void afterStopwatchRule() {
+        }
+    }
+
+    public static class SuccessfulTest extends AbstractStopwatchTest {
+        @Test
+        public void successfulTest() {
+        }
+    }
+
+    public static class FailedTest extends AbstractStopwatchTest {
+        @Test
+        public void failedTest() {
+            fail();
+        }
+    }
+
+    public static class SkippedTest extends AbstractStopwatchTest {
+        @Test
+        public void skippedTest() {
+            assumeTrue(false);
+        }
+    }
+
+    public static class DurationDuringTestTest extends AbstractStopwatchTest {
+        @Test
+        public void duration() {
+            simulateTimePassing(300L);
+            assertEquals(300L, stopwatch.runtime(MILLISECONDS));
+            simulateTimePassing(500L);
+            assertEquals(800L, stopwatch.runtime(MILLISECONDS));
+        }
+    }
+
+    public static class DurationAfterTestTest extends AbstractStopwatchTest {
+        @Test
+        public void duration() {
+            simulateTimePassing(300L);
+            assertEquals(300L, stopwatch.runtime(MILLISECONDS));
+        }
+
+        @Override
+        protected void afterStopwatchRule() {
+            assertEquals(300L, stopwatch.runtime(MILLISECONDS));
+            simulateTimePassing(500L);
+            assertEquals(300L, stopwatch.runtime(MILLISECONDS));
+        }
+    }
+
+    @Before
+    public void init() {
+        record = new Record();
+        finishedRecord = new Record();
+        simulateTimePassing(1L);
+    }
+
+    private static Result runTest(Class<?> test) {
+        simulateTimePassing(1L);
+        JUnitCore junitCore = new JUnitCore();
+        return junitCore.run(Request.aClass(test).getRunner());
+    }
+
+    private static void simulateTimePassing(long millis) {
+        fakeTimeNanos += TimeUnit.MILLISECONDS.toNanos(millis);
+    }
+
+    @Test
+    public void succeeded() {
+        Result result = runTest(SuccessfulTest.class);
+        assertEquals(0, result.getFailureCount());
+        assertThat(record.name, is("successfulTest"));
+        assertThat(record.name, is(finishedRecord.name));
+        assertThat(record.status, is(TestStatus.SUCCEEDED));
+        assertTrue("timeSpent > 0", record.duration > 0);
+        assertThat(record.duration, is(finishedRecord.duration));
+    }
+
+    @Test
+    public void failed() {
+        Result result = runTest(FailedTest.class);
+        assertEquals(1, result.getFailureCount());
+        assertThat(record.name, is("failedTest"));
+        assertThat(record.name, is(finishedRecord.name));
+        assertThat(record.status, is(TestStatus.FAILED));
+        assertTrue("timeSpent > 0", record.duration > 0);
+        assertThat(record.duration, is(finishedRecord.duration));
+    }
+
+    @Test
+    public void skipped() {
+        Result result = runTest(SkippedTest.class);
+        assertEquals(0, result.getFailureCount());
+        assertThat(record.name, is("skippedTest"));
+        assertThat(record.name, is(finishedRecord.name));
+        assertThat(record.status, is(TestStatus.SKIPPED));
+        assertTrue("timeSpent > 0", record.duration > 0);
+        assertThat(record.duration, is(finishedRecord.duration));
+    }
+
+    @Test
+    public void runtimeDuringTestShouldReturnTimeSinceStart() {
+        Result result = runTest(DurationDuringTestTest.class);
+        assertTrue(result.wasSuccessful());
+    }
+
+  @Test
+    public void runtimeAfterTestShouldReturnRunDuration() {
+        Result result = runTest(DurationAfterTestTest.class);
+        assertTrue(result.wasSuccessful());
+    }
+}
diff --git a/src/test/java/org/junit/runner/FilterFactoriesTest.java b/src/test/java/org/junit/runner/FilterFactoriesTest.java
new file mode 100644
index 0000000..0293cf8
--- /dev/null
+++ b/src/test/java/org/junit/runner/FilterFactoriesTest.java
@@ -0,0 +1,137 @@
+package org.junit.runner;

+

+import static org.hamcrest.CoreMatchers.instanceOf;

+import static org.hamcrest.CoreMatchers.is;

+import static org.hamcrest.CoreMatchers.startsWith;

+import static org.hamcrest.MatcherAssert.assertThat;

+import static org.junit.Assume.assumeThat;

+import org.junit.Rule;

+import org.junit.Test;

+import org.junit.experimental.categories.ExcludeCategories;

+import org.junit.rules.ExpectedException;

+import org.junit.rules.TestName;

+import org.junit.runner.manipulation.Filter;

+import org.junit.runners.Suite;

+import org.junit.runners.Suite.SuiteClasses;

+

+public class FilterFactoriesTest {

+    @Rule

+    public ExpectedException expectedException = ExpectedException.none();

+

+    @Rule

+    public TestName testName = new TestName();

+

+    private Request createSuiteRequest() {

+        return Request.aClass(DummySuite.class);

+    }

+

+    @Test

+    public void shouldCreateFilterWithArguments() throws Exception {

+        Filter filter = FilterFactories.createFilterFromFilterSpec(

+                createSuiteRequest(),

+                ExcludeCategories.class.getName() + "=" + DummyCategory.class.getName());

+

+        assertThat(filter.describe(), startsWith("excludes "));

+    }

+

+    @Test

+    public void shouldCreateFilterWithNoArguments() throws Exception {

+        Filter filter = FilterFactories.createFilterFromFilterSpec(

+                createSuiteRequest(), FilterFactoryStub.class.getName());

+

+        assertThat(filter, instanceOf(DummyFilter.class));

+    }

+

+    @Test

+    public void shouldPassOnDescriptionToFilterFactory() throws Exception {

+        Request request = createSuiteRequest();

+        Description description = request.getRunner().getDescription();

+        Filter filter = FilterFactories.createFilterFromFilterSpec(

+                request, FilterFactoryStub.class.getName());

+

+        // This assumption tested in shouldCreateFilterWithNoArguments()

+        assumeThat(filter, instanceOf(DummyFilter.class));

+

+        DummyFilter dummyFilter = (DummyFilter) filter;

+        assertThat(dummyFilter.getTopLevelDescription(), is(description));

+    }

+

+    @Test

+    public void shouldCreateFilter() throws Exception {

+        Filter filter = FilterFactories.createFilter(

+                FilterFactoryStub.class,

+                new FilterFactoryParams(

+                        Description.createSuiteDescription(testName.getMethodName()),

+                        ""));

+

+        assertThat(filter, instanceOf(DummyFilter.class));

+    }

+

+    @Test

+    public void shouldThrowExceptionIfNotFilterFactory() throws Exception {

+        expectedException.expect(FilterFactory.FilterNotCreatedException.class);

+

+        FilterFactories.createFilterFactory(NonFilterFactory.class.getName());

+    }

+

+    @Test

+    public void shouldThrowExceptionIfNotInstantiable() throws Exception {

+        expectedException.expect(FilterFactory.FilterNotCreatedException.class);

+

+        FilterFactories.createFilterFactory(NonInstantiableFilterFactory.class);

+    }

+

+    public static class NonFilterFactory {

+    }

+

+    public static class NonInstantiableFilterFactory implements FilterFactory {

+        private NonInstantiableFilterFactory() {

+        }

+

+        public Filter createFilter(FilterFactoryParams params) throws FilterNotCreatedException {

+            throw new FilterNotCreatedException(new Exception("not implemented"));

+        }

+    }

+

+    public static class FilterFactoryStub implements FilterFactory {

+        public Filter createFilter(FilterFactoryParams params) {

+            return new DummyFilter(params.getTopLevelDescription());

+        }

+    }

+

+    private static class DummyFilter extends Filter {

+        private final Description fTopLevelDescription;

+

+        public DummyFilter(Description topLevelDescription) {

+            fTopLevelDescription = topLevelDescription;

+        }

+

+        public Description getTopLevelDescription() {

+            return fTopLevelDescription;

+        }

+

+        @Override

+        public boolean shouldRun(Description description) {

+            return false;

+        }

+

+        @Override

+        public String describe() {

+            return null;

+        }

+    }

+

+    public static class DummyCategory {

+    }

+

+    @RunWith(Suite.class)

+    @SuiteClasses(DummyTest.class)

+    public static class DummySuite {

+    }

+

+    public static class DummyTest {

+        @Test

+        public void passes() {

+        }

+    }

+}

diff --git a/src/test/java/org/junit/runner/FilterOptionIntegrationTest.java b/src/test/java/org/junit/runner/FilterOptionIntegrationTest.java
new file mode 100644
index 0000000..25cde87
--- /dev/null
+++ b/src/test/java/org/junit/runner/FilterOptionIntegrationTest.java
@@ -0,0 +1,190 @@
+package org.junit.runner;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.experimental.categories.ExcludeCategories;
+import org.junit.experimental.categories.IncludeCategories;
+import org.junit.runner.notification.RunListener;
+import org.junit.tests.TestSystem;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class FilterOptionIntegrationTest {
+    private static final String INCLUDES_DUMMY_CATEGORY_0 = "--filter=" +
+            IncludeCategories.class.getName() + "=" + DummyCategory0.class.getName();
+    private static final String EXCLUDES_DUMMY_CATEGORY_1 = "--filter=" +
+            ExcludeCategories.class.getName() + "=" + DummyCategory1.class.getName();
+
+    private JUnitCore jUnitCore = new JUnitCore();
+    private TestListener testListener = new TestListener();
+
+    @Before
+    public void setUp() {
+        jUnitCore.addListener(testListener);
+    }
+
+    @Test
+    public void shouldRunAllTests() {
+        Result result = runJUnit(
+                DummyTestClass.class.getName(),
+                DummyTestClass0.class.getName(),
+                DummyTestClass1.class.getName(),
+                DummyTestClass01.class.getName(),
+                DummyTestClass0TestMethod1.class.getName());
+
+        assertWasRun(DummyTestClass.class);
+        assertWasRun(DummyTestClass0.class);
+        assertWasRun(DummyTestClass1.class);
+        assertWasRun(DummyTestClass01.class);
+        assertWasRun(DummyTestClass0TestMethod1.class);
+        assertThat("runCount does not match", result.getRunCount(), is(5));
+        assertThat("failureCount does not match", result.getFailureCount(), is(0));
+    }
+
+    @Test
+    public void shouldExcludeSomeTests() {
+        Result result = runJUnit(
+                EXCLUDES_DUMMY_CATEGORY_1,
+                DummyTestClass.class.getName(),
+                DummyTestClass0.class.getName(),
+                DummyTestClass1.class.getName(),
+                DummyTestClass01.class.getName(),
+                DummyTestClass0TestMethod1.class.getName());
+
+        assertWasRun(DummyTestClass.class);
+        assertWasRun(DummyTestClass0.class);
+        assertWasNotRun(DummyTestClass1.class);
+        assertWasNotRun(DummyTestClass01.class);
+        assertWasNotRun(DummyTestClass0TestMethod1.class);
+        assertThat("runCount does not match", result.getRunCount(), is(2));
+        assertThat("failureCount does not match", result.getFailureCount(), is(0));
+    }
+
+    @Test
+    public void shouldIncludeSomeTests() {
+        Result result = runJUnit(
+                INCLUDES_DUMMY_CATEGORY_0,
+                DummyTestClass.class.getName(),
+                DummyTestClass0.class.getName(),
+                DummyTestClass1.class.getName(),
+                DummyTestClass01.class.getName(),
+                DummyTestClass0TestMethod1.class.getName());
+
+        assertWasNotRun(DummyTestClass.class);
+        assertWasRun(DummyTestClass0.class);
+        assertWasNotRun(DummyTestClass1.class);
+        assertWasRun(DummyTestClass01.class);
+        assertWasRun(DummyTestClass0TestMethod1.class);
+        assertThat("runCount does not match", result.getRunCount(), is(3));
+        assertThat("failureCount does not match", result.getFailureCount(), is(0));
+    }
+
+    @Test
+    public void shouldCombineFilters() {
+        Result result = runJUnit(
+                INCLUDES_DUMMY_CATEGORY_0,
+                EXCLUDES_DUMMY_CATEGORY_1,
+                DummyTestClass.class.getName(),
+                DummyTestClass0.class.getName(),
+                DummyTestClass1.class.getName(),
+                DummyTestClass01.class.getName(),
+                DummyTestClass0TestMethod1.class.getName());
+
+        assertWasNotRun(DummyTestClass.class);
+        assertWasRun(DummyTestClass0.class);
+        assertWasNotRun(DummyTestClass1.class);
+        assertWasNotRun(DummyTestClass01.class);
+        assertWasNotRun(DummyTestClass0TestMethod1.class);
+        assertThat("runCount does not match", result.getRunCount(), is(1));
+        assertThat("failureCount does not match", result.getFailureCount(), is(0));
+    }
+
+    private Result runJUnit(final String... args) {
+        return jUnitCore.runMain(new TestSystem(), args);
+    }
+
+    private void assertWasRun(Class<?> testClass) {
+        assertTrue(testClass.getName() + " expected to finish but did not", testListener.wasRun(testClass));
+    }
+
+    private void assertWasNotRun(Class<?> testClass) {
+        assertFalse(
+                testClass.getName() + " expected not to have been started but was",
+                testListener.wasRun(testClass));
+    }
+
+    private static class TestListener extends RunListener {
+        private Set<String> startedTests = new HashSet<String>();
+        private Set<String> finishedTests = new HashSet<String>();
+
+        @Override
+        public void testFinished(final Description description) {
+            finishedTests.add(description.getClassName());
+        }
+
+        private boolean testFinished(final Class<?> testClass) {
+            return finishedTests.contains(testClass.getName());
+        }
+
+        @Override
+        public void testStarted(final Description description) {
+            startedTests.add(description.getClassName());
+        }
+
+        private boolean testStarted(final Class<?> testClass) {
+            return startedTests.contains(testClass.getName());
+        }
+
+        public boolean wasRun(final Class<?> testClass) {
+            return testStarted(testClass) && testFinished(testClass);
+        }
+    }
+
+    public static class DummyTestClass {
+        @Test
+        public void dummyTest() {
+        }
+    }
+
+    @Category(DummyCategory0.class)
+    public static class DummyTestClass0 {
+        @Test
+        public void dummyTest() {
+        }
+    }
+
+    @Category(DummyCategory1.class)
+    public static class DummyTestClass1 {
+        @Test
+        public void dummyTest() {
+        }
+    }
+
+    @Category({DummyCategory0.class, DummyCategory1.class})
+    public static class DummyTestClass01 {
+        @Test
+        public void dummyTest() {
+        }
+    }
+
+    @Category(DummyCategory0.class)
+    public static class DummyTestClass0TestMethod1 {
+        @Category(DummyCategory1.class)
+        @Test
+        public void dummyTest() {
+        }
+    }
+
+    public static interface DummyCategory0 {
+    }
+
+    public static interface DummyCategory1 {
+    }
+}
diff --git a/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java b/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java
new file mode 100644
index 0000000..ffd1f1c
--- /dev/null
+++ b/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java
@@ -0,0 +1,146 @@
+package org.junit.runner;

+

+import static org.hamcrest.CoreMatchers.containsString;

+import static org.hamcrest.CoreMatchers.hasItems;

+import static org.hamcrest.CoreMatchers.is;

+import static org.hamcrest.MatcherAssert.assertThat;

+

+import java.util.List;

+

+import org.junit.Rule;

+import org.junit.Test;

+import org.junit.experimental.categories.IncludeCategories;

+import org.junit.rules.ExpectedException;

+import org.junit.runner.manipulation.Filter;

+

+public class JUnitCommandLineParseResultTest {

+    @Rule

+    public ExpectedException expectedException = ExpectedException.none();

+

+    private final JUnitCommandLineParseResult jUnitCommandLineParseResult = new JUnitCommandLineParseResult();

+

+    @Test

+    public void shouldStopParsingOptionsUponDoubleHyphenArg() throws Exception {

+        String[] restOfArgs = jUnitCommandLineParseResult.parseOptions(

+                "--0", "--1", "--", "--2", "--3");

+

+        assertThat(restOfArgs, is(new String[]{"--2", "--3"}));

+    }

+

+    @Test

+    public void shouldParseFilterArgWithEqualsSyntax() throws Exception {

+        String value= IncludeCategories.class.getName() + "=" + DummyCategory0.class.getName();

+        jUnitCommandLineParseResult.parseOptions("--filter=" + value);

+

+        List<String> specs= jUnitCommandLineParseResult.getFilterSpecs();

+

+        assertThat(specs, hasItems(value));

+    }

+

+    @Test

+    public void shouldCreateFailureUponBaldFilterOptionNotFollowedByValue() {

+        jUnitCommandLineParseResult.parseOptions("--filter");

+

+        Runner runner = jUnitCommandLineParseResult.createRequest(new Computer()).getRunner();

+        Description description = runner.getDescription().getChildren().get(0);

+

+        assertThat(description.toString(), containsString("initializationError"));

+    }

+

+    @Test

+    public void shouldParseFilterArgInWhichValueIsASeparateArg() throws Exception {

+        String value= IncludeCategories.class.getName() + "=" + DummyCategory0.class.getName();

+        jUnitCommandLineParseResult.parseOptions("--filter", value);

+

+        List<String> specs= jUnitCommandLineParseResult.getFilterSpecs();

+

+        assertThat(specs, hasItems(value));

+    }

+

+    @Test

+    public void shouldStopParsingOptionsUponNonOption() throws Exception {

+        String[] restOfArgs = jUnitCommandLineParseResult.parseOptions(new String[]{

+                "--0", "--1", "2", "3"

+        });

+

+        assertThat(restOfArgs, is(new String[]{"2", "3"}));

+    }

+

+    @Test

+    public void shouldCreateFailureUponUnknownOption() throws Exception {

+        String unknownOption = "--unknown-option";

+        jUnitCommandLineParseResult.parseOptions(new String[]{

+                unknownOption

+        });

+

+        Runner runner = jUnitCommandLineParseResult.createRequest(new Computer()).getRunner();

+        Description description = runner.getDescription().getChildren().get(0);

+

+        assertThat(description.toString(), containsString("initializationError"));

+    }

+

+    @Test

+    public void shouldCreateFailureUponUncreatedFilter() throws Exception {

+        jUnitCommandLineParseResult.parseOptions(new String[]{

+                "--filter=" + FilterFactoryStub.class.getName()

+        });

+

+        Runner runner = jUnitCommandLineParseResult.createRequest(new Computer()).getRunner();

+        Description description = runner.getDescription().getChildren().get(0);

+

+        assertThat(description.toString(), containsString("initializationError"));

+    }

+

+    @Test

+    public void shouldCreateFailureUponUnfoundFilterFactory() throws Exception {

+        String nonExistentFilterFactory = "NonExistentFilterFactory";

+        jUnitCommandLineParseResult.parseOptions(new String[]{

+                "--filter=" + nonExistentFilterFactory

+        });

+

+        Runner runner = jUnitCommandLineParseResult.createRequest(new Computer()).getRunner();

+        Description description = runner.getDescription().getChildren().get(0);

+

+        assertThat(description.toString(), containsString("initializationError"));

+    }

+

+    @Test

+    public void shouldAddToClasses() {

+        jUnitCommandLineParseResult.parseParameters(new String[]{

+                DummyTest.class.getName()

+        });

+

+        List<Class<?>> classes = jUnitCommandLineParseResult.getClasses();

+        Class<?> testClass = classes.get(0);

+

+        assertThat(testClass.getName(), is(DummyTest.class.getName()));

+    }

+

+    @Test

+    public void shouldCreateFailureUponUnknownTestClass() throws Exception {

+        String unknownTestClass = "UnknownTestClass";

+        jUnitCommandLineParseResult.parseParameters(new String[]{

+                unknownTestClass

+        });

+

+        Runner runner = jUnitCommandLineParseResult.createRequest(new Computer()).getRunner();

+        Description description = runner.getDescription().getChildren().get(0);

+

+        assertThat(description.toString(), containsString("initializationError"));

+    }

+

+    public static class FilterFactoryStub implements FilterFactory {

+        public Filter createFilter(FilterFactoryParams params) throws FilterNotCreatedException {

+            throw new FilterNotCreatedException(new Exception("stub"));

+        }

+    }

+

+    public static interface DummyCategory0 {

+    }

+

+    public static class DummyTest {

+        @Test

+        public void dummyTest() {

+        }

+    }

+}

diff --git a/src/test/java/org/junit/runner/JUnitCoreTest.java b/src/test/java/org/junit/runner/JUnitCoreTest.java
new file mode 100644
index 0000000..2c5e408
--- /dev/null
+++ b/src/test/java/org/junit/runner/JUnitCoreTest.java
@@ -0,0 +1,20 @@
+package org.junit.runner;
+
+import org.junit.Test;
+import org.junit.tests.TestSystem;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class JUnitCoreTest {
+    @Test
+    public void shouldAddFailuresToResult() {
+        JUnitCore jUnitCore = new JUnitCore();
+
+        Result result = jUnitCore.runMain(new TestSystem(), "NonExistentTest");
+
+        assertThat(result.getFailureCount(), is(1));
+        assertThat(result.getFailures().get(0).getException(), instanceOf(IllegalArgumentException.class));
+    }
+}
diff --git a/src/test/java/org/junit/runner/RunnerSpy.java b/src/test/java/org/junit/runner/RunnerSpy.java
new file mode 100644
index 0000000..939cd75
--- /dev/null
+++ b/src/test/java/org/junit/runner/RunnerSpy.java
@@ -0,0 +1,37 @@
+package org.junit.runner;
+
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.RunnerBuilder;
+
+public class RunnerSpy extends Runner {
+    public static final Description DESCRIPTION = Description.TEST_MECHANISM;
+
+    private RunnerBuilder invokedRunnerBuilder;
+    private Class<?> invokedTestClass;
+
+    public RunnerSpy(Class<?> testClass) {
+        invokedTestClass = testClass;
+    }
+
+    public RunnerSpy(Class<?> testClass, RunnerBuilder runnerBuilder) {
+        invokedTestClass = testClass;
+        invokedRunnerBuilder = runnerBuilder;
+    }
+
+    @Override
+    public Description getDescription() {
+        return DESCRIPTION;
+    }
+
+    @Override
+    public void run(RunNotifier runNotifier) {
+    }
+
+    public RunnerBuilder getInvokedRunnerBuilder() {
+        return invokedRunnerBuilder;
+    }
+
+    public Class<?> getInvokedTestClass() {
+        return invokedTestClass;
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/runner/notification/ConcurrentRunNotifierTest.java b/src/test/java/org/junit/runner/notification/ConcurrentRunNotifierTest.java
new file mode 100644
index 0000000..3406ed9
--- /dev/null
+++ b/src/test/java/org/junit/runner/notification/ConcurrentRunNotifierTest.java
@@ -0,0 +1,180 @@
+package org.junit.runner.notification;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Testing RunNotifier in concurrent access.
+ *
+ * @author Tibor Digana (tibor17)
+ * @version 4.12
+ * @since 4.12
+ */
+public final class ConcurrentRunNotifierTest {
+    private static final long TIMEOUT = 3;
+    private final RunNotifier fNotifier = new RunNotifier();
+
+    private static class ConcurrentRunListener extends RunListener {
+        final AtomicInteger fTestStarted = new AtomicInteger(0);
+
+        @Override
+        public void testStarted(Description description) throws Exception {
+            fTestStarted.incrementAndGet();
+        }
+    }
+
+    @Test
+    public void realUsage() throws Exception {
+        ConcurrentRunListener listener1 = new ConcurrentRunListener();
+        ConcurrentRunListener listener2 = new ConcurrentRunListener();
+        fNotifier.addListener(listener1);
+        fNotifier.addListener(listener2);
+
+        final int numParallelTests = 4;
+        ExecutorService pool = Executors.newFixedThreadPool(numParallelTests);
+        for (int i = 0; i < numParallelTests; ++i) {
+            pool.submit(new Runnable() {
+                public void run() {
+                    fNotifier.fireTestStarted(null);
+                }
+            });
+        }
+        pool.shutdown();
+        assertTrue(pool.awaitTermination(TIMEOUT, TimeUnit.SECONDS));
+
+        fNotifier.removeListener(listener1);
+        fNotifier.removeListener(listener2);
+
+        assertThat(listener1.fTestStarted.get(), is(numParallelTests));
+        assertThat(listener2.fTestStarted.get(), is(numParallelTests));
+    }
+
+    private static class ExaminedListener extends RunListener {
+        final boolean throwFromTestStarted;
+        volatile boolean hasTestFailure = false;
+
+        ExaminedListener(boolean throwFromTestStarted) {
+            this.throwFromTestStarted = throwFromTestStarted;
+        }
+
+        @Override
+        public void testStarted(Description description) throws Exception {
+            if (throwFromTestStarted) {
+                throw new Exception();
+            }
+        }
+
+        @Override
+        public void testFailure(Failure failure) throws Exception {
+            hasTestFailure = true;
+        }
+    }
+
+    private abstract class AbstractConcurrentFailuresTest {
+
+        protected abstract void addListener(ExaminedListener listener);
+
+        public void test() throws Exception {
+            int totalListenersFailures = 0;
+
+            Random random = new Random(42);
+            ExaminedListener[] examinedListeners = new ExaminedListener[1000];
+            for (int i = 0; i < examinedListeners.length; ++i) {
+                boolean fail = random.nextDouble() >= 0.5d;
+                if (fail) {
+                    ++totalListenersFailures;
+                }
+                examinedListeners[i] = new ExaminedListener(fail);
+            }
+
+            final AtomicBoolean condition = new AtomicBoolean(true);
+            final CyclicBarrier trigger = new CyclicBarrier(2);
+            final CountDownLatch latch = new CountDownLatch(10);
+
+            ExecutorService notificationsPool = Executors.newFixedThreadPool(4);
+            notificationsPool.submit(new Callable<Void>() {
+                public Void call() throws Exception {
+                    trigger.await();
+                    while (condition.get()) {
+                        fNotifier.fireTestStarted(null);
+                        latch.countDown();
+                    }
+                    fNotifier.fireTestStarted(null);
+                    return null;
+                }
+            });
+
+            // Wait for callable to start
+            trigger.await(TIMEOUT, TimeUnit.SECONDS);
+
+            // Wait for callable to fire a few events
+            latch.await(TIMEOUT, TimeUnit.SECONDS);
+
+            for (ExaminedListener examinedListener : examinedListeners) {
+              addListener(examinedListener);
+            }
+
+            notificationsPool.shutdown();
+            condition.set(false);
+            assertTrue(notificationsPool.awaitTermination(TIMEOUT, TimeUnit.SECONDS));
+
+            if (totalListenersFailures != 0) {
+                // If no listener failures, then all the listeners do not report any failure.
+                int countTestFailures = examinedListeners.length - countReportedTestFailures(examinedListeners);
+                assertThat(totalListenersFailures, is(countTestFailures));
+            }
+        }
+    }
+
+    /**
+     * Verifies that listeners added while tests are run concurrently are
+     * notified about test failures.
+     */
+    @Test
+    public void reportConcurrentFailuresAfterAddListener() throws Exception {
+        new AbstractConcurrentFailuresTest() {
+            @Override
+            protected void addListener(ExaminedListener listener) {
+                fNotifier.addListener(listener);
+            }
+        }.test();
+    }
+
+    /**
+     * Verifies that listeners added with addFirstListener() while tests are run concurrently are
+     * notified about test failures.
+     */
+    @Test
+    public void reportConcurrentFailuresAfterAddFirstListener() throws Exception {
+        new AbstractConcurrentFailuresTest() {
+            @Override
+            protected void addListener(ExaminedListener listener) {
+                fNotifier.addFirstListener(listener);
+            }
+        }.test();
+    }
+
+    private static int countReportedTestFailures(ExaminedListener[] listeners) {
+        int count = 0;
+        for (ExaminedListener listener : listeners) {
+            if (listener.hasTestFailure) {
+                ++count;
+            }
+        }
+        return count;
+    }
+}
diff --git a/src/test/java/org/junit/runner/notification/RunNotifierTest.java b/src/test/java/org/junit/runner/notification/RunNotifierTest.java
index 28bfc75..1c2e7c9 100644
--- a/src/test/java/org/junit/runner/notification/RunNotifierTest.java
+++ b/src/test/java/org/junit/runner/notification/RunNotifierTest.java
@@ -1,30 +1,36 @@
 package org.junit.runner.notification;
 
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.junit.Test;
+import org.junit.runner.Description;
 import org.junit.runner.Result;
 
 public class RunNotifierTest {
+    private final RunNotifier fNotifier = new RunNotifier();
 
     @Test
     public void notifiesSecondListenerIfFirstThrowsException() {
         FailureListener failureListener = new FailureListener();
-        RunNotifier notifier = new RunNotifier();
-        notifier.addListener(new CorruptListener());
-        notifier.addListener(failureListener);
-        notifier.fireTestFailure(new Failure(null, null));
+        fNotifier.addListener(new CorruptListener());
+        fNotifier.addListener(failureListener);
+        fNotifier.fireTestFailure(new Failure(null, null));
         assertNotNull("The FailureListener registered no failure.",
                 failureListener.failure);
     }
 
     @Test
     public void hasNoProblemsWithFailingListeners() { // see issues 209 and 395
-        RunNotifier notifier = new RunNotifier();
-        notifier.addListener(new CorruptListener());
-        notifier.addListener(new FailureListener());
-        notifier.addListener(new CorruptListener());
-        notifier.fireTestRunFinished(new Result());
+        fNotifier.addListener(new CorruptListener());
+        fNotifier.addListener(new FailureListener());
+        fNotifier.addListener(new CorruptListener());
+        fNotifier.fireTestRunFinished(new Result());
     }
 
     private static class CorruptListener extends RunListener {
@@ -38,6 +44,67 @@
             throw new RuntimeException();
         }
     }
+    
+    @Test
+    public void addAndRemoveWithNonThreadSafeListener() {
+        CountingListener listener = new CountingListener();
+        assertThat(listener.fTestStarted.get(), is(0));
+        fNotifier.addListener(listener);
+        fNotifier.fireTestStarted(null);
+        assertThat(listener.fTestStarted.get(), is(1));
+        fNotifier.removeListener(listener);
+        fNotifier.fireTestStarted(null);
+        assertThat(listener.fTestStarted.get(), is(1));
+    }
+
+    @Test
+    public void addFirstAndRemoveWithNonThreadSafeListener() {
+        CountingListener listener = new CountingListener();
+        assertThat(listener.fTestStarted.get(), is(0));
+        fNotifier.addFirstListener(listener);
+        fNotifier.fireTestStarted(null);
+        assertThat(listener.fTestStarted.get(), is(1));
+        fNotifier.removeListener(listener);
+        fNotifier.fireTestStarted(null);
+        assertThat(listener.fTestStarted.get(), is(1));
+    }
+    
+    @Test
+    public void addAndRemoveWithThreadSafeListener() {
+        ThreadSafeListener listener = new ThreadSafeListener();
+        assertThat(listener.fTestStarted.get(), is(0));
+        fNotifier.addListener(listener);
+        fNotifier.fireTestStarted(null);
+        assertThat(listener.fTestStarted.get(), is(1));
+        fNotifier.removeListener(listener);
+        fNotifier.fireTestStarted(null);
+        assertThat(listener.fTestStarted.get(), is(1));
+    }
+
+    @Test
+    public void addFirstAndRemoveWithThreadSafeListener() {
+        ThreadSafeListener listener = new ThreadSafeListener();
+        assertThat(listener.fTestStarted.get(), is(0));
+        fNotifier.addFirstListener(listener);
+        fNotifier.fireTestStarted(null);
+        assertThat(listener.fTestStarted.get(), is(1));
+        fNotifier.removeListener(listener);
+        fNotifier.fireTestStarted(null);
+        assertThat(listener.fTestStarted.get(), is(1));
+    }
+
+    @Test
+    public void wrapIfNotThreadSafeShouldNotWrapThreadSafeListeners() {
+        ThreadSafeListener listener = new ThreadSafeListener();;
+        assertSame(listener, new RunNotifier().wrapIfNotThreadSafe(listener));
+    }
+
+    @Test
+    public void wrapIfNotThreadSafeShouldWrapNonThreadSafeListeners() {
+        CountingListener listener = new CountingListener();
+        RunListener wrappedListener = new RunNotifier().wrapIfNotThreadSafe(listener);
+        assertThat(wrappedListener, instanceOf(SynchronizedRunListener.class));
+    }
 
     private static class FailureListener extends RunListener {
         private Failure failure;
@@ -47,4 +114,18 @@
             this.failure = failure;
         }
     }
+    
+    private static class CountingListener extends RunListener {
+        final AtomicInteger fTestStarted = new AtomicInteger(0);
+
+        @Override
+        public void testStarted(Description description) throws Exception {
+            fTestStarted.incrementAndGet();
+        }
+    }
+    
+    @RunListener.ThreadSafe
+    private static class ThreadSafeListener extends CountingListener {
+    }
+
 }
diff --git a/src/test/java/org/junit/runner/notification/SynchronizedRunListenerTest.java b/src/test/java/org/junit/runner/notification/SynchronizedRunListenerTest.java
new file mode 100644
index 0000000..6bd39b7
--- /dev/null
+++ b/src/test/java/org/junit/runner/notification/SynchronizedRunListenerTest.java
@@ -0,0 +1,156 @@
+package org.junit.runner.notification;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link SynchronizedRunListener}.
+ *
+ * @author kcooney (Kevin Cooney)
+ */
+public class SynchronizedRunListenerTest {
+
+    private static class MethodSignature {
+        private final Method fMethod;
+        private final String fName;
+        private final List<Class<?>> fParameterTypes;
+
+        public MethodSignature(Method method) {
+            fMethod = method;
+            fName = method.getName();
+            fParameterTypes = Arrays.asList(method.getParameterTypes());
+        }
+
+        @Override
+        public String toString() {
+            return fMethod.toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return fName.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof MethodSignature)) {
+                return false;
+            }
+            MethodSignature that = (MethodSignature) obj;
+            return fName.equals(that.fName) && fParameterTypes.equals(that.fParameterTypes);
+        }
+    }
+
+    private Set<MethodSignature> getAllDeclaredMethods(Class<?> type) {
+        Set<MethodSignature> methods = new HashSet<MethodSignature>();
+        for (Method method : type.getDeclaredMethods()) {
+          methods.add(new MethodSignature(method));
+        }
+        return methods;
+    }
+
+    @Test
+    public void overridesAllMethodsInRunListener() {
+        Set<MethodSignature> runListenerMethods = getAllDeclaredMethods(RunListener.class);
+        Set<MethodSignature> synchronizedRunListenerMethods = getAllDeclaredMethods(
+                SynchronizedRunListener.class);
+
+        assertTrue(synchronizedRunListenerMethods.containsAll(runListenerMethods));
+    }
+
+    private static class NamedListener extends RunListener {
+        private final String fName;
+
+        public NamedListener(String name) {
+            fName = name;
+        }
+
+        @Override
+        public String toString() {
+          return "NamedListener";
+        }
+
+        @Override
+        public int hashCode() {
+            return fName.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof NamedListener)) {
+                return false;
+            }
+            NamedListener that = (NamedListener) obj;
+            return this.fName.equals(that.fName);
+        }
+    }
+
+    @Test
+    public void namedListenerCorrectlyImplementsEqualsAndHashCode() {
+        NamedListener listener1 = new NamedListener("blue");
+        NamedListener listener2 = new NamedListener("blue");
+        NamedListener listener3 = new NamedListener("red");
+
+        assertTrue(listener1.equals(listener1));
+        assertTrue(listener2.equals(listener2));
+        assertTrue(listener3.equals(listener3));
+
+        assertFalse(listener1.equals(null));
+        assertFalse(listener1.equals(new Object()));
+
+        assertTrue(listener1.equals(listener2));
+        assertTrue(listener2.equals(listener1));
+        assertFalse(listener1.equals(listener3));
+        assertFalse(listener3.equals(listener1));
+
+        assertEquals(listener1.hashCode(), listener2.hashCode());
+        assertNotEquals(listener1.hashCode(), listener3.hashCode());
+    }
+
+    @Test
+    public void toStringDelegates() {
+        NamedListener listener = new NamedListener("blue");
+
+        assertEquals("NamedListener", listener.toString());
+        assertEquals("NamedListener (with synchronization wrapper)", wrap(listener).toString());
+    }
+
+    @Test
+    public void equalsDelegates() {
+        NamedListener listener1 = new NamedListener("blue");
+        NamedListener listener2 = new NamedListener("blue");
+        NamedListener listener3 = new NamedListener("red");
+
+        assertEquals(wrap(listener1), wrap(listener1));
+        assertEquals(wrap(listener1), wrap(listener2));
+        assertNotEquals(wrap(listener1), wrap(listener3));
+        assertNotEquals(wrap(listener1), listener1);
+        assertNotEquals(listener1, wrap(listener1));
+    }
+
+    @Test
+    public void hashCodeDelegates() {
+        NamedListener listener = new NamedListener("blue");
+        assertEquals(listener.hashCode(), wrap(listener).hashCode());
+    }
+
+    private SynchronizedRunListener wrap(RunListener listener) {
+        return new SynchronizedRunListener(listener, this);
+    }
+}
diff --git a/src/test/java/org/junit/runners/CustomBlockJUnit4ClassRunnerTest.java b/src/test/java/org/junit/runners/CustomBlockJUnit4ClassRunnerTest.java
new file mode 100644
index 0000000..d9f072b
--- /dev/null
+++ b/src/test/java/org/junit/runners/CustomBlockJUnit4ClassRunnerTest.java
@@ -0,0 +1,90 @@
+package org.junit.runners;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+/**
+ * Tests that verify proper behavior for custom runners that extend
+ * {@link BlockJUnit4ClassRunner}.
+ *
+ * @author Sam Brannen
+ * @since 4.13
+ */
+public class CustomBlockJUnit4ClassRunnerTest {
+
+	@Test
+	public void exceptionsFromMethodBlockMustNotResultInUnrootedTests() throws Exception {
+		TrackingRunListener listener = new TrackingRunListener();
+		RunNotifier notifier = new RunNotifier();
+		notifier.addListener(listener);
+
+		new CustomBlockJUnit4ClassRunner(CustomBlockJUnit4ClassRunnerTestCase.class).run(notifier);
+		assertEquals("tests started.", 2, listener.testStartedCount.get());
+		assertEquals("tests failed.", 1, listener.testFailureCount.get());
+		assertEquals("tests finished.", 2, listener.testFinishedCount.get());
+	}
+
+
+	public static class CustomBlockJUnit4ClassRunnerTestCase {
+		@Test public void shouldPass() { /* no-op */ }
+		@Test public void throwException() { /* no-op */ }
+	}
+
+	/**
+	 * Custom extension of {@link BlockJUnit4ClassRunner} that always throws
+	 * an exception from the {@code methodBlock()} if a test method is named
+	 * exactly {@code "throwException"}.
+	 */
+	private static class CustomBlockJUnit4ClassRunner extends BlockJUnit4ClassRunner {
+
+		CustomBlockJUnit4ClassRunner(Class<?> testClass) throws InitializationError {
+			super(testClass);
+		}
+
+		@Override
+		protected Statement methodBlock(FrameworkMethod method) {
+			if ("throwException".equals(method.getName())) {
+				throw new RuntimeException("throwException() test method invoked");
+			}
+			return super.methodBlock(method);
+		}
+	}
+
+	/**
+	 * Simple {@link RunListener} that tracks the number of times that
+	 * certain callbacks are invoked.
+	 */
+	private static class TrackingRunListener extends RunListener {
+
+		final AtomicInteger testStartedCount = new AtomicInteger();
+		final AtomicInteger testFailureCount = new AtomicInteger();
+		final AtomicInteger testFinishedCount = new AtomicInteger();
+
+
+		@Override
+		public void testStarted(Description description) throws Exception {
+			testStartedCount.incrementAndGet();
+		}
+
+		@Override
+		public void testFailure(Failure failure) throws Exception {
+			testFailureCount.incrementAndGet();
+		}
+
+		@Override
+		public void testFinished(Description description) throws Exception {
+			testFinishedCount.incrementAndGet();
+		}
+	}
+
+}
diff --git a/src/test/java/org/junit/runners/model/FrameworkFieldTest.java b/src/test/java/org/junit/runners/model/FrameworkFieldTest.java
new file mode 100644
index 0000000..1d185a5
--- /dev/null
+++ b/src/test/java/org/junit/runners/model/FrameworkFieldTest.java
@@ -0,0 +1,58 @@
+package org.junit.runners.model;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.rules.ExpectedException.none;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class FrameworkFieldTest {
+    @Rule
+    public final ExpectedException thrown = none();
+
+    @Test
+    public void cannotBeCreatedWithoutUnderlyingField() {
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage("FrameworkField cannot be created without an underlying field.");
+        new FrameworkField(null);
+    }
+
+    @Test
+    public void hasToStringWhichPrintsFieldName() throws Exception {
+        Field field = ClassWithDummyField.class.getField("dummyField");
+        FrameworkField frameworkField = new FrameworkField(field);
+        assertTrue(frameworkField.toString().contains("dummyField"));
+    }
+
+    @Test
+    public void presentAnnotationIsAvailable() throws Exception {
+        Field field = ClassWithDummyField.class.getField("annotatedField");
+        FrameworkField frameworkField = new FrameworkField(field);
+        Annotation annotation = frameworkField.getAnnotation(Rule.class);
+        assertTrue(Rule.class.isAssignableFrom(annotation.getClass()));
+    }
+
+    @Test
+    public void missingAnnotationIsNotAvailable() throws Exception {
+        Field field = ClassWithDummyField.class.getField("annotatedField");
+        FrameworkField frameworkField = new FrameworkField(field);
+        Annotation annotation = frameworkField.getAnnotation(ClassRule.class);
+        assertThat(annotation, is(nullValue()));
+    }
+
+    private static class ClassWithDummyField {
+        @SuppressWarnings("unused")
+        public final int dummyField = 0;
+
+        @Rule
+        public final int annotatedField = 0;
+    }
+}
diff --git a/src/test/java/org/junit/runners/model/FrameworkMethodTest.java b/src/test/java/org/junit/runners/model/FrameworkMethodTest.java
new file mode 100644
index 0000000..9927d19
--- /dev/null
+++ b/src/test/java/org/junit/runners/model/FrameworkMethodTest.java
@@ -0,0 +1,60 @@
+package org.junit.runners.model;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.rules.ExpectedException.none;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class FrameworkMethodTest {
+    @Rule
+    public final ExpectedException thrown = none();
+
+    @Test
+    public void cannotBeCreatedWithoutUnderlyingField() {
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage("FrameworkMethod cannot be created without an underlying method.");
+        new FrameworkMethod(null);
+    }
+
+    @Test
+    public void hasToStringWhichPrintsMethodName() throws Exception {
+        Method method = ClassWithDummyMethod.class.getMethod("dummyMethod");
+        FrameworkMethod frameworkMethod = new FrameworkMethod(method);
+        assertTrue(frameworkMethod.toString().contains("dummyMethod"));
+    }
+
+    @Test
+    public void presentAnnotationIsAvailable() throws Exception {
+        Method method = ClassWithDummyMethod.class.getMethod("annotatedDummyMethod");
+        FrameworkMethod frameworkMethod = new FrameworkMethod(method);
+        Annotation annotation = frameworkMethod.getAnnotation(Rule.class);
+        assertTrue(Rule.class.isAssignableFrom(annotation.getClass()));
+    }
+
+    @Test
+    public void missingAnnotationIsNotAvailable() throws Exception {
+        Method method = ClassWithDummyMethod.class.getMethod("annotatedDummyMethod");
+        FrameworkMethod frameworkMethod = new FrameworkMethod(method);
+        Annotation annotation = frameworkMethod.getAnnotation(ClassRule.class);
+        assertThat(annotation, is(nullValue()));
+    }
+
+    private static class ClassWithDummyMethod {
+        @SuppressWarnings("unused")
+        public void dummyMethod() {
+        }
+
+        @Rule
+        public void annotatedDummyMethod() {
+        }
+    }
+}
diff --git a/src/test/java/org/junit/runners/model/RunnerBuilderStub.java b/src/test/java/org/junit/runners/model/RunnerBuilderStub.java
new file mode 100644
index 0000000..2e11137
--- /dev/null
+++ b/src/test/java/org/junit/runners/model/RunnerBuilderStub.java
@@ -0,0 +1,11 @@
+package org.junit.runners.model;
+
+import org.junit.runner.Runner;
+import org.junit.runner.RunnerSpy;
+
+public class RunnerBuilderStub extends RunnerBuilder {
+    @Override
+    public Runner runnerForClass(Class<?> testClass) throws Throwable {
+        return new RunnerSpy(testClass, this);
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/runners/model/TestClassTest.java b/src/test/java/org/junit/runners/model/TestClassTest.java
new file mode 100644
index 0000000..7682968
--- /dev/null
+++ b/src/test/java/org/junit/runners/model/TestClassTest.java
@@ -0,0 +1,245 @@
+package org.junit.runners.model;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+public class TestClassTest {
+
+    @Rule
+    public ExpectedException exception = ExpectedException.none();
+
+    public static class TwoConstructors {
+        public TwoConstructors() {
+        }
+
+        public TwoConstructors(int x) {
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void complainIfMultipleConstructors() {
+        new TestClass(TwoConstructors.class);
+    }
+
+    public static class SuperclassWithField {
+        @Rule
+        public TestRule x;
+    }
+
+    public static class SubclassWithField extends SuperclassWithField {
+        @Rule
+        public TestRule x;
+    }
+
+    @Test
+    public void fieldsOnSubclassesShadowSuperclasses() {
+        assertThat(new TestClass(SubclassWithField.class).getAnnotatedFields(
+                Rule.class).size(), is(1));
+    }
+
+    public static class OuterClass {
+        public class NonStaticInnerClass {
+        }
+    }
+
+    @Test
+    public void identifyNonStaticInnerClass() {
+        assertThat(
+                new TestClass(OuterClass.NonStaticInnerClass.class)
+                        .isANonStaticInnerClass(),
+                is(true));
+    }
+
+    public static class OuterClass2 {
+        public static class StaticInnerClass {
+        }
+    }
+
+    @Test
+    public void dontMarkStaticInnerClassAsNonStatic() {
+        assertThat(
+                new TestClass(OuterClass2.StaticInnerClass.class)
+                        .isANonStaticInnerClass(),
+                is(false));
+    }
+
+    public static class SimpleClass {
+    }
+
+    @Test
+    public void dontMarkNonInnerClassAsInnerClass() {
+        assertThat(new TestClass(SimpleClass.class).isANonStaticInnerClass(),
+                is(false));
+    }
+
+    public static class FieldAnnotated {
+        @Rule
+        public String fieldC= "andromeda";
+
+        @Rule
+        public boolean fieldA;
+
+        @Rule
+        public boolean fieldB;
+    }
+
+    @Test
+    public void providesAnnotatedFieldsSortedByName() {
+        TestClass tc= new TestClass(FieldAnnotated.class);
+        List<FrameworkField> annotatedFields= tc.getAnnotatedFields();
+        assertThat("Wrong number of annotated fields.", annotatedFields.size(), is(3));
+        assertThat("First annotated field is wrong.", annotatedFields
+            .iterator().next().getName(), is("fieldA"));
+    }
+
+    @Test
+    public void annotatedFieldValues() {
+        TestClass tc = new TestClass(FieldAnnotated.class);
+        List<String> values = tc.getAnnotatedFieldValues(new FieldAnnotated(), Rule.class, String.class);
+        assertThat(values, hasItem("andromeda"));
+        assertThat(values.size(), is(1));
+    }
+
+    public static class MethodsAnnotated {
+        @Ignore
+        @Test
+        public int methodC() {
+            return 0;
+        }
+
+        @Ignore
+        @Test
+        public String methodA() {
+            return "jupiter";
+        }
+
+        @Ignore
+        @Test
+        public int methodB() {
+            return 0;
+    	}
+    }
+
+    @Test
+    public void providesAnnotatedMethodsSortedByName() {
+    	TestClass tc = new TestClass(MethodsAnnotated.class);
+    	List<FrameworkMethod> annotatedMethods = tc.getAnnotatedMethods();
+    	assertThat("Wrong number of annotated methods.",
+    	    annotatedMethods.size(), is(3));
+    	assertThat("First annotated method is wrong.", annotatedMethods
+    	    .iterator().next().getName(), is("methodA"));
+    }
+
+    @Test
+    public void annotatedMethodValues() {
+    	TestClass tc = new TestClass(MethodsAnnotated.class);
+    	List<String> values = tc.getAnnotatedMethodValues(
+    	    new MethodsAnnotated(), Ignore.class, String.class);
+    	assertThat(values, hasItem("jupiter"));
+    	assertThat(values.size(), is(1));
+    }
+
+    @Test
+    public void isEqualToTestClassThatWrapsSameJavaClass() {
+        TestClass testClass = new TestClass(DummyClass.class);
+        TestClass testClassThatWrapsSameJavaClass = new TestClass(
+                DummyClass.class);
+        assertTrue(testClass.equals(testClassThatWrapsSameJavaClass));
+    }
+
+    @Test
+    public void isEqualToTestClassThatWrapsNoJavaClassToo() {
+        TestClass testClass = new TestClass(null);
+        TestClass testClassThatWrapsNoJavaClassToo = new TestClass(null);
+        assertTrue(testClass.equals(testClassThatWrapsNoJavaClassToo));
+    }
+
+    @Test
+    public void isNotEqualToTestClassThatWrapsADifferentJavaClass() {
+        TestClass testClass = new TestClass(DummyClass.class);
+        TestClass testClassThatWrapsADifferentJavaClass = new TestClass(
+                AnotherDummyClass.class);
+        assertFalse(testClass.equals(testClassThatWrapsADifferentJavaClass));
+    }
+
+    @Test
+    public void isNotEqualToNull() {
+        TestClass testClass = new TestClass(DummyClass.class);
+        assertFalse(testClass.equals(null));
+    }
+
+    private static class DummyClass {
+    }
+
+    private static class AnotherDummyClass {
+    }
+
+    @Test
+    public void hasSameHashCodeAsTestClassThatWrapsSameJavaClass() {
+        TestClass testClass = new TestClass(DummyClass.class);
+        TestClass testClassThatWrapsSameJavaClass = new TestClass(
+                DummyClass.class);
+        assertEquals(testClass.hashCode(),
+                testClassThatWrapsSameJavaClass.hashCode());
+    }
+
+    @Test
+    public void hasHashCodeWithoutJavaClass() {
+        TestClass testClass = new TestClass(null);
+        testClass.hashCode();
+        // everything is fine if no exception is thrown.
+    }
+
+    public static class PublicClass {
+
+    }
+
+    @Test
+    public void identifiesPublicModifier() {
+        TestClass tc = new TestClass(PublicClass.class);
+        assertEquals("Wrong flag 'public',", true, tc.isPublic());
+    }
+
+    static class NonPublicClass {
+
+    }
+    
+    @Test
+    public void identifiesNonPublicModifier() {
+        TestClass tc = new TestClass(NonPublicClass.class);
+        assertEquals("Wrong flag 'public',", false, tc.isPublic());
+    }
+
+    @Ignore
+    static class AnnotatedClass {
+    }
+
+    @Test
+    public void presentAnnotationIsAvailable() {
+        TestClass tc = new TestClass(AnnotatedClass.class);
+        Annotation annotation = tc.getAnnotation(Ignore.class);
+        assertTrue(Ignore.class.isAssignableFrom(annotation.getClass()));
+    }
+
+    @Test
+    public void missingAnnotationIsNotAvailable() {
+        TestClass tc = new TestClass(AnnotatedClass.class);
+        Annotation annotation = tc.getAnnotation(RunWith.class);
+        assertThat(annotation, is(nullValue()));
+    }
+}
diff --git a/src/test/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersTest.java b/src/test/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersTest.java
new file mode 100644
index 0000000..0bf6374
--- /dev/null
+++ b/src/test/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersTest.java
@@ -0,0 +1,45 @@
+package org.junit.runners.parameterized;
+
+import static java.util.Collections.emptyList;
+import static org.junit.Assert.assertEquals;
+
+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.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.model.TestClass;
+
+public class BlockJUnit4ClassRunnerWithParametersTest {
+    private static final List<Object> NO_PARAMETERS = emptyList();
+
+    @RunWith(Parameterized.class)
+    @DummyAnnotation
+    public static class ClassWithParameterizedAnnotation {
+        @Test
+        public void dummyTest() {
+        }
+    }
+
+    @Test
+    public void hasAllAnnotationsExceptRunWith() throws Exception {
+        TestWithParameters testWithParameters = new TestWithParameters(
+                "dummy name", new TestClass(
+                        ClassWithParameterizedAnnotation.class), NO_PARAMETERS);
+        BlockJUnit4ClassRunnerWithParameters runner = new BlockJUnit4ClassRunnerWithParameters(
+                testWithParameters);
+        Annotation[] annotations = runner.getRunnerAnnotations();
+        assertEquals(1, annotations.length);
+        assertEquals(annotations[0].annotationType(), DummyAnnotation.class);
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    private static @interface DummyAnnotation {
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/runners/parameterized/ParameterizedNamesTest.java b/src/test/java/org/junit/runners/parameterized/ParameterizedNamesTest.java
new file mode 100644
index 0000000..25dedfe
--- /dev/null
+++ b/src/test/java/org/junit/runners/parameterized/ParameterizedNamesTest.java
@@ -0,0 +1,51 @@
+package org.junit.runners.parameterized;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Dmitry Baev charlie@yandex-team.ru
+ *         Date: 03.05.14
+ */
+public class ParameterizedNamesTest {
+    @RunWith(Parameterized.class)
+    public static class ParametrizedWithSpecialCharsInName {
+
+        public ParametrizedWithSpecialCharsInName(String s) {
+        }
+
+        @Parameterized.Parameters(name = "{0}")
+        public static Collection<Object[]> data() {
+            return Arrays.asList(
+                    new Object[]{"\n"},
+                    new Object[]{"\r\n"},
+                    new Object[]{"\r"},
+                    new Object[]{"\u0085"},
+                    new Object[]{"\u2028"},
+                    new Object[]{"\u2029"}
+            );
+        }
+
+        @Test
+        public void test() {
+        }
+    }
+
+    @Test
+    public void parameterizedTestsWithSpecialCharsInName() {
+        Request request = Request.aClass(ParametrizedWithSpecialCharsInName.class);
+        for (Description parent : request.getRunner().getDescription().getChildren()) {
+            for (Description description : parent.getChildren()) {
+                assertEquals("test" + parent.getDisplayName(), description.getMethodName());
+            }
+        }
+    }
+}
diff --git a/src/test/java/org/junit/runners/parameterized/TestWithParametersTest.java b/src/test/java/org/junit/runners/parameterized/TestWithParametersTest.java
new file mode 100644
index 0000000..b8156e9
--- /dev/null
+++ b/src/test/java/org/junit/runners/parameterized/TestWithParametersTest.java
@@ -0,0 +1,137 @@
+package org.junit.runners.parameterized;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.rules.ExpectedException.none;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runners.model.TestClass;
+
+public class TestWithParametersTest {
+    private static final String DUMMY_NAME = "dummy name";
+
+    private static final TestClass DUMMY_TEST_CLASS = new TestClass(
+            DummyClass.class);
+
+    private static final List<Object> DUMMY_PARAMETERS = Arrays
+            .<Object> asList("a", "b");
+
+    @Rule
+    public final ExpectedException thrown = none();
+
+    @Test
+    public void cannotBeCreatedWithoutAName() {
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage("The name is missing.");
+        new TestWithParameters(null, DUMMY_TEST_CLASS, DUMMY_PARAMETERS);
+    }
+
+    @Test
+    public void cannotBeCreatedWithoutTestClass() {
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage("The test class is missing.");
+        new TestWithParameters(DUMMY_NAME, null, DUMMY_PARAMETERS);
+    }
+
+    @Test
+    public void cannotBeCreatedWithoutParameters() {
+        thrown.expect(NullPointerException.class);
+        thrown.expectMessage("The parameters are missing.");
+        new TestWithParameters(DUMMY_NAME, DUMMY_TEST_CLASS,
+                (List<Object>) null);
+    }
+
+    @Test
+    public void doesNotAllowToModifyProvidedParameters() {
+        TestWithParameters test = new TestWithParameters(DUMMY_NAME,
+                DUMMY_TEST_CLASS, DUMMY_PARAMETERS);
+        thrown.expect(UnsupportedOperationException.class);
+        test.getParameters().set(0, "another parameter");
+    }
+
+    @Test
+    public void doesNotConsiderParametersWhichChangedAfterTestInstantiation() {
+        List<Object> parameters = Arrays.<Object> asList("dummy parameter");
+        TestWithParameters test = new TestWithParameters(DUMMY_NAME,
+                DUMMY_TEST_CLASS, parameters);
+        parameters.set(0, "another parameter");
+        assertEquals(asList("dummy parameter"), test.getParameters());
+    }
+
+    @Test
+    public void isEqualToTestWithSameNameAndTestClassAndParameters() {
+        TestWithParameters firstTest = new TestWithParameters(DUMMY_NAME,
+                new TestClass(DummyClass.class), Arrays.<Object> asList("a",
+                        "b"));
+        TestWithParameters secondTest = new TestWithParameters(DUMMY_NAME,
+                new TestClass(DummyClass.class), Arrays.<Object> asList("a",
+                        "b"));
+        assertEquals(firstTest, secondTest);
+    }
+
+    @Test
+    public void isNotEqualToTestWithDifferentName() {
+        TestWithParameters firstTest = new TestWithParameters("name",
+                DUMMY_TEST_CLASS, DUMMY_PARAMETERS);
+        TestWithParameters secondTest = new TestWithParameters("another name",
+                DUMMY_TEST_CLASS, DUMMY_PARAMETERS);
+        assertNotEquals(firstTest, secondTest);
+    }
+
+    @Test
+    public void isNotEqualToTestWithDifferentTestClass() {
+        TestWithParameters firstTest = new TestWithParameters(DUMMY_NAME,
+                new TestClass(DummyClass.class), DUMMY_PARAMETERS);
+        TestWithParameters secondTest = new TestWithParameters(DUMMY_NAME,
+                new TestClass(AnotherDummyClass.class), DUMMY_PARAMETERS);
+        assertNotEquals(firstTest, secondTest);
+    }
+
+    @Test
+    public void isNotEqualToTestWithDifferentParameters() {
+        TestWithParameters firstTest = new TestWithParameters(DUMMY_NAME,
+                DUMMY_TEST_CLASS, Arrays.<Object> asList("a"));
+        TestWithParameters secondTest = new TestWithParameters(DUMMY_NAME,
+                DUMMY_TEST_CLASS, Arrays.<Object> asList("b"));
+        assertNotEquals(firstTest, secondTest);
+    }
+
+    @Test
+    public void isNotEqualToObjectWithDifferentClass() {
+        TestWithParameters test = new TestWithParameters(DUMMY_NAME,
+                DUMMY_TEST_CLASS, DUMMY_PARAMETERS);
+        assertNotEquals(test, new Integer(3));
+    }
+
+    @Test
+    public void hasSameHashCodeAsEqualTest() {
+        TestWithParameters firstTest = new TestWithParameters(DUMMY_NAME,
+                DUMMY_TEST_CLASS, DUMMY_PARAMETERS);
+        TestWithParameters secondTest = new TestWithParameters(DUMMY_NAME,
+                DUMMY_TEST_CLASS, DUMMY_PARAMETERS);
+        assertEquals(firstTest.hashCode(), secondTest.hashCode());
+    }
+
+    @Test
+    public void hasMeaningfulToString() {
+        TestWithParameters test = new TestWithParameters("name", new TestClass(
+                DummyClass.class), Arrays.<Object> asList("first parameter",
+                "second parameter"));
+        assertEquals(
+                "Wrong toString().",
+                "org.junit.runners.parameterized.TestWithParametersTest$DummyClass 'name' with parameters [first parameter, second parameter]",
+                test.toString());
+    }
+
+    private static class DummyClass {
+    }
+
+    private static class AnotherDummyClass {
+    }
+}
diff --git a/src/test/java/org/junit/samples/ListTest.java b/src/test/java/org/junit/samples/ListTest.java
index a281219..02ade82 100644
--- a/src/test/java/org/junit/samples/ListTest.java
+++ b/src/test/java/org/junit/samples/ListTest.java
@@ -12,7 +12,7 @@
 import org.junit.Test;
 
 /**
- * A sample test case, testing {@link java.util.Vector}.
+ * A sample test case, testing {@link java.util.ArrayList}.
  */
 public class ListTest {
     protected List<Integer> fEmpty;
diff --git a/src/test/java/org/junit/tests/AllTests.java b/src/test/java/org/junit/tests/AllTests.java
index 6bcd142..966ef8b 100644
--- a/src/test/java/org/junit/tests/AllTests.java
+++ b/src/test/java/org/junit/tests/AllTests.java
@@ -2,25 +2,48 @@
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
+import junit.samples.money.MoneyTest;
+import org.junit.AssumptionViolatedExceptionTest;
+import org.junit.experimental.categories.CategoryFilterFactoryTest;
 import org.junit.internal.MethodSorterTest;
 import org.junit.internal.matchers.StacktracePrintingMatcherTest;
+import org.junit.internal.matchers.ThrowableCauseMatcherTest;
+import org.junit.rules.DisableOnDebugTest;
+import org.junit.rules.StopwatchTest;
+import org.junit.runner.FilterFactoriesTest;
+import org.junit.runner.FilterOptionIntegrationTest;
+import org.junit.runner.JUnitCommandLineParseResultTest;
+import org.junit.runner.JUnitCoreTest;
 import org.junit.runner.RunWith;
+import org.junit.runner.notification.ConcurrentRunNotifierTest;
+import org.junit.runner.notification.RunNotifierTest;
+import org.junit.runner.notification.SynchronizedRunListenerTest;
+import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParametersTest;
+import org.junit.runners.CustomBlockJUnit4ClassRunnerTest;
 import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;
+import org.junit.runners.model.FrameworkFieldTest;
+import org.junit.runners.model.FrameworkMethodTest;
+import org.junit.runners.model.TestClassTest;
+import org.junit.runners.parameterized.ParameterizedNamesTest;
+import org.junit.runners.parameterized.TestWithParametersTest;
 import org.junit.tests.assertion.AssertionTest;
+import org.junit.tests.assertion.ComparisonFailureTest;
 import org.junit.tests.assertion.MultipleFailureExceptionTest;
 import org.junit.tests.deprecated.JUnit4ClassRunnerTest;
 import org.junit.tests.description.AnnotatedDescriptionTest;
 import org.junit.tests.description.SuiteDescriptionTest;
+import org.junit.tests.description.TestDescriptionMethodNameTest;
 import org.junit.tests.description.TestDescriptionTest;
 import org.junit.tests.experimental.AssumptionTest;
-import org.junit.tests.experimental.AssumptionViolatedExceptionTest;
 import org.junit.tests.experimental.ExperimentalTests;
 import org.junit.tests.experimental.MatcherTest;
 import org.junit.tests.experimental.categories.CategoriesAndParameterizedTest;
 import org.junit.tests.experimental.categories.CategoryTest;
+import org.junit.tests.experimental.categories.CategoryValidatorTest;
 import org.junit.tests.experimental.categories.JavadocTest;
 import org.junit.tests.experimental.categories.MultiCategoryTest;
+import org.junit.tests.experimental.max.DescriptionTest;
 import org.junit.tests.experimental.max.JUnit38SortingTest;
 import org.junit.tests.experimental.max.MaxStarterTest;
 import org.junit.tests.experimental.parallel.ParallelClassTest;
@@ -32,18 +55,30 @@
 import org.junit.tests.experimental.rules.MethodRulesTest;
 import org.junit.tests.experimental.rules.NameRulesTest;
 import org.junit.tests.experimental.rules.RuleChainTest;
-import org.junit.tests.experimental.rules.RuleFieldValidatorTest;
-import org.junit.tests.experimental.rules.StopwatchTest;
+import org.junit.tests.experimental.rules.RuleMemberValidatorTest;
 import org.junit.tests.experimental.rules.TempFolderRuleTest;
+import org.junit.tests.experimental.rules.TemporaryFolderRuleAssuredDeletionTest;
 import org.junit.tests.experimental.rules.TemporaryFolderUsageTest;
 import org.junit.tests.experimental.rules.TestRuleTest;
+import org.junit.tests.experimental.rules.TestWatcherTest;
 import org.junit.tests.experimental.rules.TimeoutRuleTest;
 import org.junit.tests.experimental.rules.VerifierRuleTest;
-import org.junit.tests.experimental.theories.AllMembersSupplierTest;
 import org.junit.tests.experimental.theories.TestedOnSupplierTest;
+import org.junit.tests.experimental.theories.internal.AllMembersSupplierTest;
+import org.junit.tests.experimental.theories.internal.ParameterizedAssertionErrorTest;
+import org.junit.tests.experimental.theories.internal.SpecificDataPointsSupplierTest;
+import org.junit.tests.experimental.theories.runner.FailingDataPointMethods;
 import org.junit.tests.experimental.theories.runner.TheoriesPerformanceTest;
+import org.junit.tests.experimental.theories.runner.TypeMatchingBetweenMultiDataPointsMethod;
+import org.junit.tests.experimental.theories.runner.WithAutoGeneratedDataPoints;
+import org.junit.tests.experimental.theories.runner.WithDataPointMethod;
+import org.junit.tests.experimental.theories.runner.WithNamedDataPoints;
+import org.junit.tests.experimental.theories.runner.WithParameterSupplier;
+import org.junit.tests.internal.runners.ErrorReportingRunnerTest;
+import org.junit.tests.internal.runners.statements.FailOnTimeoutTest;
 import org.junit.tests.junit3compatibility.AllTestsTest;
 import org.junit.tests.junit3compatibility.ClassRequestTest;
+import org.junit.tests.junit3compatibility.ForwardCompatibilityPrintingTest;
 import org.junit.tests.junit3compatibility.ForwardCompatibilityTest;
 import org.junit.tests.junit3compatibility.InitializationErrorForwardCompatibilityTest;
 import org.junit.tests.junit3compatibility.JUnit38ClassRunnerTest;
@@ -60,6 +95,7 @@
 import org.junit.tests.manipulation.SingleMethodTest;
 import org.junit.tests.manipulation.SortableTest;
 import org.junit.tests.running.classes.BlockJUnit4ClassRunnerTest;
+import org.junit.tests.running.classes.ClassLevelMethodsWithIgnoredTestsTest;
 import org.junit.tests.running.classes.EnclosedTest;
 import org.junit.tests.running.classes.IgnoreClassTest;
 import org.junit.tests.running.classes.ParameterizedTestTest;
@@ -67,7 +103,6 @@
 import org.junit.tests.running.classes.ParentRunnerTest;
 import org.junit.tests.running.classes.RunWithTest;
 import org.junit.tests.running.classes.SuiteTest;
-import org.junit.tests.running.classes.TestClassTest;
 import org.junit.tests.running.classes.UseSuiteAsASuperclassTest;
 import org.junit.tests.running.core.CommandLineTest;
 import org.junit.tests.running.core.JUnitCoreReturnsCorrectExitCodeTest;
@@ -80,8 +115,8 @@
 import org.junit.tests.running.methods.TimeoutTest;
 import org.junit.tests.validation.BadlyFormedClassesTest;
 import org.junit.tests.validation.FailedConstructionTest;
-import org.junit.tests.validation.InaccessibleBaseClassTest;
 import org.junit.tests.validation.ValidationTest;
+import org.junit.validator.PublicClassValidatorTest;
 
 // 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
@@ -94,12 +129,14 @@
         ListenerTest.class,
         FailedConstructionTest.class,
         TestDescriptionTest.class,
+        TestDescriptionMethodNameTest.class,
         SuiteDescriptionTest.class,
         AllTestsTest.class,
         AnnotationTest.class,
         AssertionTest.class,
         CommandLineTest.class,
         ExpectedTest.class,
+        ComparisonFailureTest.class,
         MultipleFailureExceptionTest.class,
         ForwardCompatibilityTest.class,
         OldTests.class,
@@ -115,13 +152,13 @@
         ParameterizedTestMethodTest.class,
         InitializationErrorForwardCompatibilityTest.class,
         SingleMethodTest.class,
+        ClassLevelMethodsWithIgnoredTestsTest.class,
         ValidationTest.class,
         UserStopTest.class,
         SortableTest.class,
         JUnit38ClassRunnerTest.class,
         SystemExitTest.class,
         JUnitCoreReturnsCorrectExitCodeTest.class,
-        InaccessibleBaseClassTest.class,
         SuiteMethodTest.class,
         BadlyFormedClassesTest.class,
         IgnoreClassTest.class,
@@ -132,6 +169,11 @@
         InheritedTestTest.class,
         TestClassTest.class,
         AllMembersSupplierTest.class,
+        SpecificDataPointsSupplierTest.class,
+        ParameterizedAssertionErrorTest.class,
+        WithDataPointMethod.class,
+        WithNamedDataPoints.class,
+        WithAutoGeneratedDataPoints.class,
         MatcherTest.class,
         ObjectContractTest.class,
         TheoriesPerformanceTest.class,
@@ -160,13 +202,42 @@
         JavadocTest.class,
         ParentRunnerFilteringTest.class,
         BlockJUnit4ClassRunnerOverrideTest.class,
-        RuleFieldValidatorTest.class,
+        RuleMemberValidatorTest.class,
         RuleChainTest.class,
         BlockJUnit4ClassRunnerTest.class,
+        CustomBlockJUnit4ClassRunnerTest.class,
         MethodSorterTest.class,
         TestedOnSupplierTest.class,
         StacktracePrintingMatcherTest.class,
-        StopwatchTest.class
+        StopwatchTest.class,
+        RunNotifierTest.class,
+        ConcurrentRunNotifierTest.class,
+        SynchronizedRunListenerTest.class,
+        FilterOptionIntegrationTest.class,
+        JUnitCommandLineParseResultTest.class,
+        FilterFactoriesTest.class,
+        CategoryFilterFactoryTest.class,
+        FrameworkFieldTest.class,
+        FrameworkMethodTest.class,
+        FailOnTimeoutTest.class,
+        JUnitCoreTest.class,
+        TestWithParametersTest.class,
+        ParameterizedNamesTest.class,
+        PublicClassValidatorTest.class,
+        DisableOnDebugTest.class,
+        ThrowableCauseMatcherTest.class,
+        TestWatcherTest.class,
+        WithParameterSupplier.class,
+        FailingDataPointMethods.class,
+        TypeMatchingBetweenMultiDataPointsMethod.class,
+        TheoriesPerformanceTest.class,
+        MoneyTest.class,
+        BlockJUnit4ClassRunnerWithParametersTest.class,
+        CategoryValidatorTest.class,
+        ForwardCompatibilityPrintingTest.class,
+        DescriptionTest.class,
+        ErrorReportingRunnerTest.class,
+        TemporaryFolderRuleAssuredDeletionTest.class
 })
 public class AllTests {
     public static Test suite() {
diff --git a/src/test/java/org/junit/tests/TestSystem.java b/src/test/java/org/junit/tests/TestSystem.java
index e199c7a..d74166c 100644
--- a/src/test/java/org/junit/tests/TestSystem.java
+++ b/src/test/java/org/junit/tests/TestSystem.java
@@ -8,6 +8,7 @@
 
 public class TestSystem implements JUnitSystem {
     private PrintStream out;
+    public int fCode;
     private ByteArrayOutputStream fOutContents;
 
     public TestSystem() {
@@ -15,6 +16,14 @@
         out = new PrintStream(fOutContents);
     }
 
+    /**
+     * Will be removed in the next major release
+     */
+    @Deprecated
+    public void exit(int code) {
+        fCode = code;
+    }
+
     public PrintStream out() {
         return out;
     }
diff --git a/src/test/java/org/junit/tests/assertion/AssertionTest.java b/src/test/java/org/junit/tests/assertion/AssertionTest.java
index fb1ea0e..12a85f5 100755
--- a/src/test/java/org/junit/tests/assertion/AssertionTest.java
+++ b/src/test/java/org/junit/tests/assertion/AssertionTest.java
@@ -151,6 +151,7 @@
 
     @Test
     public void oneDimensionalPrimitiveArraysAreEqual() {
+        assertArrayEquals(new boolean[]{true}, new boolean[]{true});
         assertArrayEquals(new byte[]{1}, new byte[]{1});
         assertArrayEquals(new char[]{1}, new char[]{1});
         assertArrayEquals(new short[]{1}, new short[]{1});
@@ -169,6 +170,11 @@
     public void oneDimensionalFloatArraysAreNotEqual() {
         assertArrayEquals(new float[]{1.0f}, new float[]{2.5f}, 1.0f);
     }
+    
+    @Test(expected = AssertionError.class)
+    public void oneDimensionalBooleanArraysAreNotEqual() {
+        assertArrayEquals(new boolean[]{true}, new boolean[]{false});
+    }
 
     @Test(expected = AssertionError.class)
     public void IntegerDoesNotEqualLong() {
@@ -206,6 +212,30 @@
     }
 
     @Test
+    public void multiDimensionalArraysDifferentLengthMessage() {
+        try {
+            assertArrayEquals("message", new Object[][]{{true, true}, {false, false}}, new Object[][]{{true, true}, {false}});
+        } catch (AssertionError exception) {
+            assertEquals("message: arrays first differed at element [1]; array lengths differed, expected.length=2 actual.length=1", exception.getMessage());
+            return;
+        }
+
+        fail("Expected AssertionError to be thrown");
+    }
+
+    @Test
+    public void multiDimensionalArraysDifferentLengthNoMessage() {
+        try {
+            assertArrayEquals(new Object[][]{{true, true}, {false, false}}, new Object[][]{{true, true}, {false}});
+        } catch (AssertionError exception) {
+            assertEquals("arrays first differed at element [1]; array lengths differed, expected.length=2 actual.length=1", exception.getMessage());
+            return;
+        }
+
+        fail("Expected AssertionError to be thrown");
+    }
+
+    @Test
     public void arraysWithNullElementEqual() {
         Object[] objects1 = new Object[]{null};
         Object[] objects2 = new Object[]{null};
@@ -360,6 +390,7 @@
         assertEquals(Double.NaN, Double.NaN, Double.POSITIVE_INFINITY);
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void nullNullmessage() {
         try {
@@ -370,6 +401,7 @@
         }
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void nullWithMessage() {
         try {
diff --git a/src/test/java/org/junit/tests/assertion/ComparisonFailureTest.java b/src/test/java/org/junit/tests/assertion/ComparisonFailureTest.java
new file mode 100644
index 0000000..17ff2af
--- /dev/null
+++ b/src/test/java/org/junit/tests/assertion/ComparisonFailureTest.java
@@ -0,0 +1,78 @@
+package org.junit.tests.assertion;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.ComparisonFailure;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ComparisonFailureTest {
+		
+	private String expected, actual, message;
+	
+	public ComparisonFailureTest(String e, String a, String m) {
+		expected = e;
+		actual = a;
+		message = m;
+	}
+	
+	@Parameters(name = "compact-msg-{index}, exp=\"{1}\"")
+	public static Collection<Object[]> data() {
+		return Arrays.asList(new Object[][] {
+			// simple base case
+			{ "a", "b", "expected:<[a]> but was:<[b]>" },
+				
+			// common prefix
+			{ "ba", "bc", "expected:<b[a]> but was:<b[c]>" },
+				
+			// common suffix
+			{ "ab", "cb", "expected:<[a]b> but was:<[c]b>" },
+				
+			// common pre and suffix
+			{ "abc", "adc", "expected:<a[b]c> but was:<a[d]c>" },
+			
+			// expected is subset of actual
+			{ "ab", "abc", "expected:<ab[]> but was:<ab[c]>" },
+
+			// expected is superset of actual
+			{ "abc", "ab", "expected:<ab[c]> but was:<ab[]>" },
+			
+			// overlapping matches.
+			{ "abc", "abbc", "expected:<ab[]c> but was:<ab[b]c>" },
+
+			// long prefix yielding "..."
+			{ "01234567890123456789PRE:hello:POST", 
+				"01234567890123456789PRE:world:POST",
+				"expected:<...4567890123456789PRE:[hello]:POST> but was:<...4567890123456789PRE:[world]:POST>" },
+					
+			// long suffix	yielding "..."
+			{ "PRE:hello:01234567890123456789POST",
+				"PRE:world:01234567890123456789POST",
+				"expected:<PRE:[hello]:0123456789012345678...> but was:<PRE:[world]:0123456789012345678...>"	
+			},
+					
+			// bug609972
+			{ "S&P500", "0", "expected:<[S&P50]0> but was:<[]0>" },
+			
+			// empty expected string
+			{ "", "a", "expected:<[]> but was:<[a]>" },
+
+			// empty actual string
+			{ "a", "", "expected:<[a]> but was:<[]>" }
+
+		});	
+	}
+
+	@Test
+	public void compactFailureMessage() {
+		ComparisonFailure failure = new ComparisonFailure("", expected, actual);
+		assertEquals(message, failure.getMessage());
+	}
+	
+}
diff --git a/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java b/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java
index f4b6bf0..0c5e2d5 100644
--- a/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java
+++ b/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java
@@ -1,12 +1,12 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
-
 package org.junit.tests.assertion;
 
 import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.lang.annotation.AnnotationFormatError;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -22,18 +22,36 @@
 public class MultipleFailureExceptionTest {
 
     @Test
-    public void assertEmptyDoesNotThrowForEmptyList() throws Throwable {
+    public void assertEmptyDoesNotThrowForEmptyList() throws Exception {
         MultipleFailureException.assertEmpty(Collections.<Throwable>emptyList());
     }
 
-    @Test(expected = ExpectedException.class)
-    public void assertEmptyRethrowsSingleThrowable() throws Throwable {
-        MultipleFailureException.assertEmpty(
-                Collections.<Throwable>singletonList(new ExpectedException("pesto")));
+    @Test
+    public void assertEmptyRethrowsSingleRuntimeException() throws Exception {
+        Throwable exception= new ExpectedException("pesto");
+        List<Throwable> errors= Collections.singletonList(exception);
+        try {
+            MultipleFailureException.assertEmpty(errors);
+            fail();
+        } catch (ExpectedException e) {
+            assertSame(e, exception);
+        }
+    }
+    
+    @Test
+    public void assertEmptyRethrowsSingleError() throws Exception {
+        Throwable exception= new AnnotationFormatError("changeo");
+        List<Throwable> errors= Collections.singletonList(exception);
+        try {
+            MultipleFailureException.assertEmpty(errors);
+            fail();
+        } catch (AnnotationFormatError e) {
+            assertSame(e, exception);
+        }
     }
 
     @Test
-    public void assertEmptyThrowsMutipleFailureExceptionForManyThrowables() throws Throwable {
+    public void assertEmptyThrowsMutipleFailureExceptionForManyThrowables() throws Exception {
         List<Throwable> errors = new ArrayList<Throwable>();
         errors.add(new ExpectedException("basil"));
         errors.add(new RuntimeException("garlic"));
diff --git a/src/test/java/org/junit/tests/description/TestDescriptionMethodNameTest.java b/src/test/java/org/junit/tests/description/TestDescriptionMethodNameTest.java
new file mode 100644
index 0000000..21943e9
--- /dev/null
+++ b/src/test/java/org/junit/tests/description/TestDescriptionMethodNameTest.java
@@ -0,0 +1,50 @@
+package org.junit.tests.description;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author Dmitry Baev charlie@yandex-team.ru
+ *         Date: 03.05.14
+ */
+@RunWith(Parameterized.class)
+public class TestDescriptionMethodNameTest {
+
+    private String methodName;
+
+    public TestDescriptionMethodNameTest(String methodName) {
+        this.methodName = methodName;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> getMethodNames() {
+        return Arrays.asList(
+                new Object[]{"simple"},
+                new Object[]{"with space"},
+                new Object[]{"[]!@#$%^&*()"},
+                new Object[]{""},
+                new Object[]{"\t"},
+                new Object[]{"\n"},
+                new Object[]{"\r\n"},
+                new Object[]{"\r"},
+                new Object[]{"\u0085"},
+                new Object[]{"\u2028"},
+                new Object[]{"\u2029"}
+        );
+    }
+
+    @Test
+    public void methodNameTest() throws Exception {
+        Description description = Description.createTestDescription("some-class-name", methodName);
+        assertNotNull("Method name should be not null", description.getMethodName());
+        assertEquals(methodName, description.getMethodName());
+    }
+}
diff --git a/src/test/java/org/junit/tests/experimental/AssumptionTest.java b/src/test/java/org/junit/tests/experimental/AssumptionTest.java
index 6b65cd4..8d2d0a0 100644
--- a/src/test/java/org/junit/tests/experimental/AssumptionTest.java
+++ b/src/test/java/org/junit/tests/experimental/AssumptionTest.java
@@ -18,10 +18,10 @@
 import java.util.List;
 
 import org.junit.Assume;
+import org.junit.AssumptionViolatedException;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
-import org.junit.internal.AssumptionViolatedException;
 import org.junit.runner.JUnitCore;
 import org.junit.runner.Result;
 import org.junit.runner.notification.Failure;
@@ -194,7 +194,7 @@
     }
 
     final static String message = "Some random message string.";
-    final static Throwable t = new Throwable();
+    final static Throwable e = new Throwable();
 
     /**
      * @see AssumptionTest#assumptionsWithMessage()
@@ -220,7 +220,7 @@
     public static class HasAssumeWithMessageAndCause {
         @Test
         public void testMethod() {
-            assumeNoException(message, t);
+            assumeNoException(message, e);
         }
     }
 
@@ -229,7 +229,7 @@
         final List<Failure> failures =
                 runAndGetAssumptionFailures(HasAssumeWithMessageAndCause.class);
         assertTrue(failures.get(0).getMessage().contains(message));
-        assertSame(failures.get(0).getException().getCause(), t);
+        assertSame(failures.get(0).getException().getCause(), e);
     }
 
     public static class HasFailingAssumptionWithMessage {
diff --git a/src/test/java/org/junit/tests/experimental/AssumptionViolatedExceptionTest.java b/src/test/java/org/junit/tests/experimental/AssumptionViolatedExceptionTest.java
deleted file mode 100644
index 892226f..0000000
--- a/src/test/java/org/junit/tests/experimental/AssumptionViolatedExceptionTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.junit.tests.experimental;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assume.assumeThat;
-
-import org.hamcrest.Matcher;
-import org.hamcrest.StringDescription;
-import org.junit.Test;
-import org.junit.experimental.theories.DataPoint;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.internal.AssumptionViolatedException;
-import org.junit.runner.RunWith;
-
-@RunWith(Theories.class)
-public class AssumptionViolatedExceptionTest {
-    @DataPoint
-    public static Object TWO = 2;
-
-    @DataPoint
-    public static Matcher<?> IS_THREE = is(3);
-
-    @DataPoint
-    public static Matcher<?> NULL = null;
-
-    @Theory
-    public void toStringReportsMatcher(Object actual, Matcher<?> matcher) {
-        assumeThat(matcher, notNullValue());
-        assertThat(new AssumptionViolatedException(actual, matcher).toString(),
-                containsString(matcher.toString()));
-    }
-
-    @Theory
-    public void toStringReportsValue(Object actual, Matcher<?> matcher) {
-        assertThat(new AssumptionViolatedException(actual, matcher).toString(),
-                containsString(String.valueOf(actual)));
-    }
-
-    @Test
-    public void AssumptionViolatedExceptionDescribesItself() {
-        AssumptionViolatedException e = new AssumptionViolatedException(3, is(2));
-        assertThat(StringDescription.asString(e), is("got: <3>, expected: is <2>"));
-    }
-
-    @Test
-    public void simpleAssumptionViolatedExceptionDescribesItself() {
-        AssumptionViolatedException e = new AssumptionViolatedException("not enough money");
-        assertThat(StringDescription.asString(e), is("not enough money"));
-    }
-}
diff --git a/src/test/java/org/junit/tests/experimental/ExperimentalTests.java b/src/test/java/org/junit/tests/experimental/ExperimentalTests.java
index f9f246e..953d156 100644
--- a/src/test/java/org/junit/tests/experimental/ExperimentalTests.java
+++ b/src/test/java/org/junit/tests/experimental/ExperimentalTests.java
@@ -6,25 +6,32 @@
 import org.junit.tests.experimental.results.PrintableResultTest;
 import org.junit.tests.experimental.results.ResultMatchersTest;
 import org.junit.tests.experimental.theories.ParameterSignatureTest;
-import org.junit.tests.experimental.theories.ParameterizedAssertionErrorTest;
 import org.junit.tests.experimental.theories.extendingwithstubs.StubbedTheoriesTest;
+import org.junit.tests.experimental.theories.internal.AllMembersSupplierTest;
+import org.junit.tests.experimental.theories.internal.ParameterizedAssertionErrorTest;
+import org.junit.tests.experimental.theories.internal.SpecificDataPointsSupplierTest;
 import org.junit.tests.experimental.theories.runner.SuccessfulWithDataPointFields;
 import org.junit.tests.experimental.theories.runner.UnsuccessfulWithDataPointFields;
 import org.junit.tests.experimental.theories.runner.WhenNoParametersMatch;
+import org.junit.tests.experimental.theories.runner.WithAutoGeneratedDataPoints;
 import org.junit.tests.experimental.theories.runner.WithDataPointMethod;
 import org.junit.tests.experimental.theories.runner.WithExtendedParameterSources;
+import org.junit.tests.experimental.theories.runner.WithNamedDataPoints;
 import org.junit.tests.experimental.theories.runner.WithOnlyTestAnnotations;
 import org.junit.tests.experimental.theories.runner.WithUnresolvedGenericTypeVariablesOnTheoryParms;
 
 @RunWith(Suite.class)
 @SuiteClasses({ParameterizedAssertionErrorTest.class,
+        AllMembersSupplierTest.class,
+        SpecificDataPointsSupplierTest.class,
         UnsuccessfulWithDataPointFields.class,
         SuccessfulWithDataPointFields.class, PrintableResultTest.class,
         ResultMatchersTest.class, WithDataPointMethod.class,
         ParameterSignatureTest.class, WhenNoParametersMatch.class,
         WithExtendedParameterSources.class, StubbedTheoriesTest.class,
-        WithOnlyTestAnnotations.class,
-        WithUnresolvedGenericTypeVariablesOnTheoryParms.class})
+        WithOnlyTestAnnotations.class, WithNamedDataPoints.class,
+        WithUnresolvedGenericTypeVariablesOnTheoryParms.class, 
+        WithAutoGeneratedDataPoints.class})
 public class ExperimentalTests {
 
 }
diff --git a/src/test/java/org/junit/tests/experimental/MatcherTest.java b/src/test/java/org/junit/tests/experimental/MatcherTest.java
index ff002e1..6a1eb42 100644
--- a/src/test/java/org/junit/tests/experimental/MatcherTest.java
+++ b/src/test/java/org/junit/tests/experimental/MatcherTest.java
@@ -30,7 +30,7 @@
             Arrays.asList(failure("cheese"), failure("mustard")));
 
     @Theory
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     public void differentMatchersHaveDifferentDescriptions(
             Matcher matcher1, Matcher matcher2, Object value) {
         assumeThat(value, matcher1);
diff --git a/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java b/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java
index d01e5a7..511d686 100644
--- a/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java
+++ b/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java
@@ -1,18 +1,16 @@
 package org.junit.tests.experimental.categories;
 
-import static org.junit.Assert.assertThat;
-import static org.junit.experimental.results.PrintableResult.testResult;
-import static org.junit.experimental.results.ResultMatchers.hasFailureContaining;
-import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.Assert.assertEquals;
 
-import java.util.Collection;
-import java.util.Collections;
+import java.util.Arrays;
 
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.experimental.categories.Categories;
 import org.junit.experimental.categories.Categories.IncludeCategory;
 import org.junit.experimental.categories.Category;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
@@ -24,14 +22,14 @@
     }
 
     @RunWith(Parameterized.class)
-    public static class WellBehavedParameterizedTest {
-        public WellBehavedParameterizedTest(String a) {
+    public static class ParameterizedTestWithoutCategory {
+        @Parameters
+        public static Iterable<String> getParameters() {
+            return Arrays.asList("first", "second");
         }
 
-        @Parameters
-        public static Collection<Object[]> getParameters() {
-            return Collections.singletonList(new Object[]{"a"});
-        }
+        @Parameterized.Parameter
+        public String value;
 
         @Test
         public void testSomething() {
@@ -39,85 +37,93 @@
         }
     }
 
+    @Category(Token.class)
+    public static class TestThatAvoidsNoTestRemainsException {
+        @Test
+        public void testSomething() {
+            Assert.assertTrue(true);
+        }
+    }
+
+    @RunWith(Categories.class)
+    @IncludeCategory(Token.class)
+    @SuiteClasses({ TestThatAvoidsNoTestRemainsException.class,
+            ParameterizedTestWithoutCategory.class })
+    public static class SuiteWithParameterizedTestWithoutCategory {
+    }
+
+    @Test
+    public void doesNotRunTestsWithoutCategory() {
+        Result result = new JUnitCore()
+                .run(SuiteWithParameterizedTestWithoutCategory.class);
+        assertEquals(1, result.getRunCount());
+        assertEquals(0, result.getFailureCount());
+    }
+
     @RunWith(Parameterized.class)
-    public static class ParameterizedTestWithAttemptedMethodCategory {
-        public ParameterizedTestWithAttemptedMethodCategory(String a) {
+    @Category(Token.class)
+    public static class ParameterizedTestWithCategory {
+        @Parameters
+        public static Iterable<String> getParameters() {
+            return Arrays.asList("first", "second");
         }
 
-        @Parameters
-        public static Collection<Object[]> getParameters() {
-            return Collections.singletonList(new Object[]{"a"});
+        @Parameterized.Parameter
+        public String value;
+
+        @Test
+        public void testSomething() {
+            Assert.assertTrue(true);
         }
+    }
+
+    @RunWith(Categories.class)
+    @IncludeCategory(Token.class)
+    @SuiteClasses({ ParameterizedTestWithCategory.class })
+    public static class SuiteWithParameterizedTestWithCategory {
+    }
+
+    @Test
+    public void runsTestsWithoutCategory() {
+        Result result = new JUnitCore()
+                .run(SuiteWithParameterizedTestWithCategory.class);
+        assertEquals(2, result.getRunCount());
+        assertEquals(0, result.getFailureCount());
+    }
+
+    @RunWith(Parameterized.class)
+    public static class ParameterizedTestWithMethodWithCategory {
+        @Parameters
+        public static Iterable<String> getParameters() {
+            return Arrays.asList("first", "second");
+        }
+
+        @Parameterized.Parameter
+        public String value;
 
         @Test
         @Category(Token.class)
         public void testSomething() {
             Assert.assertTrue(true);
         }
-    }
-
-    @RunWith(Parameterized.class)
-    @Category(Token.class)
-    public static class ParameterizedTestWithClassCategory {
-        public ParameterizedTestWithClassCategory(String a) {
-        }
-
-        @Parameters
-        public static Collection<Object[]> getParameters() {
-            return Collections.singletonList(new Object[]{"a"});
-        }
 
         @Test
-        public void testSomething() {
-            Assert.assertTrue(true);
-        }
-    }
-
-    @Category(Token.class)
-    public static class VanillaCategorizedJUnitTest {
-        @Test
-        public void testSomething() {
+        public void testThatIsNotExecuted() {
             Assert.assertTrue(true);
         }
     }
 
     @RunWith(Categories.class)
     @IncludeCategory(Token.class)
-    @SuiteClasses({VanillaCategorizedJUnitTest.class,
-            WellBehavedParameterizedTest.class,
-            ParameterizedTestWithClassCategory.class})
-    public static class ParameterTokenSuiteWellFormed {
-    }
-
-    @RunWith(Categories.class)
-    @IncludeCategory(Token.class)
-    @SuiteClasses({ParameterizedTestWithAttemptedMethodCategory.class, VanillaCategorizedJUnitTest.class})
-    public static class ParameterTokenSuiteMalformed {
-    }
-
-    @RunWith(Categories.class)
-    @IncludeCategory(Token.class)
-    @SuiteClasses({VanillaCategorizedJUnitTest.class, ParameterizedTestWithAttemptedMethodCategory.class})
-    public static class ParameterTokenSuiteMalformedAndSwapped {
+    @SuiteClasses({ ParameterizedTestWithMethodWithCategory.class })
+    public static class SuiteWithParameterizedTestWithMethodWithCategory {
     }
 
     @Test
-    public void shouldSucceedWithAParameterizedClassSomewhere() {
-        assertThat(testResult(ParameterTokenSuiteWellFormed.class),
-                isSuccessful());
-    }
-
-    @Test
-    public void shouldFailWithMethodLevelCategoryAnnotation() {
-        assertThat(
-                testResult(ParameterTokenSuiteMalformed.class),
-                hasFailureContaining("Category annotations on Parameterized classes are not supported on individual methods."));
-    }
-
-    @Test
-    public void shouldFailWithMethodLevelCategoryAnnotationSwapped() {
-        assertThat(
-                testResult(ParameterTokenSuiteMalformedAndSwapped.class),
-                hasFailureContaining("Category annotations on Parameterized classes are not supported on individual methods."));
+    public void runsTestMethodWithCategory() {
+        Result result = new JUnitCore()
+                .run(SuiteWithParameterizedTestWithMethodWithCategory.class);
+        assertEquals(2, result.getRunCount());
+        assertEquals(0, result.getFailureCount());
     }
 }
\ No newline at end of file
diff --git a/src/test/java/org/junit/tests/experimental/categories/CategoryValidatorTest.java b/src/test/java/org/junit/tests/experimental/categories/CategoryValidatorTest.java
new file mode 100644
index 0000000..8f7397e
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/categories/CategoryValidatorTest.java
@@ -0,0 +1,88 @@
+package org.junit.tests.experimental.categories;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.experimental.categories.CategoryValidator;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.TestClass;
+
+public class CategoryValidatorTest {
+
+    public static class SampleCategory {
+    }
+
+    public static class CategoryTest {
+        @BeforeClass
+        @Category(value = SampleCategory.class)
+        public static void methodWithCategoryAndBeforeClass() {
+        }
+
+        @AfterClass
+        @Category(value = SampleCategory.class)
+        public static void methodWithCategoryAndAfterClass() {
+        }
+
+        @Before
+        @Category(value = SampleCategory.class)
+        public static void methodWithCategoryAndBefore() {
+        }
+
+        @After
+        @Category(value = SampleCategory.class)
+        public static void methodWithCategoryAndAfter() {
+        }
+
+        @Category(value = SampleCategory.class)
+        public static void methodWithCategory() {
+        }
+    }
+
+    @Test
+    public void errorIsAddedWhenCategoryIsUsedWithBeforeClass() {
+        FrameworkMethod method = new TestClass(CategoryTest.class).getAnnotatedMethods(BeforeClass.class).get(0);
+        testAndAssertErrorMessage(method, "@BeforeClass can not be combined with @Category");
+    }
+
+    @Test
+    public void errorIsAddedWhenCategoryIsUsedWithAfterClass() {
+        FrameworkMethod method = new TestClass(CategoryTest.class).getAnnotatedMethods(AfterClass.class).get(0);
+        testAndAssertErrorMessage(method, "@AfterClass can not be combined with @Category");
+    }
+
+    @Test
+    public void errorIsAddedWhenCategoryIsUsedWithBefore() {
+        FrameworkMethod method = new TestClass(CategoryTest.class).getAnnotatedMethods(Before.class).get(0);
+        testAndAssertErrorMessage(method, "@Before can not be combined with @Category");
+    }
+
+    @Test
+    public void errorIsAddedWhenCategoryIsUsedWithAfter() {
+        FrameworkMethod method = new TestClass(CategoryTest.class).getAnnotatedMethods(After.class).get(0);
+        testAndAssertErrorMessage(method, "@After can not be combined with @Category");
+    }
+
+    private void testAndAssertErrorMessage(FrameworkMethod method, String expectedErrorMessage) {
+        List<Exception> errors = new CategoryValidator().validateAnnotatedMethod(method);
+
+        assertThat(errors.size(), is(1));
+        Exception exception = errors.get(0);
+        assertThat(exception.getMessage(), is(expectedErrorMessage));
+    }
+
+    @Test
+    public void errorIsNotAddedWhenCategoryIsNotCombinedWithIllegalCombination() throws NoSuchMethodException {
+        FrameworkMethod method = new FrameworkMethod(CategoryTest.class.getMethod("methodWithCategory"));
+        List<Exception> errors = new CategoryValidator().validateAnnotatedMethod(method);
+
+        assertThat(errors.size(), is(0));
+    }
+}
diff --git a/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java b/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java
index 7b3871a..9dd0f71 100644
--- a/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java
@@ -2,6 +2,7 @@
 
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 import static org.junit.experimental.results.PrintableResult.testResult;
 import static org.junit.experimental.results.ResultMatchers.isSuccessful;
 
@@ -18,7 +19,6 @@
 import org.junit.runners.model.InitializationError;
 import org.junit.runners.model.Statement;
 
-@SuppressWarnings("deprecation")
 public class BlockJUnit4ClassRunnerOverrideTest {
     public static class FlipBitRule implements MethodRule {
         public Statement apply(final Statement base, FrameworkMethod method,
@@ -90,4 +90,88 @@
     public void overrideTestRulesMethod() {
         assertThat(testResult(OverrideRulesTest.class), isSuccessful());
     }
+
+
+    /**
+     * Runner for testing override of {@link org.junit.runners.BlockJUnit4ClassRunner#createTest(org.junit.runners.model.FrameworkMethod)}
+     * by setting the {@link org.junit.runners.model.FrameworkMethod} in a field
+     * of the test class so it can be compared with the test method that is being
+     * executed.
+     */
+    public static class OverrideCreateTestRunner extends BlockJUnit4ClassRunner {
+        public OverrideCreateTestRunner(final Class<?> klass) throws InitializationError {
+            super(klass);
+
+            assert(klass.equals(OverrideCreateTest.class));
+        }
+
+        @Override
+        protected Object createTest(FrameworkMethod method) {
+            final OverrideCreateTest obj = new OverrideCreateTest();
+
+            obj.method = method;
+
+            return obj;
+        }
+    }
+
+    @RunWith(OverrideCreateTestRunner.class)
+    public static class OverrideCreateTest {
+        public FrameworkMethod method;
+
+        @Test
+        public void testMethodA() {
+            assertEquals("testMethodA", method.getMethod().getName());
+        }
+
+        @Test
+        public void testMethodB() {
+            assertEquals("testMethodB", method.getMethod().getName());
+        }
+    }
+
+    @Test
+    public void overrideCreateTestMethod() {
+        assertThat(testResult(OverrideCreateTest.class), isSuccessful());
+    }
+
+
+    /**
+     * Runner for testing override of {@link org.junit.runners.BlockJUnit4ClassRunner#createTest()}
+     * is still called by default if no other {@code createTest} method override
+     * is in place. This is tested by setting a boolean flag in a field of the
+     * test class so it can be checked to confirm that the createTest method was
+     * called.
+     */
+    public static class CreateTestDefersToNoArgCreateTestRunner extends BlockJUnit4ClassRunner {
+        public CreateTestDefersToNoArgCreateTestRunner(final Class<?> klass) throws InitializationError {
+            super(klass);
+
+            assert(klass.equals(CreateTestDefersToNoArgCreateTestTest.class));
+        }
+
+        @Override
+        protected Object createTest() {
+            final CreateTestDefersToNoArgCreateTestTest obj = new CreateTestDefersToNoArgCreateTestTest();
+
+            obj.createTestCalled = true;
+
+            return obj;
+        }
+    }
+
+    @RunWith(CreateTestDefersToNoArgCreateTestRunner.class)
+    public static class CreateTestDefersToNoArgCreateTestTest {
+        public boolean createTestCalled = false;
+
+        @Test
+        public void testCreateTestCalled() {
+            assertEquals(true, createTestCalled);
+        }
+    }
+
+    @Test
+    public void createTestDefersToNoArgCreateTest() {
+        assertThat(testResult(CreateTestDefersToNoArgCreateTestTest.class), isSuccessful());
+    }
 }
diff --git a/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java b/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java
index 00c7709..9e0153d 100644
--- a/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java
@@ -23,9 +23,6 @@
 
 /**
  * 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 {
diff --git a/src/test/java/org/junit/tests/experimental/rules/EventCollector.java b/src/test/java/org/junit/tests/experimental/rules/EventCollector.java
index 8c89a28..de6f49a 100644
--- a/src/test/java/org/junit/tests/experimental/rules/EventCollector.java
+++ b/src/test/java/org/junit/tests/experimental/rules/EventCollector.java
@@ -31,6 +31,13 @@
                 description.appendValue(numberOfFailures);
                 description.appendText(" failures");
             }
+
+            @Override
+            protected void describeMismatchSafely(EventCollector item,
+                    org.hamcrest.Description description) {
+                description.appendValue(item.fFailures.size());
+                description.appendText(" failures");
+            }
         };
     }
 
@@ -84,6 +91,24 @@
                 description.appendText("has single failure with message ");
                 messageMatcher.describeTo(description);
             }
+
+            @Override
+            protected void describeMismatchSafely(EventCollector item,
+                    org.hamcrest.Description description) {
+                description.appendText("was ");
+                hasSingleFailure().describeMismatch(item, description);
+                description.appendText(": ");
+                boolean first= true;
+                for (Failure f : item.fFailures) {
+                    if (!first) {
+                        description.appendText(" ,");
+                    }
+                    description.appendText("'");
+                    description.appendText(f.getMessage());
+                    description.appendText("'");
+                    first= false;
+                }
+            }
         };
     }
 
@@ -155,22 +180,12 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append(fTestRunsStarted.size());
-        sb.append(" test runs started, ");
-        sb.append(fTestRunsFinished.size());
-        sb.append(" test runs finished, ");
-        sb.append(fTestsStarted.size());
-        sb.append(" tests started, ");
-        sb.append(fTestsFinished.size());
-        sb.append(" tests finished, ");
-        sb.append(fFailures.size());
-        sb.append(" failures, ");
-        sb.append(fAssumptionFailures.size());
-        sb.append(" assumption failures, ");
-        sb.append(fTestsIgnored.size());
-        sb.append(" tests ignored");
-
-        return sb.toString();
+        return fTestRunsStarted.size() + " test runs started, "
+            + fTestRunsFinished.size() + " test runs finished, "
+            + fTestsStarted.size() + " tests started, "
+            + fTestsFinished.size() + " tests finished, "
+            + fFailures.size() + " failures, "
+            + fAssumptionFailures.size() + " assumption failures, "
+            + fTestsIgnored.size() + " tests ignored";
     }
 }
diff --git a/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java b/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java
index 24eecfe..94024c6 100644
--- a/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java
@@ -22,7 +22,6 @@
 import org.hamcrest.Matcher;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.internal.AssumptionViolatedException;
 import org.junit.rules.ExpectedException;
 import org.junit.runner.JUnitCore;
 import org.junit.runner.RunWith;
@@ -33,7 +32,7 @@
 public class ExpectedExceptionTest {
     private static final String ARBITRARY_MESSAGE = "arbitrary message";
 
-    @Parameters
+    @Parameters(name= "{0}")
     public static Collection<Object[]> testsWithEventMatcher() {
         return asList(new Object[][]{
                 {EmptyTestExpectingNoException.class, everyTestRunSuccessful()},
@@ -61,23 +60,10 @@
                         ExpectedMessageMatcherFails.class,
                         hasSingleFailureWithMessage(startsWith("\nExpected: exception with message \"Wrong start\""))},
                 {ExpectsMatcher.class, everyTestRunSuccessful()},
-                {ThrowExpectedAssumptionViolatedException.class,
-                        everyTestRunSuccessful()},
-                {ThrowAssumptionViolatedExceptionButExpectOtherType.class,
-                        hasSingleFailure()},
-                {
-                        ThrowAssumptionViolatedExceptionButExpectOtherType.class,
-                        hasSingleFailureWithMessage(containsString("Stacktrace was: org.junit.internal.AssumptionViolatedException"))},
-                {ViolateAssumptionAndExpectException.class,
+                {ExpectAssertionErrorWhichIsNotThrown.class, hasSingleFailure()},
+                {FailedAssumptionAndExpectException.class,
                         hasSingleAssumptionFailure()},
-                {ThrowExpectedAssertionError.class, everyTestRunSuccessful()},
-                {
-                        DontThrowAssertionErrorButExpectOne.class,
-                        hasSingleFailureWithMessage("Expected test to throw an instance of java.lang.AssertionError")},
-                {
-                        ThrowUnexpectedAssertionError.class,
-                        hasSingleFailureWithMessage(startsWith("\nExpected: an instance of java.lang.NullPointerException"))},
-                {FailAndDontHandleAssertinErrors.class,
+                {FailBeforeExpectingException.class,
                         hasSingleFailureWithMessage(ARBITRARY_MESSAGE)},
                 {
                         ExpectsMultipleMatchers.class,
@@ -92,7 +78,16 @@
                                 containsString("cause was <java.lang.NullPointerException: an unexpected cause>"),
                                 containsString("Stacktrace was: java.lang.IllegalArgumentException: Ack!"),
                                 containsString("Caused by: java.lang.NullPointerException: an unexpected cause")))},
-                { CustomMessageWithoutExpectedException.class, hasSingleFailureWithMessage(ARBITRARY_MESSAGE) }
+                {
+                        UseNoCustomMessage.class,
+                        hasSingleFailureWithMessage("Expected test to throw an instance of java.lang.IllegalArgumentException") },
+                {
+                        UseCustomMessageWithoutPlaceHolder.class,
+                        hasSingleFailureWithMessage(ARBITRARY_MESSAGE) },
+                {
+                        UseCustomMessageWithPlaceHolder.class,
+                        hasSingleFailureWithMessage(ARBITRARY_MESSAGE
+                                + " - an instance of java.lang.IllegalArgumentException") }
         });
     }
 
@@ -257,85 +252,36 @@
         }
     }
 
-    public static class FailAndDontHandleAssertinErrors {
+    //https://github.com/junit-team/junit/pull/583
+    public static class ExpectAssertionErrorWhichIsNotThrown {
         @Rule
         public ExpectedException thrown = none();
 
         @Test
-        public void violatedAssumption() {
-            thrown.expect(IllegalArgumentException.class);
+        public void fails() {
+            thrown.expect(AssertionError.class);
+        }
+    }
+
+    public static class FailBeforeExpectingException {
+        @Rule
+        public ExpectedException thrown = none();
+
+        @Test
+        public void fails() {
             fail(ARBITRARY_MESSAGE);
+            thrown.expect(IllegalArgumentException.class);
         }
     }
 
-    public static class ThrowUnexpectedAssertionError {
+    public static class FailedAssumptionAndExpectException {
         @Rule
         public ExpectedException thrown = none();
 
         @Test
-        public void wrongException() {
-            thrown.handleAssertionErrors();
-            thrown.expect(NullPointerException.class);
-            throw new AssertionError("the unexpected assertion error");
-        }
-    }
-
-    public static class ThrowExpectedAssertionError {
-        @Rule
-        public ExpectedException thrown = none();
-
-        @Test
-        public void wrongException() {
-            thrown.handleAssertionErrors();
-            thrown.expect(AssertionError.class);
-            throw new AssertionError("the expected assertion error");
-        }
-    }
-
-    public static class DontThrowAssertionErrorButExpectOne {
-        @Rule
-        public ExpectedException thrown = none();
-
-        @Test
-        public void assertionErrorExpectedButNonIsThrown() {
-            thrown.handleAssertionErrors();
-            thrown.expect(AssertionError.class);
-        }
-    }
-
-    public static class ViolateAssumptionAndExpectException {
-        @Rule
-        public ExpectedException thrown = none();
-
-        @Test
-        public void violatedAssumption() {
-            // expect an exception, which is not an AssumptionViolatedException
-            thrown.expect(NullPointerException.class);
+        public void failedAssumption() {
             assumeTrue(false);
-        }
-    }
-
-    public static class ThrowAssumptionViolatedExceptionButExpectOtherType {
-        @Rule
-        public ExpectedException thrown = none();
-
-        @Test
-        public void wrongException() {
-            thrown.handleAssumptionViolatedExceptions();
             thrown.expect(NullPointerException.class);
-            throw new AssumptionViolatedException("");
-        }
-    }
-
-    public static class ThrowExpectedAssumptionViolatedException {
-        @Rule
-        public ExpectedException thrown = none();
-
-        @Test
-        public void throwExpectAssumptionViolatedException() {
-            thrown.handleAssumptionViolatedExceptions();
-            thrown.expect(AssumptionViolatedException.class);
-            throw new AssumptionViolatedException("");
         }
     }
 
@@ -384,7 +330,18 @@
         }
     }
     
-    public static class CustomMessageWithoutExpectedException {
+    public static class UseNoCustomMessage {
+
+        @Rule
+        public ExpectedException thrown= ExpectedException.none();
+
+        @Test
+        public void noThrow() {
+            thrown.expect(IllegalArgumentException.class);
+        }
+    }
+
+    public static class UseCustomMessageWithPlaceHolder {
 
         @Rule
         public ExpectedException thrown = ExpectedException.none();
@@ -392,6 +349,19 @@
         @Test
         public void noThrow() {
             thrown.expect(IllegalArgumentException.class);
+            thrown.reportMissingExceptionWithMessage(ARBITRARY_MESSAGE
+                    + " - %s");
+        }
+    }
+
+    public static class UseCustomMessageWithoutPlaceHolder {
+
+        @Rule
+        public ExpectedException thrown= ExpectedException.none();
+
+        @Test
+        public void noThrow() {
+            thrown.expect(IllegalArgumentException.class);
             thrown.reportMissingExceptionWithMessage(ARBITRARY_MESSAGE);
         }
     }
diff --git a/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java b/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java
index 19a63c4..edb899f 100644
--- a/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java
+++ b/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java
@@ -1,5 +1,6 @@
 package org.junit.tests.experimental.rules;
 
+import org.junit.AssumptionViolatedException;
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
 
@@ -21,6 +22,11 @@
     }
 
     @Override
+    protected void skipped(AssumptionViolatedException e, Description description) {
+        log.append("skipped ");
+    }
+
+    @Override
     protected void starting(Description description) {
         log.append("starting ");
     }
diff --git a/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java b/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java
index 38d00a8..c00385d 100644
--- a/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java
@@ -9,7 +9,6 @@
 import static org.junit.experimental.results.PrintableResult.testResult;
 import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
 import static org.junit.experimental.results.ResultMatchers.isSuccessful;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -71,21 +70,20 @@
 
     private static int runCount;
 
-    public static class MultipleRuleTest {
-        private static class Increment implements MethodRule {
-            public Statement apply(final Statement base,
-                    FrameworkMethod method, Object target) {
-                return new Statement() {
-                    @Override
-                    public void evaluate() throws Throwable {
-                        runCount++;
-                        base.evaluate();
-                    }
-
-                    ;
-                };
-            }
+    private static class Increment implements MethodRule {
+        public Statement apply(final Statement base,
+                FrameworkMethod method, Object target) {
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    runCount++;
+                    base.evaluate();
+                }
+            };
         }
+    }
+    
+    public static class MultipleRuleTest {
 
         @Rule
         public MethodRule incrementor1 = new Increment();
@@ -251,7 +249,6 @@
     }
 
     public static class PrivateRule {
-        @SuppressWarnings("unused")
         @Rule
         private TestRule rule = new TestName();
 
@@ -294,4 +291,118 @@
     public void useCustomMethodRule() {
         assertThat(testResult(UsesCustomMethodRule.class), isSuccessful());
     }
+    
+    public static class HasMethodReturningMethodRule {
+        private MethodRule methodRule = new MethodRule() {
+            public Statement apply(final Statement base, FrameworkMethod method, Object target) {
+                return new Statement() {
+                    
+                    @Override
+                    public void evaluate() throws Throwable {
+                        wasRun = true;
+                        base.evaluate();
+                    }
+                };
+            }
+        };
+        
+        @Rule
+        public MethodRule methodRule() {
+            return methodRule;
+        }
+        
+        @Test
+        public void doNothing() {
+            
+        }
+    }
+
+    /**
+     * If there are any public methods annotated with @Rule returning a {@link MethodRule}
+     * then it should also be run.
+     * 
+     * <p>This case has been added with 
+     * <a href="https://github.com/junit-team/junit/issues/589">Issue #589</a> - 
+     * Support @Rule for methods works only for TestRule but not for MethodRule
+     */
+    @Test
+    public void runsMethodRuleThatIsReturnedByMethod() {
+        wasRun = false;
+        JUnitCore.runClasses(HasMethodReturningMethodRule.class);
+        assertTrue(wasRun);
+    }
+    
+    public static class HasMultipleMethodsReturningMethodRule {
+        @Rule
+        public Increment methodRule1() {
+            return new Increment();
+        }
+        
+        @Rule
+        public Increment methodRule2() {
+            return new Increment();
+        }
+        
+        @Test
+        public void doNothing() {
+            
+        }
+    }
+
+    /**
+     * If there are multiple public methods annotated with @Rule returning a {@link MethodRule}
+     * then all the rules returned should be run.
+     * 
+     * <p>This case has been added with 
+     * <a href="https://github.com/junit-team/junit/issues/589">Issue #589</a> - 
+     * Support @Rule for methods works only for TestRule but not for MethodRule
+     */
+    @Test
+    public void runsAllMethodRulesThatAreReturnedByMethods() {
+        runCount = 0;
+        JUnitCore.runClasses(HasMultipleMethodsReturningMethodRule.class);
+        assertEquals(2, runCount);
+    }
+    
+    
+    public static class CallsMethodReturningRuleOnlyOnce {
+        int callCount = 0;
+        
+        private static class Dummy implements MethodRule {
+            public Statement apply(final Statement base, FrameworkMethod method, Object target) {
+                return new Statement() {
+                    
+                    @Override
+                    public void evaluate() throws Throwable {
+                        base.evaluate();
+                    }
+                };
+            }
+        };
+       
+        
+        @Rule
+        public MethodRule methodRule() {
+            callCount++;
+            return new Dummy();
+        }
+        
+        @Test
+        public void doNothing() {
+            assertEquals(1, callCount);
+        }
+    }
+
+    /**
+     * If there are any public methods annotated with @Rule returning a {@link MethodRule}
+     * then method should be called only once.
+     * 
+     * <p>This case has been added with 
+     * <a href="https://github.com/junit-team/junit/issues/589">Issue #589</a> - 
+     * Support @Rule for methods works only for TestRule but not for MethodRule
+     */
+    @Test
+    public void callsMethodReturningRuleOnlyOnce() {
+        assertTrue(JUnitCore.runClasses(CallsMethodReturningRuleOnlyOnce.class).wasSuccessful());
+    }
 }
diff --git a/src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java b/src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java
deleted file mode 100644
index 8f70a70..0000000
--- a/src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-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;
-import java.util.List;
-
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.MethodRule;
-import org.junit.rules.TemporaryFolder;
-import org.junit.rules.TestRule;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.Statement;
-import org.junit.runners.model.TestClass;
-
-@SuppressWarnings("deprecation")
-public class RuleFieldValidatorTest {
-    private final List<Throwable> errors = new ArrayList<Throwable>();
-
-    @Test
-    public void rejectProtectedClassRule() {
-        TestClass target = new TestClass(TestWithProtectedClassRule.class);
-        CLASS_RULE_VALIDATOR.validate(target, errors);
-        assertOneErrorWithMessage("The @ClassRule 'temporaryFolder' must be public.");
-    }
-
-    public static class TestWithProtectedClassRule {
-        @ClassRule
-        protected static TestRule temporaryFolder = new TemporaryFolder();
-    }
-
-    @Test
-    public void rejectNonStaticClassRule() {
-        TestClass target = new TestClass(TestWithNonStaticClassRule.class);
-        CLASS_RULE_VALIDATOR.validate(target, errors);
-        assertOneErrorWithMessage("The @ClassRule 'temporaryFolder' must be static.");
-    }
-
-    public static class TestWithNonStaticClassRule {
-        @ClassRule
-        public TestRule temporaryFolder = new TemporaryFolder();
-    }
-
-    @Test
-    public void acceptNonStaticTestRule() {
-        TestClass target = new TestClass(TestWithNonStaticTestRule.class);
-        RULE_VALIDATOR.validate(target, errors);
-        assertNumberOfErrors(0);
-    }
-
-    public static class TestWithNonStaticTestRule {
-        @Rule
-        public TestRule temporaryFolder = new TemporaryFolder();
-    }
-
-    @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);
-        assertNumberOfErrors(0);
-    }
-
-    public static class TestWithMethodRule {
-        @Rule
-        public MethodRule temporaryFolder = new MethodRule() {
-            public Statement apply(Statement base, FrameworkMethod method,
-                    Object target) {
-                return null;
-            }
-        };
-    }
-
-    @Test
-    public void rejectArbitraryObjectWithRuleAnnotation() throws Exception {
-        TestClass target = new TestClass(TestWithArbitraryObjectWithRuleAnnotation.class);
-        RULE_VALIDATOR.validate(target, errors);
-        assertOneErrorWithMessage("The @Rule 'arbitraryObject' must implement MethodRule or TestRule.");
-    }
-
-    public static class TestWithArbitraryObjectWithRuleAnnotation {
-        @Rule
-        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());
-    }
-
-    private void assertNumberOfErrors(int numberOfErrors) {
-        assertEquals("Wrong number of errors:", numberOfErrors, errors.size());
-    }
-}
diff --git a/src/test/java/org/junit/tests/experimental/rules/RuleMemberValidatorTest.java b/src/test/java/org/junit/tests/experimental/rules/RuleMemberValidatorTest.java
new file mode 100644
index 0000000..00a0e13
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/rules/RuleMemberValidatorTest.java
@@ -0,0 +1,359 @@
+package org.junit.tests.experimental.rules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_METHOD_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_VALIDATOR;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.MethodRule;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+public class RuleMemberValidatorTest {
+    private final List<Throwable> errors = new ArrayList<Throwable>();
+
+    @Test
+    public void rejectProtectedClassRule() {
+        TestClass target = new TestClass(TestWithProtectedClassRule.class);
+        CLASS_RULE_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @ClassRule 'temporaryFolder' must be public.");
+    }
+
+    public static class TestWithProtectedClassRule {
+        @ClassRule
+        protected static TestRule temporaryFolder = new TemporaryFolder();
+    }
+
+    @Test
+    public void rejectNonStaticClassRule() {
+        TestClass target = new TestClass(TestWithNonStaticClassRule.class);
+        CLASS_RULE_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @ClassRule 'temporaryFolder' must be static.");
+    }
+
+    public static class TestWithNonStaticClassRule {
+        @ClassRule
+        public TestRule temporaryFolder = new TemporaryFolder();
+    }
+
+    @Test
+    public void acceptStaticTestRuleThatIsAlsoClassRule() {
+        TestClass target = new TestClass(TestWithStaticClassAndTestRule.class);
+        CLASS_RULE_VALIDATOR.validate(target, errors);
+        assertNumberOfErrors(0);
+    }
+
+    public static class TestWithStaticClassAndTestRule {
+        @ClassRule
+        @Rule
+        public static TestRule temporaryFolder = new TemporaryFolder();
+    }
+
+    @Test
+    public void rejectClassRuleInNonPublicClass() {
+        TestClass target = new TestClass(NonPublicTestWithClassRule.class);
+        CLASS_RULE_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @ClassRule 'temporaryFolder' must be declared in a public class.");
+    }
+
+    static class NonPublicTestWithClassRule {
+        @ClassRule
+        public static TestRule temporaryFolder = new TemporaryFolder();
+    }
+    
+    /**
+     * If there is any property annotated with @ClassRule then it must implement
+     * {@link TestRule}
+     * 
+     * <p>This case has been added with 
+     * <a href="https://github.com/junit-team/junit/issues/1019">Issue #1019</a>
+     */
+    @Test
+    public void rejectClassRuleThatIsImplemetationOfMethodRule() {
+        TestClass target = new TestClass(TestWithClassRuleIsImplementationOfMethodRule.class);
+        CLASS_RULE_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @ClassRule 'classRule' must implement TestRule.");
+    }
+    
+    public static class TestWithClassRuleIsImplementationOfMethodRule {
+        @ClassRule
+        public static MethodRule classRule = new MethodRule() {
+            
+            public Statement apply(Statement base, FrameworkMethod method, Object target) {
+                return base;
+            }
+        };
+    }
+
+    /**
+     * If there is any method annotated with @ClassRule then it must return an 
+     * implementation of {@link TestRule}
+     * 
+     * <p>This case has been added with 
+     * <a href="https://github.com/junit-team/junit/issues/1019">Issue #1019</a>
+     */
+    @Test
+    public void rejectClassRuleThatReturnsImplementationOfMethodRule() {
+        TestClass target = new TestClass(TestWithClassRuleMethodThatReturnsMethodRule.class);
+        CLASS_RULE_METHOD_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @ClassRule 'methodRule' must return an implementation of TestRule.");
+    }
+
+    public static class TestWithClassRuleMethodThatReturnsMethodRule {
+        @ClassRule
+        public static MethodRule methodRule() {
+            return new MethodRule() {
+                
+                public Statement apply(Statement base, FrameworkMethod method, Object target) {
+                    return base;
+                }
+            };
+        }
+    }
+    
+    /**
+     * If there is any property annotated with @ClassRule then it must implement
+     * {@link TestRule}
+     * 
+     * <p>This case has been added with 
+     * <a href="https://github.com/junit-team/junit/issues/1019">Issue #1019</a>
+     */
+    @Test
+    public void rejectClassRuleIsAnArbitraryObject() throws Exception {
+        TestClass target = new TestClass(TestWithClassRuleIsAnArbitraryObject.class);
+        CLASS_RULE_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @ClassRule 'arbitraryObject' must implement TestRule.");
+    }
+
+    public static class TestWithClassRuleIsAnArbitraryObject {
+        @ClassRule
+        public static Object arbitraryObject = 1;
+    }
+    
+    /**
+     * If there is any method annotated with @ClassRule then it must return an 
+     * implementation of {@link TestRule}
+     * 
+     * <p>This case has been added with 
+     * <a href="https://github.com/junit-team/junit/issues/1019">Issue #1019</a> 
+     */
+    @Test
+    public void rejectClassRuleMethodReturnsAnArbitraryObject() throws Exception {
+        TestClass target = new TestClass(TestWithClassRuleMethodReturnsAnArbitraryObject.class);
+        CLASS_RULE_METHOD_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @ClassRule 'arbitraryObject' must return an implementation of TestRule.");
+    }
+
+    public static class TestWithClassRuleMethodReturnsAnArbitraryObject {
+        @ClassRule
+        public static Object arbitraryObject() {
+            return 1;
+        }
+    }
+    
+    @Test
+    public void acceptNonStaticTestRule() {
+        TestClass target = new TestClass(TestWithNonStaticTestRule.class);
+        RULE_VALIDATOR.validate(target, errors);
+        assertNumberOfErrors(0);
+    }
+
+    public static class TestWithNonStaticTestRule {
+        @Rule
+        public TestRule temporaryFolder = new TemporaryFolder();
+    }
+
+    @Test
+    public void rejectStaticTestRule() {
+        TestClass target = new TestClass(TestWithStaticTestRule.class);
+        RULE_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @Rule 'temporaryFolder' must not be static or it must be annotated with @ClassRule.");
+    }
+
+    public static class TestWithStaticTestRule {
+        @Rule
+        public static TestRule temporaryFolder = new TemporaryFolder();
+    }
+
+    @Test
+    public void rejectStaticMethodRule() {
+        TestClass target = new TestClass(TestWithStaticMethodRule.class);
+        RULE_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @Rule 'someMethodRule' must not be static.");
+    }
+
+    public static class TestWithStaticMethodRule {
+        @Rule
+        public static MethodRule someMethodRule = new SomeMethodRule();
+    }
+    
+    @Test
+    public void acceptMethodRule() throws Exception {
+        TestClass target = new TestClass(TestWithMethodRule.class);
+        RULE_VALIDATOR.validate(target, errors);
+        assertNumberOfErrors(0);
+    }
+
+    public static class TestWithMethodRule {
+        @Rule
+        public MethodRule temporaryFolder = new MethodRule() {
+            public Statement apply(Statement base, FrameworkMethod method,
+                    Object target) {
+                return null;
+            }
+        };
+    }
+
+    @Test
+    public void rejectArbitraryObjectWithRuleAnnotation() throws Exception {
+        TestClass target = new TestClass(TestWithArbitraryObjectWithRuleAnnotation.class);
+        RULE_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @Rule 'arbitraryObject' must implement MethodRule or TestRule.");
+    }
+
+    public static class TestWithArbitraryObjectWithRuleAnnotation {
+        @Rule
+        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 acceptMethodStaticTestRuleThatIsAlsoClassRule() {
+        TestClass target = new TestClass(MethodTestWithStaticClassAndTestRule.class);
+        CLASS_RULE_METHOD_VALIDATOR.validate(target, errors);
+        assertNumberOfErrors(0);
+    }
+
+    public static class MethodTestWithStaticClassAndTestRule {
+        @ClassRule
+        @Rule
+        public static 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 or it must be annotated with @ClassRule.");
+    }
+
+    public static class TestMethodWithStaticTestRule {
+        @Rule
+        public static TestRule getTemporaryFolder() {
+            return new TemporaryFolder();
+        }
+    }
+
+    @Test
+    public void rejectMethodStaticMethodRule() {
+        TestClass target = new TestClass(TestMethodWithStaticMethodRule.class);
+        RULE_METHOD_VALIDATOR.validate(target, errors);
+        assertOneErrorWithMessage("The @Rule 'getSomeMethodRule' must not be static.");
+    }
+
+    public static class TestMethodWithStaticMethodRule {
+        @Rule
+        public static MethodRule getSomeMethodRule() { return new SomeMethodRule(); }
+    }
+
+    @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());
+    }
+
+    private void assertNumberOfErrors(int numberOfErrors) {
+        assertEquals("Wrong number of errors:", numberOfErrors, errors.size());
+    }
+    
+    private static final class SomeMethodRule implements MethodRule {
+        public Statement apply(Statement base, FrameworkMethod method, Object target) {
+            return base;
+        }
+    }
+}
diff --git a/src/test/java/org/junit/tests/experimental/rules/StopwatchTest.java b/src/test/java/org/junit/tests/experimental/rules/StopwatchTest.java
deleted file mode 100644
index 35630e2..0000000
--- a/src/test/java/org/junit/tests/experimental/rules/StopwatchTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package org.junit.tests.experimental.rules;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.internal.AssumptionViolatedException;
-import org.junit.rules.Stopwatch;
-import org.junit.runner.Description;
-import org.junit.runner.JUnitCore;
-import org.junit.runner.Result;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assume.assumeTrue;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.Assert.assertNotEquals;
-
-/**
- * @author tibor17
- * @since 4.12
- */
-public class StopwatchTest {
-    private static enum TestStatus { SUCCEEDED, FAILED, SKIPPED }
-    private static Record fRecord;
-    private static Record fFinishedRecord;
-
-    private static class Record {
-        final long fDuration;
-        final String fName;
-        final TestStatus fStatus;
-
-        Record() {
-            this(0, null, null);
-        }
-
-        Record(long duration, String name) {
-            this(duration, null, name);
-        }
-
-        Record(long duration, TestStatus status, String name) {
-            fDuration= duration;
-            fStatus= status;
-            fName= name;
-        }
-    }
-
-    public static abstract class AbstractStopwatchTest {
-
-        @Rule
-        public final Stopwatch fStopwatch= new Stopwatch() {
-            @Override
-            protected void succeeded(long nanos, Description description) {
-                StopwatchTest.fRecord= new Record(nanos, TestStatus.SUCCEEDED, description.getMethodName());
-            }
-
-            @Override
-            protected void failed(long nanos, Throwable e, Description description) {
-                StopwatchTest.fRecord= new Record(nanos, TestStatus.FAILED, description.getMethodName());
-            }
-
-            @Override
-            protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
-                StopwatchTest.fRecord= new Record(nanos, TestStatus.SKIPPED, description.getMethodName());
-            }
-
-            @Override
-            protected void finished(long nanos, Description description) {
-                StopwatchTest.fFinishedRecord= new Record(nanos, description.getMethodName());
-            }
-        };
-    }
-
-    public static class SuccessfulTest extends AbstractStopwatchTest {
-        @Test
-        public void successfulTest() {
-        }
-    }
-
-    public static class FailedTest extends AbstractStopwatchTest {
-        @Test
-        public void failedTest() {
-            fail();
-        }
-    }
-
-    public static class SkippedTest extends AbstractStopwatchTest {
-        @Test
-        public void skippedTest() {
-            assumeTrue(false);
-        }
-    }
-
-    public static class WrongDurationTest extends AbstractStopwatchTest {
-        @Test
-        public void wrongDuration() throws InterruptedException {
-            Thread.sleep(500L);
-            assertNotEquals(fStopwatch.runtime(MILLISECONDS), 300d, 100d);
-        }
-    }
-
-    public static class DurationTest extends AbstractStopwatchTest {
-        @Test
-        public void duration() throws InterruptedException {
-            Thread.sleep(300L);
-            assertEquals(300d, fStopwatch.runtime(MILLISECONDS), 100d);
-            Thread.sleep(500L);
-            assertEquals(800d, fStopwatch.runtime(MILLISECONDS), 250d);
-        }
-    }
-
-    @Before
-    public void init() {
-        fRecord= new Record();
-        fFinishedRecord= new Record();
-    }
-
-    @Test
-    public void succeeded() {
-        Result result= JUnitCore.runClasses(SuccessfulTest.class);
-        assertEquals(0, result.getFailureCount());
-        assertThat(fRecord.fName, is("successfulTest"));
-        assertThat(fRecord.fName, is(fFinishedRecord.fName));
-        assertThat(fRecord.fStatus, is(TestStatus.SUCCEEDED));
-        assertTrue("timeSpent > 0", fRecord.fDuration > 0);
-        assertThat(fRecord.fDuration, is(fFinishedRecord.fDuration));
-    }
-
-    @Test
-    public void failed() {
-        Result result= JUnitCore.runClasses(FailedTest.class);
-        assertEquals(1, result.getFailureCount());
-        assertThat(fRecord.fName, is("failedTest"));
-        assertThat(fRecord.fName, is(fFinishedRecord.fName));
-        assertThat(fRecord.fStatus, is(TestStatus.FAILED));
-        assertTrue("timeSpent > 0", fRecord.fDuration > 0);
-        assertThat(fRecord.fDuration, is(fFinishedRecord.fDuration));
-    }
-
-    @Test
-    public void skipped() {
-        Result result= JUnitCore.runClasses(SkippedTest.class);
-        assertEquals(0, result.getFailureCount());
-        assertThat(fRecord.fName, is("skippedTest"));
-        assertThat(fRecord.fName, is(fFinishedRecord.fName));
-        assertThat(fRecord.fStatus, is(TestStatus.SKIPPED));
-        assertTrue("timeSpent > 0", fRecord.fDuration > 0);
-        assertThat(fRecord.fDuration, is(fFinishedRecord.fDuration));
-    }
-
-    @Test
-    public void wrongDuration() {
-        Result result= JUnitCore.runClasses(WrongDurationTest.class);
-        assertTrue(result.wasSuccessful());
-    }
-
-    @Test
-    public void duration() {
-        Result result= JUnitCore.runClasses(DurationTest.class);
-        assertTrue(result.wasSuccessful());
-    }
-}
diff --git a/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderRuleAssuredDeletionTest.java b/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderRuleAssuredDeletionTest.java
new file mode 100644
index 0000000..3aad069
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderRuleAssuredDeletionTest.java
@@ -0,0 +1,78 @@
+package org.junit.tests.experimental.rules;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.failureCountIs;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+
+import java.io.IOException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.results.PrintableResult;
+import org.junit.rules.TemporaryFolder;
+
+public class TemporaryFolderRuleAssuredDeletionTest {
+
+    private static class StubTemporaryFolder extends TemporaryFolder {
+        private StubTemporaryFolder(Builder builder) {
+            super(builder);
+        }
+
+        /**
+         * Don't need to create as we are overriding deletion.
+         */
+        @Override
+        public void create() throws IOException {
+        }
+
+        /**
+         * Simulates failure to clean-up temporary folder.
+         */
+        @Override
+        protected boolean tryDelete() {
+            return false;
+        }
+
+        public static Builder builder() {
+            return new TemporaryFolder.Builder() {
+                @Override
+                public TemporaryFolder build() {
+                    return new StubTemporaryFolder(this);
+               }
+            };
+        }
+    }
+
+    public static class HasTempFolderWithAssuredDeletion {
+        @Rule public TemporaryFolder folder = StubTemporaryFolder.builder()
+                .assureDeletion()
+                .build();
+
+        @Test
+        public void alwaysPasses() {
+        }
+    }
+
+    @Test
+    public void testStrictVerificationFailure() {
+        PrintableResult result = testResult(HasTempFolderWithAssuredDeletion.class);
+        assertThat(result, failureCountIs(1));
+        assertThat(result.toString(), containsString("Unable to clean up temporary folder"));
+    }
+
+    public static class HasTempFolderWithoutAssuredDeletion {
+        @Rule public TemporaryFolder folder = StubTemporaryFolder.builder().build();
+
+        @Test
+        public void alwaysPasses() {
+        }
+    }
+
+    @Test
+    public void testStrictVerificationSuccess() {
+        PrintableResult result = testResult(HasTempFolderWithoutAssuredDeletion.class);
+        assertThat(result, isSuccessful());
+    }
+}
diff --git a/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java b/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java
index c208aad..314a141 100644
--- a/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java
@@ -84,7 +84,16 @@
         thrown.expectMessage("a folder with the name 'level1' already exists");
         tempFolder.newFolder("level1");
     }
-
+    
+    @Test
+    public void newFolderWithGivenFolderThrowsIOExceptionIfFolderNameConsistsOfMultiplePathComponents()
+            throws IOException {
+        tempFolder.create();
+        thrown.expect(IOException.class);
+        thrown.expectMessage("name cannot consist of multiple path components");
+        tempFolder.newFolder("temp1/temp2");
+    }
+    
     @Test
     public void newFolderWithGivenPathThrowsIllegalArgumentExceptionIfPathExists() throws IOException {
         tempFolder.create();
@@ -96,6 +105,15 @@
     }
 
     @Test
+    public void newFolderWithGivenPathThrowsIOExceptionIfFolderNamesConsistOfMultiplePathComponents()
+            throws IOException {
+        tempFolder.create();
+        thrown.expect(IOException.class);
+        thrown.expectMessage("name cannot consist of multiple path components");
+        tempFolder.newFolder("temp1", "temp2", "temp3/temp4");
+    }
+    
+    @Test
     public void createInitializesRootFolder() throws IOException {
         tempFolder.create();
         assertFileExists(tempFolder.getRoot());
diff --git a/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java b/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
index b754633..1c1355f 100644
--- a/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
@@ -28,11 +28,6 @@
 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;
 
@@ -65,7 +60,6 @@
         assertTrue(wasRun);
     }
 
-    @SuppressWarnings("deprecation")
     public static class BothKindsOfRule implements TestRule, org.junit.rules.MethodRule {
         public int applications = 0;
 
@@ -275,7 +269,6 @@
     }
 
     public static class PrivateRule {
-        @SuppressWarnings("unused")
         @Rule
         private TestRule rule = new TestName();
 
@@ -352,7 +345,6 @@
         assertTrue(wasRun);
     }
 
-    @SuppressWarnings("deprecation")
     public static class MethodBothKindsOfRule implements TestRule, org.junit.rules.MethodRule {
         public int applications = 0;
 
@@ -399,8 +391,6 @@
         assertTrue(wasRun);
     }
 
-//	private static int runCount;
-
     public static class MethodMultipleRuleTest {
         private static class Increment implements TestRule {
             public Statement apply(final Statement base, Description description) {
@@ -514,6 +504,7 @@
     }
 
     public static class MethodWatchmanTest {
+        @SuppressWarnings("unused")
         private static String watchedLog;
 
         private TestRule watchman = new TestWatcher() {
@@ -628,7 +619,6 @@
     }
 
     public static class MethodPrivateRule {
-        @SuppressWarnings("unused")
         @Rule
         private TestRule getRule() {
             return new TestName();
@@ -684,8 +674,6 @@
         }
     }
 
-    ;
-
     public static class UsesFieldAndMethodRule {
         @Rule
         public OrderTestRule orderMethod() {
@@ -708,15 +696,6 @@
         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;
 
diff --git a/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java b/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java
index 7b28147..bae1dc2 100644
--- a/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java
@@ -1,14 +1,13 @@
 package org.junit.tests.experimental.rules;
 
-import static junit.framework.Assert.fail;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 import static org.junit.experimental.results.PrintableResult.testResult;
 import static org.junit.experimental.results.ResultMatchers.failureCountIs;
 import static org.junit.experimental.results.ResultMatchers.hasFailureContaining;
 import static org.junit.runner.JUnitCore.runClasses;
-
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.results.PrintableResult;
@@ -35,7 +34,43 @@
         ViolatedAssumptionTest.watchedLog = new StringBuilder();
         runClasses(ViolatedAssumptionTest.class);
         assertThat(ViolatedAssumptionTest.watchedLog.toString(),
-                is("starting finished "));
+                is("starting skipped finished "));
+    }
+
+    public static class InternalViolatedAssumptionTest {
+        private static StringBuilder watchedLog = new StringBuilder();
+
+        @Rule
+        public TestRule watcher = new TestWatcher() {
+            @Override
+            protected void starting(Description description) {
+                watchedLog.append("starting ");
+            }
+
+            @Override
+            protected void finished(Description description) {
+                watchedLog.append("finished ");
+            }
+
+            @Override
+            protected void skipped(AssumptionViolatedException e, Description description) {
+                watchedLog.append("skipped ");
+            }
+        };
+
+        @SuppressWarnings("deprecation")
+        @Test
+        public void succeeds() {
+            throw new AssumptionViolatedException("don't run");
+        }
+    }
+
+    @Test
+    public void internalViolatedAssumption() {
+        InternalViolatedAssumptionTest.watchedLog = new StringBuilder();
+        runClasses(InternalViolatedAssumptionTest.class);
+        assertThat(InternalViolatedAssumptionTest.watchedLog.toString(),
+                is("starting skipped finished "));
     }
 
     public static class TestWatcherSkippedThrowsExceptionTest {
@@ -47,6 +82,7 @@
             }
         };
 
+        @SuppressWarnings("deprecation")
         @Test
         public void fails() {
             throw new AssumptionViolatedException("test failure");
@@ -131,7 +167,7 @@
         @Rule
         public TestRule watcher = new TestWatcher() {
             @Override
-            protected void failed(Throwable t, Description description) {
+            protected void failed(Throwable e, Description description) {
                 throw new RuntimeException("watcher failed failure");
             }
 
@@ -155,4 +191,4 @@
         assertThat(result, hasFailureContaining("watcher failed failure"));
         assertThat(result, hasFailureContaining("watcher finished failure"));
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java b/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java
index ed680ec..288f1bf 100644
--- a/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java
@@ -1,14 +1,8 @@
 package org.junit.tests.experimental.rules;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.rules.TestRule;
-import org.junit.rules.Timeout;
-import org.junit.runner.JUnitCore;
-import org.junit.runner.Result;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 
 import java.io.File;
 import java.io.IOException;
@@ -20,9 +14,16 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
 
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
 
 public class TimeoutRuleTest {
     private static final ReentrantLock run1Lock = new ReentrantLock();
@@ -68,12 +69,16 @@
             byte[] data = new byte[1024];
             File tmp = tmpFile.newFile();
             while (true) {
-                FileChannel channel = new RandomAccessFile(tmp, "rw").getChannel();
-                rnd.nextBytes(data);
-                ByteBuffer buffer = ByteBuffer.wrap(data);
-                // Interrupted thread closes channel and throws ClosedByInterruptException.
-                channel.write(buffer);
-                channel.close();
+                RandomAccessFile randomAccessFile = new RandomAccessFile(tmp, "rw");
+                try {
+                    FileChannel channel = randomAccessFile.getChannel();
+                    rnd.nextBytes(data);
+                    ByteBuffer buffer = ByteBuffer.wrap(data);
+                    // Interrupted thread closes channel and throws ClosedByInterruptException.
+                    channel.write(buffer);
+                } finally {
+                    randomAccessFile.close();
+                }
                 tmp.delete();
             }
         }
@@ -89,13 +94,23 @@
     public static class HasGlobalLongTimeout extends AbstractTimeoutTest {
 
         @Rule
-        public final TestRule globalTimeout = Timeout.millis(50L);
+        public final TestRule globalTimeout = Timeout.millis(200);
     }
 
     public static class HasGlobalTimeUnitTimeout extends AbstractTimeoutTest {
 
         @Rule
-        public final TestRule globalTimeout = new Timeout(50, TimeUnit.MILLISECONDS);
+        public final TestRule globalTimeout = new Timeout(200, TimeUnit.MILLISECONDS);
+    }
+    
+    public static class HasNullTimeUnit {
+
+        @Rule
+        public final TestRule globalTimeout = new Timeout(200, null);
+        
+        @Test
+        public void wouldPass() {
+        }
     }
 
     @Before
@@ -112,7 +127,7 @@
     }
 
     @Test
-    public void timeUnitTimeout() throws InterruptedException {
+    public void timeUnitTimeout() {
         HasGlobalTimeUnitTimeout.logger.setLength(0);
         Result result = JUnitCore.runClasses(HasGlobalTimeUnitTimeout.class);
         assertEquals(6, result.getFailureCount());
@@ -125,7 +140,7 @@
     }
 
     @Test
-    public void longTimeout() throws InterruptedException {
+    public void longTimeout() {
         HasGlobalLongTimeout.logger.setLength(0);
         Result result = JUnitCore.runClasses(HasGlobalLongTimeout.class);
         assertEquals(6, result.getFailureCount());
@@ -136,4 +151,15 @@
         assertThat(HasGlobalLongTimeout.logger.toString(), containsString("run5"));
         assertThat(HasGlobalLongTimeout.logger.toString(), containsString("run6"));
     }
+
+    @Test
+    public void nullTimeUnit() {
+        Result result = JUnitCore.runClasses(HasNullTimeUnit.class);
+        assertEquals(1, result.getFailureCount());
+        Failure failure = result.getFailures().get(0);
+        assertThat(failure.getException().getMessage(),
+                containsString("Invalid parameters for Timeout"));
+        Throwable cause = failure.getException().getCause();
+        assertThat(cause.getMessage(), containsString("TimeUnit cannot be null"));
+    }
 }
diff --git a/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java b/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
index 7e55709..f02dcb7 100644
--- a/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
+++ b/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
@@ -84,11 +84,17 @@
                     throw new RuntimeException("first!");
                 }
             });
-            collector.checkSucceeds(new Callable<Object>() {
-                public Object call() throws Exception {
+            collector.checkSucceeds(new Callable<Integer>() {
+                public Integer call() throws Exception {
                     throw new RuntimeException("second!");
                 }
             });
+            Integer result = collector.checkSucceeds(new Callable<Integer>() {
+                public Integer call() throws Exception {
+                    return 1;
+                }
+            });
+            assertEquals(Integer.valueOf(1), result);
         }
     }
 
diff --git a/src/test/java/org/junit/tests/experimental/theories/AllMembersSupplierTest.java b/src/test/java/org/junit/tests/experimental/theories/AllMembersSupplierTest.java
deleted file mode 100644
index 5b1e3f4..0000000
--- a/src/test/java/org/junit/tests/experimental/theories/AllMembersSupplierTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.junit.tests.experimental.theories;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.util.List;
-
-import org.junit.Test;
-import org.junit.experimental.theories.DataPoints;
-import org.junit.experimental.theories.ParameterSignature;
-import org.junit.experimental.theories.PotentialAssignment;
-import org.junit.experimental.theories.internal.AllMembersSupplier;
-import org.junit.runners.model.TestClass;
-
-public class AllMembersSupplierTest {
-    public static class HasDataPoints {
-        @DataPoints
-        public static Object[] objects = {1, 2};
-
-        public HasDataPoints(Object obj) {
-        }
-    }
-
-    @Test
-    public void dataPointsAnnotationMeansTreatAsArrayOnly()
-            throws SecurityException, NoSuchMethodException {
-        List<PotentialAssignment> valueSources = new AllMembersSupplier(
-                new TestClass(HasDataPoints.class))
-                .getValueSources(ParameterSignature.signatures(
-                        HasDataPoints.class.getConstructor(Object.class))
-                        .get(0));
-        assertThat(valueSources.size(), is(2));
-    }
-
-    public static class HasDataPointsFieldWithNullValue {
-        @DataPoints
-        public static Object[] objects = {null, "a"};
-
-        public HasDataPointsFieldWithNullValue(Object obj) {
-        }
-    }
-
-    @Test
-    public void dataPointsArrayFieldMayContainNullValue()
-            throws SecurityException, NoSuchMethodException {
-        List<PotentialAssignment> valueSources = new AllMembersSupplier(
-                new TestClass(HasDataPointsFieldWithNullValue.class))
-                .getValueSources(ParameterSignature.signatures(
-                        HasDataPointsFieldWithNullValue.class.getConstructor(Object.class))
-                        .get(0));
-        assertThat(valueSources.size(), is(2));
-    }
-
-    public static class HasDataPointsMethodWithNullValue {
-        @DataPoints
-        public static Integer[] getObjects() {
-            return new Integer[] {null, 1};
-        }
-
-        public HasDataPointsMethodWithNullValue(Integer i) {
-        }
-    }
-
-    @Test
-    public void dataPointsArrayMethodMayContainNullValue()
-            throws SecurityException, NoSuchMethodException {
-        List<PotentialAssignment> valueSources = new AllMembersSupplier(
-                new TestClass(HasDataPointsMethodWithNullValue.class))
-                .getValueSources(ParameterSignature.signatures(
-                        HasDataPointsMethodWithNullValue.class.getConstructor(Integer.class))
-                        .get(0));
-        assertThat(valueSources.size(), is(2));
-    }
-}
diff --git a/src/test/java/org/junit/tests/experimental/theories/AssumingInTheoriesTest.java b/src/test/java/org/junit/tests/experimental/theories/AssumingInTheoriesTest.java
index 1972d82..758e6fb 100644
--- a/src/test/java/org/junit/tests/experimental/theories/AssumingInTheoriesTest.java
+++ b/src/test/java/org/junit/tests/experimental/theories/AssumingInTheoriesTest.java
@@ -1,47 +1,42 @@
 package org.junit.tests.experimental.theories;
 
+import static org.junit.tests.experimental.theories.TheoryTestUtils.runTheoryClass;
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Test;
 import org.junit.experimental.theories.DataPoint;
 import org.junit.experimental.theories.Theories;
 import org.junit.experimental.theories.Theory;
-import org.junit.runner.JUnitCore;
-import org.junit.runner.Request;
 import org.junit.runner.Result;
 import org.junit.runner.RunWith;
-import org.junit.runner.Runner;
 import org.junit.runners.model.InitializationError;
 
 @RunWith(Theories.class)
 public class AssumingInTheoriesTest {
 
-	@Test
-	public void noTheoryAnnotationMeansAssumeShouldIgnore() {
-		Assume.assumeTrue(false);
-	}
+    @Test
+    public void noTheoryAnnotationMeansAssumeShouldIgnore() {
+        Assume.assumeTrue(false);
+    }
 
-	@Test
-	public void theoryMeansOnlyAssumeShouldFail() throws InitializationError {
-		JUnitCore junitRunner = new JUnitCore();
-		Runner theoryRunner = new Theories(TheoryWithNoUnassumedParameters.class);
-		Request request = Request.runner(theoryRunner);
-		Result result = junitRunner.run(request);
-		Assert.assertEquals(1, result.getFailureCount());
-	}
+    @Test
+    public void theoryMeansOnlyAssumeShouldFail() throws InitializationError {
+        Result result = runTheoryClass(TheoryWithNoUnassumedParameters.class);
+        Assert.assertEquals(1, result.getFailureCount());
+    }
 
-	/**
-	 * Simple class that SHOULD fail because no parameters are met.
-	 */
-	public static class TheoryWithNoUnassumedParameters {
-		
-		@DataPoint 
-		public final static boolean FALSE = false;
-		
-		@Theory
-		public void theoryWithNoUnassumedParameters(boolean value) {
-			Assume.assumeTrue(value);
-		}
-	}
+    /**
+     * Simple class that SHOULD fail because no parameters are met.
+     */
+    public static class TheoryWithNoUnassumedParameters {
+
+        @DataPoint
+        public final static boolean FALSE = false;
+
+        @Theory
+        public void theoryWithNoUnassumedParameters(boolean value) {
+            Assume.assumeTrue(value);
+        }
+    }
 
 }
diff --git a/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java b/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java
index 83b9266..edfcdd1 100644
--- a/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java
+++ b/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java
@@ -3,6 +3,7 @@
 import static org.hamcrest.CoreMatchers.isA;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import java.lang.annotation.Annotation;
@@ -40,17 +41,52 @@
                 .signatures(method).get(index).getType());
     }
 
-    public void foo(@TestedOn(ints = {1, 2, 3})
-    int x) {
+    public void foo(@TestedOn(ints = {1, 2, 3}) int x) {
     }
 
     @Test
     public void getAnnotations() throws SecurityException,
             NoSuchMethodException {
-        Method method = ParameterSignatureTest.class.getMethod("foo", int.class);
+        Method method = getClass().getMethod("foo", int.class);
         List<Annotation> annotations = ParameterSignature.signatures(method)
                 .get(0).getAnnotations();
         assertThat(annotations,
                 CoreMatchers.<TestedOn>hasItem(isA(TestedOn.class)));
     }
+    
+    public void intMethod(int param) {
+    }
+    
+    public void integerMethod(Integer param) {
+    }
+    
+    public void numberMethod(Number param) {
+    }
+
+    @Test
+    public void primitiveTypesShouldBeAcceptedAsWrapperTypes() throws Exception {
+        List<ParameterSignature> signatures = ParameterSignature
+                .signatures(getClass().getMethod("integerMethod", Integer.class));
+        ParameterSignature integerSignature = signatures.get(0);
+
+        assertTrue(integerSignature.canAcceptType(int.class));
+    }
+    
+    @Test
+    public void primitiveTypesShouldBeAcceptedAsWrapperTypeAssignables() throws Exception {
+        List<ParameterSignature> signatures = ParameterSignature
+                .signatures(getClass().getMethod("numberMethod", Number.class));
+        ParameterSignature numberSignature = signatures.get(0);
+
+        assertTrue(numberSignature.canAcceptType(int.class));
+    }
+    
+    @Test
+    public void wrapperTypesShouldBeAcceptedAsPrimitiveTypes() throws Exception {
+        List<ParameterSignature> signatures = ParameterSignature
+                .signatures(getClass().getMethod("intMethod", int.class));
+        ParameterSignature intSignature = signatures.get(0);
+
+        assertTrue(intSignature.canAcceptType(Integer.class));
+    }
 }
diff --git a/src/test/java/org/junit/tests/experimental/theories/TheoryTestUtils.java b/src/test/java/org/junit/tests/experimental/theories/TheoryTestUtils.java
new file mode 100644
index 0000000..6e1b351
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/theories/TheoryTestUtils.java
@@ -0,0 +1,33 @@
+package org.junit.tests.experimental.theories;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.internal.Assignments;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.Runner;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.TestClass;
+
+public final class TheoryTestUtils {
+    
+    private TheoryTestUtils() { }
+    
+    public static List<PotentialAssignment> potentialAssignments(Method method)
+            throws Throwable {
+        return Assignments.allUnassigned(method,
+                new TestClass(method.getDeclaringClass()))
+                .potentialsForNextUnassigned();
+    }
+    
+    public static Result runTheoryClass(Class<?> testClass) throws InitializationError {
+        Runner theoryRunner = new Theories(testClass);
+        Request request = Request.runner(theoryRunner);
+        return new JUnitCore().run(request);
+    }
+
+}
diff --git a/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheories.java b/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheories.java
index 2ae0d67..cf6a6ef 100644
--- a/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheories.java
+++ b/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheories.java
@@ -40,8 +40,7 @@
 
         @Override
         protected void runWithIncompleteAssignment(Assignments incomplete)
-                throws InstantiationException, IllegalAccessException,
-                Throwable {
+                throws Throwable {
             GuesserQueue guessers = createGuesserQueue(incomplete);
             queues.add(guessers);
             while (!guessers.isEmpty())
@@ -50,7 +49,7 @@
         }
 
         private GuesserQueue createGuesserQueue(Assignments incomplete)
-                throws InstantiationException, IllegalAccessException {
+                throws Throwable {
             ParameterSignature nextUnassigned = incomplete.nextUnassigned();
 
             if (nextUnassigned.hasAnnotation(Stub.class)) {
diff --git a/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java b/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java
index abecdf7..a86bcd6 100644
--- a/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java
+++ b/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java
Binary files differ
diff --git a/src/test/java/org/junit/tests/experimental/theories/internal/AllMembersSupplierTest.java b/src/test/java/org/junit/tests/experimental/theories/internal/AllMembersSupplierTest.java
new file mode 100644
index 0000000..a3ee363
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/theories/internal/AllMembersSupplierTest.java
@@ -0,0 +1,209 @@
+package org.junit.tests.experimental.theories.internal;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.tests.experimental.theories.TheoryTestUtils.potentialAssignments;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.experimental.theories.Theory;
+import org.junit.experimental.theories.internal.AllMembersSupplier;
+import org.junit.rules.ExpectedException;
+import org.junit.runners.model.TestClass;
+
+public class AllMembersSupplierTest {
+    @Rule
+    public ExpectedException expected = ExpectedException.none();
+    
+    public static class HasDataPointsArrayField {
+        @DataPoints
+        public static String[] list = new String[] { "qwe", "asd" };
+
+        @Theory
+        public void theory(String param) {
+        }
+    }
+    
+    @Test
+    public void dataPointsArrayShouldBeRecognized() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(
+                HasDataPointsArrayField.class.getMethod("theory", String.class));
+        
+        assertEquals(2, assignments.size());
+    }
+    
+    public static class HasDataPointsArrayWithMatchingButInaccurateTypes {
+        @DataPoints
+        public static Object[] objects = {1, "string!", 2};
+
+        @Theory
+        public void theory(Integer param) {
+        }
+    }
+
+    @Test
+    public void dataPointsArrayShouldBeRecognizedOnValueTypeNotFieldType() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(
+                HasDataPointsArrayWithMatchingButInaccurateTypes.class.getMethod("theory", Integer.class));
+        
+        assertEquals(2, assignments.size());
+    }
+    
+    public static class HasDataPointMethodWithOverlyGeneralTypes {
+        @DataPoint
+        public static Integer object() {
+            return 1;
+        }
+
+        @Theory
+        public void theory(Object param) {
+        }
+    }
+
+    @Test
+    public void dataPointMethodShouldBeRecognizedForOverlyGeneralParameters() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(
+                HasDataPointMethodWithOverlyGeneralTypes.class.getMethod("theory", Object.class));
+        
+        assertEquals(1, assignments.size());
+    }
+    
+    public static class HasDataPointsWithObjectParameter {
+        @DataPoints
+        public static Object[] objectField = {1, 2};
+
+        @Theory
+        public void theory(Object obj) {
+        }
+    }
+
+    @Test
+    public void dataPointsAnnotationMeansTreatAsArrayOnly() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(
+                HasDataPointsWithObjectParameter.class.getMethod("theory", Object.class));
+        
+        assertEquals(2, assignments.size());
+        for (PotentialAssignment assignment : assignments) {
+            assertNotEquals(HasDataPointsWithObjectParameter.objectField, assignment.getValue());
+        }
+    }
+
+    public static class HasDataPointsFieldWithNullValue {
+        @DataPoints
+        public static Object[] objects = {null, "a"};
+
+        public HasDataPointsFieldWithNullValue(Object obj) {
+        }
+    }
+
+    @Test
+    public void dataPointsArrayFieldMayContainNullValue() throws Throwable {
+        List<PotentialAssignment> valueSources = allMemberValuesFor(
+                HasDataPointsFieldWithNullValue.class, Object.class);
+        assertThat(valueSources.size(), is(2));
+    }
+
+    public static class HasDataPointsMethodWithNullValue {
+        @DataPoints
+        public static Integer[] getObjects() {
+            return new Integer[] {null, 1};
+        }
+
+        public HasDataPointsMethodWithNullValue(Integer i) {
+        }
+    }
+
+    @Test
+    public void dataPointsArrayMethodMayContainNullValue() throws Throwable {
+        List<PotentialAssignment> valueSources = allMemberValuesFor(
+                HasDataPointsMethodWithNullValue.class, Integer.class);
+        assertThat(valueSources.size(), is(2));
+    }
+    
+    public static class HasFailingDataPointsArrayMethod {
+        @DataPoints
+        public static Object[] objects() {
+            throw new RuntimeException("failing method");
+        }
+
+        public HasFailingDataPointsArrayMethod(Object obj) {
+        }
+    }
+
+    @Test
+    public void allMembersFailsOnFailingDataPointsArrayMethod() throws Throwable {
+        expected.expect(RuntimeException.class);
+        expected.expectMessage("failing method");
+        allMemberValuesFor(HasFailingDataPointsArrayMethod.class, Object.class);
+    }
+
+    private List<PotentialAssignment> allMemberValuesFor(Class<?> testClass,
+            Class<?>... constructorParameterTypes) throws Throwable {
+        return new AllMembersSupplier(new TestClass(testClass))
+                .getValueSources(ParameterSignature.signatures(
+                        testClass.getConstructor(constructorParameterTypes))
+                        .get(0));
+    }
+    
+    public static class HasDataPointsListField {
+        @DataPoints
+        public static List<String> list = Arrays.asList("one", "two");
+
+        @Theory
+        public void theory(String param) {
+        }
+    }
+
+    @Test
+    public void dataPointsCollectionFieldsShouldBeRecognized() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(
+            HasDataPointsListField.class.getMethod("theory", String.class));
+
+        assertEquals(2, assignments.size());
+    }
+    
+    public static class HasDataPointsListMethod {
+        @DataPoints
+        public static List<String> getList() {
+            return Arrays.asList("one", "two");
+        }
+
+        @Theory
+        public void theory(String param) {
+        }
+    }
+
+    @Test
+    public void dataPointsCollectionMethodShouldBeRecognized() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(
+            HasDataPointsListMethod.class.getMethod("theory", String.class));
+
+        assertEquals(2, assignments.size());
+    }
+    
+    public static class HasDataPointsListFieldWithOverlyGenericTypes {
+        @DataPoints
+        public static List<Object> list = Arrays.asList("string", new Object());
+
+        @Theory
+        public void theory(String param) {
+        }
+    }
+
+    @Test
+    public void dataPointsCollectionShouldBeRecognizedIgnoringStrangeTypes() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(
+            HasDataPointsListFieldWithOverlyGenericTypes.class.getMethod("theory", String.class));
+
+        assertEquals(1, assignments.size());
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/junit/tests/experimental/theories/ParameterizedAssertionErrorTest.java b/src/test/java/org/junit/tests/experimental/theories/internal/ParameterizedAssertionErrorTest.java
similarity index 68%
rename from src/test/java/org/junit/tests/experimental/theories/ParameterizedAssertionErrorTest.java
rename to src/test/java/org/junit/tests/experimental/theories/internal/ParameterizedAssertionErrorTest.java
index 9a78ffe..2d42d99 100644
--- a/src/test/java/org/junit/tests/experimental/theories/ParameterizedAssertionErrorTest.java
+++ b/src/test/java/org/junit/tests/experimental/theories/internal/ParameterizedAssertionErrorTest.java
@@ -1,9 +1,10 @@
-package org.junit.tests.experimental.theories;
+package org.junit.tests.experimental.theories.internal;
 
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assume.assumeThat;
 
 import org.junit.Test;
@@ -53,15 +54,33 @@
     @Theory
     public void equalsReturnsTrue(Throwable targetException, String methodName,
             Object[] params) {
-        assertThat(new ParameterizedAssertionError(targetException, methodName,
-                params), is(new ParameterizedAssertionError(targetException,
-                methodName, params)));
+        assertThat(
+                new ParameterizedAssertionError(targetException, methodName, params),
+                is(new ParameterizedAssertionError(targetException, methodName, params)));
+    }
+
+    @Theory
+    public void sameHashCodeWhenEquals(Throwable targetException, String methodName,
+            Object[] params) {
+        ParameterizedAssertionError one = new ParameterizedAssertionError(
+                targetException, methodName, params);
+        ParameterizedAssertionError two = new ParameterizedAssertionError(
+                targetException, methodName, params);
+        assumeThat(one, is(two));
+
+        assertThat(one.hashCode(), is(two.hashCode()));
     }
 
     @Theory(nullsAccepted = false)
     public void buildParameterizedAssertionError(String methodName, String param) {
-        assertThat(new ParameterizedAssertionError(new RuntimeException(),
-                methodName, param).toString(), containsString(methodName));
+        assertThat(new ParameterizedAssertionError(
+                new RuntimeException(), methodName, param).toString(),
+                containsString(methodName));
+    }
+
+    @Theory
+    public void isNotEqualToNull(ParameterizedAssertionError a) {
+        assertFalse(a.equals(null));
     }
 
     @Test
diff --git a/src/test/java/org/junit/tests/experimental/theories/internal/SpecificDataPointsSupplierTest.java b/src/test/java/org/junit/tests/experimental/theories/internal/SpecificDataPointsSupplierTest.java
new file mode 100644
index 0000000..3ccf902
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/theories/internal/SpecificDataPointsSupplierTest.java
@@ -0,0 +1,156 @@
+package org.junit.tests.experimental.theories.internal;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.FromDataPoints;
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.experimental.theories.PotentialAssignment.CouldNotGenerateValueException;
+import org.junit.experimental.theories.internal.SpecificDataPointsSupplier;
+import org.junit.runners.model.TestClass;
+
+public class SpecificDataPointsSupplierTest {
+
+    public static class TestClassWithNamedDataPoints {
+
+        @DataPoints({"field", "named"})
+        public static String[] values = new String[] { "named field" };
+
+        @DataPoints
+        public static String[] otherValues = new String[] { "other" };
+        
+        @DataPoints({"method", "named"})
+        public static String[] getValues() {
+            return new String[] { "named method" };
+        }
+        
+        @DataPoint({"single", "named"})
+        public static String singleValue = "named single value";
+        
+        @DataPoint
+        public static String otherSingleValue = "other value";
+        
+        @DataPoint({"singlemethod", "named"})
+        public static String getSingleValue() { 
+            return "named single method value";
+        }
+        
+        @DataPoint
+        public static String getSingleOtherValue() {
+            return "other single method value";
+        }
+         
+        @DataPoints
+        public static String[] getOtherValues() {
+            return new String[] { "other method" };
+        }
+    }
+
+    @Test
+    public void shouldReturnOnlyTheNamedDataPoints() throws Throwable {
+        SpecificDataPointsSupplier supplier = new SpecificDataPointsSupplier(new TestClass(TestClassWithNamedDataPoints.class));
+
+        List<PotentialAssignment> assignments = supplier.getValueSources(signature("methodWantingAllNamedStrings"));
+        List<String> assignedStrings = getStringValuesFromAssignments(assignments);
+
+        assertEquals(4, assignedStrings.size());
+        assertThat(assignedStrings, hasItems("named field", "named method", "named single value", "named single method value"));
+    }
+    
+    @Test
+    public void shouldReturnOnlyTheNamedFieldDataPoints() throws Throwable {
+        SpecificDataPointsSupplier supplier = new SpecificDataPointsSupplier(new TestClass(TestClassWithNamedDataPoints.class));
+
+        List<PotentialAssignment> assignments = supplier.getValueSources(signature("methodWantingNamedFieldString"));
+        List<String> assignedStrings = getStringValuesFromAssignments(assignments);
+
+        assertEquals(1, assignedStrings.size());
+        assertThat(assignedStrings, hasItem("named field"));
+    }
+
+    @Test
+    public void shouldReturnOnlyTheNamedMethodDataPoints() throws Throwable {
+        SpecificDataPointsSupplier supplier = new SpecificDataPointsSupplier(new TestClass(TestClassWithNamedDataPoints.class));
+
+        List<PotentialAssignment> assignments = supplier.getValueSources(signature("methodWantingNamedMethodString"));
+        List<String> assignedStrings = getStringValuesFromAssignments(assignments);
+
+        assertEquals(1, assignedStrings.size());
+        assertThat(assignedStrings, hasItem("named method"));
+    }
+    
+    @Test
+    public void shouldReturnOnlyTheNamedSingleFieldDataPoints() throws Throwable {
+        SpecificDataPointsSupplier supplier = new SpecificDataPointsSupplier(new TestClass(TestClassWithNamedDataPoints.class));
+
+        List<PotentialAssignment> assignments = supplier.getValueSources(signature("methodWantingNamedSingleFieldString"));
+        List<String> assignedStrings = getStringValuesFromAssignments(assignments);
+
+        assertEquals(1, assignedStrings.size());
+        assertThat(assignedStrings, hasItem("named single value"));
+    }
+
+    @Test
+    public void shouldReturnOnlyTheNamedSingleMethodDataPoints() throws Throwable {
+        SpecificDataPointsSupplier supplier = new SpecificDataPointsSupplier(new TestClass(TestClassWithNamedDataPoints.class));
+
+        List<PotentialAssignment> assignments = supplier.getValueSources(signature("methodWantingNamedSingleMethodString"));
+        List<String> assignedStrings = getStringValuesFromAssignments(assignments);
+
+        assertEquals(1, assignedStrings.size());
+        assertThat(assignedStrings, hasItem("named single method value"));
+    }    
+    
+    @Test
+    public void shouldReturnNothingIfTheNamedDataPointsAreMissing() throws Throwable {
+        SpecificDataPointsSupplier supplier = new SpecificDataPointsSupplier(new TestClass(TestClassWithNamedDataPoints.class));
+
+        List<PotentialAssignment> assignments = supplier.getValueSources(signature("methodWantingWrongNamedString"));
+        List<String> assignedStrings = getStringValuesFromAssignments(assignments);
+
+        assertEquals(0, assignedStrings.size());
+    }
+
+    private List<String> getStringValuesFromAssignments(List<PotentialAssignment> assignments) throws CouldNotGenerateValueException {
+        List<String> stringValues = new ArrayList<String>();
+        for (PotentialAssignment assignment : assignments) {
+            stringValues.add((String) assignment.getValue());
+        }
+        return stringValues;
+    }
+
+    private ParameterSignature signature(String methodName) throws Exception {
+        return ParameterSignature.signatures(this.getClass().getMethod(methodName, String.class)).get(0);
+    }
+
+    public void methodWantingAnyString(String input) {
+    }
+
+    public void methodWantingNamedFieldString(@FromDataPoints("field") String input) {
+    }
+    
+    public void methodWantingNamedMethodString(@FromDataPoints("method") String input) {
+    }
+    
+    public void methodWantingNamedSingleFieldString(@FromDataPoints("single") String input) {
+    }
+    
+    public void methodWantingNamedSingleMethodString(@FromDataPoints("singlemethod") String input) {
+    }
+    
+    public void methodWantingAllNamedStrings(@FromDataPoints("named") String input) {
+    }
+
+    public void methodWantingWrongNamedString(@FromDataPoints("invalid name") String input) {
+    }
+
+}
diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/FailingDataPointMethods.java b/src/test/java/org/junit/tests/experimental/theories/runner/FailingDataPointMethods.java
new file mode 100644
index 0000000..5abc0ea
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/theories/runner/FailingDataPointMethods.java
@@ -0,0 +1,136 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+public class FailingDataPointMethods {
+    
+    @RunWith(Theories.class)
+    public static class HasFailingSingleDataPointMethod {
+        @DataPoint
+        public static int num = 10;
+
+        @DataPoint
+        public static int failingDataPoint() {
+            throw new RuntimeException();
+        }
+
+        @Theory
+        public void theory(int x) {
+        }
+    }
+
+    @Test
+    public void shouldFailFromExceptionsInSingleDataPointMethods() {
+        assertThat(testResult(HasWronglyIgnoredFailingSingleDataPointMethod.class), not(isSuccessful()));
+    }
+    
+    @RunWith(Theories.class)
+    public static class HasFailingDataPointArrayMethod {
+        @DataPoints
+        public static int[] num = { 1, 2, 3 };
+
+        @DataPoints
+        public static int[] failingDataPoints() {
+            throw new RuntimeException();
+        }
+
+        @Theory
+        public void theory(int x) {
+        }
+    }
+
+    @Test
+    public void shouldFailFromExceptionsInDataPointArrayMethods() {
+        assertThat(testResult(HasFailingDataPointArrayMethod.class), not(isSuccessful()));
+    }
+    
+    @RunWith(Theories.class)
+    public static class HasIgnoredFailingSingleDataPointMethod {
+        @DataPoint
+        public static int num = 10;
+
+        @DataPoint(ignoredExceptions=Throwable.class)
+        public static int failingDataPoint() {
+            throw new RuntimeException();
+        }
+
+        @Theory
+        public void theory(int x) {
+        }
+    }
+    
+    @Test
+    public void shouldIgnoreSingleDataPointMethodExceptionsOnRequest() {
+        assertThat(testResult(HasIgnoredFailingSingleDataPointMethod.class), isSuccessful());
+    }
+    
+    @RunWith(Theories.class)
+    public static class HasIgnoredFailingMultipleDataPointMethod {
+        @DataPoint
+        public static int num = 10;
+
+        @DataPoints(ignoredExceptions=Throwable.class)
+        public static int[] failingDataPoint() {
+            throw new RuntimeException();
+        }
+
+        @Theory
+        public void theory(int x) {
+        }
+    }
+    
+    @Test
+    public void shouldIgnoreMultipleDataPointMethodExceptionsOnRequest() {
+        assertThat(testResult(HasIgnoredFailingMultipleDataPointMethod.class), isSuccessful());
+    }
+    
+    @RunWith(Theories.class)
+    public static class HasWronglyIgnoredFailingSingleDataPointMethod {
+        @DataPoint
+        public static int num = 10;
+
+        @DataPoint(ignoredExceptions=NullPointerException.class)
+        public static int failingDataPoint() {
+            throw new RuntimeException();
+        }
+
+        @Theory
+        public void theory(int x) {
+        }
+    }    
+    
+    @Test
+    public void shouldNotIgnoreNonMatchingSingleDataPointExceptions() {
+        assertThat(testResult(HasWronglyIgnoredFailingSingleDataPointMethod.class), not(isSuccessful()));
+    }
+    
+    @RunWith(Theories.class)
+    public static class HasWronglyIgnoredFailingMultipleDataPointMethod {
+        @DataPoint
+        public static int num = 10;
+
+        @DataPoint(ignoredExceptions=NullPointerException.class)
+        public static int failingDataPoint() {
+            throw new RuntimeException();
+        }
+
+        @Theory
+        public void theory(int x) {
+        }
+    }    
+    
+    @Test
+    public void shouldNotIgnoreNonMatchingMultipleDataPointExceptions() {
+        assertThat(testResult(HasWronglyIgnoredFailingMultipleDataPointMethod.class), not(isSuccessful()));
+    }
+    
+}
diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java b/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java
index fddb09b..e752d14 100644
--- a/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java
+++ b/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java
@@ -3,7 +3,6 @@
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.experimental.results.PrintableResult.testResult;
 import static org.junit.experimental.results.ResultMatchers.failureCountIs;
diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithAutoGeneratedDataPoints.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithAutoGeneratedDataPoints.java
new file mode 100644
index 0000000..26eb515
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithAutoGeneratedDataPoints.java
@@ -0,0 +1,71 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.tests.experimental.theories.TheoryTestUtils.potentialAssignments;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.runner.RunWith;
+
+public class WithAutoGeneratedDataPoints {
+
+    private enum ENUM { VALUE, OTHER_VALUE, THIRD_VALUE };
+    
+    @RunWith(Theories.class)
+    public static class TheoryTestClassWithAutogeneratedParameterValues {
+        
+        public void theory(ENUM e) {
+        }
+        
+        public void theory(boolean b) {
+        }
+        
+    }
+    
+    @Test
+    public void shouldAutomaticallyGenerateEnumDataPoints() throws Throwable {
+        assertEquals(ENUM.values().length, potentialAssignments(
+                TheoryTestClassWithAutogeneratedParameterValues.class.getMethod("theory", ENUM.class)).size());
+    }
+    
+    @Test
+    public void shouldAutomaticallyGenerateBooleanDataPoints() throws Throwable {
+        assertEquals(2, potentialAssignments(
+                TheoryTestClassWithAutogeneratedParameterValues.class.getMethod("theory", boolean.class)).size());
+    }
+    
+    @RunWith(Theories.class)
+    public static class TheoryTestClassWithSpecificEnumDataPoint {
+        
+        @DataPoint
+        public static ENUM value = ENUM.OTHER_VALUE;
+        
+        public void theory(ENUM e) {
+        }
+        
+    }
+    
+    @Test
+    public void shouldNotAutogenerateEnumDataPointsWhenSpecificDataPointGiven() throws Throwable {
+        assertEquals(1, potentialAssignments(
+                TheoryTestClassWithSpecificEnumDataPoint.class.getMethod("theory", ENUM.class)).size());
+    }
+    
+    @RunWith(Theories.class)
+    public static class TheoryTestClassWithSpecificBooleanDataPoint {
+        
+        @DataPoint
+        public static boolean value = true;
+        
+        public void theory(boolean b) {
+        }
+        
+    }
+    
+    @Test
+    public void shouldNotAutogenerateBooleanDataPointsWhenSpecificDataPointGiven() throws Throwable {
+        assertEquals(1, potentialAssignments(
+                TheoryTestClassWithSpecificBooleanDataPoint.class.getMethod("theory", boolean.class)).size());
+    }    
+    
+}
diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java
index 2089287..c814508 100644
--- a/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java
+++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java
@@ -8,8 +8,8 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.experimental.results.PrintableResult.testResult;
 import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.tests.experimental.theories.TheoryTestUtils.potentialAssignments;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -17,14 +17,11 @@
 import org.hamcrest.Matcher;
 import org.junit.Test;
 import org.junit.experimental.theories.DataPoint;
-import org.junit.experimental.theories.PotentialAssignment;
 import org.junit.experimental.theories.Theories;
 import org.junit.experimental.theories.Theory;
-import org.junit.experimental.theories.internal.Assignments;
 import org.junit.runner.JUnitCore;
 import org.junit.runner.RunWith;
 import org.junit.runner.notification.Failure;
-import org.junit.runners.model.TestClass;
 
 public class WithDataPointMethod {
     @RunWith(Theories.class)
@@ -36,25 +33,6 @@
 
         @Theory
         public void allIntsOk(int x) {
-
-        }
-    }
-
-    @RunWith(Theories.class)
-    public static class HasUglyDataPointMethod {
-        @DataPoint
-        public static int oneHundred() {
-            return 100;
-        }
-
-        @DataPoint
-        public static int oneUglyHundred() {
-            throw new RuntimeException();
-        }
-
-        @Theory
-        public void allIntsOk(int x) {
-
         }
     }
 
@@ -63,11 +41,6 @@
         assertThat(testResult(HasDataPointMethod.class), isSuccessful());
     }
 
-    @Test
-    public void ignoreExceptionsFromDataPointMethods() {
-        assertThat(testResult(HasUglyDataPointMethod.class), isSuccessful());
-    }
-
     @RunWith(Theories.class)
     public static class DataPointMethodReturnsMutableObject {
         @DataPoint
@@ -96,51 +69,41 @@
     @RunWith(Theories.class)
     public static class HasDateMethod {
         @DataPoint
-        public int oneHundred() {
+        public static int oneHundred() {
             return 100;
         }
 
-        public Date notADataPoint() {
+        public static Date notADataPoint() {
             return new Date();
         }
 
         @Theory
         public void allIntsOk(int x) {
-
         }
 
         @Theory
         public void onlyStringsOk(String s) {
-
         }
 
         @Theory
         public void onlyDatesOk(Date d) {
-
         }
     }
 
     @Test
-    public void ignoreDataPointMethodsWithWrongTypes() throws Exception {
-        assertThat(potentialValues(
+    public void ignoreDataPointMethodsWithWrongTypes() throws Throwable {
+        assertThat(potentialAssignments(
                 HasDateMethod.class.getMethod("onlyStringsOk", String.class))
                 .toString(), not(containsString("100")));
     }
 
     @Test
     public void ignoreDataPointMethodsWithoutAnnotation() throws Throwable {
-        assertThat(potentialValues(
+        assertThat(potentialAssignments(
                 HasDateMethod.class.getMethod("onlyDatesOk", Date.class))
                 .size(), is(0));
     }
 
-    private List<PotentialAssignment> potentialValues(Method method)
-            throws Exception {
-        return Assignments.allUnassigned(method,
-                new TestClass(HasDateMethod.class))
-                .potentialsForNextUnassigned();
-    }
-
     private List<Failure> failures(Class<?> type) {
         return JUnitCore.runClasses(type).getFailures();
     }
diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java
index e44d91a..bcda189 100644
--- a/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java
+++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java
@@ -1,6 +1,7 @@
 package org.junit.tests.experimental.theories.runner;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.junit.Assert.assertThat;
 import static org.junit.experimental.results.PrintableResult.testResult;
@@ -33,12 +34,13 @@
     }
 
     @RunWith(Theories.class)
-    public static class ShouldFilterNull {
-        @DataPoint
-        public static String NULL = null;
+    public static class ShouldFilterOutNullSingleDataPoints {
 
         @DataPoint
         public static String A = "a";
+        
+        @DataPoint
+        public static String NULL = null;
 
         @Theory(nullsAccepted = false)
         public void allStringsAreNonNull(String s) {
@@ -47,11 +49,42 @@
     }
 
     @Test
-    public void shouldFilterNull() {
-        assertThat(testResult(ShouldFilterNull.class), isSuccessful());
+    public void shouldFilterOutNullSingleDataPoints() {
+        assertThat(testResult(ShouldFilterOutNullSingleDataPoints.class), isSuccessful());
     }
 
     @RunWith(Theories.class)
+    public static class ShouldFilterOutNullElementsFromDataPointArrays {
+        @DataPoints
+        public static String[] SOME_NULLS = { "non-null", null };
+
+        @Theory(nullsAccepted = false)
+        public void allStringsAreNonNull(String s) {
+            assertThat(s, notNullValue());
+        }
+    }
+
+    @Test
+    public void shouldFilterOutNullElementsFromDataPointArrays() {
+        assertThat(testResult(ShouldFilterOutNullElementsFromDataPointArrays.class), isSuccessful());
+    }
+    
+    @RunWith(Theories.class)
+    public static class ShouldRejectTheoriesWithOnlyDisallowedNullData {
+        @DataPoints
+        public static String value = null;
+
+        @Theory(nullsAccepted = false)
+        public void allStringsAreNonNull(String s) {
+        }
+    }
+
+    @Test
+    public void ShouldRejectTheoriesWithOnlyDisallowedNullData() {
+        assertThat(testResult(ShouldRejectTheoriesWithOnlyDisallowedNullData.class), not(isSuccessful()));
+    }    
+
+    @RunWith(Theories.class)
     public static class DataPointArrays {
         public static String log = "";
 
diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithNamedDataPoints.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithNamedDataPoints.java
new file mode 100644
index 0000000..249ef10
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithNamedDataPoints.java
@@ -0,0 +1,73 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.tests.experimental.theories.TheoryTestUtils.potentialAssignments;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.FromDataPoints;
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+public class WithNamedDataPoints {
+
+    @RunWith(Theories.class)
+    public static class HasSpecificDatapointsParameters {
+        
+        @DataPoints
+        public static String[] badStrings = new String[] { "bad" };
+        
+        @DataPoint
+        public static String badString = "also bad";
+        
+        @DataPoints("named")
+        public static String[] goodStrings = new String[] { "expected", "also expected" };
+        
+        @DataPoint("named")
+        public static String goodString = "expected single value";
+        
+        @DataPoints("named")
+        public static String[] methodStrings() {
+            return new String[] { "expected method value" };
+        }
+        
+        @DataPoint("named")
+        public static String methodString() {
+            return "expected single method string";
+        }
+        
+        @DataPoints
+        public static String[] otherMethod() {
+            return new String[] { "other method value" };
+        }
+        
+        @DataPoint
+        public static String otherSingleValueMethod() {
+            return "other single value string";
+        }
+        
+        @Theory
+        public void theory(@FromDataPoints("named") String param) {
+        }
+        
+    }
+    
+    @Test
+    public void onlyUseSpecificDataPointsIfSpecified() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(HasSpecificDatapointsParameters.class
+                .getMethod("theory", String.class));
+        
+        assertEquals(5, assignments.size());
+        for (PotentialAssignment assignment : assignments) {
+            assertThat((String) assignment.getValue(), containsString("expected"));
+        }
+    }
+    
+}
diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithParameterSupplier.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithParameterSupplier.java
new file mode 100644
index 0000000..1802390
--- /dev/null
+++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithParameterSupplier.java
@@ -0,0 +1,165 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.tests.experimental.theories.TheoryTestUtils.potentialAssignments;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.ParameterSupplier;
+import org.junit.experimental.theories.ParametersSuppliedBy;
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.TestClass;
+
+public class WithParameterSupplier {
+    
+    @Rule
+    public ExpectedException expected = ExpectedException.none();
+
+    private static class SimplePotentialAssignment extends PotentialAssignment {
+        private String description;
+        private Object value;
+
+        public SimplePotentialAssignment(Object value, String description) {
+            this.value = value;
+            this.description = description;
+        }
+
+        @Override
+        public Object getValue() throws CouldNotGenerateValueException {
+            return value;
+        }
+
+        @Override
+        public String getDescription() throws CouldNotGenerateValueException {
+            return description;
+        }
+    }
+
+    private static final List<String> DATAPOINTS = Arrays.asList("qwe", "asd");
+
+    public static class SimpleSupplier extends ParameterSupplier {
+
+        @Override
+        public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+            List<PotentialAssignment> assignments = new ArrayList<PotentialAssignment>();
+
+            for (String datapoint : DATAPOINTS) {
+                assignments.add(new SimplePotentialAssignment(datapoint,
+                        datapoint));
+            }
+
+            return assignments;
+        }
+
+    }
+
+    @RunWith(Theories.class)
+    public static class TestClassUsingParameterSupplier {
+
+        @Theory
+        public void theoryMethod(@ParametersSuppliedBy(SimpleSupplier.class) String param) {
+        }
+
+    }
+
+    @Test
+    public void shouldPickUpDataPointsFromParameterSupplier() throws Throwable {
+        List<PotentialAssignment> assignments = potentialAssignments(TestClassUsingParameterSupplier.class
+                .getMethod("theoryMethod", String.class));
+
+        assertEquals(2, assignments.size());
+        assertEquals(DATAPOINTS.get(0), assignments.get(0).getValue());
+        assertEquals(DATAPOINTS.get(1), assignments.get(1).getValue());
+    }
+    
+    public static class SupplierWithUnknownConstructor extends ParameterSupplier {
+        
+        public SupplierWithUnknownConstructor(String param) {
+        }
+
+        @Override
+        public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+            return null;
+        }
+
+    }
+
+    @RunWith(Theories.class)
+    public static class TestClassUsingSupplierWithUnknownConstructor {
+
+        @Theory
+        public void theory(@ParametersSuppliedBy(SupplierWithUnknownConstructor.class) String param) {
+        }
+
+    }
+    
+    @Test
+    public void shouldRejectSuppliersWithUnknownConstructors() throws Exception {
+        expected.expect(InitializationError.class);
+        new Theories(TestClassUsingSupplierWithUnknownConstructor.class);
+    }
+    
+    public static class SupplierWithTwoConstructors extends ParameterSupplier {
+        
+        public SupplierWithTwoConstructors(String param) {
+        }
+
+        @Override
+        public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+            return null;
+        }
+
+    }
+
+    @RunWith(Theories.class)
+    public static class TestClassUsingSupplierWithTwoConstructors {
+
+        @Theory
+        public void theory(@ParametersSuppliedBy(SupplierWithTwoConstructors.class) String param) {
+        }
+
+    }
+    
+    @Test
+    public void shouldRejectSuppliersWithTwoConstructors() throws Exception {
+        expected.expect(InitializationError.class);
+        new Theories(TestClassUsingSupplierWithTwoConstructors.class);
+    }
+    
+    public static class SupplierWithTestClassConstructor extends ParameterSupplier {
+        
+        public SupplierWithTestClassConstructor(TestClass param) {
+        }
+
+        @Override
+        public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+            return null;
+        }
+
+    }
+
+    @RunWith(Theories.class)
+    public static class TestClassUsingSupplierWithTestClassConstructor {
+
+        @Theory
+        public void theory(@ParametersSuppliedBy(SupplierWithTestClassConstructor.class) String param) {
+        }
+
+    }
+    
+    @Test
+    public void shouldAcceptSuppliersWithTestClassConstructor() throws Exception {
+        new Theories(TestClassUsingSupplierWithTestClassConstructor.class);
+    }
+
+}
diff --git a/src/test/java/org/junit/tests/internal/runners/ErrorReportingRunnerTest.java b/src/test/java/org/junit/tests/internal/runners/ErrorReportingRunnerTest.java
new file mode 100644
index 0000000..56b5e31
--- /dev/null
+++ b/src/test/java/org/junit/tests/internal/runners/ErrorReportingRunnerTest.java
@@ -0,0 +1,28 @@
+package org.junit.tests.internal.runners;
+
+import org.junit.Test;
+import org.junit.internal.runners.ErrorReportingRunner;
+
+public class ErrorReportingRunnerTest {
+    
+    @Test(expected = NullPointerException.class)
+    public void cannotCreateWithNullClass() {
+        new ErrorReportingRunner(null, new RuntimeException());
+    }
+    
+    @Test(expected = NullPointerException.class)
+    public void cannotCreateWithNullClass2() {
+        new ErrorReportingRunner(new RuntimeException(), (Class<?>) null);
+    }
+    
+    @Test(expected = NullPointerException.class)
+    public void cannotCreateWithNullClasses() {
+        new ErrorReportingRunner(new RuntimeException(), (Class<?>[]) null);
+    }
+    
+    @Test(expected = NullPointerException.class)
+    public void cannotCreateWithoutClass() {
+        new ErrorReportingRunner(new RuntimeException());
+    }
+    
+}
diff --git a/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java b/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java
index 2a3f648..055ef08 100644
--- a/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java
+++ b/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java
@@ -4,35 +4,47 @@
 import static java.lang.Math.atan;
 import static java.lang.System.currentTimeMillis;
 import static java.lang.Thread.sleep;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.internal.runners.statements.FailOnTimeout.builder;
+
+import java.util.concurrent.TimeUnit;
 
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.internal.runners.statements.FailOnTimeout;
 import org.junit.rules.ExpectedException;
 import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestTimedOutException;
 
 /**
  * @author Asaf Ary, Stefan Birkner
  */
 public class FailOnTimeoutTest {
-    private static final int TIMEOUT = 100;
+    private static final long TIMEOUT = 100;
+    private static final long DURATION_THAT_EXCEEDS_TIMEOUT = 60 * 60 * 1000; //1 hour
 
     @Rule
     public final ExpectedException thrown = ExpectedException.none();
 
     private final TestStatement statement = new TestStatement();
 
-    private final FailOnTimeout failOnTimeout = new FailOnTimeout(statement,
-            TIMEOUT);
+    private final FailOnTimeout failOnTimeout = builder().withTimeout(TIMEOUT, MILLISECONDS).build(statement);
+
+    @Test
+    public void throwsTestTimedOutException() throws Throwable {
+        thrown.expect(TestTimedOutException.class);
+        evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT);
+    }
 
     @Test
     public void throwExceptionWithNiceMessageOnTimeout() throws Throwable {
         thrown.expectMessage("test timed out after 100 milliseconds");
-        evaluateWithWaitDuration(TIMEOUT + 50);
+        evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT);
     }
 
     @Test
@@ -45,9 +57,9 @@
     @Test
     public void throwExceptionIfTheSecondCallToEvaluateNeedsTooMuchTime()
             throws Throwable {
-        thrown.expect(Exception.class);
+        thrown.expect(TestTimedOutException.class);
         evaluateWithWaitDuration(0);
-        evaluateWithWaitDuration(TIMEOUT + 50);
+        evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT);
     }
 
     @Test
@@ -58,7 +70,19 @@
             evaluateWithException(new RuntimeException());
         } catch (Throwable expected) {
         }
-        evaluateWithWaitDuration(TIMEOUT + 50);
+        evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT);
+    }
+
+    @Test
+    public void throwsExceptionWithTimeoutValueAndTimeUnitSet()
+            throws Throwable {
+        try {
+            evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT);
+            fail("No exception was thrown when test timed out");
+        } catch (TestTimedOutException e) {
+            assertEquals(TIMEOUT, e.getTimeout());
+            assertEquals(TimeUnit.MILLISECONDS, e.getTimeUnit());
+        }
     }
 
     private void evaluateWithException(Exception exception) throws Throwable {
@@ -67,14 +91,14 @@
         failOnTimeout.evaluate();
     }
 
-    private void evaluateWithWaitDuration(int waitDuration) throws Throwable {
+    private void evaluateWithWaitDuration(long waitDuration) throws Throwable {
         statement.nextException = null;
         statement.waitDuration = waitDuration;
         failOnTimeout.evaluate();
     }
 
     private static final class TestStatement extends Statement {
-        int waitDuration;
+        long waitDuration;
 
         Exception nextException;
 
@@ -90,8 +114,7 @@
     @Test
     public void stopEndlessStatement() throws Throwable {
         InfiniteLoopStatement infiniteLoop = new InfiniteLoopStatement();
-        FailOnTimeout infiniteLoopTimeout = new FailOnTimeout(infiniteLoop,
-                TIMEOUT);
+        FailOnTimeout infiniteLoopTimeout = builder().withTimeout(TIMEOUT, MILLISECONDS).build(infiniteLoop);
         try {
             infiniteLoopTimeout.evaluate();
         } catch (Exception timeoutException) {
@@ -118,7 +141,7 @@
     @Test
     public void stackTraceContainsRealCauseOfTimeout() throws Throwable {
         StuckStatement stuck = new StuckStatement();
-        FailOnTimeout stuckTimeout = new FailOnTimeout(stuck, TIMEOUT);
+        FailOnTimeout stuckTimeout = builder().withTimeout(TIMEOUT, MILLISECONDS).build(stuck);
         try {
             stuckTimeout.evaluate();
             // We must not get here, we expect a timeout exception
@@ -170,4 +193,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityTest.java b/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityTest.java
index bb1f2cd..34673e9 100644
--- a/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityTest.java
+++ b/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityTest.java
@@ -79,18 +79,18 @@
         result.addListener(new TestListener() {
 
             public void startTest(junit.framework.Test test) {
-                log.append(" start " + test);
+                log.append(" start ").append(test);
             }
 
             public void endTest(junit.framework.Test test) {
-                log.append(" end " + test);
+                log.append(" end ").append(test);
             }
 
             public void addFailure(junit.framework.Test test, AssertionFailedError t) {
-                log.append(" failure " + test);
+                log.append(" failure ").append(test);
             }
 
-            public void addError(junit.framework.Test test, Throwable t) {
+            public void addError(junit.framework.Test test, Throwable e) {
                 log.append(" error " + test);
             }
         });
diff --git a/src/test/java/org/junit/tests/junit3compatibility/InitializationErrorForwardCompatibilityTest.java b/src/test/java/org/junit/tests/junit3compatibility/InitializationErrorForwardCompatibilityTest.java
index c891ab9..ec49701 100644
--- a/src/test/java/org/junit/tests/junit3compatibility/InitializationErrorForwardCompatibilityTest.java
+++ b/src/test/java/org/junit/tests/junit3compatibility/InitializationErrorForwardCompatibilityTest.java
@@ -63,7 +63,7 @@
     private final class ErrorRememberingListener implements TestListener {
         private junit.framework.Test fError;
 
-        public void addError(junit.framework.Test test, Throwable t) {
+        public void addError(junit.framework.Test test, Throwable e) {
             fError = test;
         }
 
diff --git a/src/test/java/org/junit/tests/junit3compatibility/JUnit38ClassRunnerTest.java b/src/test/java/org/junit/tests/junit3compatibility/JUnit38ClassRunnerTest.java
index 19e50fa..b7a1c51 100644
--- a/src/test/java/org/junit/tests/junit3compatibility/JUnit38ClassRunnerTest.java
+++ b/src/test/java/org/junit/tests/junit3compatibility/JUnit38ClassRunnerTest.java
@@ -1,7 +1,13 @@
 package org.junit.tests.junit3compatibility;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import junit.extensions.TestDecorator;
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.TestCase;
@@ -14,6 +20,8 @@
 import org.junit.runner.Result;
 import org.junit.runner.notification.Failure;
 import org.junit.runner.notification.RunListener;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.NoTestsRemainException;
 
 public class JUnit38ClassRunnerTest {
     public static class MyTest extends TestCase {
@@ -83,4 +91,65 @@
         assertEquals("junit.framework.TestSuite$1", failure.getDescription().getClassName());
     }
 
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public static @interface MyAnnotation {
+    }
+
+    public static class JUnit3ClassWithAnnotatedMethod extends TestCase {
+        @MyAnnotation
+        public void testAnnotated() {
+        }
+
+        public void testNotAnnotated() {
+        }
+    }
+
+    public static class DerivedAnnotatedMethod extends JUnit3ClassWithAnnotatedMethod {
+    }
+
+    @Test
+    public void getDescriptionWithAnnotation() {
+        JUnit38ClassRunner runner = new JUnit38ClassRunner(JUnit3ClassWithAnnotatedMethod.class);
+        assertAnnotationFiltering(runner);
+    }
+    
+    @Test
+    public void getDescriptionWithAnnotationInSuper() {
+        JUnit38ClassRunner runner = new JUnit38ClassRunner(DerivedAnnotatedMethod.class);
+        assertAnnotationFiltering(runner);
+    }
+
+    private void assertAnnotationFiltering(JUnit38ClassRunner runner) {
+        Description d = runner.getDescription();
+        assertEquals(2, d.testCount());
+        for (Description methodDesc : d.getChildren()) {
+            if (methodDesc.getMethodName().equals("testAnnotated")) {
+                assertNotNull(methodDesc.getAnnotation(MyAnnotation.class));
+            } else {
+                assertNull(methodDesc.getAnnotation(MyAnnotation.class));
+            }
+        }
+    }
+
+    public static class RejectAllTestsFilter extends Filter {
+        @Override
+        public boolean shouldRun(Description description) {
+            return description.isSuite();
+        }
+
+        @Override
+        public String describe() {
+            return "filter all";
+        }
+    }
+
+    /**
+     * Test that NoTestsRemainException is thrown when all methods have been filtered.
+     */
+    @Test(expected = NoTestsRemainException.class) 
+    public void filterNoTestsRemain() throws NoTestsRemainException {
+        JUnit38ClassRunner runner = new JUnit38ClassRunner(OneTest.class);
+        runner.filter(new RejectAllTestsFilter());  
+    }
 }
diff --git a/src/test/java/org/junit/tests/junit3compatibility/SuiteMethodTest.java b/src/test/java/org/junit/tests/junit3compatibility/SuiteMethodTest.java
index 3d050d5..edc9eac 100644
--- a/src/test/java/org/junit/tests/junit3compatibility/SuiteMethodTest.java
+++ b/src/test/java/org/junit/tests/junit3compatibility/SuiteMethodTest.java
@@ -24,9 +24,9 @@
         }
 
         public static junit.framework.Test suite() {
-            TestSuite result = new TestSuite();
-            result.addTest(new OldTest("notObviouslyATest"));
-            return result;
+            TestSuite suite = new TestSuite();
+            suite.addTest(new OldTest("notObviouslyATest"));
+            return suite;
         }
 
         public void notObviouslyATest() {
diff --git a/src/test/java/org/junit/tests/running/classes/ClassLevelMethodsWithIgnoredTestsTest.java b/src/test/java/org/junit/tests/running/classes/ClassLevelMethodsWithIgnoredTestsTest.java
new file mode 100644
index 0000000..076988b
--- /dev/null
+++ b/src/test/java/org/junit/tests/running/classes/ClassLevelMethodsWithIgnoredTestsTest.java
@@ -0,0 +1,165 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Categories.CategoryFilter;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runners.model.Statement;
+
+/**
+ * Tests verifying that class-level fixtures ({@link BeforeClass} and
+ * {@link AfterClass}) and rules ({@link ClassRule}) are not executed when there
+ * are no test methods to be run in a test class because they have been ignored.
+ * 
+ */
+public class ClassLevelMethodsWithIgnoredTestsTest {
+    private static final String FAILURE_MESSAGE = "This should not have happened!";
+
+    public static class BeforeClassWithIgnoredTest {
+        @BeforeClass
+        public static void beforeClass() {
+            fail(FAILURE_MESSAGE);
+        }
+        
+        @Ignore
+        @Test
+        public void test() throws Exception {
+            fail("test() should not run");
+        }
+    }
+
+    @Test
+    public void beforeClassShouldNotRunWhenAllTestsAreIgnored() {
+        runClassAndVerifyNoFailures(BeforeClassWithIgnoredTest.class,
+                "BeforeClass should not have been executed because the test method is ignored!");
+    }
+
+    @Ignore
+    public static class BeforeClassWithIgnoredClass {
+        @BeforeClass
+        public static void beforeClass() {
+            fail(FAILURE_MESSAGE);
+        }
+
+        @Test
+        public void test() throws Exception {
+            fail("test() should not run");
+        }
+    }
+
+    @Test
+    public void beforeClassShouldNotRunWhenWholeClassIsIgnored() {
+        runClassAndVerifyNoFailures(
+                BeforeClassWithIgnoredClass.class,
+                "BeforeClass should not have been executed because the whole test class is ignored!");
+    }
+
+    public static class AfterClassWithIgnoredTest {
+        @Ignore
+        @Test
+        public void test() throws Exception {
+            fail("test() should not run");
+        }
+
+        @AfterClass
+        public static void afterClass() {
+            fail(FAILURE_MESSAGE);
+        }
+    }
+
+    @Test
+    public void afterClassShouldNotRunWhenAllTestsAreIgnored() {
+        runClassAndVerifyNoFailures(AfterClassWithIgnoredTest.class,
+                "AfterClass should not have been executed because the test method is ignored!");
+    }
+
+    public interface FilteredTests {
+    }
+
+    public static class BeforeClassWithFilteredTest {
+        @BeforeClass
+        public static void setUpClass() {
+            fail(FAILURE_MESSAGE);
+        }
+
+        @Category(FilteredTests.class)
+        @Test
+        public void test() throws Exception {
+            fail("test() should not run");
+        }
+    }
+
+    public static class HasUnfilteredTest {
+        @Test
+        public void unfilteredTest() {
+            // to prevent errors when all other tests have been filtered
+        }
+    }
+
+    @Test
+    public void beforeClassShouldNotRunWhenAllTestsAreFiltered() {
+        Result result = new JUnitCore().run(Request.classes(
+                BeforeClassWithFilteredTest.class, HasUnfilteredTest.class)
+                .filterWith(CategoryFilter.exclude(FilteredTests.class)));
+        analyseResult(
+                result,
+                "BeforeClass should not have been executed because the test method is filtered!");
+    }
+
+    public static class BrokenRule implements TestRule {
+        public Statement apply(Statement base, Description description) {
+            throw new RuntimeException("this rule is broken");
+        }
+    }
+
+    public static class ClassRuleWithIgnoredTest {
+        @ClassRule
+        public static BrokenRule brokenRule = new BrokenRule();
+
+        @Ignore
+        @Test
+        public void test() throws Exception {
+            fail("test() should not be run");
+        }
+    }
+
+    @Test
+    public void classRuleShouldNotBeAppliedWhenAllTestsAreIgnored() {
+        runClassAndVerifyNoFailures(ClassRuleWithIgnoredTest.class,
+                "The class rule should have been applied because the test method is ignored!");
+    }
+
+    private void runClassAndVerifyNoFailures(Class<?> klass,
+            String testFailureDescription) {
+        Result result = JUnitCore.runClasses(klass);
+        analyseResult(result, testFailureDescription);
+    }
+
+    private void analyseResult(Result result, String testFailureDescription) {
+        List<Failure> failures = result.getFailures();
+        if (failures.isEmpty() == false) {
+            analyzeFailure(failures.get(0), testFailureDescription);
+        }
+    }
+
+    private void analyzeFailure(Failure failure, String testFailureDescription) {
+        String actualFailureMsg = failure.getMessage();
+        if (FAILURE_MESSAGE.equals(actualFailureMsg)) {
+            fail(testFailureDescription);
+        }
+        fail("Unexpected failure : " + actualFailureMsg);
+    }
+}
diff --git a/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java b/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
index 5832eef..52ba09e 100644
--- a/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
+++ b/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
@@ -1,9 +1,11 @@
 package org.junit.tests.running.classes;
 
+import static java.util.Arrays.asList;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.junit.experimental.results.PrintableResult.testResult;
 
 import java.util.Arrays;
@@ -24,66 +26,89 @@
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
 import org.junit.runners.model.InitializationError;
+import org.junit.runners.parameterized.ParametersRunnerFactory;
+import org.junit.runners.parameterized.TestWithParameters;
 
 public class ParameterizedTestTest {
     @RunWith(Parameterized.class)
-    static public class FibonacciTest {
-        @Parameters(name = "{index}: fib({0})={1}")
+    public static class AdditionTest {
+        @Parameters(name = "{index}: {0} + {1} = {2}")
         public static Iterable<Object[]> data() {
-            return Arrays.asList(new Object[][]{{0, 0}, {1, 1}, {2, 1},
-                    {3, 2}, {4, 3}, {5, 5}, {6, 8}});
+            return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 },
+                    { 3, 2, 5 }, { 4, 3, 7 } });
         }
 
-        private final int fInput;
+        private int firstSummand;
 
-        private final int fExpected;
+        private int secondSummand;
 
-        public FibonacciTest(int input, int expected) {
-            fInput = input;
-            fExpected = expected;
+        private int sum;
+
+        public AdditionTest(int firstSummand, int secondSummand, int sum) {
+            this.firstSummand = firstSummand;
+            this.secondSummand = secondSummand;
+            this.sum = sum;
         }
 
         @Test
         public void test() {
-            assertEquals(fExpected, fib(fInput));
-        }
-
-        private int fib(int x) {
-            return 0;
+            assertEquals(sum, firstSummand + secondSummand);
         }
     }
 
     @Test
-    public void count() {
-        Result result = JUnitCore.runClasses(FibonacciTest.class);
-        assertEquals(7, result.getRunCount());
-        assertEquals(6, result.getFailureCount());
-    }
-
-    @Test
-    public void failuresNamedCorrectly() {
-        Result result = JUnitCore.runClasses(FibonacciTest.class);
-        assertEquals(
-                "test[1: fib(1)=1](" + FibonacciTest.class.getName() + ")",
-                result.getFailures().get(0).getTestHeader());
+    public void countsRuns() {
+        Result result = JUnitCore.runClasses(AdditionTest.class);
+        assertEquals(4, result.getRunCount());
     }
 
     @Test
     public void countBeforeRun() throws Exception {
-        Runner runner = Request.aClass(FibonacciTest.class).getRunner();
-        assertEquals(7, runner.testCount());
+        Runner runner = Request.aClass(AdditionTest.class).getRunner();
+        assertEquals(4, runner.testCount());
     }
 
     @Test
     public void plansNamedCorrectly() throws Exception {
-        Runner runner = Request.aClass(FibonacciTest.class).getRunner();
+        Runner runner = Request.aClass(AdditionTest.class).getRunner();
         Description description = runner.getDescription();
-        assertEquals("[0: fib(0)=0]", description.getChildren().get(0)
+        assertEquals("[2: 3 + 2 = 5]", description.getChildren().get(2)
                 .getDisplayName());
     }
 
     @RunWith(Parameterized.class)
+    public static class ThreeFailures {
+        @Parameters(name = "{index}: x={0}")
+        public static Collection<Integer> data() {
+            return Arrays.asList(1, 2, 3);
+        }
+
+        @Parameter(0)
+        public int unused;
+
+        @Test
+        public void testSomething() {
+            fail();
+        }
+    }
+
+    @Test
+    public void countsFailures() throws Exception {
+        Result result = JUnitCore.runClasses(ThreeFailures.class);
+        assertEquals(3, result.getFailureCount());
+    }
+
+    @Test
+    public void failuresNamedCorrectly() {
+        Result result = JUnitCore.runClasses(ThreeFailures.class);
+        assertEquals(
+                "testSomething[0: x=1](" + ThreeFailures.class.getName() + ")",
+                result.getFailures().get(0).getTestHeader());
+    }
+
+    @RunWith(Parameterized.class)
     public static class ParameterizedWithoutSpecialTestname {
         @Parameters
         public static Collection<Object[]> data() {
@@ -107,55 +132,33 @@
     }
 
     @RunWith(Parameterized.class)
-    static public class FibonacciWithParameterizedFieldTest {
-        @Parameters
-        public static Collection<Object[]> data() {
-            return Arrays.asList(new Object[][]{{0, 0}, {1, 1}, {2, 1},
-                    {3, 2}, {4, 3}, {5, 5}, {6, 8}});
+    public static class AdditionTestWithAnnotatedFields {
+        @Parameters(name = "{index}: {0} + {1} = {2}")
+        public static Iterable<Object[]> data() {
+            return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 },
+                    { 3, 2, 5 }, { 4, 3, 7 } });
         }
 
         @Parameter(0)
-        public int fInput;
+        public int firstSummand;
 
         @Parameter(1)
-        public int fExpected;
+        public int secondSummand;
+
+        @Parameter(2)
+        public int sum;
 
         @Test
         public void test() {
-            assertEquals(fExpected, fib(fInput));
-        }
-
-        private int fib(int x) {
-            return 0;
+            assertEquals(sum, firstSummand + secondSummand);
         }
     }
 
     @Test
-    public void countWithParameterizedField() {
-        Result result = JUnitCore.runClasses(FibonacciWithParameterizedFieldTest.class);
-        assertEquals(7, result.getRunCount());
-        assertEquals(6, result.getFailureCount());
-    }
-
-    @Test
-    public void failuresNamedCorrectlyWithParameterizedField() {
-        Result result = JUnitCore.runClasses(FibonacciWithParameterizedFieldTest.class);
-        assertEquals(String
-                .format("test[1](%s)", FibonacciWithParameterizedFieldTest.class.getName()), result
-                .getFailures().get(0).getTestHeader());
-    }
-
-    @Test
-    public void countBeforeRunWithParameterizedField() throws Exception {
-        Runner runner = Request.aClass(FibonacciWithParameterizedFieldTest.class).getRunner();
-        assertEquals(7, runner.testCount());
-    }
-
-    @Test
-    public void plansNamedCorrectlyWithParameterizedField() throws Exception {
-        Runner runner = Request.aClass(FibonacciWithParameterizedFieldTest.class).getRunner();
-        Description description = runner.getDescription();
-        assertEquals("[0]", description.getChildren().get(0).getDisplayName());
+    public void providesDataByAnnotatedFields() {
+        Result result = JUnitCore.runClasses(AdditionTestWithAnnotatedFields.class);
+        assertEquals(4, result.getRunCount());
+        assertEquals(0, result.getFailureCount());
     }
 
     @RunWith(Parameterized.class)
@@ -306,31 +309,10 @@
     }
 
     @Test
-    public void meaningfulFailureWhenParametersNotPublic() throws Exception {
-        Result result = JUnitCore.runClasses(ProtectedParametersTest.class);
-        String expected = String.format(
-                "No public static parameters method on class %s",
-                ProtectedParametersTest.class.getName());
-        assertEquals(expected, result.getFailures().get(0).getMessage());
-    }
-
-    @RunWith(Parameterized.class)
-    static public class WrongElementType {
-        @Parameters
-        public static Iterable<String> data() {
-            return Arrays.asList("a", "b", "c");
-        }
-
-        @Test
-        public void aTest() {
-        }
-    }
-
-    @Test
-    public void meaningfulFailureWhenParametersAreNotArrays() {
-        assertThat(
-                testResult(WrongElementType.class).toString(),
-                containsString("WrongElementType.data() must return an Iterable of arrays."));
+    public void meaningfulFailureWhenParametersNotPublic() {
+        assertTestCreatesSingleFailureWithMessage(ProtectedParametersTest.class,
+                "No public static parameters method on class "
+                        + ProtectedParametersTest.class.getName());
     }
 
     @RunWith(Parameterized.class)
@@ -372,4 +354,142 @@
     public void exceptionWhenPrivateConstructor() throws Throwable {
         new Parameterized(PrivateConstructor.class);
     }
+
+    @RunWith(Parameterized.class)
+    public static class AdditionTestWithArray {
+        @Parameters(name = "{index}: {0} + {1} = {2}")
+        public static Object[][] data() {
+            return new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, { 3, 2, 5 },
+                    { 4, 3, 7 } };
+        }
+
+        @Parameter(0)
+        public int firstSummand;
+
+        @Parameter(1)
+        public int secondSummand;
+
+        @Parameter(2)
+        public int sum;
+
+        @Test
+        public void test() {
+            assertEquals(sum, firstSummand + secondSummand);
+        }
+    }
+
+    @Test
+    public void runsEveryTestOfArray() {
+        Result result= JUnitCore.runClasses(AdditionTestWithArray.class);
+        assertEquals(4, result.getRunCount());
+    }
+
+    @RunWith(Parameterized.class)
+    static public class SingleArgumentTestWithArray {
+        @Parameters
+        public static Object[] data() {
+            return new Object[] { "first test", "second test" };
+        }
+
+        public SingleArgumentTestWithArray(Object argument) {
+        }
+
+        @Test
+        public void aTest() {
+        }
+    }
+
+    @Test
+    public void runsForEverySingleArgumentOfArray() {
+        Result result= JUnitCore.runClasses(SingleArgumentTestWithArray.class);
+        assertEquals(2, result.getRunCount());
+    }
+
+    @RunWith(Parameterized.class)
+    static public class SingleArgumentTestWithIterable {
+        @Parameters
+        public static Iterable<? extends Object> data() {
+            return asList("first test", "second test");
+        }
+
+        public SingleArgumentTestWithIterable(Object argument) {
+        }
+
+        @Test
+        public void aTest() {
+        }
+  	}
+
+    @Test
+    public void runsForEverySingleArgumentOfIterable() {
+        Result result= JUnitCore
+                .runClasses(SingleArgumentTestWithIterable.class);
+        assertEquals(2, result.getRunCount());
+    }
+
+    static public class ExceptionThrowingRunnerFactory implements
+            ParametersRunnerFactory {
+        public Runner createRunnerForTestWithParameters(TestWithParameters test)
+                throws InitializationError {
+            throw new InitializationError(
+                    "Called ExceptionThrowingRunnerFactory.");
+        }
+    }
+
+    @RunWith(Parameterized.class)
+    @UseParametersRunnerFactory(ExceptionThrowingRunnerFactory.class)
+    static public class TestWithUseParametersRunnerFactoryAnnotation {
+        @Parameters
+        public static Iterable<? extends Object> data() {
+            return asList("single test");
+        }
+
+        public TestWithUseParametersRunnerFactoryAnnotation(Object argument) {
+        }
+
+        @Test
+        public void aTest() {
+        }
+    }
+
+    @Test
+    public void usesParametersRunnerFactoryThatWasSpecifiedByAnnotation() {
+        assertTestCreatesSingleFailureWithMessage(
+                TestWithUseParametersRunnerFactoryAnnotation.class,
+                "Called ExceptionThrowingRunnerFactory.");
+    }
+
+    private void assertTestCreatesSingleFailureWithMessage(Class<?> test, String message) {
+        Result result = JUnitCore.runClasses(test);
+        assertEquals(1, result.getFailures().size());
+        assertEquals(message, result.getFailures().get(0).getMessage());
+    }
+    
+    @RunWith(Parameterized.class)
+    @UseParametersRunnerFactory(ExceptionThrowingRunnerFactory.class)
+    public static abstract class UseParameterizedFactoryAbstractTest {
+        @Parameters
+        public static Iterable<? extends Object> data() {
+            return asList("single test");
+        }
+    }
+    
+    public static class UseParameterizedFactoryTest extends
+            UseParameterizedFactoryAbstractTest {
+
+        public UseParameterizedFactoryTest(String parameter) {
+
+        }
+
+        @Test
+        public void parameterizedTest() {
+        }
+    }
+    
+    @Test
+    public void usesParametersRunnerFactoryThatWasSpecifiedByAnnotationInSuperClass() {
+        assertTestCreatesSingleFailureWithMessage(
+                UseParameterizedFactoryTest.class,
+                "Called ExceptionThrowingRunnerFactory.");
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java b/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java
index e02430d..8ec87a8 100644
--- a/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java
+++ b/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java
@@ -9,19 +9,25 @@
 
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.internal.AssumptionViolatedException;
 import org.junit.runner.Description;
 import org.junit.runner.JUnitCore;
 import org.junit.runner.Request;
 import org.junit.runner.Result;
 import org.junit.runner.manipulation.Filter;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
 import org.junit.runner.notification.RunNotifier;
 import org.junit.runners.BlockJUnit4ClassRunner;
 import org.junit.runners.ParentRunner;
 import org.junit.runners.model.InitializationError;
 import org.junit.runners.model.RunnerScheduler;
-import org.junit.tests.experimental.rules.RuleFieldValidatorTest.TestWithNonStaticClassRule;
-import org.junit.tests.experimental.rules.RuleFieldValidatorTest.TestWithProtectedClassRule;
+import org.junit.tests.experimental.rules.RuleMemberValidatorTest.TestWithNonStaticClassRule;
+import org.junit.tests.experimental.rules.RuleMemberValidatorTest.TestWithProtectedClassRule;
 
 public class ParentRunnerTest {
     public static String log = "";
@@ -84,7 +90,7 @@
     }
 
     private static class Exclude extends Filter {
-        private String methodName;
+        private final String methodName;
 
         public Exclude(String methodName) {
             this.methodName = methodName;
@@ -127,6 +133,18 @@
                 "The @ClassRule 'temporaryFolder' must be static.");
     }
 
+    static class NonPublicTestClass {
+        public NonPublicTestClass() {
+        }
+    }
+
+    @Test
+    public void cannotBeCreatedWithNonPublicTestClass() {
+        assertClassHasFailureMessage(
+                NonPublicTestClass.class,
+                "The class org.junit.tests.running.classes.ParentRunnerTest$NonPublicTestClass is not public.");
+    }
+
     private void assertClassHasFailureMessage(Class<?> klass, String message) {
         JUnitCore junitCore = new JUnitCore();
         Request request = Request.aClass(klass);
@@ -134,6 +152,118 @@
         assertThat(result.getFailureCount(), is(2)); //the second failure is no runnable methods
         assertThat(result.getFailures().get(0).getMessage(),
                 is(equalTo(message)));
+    }
 
+    public static class AssertionErrorAtParentLevelTest {
+        @BeforeClass
+        public static void beforeClass() throws Throwable {
+            throw new AssertionError("Thrown from @BeforeClass");
+        }
+
+        @Test
+        public void test() {}
+    }
+
+    @Test
+    public void assertionErrorAtParentLevelTest() throws InitializationError {
+        CountingRunListener countingRunListener = runTestWithParentRunner(AssertionErrorAtParentLevelTest.class);
+        Assert.assertEquals(0, countingRunListener.testStarted);
+        Assert.assertEquals(0, countingRunListener.testFinished);
+        Assert.assertEquals(1, countingRunListener.testFailure);
+        Assert.assertEquals(0, countingRunListener.testAssumptionFailure);
+        Assert.assertEquals(0, countingRunListener.testIgnored);
+    }
+
+    public static class AssumptionViolatedAtParentLevelTest {
+        @SuppressWarnings("deprecation")
+        @BeforeClass
+        public static void beforeClass() {
+            throw new AssumptionViolatedException("Thrown from @BeforeClass");
+        }
+
+        @Test
+        public void test() {}
+    }
+
+    @Test
+    public void assumptionViolatedAtParentLevel() throws InitializationError {
+        CountingRunListener countingRunListener = runTestWithParentRunner(AssumptionViolatedAtParentLevelTest.class);
+        Assert.assertEquals(0, countingRunListener.testStarted);
+        Assert.assertEquals(0, countingRunListener.testFinished);
+        Assert.assertEquals(0, countingRunListener.testFailure);
+        Assert.assertEquals(1, countingRunListener.testAssumptionFailure);
+        Assert.assertEquals(0, countingRunListener.testIgnored);
+    }
+
+    public static class TestTest {
+        @Test
+        public void pass() {}
+
+        @Test
+        public void fail() {
+            throw new AssertionError("Thrown from @Test");
+        }
+
+        @Ignore
+        @Test
+        public void ignore() {}
+
+        @SuppressWarnings("deprecation")
+        @Test
+        public void assumptionFail() {
+            throw new AssumptionViolatedException("Thrown from @Test");
+        }
+    }
+
+    @Test
+    public void parentRunnerTestMethods() throws InitializationError {
+        CountingRunListener countingRunListener = runTestWithParentRunner(TestTest.class);
+        Assert.assertEquals(3, countingRunListener.testStarted);
+        Assert.assertEquals(3, countingRunListener.testFinished);
+        Assert.assertEquals(1, countingRunListener.testFailure);
+        Assert.assertEquals(1, countingRunListener.testAssumptionFailure);
+        Assert.assertEquals(1, countingRunListener.testIgnored);
+    }
+
+    private CountingRunListener runTestWithParentRunner(Class<?> testClass) throws InitializationError {
+        CountingRunListener listener = new CountingRunListener();
+        RunNotifier runNotifier = new RunNotifier();
+        runNotifier.addListener(listener);
+        ParentRunner<?> runner = new BlockJUnit4ClassRunner(testClass);
+        runner.run(runNotifier);
+        return listener;
+    }
+
+    private static class CountingRunListener extends RunListener {
+        private int testStarted = 0;
+        private int testFinished = 0;
+        private int testFailure = 0;
+        private int testAssumptionFailure = 0;
+        private int testIgnored = 0;
+
+        @Override
+        public void testStarted(Description description) throws Exception {
+            testStarted++;
+        }
+
+        @Override
+        public void testFinished(Description description) throws Exception {
+            testFinished++;
+        }
+
+        @Override
+        public void testFailure(Failure failure) throws Exception {
+            testFailure++;
+        }
+
+        @Override
+        public void testAssumptionFailure(Failure failure) {
+            testAssumptionFailure++;
+        }
+
+        @Override
+        public void testIgnored(Description description) throws Exception {
+            testIgnored++;
+        }
     }
 }
diff --git a/src/test/java/org/junit/tests/running/classes/TestClassTest.java b/src/test/java/org/junit/tests/running/classes/TestClassTest.java
deleted file mode 100644
index ff0ac9d..0000000
--- a/src/test/java/org/junit/tests/running/classes/TestClassTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package org.junit.tests.running.classes;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestRule;
-import org.junit.runners.model.TestClass;
-
-public class TestClassTest {
-    public static class TwoConstructors {
-        public TwoConstructors() {
-        }
-
-        public TwoConstructors(int x) {
-        }
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void complainIfMultipleConstructors() {
-        new TestClass(TwoConstructors.class);
-    }
-
-    public static class ManyMethods {
-        @Test
-        public void a() {
-        }
-
-        @Before
-        public void b() {
-        }
-
-        @Ignore
-        @Test
-        public void c() {
-        }
-
-        @Ignore
-        @After
-        public void d() {
-        }
-
-        public void e() {
-        }
-
-        @BeforeClass
-        public void f() {
-        }
-
-        public void g() {
-        }
-
-        @AfterClass
-        public void h() {
-        }
-
-        @Test
-        public void i() {
-        }
-
-        @Test
-        public void j() {
-        }
-    }
-
-    public static class SuperclassWithField {
-        @Rule
-        public TestRule x;
-    }
-
-    public static class SubclassWithField extends SuperclassWithField {
-        @Rule
-        public TestRule x;
-    }
-
-    @Test
-    public void fieldsOnSubclassesShadowSuperclasses() {
-        assertThat(new TestClass(SubclassWithField.class).getAnnotatedFields(
-                Rule.class).size(), is(1));
-    }
-
-    public static class OuterClass {
-        public class NonStaticInnerClass {
-        }
-    }
-
-    @Test
-    public void identifyNonStaticInnerClass() {
-        assertThat(
-                new TestClass(OuterClass.NonStaticInnerClass.class)
-                        .isANonStaticInnerClass(),
-                is(true));
-    }
-
-    public static class OuterClass2 {
-        public static class StaticInnerClass {
-        }
-    }
-
-    @Test
-    public void dontMarkStaticInnerClassAsNonStatic() {
-        assertThat(
-                new TestClass(OuterClass2.StaticInnerClass.class)
-                        .isANonStaticInnerClass(),
-                is(false));
-    }
-
-    public static class SimpleClass {
-    }
-
-    @Test
-    public void dontMarkNonInnerClassAsInnerClass() {
-        assertThat(new TestClass(SimpleClass.class).isANonStaticInnerClass(),
-                is(false));
-    }
-}
diff --git a/src/test/java/org/junit/tests/running/core/MainRunner.java b/src/test/java/org/junit/tests/running/core/MainRunner.java
index 317a23c..3068e14 100644
--- a/src/test/java/org/junit/tests/running/core/MainRunner.java
+++ b/src/test/java/org/junit/tests/running/core/MainRunner.java
@@ -39,6 +39,7 @@
             throw new ExitException(status);
         }
 
+        @SuppressWarnings("deprecation")
         @Override
         public boolean getInCheck() {
             return (originalSecurityManager != null) && originalSecurityManager.getInCheck();
@@ -175,6 +176,7 @@
             }
         }
 
+        @SuppressWarnings("deprecation")
         @Override
         public void checkMulticast(InetAddress maddr, byte ttl) {
             if (originalSecurityManager != null) {
@@ -273,7 +275,7 @@
     public Integer runWithCheckForSystemExit(Runnable runnable) {
         SecurityManager oldSecurityManager = System.getSecurityManager();
         System.setSecurityManager(new NoExitSecurityManager(oldSecurityManager));
-        PrintStream oldPrintStream = System.out;
+        PrintStream oldOut = System.out;
 
         System.setOut(new PrintStream(new ByteArrayOutputStream()));
         try {
@@ -285,7 +287,7 @@
             return e.getStatus();
         } finally {
             System.setSecurityManager(oldSecurityManager);
-            System.setOut(oldPrintStream);
+            System.setOut(oldOut);
         }
     }
 }
diff --git a/src/test/java/org/junit/tests/running/methods/TimeoutTest.java b/src/test/java/org/junit/tests/running/methods/TimeoutTest.java
index 2eccada..8d23909 100644
--- a/src/test/java/org/junit/tests/running/methods/TimeoutTest.java
+++ b/src/test/java/org/junit/tests/running/methods/TimeoutTest.java
@@ -1,6 +1,7 @@
 package org.junit.tests.running.methods;
 
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
@@ -10,18 +11,22 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.io.Writer;
+import java.util.concurrent.TimeUnit;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.TestResult;
 import org.junit.After;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 import org.junit.runner.JUnitCore;
 import org.junit.runner.Result;
 
 public class TimeoutTest {
 
-    static public class FailureWithTimeoutTest {
+    public static class FailureWithTimeoutTest {
         @Test(timeout = 1000)
         public void failure() {
             fail();
@@ -37,7 +42,7 @@
         assertEquals(AssertionError.class, result.getFailures().get(0).getException().getClass());
     }
 
-    static public class FailureWithTimeoutRunTimeExceptionTest {
+    public static class FailureWithTimeoutRunTimeExceptionTest {
         @Test(timeout = 1000)
         public void failure() {
             throw new NullPointerException();
@@ -53,7 +58,7 @@
         assertEquals(NullPointerException.class, result.getFailures().get(0).getException().getClass());
     }
 
-    static public class SuccessWithTimeoutTest {
+    public static class SuccessWithTimeoutTest {
         @Test(timeout = 1000)
         public void success() {
         }
@@ -67,7 +72,7 @@
         assertEquals(0, result.getFailureCount());
     }
 
-    static public class TimeoutFailureTest {
+    public static class TimeoutFailureTest {
         @Test(timeout = 100)
         public void success() throws InterruptedException {
             Thread.sleep(40000);
@@ -84,7 +89,7 @@
         assertEquals(InterruptedException.class, result.getFailures().get(0).getException().getClass());
     }
 
-    static public class InfiniteLoopTest {
+    public static class InfiniteLoopTest {
         @Test(timeout = 100)
         public void failure() {
             infiniteLoop();
@@ -110,7 +115,7 @@
         assertTrue(exception.getMessage().contains("test timed out after 100 milliseconds"));
     }
 
-    static public class ImpatientLoopTest {
+    public static class ImpatientLoopTest {
         @Test(timeout = 1)
         public void failure() {
             infiniteLoop();
@@ -141,6 +146,13 @@
         return totalTime;
     }
 
+    private String stackForException(Throwable exception) {
+        Writer buffer = new StringWriter();
+        PrintWriter writer = new PrintWriter(buffer);
+        exception.printStackTrace(writer);
+        return buffer.toString();
+    }
+    
     @Test
     public void stalledThreadAppearsInStackTrace() throws Exception {
         JUnitCore core = new JUnitCore();
@@ -148,10 +160,92 @@
         assertEquals(1, result.getRunCount());
         assertEquals(1, result.getFailureCount());
         Throwable exception = result.getFailures().get(0).getException();
-        Writer buffer = new StringWriter();
-        PrintWriter writer = new PrintWriter(buffer);
-        exception.printStackTrace(writer);
-        assertThat(buffer.toString(), containsString("infiniteLoop")); // Make sure we have the stalled frame on the stack somewhere
+        assertThat(stackForException(exception), containsString("infiniteLoop")); // Make sure we have the stalled frame on the stack somewhere
+    }
+
+    public static class InfiniteLoopMultithreaded {
+        
+        private static class ThreadTest implements Runnable {
+            private boolean fStall;
+
+            public ThreadTest(boolean stall) {
+                fStall = stall;
+            }
+
+            public void run() {
+                if (fStall)
+                    for (; ; ) ;   
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        
+        public void failure(boolean mainThreadStalls) throws Exception {
+            Thread t1 = new Thread(new ThreadTest(false), "timeout-thr1");
+            Thread t2 = new Thread(new ThreadTest(!mainThreadStalls), "timeout-thr2");
+            Thread t3 = new Thread(new ThreadTest(false), "timeout-thr3");
+            t1.start();
+            t2.start();
+            t3.start();
+            if (mainThreadStalls)
+                for (; ; ) ;
+            t1.join();
+            t2.join();
+            t3.join();
+        }
+   }
+    
+    public static class InfiniteLoopWithStuckThreadTest {
+        @Rule
+        public TestRule globalTimeout = Timeout.builder()
+            .withTimeout(100, TimeUnit.MILLISECONDS)
+            .withLookingForStuckThread(true)
+            .build();
+
+        @Test
+        public void failure() throws Exception {
+            (new InfiniteLoopMultithreaded()).failure(false);
+        }
+    }
+    
+    public static class InfiniteLoopStuckInMainThreadTest {
+        @Rule
+        public TestRule globalTimeout = Timeout.builder()
+            .withTimeout(100, TimeUnit.MILLISECONDS)
+            .withLookingForStuckThread(true)
+            .build();
+
+        @Test
+        public void failure() throws Exception {
+            (new InfiniteLoopMultithreaded()).failure(true);
+        }
+    }
+
+    @Test
+    public void timeoutFailureMultithreaded() throws Exception {
+        JUnitCore core = new JUnitCore();
+        Result result = core.run(InfiniteLoopWithStuckThreadTest.class);
+        assertEquals(1, result.getRunCount());
+        assertEquals(2, result.getFailureCount());
+        Throwable exception[] = new Throwable[2];
+        for (int i = 0; i < 2; i++)
+            exception[i] = result.getFailures().get(i).getException();
+        assertThat(exception[0].getMessage(), containsString("test timed out after 100 milliseconds"));
+        assertThat(stackForException(exception[0]), containsString("Thread.join"));
+        assertThat(exception[1].getMessage(), containsString("Appears to be stuck in thread timeout-thr2"));
+    }
+
+    @Test
+    public void timeoutFailureMultithreadedStuckInMain() throws Exception {
+        JUnitCore core = new JUnitCore();
+        Result result = core.run(InfiniteLoopStuckInMainThreadTest.class);
+        assertEquals(1, result.getRunCount());
+        assertEquals(1, result.getFailureCount());
+        Throwable exception = result.getFailures().get(0).getException();
+        assertThat(exception.getMessage(), containsString("test timed out after 100 milliseconds"));
+        assertThat(exception.getMessage(), not(containsString("Appears to be stuck")));
     }
 
     @Test
@@ -186,4 +280,55 @@
         JUnitCore.runClasses(WillTimeOut.class);
         assertThat(WillTimeOut.afterWasCalled, is(true));
     }
+
+    public static class TimeOutZero {
+        @Rule
+        public Timeout timeout = Timeout.seconds(0);
+
+        @Test
+        public void test() {
+            try {
+                Thread.sleep(200); // long enough to suspend thread execution
+            } catch (InterruptedException e) {
+                // Don't care
+            }
+        }
+    }
+
+    @Test
+    public void testZeroTimeoutIsIgnored() {
+        JUnitCore core = new JUnitCore();
+        Result result = core.run(TimeOutZero.class);
+        assertEquals("Should run the test", 1, result.getRunCount());
+        assertEquals("Test should not have failed", 0, result.getFailureCount());
+    }
+
+    private static class TimeoutSubclass extends Timeout {
+
+        public TimeoutSubclass(long timeout, TimeUnit timeUnit) {
+            super(timeout, timeUnit);
+        }
+
+        public long getTimeoutFromSuperclass(TimeUnit unit) {
+            return super.getTimeout(unit);
+        }
+    }
+
+    public static class TimeOutOneSecond {
+        @Rule
+        public TimeoutSubclass timeout = new TimeoutSubclass(1, TimeUnit.SECONDS);
+
+        @Test
+        public void test() {
+            assertEquals(1000, timeout.getTimeoutFromSuperclass(TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
+    public void testGetTimeout() {
+        JUnitCore core = new JUnitCore();
+        Result result = core.run(TimeOutOneSecond.class);
+        assertEquals("Should run the test", 1, result.getRunCount());
+        assertEquals("Test should not have failed", 0, result.getFailureCount());
+    }
 }
diff --git a/src/test/java/org/junit/tests/validation/InaccessibleBaseClassTest.java b/src/test/java/org/junit/tests/validation/InaccessibleBaseClassTest.java
deleted file mode 100644
index 3737cd9..0000000
--- a/src/test/java/org/junit/tests/validation/InaccessibleBaseClassTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.junit.tests.validation;
-
-import org.junit.Test;
-import org.junit.runners.BlockJUnit4ClassRunner;
-import org.junit.runners.model.InitializationError;
-import org.junit.tests.validation.anotherpackage.Sub;
-
-public class InaccessibleBaseClassTest {
-    @Test(expected = InitializationError.class)
-    public void inaccessibleBaseClassIsCaughtAtValidation() throws InitializationError {
-        new BlockJUnit4ClassRunner(Sub.class);
-    }
-}
diff --git a/src/test/java/org/junit/validator/AnnotationValidatorFactoryTest.java b/src/test/java/org/junit/validator/AnnotationValidatorFactoryTest.java
new file mode 100644
index 0000000..4003ff3
--- /dev/null
+++ b/src/test/java/org/junit/validator/AnnotationValidatorFactoryTest.java
@@ -0,0 +1,47 @@
+package org.junit.validator;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertThat;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class AnnotationValidatorFactoryTest {
+
+    @Rule
+    public ExpectedException exception = ExpectedException.none();
+
+    @Test
+    public void createAnnotationValidator() {
+        ValidateWith validateWith = SampleTestWithValidator.class.getAnnotation(ValidateWith.class);
+        AnnotationValidator annotationValidator = new AnnotationValidatorFactory().createAnnotationValidator(validateWith);
+        assertThat(annotationValidator, is(instanceOf(Validator.class)));
+    }
+
+    @ValidateWith(value = Validator.class)
+    public static class SampleTestWithValidator {
+    }
+
+    public static class Validator extends AnnotationValidator {
+    }
+
+    @Test
+    public void exceptionWhenAnnotationValidatorCantBeCreated() {
+        ValidateWith validateWith = SampleTestWithValidatorThatThrowsException.class.getAnnotation(ValidateWith.class);
+        exception.expect(RuntimeException.class);
+        exception.expectMessage("Exception received when creating AnnotationValidator class " +
+                "org.junit.validator.AnnotationValidatorFactoryTest$ValidatorThatThrowsException");
+        new AnnotationValidatorFactory().createAnnotationValidator(validateWith);
+    }
+
+    @ValidateWith(value = ValidatorThatThrowsException.class)
+    public static class SampleTestWithValidatorThatThrowsException {
+    }
+
+    public static class ValidatorThatThrowsException extends AnnotationValidator {
+        public ValidatorThatThrowsException() throws InstantiationException {
+            throw new InstantiationException("Simulating exception in test");
+        }
+    }
+}
diff --git a/src/test/java/org/junit/validator/AnnotationsValidatorTest.java b/src/test/java/org/junit/validator/AnnotationsValidatorTest.java
new file mode 100644
index 0000000..6573309
--- /dev/null
+++ b/src/test/java/org/junit/validator/AnnotationsValidatorTest.java
@@ -0,0 +1,98 @@
+package org.junit.validator;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runners.model.FrameworkField;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.TestClass;
+
+public class AnnotationsValidatorTest {
+    public static class ExampleAnnotationValidator extends AnnotationValidator {
+        private static final String ANNOTATED_METHOD_CALLED= "annotated method called";
+
+        private static final String ANNOTATED_FIELD_CALLED= "annotated field called";
+
+        private static final String ANNOTATED_CLASS_CALLED= "annotated class called";
+
+        @Override
+        public List<Exception> validateAnnotatedClass(TestClass testClass) {
+            return asList(new Exception(ANNOTATED_CLASS_CALLED));
+        }
+
+        @Override
+        public List<Exception> validateAnnotatedField(FrameworkField field) {
+            return asList(new Exception(ANNOTATED_FIELD_CALLED));
+        }
+
+        @Override
+        public List<Exception> validateAnnotatedMethod(FrameworkMethod method) {
+            return asList(new Exception(ANNOTATED_METHOD_CALLED));
+        }
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Inherited
+    @ValidateWith(ExampleAnnotationValidator.class)
+    public @interface ExampleAnnotationWithValidator {
+    }
+
+    public static class AnnotationValidatorMethodTest {
+        @ExampleAnnotationWithValidator
+        @Test
+        public void test() {
+        }
+    }
+
+    public static class AnnotationValidatorFieldTest {
+        @ExampleAnnotationWithValidator
+        private String field;
+
+        @Test
+        public void test() {
+        }
+    }
+
+    @ExampleAnnotationWithValidator
+    public static class AnnotationValidatorClassTest {
+        @Test
+        public void test() {
+        }
+    }
+
+    @Test
+    public void validatorIsCalledForAClass() {
+        assertClassHasFailureMessage(AnnotationValidatorClassTest.class,
+                ExampleAnnotationValidator.ANNOTATED_CLASS_CALLED);
+    }
+
+    @Test
+    public void validatorIsCalledForAMethod() {
+        assertClassHasFailureMessage(AnnotationValidatorMethodTest.class,
+                ExampleAnnotationValidator.ANNOTATED_METHOD_CALLED);
+    }
+
+    @Test
+    public void validatorIsCalledForAField() {
+        assertClassHasFailureMessage(AnnotationValidatorFieldTest.class,
+                ExampleAnnotationValidator.ANNOTATED_FIELD_CALLED);
+    }
+
+    private void assertClassHasFailureMessage(Class<?> klass,
+            String expectedFailure) {
+        AnnotationsValidator validator= new AnnotationsValidator();
+        Collection<Exception> errors= validator
+                .validateTestClass(new TestClass(klass));
+        assertThat(errors.size(), is(1));
+        assertThat(errors.iterator().next().getMessage(),
+                is(expectedFailure));
+    }
+}
diff --git a/src/test/java/org/junit/validator/PublicClassValidatorTest.java b/src/test/java/org/junit/validator/PublicClassValidatorTest.java
new file mode 100644
index 0000000..dfecbbc
--- /dev/null
+++ b/src/test/java/org/junit/validator/PublicClassValidatorTest.java
@@ -0,0 +1,41 @@
+package org.junit.validator;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runners.model.TestClass;
+
+public class PublicClassValidatorTest {
+    private final PublicClassValidator validator = new PublicClassValidator();
+
+    public static class PublicClass {
+
+    }
+
+    @Test
+    public void acceptsPublicClass() {
+        TestClass testClass = new TestClass(PublicClass.class);
+        List<Exception> validationErrors = validator
+                .validateTestClass(testClass);
+        assertThat(validationErrors,
+                is(equalTo(Collections.<Exception> emptyList())));
+    }
+
+    static class NonPublicClass {
+
+    }
+
+    @Test
+    public void rejectsNonPublicClass() {
+        TestClass testClass = new TestClass(NonPublicClass.class);
+        List<Exception> validationErrors = validator
+                .validateTestClass(testClass);
+        assertThat("Wrong number of errors.", validationErrors.size(),
+                is(equalTo(1)));
+    }
+}
diff --git a/src/test/resources/junit/tests/runner/testRunFailureResultCanBeSerialised b/src/test/resources/junit/tests/runner/testRunFailureResultCanBeSerialised
new file mode 100644
index 0000000..79d8c01
--- /dev/null
+++ b/src/test/resources/junit/tests/runner/testRunFailureResultCanBeSerialised
Binary files differ
diff --git a/src/test/resources/junit/tests/runner/testRunSuccessResultCanBeSerialised b/src/test/resources/junit/tests/runner/testRunSuccessResultCanBeSerialised
new file mode 100644
index 0000000..e5163d1
--- /dev/null
+++ b/src/test/resources/junit/tests/runner/testRunSuccessResultCanBeSerialised
Binary files differ
diff --git a/to-do.txt b/to-do.txt
index 2e30000..4efa20f 100644
--- a/to-do.txt
+++ b/to-do.txt
@@ -1,5 +1,3 @@
-* assertArrayEquals(double[], double[], double) and assertArrayEquals(float[], float[], float)
-
 * update documentation
 	* new cook's tour
 	* update Test Infected
@@ -8,14 +6,12 @@
     but the same component tests, to co-exist
 
 * update the build process
-    * automatically upload a new JAR
     * update site for plug-in version?
 * Ant
 	* Basic task
 * support testing run once initialization code e.g. class Foo {{...}}
 * Automatically add failing tests to the Known Defects section of the README.html
 
-* Create test target in ant
 * Create assume(that()) and assert(that()) 
   (what is a better name for the second one?)
   
@@ -28,4 +24,4 @@
 * If a suite() returns a JUnit4TestAdapter, allow Filters and Sorters to operate on 
   the adapted Runner.
   
-* Every time I add a Filter feature, I have to add an equivalent Sorter feature.  Suspicious.
\ No newline at end of file
+* Every time I add a Filter feature, I have to add an equivalent Sorter feature.  Suspicious.