aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Android.mk4
-rw-r--r--README.android6
-rw-r--r--README.html1300
-rw-r--r--src/META-INF/MANIFEST.MF4
-rw-r--r--src/junit/awtui/AboutDialog.java77
-rw-r--r--src/junit/awtui/Logo.java58
-rw-r--r--src/junit/awtui/ProgressBar.java88
-rw-r--r--src/junit/awtui/TestRunner.java571
-rw-r--r--src/junit/extensions/ActiveTestSuite.java8
-rw-r--r--src/junit/extensions/ExceptionTestCase.java46
-rw-r--r--src/junit/extensions/RepeatedTest.java16
-rw-r--r--src/junit/extensions/TestDecorator.java13
-rw-r--r--src/junit/extensions/TestSetup.java17
-rw-r--r--src/junit/extensions/package-info.java4
-rw-r--r--src/junit/framework/Assert.java35
-rw-r--r--src/junit/framework/AssertionFailedError.java15
-rw-r--r--src/junit/framework/ComparisonFailure.java3
-rw-r--r--src/junit/framework/JUnit4TestAdapter.java85
-rw-r--r--src/junit/framework/JUnit4TestAdapterCache.java81
-rw-r--r--src/junit/framework/JUnit4TestCaseFacade.java33
-rw-r--r--src/junit/framework/TestCase.java61
-rw-r--r--src/junit/framework/TestFailure.java1
-rw-r--r--src/junit/framework/TestResult.java63
-rw-r--r--src/junit/framework/TestSuite.java106
-rw-r--r--src/junit/framework/package-info.java4
-rw-r--r--src/junit/runner/BaseTestRunner.java35
-rw-r--r--src/junit/runner/ClassPathTestCollector.java83
-rw-r--r--src/junit/runner/FailureDetailView.java23
-rw-r--r--src/junit/runner/LoadingTestCollector.java70
-rw-r--r--src/junit/runner/ReloadingTestSuiteLoader.java19
-rw-r--r--src/junit/runner/SimpleTestCollector.java20
-rw-r--r--src/junit/runner/Sorter.java36
-rw-r--r--src/junit/runner/StandardTestSuiteLoader.java19
-rw-r--r--src/junit/runner/TestCaseClassLoader.java240
-rw-r--r--src/junit/runner/TestCollector.java17
-rw-r--r--src/junit/runner/TestSuiteLoader.java9
-rw-r--r--src/junit/runner/Version.java2
-rw-r--r--src/junit/runner/Version.java.template18
-rw-r--r--src/junit/runner/excluded.properties13
-rw-r--r--src/junit/runner/package-info.java4
-rw-r--r--src/junit/swingui/AboutDialog.java93
-rw-r--r--src/junit/swingui/CounterPanel.java118
-rw-r--r--src/junit/swingui/DefaultFailureDetailView.java101
-rw-r--r--src/junit/swingui/FailureRunView.java122
-rw-r--r--src/junit/swingui/MacProgressBar.java20
-rw-r--r--src/junit/swingui/ProgressBar.java46
-rw-r--r--src/junit/swingui/StatusLine.java45
-rw-r--r--src/junit/swingui/TestHierarchyRunView.java77
-rw-r--r--src/junit/swingui/TestRunContext.java21
-rw-r--r--src/junit/swingui/TestRunView.java39
-rw-r--r--src/junit/swingui/TestRunner.java849
-rw-r--r--src/junit/swingui/TestSelector.java285
-rw-r--r--src/junit/swingui/TestSuitePanel.java172
-rw-r--r--src/junit/swingui/TestTreeModel.java190
-rw-r--r--src/junit/swingui/icons/error.gifbin868 -> 0 bytes
-rw-r--r--src/junit/swingui/icons/failure.gifbin862 -> 0 bytes
-rw-r--r--src/junit/swingui/icons/hierarchy.gifbin891 -> 0 bytes
-rw-r--r--src/junit/swingui/icons/ok.gifbin85 -> 0 bytes
-rw-r--r--src/junit/textui/ResultPrinter.java4
-rw-r--r--src/junit/textui/TestRunner.java38
-rw-r--r--src/junit/textui/package-info.java4
-rw-r--r--src/org/junit/After.java40
-rw-r--r--src/org/junit/AfterClass.java41
-rw-r--r--src/org/junit/Assert.java783
-rw-r--r--src/org/junit/Assume.java94
-rw-r--r--src/org/junit/Before.java39
-rw-r--r--src/org/junit/BeforeClass.java35
-rw-r--r--src/org/junit/ClassRule.java60
-rw-r--r--src/org/junit/ComparisonFailure.java138
-rw-r--r--src/org/junit/Ignore.java39
-rw-r--r--src/org/junit/Rule.java47
-rw-r--r--src/org/junit/Test.java68
-rw-r--r--src/org/junit/experimental/ParallelComputer.java78
-rw-r--r--src/org/junit/experimental/categories/Categories.java192
-rw-r--r--src/org/junit/experimental/categories/Category.java43
-rw-r--r--src/org/junit/experimental/max/CouldNotReadCoreException.java15
-rw-r--r--src/org/junit/experimental/max/MaxCore.java170
-rw-r--r--src/org/junit/experimental/max/MaxHistory.java166
-rw-r--r--src/org/junit/experimental/results/FailureList.java31
-rw-r--r--src/org/junit/experimental/results/PrintableResult.java63
-rw-r--r--src/org/junit/experimental/results/ResultMatchers.java70
-rw-r--r--src/org/junit/experimental/runners/Enclosed.java31
-rw-r--r--src/org/junit/experimental/theories/DataPoint.java9
-rw-r--r--src/org/junit/experimental/theories/DataPoints.java9
-rw-r--r--src/org/junit/experimental/theories/ParameterSignature.java90
-rw-r--r--src/org/junit/experimental/theories/ParameterSupplier.java8
-rw-r--r--src/org/junit/experimental/theories/ParametersSuppliedBy.java12
-rw-r--r--src/org/junit/experimental/theories/PotentialAssignment.java31
-rw-r--r--src/org/junit/experimental/theories/Theories.java199
-rw-r--r--src/org/junit/experimental/theories/Theory.java12
-rw-r--r--src/org/junit/experimental/theories/internal/AllMembersSupplier.java127
-rw-r--r--src/org/junit/experimental/theories/internal/Assignments.java133
-rw-r--r--src/org/junit/experimental/theories/internal/ParameterizedAssertionError.java49
-rw-r--r--src/org/junit/experimental/theories/suppliers/TestedOn.java13
-rw-r--r--src/org/junit/experimental/theories/suppliers/TestedOnSupplier.java23
-rw-r--r--src/org/junit/internal/ArrayComparisonFailure.java59
-rw-r--r--src/org/junit/internal/AssumptionViolatedException.java40
-rw-r--r--src/org/junit/internal/ComparisonCriteria.java76
-rw-r--r--src/org/junit/internal/ExactComparisonCriteria.java10
-rw-r--r--src/org/junit/internal/InexactComparisonCriteria.java19
-rw-r--r--src/org/junit/internal/JUnitSystem.java8
-rw-r--r--src/org/junit/internal/RealSystem.java15
-rw-r--r--src/org/junit/internal/TextListener.java98
-rw-r--r--src/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java57
-rw-r--r--src/org/junit/internal/builders/AnnotatedBuilder.java45
-rw-r--r--src/org/junit/internal/builders/IgnoredBuilder.java17
-rw-r--r--src/org/junit/internal/builders/IgnoredClassRunner.java26
-rw-r--r--src/org/junit/internal/builders/JUnit3Builder.java21
-rw-r--r--src/org/junit/internal/builders/JUnit4Builder.java15
-rw-r--r--src/org/junit/internal/builders/NullBuilder.java14
-rw-r--r--src/org/junit/internal/builders/SuiteMethodBuilder.java26
-rw-r--r--src/org/junit/internal/matchers/CombinableMatcher.java34
-rw-r--r--src/org/junit/internal/matchers/Each.java24
-rw-r--r--src/org/junit/internal/matchers/IsCollectionContaining.java67
-rw-r--r--src/org/junit/internal/matchers/StringContains.java31
-rw-r--r--src/org/junit/internal/matchers/SubstringMatcher.java28
-rw-r--r--src/org/junit/internal/matchers/TypeSafeMatcher.java60
-rw-r--r--src/org/junit/internal/requests/ClassRequest.java26
-rw-r--r--src/org/junit/internal/requests/FilterRequest.java42
-rw-r--r--src/org/junit/internal/requests/SortingRequest.java25
-rw-r--r--src/org/junit/internal/requests/package-info.java6
-rw-r--r--src/org/junit/internal/runners/ClassRoadie.java79
-rw-r--r--src/org/junit/internal/runners/ErrorReportingRunner.java60
-rw-r--r--src/org/junit/internal/runners/FailedBefore.java14
-rw-r--r--src/org/junit/internal/runners/InitializationError.java30
-rw-r--r--src/org/junit/internal/runners/JUnit38ClassRunner.java158
-rw-r--r--src/org/junit/internal/runners/JUnit4ClassRunner.java145
-rw-r--r--src/org/junit/internal/runners/MethodRoadie.java157
-rw-r--r--src/org/junit/internal/runners/MethodValidator.java91
-rw-r--r--src/org/junit/internal/runners/SuiteMethod.java40
-rw-r--r--src/org/junit/internal/runners/TestClass.java102
-rw-r--r--src/org/junit/internal/runners/TestMethod.java69
-rw-r--r--src/org/junit/internal/runners/model/EachTestNotifier.java51
-rw-r--r--src/org/junit/internal/runners/model/MultipleFailureException.java12
-rw-r--r--src/org/junit/internal/runners/model/ReflectiveCallable.java22
-rw-r--r--src/org/junit/internal/runners/package-info.java6
-rw-r--r--src/org/junit/internal/runners/rules/RuleFieldValidator.java92
-rw-r--r--src/org/junit/internal/runners/statements/ExpectException.java38
-rw-r--r--src/org/junit/internal/runners/statements/Fail.java17
-rw-r--r--src/org/junit/internal/runners/statements/FailOnTimeout.java71
-rw-r--r--src/org/junit/internal/runners/statements/InvokeMethod.java22
-rw-r--r--src/org/junit/internal/runners/statements/RunAfters.java43
-rw-r--r--src/org/junit/internal/runners/statements/RunBefores.java30
-rw-r--r--src/org/junit/matchers/JUnitMatchers.java83
-rw-r--r--src/org/junit/matchers/package-info.java9
-rw-r--r--src/org/junit/package-info.java8
-rw-r--r--src/org/junit/rules/ErrorCollector.java85
-rw-r--r--src/org/junit/rules/ExpectedException.java136
-rw-r--r--src/org/junit/rules/ExternalResource.java68
-rw-r--r--src/org/junit/rules/MethodRule.java40
-rw-r--r--src/org/junit/rules/RuleChain.java99
-rw-r--r--src/org/junit/rules/RunRules.java27
-rw-r--r--src/org/junit/rules/TemporaryFolder.java113
-rw-r--r--src/org/junit/rules/TestName.java39
-rw-r--r--src/org/junit/rules/TestRule.java54
-rw-r--r--src/org/junit/rules/TestWatcher.java94
-rw-r--r--src/org/junit/rules/TestWatchman.java100
-rw-r--r--src/org/junit/rules/Timeout.java49
-rw-r--r--src/org/junit/rules/Verifier.java45
-rw-r--r--src/org/junit/runner/Computer.java40
-rw-r--r--src/org/junit/runner/Describable.java12
-rw-r--r--src/org/junit/runner/Description.java242
-rw-r--r--src/org/junit/runner/JUnitCore.java186
-rw-r--r--src/org/junit/runner/Request.java161
-rw-r--r--src/org/junit/runner/Result.java106
-rw-r--r--src/org/junit/runner/RunWith.java34
-rw-r--r--src/org/junit/runner/Runner.java40
-rw-r--r--src/org/junit/runner/manipulation/Filter.java114
-rw-r--r--src/org/junit/runner/manipulation/Filterable.java16
-rw-r--r--src/org/junit/runner/manipulation/NoTestsRemainException.java8
-rw-r--r--src/org/junit/runner/manipulation/Sortable.java17
-rw-r--r--src/org/junit/runner/manipulation/Sorter.java46
-rw-r--r--src/org/junit/runner/manipulation/package-info.java7
-rw-r--r--src/org/junit/runner/notification/Failure.java79
-rw-r--r--src/org/junit/runner/notification/RunListener.java93
-rw-r--r--src/org/junit/runner/notification/RunNotifier.java166
-rw-r--r--src/org/junit/runner/notification/StoppedByUserException.java11
-rw-r--r--src/org/junit/runner/notification/package-info.java6
-rw-r--r--src/org/junit/runner/package-info.java6
-rw-r--r--src/org/junit/runners/AllTests.java24
-rw-r--r--src/org/junit/runners/BlockJUnit4ClassRunner.java407
-rw-r--r--src/org/junit/runners/JUnit4.java22
-rw-r--r--src/org/junit/runners/Parameterized.java167
-rw-r--r--src/org/junit/runners/ParentRunner.java378
-rw-r--r--src/org/junit/runners/Suite.java130
-rw-r--r--src/org/junit/runners/model/FrameworkField.java65
-rw-r--r--src/org/junit/runners/model/FrameworkMember.java20
-rw-r--r--src/org/junit/runners/model/FrameworkMethod.java156
-rw-r--r--src/org/junit/runners/model/InitializationError.java39
-rw-r--r--src/org/junit/runners/model/MultipleFailureException.java60
-rw-r--r--src/org/junit/runners/model/NoGenericTypeParametersValidator.java53
-rw-r--r--src/org/junit/runners/model/RunnerBuilder.java104
-rw-r--r--src/org/junit/runners/model/RunnerScheduler.java21
-rw-r--r--src/org/junit/runners/model/Statement.java16
-rw-r--r--src/org/junit/runners/model/TestClass.java159
-rw-r--r--src/org/junit/runners/package-info.java8
-rw-r--r--version2
198 files changed, 10544 insertions, 4454 deletions
diff --git a/.gitignore b/.gitignore
index ba077a4..20603ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
bin
+src/META-INF/MANIFEST.MF
diff --git a/Android.mk b/Android.mk
index ad95080..ef7e3af 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,4 +21,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE := junit
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := hamcrest-host
+
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/README.android b/README.android
index 704cf9e..c4194e4 100644
--- a/README.android
+++ b/README.android
@@ -1,4 +1,4 @@
-This is junit3.8.2 source, intended for host side use.
+This is junit4.10 source, currently intended for host side use.
+
+Obtained from https://github.com/downloads/KentBeck/junit/junit-4.10-src.jar
-Obtained from http://sourceforge.net/project/showfiles.php?group_id=15278&package_id=12472 without
-modification. \ No newline at end of file
diff --git a/README.html b/README.html
index df6f10f..42f29a6 100644
--- a/README.html
+++ b/README.html
@@ -1,736 +1,672 @@
-<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<!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 &amp; Kent Beck">
- <title>JUnit 3.8</title>
+ <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, Kent Beck, and David Saff">
+ <title>JUnit 4.6</title>
</head>
<body>
+
<h1>
-<b><font color="#00cc00">J</font><font color="#ff0000">U</font><font
- color="#000000">nit
-3.8.2</font></b></h1>
-<hr width="100%">
-<font color="#000000"><br>
-11/11/2004<br>
-</font>
+<b><font color="#00CC00">J</font><font color="#FF0000">U</font><font color="#000000">nit
+4.6</b></h1>
+<br>Brought to you by <a href="http://www.threeriversinstitute.org">Kent Beck</a>, Erich
+Gamma, and <a href="http://david.saff.net">David Saff</a>.
+<br>FAQ edited by <a href="http://www.clarkware.com">Mike Clark</a>. Web mastering by Erik
+Meade.
+<br>(see also <a href="http://www.junit.org">JUnit.org</a>)
+
+<hr WIDTH="100%">
+<br>6 April 2009
+<p>JUnit is a simple framework to write repeatable tests. It is an instance
+of the xUnit architecture for unit testing frameworks.
<ul>
- <li><font color="#000000"><a href="#Summary%20of">Summary of Changes</a></font></li>
- <li>
- <font color="#000000"><a href="#Contents">Contents</a></font></li>
- <li>
- <font color="#000000"><a href="#Installation">Installation</a></font></li>
- <li>
- <font color="#000000"><a href="#Getting">Getting Started</a></font></li>
- <li>
- <font color="#000000"><a href="#Documentation">Documentation</a></font></li>
+<li>
+<a href="#Summary of">Summary of Changes</a></li>
+
+<li>
+<a href="#Contents">Contents</a></li>
+
+<li>
+<a href="#Installation">Installation</a></li>
+
+<li>
+<a href="#Getting">Getting Started</a></li>
+
+<li>
+<a href="#Documentation">Documentation</a></li>
+<li>
+<a href="#Known Defects">Known Defects</a></li>
</ul>
-<h2>
-<font><a name="Summary of"></a><font color="#000000">Summary of Changes
-between 3.8.1 and 3.8.2</font></font></h2>
-<font color="#000000">The changes between the versions are minimal and
-the focus was on fixing the accumulated bug reports. The most
-signifanct change is replacing the much-reviled string comparison
-format with something easier to read and use.<br>
-</font>
-<ul>
- <li>ComparisonFailure shows context.&nbsp; <br>
- </li>
- <ul>
- <li>assertEquals("Mary had a little lamb", "Mary had the little
-lamb") shows: expected:&lt;Mary had [a] little lamb&gt; but
-was:&lt;Mary had [the] little lamb&gt;<br>
-Longer prefixes and suffixes are truncated to a fixed size (currently
-20):</li>
- <li>expected:&lt;...st of the emergency [broadcasting]
-system&gt; but was:&lt;...st of the emergency [locating] system&gt;<br>
- </li>
- </ul>
- <li><font color="#000000">Running single tests.&nbsp;
-junit.ui.TestRunner can be invoked with "-m</font> ClassName.testName"
-to run a single test.</li>
- <li>TestSuite(Class[]).&nbsp;
-There is a new TestSuite constructor that takes an array of classes as
-a parameter and returns a suite of suites, each of which is constructed
-from a single class.</li>
-</ul>
-<h3><font><font color="#000000">Closed Bugs/Patches and Enhancment
-Requests<br>
-</font></font></h3>
+
+<a NAME="Summary of">
+<h2>Summary of Changes in version 4.6</h2>
+
+<h3>Max</h3>
+
+<p>JUnit now includes a new experimental Core, <code>MaxCore</code>. <code>MaxCore</code>
+remembers the results of previous test runs in order to run new
+tests out of order. <code>MaxCore</code> prefers new tests to old tests, fast
+tests to slow tests, and recently failing tests to tests that last
+failed long ago. There's currently not a standard UI for running
+<code>MaxCore</code> included in JUnit, but there is a UI included in the JUnit
+Max Eclipse plug-in at:</p>
+
+<p>http://www.junitmax.com/junitmax/subscribe.html</p>
+
+<p>Example:</p>
+
+<pre><code>public static class TwoUnEqualTests {
+ @Test
+ public void slow() throws InterruptedException {
+ Thread.sleep(100);
+ fail();
+ }
+
+ @Test
+ 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&lt;Failure&gt; failures= useHistory.run(TwoUnEqualTests.class)
+ .getFailures();
+ assertEquals("fast", failures.get(0).getDescription().getMethodName());
+ assertEquals("slow", failures.get(1).getDescription().getMethodName());
+}
+</code></pre>
+
+<h3>Test scheduling strategies</h3>
+
+<p><code>JUnitCore</code> now includes an experimental method that allows you to
+specify a model of the <code>Computer</code> that runs your tests. Currently,
+the only built-in Computers are the default, serial runner, and two
+runners provided in the <code>ParallelRunner</code> class:
+<code>ParallelRunner.classes()</code>, which runs classes in parallel, and
+<code>ParallelRunner.methods()</code>, which runs classes and methods in parallel.</p>
+
+<p>This feature is currently less stable than MaxCore, and may be
+merged with MaxCore in some way in the future.</p>
+
+<p>Example:</p>
+
+<pre><code>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));
+}
+</code></pre>
+
+<h3>Comparing double arrays</h3>
+
+<p>Arrays of doubles can be compared, using a delta allowance for equality:</p>
+
+<pre><code>@Test
+public void doubleArraysAreEqual() {
+ assertArrayEquals(new double[] {1.0, 2.0}, new double[] {1.0, 2.0}, 0.01);
+}
+</code></pre>
+
+<h3><code>Filter.matchDescription</code> API</h3>
+
+<p>Since 4.0, it has been possible to run a single method using the <code>Request.method</code>
+API. In 4.6, the filter that implements this is exposed as <code>Filter.matchDescription</code>.</p>
+
+<h3>Documentation</h3>
+
<ul>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=698067&amp;group_id=15278&amp;atid=115278">assertEquals(float,float,delta)
-fails on negative delta</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=609972&amp;group_id=15278&amp;atid=115278">'...'
-in ComparisonFailure</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=461535&amp;group_id=15278&amp;atid=115278">Trouble
-in teardown hides orig. probl.</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=609819&amp;group_id=15278&amp;atid=115278">NaN's
-in assertEquals</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=620039&amp;group_id=15278&amp;atid=115278">BaseTestRunner.setPreference
-static</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=658044&amp;group_id=15278&amp;atid=115278">failNotEquals()
-should be protected</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=777097&amp;group_id=15278&amp;atid=115278">RFE:
-make private methods protected</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=654507&amp;group_id=15278&amp;atid=365278">Printing
-version number</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=993150&amp;group_id=15278&amp;atid=315278">Patch
-to quell warnings in tiger</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=657593&amp;group_id=15278&amp;atid=315278">Enhanced
-ComparisonFailure output</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=625016&amp;group_id=15278&amp;atid=315278">addt'l
-TestSuite constructrs for Class[]</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=908467&amp;group_id=15278&amp;atid=315278">Run
-one test method for junit</a></li>
- <li><a
- href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=756480&amp;group_id=15278&amp;atid=315278">excluded.properties:
-Add commons logging</a></li>
+<li><p>A couple classes and packages that once had empty javadoc have been
+doc'ed.</p></li>
+<li><p>Added how to run JUnit from the command line to the cookbook.</p></li>
+<li><p>junit-4.x.zip now contains build.xml</p></li>
</ul>
-<h2><font color="#000000">Summary of Changes between 3.8 and 3.8.1</font></h2>
+
+<h3>Bug fixes</h3>
+
<ul>
- <font color="#000000"> <li>Backed out setting the testing Thread's
-context class loader (see <a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=598200&amp;group_id=15278&amp;atid=115278">JUnit
-not setting ClassLoader</a>). It has caused problems in tests that
-worked OK before. See the bug report for more details.</li>
- <li>Fixes:&nbsp;
- <ul>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=601326&amp;group_id=15278&amp;atid=115278">NPE
-in ComparisonFailure</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=602948&amp;group_id=15278&amp;atid=115278">Swing
-UI: NoSuchMethodError on JDK 1.3</a></li>
- </ul>
- </li>
- </font>
+<li>Fixed overly permissive @DataPoint processing (2191102)</li>
+<li>Fixed bug in test counting after an ignored method (2106324)</li>
</ul>
-<h2>
-<font color="#000000">Summary of Changes between 3.7 and 3.8</font></h2>
-<h3>
-<font color="#000000">Framework</font></h3>
+
+<h2>Summary of Changes in version 4.5</h2>
+
+<h3>Installation</h3>
+
<ul>
- <li>
- <font color="#000000">Made the string argument TestCase constructor
-optional. You can now delete
-constructors of the form "FooTestCase(String name) { super(name); }".</font></li>
- <li>
- <font color="#000000">Deleted deprecated assert(boolean) in favor
-of assertTrue(boolean) and
-assertFalse(boolean). To migrate to JUnit 3.8, rename calls to
-assert(boolean)
-to call assertTrue(boolean).</font></li>
- <li>
- <font color="#000000">Added assertFalse() to avoid the difficult of
-reading the assertTrue(!
-condition).</font></li>
- <li>
- <font color="#000000">Added assertNotSame(Object, Object).</font></li>
- <li>
- <font color="#000000">Deleted deprecated TestCase.name() in favor
-of TestCase.getName().</font></li>
- <li>
- <font color="#000000">Deleted deprecated package junit.ui in favor
-of junit.awtui.</font></li>
+<li>We are releasing <code>junit-4.6.jar</code>, which contains all the classes
+necessary to run JUnit, and <code>junit-dep-4.6.jar</code>, which leaves out
+hamcrest classes, for developers who already use hamcrest outside of
+JUnit.</li>
</ul>
-<h3>
-<font color="#000000">Test Runner</font></h3>
+
+<h3>Basic JUnit operation</h3>
+
<ul>
- <li>
- <font color="#000000">When you compare two long strings with a
-small delta embedded in the middle, it
-is hard to spot the difference. In 3.8, when you call
-assertEquals(String,
-String), only the differences between the strings are displayed. The
-common
-prefix and suffix are replaced with "...".</font></li>
- <li>
- <font color="#000000">Added initial version of a TestRunListener
-attached to TestRunners which
-eventually will replace TestListeners attached to the TestResult.</font></li>
- <li>
- <font color="#000000">Filled in ActiveTestSuite constructors.</font></li>
- <li>
- <font color="#000000">Added these packages to the
-excluded.properties:<font size="2">
- <ul>
- <li>org.w3c.dom.*</li>
- <li>org.xml.sax.*</li>
- <li>net.jini.*</li>
- </ul>
- </font></font></li>
- <li><font color="#000000">Extracted textual formatting of a
-TestResult from junit.textui.TestRunner into ResultPrinter.</font></li>
+<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><font color="#000000">Documentation</font></h3>
+
+<h3>Extension</h3>
+
<ul>
- <font color="#000000"> <li>Much improved <a href="doc/faq/faq.htm">FAQ</a>
-thanks to Mike Clark.</li>
- </font>
-</ul>
-<h3><font color="#000000">Closed Bugs</font></h3>
+<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>
- <font color="#000000"> <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=583346&amp;group_id=15278&amp;atid=115278">Class
-loader problem</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=551239&amp;group_id=15278&amp;atid=115278">Cookbook
-Simple Test Case problems</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=539015&amp;group_id=15278&amp;atid=115278">License
-not included in source</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=560081&amp;group_id=15278&amp;atid=115278">assert
-is a keyword</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=572444&amp;group_id=15278&amp;atid=115278">javadoc
-returns mysterious message</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=581251&amp;group_id=15278&amp;atid=115278">swingui
-CounterPanel values disappear</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=574641&amp;group_id=15278&amp;atid=115278">TestCase
-javadoc incorrect example</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=582784&amp;group_id=15278&amp;atid=115278">silly
-cookbook error</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=583328&amp;group_id=15278&amp;atid=115278">junit
-properties missfunction</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=595957&amp;group_id=15278&amp;atid=115278">Test.java
-is not Serializable</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=598200&amp;group_id=15278&amp;atid=115278">JUnit
-not setting ClassLoader`</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=592713&amp;group_id=15278&amp;atid=115278">NullPointerException
-when loading suite</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=544683&amp;group_id=15278&amp;atid=115278">labels
-for bug counts too small in Swing</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=537502&amp;group_id=15278&amp;atid=115278">Swing
-TestRunner layout shifts</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=528868&amp;group_id=15278&amp;atid=115278">Exit
-code problem for cygwin/w2k</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=529953&amp;group_id=15278&amp;atid=115278">Automatic
-reload causes strange errors</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=532952&amp;group_id=15278&amp;atid=115278">TestRunner
-fails with swing/awtui</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=533411&amp;group_id=15278&amp;atid=115278">CVS
-version doesn't build on NetBSD</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=520210&amp;group_id=15278&amp;atid=115278">NullPointerException
-JUnit sample w/ Ant</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=527511&amp;group_id=15278&amp;atid=115278">money
-sample bug</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=491981&amp;group_id=15278&amp;atid=115278">incomplete
-message from failNotSame()</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=471577&amp;group_id=15278&amp;atid=115278">Icons
-on systems with 64 colors exceptio</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=470324&amp;group_id=15278&amp;atid=115278">1000+
-tests, swing gui doesn't display</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=442752&amp;group_id=15278&amp;atid=115278">test
-selector included incorrect classes</a></li>
- <li><a
- href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=430974&amp;group_id=15278&amp;atid=115278">No
-UI update when re-run methods fail</a></li>
- </font>
+<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>
-<h2>
-<font color="#000000">Summary of Changes between 3.6 and 3.7</font></h2>
-<h3>
-<font color="#000000">GUI</font></h3>
+
+<h3>Extra Runners</h3>
+
<ul>
- <li>
- <font color="#000000">Eliminated warning when re-running tests when
-class loading checkbox is
-unchecked. There are legitimate reasons for doing this, so a warning
-didn't
-make much sense, and it was too obtrusive.</font></li>
- <li>
- <font color="#000000">Stopped reloading classes when running in
-VisualAge for Java.</font></li>
- <li>
- <font color="#000000">Print total number of tests as well as number
-of tests run so far (Swing
-only).</font></li>
+<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>
-<font color="#000000">Framework</font></h3>
+
+<h3>Theories</h3>
+
<ul>
- <li>
- <font color="#000000">Introduced Assert.assertTrue(boolean) and
-assertTrue(String, boolean) deprecated
-assert(boolean) and assert(String, boolean) in preparation for the
-assert
-keyword in Java 1.4. We plan to support native assertions when they are
-publicly available. You can either move to assertTrue() or wait for 1.4
-and delete parentheses as the syntax is e.g. "assert 2 == 3".</font></li>
- <li>
- <font color="#000000">Added accessors for TestCase.fName and
-TestSuite.fName.</font></li>
- <li>
- <font color="#000000">Added a no argument TestCase constructor to
-support serialization.</font></li>
- <li>
- <font color="#000000">Improved warnings when constructing
-TestSuites.</font></li>
+<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>
-<font color="#000000">Text Runner</font></h3>
+
+<h3>Development</h3>
+
<ul>
- <li>
- <font color="#000000">Made doRun() public so clients can create a
-text runner with a specified
-output stream and then run tests.</font></li>
+<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>
-<h3>
-<font color="#000000">Fixed Bugs (SourceForge Bug Tracker Ids)</font></h3>
-<font color="#000000">&nbsp;&nbsp;&nbsp; [420315] No trace when fail
-with message...
-<br>
-&nbsp;&nbsp;&nbsp; [419375] reload warning lags
-<br>
-&nbsp;&nbsp;&nbsp; [418849] Classloader warning too obtrusive
-<br>
-&nbsp;&nbsp;&nbsp; [417978] constructor stack trace, please
-<br>
-&nbsp;&nbsp;&nbsp; [415103] Reload checkbox should be ignored in VAJ
-<br>
-&nbsp;&nbsp;&nbsp; [414954] error reporting when invoking suite()
-<br>
-&nbsp;&nbsp;&nbsp; [407296] Make doRun() public
-<br>
-&nbsp;&nbsp;&nbsp; [227578] rmi callbacks fail since TestCase has no
-noArg constructor
-<br>
-&nbsp;&nbsp;&nbsp; [422603] Decorated decorators bug
-</font>
-<h2><font color="#000000">Summary of Changes between 3.5 and 3.6</font></h2>
-<h3>
-<font color="#000000">TestRunner</font></h3>
+
+<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>
- <font color="#000000">The UI test runners provide a check box to
-enable/disable the custom class
-loader. The user is warned when running a second test with the non
-loading
-class loader.</font></li>
- <li>
- <font color="#000000">Renames to address file name length
-limitation on MacOS:</font></li>
- <ul>
- <li>
- <font color="#000000">LoadingClassPathTestCollector -&gt;
-LoadingTestCollector</font></li>
- <li>
- <font color="#000000">SimpleClassPathTestCollector -&gt;
-SimpleTestCollector</font></li>
- </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>
-<h3>
-<font color="#000000">Framework</font></h3>
+
+<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>
- <font color="#000000">Added TestSuite.getName()</font></li>
+<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>
-<font color="#000000">Builds</font></h3>
+
+<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>
- <font color="#000000">Updated the build script for Ant 1.3.</font></li>
+<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>
-<h3>
-<font color="#000000">Fixed Bugs (SourceForge Bug Tracker Ids)</font></h3>
-<blockquote><font color="#000000">[ #229753 ] assertEquals on NaN and
-Infinity does not work
-correctly
- <br>
-[ #229287 ] Class Name too long "SimpleClassPathTestCollector"
- <br>
-[ #229609 ] Stack Filtering missing in textui.TesRunner
- <br>
-[ #229870 ] Clicking on ... after tests failed gives NPE
- <br>
-[ #229974 ] Incorrect icon shown for first element in Swing GUI
- <br>
-[ #230581 ] swingui.TestTreeModel: results of decorated testcases...
- <br>
-[ #230971 ] Make junit.extensions.TestDecorator.getTest() public
- <br>
-[ #231569 ] DocBug: JUnit Test Infected: Programmers Love Writing Tests
- <br>
-[ #232645 ] BaseTestRunner.getTest loses exception information
- <br>
-[ #233094 ] TestSuite masks exceptions
- <br>
-[ #410967 ] No icon provided for first test
- <br>
-[ #230745 ] ClassPathTestCollector sometimes lists classes in duplicate</font></blockquote>
-<h3>
-<font color="#000000">Documentation</font></h3>
+
+<h2>
+<a NAME="Summary of"></a>Summary of Changes in version 4.3.1</h2>
+<p>
<ul>
- <li>
- <font color="#000000">Added documentation about the <a
- href="doc/JUnitProperties.html">properties</a>
-supported by TestRunners.</font></li>
- <li>
- <font color="#000000">Updated the FAQ</font></li>
+<li>Bug fix: 4.3 introduced a
+<a href="https://sourceforge.net/tracker/?func=detail&atid=115278&aid=1684562&group_id=15278">bug</a>
+that caused a NullPointerException
+when comparing a null reference to a non-null reference in <tt>assertEquals</tt>.
+This has been fixed.
+<li>Bug fix: The binary jar for 4.3 <a href="https://sourceforge.net/tracker/?func=detail&atid=115278&aid=1686931&group_id=15278">accidentally</a> included the tests and sample code,
+which are now removed for a smaller download, but, as always, available from the
+full zip.
</ul>
+</p>
+
<h2>
-<font color="#000000">Summary of Changes between 3.4 and 3.5</font></h2>
-<h3>
-<font color="#000000">Framework</font></h3>
+<a NAME="Summary of"></a>Summary of Changes with version 4.3</h2>
+<p>
<ul>
- <li>
- <font color="#000000">Added TestSuite.addTestSuite(Class testClass)</font></li>
- <font color="#000000"><br>
-This method allows to create a TestSuite with a class containing test
-cases directly.
- <br>
-Instead of writing <b>suite.addTest(new TestSuite(AssertTest.class))
- </b>you
-can now write <b>suite.addTestSuite(AssertTest.class)</b>;
- <li>Added assertEquals methods for all primitive types: float,
-boolean, byte,
-char, int, short</li>
- <li>
-The signature of&nbsp; TestListeners.addFailure(Test test, Throwable t)</li>
- <br>
-was changed to addFailure(Test test, AssertionFailedError t)</font>
-</ul>
-<h3>
-<font color="#000000">TestRunner</font></h3>
+<li>Changes in array equality. Using <tt>assertEquals</tt> to compare array contents is now deprecated.
+In the future, <tt>assertEquals</tt> will revert to its pre-4.0 meaning of comparing objects based on
+Java's <tt>Object.equals</tt> semantics. To compare array contents, use the new, more reliable
+<tt>Assert.assertArrayEquals</tt> methods.
+<li>The <tt>@Ignore</tt> annotation can now be applied to classes, to ignore the entire class, instead of
+individual methods.
+<li>Originally, developers who wanted to use a static <tt>suite()</tt> method from JUnit 3.x with a JUnit 4.x
+runner had to annotate the class with <tt>@RunWith(AllTests.class)</tt>. In the common case, this requirement
+has been removed. However, when such a class is wrapped with a JUnit4TestAdapter (which we believe is rare), the
+results may not be as expected.
+<li>Improved error messages for array comparison("arrays first differed at element [1][0]")
+<li>Bug fix: Inaccessible base class is caught at test construction time.
+<li>Bug fix: Circular suites are caught at test construction time.
+<li>Bug fix: Test constructors that throw exceptions are reported correctly.
+<li><b>For committers and extenders</b>
<ul>
- <li>
- <font color="#000000">The Swing TestRunner provides an experimental
-feature to browse test classes.
-There is an additional browse ("...") button besides the suite combo.
-It
-shows a simple dialog to select a test class from a list. Different
-strategies
-to locate Test classes are supported and you can plug-in your own
-strategy.
-This allows to leverage functionality provided by an extension API of
-an
-integrated development environment (IDE). To define a custom test
-collector
-you 1) implement the <b>junit.runner.TestCollector </b>interface and
-2)
-add an entry to the <b>junit.properties</b> file with the key <b>TestCollectorClass</b>
-and the name of your TestCollector implementation class as the key:</font></li>
- <font color="#000000"><br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-TestCollectorClass=junit.swingui.LoadingClassPathTestCollector
- <br>
-This class has to be installed on the class path.
- <br>
-JUnit provides two different TestCollector implementations:
- </font>
- <ul>
- <li>
- <font color="#000000">simple
-(junit.runner.SimpleClassPathTestCollector) - considers all classes
-on the class path on the file system that contain "Test" in their name.
-Classes in JARs are not considered.</font></li>
- <li>
- <font color="#000000">loading
-(junit.runner.LoadingClassPathTestCollector) - loads all classes
-on the class path and tests whether the class is assignable from Test
-or
-has a static <b>suite</b> method.</font></li>
- </ul>
- <font color="#000000">By default the simple the test collector is
-used. The loading collector
-is more precise but much slower than the simple one. The loading
-collector
-doesn't scale up when many classes are available on the class path.
- <br>
- <b><font color="#ff0000">Notice</font></b>: that both TestCollectors
-assume that the class files reside are kept in the file system. This
-isn't
-case in VA/Java and they will not work there. A custom TestCollector is
-required for VA/Java.
- <li>The Swing TestRunner now provides an additional test result view
-that shows
-all tests of the executed test suite as a tree. The view shows the
-success
-status for each test. The view is shown as an additional tab in the
-TestRunner
-window. In previous versions of JUnit this view was shown in a separate
-window.</li>
- <li>
-The failure panels in the Swing and AWT TestRunners filter the
-exception
-stack trace so that only non-framework stack frames are shown.</li>
- <li>
-There is support to plug-in a custom failure panel that provides
-additional
-functionality like navigating from a failure to the source. To do so
-you
-implement the <b>junit.runner.FailureDetailView</b> interface and
-register
-the implementation class in the junit.properties file under the key <b>FailureViewClass</b>,
-for example</li>
- <br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-FailureViewClass=MyFailureViewClassName.
- <li>The Swing and AWT TestRunners now understand an additional
-command line
-argument "-noloading". When this argument is set then the standard
-system
-class loader is used to load classes. This is an alternative to setting
-the <b>loading</b> property to false in the junit.properties file.</li>
- <li>
-Swing TestRunner - the maximum test history length shown in the suite
-combo
-can be defined in the junit.properties file with the key <b>maxhistory</b>.</li>
- <li>
-BaseTestRunner.<b>getLoader</b>() is no longer a static method and can
-now be overridden in subclasses.</li>
- <li>
-BaseTestRunner removed dependency on JDK 1.2.</li>
- <li>
-Swing TestRunner - fixed the problem that a suite name was sometimes
-duplicated
-in the history combo.</li>
- <li>
-Swing TestRunner - the Run button is now the default button.</li>
- <li>
-Output string truncation can now be controlled by adding the <b>maxmessage</b>
-key with the desired maximum length to the junit.properties file.
-Setting
-maxmessage to -1 means no output truncation.</li>
- <li>
-The Text TestRunner now shows the summary at the very end so that you
-don't
-have to scroll back.</li>
- </font>
+<li>Sources now are in a separate "src" directory (this means a big break in the CVS history)
+<li>Improved documentation in <tt>Request</tt>, <tt>RunWith</tt>
</ul>
-<h3>
-<font color="#000000">Tests</font></h3>
-<ul>
- <li>
- <font color="#000000">TextRunnerTest now only depends on a nonzero
-status to indicate abnormal
-termination.</font></li>
- <li>
- <font color="#000000">TextRunnerTest now also passes on JDK 1.1.*.
-It uses the -classpath command
-line argument instead of -cp.</font></li>
</ul>
-<h3>
-<font color="#000000">Documentation</font></h3>
+</p>
+
+<h2>
+<a NAME="Summary of"></a>Summary of Changes with version 4.2</h2>
+<p>
<ul>
- <li>
- <font color="#000000">Add an FAQ entry about what to do when the
-junit tests provided with the
-distribution can't be found.</font></li>
+<li>Bug fix: Inaccessible base class is caught at test construction time.
+<li>Bug fix: Circular suites are caught at test construction time.
+<li>Improved error messages for array comparison("arrays first differed at element [1][0]")
+<li>Test constructors that throw exceptions are reported correctly.
</ul>
+</p>
+
+
<h2>
-<font color="#000000">Older Change Notes</font></h2>
-<blockquote>
- <li><font color="#000000">Changes between <a
- href="doc/changes34.html">2.1 and 3.4</a></font></li>
- <li>
- <font color="#000000">Changes between <a href="doc/changes21.html">1.0
-and 2.1</a></font></li>
-</blockquote>
+<a NAME="Summary of"></a>Summary of Changes with version 4.1</h2>
+<p>
+<ul>
+<li>Bug fix: listeners now get a correct test running time, rather than always being told 0 secs.
+<li>The @RunWith annotation is now inherited by subclasses:
+all subclasses of an abstract test class will be run by the same runner.
+<li>The build script fails if the JUnit unit tests fail
+<li>The faq has been updated
+<li>Javadoc has been improved, with more internal links, and package descriptions added (Thanks, Matthias Schmidt!)
+<li>An acknowledgements.txt file has been created to credit outside contributions
+<li>The <tt>Enclosed</tt> runner, which runs all of the static inner classes of a given class, has been added
+to <tt>org.junit.runners</tt>.
+</ul>
+</p>
+
+<h2>Summary of Changes with version 4.0</h2>
+<p>
+The architecture of JUnit 4.0 is a substantial departure from that of earlier releases.
+Instead of
+tagging test classes by subclassing junit.framework.TestCase and tagging test methods by
+starting their name with "test", you now tag test methods with the @Test annotation.
+</p>
+
+
<h2>
-<font color="#000000"><a name="Contents"></a>Contents of the Release</font></h2>
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr>
- <td><tt>README.html&nbsp;</tt></td>
- <td>this file</td>
- </tr>
- <tr>
- <td><tt>junit.jar</tt></td>
- <td>a jar file with the JUnit framework and&nbsp; tools&nbsp;</td>
- </tr>
- <tr>
- <td>src.jar</td>
- <td>a jar file with the source code of the junit framework</td>
- </tr>
- <tr>
- <td><tt>junit</tt></td>
- <td>the source code of the JUnit samples</td>
- </tr>
- <tr>
- <td><tt>&nbsp;&nbsp;&nbsp; samples</tt></td>
- <td>sample test cases</td>
- </tr>
- <tr>
- <td><tt>&nbsp;&nbsp;&nbsp; tests</tt></td>
- <td>test cases for JUnit itself</td>
- </tr>
- <tr>
- <td><tt>javadoc</tt></td>
- <td>javadoc generated documentation</td>
- </tr>
- <tr>
- <td><tt>doc</tt></td>
- <td>documentation and articles</td>
- </tr>
- </tbody>
+<a NAME="Contents"></a>Contents of the Release</h2>
+
+<table CELLSPACING=0 CELLPADDING=0 >
+<tr>
+<td><tt>README.html&nbsp;</tt></td>
+
+<td>this file</td>
+</tr>
+
+<tr>
+<td><tt>junit-4.6.jar</tt></td>
+
+<td>a jar file with the JUnit framework, bundled with the hamcrest-core-1.1 dependency.</td>
+</tr>
+
+<tr>
+<td><tt>junit-dep-4.6.jar</tt></td>
+
+<td>a jar file with the JUnit framework, unbundled from any external dependencies.
+Choosing to use this jar developers will need to also provide in the classpath a compatible version of external dependencies (ie hamcrest-core-1.1+)</td>
+</tr>
+
+<tr>
+<td><tt>junit-4.6-src.jar</tt></td>
+
+<td>a jar file with the source code of the JUnit framework</td>
+</tr>
+
+<tr>
+<td><tt>org/junit</tt></td>
+
+<td>the source code of the basic JUnit annotations and classes</td>
+</tr>
+
+<tr>
+<td><tt>&nbsp;&nbsp;&nbsp; samples</tt></td>
+
+<td>sample test cases</td>
+</tr>
+
+<tr>
+<td><tt>&nbsp;&nbsp;&nbsp; tests</tt></td>
+
+<td>test cases for JUnit itself</td>
+</tr>
+
+<tr>
+<td><tt>javadoc</tt></td>
+
+<td>javadoc generated documentation</td>
+</tr>
+
+<tr>
+<td><tt>doc</tt></td>
+
+<td>documentation and articles</td>
+</tr>
</table>
+
<h2>
-<font color="#000000"><a name="Installation"></a>Installation</font></h2>
-<font color="#000000">Below are the installation steps for installing
-JUnit:
-</font>
+<a NAME="Installation"></a>Installation</h2>
+Below are the installation steps for installing JUnit:
<ol>
- <li>
- <font color="#000000">unzip the junit.zip file</font></li>
- <li>
- <font color="#000000">add<i> </i><b>junit.jar</b> to the
-CLASSPATH. For example: <tt>set
-classpath=%classpath%;INSTALL_DIR\junit3\junit.jar</tt></font></li>
- <li>
- <font color="#000000">test the installation by using either the
-batch or the graphical TestRunner
-tool to run the tests that come with this release. All the tests should
-pass OK.</font></li>
- <font color="#000000"><br>
- <b><font color="#ff0000">Notice</font></b>: that the tests are not
-contained in the junit.jar but in the installation directory directly.
-Therefore make sure that the installation directory is on the class
-path
- </font>
- <ul>
- <li>
- <font color="#000000">for the batch TestRunner type:</font></li>
- <font color="#000000"><br>
- <tt>&nbsp;&nbsp;&nbsp; java junit.textui.TestRunner
-junit.samples.AllTests</tt>
- <li>for the graphical TestRunner type:</li>
- <br>
- <tt>&nbsp;&nbsp;&nbsp; java junit.awtui.TestRunner
-junit.samples.AllTests</tt>
- <li>for the Swing based graphical TestRunner type:</li>
- <br>
- <tt>&nbsp;&nbsp;&nbsp; java junit.swingui.TestRunner
-junit.samples.AllTests</tt></font>
- </ul>
+<li>
+unzip the junit4.6.zip file</li>
+
+<li>
+add<i> </i><b>junit-4.6.jar</b> to the CLASSPATH. For example:
+<tt> set classpath=%classpath%;INSTALL_DIR\junit-4.6.jar;INSTALL_DIR</tt></li>
+
+<li>
+test the installation by running <tt>java org.junit.runner.JUnitCore org.junit.tests.AllTests</tt></li>
+
+<br><b><font color="#FF0000">Notice</font></b>: that the tests are not
+contained in the junit-4.6.jar but in the installation directory directly.
+Therefore make sure that the installation directory is on the class path
</ol>
-<font color="#000000"><b><font color="#ff0000">Important</font></b>:
-don't install the junit.jar
+<b><font color="#FF0000">Important</font></b>: don't install junit-4.6.jar
into the extension directory of your JDK installation. If you do so the
test class on the files system will not be found.
-</font>
-<h2><font color="#000000"><a name="Getting"></a>Getting Started</font></h2>
-<font color="#000000">To get started with unit testing and JUnit read
-the Java Report article:
-<a href="doc/testinfected/testing.htm">Test
-Infected - Programmers Love Writing Tests</a>.
-<br>
-This article demonstrates the development process with JUnit in the
-context of multiple currency arithmetic. The corresponding source code
-is in junit\samples\money.
-</font>
-<p><font color="#000000">You find additional samples in the
-junit.samples package:
-</font></p>
+<h2>
+<a NAME="Getting"></a>Getting Started</h2>
+To get started with unit testing and JUnit read the article:
+<a href="doc/cookbook/cookbook.htm">JUnit Cookbook</a>.
+<br>This article describes basic test writing using JUnit 4.
+<p>You find additional samples in the org.junit.samples package:
<ul>
- <li>
- <font color="#000000">SimpleTest.java - some simple test cases</font></li>
- <li>
- <font color="#000000">VectorTest.java - test cases for
-java.util.Vector</font></li>
+<li>
+SimpleTest.java - some simple test cases</li>
+
+<li>
+VectorTest.java - test cases for java.util.Vector</li>
</ul>
+
<h2>
-<font color="#000000"><a name="Documentation"></a>Documentation</font></h2>
-<blockquote><font color="#000000"><a href="doc/cookbook/cookbook.htm">JUnit
-Cookbook</a>
- <br>
-&nbsp;&nbsp;&nbsp; A cookbook for implementing tests with JUnit.
- <br>
- <a href="doc/testinfected/testing.htm">Test Infected - Programmers
+<a NAME="Documentation"></a>Documentation</h2>
+
+<blockquote><a href="doc/cookbook/cookbook.htm">JUnit Cookbook</a>
+<br>&nbsp;&nbsp;&nbsp; A cookbook for implementing tests with JUnit.
+<br><a href="javadoc/index.html">Javadoc</a>
+<br>&nbsp;&nbsp;&nbsp; API documentation generated with javadoc.
+<br><a href="doc/faq/faq.htm">Frequently asked questions</a>
+<br>&nbsp;&nbsp;&nbsp; Some frequently asked questions about using JUnit.
+<br><a href="cpl-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.
+<blockquote>
+<br><a href="doc/testinfected/testing.htm">Test Infected - Programmers
Love Writing Tests</a>
- <br>
-&nbsp;&nbsp;&nbsp; An article demonstrating the development process
+<br>&nbsp;&nbsp;&nbsp; An article demonstrating the development process
with JUnit.
- <br>
- <a href="doc/cookstour/cookstour.htm">JUnit - A cooks tour</a>
- <br>
- <a href="javadoc/index.html">Javadoc</a>
- <br>
-&nbsp;&nbsp;&nbsp; API documentation generated with javadoc.
- <br>
- <a href="doc/faq/faq.htm">Frequently asked questions</a>
- <br>
-&nbsp;&nbsp;&nbsp; Some frequently asked questions about using JUnit.
- <br>
- <a href="doc/JUnitProperties.html">TestRunner Preference settings</a>
- <br>
-&nbsp;&nbsp;&nbsp; Describes the preferences settings that can be
-configured
-for the JUnit TestRunners.<br>
- <a href="cpl-v10.html">License</a>
- <br>
-&nbsp;&nbsp;&nbsp; The terms of the common public license used for
-JUnit.</font></blockquote>
-<h2>
-<font color="#000000"><a name="Extending"></a>Extending JUnit</font></h2>
-<font color="#000000">Examples of possible JUnit extensions can be
-found in the <tt>junit.extensions</tt>
-package:
-</font>
-<ul>
- <li>
- <font color="#000000"><a
- href="javadoc/junit/extensions/TestDecorator.html">TestDecorator</a>
-- A decorator for Test. You can use it as the base class for
-implementing
-decorators to extend test cases.</font></li>
- <li>
- <font color="#000000"><a
- href="javadoc/junit/extensions/ActiveTestSuite.html">ActiveTestSuite</a>
-- A TestSuite which runs each test in a separate thread and waits until
-they are all terminated.</font></li>
- <li>
- <font color="#000000"><a
- href="javadoc/junit/extensions/TestSetup.html">TestSetup</a> - A
-Decorator
-to set up and tear down additional fixture state. Subclass TestSetup
-and
-insert it into your tests when you want to set up additional state once
-before the tests are run.</font></li>
- <li>
- <font color="#000000"><a
- href="javadoc/junit/extensions/ExceptionTestCase.html">ExceptionTestCase</a>
-- A TestCase that expects a particular Exception to be thrown.</font></li>
-</ul>
-<hr width="100%">
-<!--webbot bot="HTMLMarkup" startspan --><font color="#000000"><a
- href="http://sourceforge.net"><img
- src="http://sourceforge.net/sflogo.php?group_id=15278" width="88"
- height="31" border="0" alt="SourceForge Logo"></a><!--webbot
-bot="HTMLMarkup" endspan --></font>
+<br><a href="doc/cookstour/cookstour.htm">JUnit - A cooks tour</a>
+</blockquote>
+
+<hr WIDTH="100%">
+<!--webbot bot="HTMLMarkup" startspan --><a href="http://sourceforge.net"><IMG
+ src="http://sourceforge.net/sflogo.php?group_id=15278"
+ width="88" height="31" border="0" alt="SourceForge Logo"></a><!--webbot
+bot="HTMLMarkup" endspan -->
</body>
</html>
diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF
deleted file mode 100644
index e171a01..0000000
--- a/src/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,4 +0,0 @@
-Manifest-Version: 1.0
-Ant-Version: Apache Ant 1.6.5
-Created-By: 1.4.2_10-b03 (Sun Microsystems Inc.)
-
diff --git a/src/junit/awtui/AboutDialog.java b/src/junit/awtui/AboutDialog.java
deleted file mode 100644
index 38f57bb..0000000
--- a/src/junit/awtui/AboutDialog.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package junit.awtui;
-
-import java.awt.Button;
-import java.awt.Dialog;
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Label;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-
-import junit.runner.Version;
-
-class AboutDialog extends Dialog {
- public AboutDialog(Frame parent) {
- super(parent);
-
- setResizable(false);
- setLayout(new GridBagLayout());
- setSize(330, 138);
- setTitle("About");
-
- Button button= new Button("Close");
- button.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- dispose();
- }
- }
- );
-
- Label label1= new Label("JUnit");
- label1.setFont(new Font("dialog", Font.PLAIN, 36));
-
- Label label2= new Label("JUnit "+Version.id()+ " by Kent Beck and Erich Gamma");
- label2.setFont(new Font("dialog", Font.PLAIN, 14));
-
- Logo logo= new Logo();
-
- GridBagConstraints constraintsLabel1= new GridBagConstraints();
- constraintsLabel1.gridx = 3; constraintsLabel1.gridy = 0;
- constraintsLabel1.gridwidth = 1; constraintsLabel1.gridheight = 1;
- constraintsLabel1.anchor = GridBagConstraints.CENTER;
- add(label1, constraintsLabel1);
-
- GridBagConstraints constraintsLabel2= new GridBagConstraints();
- constraintsLabel2.gridx = 2; constraintsLabel2.gridy = 1;
- constraintsLabel2.gridwidth = 2; constraintsLabel2.gridheight = 1;
- constraintsLabel2.anchor = GridBagConstraints.CENTER;
- add(label2, constraintsLabel2);
-
- GridBagConstraints constraintsButton1= new GridBagConstraints();
- constraintsButton1.gridx = 2; constraintsButton1.gridy = 2;
- constraintsButton1.gridwidth = 2; constraintsButton1.gridheight = 1;
- constraintsButton1.anchor = GridBagConstraints.CENTER;
- constraintsButton1.insets= new Insets(8, 0, 8, 0);
- add(button, constraintsButton1);
-
- GridBagConstraints constraintsLogo1= new GridBagConstraints();
- constraintsLogo1.gridx = 2; constraintsLogo1.gridy = 0;
- constraintsLogo1.gridwidth = 1; constraintsLogo1.gridheight = 1;
- constraintsLogo1.anchor = GridBagConstraints.CENTER;
- add(logo, constraintsLogo1);
-
- addWindowListener(
- new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- dispose();
- }
- }
- );
- }
-} \ No newline at end of file
diff --git a/src/junit/awtui/Logo.java b/src/junit/awtui/Logo.java
deleted file mode 100644
index 4cc3b4f..0000000
--- a/src/junit/awtui/Logo.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package junit.awtui;
-
-import java.awt.Canvas;
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.MediaTracker;
-import java.awt.SystemColor;
-import java.awt.Toolkit;
-import java.awt.image.ImageProducer;
-import java.net.URL;
-
-import junit.runner.BaseTestRunner;
-
-public class Logo extends Canvas {
- private Image fImage;
- private int fWidth;
- private int fHeight;
-
- public Logo() {
- fImage= loadImage("logo.gif");
- MediaTracker tracker= new MediaTracker(this);
- tracker.addImage(fImage, 0);
- try {
- tracker.waitForAll();
- } catch (Exception e) {
- }
-
- if (fImage != null) {
- fWidth= fImage.getWidth(this);
- fHeight= fImage.getHeight(this);
- } else {
- fWidth= 20;
- fHeight= 20;
- }
- setSize(fWidth, fHeight);
- }
-
- public Image loadImage(String name) {
- Toolkit toolkit= Toolkit.getDefaultToolkit();
- try {
- URL url= BaseTestRunner.class.getResource(name);
- return toolkit.createImage((ImageProducer) url.getContent());
- } catch (Exception ex) {
- }
- return null;
- }
-
- public void paint(Graphics g) {
- paintBackground(g);
- if (fImage != null)
- g.drawImage(fImage, 0, 0, fWidth, fHeight, this);
- }
-
- public void paintBackground( java.awt.Graphics g) {
- g.setColor(SystemColor.control);
- g.fillRect(0, 0, getBounds().width, getBounds().height);
- }
-} \ No newline at end of file
diff --git a/src/junit/awtui/ProgressBar.java b/src/junit/awtui/ProgressBar.java
deleted file mode 100644
index 03e7ec2..0000000
--- a/src/junit/awtui/ProgressBar.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package junit.awtui;
-
-import java.awt.Canvas;
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Rectangle;
-import java.awt.SystemColor;
-
-public class ProgressBar extends Canvas {
- public boolean fError= false;
- public int fTotal= 0;
- public int fProgress= 0;
- public int fProgressX= 0;
-
- public ProgressBar() {
- super();
- setSize(20, 30);
- }
-
- private Color getStatusColor() {
- if (fError)
- return Color.red;
- return Color.green;
- }
-
- public void paint(Graphics g) {
- paintBackground(g);
- paintStatus(g);
- }
-
- public void paintBackground(Graphics g) {
- g.setColor(SystemColor.control);
- Rectangle r= getBounds();
- g.fillRect(0, 0, r.width, r.height);
- g.setColor(Color.darkGray);
- g.drawLine(0, 0, r.width-1, 0);
- g.drawLine(0, 0, 0, r.height-1);
- g.setColor(Color.white);
- g.drawLine(r.width-1, 0, r.width-1, r.height-1);
- g.drawLine(0, r.height-1, r.width-1, r.height-1);
- }
-
- public void paintStatus(Graphics g) {
- g.setColor(getStatusColor());
- Rectangle r= new Rectangle(0, 0, fProgressX, getBounds().height);
- g.fillRect(1, 1, r.width-1, r.height-2);
- }
-
- private void paintStep(int startX, int endX) {
- repaint(startX, 1, endX-startX, getBounds().height-2);
- }
-
- public void reset() {
- fProgressX= 1;
- fProgress= 0;
- fError= false;
- paint(getGraphics());
- }
-
- public int scale(int value) {
- if (fTotal > 0)
- return Math.max(1, value*(getBounds().width-1)/fTotal);
- return value;
- }
-
- public void setBounds(int x, int y, int w, int h) {
- super.setBounds(x, y, w, h);
- fProgressX= scale(fProgress);
- }
-
- public void start(int total) {
- fTotal= total;
- reset();
- }
-
- public void step(boolean successful) {
- fProgress++;
- int x= fProgressX;
-
- fProgressX= scale(fProgress);
-
- if (!fError && !successful) {
- fError= true;
- x= 1;
- }
- paintStep(x, fProgressX);
- }
-} \ No newline at end of file
diff --git a/src/junit/awtui/TestRunner.java b/src/junit/awtui/TestRunner.java
deleted file mode 100644
index cb735d5..0000000
--- a/src/junit/awtui/TestRunner.java
+++ /dev/null
@@ -1,571 +0,0 @@
-package junit.awtui;
-
-import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.Checkbox;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.GridLayout;
-import java.awt.Image;
-import java.awt.Insets;
-import java.awt.Label;
-import java.awt.List;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.MenuItem;
-import java.awt.Panel;
-import java.awt.SystemColor;
-import java.awt.TextArea;
-import java.awt.TextField;
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.TextEvent;
-import java.awt.event.TextListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.image.ImageProducer;
-import java.util.Vector;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestResult;
-import junit.framework.TestSuite;
-import junit.runner.BaseTestRunner;
-import junit.runner.TestRunListener;
-
-/**
- * An AWT based user interface to run tests.
- * Enter the name of a class which either provides a static
- * suite method or is a subclass of TestCase.
- * <pre>
- * Synopsis: java junit.awtui.TestRunner [-noloading] [TestCase]
- * </pre>
- * TestRunner takes as an optional argument the name of the testcase class to be run.
- */
- public class TestRunner extends BaseTestRunner {
- protected Frame fFrame;
- protected Vector fExceptions;
- protected Vector fFailedTests;
- protected Thread fRunner;
- protected TestResult fTestResult;
-
- protected TextArea fTraceArea;
- protected TextField fSuiteField;
- protected Button fRun;
- protected ProgressBar fProgressIndicator;
- protected List fFailureList;
- protected Logo fLogo;
- protected Label fNumberOfErrors;
- protected Label fNumberOfFailures;
- protected Label fNumberOfRuns;
- protected Button fQuitButton;
- protected Button fRerunButton;
- protected TextField fStatusLine;
- protected Checkbox fUseLoadingRunner;
-
- protected static final Font PLAIN_FONT= new Font("dialog", Font.PLAIN, 12);
- private static final int GAP= 4;
-
- public TestRunner() {
- }
-
- private void about() {
- AboutDialog about= new AboutDialog(fFrame);
- about.setModal(true);
- about.setLocation(300, 300);
- about.setVisible(true);
- }
-
- public void testStarted(String testName) {
- showInfo("Running: "+testName);
- }
-
- public void testEnded(String testName) {
- setLabelValue(fNumberOfRuns, fTestResult.runCount());
- synchronized(this) {
- fProgressIndicator.step(fTestResult.wasSuccessful());
- }
- }
-
- public void testFailed(int status, Test test, Throwable t) {
- switch (status) {
- case TestRunListener.STATUS_ERROR:
- fNumberOfErrors.setText(Integer.toString(fTestResult.errorCount()));
- appendFailure("Error", test, t);
- break;
- case TestRunListener.STATUS_FAILURE:
- fNumberOfFailures.setText(Integer.toString(fTestResult.failureCount()));
- appendFailure("Failure", test, t);
- break;
- }
- }
-
- protected void addGrid(Panel p, Component co, int x, int y, int w, int fill, double wx, int anchor) {
- GridBagConstraints c= new GridBagConstraints();
- c.gridx= x; c.gridy= y;
- c.gridwidth= w;
- c.anchor= anchor;
- c.weightx= wx;
- c.fill= fill;
- if (fill == GridBagConstraints.BOTH || fill == GridBagConstraints.VERTICAL)
- c.weighty= 1.0;
- c.insets= new Insets(y == 0 ? GAP : 0, x == 0 ? GAP : 0, GAP, GAP);
- p.add(co, c);
- }
-
- private void appendFailure(String kind, Test test, Throwable t) {
- kind+= ": " + test;
- String msg= t.getMessage();
- if (msg != null) {
- kind+= ":" + truncate(msg);
- }
- fFailureList.add(kind);
- fExceptions.addElement(t);
- fFailedTests.addElement(test);
- if (fFailureList.getItemCount() == 1) {
- fFailureList.select(0);
- failureSelected();
- }
- }
- /**
- * Creates the JUnit menu. Clients override this
- * method to add additional menu items.
- */
- protected Menu createJUnitMenu() {
- Menu menu= new Menu("JUnit");
- MenuItem mi= new MenuItem("About...");
- mi.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent event) {
- about();
- }
- }
- );
- menu.add(mi);
-
- menu.addSeparator();
- mi= new MenuItem("Exit");
- mi.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent event) {
- System.exit(0);
- }
- }
- );
- menu.add(mi);
- return menu;
- }
-
- protected void createMenus(MenuBar mb) {
- mb.add(createJUnitMenu());
- }
- protected TestResult createTestResult() {
- return new TestResult();
- }
-
- protected Frame createUI(String suiteName) {
- Frame frame= new Frame("JUnit");
- Image icon= loadFrameIcon();
- if (icon != null)
- frame.setIconImage(icon);
-
- frame.setLayout(new BorderLayout(0, 0));
- frame.setBackground(SystemColor.control);
- final Frame finalFrame= frame;
-
- frame.addWindowListener(
- new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- finalFrame.dispose();
- System.exit(0);
- }
- }
- );
-
- MenuBar mb = new MenuBar();
- createMenus(mb);
- frame.setMenuBar(mb);
-
- //---- first section
- Label suiteLabel= new Label("Test class name:");
-
- fSuiteField= new TextField(suiteName != null ? suiteName : "");
- fSuiteField.selectAll();
- fSuiteField.requestFocus();
- fSuiteField.setFont(PLAIN_FONT);
- fSuiteField.setColumns(40);
- fSuiteField.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- runSuite();
- }
- }
- );
- fSuiteField.addTextListener(
- new TextListener() {
- public void textValueChanged(TextEvent e) {
- fRun.setEnabled(fSuiteField.getText().length() > 0);
- fStatusLine.setText("");
- }
- }
- );
- fRun= new Button("Run");
- fRun.setEnabled(false);
- fRun.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- runSuite();
- }
- }
- );
- boolean useLoader= useReloadingTestSuiteLoader();
- fUseLoadingRunner= new Checkbox("Reload classes every run", useLoader);
- if (inVAJava())
- fUseLoadingRunner.setVisible(false);
-
- //---- second section
- fProgressIndicator= new ProgressBar();
-
- //---- third section
- fNumberOfErrors= new Label("0000", Label.RIGHT);
- fNumberOfErrors.setText("0");
- fNumberOfErrors.setFont(PLAIN_FONT);
-
- fNumberOfFailures= new Label("0000", Label.RIGHT);
- fNumberOfFailures.setText("0");
- fNumberOfFailures.setFont(PLAIN_FONT);
-
- fNumberOfRuns= new Label("0000", Label.RIGHT);
- fNumberOfRuns.setText("0");
- fNumberOfRuns.setFont(PLAIN_FONT);
-
- Panel numbersPanel= createCounterPanel();
-
- //---- fourth section
- Label failureLabel= new Label("Errors and Failures:");
-
- fFailureList= new List(5);
- fFailureList.addItemListener(
- new ItemListener() {
- public void itemStateChanged(ItemEvent e) {
- failureSelected();
- }
- }
- );
- fRerunButton= new Button("Run");
- fRerunButton.setEnabled(false);
- fRerunButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- rerun();
- }
- }
- );
-
- Panel failedPanel= new Panel(new GridLayout(0, 1, 0, 2));
- failedPanel.add(fRerunButton);
-
- fTraceArea= new TextArea();
- fTraceArea.setRows(5);
- fTraceArea.setColumns(60);
-
- //---- fifth section
- fStatusLine= new TextField();
- fStatusLine.setFont(PLAIN_FONT);
- fStatusLine.setEditable(false);
- fStatusLine.setForeground(Color.red);
-
- fQuitButton= new Button("Exit");
- fQuitButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- System.exit(0);
- }
- }
- );
-
- // ---------
- fLogo= new Logo();
-
- //---- overall layout
- Panel panel= new Panel(new GridBagLayout());
-
- addGrid(panel, suiteLabel, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
-
- addGrid(panel, fSuiteField, 0, 1, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
- addGrid(panel, fRun, 2, 1, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
- addGrid(panel, fUseLoadingRunner, 0, 2, 2, GridBagConstraints.NONE, 1.0, GridBagConstraints.WEST);
- addGrid(panel, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
- addGrid(panel, fLogo, 2, 3, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.NORTH);
-
- addGrid(panel, numbersPanel, 0, 4, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
-
- addGrid(panel, failureLabel, 0, 5, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
- addGrid(panel, fFailureList, 0, 6, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST);
- addGrid(panel, failedPanel, 2, 6, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
- addGrid(panel, fTraceArea, 0, 7, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST);
-
- addGrid(panel, fStatusLine, 0, 8, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.CENTER);
- addGrid(panel, fQuitButton, 2, 8, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
-
- frame.add(panel, BorderLayout.CENTER);
- frame.pack();
- return frame;
- }
-
- protected Panel createCounterPanel() {
- Panel numbersPanel= new Panel(new GridBagLayout());
- addToCounterPanel(
- numbersPanel,
- new Label("Runs:"),
- 0, 0, 1, 1, 0.0, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.NONE,
- new Insets(0, 0, 0, 0)
- );
- addToCounterPanel(
- numbersPanel,
- fNumberOfRuns,
- 1, 0, 1, 1, 0.33, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
- new Insets(0, 8, 0, 40)
- );
- addToCounterPanel(
- numbersPanel,
- new Label("Errors:"),
- 2, 0, 1, 1, 0.0, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.NONE,
- new Insets(0, 8, 0, 0)
- );
- addToCounterPanel(
- numbersPanel,
- fNumberOfErrors,
- 3, 0, 1, 1, 0.33, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
- new Insets(0, 8, 0, 40)
- );
- addToCounterPanel(
- numbersPanel,
- new Label("Failures:"),
- 4, 0, 1, 1, 0.0, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.NONE,
- new Insets(0, 8, 0, 0)
- );
- addToCounterPanel(
- numbersPanel,
- fNumberOfFailures,
- 5, 0, 1, 1, 0.33, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
- new Insets(0, 8, 0, 0)
- );
- return numbersPanel;
- }
-
- private void addToCounterPanel(Panel counter, Component comp,
- int gridx, int gridy, int gridwidth, int gridheight,
- double weightx, double weighty,
- int anchor, int fill,
- Insets insets) {
-
- GridBagConstraints constraints= new GridBagConstraints();
- constraints.gridx= gridx;
- constraints.gridy= gridy;
- constraints.gridwidth= gridwidth;
- constraints.gridheight= gridheight;
- constraints.weightx= weightx;
- constraints.weighty= weighty;
- constraints.anchor= anchor;
- constraints.fill= fill;
- constraints.insets= insets;
- counter.add(comp, constraints);
- }
-
-
- public void failureSelected() {
- fRerunButton.setEnabled(isErrorSelected());
- showErrorTrace();
- }
-
- private boolean isErrorSelected() {
- return fFailureList.getSelectedIndex() != -1;
- }
-
- private Image loadFrameIcon() {
- Toolkit toolkit= Toolkit.getDefaultToolkit();
- try {
- java.net.URL url= BaseTestRunner.class.getResource("smalllogo.gif");
- return toolkit.createImage((ImageProducer) url.getContent());
- } catch (Exception ex) {
- }
- return null;
- }
-
- public Thread getRunner() {
- return fRunner;
- }
-
- public static void main(String[] args) {
- new TestRunner().start(args);
- }
-
- public static void run(Class test) {
- String args[]= { test.getName() };
- main(args);
- }
-
- public void rerun() {
- int index= fFailureList.getSelectedIndex();
- if (index == -1)
- return;
-
- Test test= (Test)fFailedTests.elementAt(index);
- rerunTest(test);
- }
-
- private void rerunTest(Test test) {
- if (!(test instanceof TestCase)) {
- showInfo("Could not reload "+ test.toString());
- return;
- }
- Test reloadedTest= null;
- TestCase rerunTest= (TestCase)test;
- try {
- Class reloadedTestClass= getLoader().reload(test.getClass());
- reloadedTest= TestSuite.createTest(reloadedTestClass, rerunTest.getName());
- } catch(Exception e) {
- showInfo("Could not reload "+ test.toString());
- return;
- }
- TestResult result= new TestResult();
- reloadedTest.run(result);
-
- String message= reloadedTest.toString();
- if(result.wasSuccessful())
- showInfo(message+" was successful");
- else if (result.errorCount() == 1)
- showStatus(message+" had an error");
- else
- showStatus(message+" had a failure");
- }
-
- protected void reset() {
- setLabelValue(fNumberOfErrors, 0);
- setLabelValue(fNumberOfFailures, 0);
- setLabelValue(fNumberOfRuns, 0);
- fProgressIndicator.reset();
- fRerunButton.setEnabled(false);
- fFailureList.removeAll();
- fExceptions= new Vector(10);
- fFailedTests= new Vector(10);
- fTraceArea.setText("");
-
- }
-
- protected void runFailed(String message) {
- showStatus(message);
- fRun.setLabel("Run");
- fRunner= null;
- }
-
- synchronized public void runSuite() {
- if (fRunner != null && fTestResult != null) {
- fTestResult.stop();
- } else {
- setLoading(shouldReload());
- fRun.setLabel("Stop");
- showInfo("Initializing...");
- reset();
-
- showInfo("Load Test Case...");
-
- final Test testSuite= getTest(fSuiteField.getText());
- if (testSuite != null) {
- fRunner= new Thread() {
- public void run() {
- fTestResult= createTestResult();
- fTestResult.addListener(TestRunner.this);
- fProgressIndicator.start(testSuite.countTestCases());
- showInfo("Running...");
-
- long startTime= System.currentTimeMillis();
- testSuite.run(fTestResult);
-
- if (fTestResult.shouldStop()) {
- showStatus("Stopped");
- } else {
- long endTime= System.currentTimeMillis();
- long runTime= endTime-startTime;
- showInfo("Finished: " + elapsedTimeAsString(runTime) + " seconds");
- }
- fTestResult= null;
- fRun.setLabel("Run");
- fRunner= null;
- System.gc();
- }
- };
- fRunner.start();
- }
- }
- }
-
- private boolean shouldReload() {
- return !inVAJava() && fUseLoadingRunner.getState();
- }
-
- private void setLabelValue(Label label, int value) {
- label.setText(Integer.toString(value));
- label.invalidate();
- label.getParent().validate();
-
- }
-
- public void setSuiteName(String suite) {
- fSuiteField.setText(suite);
- }
-
- private void showErrorTrace() {
- int index= fFailureList.getSelectedIndex();
- if (index == -1)
- return;
-
- Throwable t= (Throwable) fExceptions.elementAt(index);
- fTraceArea.setText(getFilteredTrace(t));
- }
-
-
- private void showInfo(String message) {
- fStatusLine.setFont(PLAIN_FONT);
- fStatusLine.setForeground(Color.black);
- fStatusLine.setText(message);
- }
-
- protected void clearStatus() {
- showStatus("");
- }
-
- private void showStatus(String status) {
- fStatusLine.setFont(PLAIN_FONT);
- fStatusLine.setForeground(Color.red);
- fStatusLine.setText(status);
- }
- /**
- * Starts the TestRunner
- */
- public void start(String[] args) {
- String suiteName= processArguments(args);
- fFrame= createUI(suiteName);
- fFrame.setLocation(200, 200);
- fFrame.setVisible(true);
-
- if (suiteName != null) {
- setSuiteName(suiteName);
- runSuite();
- }
- }
-} \ No newline at end of file
diff --git a/src/junit/extensions/ActiveTestSuite.java b/src/junit/extensions/ActiveTestSuite.java
index 9fc4edd..0623565 100644
--- a/src/junit/extensions/ActiveTestSuite.java
+++ b/src/junit/extensions/ActiveTestSuite.java
@@ -1,6 +1,7 @@
package junit.extensions;
import junit.framework.Test;
+import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
@@ -16,7 +17,7 @@ public class ActiveTestSuite extends TestSuite {
public ActiveTestSuite() {
}
- public ActiveTestSuite(Class theClass) {
+ public ActiveTestSuite(Class<? extends TestCase> theClass) {
super(theClass);
}
@@ -24,18 +25,21 @@ public class ActiveTestSuite extends TestSuite {
super (name);
}
- public ActiveTestSuite(Class theClass, String name) {
+ public ActiveTestSuite(Class<? extends TestCase> theClass, String name) {
super(theClass, name);
}
+ @Override
public void run(TestResult result) {
fActiveTestDeathCount= 0;
super.run(result);
waitUntilFinished();
}
+ @Override
public void runTest(final Test test, final TestResult result) {
Thread t= new Thread() {
+ @Override
public void run() {
try {
// inlined due to limitation in VA/Java
diff --git a/src/junit/extensions/ExceptionTestCase.java b/src/junit/extensions/ExceptionTestCase.java
deleted file mode 100644
index 7004085..0000000
--- a/src/junit/extensions/ExceptionTestCase.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package junit.extensions;
-
-import junit.framework.TestCase;
-
-/**
- * A TestCase that expects an Exception of class fExpected to be thrown.
- * The other way to check that an expected exception is thrown is:
- * <pre>
- * try {
- * shouldThrow();
- * }
- * catch (SpecialException e) {
- * return;
- * }
- * fail("Expected SpecialException");
- * </pre>
- *
- * To use ExceptionTestCase, create a TestCase like:
- * <pre>
- * new ExceptionTestCase("testShouldThrow", SpecialException.class);
- * </pre>
- */
-public class ExceptionTestCase extends TestCase {
- Class fExpected;
-
- public ExceptionTestCase(String name, Class exception) {
- super(name);
- fExpected= exception;
- }
- /**
- * Execute the test method expecting that an Exception of
- * class fExpected or one of its subclasses will be thrown
- */
- protected void runTest() throws Throwable {
- try {
- super.runTest();
- }
- catch (Exception e) {
- if (fExpected.isAssignableFrom(e.getClass()))
- return;
- else
- throw e;
- }
- fail("Expected exception " + fExpected);
- }
-} \ No newline at end of file
diff --git a/src/junit/extensions/RepeatedTest.java b/src/junit/extensions/RepeatedTest.java
index be5c439..3b687a5 100644
--- a/src/junit/extensions/RepeatedTest.java
+++ b/src/junit/extensions/RepeatedTest.java
@@ -5,20 +5,24 @@ import junit.framework.TestResult;
/**
* A Decorator that runs a test repeatedly.
- *
+ *
*/
-public class RepeatedTest extends TestDecorator {
+public class RepeatedTest extends TestDecorator {
private int fTimesRepeat;
public RepeatedTest(Test test, int repeat) {
super(test);
if (repeat < 0)
- throw new IllegalArgumentException("Repetition count must be > 0");
+ throw new IllegalArgumentException("Repetition count must be >= 0");
fTimesRepeat= repeat;
}
+
+ @Override
public int countTestCases() {
- return super.countTestCases()*fTimesRepeat;
+ return super.countTestCases() * fTimesRepeat;
}
+
+ @Override
public void run(TestResult result) {
for (int i= 0; i < fTimesRepeat; i++) {
if (result.shouldStop())
@@ -26,7 +30,9 @@ public class RepeatedTest extends TestDecorator {
super.run(result);
}
}
+
+ @Override
public String toString() {
- return super.toString()+"(repeated)";
+ return super.toString() + "(repeated)";
}
} \ No newline at end of file
diff --git a/src/junit/extensions/TestDecorator.java b/src/junit/extensions/TestDecorator.java
index 2111e8f..d9ae474 100644
--- a/src/junit/extensions/TestDecorator.java
+++ b/src/junit/extensions/TestDecorator.java
@@ -5,11 +5,10 @@ import junit.framework.Test;
import junit.framework.TestResult;
/**
- * A Decorator for Tests. Use TestDecorator as the base class
- * for defining new test decorators. Test decorator subclasses
- * can be introduced to add behaviour before or after a test
- * is run.
- *
+ * A Decorator for Tests. Use TestDecorator as the base class for defining new
+ * test decorators. Test decorator subclasses can be introduced to add behaviour
+ * before or after a test is run.
+ *
*/
public class TestDecorator extends Assert implements Test {
protected Test fTest;
@@ -17,19 +16,23 @@ public class TestDecorator extends Assert implements Test {
public TestDecorator(Test test) {
fTest= test;
}
+
/**
* The basic run behaviour.
*/
public void basicRun(TestResult result) {
fTest.run(result);
}
+
public int countTestCases() {
return fTest.countTestCases();
}
+
public void run(TestResult result) {
basicRun(result);
}
+ @Override
public String toString() {
return fTest.toString();
}
diff --git a/src/junit/extensions/TestSetup.java b/src/junit/extensions/TestSetup.java
index 9ee8b05..00dcd21 100644
--- a/src/junit/extensions/TestSetup.java
+++ b/src/junit/extensions/TestSetup.java
@@ -5,15 +5,17 @@ import junit.framework.Test;
import junit.framework.TestResult;
/**
- * A Decorator to set up and tear down additional fixture state.
- * Subclass TestSetup and insert it into your tests when you want
- * to set up additional state once before the tests are run.
+ * A Decorator to set up and tear down additional fixture state. Subclass
+ * TestSetup and insert it into your tests when you want to set up additional
+ * state once before the tests are run.
*/
public class TestSetup extends TestDecorator {
public TestSetup(Test test) {
super(test);
}
+
+ @Override
public void run(final TestResult result) {
Protectable p= new Protectable() {
public void protect() throws Exception {
@@ -24,15 +26,16 @@ public class TestSetup extends TestDecorator {
};
result.runProtected(this, p);
}
+
/**
- * Sets up the fixture. Override to set up additional fixture
- * state.
+ * Sets up the fixture. Override to set up additional fixture state.
*/
protected void setUp() throws Exception {
}
+
/**
- * Tears down the fixture. Override to tear down the additional
- * fixture state.
+ * Tears down the fixture. Override to tear down the additional fixture
+ * state.
*/
protected void tearDown() throws Exception {
}
diff --git a/src/junit/extensions/package-info.java b/src/junit/extensions/package-info.java
new file mode 100644
index 0000000..a1c5bb4
--- /dev/null
+++ b/src/junit/extensions/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides extended functionality for JUnit v3.x.
+ */
+package junit.extensions; \ No newline at end of file
diff --git a/src/junit/framework/Assert.java b/src/junit/framework/Assert.java
index ec6e838..3dcc23d 100644
--- a/src/junit/framework/Assert.java
+++ b/src/junit/framework/Assert.java
@@ -44,6 +44,9 @@ public class Assert {
* Fails a test with the given message.
*/
static public void fail(String message) {
+ if (message == null) {
+ throw new AssertionFailedError();
+ }
throw new AssertionFailedError(message);
}
/**
@@ -78,7 +81,8 @@ public class Assert {
return;
if (expected != null && expected.equals(actual))
return;
- throw new ComparisonFailure(message, expected, actual);
+ String cleanMessage= message == null ? "" : message;
+ throw new ComparisonFailure(cleanMessage, expected, actual);
}
/**
* Asserts that two Strings are equal.
@@ -105,18 +109,15 @@ public class Assert {
assertEquals(null, expected, actual, delta);
}
/**
- * Asserts that two floats are equal concerning a delta. If they are not
- * an AssertionFailedError is thrown with the given message. If the expected
- * value is infinity then the delta value is ignored.
+ * Asserts that two floats are equal concerning a positive delta. If they
+ * are not an AssertionFailedError is thrown with the given message. If the
+ * expected value is infinity then the delta value is ignored.
*/
static public void assertEquals(String message, float expected, float actual, float delta) {
- // handle infinity specially since subtracting to infinite values gives NaN and the
- // the following test fails
- if (Float.isInfinite(expected)) {
- if (!(expected == actual))
+ if (Float.compare(expected, actual) == 0)
+ return;
+ if (!(Math.abs(expected - actual) <= delta))
failNotEquals(message, new Float(expected), new Float(actual));
- } else if (!(Math.abs(expected-actual) <= delta))
- failNotEquals(message, new Float(expected), new Float(actual));
}
/**
* Asserts that two floats are equal concerning a delta. If the expected
@@ -217,10 +218,16 @@ public class Assert {
assertTrue(message, object != null);
}
/**
- * Asserts that an object is null.
+ * Asserts that an object is null. If it isn't an {@link AssertionError} is
+ * thrown.
+ * Message contains: Expected: <null> but was: object
+ *
+ * @param object
+ * Object to check or <code>null</code>
*/
static public void assertNull(Object object) {
- assertNull(null, object);
+ String message = "Expected: <null> but was: " + String.valueOf(object);
+ assertNull(message, object);
}
/**
* Asserts that an object is null. If it is not
@@ -280,9 +287,9 @@ public class Assert {
fail(format(message, expected, actual));
}
- static String format(String message, Object expected, Object actual) {
+ public static String format(String message, Object expected, Object actual) {
String formatted= "";
- if (message != null)
+ if (message != null && message.length() > 0)
formatted= message+" ";
return formatted+"expected:<"+expected+"> but was:<"+actual+">";
}
diff --git a/src/junit/framework/AssertionFailedError.java b/src/junit/framework/AssertionFailedError.java
index b041f06..0d7802c 100644
--- a/src/junit/framework/AssertionFailedError.java
+++ b/src/junit/framework/AssertionFailedError.java
@@ -3,13 +3,18 @@ package junit.framework;
/**
* Thrown when an assertion failed.
*/
-public class AssertionFailedError extends Error {
+public class AssertionFailedError extends AssertionError {
private static final long serialVersionUID= 1L;
-
- public AssertionFailedError () {
+
+ public AssertionFailedError() {
+ }
+
+ public AssertionFailedError(String message) {
+ super(defaultString(message));
}
- public AssertionFailedError (String message) {
- super (message);
+
+ private static String defaultString(String message) {
+ return message == null ? "" : message;
}
} \ No newline at end of file
diff --git a/src/junit/framework/ComparisonFailure.java b/src/junit/framework/ComparisonFailure.java
index c31068f..5077993 100644
--- a/src/junit/framework/ComparisonFailure.java
+++ b/src/junit/framework/ComparisonFailure.java
@@ -28,8 +28,9 @@ public class ComparisonFailure extends AssertionFailedError {
* Returns "..." in place of common prefix and "..." in
* place of common suffix between expected and actual.
*
- * @see java.lang.Throwable#getMessage()
+ * @see Throwable#getMessage()
*/
+ @Override
public String getMessage() {
return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage());
}
diff --git a/src/junit/framework/JUnit4TestAdapter.java b/src/junit/framework/JUnit4TestAdapter.java
new file mode 100644
index 0000000..a05a313
--- /dev/null
+++ b/src/junit/framework/JUnit4TestAdapter.java
@@ -0,0 +1,85 @@
+package junit.framework;
+
+import java.util.List;
+
+import org.junit.Ignore;
+import org.junit.runner.Describable;
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.Filterable;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runner.manipulation.Sortable;
+import org.junit.runner.manipulation.Sorter;
+
+public class JUnit4TestAdapter implements Test, Filterable, Sortable, Describable {
+ private final Class<?> fNewTestClass;
+
+ private final Runner fRunner;
+
+ private final JUnit4TestAdapterCache fCache;
+
+ public JUnit4TestAdapter(Class<?> newTestClass) {
+ this(newTestClass, JUnit4TestAdapterCache.getDefault());
+ }
+
+ public JUnit4TestAdapter(final Class<?> newTestClass,
+ JUnit4TestAdapterCache cache) {
+ fCache = cache;
+ fNewTestClass = newTestClass;
+ fRunner = Request.classWithoutSuiteMethod(newTestClass).getRunner();
+ }
+
+ public int countTestCases() {
+ return fRunner.testCount();
+ }
+
+ public void run(TestResult result) {
+ fRunner.run(fCache.getNotifier(result, this));
+ }
+
+ // reflective interface for Eclipse
+ public List<Test> getTests() {
+ return fCache.asTestList(getDescription());
+ }
+
+ // reflective interface for Eclipse
+ public Class<?> getTestClass() {
+ return fNewTestClass;
+ }
+
+ public Description getDescription() {
+ Description description= fRunner.getDescription();
+ return removeIgnored(description);
+ }
+
+ private Description removeIgnored(Description description) {
+ if (isIgnored(description))
+ return Description.EMPTY;
+ Description result = description.childlessCopy();
+ for (Description each : description.getChildren()) {
+ Description child= removeIgnored(each);
+ if (! child.isEmpty())
+ result.addChild(child);
+ }
+ return result;
+ }
+
+ private boolean isIgnored(Description description) {
+ return description.getAnnotation(Ignore.class) != null;
+ }
+
+ @Override
+ public String toString() {
+ return fNewTestClass.getName();
+ }
+
+ public void filter(Filter filter) throws NoTestsRemainException {
+ filter.apply(fRunner);
+ }
+
+ public void sort(Sorter sorter) {
+ sorter.apply(fRunner);
+ }
+} \ No newline at end of file
diff --git a/src/junit/framework/JUnit4TestAdapterCache.java b/src/junit/framework/JUnit4TestAdapterCache.java
new file mode 100644
index 0000000..26175c5
--- /dev/null
+++ b/src/junit/framework/JUnit4TestAdapterCache.java
@@ -0,0 +1,81 @@
+/**
+ *
+ */
+package junit.framework;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
+
+public class JUnit4TestAdapterCache extends HashMap<Description, Test> {
+ private static final long serialVersionUID = 1L;
+ private static final JUnit4TestAdapterCache fInstance = new JUnit4TestAdapterCache();
+
+ public static JUnit4TestAdapterCache getDefault() {
+ return fInstance;
+ }
+
+ public Test asTest(Description description) {
+ if (description.isSuite())
+ return createTest(description);
+ else {
+ if (!containsKey(description))
+ put(description, createTest(description));
+ return get(description);
+ }
+ }
+
+ Test createTest(Description description) {
+ if (description.isTest())
+ return new JUnit4TestCaseFacade(description);
+ else {
+ TestSuite suite = new TestSuite(description.getDisplayName());
+ for (Description child : description.getChildren())
+ suite.addTest(asTest(child));
+ return suite;
+ }
+ }
+
+ public RunNotifier getNotifier(final TestResult result,
+ final JUnit4TestAdapter adapter) {
+ RunNotifier notifier = new RunNotifier();
+ notifier.addListener(new RunListener() {
+ @Override
+ public void testFailure(Failure failure) throws Exception {
+ result.addError(asTest(failure.getDescription()), failure.getException());
+ }
+
+ @Override
+ public void testFinished(Description description)
+ throws Exception {
+ result.endTest(asTest(description));
+ }
+
+ @Override
+ public void testStarted(Description description)
+ throws Exception {
+ result.startTest(asTest(description));
+ }
+ });
+ return notifier;
+ }
+
+ public List<Test> asTestList(Description description) {
+ if (description.isTest())
+ return Arrays.asList(asTest(description));
+ else {
+ List<Test> returnThis = new ArrayList<Test>();
+ for (Description child : description.getChildren()) {
+ returnThis.add(asTest(child));
+ }
+ return returnThis;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/junit/framework/JUnit4TestCaseFacade.java b/src/junit/framework/JUnit4TestCaseFacade.java
new file mode 100644
index 0000000..fd43822
--- /dev/null
+++ b/src/junit/framework/JUnit4TestCaseFacade.java
@@ -0,0 +1,33 @@
+/**
+ *
+ */
+package junit.framework;
+
+import org.junit.runner.Describable;
+import org.junit.runner.Description;
+
+public class JUnit4TestCaseFacade implements Test, Describable {
+ private final Description fDescription;
+
+ JUnit4TestCaseFacade(Description description) {
+ fDescription = description;
+ }
+
+ @Override
+ public String toString() {
+ return getDescription().toString();
+ }
+
+ public int countTestCases() {
+ return 1;
+ }
+
+ public void run(TestResult result) {
+ throw new RuntimeException(
+ "This test stub created only for informational purposes.");
+ }
+
+ public Description getDescription() {
+ return fDescription;
+ }
+} \ No newline at end of file
diff --git a/src/junit/framework/TestCase.java b/src/junit/framework/TestCase.java
index e54b16b..b047ec9 100644
--- a/src/junit/framework/TestCase.java
+++ b/src/junit/framework/TestCase.java
@@ -5,48 +5,52 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
- * A test case defines the fixture to run multiple tests. To define a test case<br>
- * 1) implement a subclass of TestCase<br>
- * 2) define instance variables that store the state of the fixture<br>
- * 3) initialize the fixture state by overriding <code>setUp</code><br>
- * 4) clean-up after a test by overriding <code>tearDown</code>.<br>
+ * A test case defines the fixture to run multiple tests. To define a test case<br/>
+ * <ol>
+ * <li>implement a subclass of <code>TestCase</code></li>
+ * <li>define instance variables that store the state of the fixture</li>
+ * <li>initialize the fixture state by overriding {@link #setUp()}</li>
+ * <li>clean-up after a test by overriding {@link #tearDown()}.</li>
+ * </ol>
* Each test runs in its own fixture so there
* can be no side effects among test runs.
* Here is an example:
* <pre>
* public class MathTest extends TestCase {
- * protected double fValue1;
- * protected double fValue2;
+ * protected double fValue1;
+ * protected double fValue2;
*
* protected void setUp() {
- * fValue1= 2.0;
- * fValue2= 3.0;
- * }
+ * fValue1= 2.0;
+ * fValue2= 3.0;
+ * }
* }
* </pre>
*
* For each test implement a method which interacts
* with the fixture. Verify the expected results with assertions specified
- * by calling <code>assertTrue</code> with a boolean.
+ * by calling {@link junit.framework.Assert#assertTrue(String, boolean)} with a boolean.
* <pre>
* public void testAdd() {
- * double result= fValue1 + fValue2;
- * assertTrue(result == 5.0);
+ * double result= fValue1 + fValue2;
+ * assertTrue(result == 5.0);
* }
* </pre>
+ *
* Once the methods are defined you can run them. The framework supports
* both a static type safe and more dynamic way to run a test.
* In the static way you override the runTest method and define the method to
* be invoked. A convenient way to do so is with an anonymous inner class.
* <pre>
* TestCase test= new MathTest("add") {
- * public void runTest() {
- * testAdd();
- * }
+ * public void runTest() {
+ * testAdd();
+ * }
* };
* test.run();
* </pre>
- * The dynamic way uses reflection to implement <code>runTest</code>. It dynamically finds
+ *
+ * The dynamic way uses reflection to implement {@link #runTest()}. It dynamically finds
* and invokes a method.
* In this case the name of the test case has to correspond to the test method
* to be run.
@@ -54,21 +58,21 @@ import java.lang.reflect.Modifier;
* TestCase test= new MathTest("testAdd");
* test.run();
* </pre>
+ *
* The tests to be run can be collected into a TestSuite. JUnit provides
* different <i>test runners</i> which can run a test suite and collect the results.
* A test runner either expects a static method <code>suite</code> as the entry
* point to get a test to run or it will extract the suite automatically.
* <pre>
* public static Test suite() {
- * suite.addTest(new MathTest("testAdd"));
- * suite.addTest(new MathTest("testDivideByZero"));
- * return suite;
- * }
+ * suite.addTest(new MathTest("testAdd"));
+ * suite.addTest(new MathTest("testDivideByZero"));
+ * return suite;
+ * }
* </pre>
* @see TestResult
* @see TestSuite
*/
-
public abstract class TestCase extends Assert implements Test {
/**
* the name of the test case
@@ -121,7 +125,7 @@ public abstract class TestCase extends Assert implements Test {
}
/**
* Runs the bare test sequence.
- * @exception Throwable if any exception is thrown
+ * @throws Throwable if any exception is thrown
*/
public void runBare() throws Throwable {
Throwable exception= null;
@@ -142,10 +146,10 @@ public abstract class TestCase extends Assert implements Test {
}
/**
* Override to run the test and assert its state.
- * @exception Throwable if any exception is thrown
+ * @throws Throwable if any exception is thrown
*/
protected void runTest() throws Throwable {
- assertNotNull(fName); // Some VMs crash when calling getMethod(null,null);
+ assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null);
Method runMethod= null;
try {
// use getMethod to get all public inherited
@@ -161,7 +165,7 @@ public abstract class TestCase extends Assert implements Test {
}
try {
- runMethod.invoke(this, (Object[])new Class[0]);
+ runMethod.invoke(this);
}
catch (InvocationTargetException e) {
e.fillInStackTrace();
@@ -187,19 +191,20 @@ public abstract class TestCase extends Assert implements Test {
/**
* Returns a string representation of the test case
*/
+ @Override
public String toString() {
return getName() + "(" + getClass().getName() + ")";
}
/**
* Gets the name of a TestCase
- * @return returns a String
+ * @return the name of the TestCase
*/
public String getName() {
return fName;
}
/**
* Sets the name of a TestCase
- * @param name The name to set
+ * @param name the name to set
*/
public void setName(String name) {
fName= name;
diff --git a/src/junit/framework/TestFailure.java b/src/junit/framework/TestFailure.java
index aff6a5a..6662b1f 100644
--- a/src/junit/framework/TestFailure.java
+++ b/src/junit/framework/TestFailure.java
@@ -36,6 +36,7 @@ public class TestFailure extends Object {
/**
* Returns a short description of the failure.
*/
+ @Override
public String toString() {
StringBuffer buffer= new StringBuffer();
buffer.append(fFailedTest+": "+fThrownException.getMessage());
diff --git a/src/junit/framework/TestResult.java b/src/junit/framework/TestResult.java
index 8535ce0..5768e9a 100644
--- a/src/junit/framework/TestResult.java
+++ b/src/junit/framework/TestResult.java
@@ -1,28 +1,30 @@
package junit.framework;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
-import java.util.Vector;
+import java.util.List;
/**
* A <code>TestResult</code> collects the results of executing
* a test case. It is an instance of the Collecting Parameter pattern.
* The test framework distinguishes between <i>failures</i> and <i>errors</i>.
* A failure is anticipated and checked for with assertions. Errors are
- * unanticipated problems like an <code>ArrayIndexOutOfBoundsException</code>.
+ * unanticipated problems like an {@link ArrayIndexOutOfBoundsException}.
*
* @see Test
*/
public class TestResult extends Object {
- protected Vector fFailures;
- protected Vector fErrors;
- protected Vector fListeners;
+ protected List<TestFailure> fFailures;
+ protected List<TestFailure> fErrors;
+ protected List<TestListener> fListeners;
protected int fRunTests;
private boolean fStop;
public TestResult() {
- fFailures= new Vector();
- fErrors= new Vector();
- fListeners= new Vector();
+ fFailures= new ArrayList<TestFailure>();
+ fErrors= new ArrayList<TestFailure>();
+ fListeners= new ArrayList<TestListener>();
fRunTests= 0;
fStop= false;
}
@@ -31,46 +33,45 @@ public class TestResult extends Object {
* caused the error.
*/
public synchronized void addError(Test test, Throwable t) {
- fErrors.addElement(new TestFailure(test, t));
- for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
- ((TestListener)e.nextElement()).addError(test, t);
- }
+ fErrors.add(new TestFailure(test, t));
+ for (TestListener each : cloneListeners())
+ each.addError(test, t);
}
/**
* Adds a failure to the list of failures. The passed in exception
* caused the failure.
*/
public synchronized void addFailure(Test test, AssertionFailedError t) {
- fFailures.addElement(new TestFailure(test, t));
- for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
- ((TestListener)e.nextElement()).addFailure(test, t);
- }
+ fFailures.add(new TestFailure(test, t));
+ for (TestListener each : cloneListeners())
+ each.addFailure(test, t);
}
/**
* Registers a TestListener
*/
public synchronized void addListener(TestListener listener) {
- fListeners.addElement(listener);
+ fListeners.add(listener);
}
/**
* Unregisters a TestListener
*/
public synchronized void removeListener(TestListener listener) {
- fListeners.removeElement(listener);
+ fListeners.remove(listener);
}
/**
* Returns a copy of the listeners.
*/
- private synchronized Vector cloneListeners() {
- return (Vector)fListeners.clone();
+ private synchronized List<TestListener> cloneListeners() {
+ List<TestListener> result= new ArrayList<TestListener>();
+ result.addAll(fListeners);
+ return result;
}
/**
* Informs the result that a test was completed.
*/
public void endTest(Test test) {
- for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
- ((TestListener)e.nextElement()).endTest(test);
- }
+ for (TestListener each : cloneListeners())
+ each.endTest(test);
}
/**
* Gets the number of detected errors.
@@ -81,9 +82,11 @@ public class TestResult extends Object {
/**
* Returns an Enumeration for the errors
*/
- public synchronized Enumeration errors() {
- return fErrors.elements();
+ public synchronized Enumeration<TestFailure> errors() {
+ return Collections.enumeration(fErrors);
}
+
+
/**
* Gets the number of detected failures.
*/
@@ -93,9 +96,10 @@ public class TestResult extends Object {
/**
* Returns an Enumeration for the failures
*/
- public synchronized Enumeration failures() {
- return fFailures.elements();
+ public synchronized Enumeration<TestFailure> failures() {
+ return Collections.enumeration(fFailures);
}
+
/**
* Runs a TestCase.
*/
@@ -147,9 +151,8 @@ public class TestResult extends Object {
synchronized(this) {
fRunTests+= count;
}
- for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
- ((TestListener)e.nextElement()).startTest(test);
- }
+ for (TestListener each : cloneListeners())
+ each.startTest(test);
}
/**
* Marks that the test run should stop.
diff --git a/src/junit/framework/TestSuite.java b/src/junit/framework/TestSuite.java
index 5a96bc2..336efd1 100644
--- a/src/junit/framework/TestSuite.java
+++ b/src/junit/framework/TestSuite.java
@@ -6,11 +6,13 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.List;
import java.util.Vector;
/**
- * A <code>TestSuite</code> is a <code>Composite</code> of Tests.
+ * <p>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>
@@ -18,20 +20,25 @@ import java.util.Vector;
* suite.addTest(new MathTest("testAdd"));
* suite.addTest(new MathTest("testDivideByZero"));
* </pre>
- * Alternatively, a TestSuite can extract the tests to be run automatically.
+ * </p>
+ *
+ * <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>
- * 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.
+ * </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.
* <pre>
* Class[] testClasses = { MathTest.class, AnotherTest.class }
* TestSuite suite= new TestSuite(testClasses);
* </pre>
+ * </p>
*
* @see Test
*/
@@ -41,8 +48,8 @@ public class TestSuite implements Test {
* ...as the moon sets over the early morning Merlin, Oregon
* mountains, our intrepid adventurers type...
*/
- static public Test createTest(Class theClass, String name) {
- Constructor constructor;
+ static public Test createTest(Class<?> theClass, String name) {
+ Constructor<?> constructor;
try {
constructor= getTestConstructor(theClass);
} catch (NoSuchMethodException e) {
@@ -71,10 +78,9 @@ public class TestSuite implements Test {
* Gets a constructor which takes a single String as
* its argument or a no arg constructor.
*/
- public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException {
- Class[] args= { String.class };
+ public static Constructor<?> getTestConstructor(Class<?> theClass) throws NoSuchMethodException {
try {
- return theClass.getConstructor(args);
+ return theClass.getConstructor(String.class);
} catch (NoSuchMethodException e) {
// fall through
}
@@ -86,6 +92,7 @@ public class TestSuite implements Test {
*/
public static Test warning(final String message) {
return new TestCase("warning") {
+ @Override
protected void runTest() {
fail(message);
}
@@ -100,11 +107,11 @@ public class TestSuite implements Test {
PrintWriter writer= new PrintWriter(stringWriter);
t.printStackTrace(writer);
return stringWriter.toString();
-
}
+
private String fName;
- private Vector fTests= new Vector(10);
+ private Vector<Test> fTests= new Vector<Test>(10); // Cannot convert this to List because it is used directly by some test runners
/**
* Constructs an empty TestSuite.
@@ -115,10 +122,14 @@ public class TestSuite implements Test {
/**
* Constructs a TestSuite from the given class. Adds all the methods
* starting with "test" as test cases to the suite.
- * Parts of this method was written at 2337 meters in the Hueffihuette,
+ * Parts of this method were written at 2337 meters in the Hueffihuette,
* Kanton Uri
*/
- public TestSuite(final Class theClass) {
+ public TestSuite(final Class<?> theClass) {
+ addTestsFromTestCase(theClass);
+ }
+
+ private void addTestsFromTestCase(final Class<?> theClass) {
fName= theClass.getName();
try {
getTestConstructor(theClass); // Avoid generating multiple error messages
@@ -132,13 +143,11 @@ public class TestSuite implements Test {
return;
}
- Class superClass= theClass;
- Vector names= new Vector();
+ Class<?> superClass= theClass;
+ List<String> names= new ArrayList<String>();
while (Test.class.isAssignableFrom(superClass)) {
- Method[] methods= superClass.getDeclaredMethods();
- for (int i= 0; i < methods.length; i++) {
- addTestMethod(methods[i], names, theClass);
- }
+ for (Method each : superClass.getDeclaredMethods())
+ addTestMethod(each, names, theClass);
superClass= superClass.getSuperclass();
}
if (fTests.size() == 0)
@@ -149,7 +158,7 @@ public class TestSuite implements Test {
* Constructs a TestSuite from the given class with the given name.
* @see TestSuite#TestSuite(Class)
*/
- public TestSuite(Class theClass, String name) {
+ public TestSuite(Class<? extends TestCase> theClass, String name) {
this(theClass);
setName(name);
}
@@ -163,18 +172,25 @@ public class TestSuite implements Test {
/**
* Constructs a TestSuite from the given array of classes.
- * @param classes
+ * @param classes {@link TestCase}s
*/
- public TestSuite (Class[] classes) {
- for (int i= 0; i < classes.length; i++)
- addTest(new TestSuite(classes[i]));
+ public TestSuite (Class<?>... classes) {
+ for (Class<?> each : classes)
+ addTest(testCaseForClass(each));
+ }
+
+ private Test testCaseForClass(Class<?> each) {
+ if (TestCase.class.isAssignableFrom(each))
+ return new TestSuite(each.asSubclass(TestCase.class));
+ else
+ return warning(each.getCanonicalName() + " does not extend TestCase");
}
/**
* Constructs a TestSuite from the given array of classes with the given name.
* @see TestSuite#TestSuite(Class[])
*/
- public TestSuite(Class[] classes, String name) {
+ public TestSuite(Class<? extends TestCase>[] classes, String name) {
this(classes);
setName(name);
}
@@ -183,13 +199,13 @@ public class TestSuite implements Test {
* Adds a test to the suite.
*/
public void addTest(Test test) {
- fTests.addElement(test);
+ fTests.add(test);
}
/**
* Adds the tests from the given class to the suite
*/
- public void addTestSuite(Class testClass) {
+ public void addTestSuite(Class<? extends TestCase> testClass) {
addTest(new TestSuite(testClass));
}
@@ -198,10 +214,8 @@ public class TestSuite implements Test {
*/
public int countTestCases() {
int count= 0;
- for (Enumeration e= tests(); e.hasMoreElements(); ) {
- Test test= (Test)e.nextElement();
- count= count + test.countTestCases();
- }
+ for (Test each : fTests)
+ count+= each.countTestCases();
return count;
}
@@ -218,11 +232,10 @@ public class TestSuite implements Test {
* Runs the tests and collects their result in a TestResult.
*/
public void run(TestResult result) {
- for (Enumeration e= tests(); e.hasMoreElements(); ) {
+ for (Test each : fTests) {
if (result.shouldStop() )
break;
- Test test= (Test)e.nextElement();
- runTest(test, result);
+ runTest(each, result);
}
}
@@ -232,7 +245,7 @@ public class TestSuite implements Test {
/**
* Sets the name of the suite.
- * @param name The name to set
+ * @param name the name to set
*/
public void setName(String name) {
fName= name;
@@ -242,7 +255,7 @@ public class TestSuite implements Test {
* Returns the test at the given index
*/
public Test testAt(int index) {
- return (Test)fTests.elementAt(index);
+ return fTests.get(index);
}
/**
@@ -255,28 +268,29 @@ public class TestSuite implements Test {
/**
* Returns the tests as an enumeration
*/
- public Enumeration tests() {
+ public Enumeration<Test> tests() {
return fTests.elements();
}
/**
*/
+ @Override
public String toString() {
if (getName() != null)
return getName();
return super.toString();
}
- private void addTestMethod(Method m, Vector names, Class theClass) {
+ private void addTestMethod(Method m, List<String> names, Class<?> theClass) {
String name= m.getName();
if (names.contains(name))
return;
if (! isPublicTestMethod(m)) {
if (isTestMethod(m))
- addTest(warning("Test method isn't public: "+m.getName()));
+ addTest(warning("Test method isn't public: "+ m.getName() + "(" + theClass.getCanonicalName() + ")"));
return;
}
- names.addElement(name);
+ names.add(name);
addTest(createTest(theClass, name));
}
@@ -285,9 +299,9 @@ public class TestSuite implements Test {
}
private boolean isTestMethod(Method m) {
- String name= m.getName();
- Class[] parameters= m.getParameterTypes();
- Class returnType= m.getReturnType();
- return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);
+ return
+ m.getParameterTypes().length == 0 &&
+ m.getName().startsWith("test") &&
+ m.getReturnType().equals(Void.TYPE);
}
} \ No newline at end of file
diff --git a/src/junit/framework/package-info.java b/src/junit/framework/package-info.java
new file mode 100644
index 0000000..153a1c8
--- /dev/null
+++ b/src/junit/framework/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides JUnit v3.x core classes.
+ */
+package junit.framework; \ No newline at end of file
diff --git a/src/junit/runner/BaseTestRunner.java b/src/junit/runner/BaseTestRunner.java
index 1518f7c..6a4b090 100644
--- a/src/junit/runner/BaseTestRunner.java
+++ b/src/junit/runner/BaseTestRunner.java
@@ -56,8 +56,7 @@ public abstract class BaseTestRunner implements TestListener {
public static void savePreferences() throws IOException {
FileOutputStream fos= new FileOutputStream(getPreferencesFile());
try {
- // calling of the deprecated save method to enable compiling under 1.1.7
- getPreferences().save(fos, "");
+ getPreferences().store(fos, "");
} finally {
fos.close();
}
@@ -96,7 +95,7 @@ public abstract class BaseTestRunner implements TestListener {
clearStatus();
return null;
}
- Class testClass= null;
+ Class<?> testClass= null;
try {
testClass= loadSuiteClass(suiteClassName);
} catch (ClassNotFoundException e) {
@@ -204,8 +203,8 @@ public abstract class BaseTestRunner implements TestListener {
/**
* Returns the loaded Class for a suite name.
*/
- protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
- return getLoader().load(suiteClassName);
+ protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
+ return Class.forName(suiteClassName);
}
/**
@@ -214,17 +213,8 @@ public abstract class BaseTestRunner implements TestListener {
protected void clearStatus() { // Belongs in the GUI TestRunner class
}
- /**
- * Returns the loader to be used.
- */
- public TestSuiteLoader getLoader() {
- if (useReloadingTestSuiteLoader())
- return new ReloadingTestSuiteLoader();
- return new StandardTestSuiteLoader();
- }
-
protected boolean useReloadingTestSuiteLoader() {
- return getPreference("loading").equals("true") && !inVAJava() && fLoading;
+ return getPreference("loading").equals("true") && fLoading;
}
private static File getPreferencesFile() {
@@ -263,21 +253,6 @@ public abstract class BaseTestRunner implements TestListener {
return intValue;
}
- public static boolean inVAJava() {
- try {
- Class.forName("com.ibm.uvm.tools.DebugSupport");
- }
- catch (Exception e) {
- return false;
- }
- return true;
- }
-
- public static boolean inMac() {
- return System.getProperty("mrj.version") != null;
- }
-
-
/**
* Returns a filtered stack trace
*/
diff --git a/src/junit/runner/ClassPathTestCollector.java b/src/junit/runner/ClassPathTestCollector.java
deleted file mode 100644
index 0dbb98e..0000000
--- a/src/junit/runner/ClassPathTestCollector.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package junit.runner;
-
-import java.io.File;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-/**
- * An implementation of a TestCollector that consults the
- * class path. It considers all classes on the class path
- * excluding classes in JARs. It leaves it up to subclasses
- * to decide whether a class is a runnable Test.
- *
- * @see TestCollector
- */
-public abstract class ClassPathTestCollector implements TestCollector {
-
- static final int SUFFIX_LENGTH= ".class".length();
-
- public ClassPathTestCollector() {
- }
-
- public Enumeration collectTests() {
- String classPath= System.getProperty("java.class.path");
- Hashtable result = collectFilesInPath(classPath);
- return result.elements();
- }
-
- public Hashtable collectFilesInPath(String classPath) {
- Hashtable result= collectFilesInRoots(splitClassPath(classPath));
- return result;
- }
-
- Hashtable collectFilesInRoots(Vector roots) {
- Hashtable result= new Hashtable(100);
- Enumeration e= roots.elements();
- while (e.hasMoreElements())
- gatherFiles(new File((String)e.nextElement()), "", result);
- return result;
- }
-
- void gatherFiles(File classRoot, String classFileName, Hashtable result) {
- File thisRoot= new File(classRoot, classFileName);
- if (thisRoot.isFile()) {
- if (isTestClass(classFileName)) {
- String className= classNameFromFile(classFileName);
- result.put(className, className);
- }
- return;
- }
- String[] contents= thisRoot.list();
- if (contents != null) {
- for (int i= 0; i < contents.length; i++)
- gatherFiles(classRoot, classFileName+File.separatorChar+contents[i], result);
- }
- }
-
- Vector splitClassPath(String classPath) {
- Vector result= new Vector();
- String separator= System.getProperty("path.separator");
- StringTokenizer tokenizer= new StringTokenizer(classPath, separator);
- while (tokenizer.hasMoreTokens())
- result.addElement(tokenizer.nextToken());
- return result;
- }
-
- protected boolean isTestClass(String classFileName) {
- return
- classFileName.endsWith(".class") &&
- classFileName.indexOf('$') < 0 &&
- classFileName.indexOf("Test") > 0;
- }
-
- protected String classNameFromFile(String classFileName) {
- // convert /a/b.class to a.b
- String s= classFileName.substring(0, classFileName.length()-SUFFIX_LENGTH);
- String s2= s.replace(File.separatorChar, '.');
- if (s2.startsWith("."))
- return s2.substring(1);
- return s2;
- }
-}
diff --git a/src/junit/runner/FailureDetailView.java b/src/junit/runner/FailureDetailView.java
deleted file mode 100644
index fc9aaf4..0000000
--- a/src/junit/runner/FailureDetailView.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package junit.runner;
-
-import java.awt.Component;
-
-import junit.framework.TestFailure;
-
-/**
- * A view to show a details about a failure
- */
-public interface FailureDetailView {
- /**
- * Returns the component used to present the TraceView
- */
- public Component getComponent();
- /**
- * Shows details of a TestFailure
- */
- public void showFailure(TestFailure failure);
- /**
- * Clears the view
- */
- public void clear();
-} \ No newline at end of file
diff --git a/src/junit/runner/LoadingTestCollector.java b/src/junit/runner/LoadingTestCollector.java
deleted file mode 100644
index 21a3144..0000000
--- a/src/junit/runner/LoadingTestCollector.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package junit.runner;
-
-import java.lang.reflect.Modifier;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-/**
- * An implementation of a TestCollector that loads
- * all classes on the class path and tests whether
- * it is assignable from Test or provides a static suite method.
- * @see TestCollector
- */
-public class LoadingTestCollector extends ClassPathTestCollector {
-
- TestCaseClassLoader fLoader;
-
- public LoadingTestCollector() {
- fLoader= new TestCaseClassLoader();
- }
-
- protected boolean isTestClass(String classFileName) {
- try {
- if (classFileName.endsWith(".class")) {
- Class testClass= classFromFile(classFileName);
- return (testClass != null) && isTestClass(testClass);
- }
- }
- catch (ClassNotFoundException expected) {
- }
- catch (NoClassDefFoundError notFatal) {
- }
- return false;
- }
-
- Class classFromFile(String classFileName) throws ClassNotFoundException {
- String className= classNameFromFile(classFileName);
- if (!fLoader.isExcluded(className))
- return fLoader.loadClass(className, false);
- return null;
- }
-
- boolean isTestClass(Class testClass) {
- if (hasSuiteMethod(testClass))
- return true;
- if (Test.class.isAssignableFrom(testClass) &&
- Modifier.isPublic(testClass.getModifiers()) &&
- hasPublicConstructor(testClass))
- return true;
- return false;
- }
-
- boolean hasSuiteMethod(Class testClass) {
- try {
- testClass.getMethod(BaseTestRunner.SUITE_METHODNAME, new Class[0]);
- } catch(Exception e) {
- return false;
- }
- return true;
- }
-
- boolean hasPublicConstructor(Class testClass) {
- try {
- TestSuite.getTestConstructor(testClass);
- } catch(NoSuchMethodException e) {
- return false;
- }
- return true;
- }
-}
diff --git a/src/junit/runner/ReloadingTestSuiteLoader.java b/src/junit/runner/ReloadingTestSuiteLoader.java
deleted file mode 100644
index 537504b..0000000
--- a/src/junit/runner/ReloadingTestSuiteLoader.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package junit.runner;
-
-/**
- * A TestSuite loader that can reload classes.
- */
-public class ReloadingTestSuiteLoader implements TestSuiteLoader {
-
- public Class load(String suiteClassName) throws ClassNotFoundException {
- return createLoader().loadClass(suiteClassName, true);
- }
-
- public Class reload(Class aClass) throws ClassNotFoundException {
- return createLoader().loadClass(aClass.getName(), true);
- }
-
- protected TestCaseClassLoader createLoader() {
- return new TestCaseClassLoader();
- }
-} \ No newline at end of file
diff --git a/src/junit/runner/SimpleTestCollector.java b/src/junit/runner/SimpleTestCollector.java
deleted file mode 100644
index 9d1956a..0000000
--- a/src/junit/runner/SimpleTestCollector.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package junit.runner;
-
-/**
- * An implementation of a TestCollector that considers
- * a class to be a test class when it contains the
- * pattern "Test" in its name
- * @see TestCollector
- */
-public class SimpleTestCollector extends ClassPathTestCollector {
-
- public SimpleTestCollector() {
- }
-
- protected boolean isTestClass(String classFileName) {
- return
- classFileName.endsWith(".class") &&
- classFileName.indexOf('$') < 0 &&
- classFileName.indexOf("Test") > 0;
- }
-}
diff --git a/src/junit/runner/Sorter.java b/src/junit/runner/Sorter.java
deleted file mode 100644
index e868992..0000000
--- a/src/junit/runner/Sorter.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package junit.runner;
-
-import java.util.Vector;
-
-/**
- * A custom quick sort with support to customize the swap behaviour.
- * NOTICE: We can't use the the sorting support from the JDK 1.2 collection
- * classes because of the JDK 1.1.7 compatibility.
- */
-public class Sorter {
- public static interface Swapper {
- public void swap(Vector values, int left, int right);
- }
-
- public static void sortStrings(Vector values , int left, int right, Swapper swapper) {
- int oleft= left;
- int oright= right;
- String mid= (String)values.elementAt((left + right) / 2);
- do {
- while (((String)(values.elementAt(left))).compareTo(mid) < 0)
- left++;
- while (mid.compareTo((String)(values.elementAt(right))) < 0)
- right--;
- if (left <= right) {
- swapper.swap(values, left, right);
- left++;
- right--;
- }
- } while (left <= right);
-
- if (oleft < right)
- sortStrings(values, oleft, right, swapper);
- if (left < oright)
- sortStrings(values, left, oright, swapper);
- }
-} \ No newline at end of file
diff --git a/src/junit/runner/StandardTestSuiteLoader.java b/src/junit/runner/StandardTestSuiteLoader.java
deleted file mode 100644
index 54f29c1..0000000
--- a/src/junit/runner/StandardTestSuiteLoader.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package junit.runner;
-
-/**
- * The standard test suite loader. It can only load the same class once.
- */
-public class StandardTestSuiteLoader implements TestSuiteLoader {
- /**
- * Uses the system class loader to load the test class
- */
- public Class load(String suiteClassName) throws ClassNotFoundException {
- return Class.forName(suiteClassName);
- }
- /**
- * Uses the system class loader to load the test class
- */
- public Class reload(Class aClass) throws ClassNotFoundException {
- return aClass;
- }
-} \ No newline at end of file
diff --git a/src/junit/runner/TestCaseClassLoader.java b/src/junit/runner/TestCaseClassLoader.java
deleted file mode 100644
index b4bbc24..0000000
--- a/src/junit/runner/TestCaseClassLoader.java
+++ /dev/null
@@ -1,240 +0,0 @@
-package junit.runner;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.Vector;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-/**
- * A custom class loader which enables the reloading
- * of classes for each test run. The class loader
- * can be configured with a list of package paths that
- * should be excluded from loading. The loading
- * of these packages is delegated to the system class
- * loader. They will be shared across test runs.
- * <p>
- * The list of excluded package paths is specified in
- * a properties file "excluded.properties" that is located in
- * the same place as the TestCaseClassLoader class.
- * <p>
- * <b>Known limitation:</b> the TestCaseClassLoader cannot load classes
- * from jar files.
- */
-
-
-public class TestCaseClassLoader extends ClassLoader {
- /** scanned class path */
- private Vector fPathItems;
- /** default excluded paths */
- private String[] defaultExclusions= {
- "junit.framework.",
- "junit.extensions.",
- "junit.runner."
- };
- /** name of excluded properties file */
- static final String EXCLUDED_FILE= "excluded.properties";
- /** excluded paths */
- private Vector fExcluded;
-
- /**
- * Constructs a TestCaseLoader. It scans the class path
- * and the excluded package paths
- */
- public TestCaseClassLoader() {
- this(System.getProperty("java.class.path"));
- }
-
- /**
- * Constructs a TestCaseLoader. It scans the class path
- * and the excluded package paths
- */
- public TestCaseClassLoader(String classPath) {
- scanPath(classPath);
- readExcludedPackages();
- }
-
- private void scanPath(String classPath) {
- String separator= System.getProperty("path.separator");
- fPathItems= new Vector(10);
- StringTokenizer st= new StringTokenizer(classPath, separator);
- while (st.hasMoreTokens()) {
- fPathItems.addElement(st.nextToken());
- }
- }
-
- public URL getResource(String name) {
- return ClassLoader.getSystemResource(name);
- }
-
- public InputStream getResourceAsStream(String name) {
- return ClassLoader.getSystemResourceAsStream(name);
- }
-
- public boolean isExcluded(String name) {
- for (int i= 0; i < fExcluded.size(); i++) {
- if (name.startsWith((String) fExcluded.elementAt(i))) {
- return true;
- }
- }
- return false;
- }
-
- public synchronized Class loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
-
- Class c= findLoadedClass(name);
- if (c != null)
- return c;
- //
- // Delegate the loading of excluded classes to the
- // standard class loader.
- //
- if (isExcluded(name)) {
- try {
- c= findSystemClass(name);
- return c;
- } catch (ClassNotFoundException e) {
- // keep searching
- }
- }
- if (c == null) {
- byte[] data= lookupClassData(name);
- if (data == null)
- throw new ClassNotFoundException();
- c= defineClass(name, data, 0, data.length);
- }
- if (resolve)
- resolveClass(c);
- return c;
- }
-
- private byte[] lookupClassData(String className) throws ClassNotFoundException {
- byte[] data= null;
- for (int i= 0; i < fPathItems.size(); i++) {
- String path= (String) fPathItems.elementAt(i);
- String fileName= className.replace('.', '/')+".class";
- if (isJar(path)) {
- data= loadJarData(path, fileName);
- } else {
- data= loadFileData(path, fileName);
- }
- if (data != null)
- return data;
- }
- throw new ClassNotFoundException(className);
- }
-
- boolean isJar(String pathEntry) {
- return pathEntry.endsWith(".jar") || pathEntry.endsWith(".zip");
- }
-
- private byte[] loadFileData(String path, String fileName) {
- File file= new File(path, fileName);
- if (file.exists()) {
- return getClassData(file);
- }
- return null;
- }
-
- private byte[] getClassData(File f) {
- FileInputStream stream= null;
- try {
- stream= new FileInputStream(f);
- ByteArrayOutputStream out= new ByteArrayOutputStream(1000);
- byte[] b= new byte[1000];
- int n;
- while ((n= stream.read(b)) != -1)
- out.write(b, 0, n);
- stream.close();
- out.close();
- return out.toByteArray();
-
- } catch (IOException e) {
- }
- finally {
- if (stream != null)
- try {
- stream.close();
- } catch (IOException e1) {
- }
- }
- return null;
- }
-
- private byte[] loadJarData(String path, String fileName) {
- ZipFile zipFile= null;
- InputStream stream= null;
- File archive= new File(path);
- if (!archive.exists())
- return null;
- try {
- zipFile= new ZipFile(archive);
- } catch(IOException io) {
- return null;
- }
- ZipEntry entry= zipFile.getEntry(fileName);
- if (entry == null)
- return null;
- int size= (int) entry.getSize();
- try {
- stream= zipFile.getInputStream(entry);
- byte[] data= new byte[size];
- int pos= 0;
- while (pos < size) {
- int n= stream.read(data, pos, data.length - pos);
- pos += n;
- }
- zipFile.close();
- return data;
- } catch (IOException e) {
- } finally {
- try {
- if (stream != null)
- stream.close();
- } catch (IOException e) {
- }
- }
- return null;
- }
-
- private void readExcludedPackages() {
- fExcluded= new Vector(10);
- for (int i= 0; i < defaultExclusions.length; i++)
- fExcluded.addElement(defaultExclusions[i]);
-
- InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE);
- if (is == null)
- return;
- Properties p= new Properties();
- try {
- p.load(is);
- }
- catch (IOException e) {
- return;
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) {
- String key= (String)e.nextElement();
- if (key.startsWith("excluded.")) {
- String path= p.getProperty(key);
- path= path.trim();
- if (path.endsWith("*"))
- path= path.substring(0, path.length()-1);
- if (path.length() > 0)
- fExcluded.addElement(path);
- }
- }
- }
-} \ No newline at end of file
diff --git a/src/junit/runner/TestCollector.java b/src/junit/runner/TestCollector.java
deleted file mode 100644
index 276e7fa..0000000
--- a/src/junit/runner/TestCollector.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package junit.runner;
-
-import java.util.Enumeration;
-import junit.swingui.TestSelector;
-
-
-/**
- * Collects Test class names to be presented
- * by the TestSelector.
- * @see TestSelector
- */
-public interface TestCollector {
- /**
- * Returns an enumeration of Strings with qualified class names
- */
- public Enumeration collectTests();
-}
diff --git a/src/junit/runner/TestSuiteLoader.java b/src/junit/runner/TestSuiteLoader.java
deleted file mode 100644
index 2db589e..0000000
--- a/src/junit/runner/TestSuiteLoader.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package junit.runner;
-
-/**
- * An interface to define how a test suite should be loaded.
- */
-public interface TestSuiteLoader {
- abstract public Class load(String suiteClassName) throws ClassNotFoundException;
- abstract public Class reload(Class aClass) throws ClassNotFoundException;
-} \ No newline at end of file
diff --git a/src/junit/runner/Version.java b/src/junit/runner/Version.java
index 7fd76aa..eb4794b 100644
--- a/src/junit/runner/Version.java
+++ b/src/junit/runner/Version.java
@@ -9,7 +9,7 @@ public class Version {
}
public static String id() {
- return "3.8.2";
+ return "4.10";
}
public static void main(String[] args) {
diff --git a/src/junit/runner/Version.java.template b/src/junit/runner/Version.java.template
new file mode 100644
index 0000000..3182cfd
--- /dev/null
+++ b/src/junit/runner/Version.java.template
@@ -0,0 +1,18 @@
+package junit.runner;
+
+/**
+ * This class defines the current version of JUnit
+ */
+public class Version {
+ private Version() {
+ // don't instantiate
+ }
+
+ public static String id() {
+ return "@version@";
+ }
+
+ public static void main(String[] args) {
+ System.out.println(id());
+ }
+}
diff --git a/src/junit/runner/excluded.properties b/src/junit/runner/excluded.properties
deleted file mode 100644
index 011ae3c..0000000
--- a/src/junit/runner/excluded.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# 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.*
-excluded.9=org.apache.commons.logging.* \ No newline at end of file
diff --git a/src/junit/runner/package-info.java b/src/junit/runner/package-info.java
new file mode 100644
index 0000000..b746185
--- /dev/null
+++ b/src/junit/runner/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides JUnit v3.x test runners.
+ */
+package junit.runner; \ No newline at end of file
diff --git a/src/junit/swingui/AboutDialog.java b/src/junit/swingui/AboutDialog.java
deleted file mode 100644
index c55b420..0000000
--- a/src/junit/swingui/AboutDialog.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package junit.swingui;
-
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-
-import junit.runner.BaseTestRunner;
-import junit.runner.Version;
-
-/**
- * The AboutDialog.
- */
-class AboutDialog extends JDialog {
- public AboutDialog(JFrame parent) {
- super(parent, true);
-
- setResizable(false);
- getContentPane().setLayout(new GridBagLayout());
- setSize(330, 138);
- setTitle("About");
- // setLocationRelativeTo is only available in JDK 1.4
- try {
- setLocationRelativeTo(parent);
- } catch (NoSuchMethodError e) {
- TestSelector.centerWindow(this);
- }
-
- JButton close= new JButton("Close");
- close.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- dispose();
- }
- }
- );
- getRootPane().setDefaultButton(close);
- JLabel label1= new JLabel("JUnit");
- label1.setFont(new Font("dialog", Font.PLAIN, 36));
-
- JLabel label2= new JLabel("JUnit "+Version.id()+" by Kent Beck and Erich Gamma");
- label2.setFont(new Font("dialog", Font.PLAIN, 14));
-
- JLabel logo= createLogo();
-
- GridBagConstraints constraintsLabel1= new GridBagConstraints();
- constraintsLabel1.gridx = 3; constraintsLabel1.gridy = 0;
- constraintsLabel1.gridwidth = 1; constraintsLabel1.gridheight = 1;
- constraintsLabel1.anchor = GridBagConstraints.CENTER;
- getContentPane().add(label1, constraintsLabel1);
-
- GridBagConstraints constraintsLabel2= new GridBagConstraints();
- constraintsLabel2.gridx = 2; constraintsLabel2.gridy = 1;
- constraintsLabel2.gridwidth = 2; constraintsLabel2.gridheight = 1;
- constraintsLabel2.anchor = GridBagConstraints.CENTER;
- getContentPane().add(label2, constraintsLabel2);
-
- GridBagConstraints constraintsButton1= new GridBagConstraints();
- constraintsButton1.gridx = 2; constraintsButton1.gridy = 2;
- constraintsButton1.gridwidth = 2; constraintsButton1.gridheight = 1;
- constraintsButton1.anchor = GridBagConstraints.CENTER;
- constraintsButton1.insets= new Insets(8, 0, 8, 0);
- getContentPane().add(close, constraintsButton1);
-
- GridBagConstraints constraintsLogo1= new GridBagConstraints();
- constraintsLogo1.gridx = 2; constraintsLogo1.gridy = 0;
- constraintsLogo1.gridwidth = 1; constraintsLogo1.gridheight = 1;
- constraintsLogo1.anchor = GridBagConstraints.CENTER;
- getContentPane().add(logo, constraintsLogo1);
-
- addWindowListener(
- new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- dispose();
- }
- }
- );
- }
- protected JLabel createLogo() {
- Icon icon= TestRunner.getIconResource(BaseTestRunner.class, "logo.gif");
- return new JLabel(icon);
- }
-} \ No newline at end of file
diff --git a/src/junit/swingui/CounterPanel.java b/src/junit/swingui/CounterPanel.java
deleted file mode 100644
index cac4427..0000000
--- a/src/junit/swingui/CounterPanel.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package junit.swingui;
-
-import java.awt.Component;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-
-import javax.swing.BorderFactory;
-import javax.swing.Icon;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-import javax.swing.SwingConstants;
-
-/**
- * A panel with test run counters
- */
-public class CounterPanel extends JPanel {
- private JTextField fNumberOfErrors;
- private JTextField fNumberOfFailures;
- private JTextField fNumberOfRuns;
- private Icon fFailureIcon= TestRunner.getIconResource(getClass(), "icons/failure.gif");
- private Icon fErrorIcon= TestRunner.getIconResource(getClass(), "icons/error.gif");
-
- private int fTotal;
-
- public CounterPanel() {
- super(new GridBagLayout());
- fNumberOfErrors= createOutputField(5);
- fNumberOfFailures= createOutputField(5);
- fNumberOfRuns= createOutputField(9);
-
- addToGrid(new JLabel("Runs:", SwingConstants.CENTER),
- 0, 0, 1, 1, 0.0, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.NONE,
- new Insets(0, 0, 0, 0));
- addToGrid(fNumberOfRuns,
- 1, 0, 1, 1, 0.33, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
- new Insets(0, 8, 0, 0));
-
- addToGrid(new JLabel("Errors:", fErrorIcon, SwingConstants.LEFT),
- 2, 0, 1, 1, 0.0, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.NONE,
- new Insets(0, 8, 0, 0));
- addToGrid(fNumberOfErrors,
- 3, 0, 1, 1, 0.33, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
- new Insets(0, 8, 0, 0));
-
- addToGrid(new JLabel("Failures:", fFailureIcon, SwingConstants.LEFT),
- 4, 0, 1, 1, 0.0, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.NONE,
- new Insets(0, 8, 0, 0));
- addToGrid(fNumberOfFailures,
- 5, 0, 1, 1, 0.33, 0.0,
- GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
- new Insets(0, 8, 0, 0));
- }
-
- private JTextField createOutputField(int width) {
- JTextField field= new JTextField("0", width);
- // force a fixed layout to avoid accidental hiding on relayout
- field.setMinimumSize(field.getPreferredSize());
- field.setMaximumSize(field.getPreferredSize());
- field.setHorizontalAlignment(SwingConstants.LEFT);
- field.setFont(StatusLine.BOLD_FONT);
- field.setEditable(false);
- field.setBorder(BorderFactory.createEmptyBorder());
- return field;
- }
-
- public void addToGrid(Component comp,
- int gridx, int gridy, int gridwidth, int gridheight,
- double weightx, double weighty,
- int anchor, int fill,
- Insets insets) {
-
- GridBagConstraints constraints= new GridBagConstraints();
- constraints.gridx= gridx;
- constraints.gridy= gridy;
- constraints.gridwidth= gridwidth;
- constraints.gridheight= gridheight;
- constraints.weightx= weightx;
- constraints.weighty= weighty;
- constraints.anchor= anchor;
- constraints.fill= fill;
- constraints.insets= insets;
- add(comp, constraints);
- }
-
- public void reset() {
- setLabelValue(fNumberOfErrors, 0);
- setLabelValue(fNumberOfFailures, 0);
- setLabelValue(fNumberOfRuns, 0);
- fTotal= 0;
- }
-
- public void setTotal(int value) {
- fTotal= value;
- }
-
- public void setRunValue(int value) {
- fNumberOfRuns.setText(Integer.toString(value) + "/" + fTotal);
- }
-
- public void setErrorValue(int value) {
- setLabelValue(fNumberOfErrors, value);
- }
-
- public void setFailureValue(int value) {
- setLabelValue(fNumberOfFailures, value);
- }
-
- private void setLabelValue(JTextField label, int value) {
- label.setText(Integer.toString(value));
- }
-} \ No newline at end of file
diff --git a/src/junit/swingui/DefaultFailureDetailView.java b/src/junit/swingui/DefaultFailureDetailView.java
deleted file mode 100644
index 51e79c7..0000000
--- a/src/junit/swingui/DefaultFailureDetailView.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package junit.swingui;
-
-import java.awt.Component;
-import java.awt.Font;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import javax.swing.AbstractListModel;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JList;
-import javax.swing.ListSelectionModel;
-
-import junit.framework.TestFailure;
-import junit.runner.BaseTestRunner;
-import junit.runner.FailureDetailView;
-
-/**
- * A view that shows a stack trace of a failure
- */
-public class DefaultFailureDetailView implements FailureDetailView {
- JList fList;
-
- /**
- * A ListModel representing the scanned failure stack trace.
- */
- static class StackTraceListModel extends AbstractListModel {
- private Vector fLines= new Vector(20);
-
- public Object getElementAt(int index) {
- return fLines.elementAt(index);
- }
-
- public int getSize() {
- return fLines.size();
- }
-
- public void setTrace(String trace) {
- scan(trace);
- fireContentsChanged(this, 0, fLines.size());
- }
-
- public void clear() {
- fLines.removeAllElements();
- fireContentsChanged(this, 0, fLines.size());
- }
-
- private void scan(String trace) {
- fLines.removeAllElements();
- StringTokenizer st= new StringTokenizer(trace, "\n\r", false);
- while (st.hasMoreTokens())
- fLines.addElement(st.nextToken());
- }
- }
-
- /**
- * Renderer for stack entries
- */
- static class StackEntryRenderer extends DefaultListCellRenderer {
-
- public Component getListCellRendererComponent(
- JList list, Object value, int modelIndex,
- boolean isSelected, boolean cellHasFocus) {
- String text= ((String)value).replace('\t', ' ');
- Component c= super.getListCellRendererComponent(list, text, modelIndex, isSelected, cellHasFocus);
- setText(text);
- setToolTipText(text);
- return c;
- }
- }
-
- /**
- * Returns the component used to present the trace
- */
- public Component getComponent() {
- if (fList == null) {
- fList= new JList(new StackTraceListModel());
- fList.setFont(new Font("Dialog", Font.PLAIN, 12));
- fList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- fList.setVisibleRowCount(5);
- fList.setCellRenderer(new StackEntryRenderer());
- }
- return fList;
- }
-
- /**
- * Shows a TestFailure
- */
- public void showFailure(TestFailure failure) {
- getModel().setTrace(BaseTestRunner.getFilteredTrace(failure.trace()));
- }
- /**
- * Clears the output.
- */
- public void clear() {
- getModel().clear();
- }
-
- private StackTraceListModel getModel() {
- return (StackTraceListModel)fList.getModel();
- }
-} \ No newline at end of file
diff --git a/src/junit/swingui/FailureRunView.java b/src/junit/swingui/FailureRunView.java
deleted file mode 100644
index 3ec6126..0000000
--- a/src/junit/swingui/FailureRunView.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package junit.swingui;
-
-import java.awt.Component;
-import java.awt.Font;
-
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.Icon;
-import javax.swing.JList;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
-import javax.swing.ListModel;
-import javax.swing.ListSelectionModel;
-import javax.swing.ScrollPaneConstants;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import junit.framework.Test;
-import junit.framework.TestFailure;
-import junit.framework.TestResult;
-import junit.runner.BaseTestRunner;
-
-
-/**
- * A view presenting the test failures as a list.
- */
-public class FailureRunView implements TestRunView {
- JList fFailureList;
- TestRunContext fRunContext;
-
- /**
- * Renders TestFailures in a JList
- */
- static class FailureListCellRenderer extends DefaultListCellRenderer {
- private Icon fFailureIcon;
- private Icon fErrorIcon;
-
- FailureListCellRenderer() {
- super();
- loadIcons();
- }
-
- void loadIcons() {
- fFailureIcon= TestRunner.getIconResource(getClass(), "icons/failure.gif");
- fErrorIcon= TestRunner.getIconResource(getClass(), "icons/error.gif");
- }
-
- public Component getListCellRendererComponent(
- JList list, Object value, int modelIndex,
- boolean isSelected, boolean cellHasFocus) {
-
- Component c= super.getListCellRendererComponent(list, value, modelIndex, isSelected, cellHasFocus);
- TestFailure failure= (TestFailure)value;
- String text= failure.failedTest().toString();
- String msg= failure.exceptionMessage();
- if (msg != null)
- text+= ":" + BaseTestRunner.truncate(msg);
-
- if (failure.isFailure()) {
- if (fFailureIcon != null)
- setIcon(fFailureIcon);
- } else {
- if (fErrorIcon != null)
- setIcon(fErrorIcon);
- }
- setText(text);
- setToolTipText(text);
- return c;
- }
- }
-
- public FailureRunView(TestRunContext context) {
- fRunContext= context;
- fFailureList= new JList(fRunContext.getFailures());
- fFailureList.setFont(new Font("Dialog", Font.PLAIN, 12));
-
- fFailureList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- fFailureList.setCellRenderer(new FailureListCellRenderer());
- fFailureList.setVisibleRowCount(5);
-
- fFailureList.addListSelectionListener(
- new ListSelectionListener() {
- public void valueChanged(ListSelectionEvent e) {
- testSelected();
- }
- }
- );
- }
-
- public Test getSelectedTest() {
- int index= fFailureList.getSelectedIndex();
- if (index == -1)
- return null;
-
- ListModel model= fFailureList.getModel();
- TestFailure failure= (TestFailure)model.getElementAt(index);
- return failure.failedTest();
- }
-
- public void activate() {
- testSelected();
- }
-
- public void addTab(JTabbedPane pane) {
- JScrollPane scrollPane= new JScrollPane(fFailureList, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
- Icon errorIcon= TestRunner.getIconResource(getClass(), "icons/error.gif");
- pane.addTab("Failures", errorIcon, scrollPane, "The list of failed tests");
- }
-
- public void revealFailure(Test failure) {
- fFailureList.setSelectedIndex(0);
- }
-
- public void aboutToStart(Test suite, TestResult result) {
- }
-
- public void runFinished(Test suite, TestResult result) {
- }
-
- protected void testSelected() {
- fRunContext.handleTestSelected(getSelectedTest());
- }
-}
diff --git a/src/junit/swingui/MacProgressBar.java b/src/junit/swingui/MacProgressBar.java
deleted file mode 100644
index 1de6cfd..0000000
--- a/src/junit/swingui/MacProgressBar.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package junit.swingui;
-
-import javax.swing.JTextField;
-
-/**
- http://java.sun.com/developer/technicalArticles/JavaLP/JavaToMac2/
-*/
-public class MacProgressBar extends ProgressBar {
-
- private JTextField component;
-
- public MacProgressBar(JTextField component) {
- super();
- this.component= component;
- }
-
- protected void updateBarColor() {
- component.setBackground(getStatusColor());
- }
-}
diff --git a/src/junit/swingui/ProgressBar.java b/src/junit/swingui/ProgressBar.java
deleted file mode 100644
index d5de71e..0000000
--- a/src/junit/swingui/ProgressBar.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package junit.swingui;
-
-import java.awt.Color;
-
-import javax.swing.JProgressBar;
-
-/**
- * A progress bar showing the green/red status
- */
-class ProgressBar extends JProgressBar {
- boolean fError= false;
-
- public ProgressBar() {
- super();
- setForeground(getStatusColor());
- }
-
- protected Color getStatusColor() {
- if (fError)
- return Color.red;
- return Color.green;
- }
-
- public void reset() {
- fError= false;
- updateBarColor();
- setValue(0);
- }
-
- public void start(int total) {
- setMaximum(total);
- reset();
- }
-
- public void step(int value, boolean successful) {
- setValue(value);
- if (!fError && !successful) {
- fError= true;
- updateBarColor();
- }
- }
-
- protected void updateBarColor() {
- setForeground(getStatusColor());
- }
-}
diff --git a/src/junit/swingui/StatusLine.java b/src/junit/swingui/StatusLine.java
deleted file mode 100644
index e18fda2..0000000
--- a/src/junit/swingui/StatusLine.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package junit.swingui;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Font;
-
-import javax.swing.BorderFactory;
-import javax.swing.JTextField;
-import javax.swing.border.BevelBorder;
-
-/**
- * A status line component.
- */
-public class StatusLine extends JTextField {
- public static final Font PLAIN_FONT= new Font("dialog", Font.PLAIN, 12);
- public static final Font BOLD_FONT= new Font("dialog", Font.BOLD, 12);
-
- public StatusLine(int preferredWidth) {
- super();
- setFont(BOLD_FONT);
- setEditable(false);
- setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
- Dimension d= getPreferredSize();
- d.width= preferredWidth;
- setPreferredSize(d);
- }
-
- public void showInfo(String message) {
- setFont(PLAIN_FONT);
- setForeground(Color.black);
- setText(message);
- }
-
- public void showError(String status) {
- setFont(BOLD_FONT);
- setForeground(Color.red);
- setText(status);
- setToolTipText(status);
- }
-
- public void clear() {
- setText("");
- setToolTipText(null);
- }
-} \ No newline at end of file
diff --git a/src/junit/swingui/TestHierarchyRunView.java b/src/junit/swingui/TestHierarchyRunView.java
deleted file mode 100644
index 89bd297..0000000
--- a/src/junit/swingui/TestHierarchyRunView.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package junit.swingui;
-
-import java.util.Vector;
-
-import javax.swing.Icon;
-import javax.swing.JTabbedPane;
-import javax.swing.JTree;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.TreePath;
-
-import junit.framework.Test;
-import junit.framework.TestResult;
-
-/**
- * A hierarchical view of a test run.
- * The contents of a test suite is shown
- * as a tree.
- */
-public class TestHierarchyRunView implements TestRunView {
- TestSuitePanel fTreeBrowser;
- TestRunContext fTestContext;
-
- public TestHierarchyRunView(TestRunContext context) {
- fTestContext= context;
- fTreeBrowser= new TestSuitePanel();
- fTreeBrowser.getTree().addTreeSelectionListener(
- new TreeSelectionListener() {
- public void valueChanged(TreeSelectionEvent e) {
- testSelected();
- }
- }
- );
- }
-
- public void addTab(JTabbedPane pane) {
- Icon treeIcon= TestRunner.getIconResource(getClass(), "icons/hierarchy.gif");
- pane.addTab("Test Hierarchy", treeIcon, fTreeBrowser, "The test hierarchy");
- }
-
- public Test getSelectedTest() {
- return fTreeBrowser.getSelectedTest();
- }
-
- public void activate() {
- testSelected();
- }
-
- public void revealFailure(Test failure) {
- JTree tree= fTreeBrowser.getTree();
- TestTreeModel model= (TestTreeModel)tree.getModel();
- Vector vpath= new Vector();
- int index= model.findTest(failure, (Test)model.getRoot(), vpath);
- if (index >= 0) {
- Object[] path= new Object[vpath.size()+1];
- vpath.copyInto(path);
- Object last= path[vpath.size()-1];
- path[vpath.size()]= model.getChild(last, index);
- TreePath selectionPath= new TreePath(path);
- tree.setSelectionPath(selectionPath);
- tree.makeVisible(selectionPath);
- }
- }
-
- public void aboutToStart(Test suite, TestResult result) {
- fTreeBrowser.showTestTree(suite);
- result.addListener(fTreeBrowser);
- }
-
- public void runFinished(Test suite, TestResult result) {
- result.removeListener(fTreeBrowser);
- }
-
- protected void testSelected() {
- fTestContext.handleTestSelected(getSelectedTest());
- }
-}
diff --git a/src/junit/swingui/TestRunContext.java b/src/junit/swingui/TestRunContext.java
deleted file mode 100644
index 038e3c4..0000000
--- a/src/junit/swingui/TestRunContext.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package junit.swingui;
-
-import javax.swing.ListModel;
-
-import junit.framework.Test;
-
-/**
- * The interface for accessing the Test run context. Test run views
- * should use this interface rather than accessing the TestRunner
- * directly.
- */
-public interface TestRunContext {
- /**
- * Handles the selection of a Test.
- */
- public void handleTestSelected(Test test);
- /**
- * Returns the failure model
- */
- public ListModel getFailures();
-} \ No newline at end of file
diff --git a/src/junit/swingui/TestRunView.java b/src/junit/swingui/TestRunView.java
deleted file mode 100644
index 1eb5491..0000000
--- a/src/junit/swingui/TestRunView.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package junit.swingui;
-
-import javax.swing.JTabbedPane;
-
-import junit.framework.Test;
-import junit.framework.TestResult;
-
-/**
- * A TestRunView is shown as a page in a tabbed folder.
- * It contributes the page contents and can return
- * the currently selected tests. A TestRunView is
- * notified about the start and finish of a run.
- */
-interface TestRunView {
- /**
- * Returns the currently selected Test in the View
- */
- public Test getSelectedTest();
- /**
- * Activates the TestRunView
- */
- public void activate();
- /**
- * Reveals the given failure
- */
- public void revealFailure(Test failure);
- /**
- * Adds the TestRunView to the test run views tab
- */
- public void addTab(JTabbedPane pane);
- /**
- * Informs that the suite is about to start
- */
- public void aboutToStart(Test suite, TestResult result);
- /**
- * Informs that the run of the test suite has finished
- */
- public void runFinished(Test suite, TestResult result);
-} \ No newline at end of file
diff --git a/src/junit/swingui/TestRunner.java b/src/junit/swingui/TestRunner.java
deleted file mode 100644
index 44aa7a7..0000000
--- a/src/junit/swingui/TestRunner.java
+++ /dev/null
@@ -1,849 +0,0 @@
-package junit.swingui;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.GridLayout;
-import java.awt.Image;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.Vector;
-
-import javax.swing.DefaultListModel;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSeparator;
-import javax.swing.JSplitPane;
-import javax.swing.JTabbedPane;
-import javax.swing.ListModel;
-import javax.swing.ScrollPaneConstants;
-import javax.swing.SwingConstants;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.DocumentEvent;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestFailure;
-import junit.framework.TestResult;
-import junit.framework.TestSuite;
-import junit.runner.BaseTestRunner;
-import junit.runner.FailureDetailView;
-import junit.runner.SimpleTestCollector;
-import junit.runner.TestCollector;
-import junit.runner.TestRunListener;
-import junit.runner.Version;
-
-/**
- * A Swing based user interface to run tests.
- * Enter the name of a class which either provides a static
- * suite method or is a subclass of TestCase.
- * <pre>
- * Synopsis: java junit.swingui.TestRunner [-noloading] [TestCase]
- * </pre>
- * TestRunner takes as an optional argument the name of the testcase class to be run.
- */
-public class TestRunner extends BaseTestRunner implements TestRunContext {
- private static final int GAP= 4;
- private static final int HISTORY_LENGTH= 5;
-
- protected JFrame fFrame;
- private Thread fRunner;
- private TestResult fTestResult;
-
- private JComboBox fSuiteCombo;
- private ProgressBar fProgressIndicator;
- private DefaultListModel fFailures;
- private JLabel fLogo;
- private CounterPanel fCounterPanel;
- private JButton fRun;
- private JButton fQuitButton;
- private JButton fRerunButton;
- private StatusLine fStatusLine;
- private FailureDetailView fFailureView;
- private JTabbedPane fTestViewTab;
- private JCheckBox fUseLoadingRunner;
- private Vector fTestRunViews= new Vector(); // view associated with tab in tabbed pane
-
- private static final String TESTCOLLECTOR_KEY= "TestCollectorClass";
- private static final String FAILUREDETAILVIEW_KEY= "FailureViewClass";
-
- public TestRunner() {
- }
-
- public static void main(String[] args) {
- new TestRunner().start(args);
- }
-
- public static void run(Class test) {
- String args[]= { test.getName() };
- main(args);
- }
-
- public void testFailed(final int status, final Test test, final Throwable t) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- switch (status) {
- case TestRunListener.STATUS_ERROR:
- fCounterPanel.setErrorValue(fTestResult.errorCount());
- appendFailure(test, t);
- break;
- case TestRunListener.STATUS_FAILURE:
- fCounterPanel.setFailureValue(fTestResult.failureCount());
- appendFailure(test, t);
- break;
- }
- }
- }
- );
- }
-
- public void testStarted(String testName) {
- postInfo("Running: "+testName);
- }
-
- public void testEnded(String stringName) {
- synchUI();
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- if (fTestResult != null) {
- fCounterPanel.setRunValue(fTestResult.runCount());
- fProgressIndicator.step(fTestResult.runCount(), fTestResult.wasSuccessful());
- }
- }
- }
- );
- }
-
- public void setSuite(String suiteName) {
- fSuiteCombo.getEditor().setItem(suiteName);
- }
-
- private void addToHistory(final String suite) {
- for (int i= 0; i < fSuiteCombo.getItemCount(); i++) {
- if (suite.equals(fSuiteCombo.getItemAt(i))) {
- fSuiteCombo.removeItemAt(i);
- fSuiteCombo.insertItemAt(suite, 0);
- fSuiteCombo.setSelectedIndex(0);
- return;
- }
- }
- fSuiteCombo.insertItemAt(suite, 0);
- fSuiteCombo.setSelectedIndex(0);
- pruneHistory();
- }
-
- private void pruneHistory() {
- int historyLength= getPreference("maxhistory", HISTORY_LENGTH);
- if (historyLength < 1)
- historyLength= 1;
- for (int i= fSuiteCombo.getItemCount()-1; i > historyLength-1; i--)
- fSuiteCombo.removeItemAt(i);
- }
-
- private void appendFailure(Test test, Throwable t) {
- fFailures.addElement(new TestFailure(test, t));
- if (fFailures.size() == 1)
- revealFailure(test);
- }
-
- private void revealFailure(Test test) {
- for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
- TestRunView v= (TestRunView) e.nextElement();
- v.revealFailure(test);
- }
- }
-
- protected void aboutToStart(final Test testSuite) {
- for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
- TestRunView v= (TestRunView) e.nextElement();
- v.aboutToStart(testSuite, fTestResult);
- }
- }
-
- protected void runFinished(final Test testSuite) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
- TestRunView v= (TestRunView) e.nextElement();
- v.runFinished(testSuite, fTestResult);
- }
- }
- }
- );
- }
-
- protected CounterPanel createCounterPanel() {
- return new CounterPanel();
- }
-
- protected JPanel createFailedPanel() {
- JPanel failedPanel= new JPanel(new GridLayout(0, 1, 0, 2));
- fRerunButton= new JButton("Run");
- fRerunButton.setEnabled(false);
- fRerunButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- rerun();
- }
- }
- );
- failedPanel.add(fRerunButton);
- return failedPanel;
- }
-
- protected FailureDetailView createFailureDetailView() {
- String className= BaseTestRunner.getPreference(FAILUREDETAILVIEW_KEY);
- if (className != null) {
- Class viewClass= null;
- try {
- viewClass= Class.forName(className);
- return (FailureDetailView)viewClass.newInstance();
- } catch(Exception e) {
- JOptionPane.showMessageDialog(fFrame, "Could not create Failure DetailView - using default view");
- }
- }
- return new DefaultFailureDetailView();
- }
-
- /**
- * Creates the JUnit menu. Clients override this
- * method to add additional menu items.
- */
- protected JMenu createJUnitMenu() {
- JMenu menu= new JMenu("JUnit");
- menu.setMnemonic('J');
- JMenuItem mi1= new JMenuItem("About...");
- mi1.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent event) {
- about();
- }
- }
- );
- mi1.setMnemonic('A');
- menu.add(mi1);
-
- menu.addSeparator();
- JMenuItem mi2= new JMenuItem(" Exit ");
- mi2.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent event) {
- terminate();
- }
- }
- );
- mi2.setMnemonic('x');
- menu.add(mi2);
-
- return menu;
- }
-
- protected JFrame createFrame() {
- JFrame frame= new JFrame("JUnit");
- Image icon= loadFrameIcon();
- if (icon != null)
- frame.setIconImage(icon);
- frame.getContentPane().setLayout(new BorderLayout(0, 0));
-
- frame.addWindowListener(
- new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- terminate();
- }
- }
- );
- return frame;
- }
-
- protected JLabel createLogo() {
- JLabel label;
- Icon icon= getIconResource(BaseTestRunner.class, "logo.gif");
- if (icon != null)
- label= new JLabel(icon);
- else
- label= new JLabel("JV");
- label.setToolTipText("JUnit Version "+Version.id());
- return label;
- }
-
- protected void createMenus(JMenuBar mb) {
- mb.add(createJUnitMenu());
- }
-
- protected JCheckBox createUseLoaderCheckBox() {
- boolean useLoader= useReloadingTestSuiteLoader();
- JCheckBox box= new JCheckBox("Reload classes every run", useLoader);
- box.setToolTipText("Use a custom class loader to reload the classes for every run");
- if (inVAJava())
- box.setVisible(false);
- return box;
- }
-
- protected JButton createQuitButton() {
- // spaces required to avoid layout flicker
- // Exit is shorter than Stop that shows in the same column
- JButton quit= new JButton(" Exit ");
- quit.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- terminate();
- }
- }
- );
- return quit;
- }
-
- protected JButton createRunButton() {
- JButton run= new JButton("Run");
- run.setEnabled(true);
- run.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- runSuite();
- }
- }
- );
- return run;
- }
-
- protected Component createBrowseButton() {
- JButton browse= new JButton("...");
- browse.setToolTipText("Select a Test class");
- browse.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- browseTestClasses();
- }
- }
- );
- return browse;
- }
-
- protected StatusLine createStatusLine() {
- return new StatusLine(380);
- }
-
- protected JComboBox createSuiteCombo() {
- JComboBox combo= new JComboBox();
- combo.setEditable(true);
- combo.setLightWeightPopupEnabled(false);
-
- combo.getEditor().getEditorComponent().addKeyListener(
- new KeyAdapter() {
- public void keyTyped(KeyEvent e) {
- textChanged();
- if (e.getKeyChar() == KeyEvent.VK_ENTER)
- runSuite();
- }
- }
- );
- try {
- loadHistory(combo);
- } catch (IOException e) {
- // fails the first time
- }
- combo.addItemListener(
- new ItemListener() {
- public void itemStateChanged(ItemEvent event) {
- if (event.getStateChange() == ItemEvent.SELECTED) {
- textChanged();
- }
- }
- }
- );
- return combo;
- }
-
- protected JTabbedPane createTestRunViews() {
- JTabbedPane pane= new JTabbedPane(SwingConstants.BOTTOM);
-
- FailureRunView lv= new FailureRunView(this);
- fTestRunViews.addElement(lv);
- lv.addTab(pane);
-
- TestHierarchyRunView tv= new TestHierarchyRunView(this);
- fTestRunViews.addElement(tv);
- tv.addTab(pane);
-
- pane.addChangeListener(
- new ChangeListener() {
- public void stateChanged(ChangeEvent e) {
- testViewChanged();
- }
- }
- );
- return pane;
- }
-
- public void testViewChanged() {
- TestRunView view= (TestRunView)fTestRunViews.elementAt(fTestViewTab.getSelectedIndex());
- view.activate();
- }
-
- protected TestResult createTestResult() {
- return new TestResult();
- }
-
- protected JFrame createUI(String suiteName) {
- JFrame frame= createFrame();
- JMenuBar mb= new JMenuBar();
- createMenus(mb);
- frame.setJMenuBar(mb);
-
- JLabel suiteLabel= new JLabel("Test class name:");
- fSuiteCombo= createSuiteCombo();
- fRun= createRunButton();
- frame.getRootPane().setDefaultButton(fRun);
- Component browseButton= createBrowseButton();
-
- fUseLoadingRunner= createUseLoaderCheckBox();
-
- fStatusLine= createStatusLine();
- if (inMac())
- fProgressIndicator= new MacProgressBar(fStatusLine);
- else
- fProgressIndicator= new ProgressBar();
- fCounterPanel= createCounterPanel();
-
- fFailures= new DefaultListModel();
-
- fTestViewTab= createTestRunViews();
- JPanel failedPanel= createFailedPanel();
-
- fFailureView= createFailureDetailView();
- JScrollPane tracePane= new JScrollPane(fFailureView.getComponent(), ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
-
-
-
- fQuitButton= createQuitButton();
- fLogo= createLogo();
-
- JPanel panel= new JPanel(new GridBagLayout());
-
- addGrid(panel, suiteLabel, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
- addGrid(panel, fSuiteCombo, 0, 1, 1, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
- addGrid(panel, browseButton, 1, 1, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
- addGrid(panel, fRun, 2, 1, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
-
- addGrid(panel, fUseLoadingRunner, 0, 2, 3, GridBagConstraints.NONE, 1.0, GridBagConstraints.WEST);
- //addGrid(panel, new JSeparator(), 0, 3, 3, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
-
-
- addGrid(panel, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
- addGrid(panel, fLogo, 2, 3, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.NORTH);
-
- addGrid(panel, fCounterPanel, 0, 4, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
- addGrid(panel, new JSeparator(), 0, 5, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
- addGrid(panel, new JLabel("Results:"), 0, 6, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
-
- JSplitPane splitter= new JSplitPane(JSplitPane.VERTICAL_SPLIT, fTestViewTab, tracePane);
- addGrid(panel, splitter, 0, 7, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST);
-
- addGrid(panel, failedPanel, 2, 7, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.NORTH/*CENTER*/);
-
- addGrid(panel, fStatusLine, 0, 9, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.CENTER);
- addGrid(panel, fQuitButton, 2, 9, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
-
- frame.setContentPane(panel);
- frame.pack();
- frame.setLocation(200, 200);
- return frame;
- }
-
- private void addGrid(JPanel p, Component co, int x, int y, int w, int fill, double wx, int anchor) {
- GridBagConstraints c= new GridBagConstraints();
- c.gridx= x; c.gridy= y;
- c.gridwidth= w;
- c.anchor= anchor;
- c.weightx= wx;
- c.fill= fill;
- if (fill == GridBagConstraints.BOTH || fill == GridBagConstraints.VERTICAL)
- c.weighty= 1.0;
- c.insets= new Insets(y == 0 ? 10 : 0, x == 0 ? 10 : GAP, GAP, GAP);
- p.add(co, c);
- }
-
- protected String getSuiteText() {
- if (fSuiteCombo == null)
- return "";
- return (String)fSuiteCombo.getEditor().getItem();
- }
-
- public ListModel getFailures() {
- return fFailures;
- }
-
- public void insertUpdate(DocumentEvent event) {
- textChanged();
- }
-
- protected Object instanciateClass(String fullClassName, Object param) {
- try {
- Class clazz= Class.forName(fullClassName);
- if (param == null) {
- return clazz.newInstance();
- } else {
- Class[] clazzParam= {param.getClass()};
- Constructor clazzConstructor= clazz.getConstructor(clazzParam);
- Object[] objectParam= {param};
- return clazzConstructor.newInstance(objectParam);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- public void browseTestClasses() {
- TestCollector collector= createTestCollector();
- TestSelector selector= new TestSelector(fFrame, collector);
- if (selector.isEmpty()) {
- JOptionPane.showMessageDialog(fFrame, "No Test Cases found.\nCheck that the configured \'TestCollector\' is supported on this platform.");
- return;
- }
- selector.show();
- String className= selector.getSelectedItem();
- if (className != null)
- setSuite(className);
- }
-
- TestCollector createTestCollector() {
- String className= BaseTestRunner.getPreference(TESTCOLLECTOR_KEY);
- if (className != null) {
- Class collectorClass= null;
- try {
- collectorClass= Class.forName(className);
- return (TestCollector)collectorClass.newInstance();
- } catch(Exception e) {
- JOptionPane.showMessageDialog(fFrame, "Could not create TestCollector - using default collector");
- }
- }
- return new SimpleTestCollector();
- }
-
- private Image loadFrameIcon() {
- ImageIcon icon= (ImageIcon)getIconResource(BaseTestRunner.class, "smalllogo.gif");
- if (icon != null)
- return icon.getImage();
- return null;
- }
-
- private void loadHistory(JComboBox combo) throws IOException {
- BufferedReader br= new BufferedReader(new FileReader(getSettingsFile()));
- int itemCount= 0;
- try {
- String line;
- while ((line= br.readLine()) != null) {
- combo.addItem(line);
- itemCount++;
- }
- if (itemCount > 0)
- combo.setSelectedIndex(0);
-
- } finally {
- br.close();
- }
- }
-
- private File getSettingsFile() {
- String home= System.getProperty("user.home");
- return new File(home,".junitsession");
- }
-
- private void postInfo(final String message) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- showInfo(message);
- }
- }
- );
- }
-
- private void postStatus(final String status) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- showStatus(status);
- }
- }
- );
- }
-
- public void removeUpdate(DocumentEvent event) {
- textChanged();
- }
-
- private void rerun() {
- TestRunView view= (TestRunView)fTestRunViews.elementAt(fTestViewTab.getSelectedIndex());
- Test rerunTest= view.getSelectedTest();
- if (rerunTest != null)
- rerunTest(rerunTest);
- }
-
- private void rerunTest(Test test) {
- if (!(test instanceof TestCase)) {
- showInfo("Could not reload "+ test.toString());
- return;
- }
- Test reloadedTest= null;
- TestCase rerunTest= (TestCase)test;
-
- try {
- Class reloadedTestClass= getLoader().reload(test.getClass());
- reloadedTest= TestSuite.createTest(reloadedTestClass, rerunTest.getName());
- } catch(Exception e) {
- showInfo("Could not reload "+ test.toString());
- return;
- }
- TestResult result= new TestResult();
- reloadedTest.run(result);
-
- String message= reloadedTest.toString();
- if(result.wasSuccessful())
- showInfo(message+" was successful");
- else if (result.errorCount() == 1)
- showStatus(message+" had an error");
- else
- showStatus(message+" had a failure");
- }
-
- protected void reset() {
- fCounterPanel.reset();
- fProgressIndicator.reset();
- fRerunButton.setEnabled(false);
- fFailureView.clear();
- fFailures.clear();
- }
-
- protected void runFailed(String message) {
- showStatus(message);
- fRun.setText("Run");
- fRunner= null;
- }
-
- synchronized public void runSuite() {
- if (fRunner != null) {
- fTestResult.stop();
- } else {
- setLoading(shouldReload());
- reset();
- showInfo("Load Test Case...");
- final String suiteName= getSuiteText();
- final Test testSuite= getTest(suiteName);
- if (testSuite != null) {
- addToHistory(suiteName);
- doRunTest(testSuite);
- }
- }
- }
-
- private boolean shouldReload() {
- return !inVAJava() && fUseLoadingRunner.isSelected();
- }
-
-
- synchronized protected void runTest(final Test testSuite) {
- if (fRunner != null) {
- fTestResult.stop();
- } else {
- reset();
- if (testSuite != null) {
- doRunTest(testSuite);
- }
- }
- }
-
- private void doRunTest(final Test testSuite) {
- setButtonLabel(fRun, "Stop");
- fRunner= new Thread("TestRunner-Thread") {
- public void run() {
- TestRunner.this.start(testSuite);
- postInfo("Running...");
-
- long startTime= System.currentTimeMillis();
- testSuite.run(fTestResult);
-
- if (fTestResult.shouldStop()) {
- postStatus("Stopped");
- } else {
- long endTime= System.currentTimeMillis();
- long runTime= endTime-startTime;
- postInfo("Finished: " + elapsedTimeAsString(runTime) + " seconds");
- }
- runFinished(testSuite);
- setButtonLabel(fRun, "Run");
- fRunner= null;
- System.gc();
- }
- };
- // make sure that the test result is created before we start the
- // test runner thread so that listeners can register for it.
- fTestResult= createTestResult();
- fTestResult.addListener(TestRunner.this);
- aboutToStart(testSuite);
-
- fRunner.start();
- }
-
- private void saveHistory() throws IOException {
- BufferedWriter bw= new BufferedWriter(new FileWriter(getSettingsFile()));
- try {
- for (int i= 0; i < fSuiteCombo.getItemCount(); i++) {
- String testsuite= fSuiteCombo.getItemAt(i).toString();
- bw.write(testsuite, 0, testsuite.length());
- bw.newLine();
- }
- } finally {
- bw.close();
- }
- }
-
- private void setButtonLabel(final JButton button, final String label) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- button.setText(label);
- }
- }
- );
- }
-
- public void handleTestSelected(Test test) {
- fRerunButton.setEnabled(test != null && (test instanceof TestCase));
- showFailureDetail(test);
- }
-
- private void showFailureDetail(Test test) {
- if (test != null) {
- ListModel failures= getFailures();
- for (int i= 0; i < failures.getSize(); i++) {
- TestFailure failure= (TestFailure)failures.getElementAt(i);
- if (failure.failedTest() == test) {
- fFailureView.showFailure(failure);
- return;
- }
- }
- }
- fFailureView.clear();
- }
-
- private void showInfo(String message) {
- fStatusLine.showInfo(message);
- }
-
- private void showStatus(String status) {
- fStatusLine.showError(status);
- }
-
- /**
- * Starts the TestRunner
- */
- public void start(String[] args) {
- String suiteName= processArguments(args);
- fFrame= createUI(suiteName);
- fFrame.pack();
- fFrame.setVisible(true);
-
- if (suiteName != null) {
- setSuite(suiteName);
- runSuite();
- }
- }
-
- private void start(final Test test) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- int total= test.countTestCases();
- fProgressIndicator.start(total);
- fCounterPanel.setTotal(total);
- }
- }
- );
- }
-
- /**
- * Wait until all the events are processed in the event thread
- */
- private void synchUI() {
- try {
- SwingUtilities.invokeAndWait(
- new Runnable() {
- public void run() {}
- }
- );
- }
- catch (Exception e) {
- }
- }
-
- /**
- * Terminates the TestRunner
- */
- public void terminate() {
- fFrame.dispose();
- try {
- saveHistory();
- } catch (IOException e) {
- System.out.println("Couldn't save test run history");
- }
- System.exit(0);
- }
-
- public void textChanged() {
- fRun.setEnabled(getSuiteText().length() > 0);
- clearStatus();
- }
-
- protected void clearStatus() {
- fStatusLine.clear();
- }
-
- public static Icon getIconResource(Class clazz, String name) {
- URL url= clazz.getResource(name);
- if (url == null) {
- System.err.println("Warning: could not load \""+name+"\" icon");
- return null;
- }
- return new ImageIcon(url);
- }
-
- private void about() {
- AboutDialog about= new AboutDialog(fFrame);
- about.show();
- }
-}
diff --git a/src/junit/swingui/TestSelector.java b/src/junit/swingui/TestSelector.java
deleted file mode 100644
index f0f1f9e..0000000
--- a/src/junit/swingui/TestSelector.java
+++ /dev/null
@@ -1,285 +0,0 @@
-package junit.swingui;
-
-import java.awt.Component;
-import java.awt.Cursor;
-import java.awt.Dimension;
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.util.Enumeration;
-import java.util.Vector;
-
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JScrollPane;
-import javax.swing.ListModel;
-import javax.swing.ListSelectionModel;
-import javax.swing.UIManager;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import junit.runner.Sorter;
-import junit.runner.TestCollector;
-
-/**
- * A test class selector. A simple dialog to pick the name of a test suite.
- */
-public class TestSelector extends JDialog {
- private JButton fCancel;
- private JButton fOk;
- private JList fList;
- private JScrollPane fScrolledList;
- private JLabel fDescription;
- private String fSelectedItem;
-
- /**
- * Renders TestFailures in a JList
- */
- static class TestCellRenderer extends DefaultListCellRenderer {
- Icon fLeafIcon;
- Icon fSuiteIcon;
-
- public TestCellRenderer() {
- fLeafIcon= UIManager.getIcon("Tree.leafIcon");
- fSuiteIcon= UIManager.getIcon("Tree.closedIcon");
- }
-
- public Component getListCellRendererComponent(
- JList list, Object value, int modelIndex,
- boolean isSelected, boolean cellHasFocus) {
- Component c= super.getListCellRendererComponent(list, value, modelIndex, isSelected, cellHasFocus);
- String displayString= displayString((String)value);
-
- if (displayString.startsWith("AllTests"))
- setIcon(fSuiteIcon);
- else
- setIcon(fLeafIcon);
-
- setText(displayString);
- return c;
- }
-
- public static String displayString(String className) {
- int typeIndex= className.lastIndexOf('.');
- if (typeIndex < 0)
- return className;
- return className.substring(typeIndex+1) + " - " + className.substring(0, typeIndex);
- }
-
- public static boolean matchesKey(String s, char ch) {
- return ch == Character.toUpperCase(s.charAt(typeIndex(s)));
- }
-
- private static int typeIndex(String s) {
- int typeIndex= s.lastIndexOf('.');
- int i= 0;
- if (typeIndex > 0)
- i= typeIndex+1;
- return i;
- }
- }
-
- protected class DoubleClickListener extends MouseAdapter {
- public void mouseClicked(MouseEvent e) {
- if (e.getClickCount() == 2) {
- okSelected();
- }
- }
- }
-
- protected class KeySelectListener extends KeyAdapter {
- public void keyTyped(KeyEvent e) {
- keySelectTestClass(e.getKeyChar());
- }
- }
-
- public TestSelector(Frame parent, TestCollector testCollector) {
- super(parent, true);
- setSize(350, 300);
- setResizable(false);
- // setLocationRelativeTo only exists in 1.4
- try {
- setLocationRelativeTo(parent);
- } catch (NoSuchMethodError e) {
- centerWindow(this);
- }
- setTitle("Test Selector");
-
- Vector list= null;
- try {
- parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
- list= createTestList(testCollector);
- } finally {
- parent.setCursor(Cursor.getDefaultCursor());
- }
- fList= new JList(list);
- fList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- fList.setCellRenderer(new TestCellRenderer());
- fScrolledList= new JScrollPane(fList);
-
- fCancel= new JButton("Cancel");
- fDescription= new JLabel("Select the Test class:");
- fOk= new JButton("OK");
- fOk.setEnabled(false);
- getRootPane().setDefaultButton(fOk);
-
- defineLayout();
- addListeners();
- }
-
- public static void centerWindow(Component c) {
- Dimension paneSize= c.getSize();
- Dimension screenSize= c.getToolkit().getScreenSize();
- c.setLocation((screenSize.width-paneSize.width)/2, (screenSize.height-paneSize.height)/2);
- }
-
- private void addListeners() {
- fCancel.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- dispose();
- }
- }
- );
-
- fOk.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- okSelected();
- }
- }
- );
-
- fList.addMouseListener(new DoubleClickListener());
- fList.addKeyListener(new KeySelectListener());
- fList.addListSelectionListener(
- new ListSelectionListener() {
- public void valueChanged(ListSelectionEvent e) {
- checkEnableOK(e);
- }
- }
- );
-
- addWindowListener(
- new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- dispose();
- }
- }
- );
- }
-
- private void defineLayout() {
- getContentPane().setLayout(new GridBagLayout());
- GridBagConstraints labelConstraints = new GridBagConstraints();
- labelConstraints.gridx= 0; labelConstraints.gridy= 0;
- labelConstraints.gridwidth= 1; labelConstraints.gridheight= 1;
- labelConstraints.fill= GridBagConstraints.BOTH;
- labelConstraints.anchor= GridBagConstraints.WEST;
- labelConstraints.weightx= 1.0;
- labelConstraints.weighty= 0.0;
- labelConstraints.insets= new Insets(8, 8, 0, 8);
- getContentPane().add(fDescription, labelConstraints);
-
- GridBagConstraints listConstraints = new GridBagConstraints();
- listConstraints.gridx= 0; listConstraints.gridy= 1;
- listConstraints.gridwidth= 4; listConstraints.gridheight= 1;
- listConstraints.fill= GridBagConstraints.BOTH;
- listConstraints.anchor= GridBagConstraints.CENTER;
- listConstraints.weightx= 1.0;
- listConstraints.weighty= 1.0;
- listConstraints.insets= new Insets(8, 8, 8, 8);
- getContentPane().add(fScrolledList, listConstraints);
-
- GridBagConstraints okConstraints= new GridBagConstraints();
- okConstraints.gridx= 2; okConstraints.gridy= 2;
- okConstraints.gridwidth= 1; okConstraints.gridheight= 1;
- okConstraints.anchor= java.awt.GridBagConstraints.EAST;
- okConstraints.insets= new Insets(0, 8, 8, 8);
- getContentPane().add(fOk, okConstraints);
-
-
- GridBagConstraints cancelConstraints = new GridBagConstraints();
- cancelConstraints.gridx= 3; cancelConstraints.gridy= 2;
- cancelConstraints.gridwidth= 1; cancelConstraints.gridheight= 1;
- cancelConstraints.anchor= java.awt.GridBagConstraints.EAST;
- cancelConstraints.insets= new Insets(0, 8, 8, 8);
- getContentPane().add(fCancel, cancelConstraints);
- }
-
- public void checkEnableOK(ListSelectionEvent e) {
- fOk.setEnabled(fList.getSelectedIndex() != -1);
- }
-
- public void okSelected() {
- fSelectedItem= (String)fList.getSelectedValue();
- dispose();
- }
-
- public boolean isEmpty() {
- return fList.getModel().getSize() == 0;
- }
-
- public void keySelectTestClass(char ch) {
- ListModel model= fList.getModel();
- if (!Character.isJavaIdentifierStart(ch))
- return;
- for (int i= 0; i < model.getSize(); i++) {
- String s= (String)model.getElementAt(i);
- if (TestCellRenderer.matchesKey(s, Character.toUpperCase(ch))) {
- fList.setSelectedIndex(i);
- fList.ensureIndexIsVisible(i);
- return;
- }
- }
- Toolkit.getDefaultToolkit().beep();
- }
-
- public String getSelectedItem() {
- return fSelectedItem;
- }
-
- private Vector createTestList(TestCollector collector) {
- Enumeration each= collector.collectTests();
- Vector v= new Vector(200);
- Vector displayVector= new Vector(v.size());
- while(each.hasMoreElements()) {
- String s= (String)each.nextElement();
- v.addElement(s);
- displayVector.addElement(TestCellRenderer.displayString(s));
- }
- if (v.size() > 0)
- Sorter.sortStrings(displayVector, 0, displayVector.size()-1, new ParallelSwapper(v));
- return v;
- }
-
- private class ParallelSwapper implements Sorter.Swapper {
- Vector fOther;
-
- ParallelSwapper(Vector other) {
- fOther= other;
- }
- public void swap(Vector values, int left, int right) {
- Object tmp= values.elementAt(left);
- values.setElementAt(values.elementAt(right), left);
- values.setElementAt(tmp, right);
- Object tmp2= fOther.elementAt(left);
- fOther.setElementAt(fOther.elementAt(right), left);
- fOther.setElementAt(tmp2, right);
- }
- }
-} \ No newline at end of file
diff --git a/src/junit/swingui/TestSuitePanel.java b/src/junit/swingui/TestSuitePanel.java
deleted file mode 100644
index d8902ad..0000000
--- a/src/junit/swingui/TestSuitePanel.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package junit.swingui;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.util.Vector;
-
-import javax.swing.Icon;
-import javax.swing.JComponent;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTree;
-import javax.swing.SwingUtilities;
-import javax.swing.ToolTipManager;
-import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.TreeModel;
-import javax.swing.tree.TreePath;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestListener;
-
-/**
- * A Panel showing a test suite as a tree.
- */
-class TestSuitePanel extends JPanel implements TestListener {
- private JTree fTree;
- private JScrollPane fScrollTree;
- private TestTreeModel fModel;
-
- static class TestTreeCellRenderer extends DefaultTreeCellRenderer {
- private Icon fErrorIcon;
- private Icon fOkIcon;
- private Icon fFailureIcon;
-
- TestTreeCellRenderer() {
- super();
- loadIcons();
- }
-
- void loadIcons() {
- fErrorIcon= TestRunner.getIconResource(getClass(), "icons/error.gif");
- fOkIcon= TestRunner.getIconResource(getClass(), "icons/ok.gif");
- fFailureIcon= TestRunner.getIconResource(getClass(), "icons/failure.gif");
- }
-
- String stripParenthesis(Object o) {
- String text= o.toString ();
- int pos= text.indexOf('(');
- if (pos < 1)
- return text;
- return text.substring (0, pos);
- }
-
- public Component getTreeCellRendererComponent(JTree tree, Object value,
- boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
-
- Component c= super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
- TreeModel model= tree.getModel();
- if (model instanceof TestTreeModel) {
- TestTreeModel testModel= (TestTreeModel)model;
- Test t= (Test)value;
- String s= "";
- if (testModel.isFailure(t)) {
- if (fFailureIcon != null)
- setIcon(fFailureIcon);
- s= " - Failed";
- }
- else if (testModel.isError(t)) {
- if (fErrorIcon != null)
- setIcon(fErrorIcon);
- s= " - Error";
- }
- else if (testModel.wasRun(t)) {
- if (fOkIcon != null)
- setIcon(fOkIcon);
- s= " - Passed";
- }
- if (c instanceof JComponent)
- ((JComponent)c).setToolTipText(getText()+s);
- }
- setText(stripParenthesis(value));
- return c;
- }
- }
-
- public TestSuitePanel() {
- super(new BorderLayout());
- setPreferredSize(new Dimension(300, 100));
- fTree= new JTree();
- fTree.setModel(null);
- fTree.setRowHeight(20);
- ToolTipManager.sharedInstance().registerComponent(fTree);
- fTree.putClientProperty("JTree.lineStyle", "Angled");
- fScrollTree= new JScrollPane(fTree);
- add(fScrollTree, BorderLayout.CENTER);
- }
-
- public void addError(final Test test, final Throwable t) {
- fModel.addError(test);
- fireTestChanged(test, true);
- }
-
- public void addFailure(final Test test, final AssertionFailedError t) {
- fModel.addFailure(test);
- fireTestChanged(test, true);
- }
-
- /**
- * A test ended.
- */
- public void endTest(Test test) {
- fModel.addRunTest(test);
- fireTestChanged(test, false);
- }
-
- /**
- * A test started.
- */
- public void startTest(Test test) {
- }
-
- /**
- * Returns the selected test or null if multiple or none is selected
- */
- public Test getSelectedTest() {
- TreePath[] paths= fTree.getSelectionPaths();
- if (paths != null && paths.length == 1)
- return (Test)paths[0].getLastPathComponent();
- return null;
- }
-
- /**
- * Returns the Tree
- */
- public JTree getTree() {
- return fTree;
- }
-
- /**
- * Shows the test hierarchy starting at the given test
- */
- public void showTestTree(Test root) {
- fModel= new TestTreeModel(root);
- fTree.setModel(fModel);
- fTree.setCellRenderer(new TestTreeCellRenderer());
- }
-
- private void fireTestChanged(final Test test, final boolean expand) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- Vector vpath= new Vector();
- int index= fModel.findTest(test, (Test)fModel.getRoot(), vpath);
- if (index >= 0) {
- Object[] path= new Object[vpath.size()];
- vpath.copyInto(path);
- TreePath treePath= new TreePath(path);
- fModel.fireNodeChanged(treePath, index);
- if (expand) {
- Object[] fullPath= new Object[vpath.size()+1];
- vpath.copyInto(fullPath);
- fullPath[vpath.size()]= fModel.getChild(treePath.getLastPathComponent(), index);;
- TreePath fullTreePath= new TreePath(fullPath);
- fTree.scrollPathToVisible(fullTreePath);
- }
- }
- }
- }
- );
- }
-} \ No newline at end of file
diff --git a/src/junit/swingui/TestTreeModel.java b/src/junit/swingui/TestTreeModel.java
deleted file mode 100644
index 9f3b0d3..0000000
--- a/src/junit/swingui/TestTreeModel.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package junit.swingui;
-
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Vector;
-
-import javax.swing.event.TreeModelEvent;
-import javax.swing.event.TreeModelListener;
-import javax.swing.tree.TreeModel;
-import javax.swing.tree.TreePath;
-
-import junit.extensions.TestDecorator;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-/**
- * A tree model for a Test.
- */
-class TestTreeModel implements TreeModel {
- private Test fRoot;
- private Vector fModelListeners= new Vector();
- private Hashtable fFailures= new Hashtable();
- private Hashtable fErrors= new Hashtable();
- private Hashtable fRunTests= new Hashtable();
-
- /**
- * Constructs a tree model with the given test as its root.
- */
- public TestTreeModel(Test root) {
- super();
- fRoot= root;
- }
-
- /**
- * adds a TreeModelListener
- */
- public void addTreeModelListener(TreeModelListener l) {
- if (!fModelListeners.contains(l))
- fModelListeners.addElement(l);
- }
- /**
- * Removes a TestModelListener
- */
- public void removeTreeModelListener(TreeModelListener l) {
- fModelListeners.removeElement(l);
- }
- /**
- * Finds the path to a test. Returns the index of the test in its
- * parent test suite.
- */
- public int findTest(Test target, Test node, Vector path) {
- if (target.equals(node))
- return 0;
-
- TestSuite suite= isTestSuite(node);
- for (int i= 0; i < getChildCount(node); i++) {
- Test t= suite.testAt(i);
- int index= findTest(target, t, path);
- if (index >= 0) {
- path.insertElementAt(node, 0);
- if (path.size() == 1)
- return i;
- return index;
- }
- }
- return -1;
- }
- /**
- * Fires a node changed event
- */
- public void fireNodeChanged(TreePath path, int index) {
- int[] indices= {index};
- Object[] changedChildren= {getChild(path.getLastPathComponent(), index)};
- TreeModelEvent event= new TreeModelEvent(this, path, indices, changedChildren);
-
- Enumeration e= fModelListeners.elements();
- while (e.hasMoreElements()) {
- TreeModelListener l= (TreeModelListener) e.nextElement();
- l.treeNodesChanged(event);
- }
- }
- /**
- * Gets the test at the given index
- */
- public Object getChild(Object parent, int index) {
- TestSuite suite= isTestSuite(parent);
- if (suite != null)
- return suite.testAt(index);
- return null;
- }
- /**
- * Gets the number of tests.
- */
- public int getChildCount(Object parent) {
- TestSuite suite= isTestSuite(parent);
- if (suite != null)
- return suite.testCount();
- return 0;
- }
- /**
- * Gets the index of a test in a test suite
- */
- public int getIndexOfChild(Object parent, Object child) {
- TestSuite suite= isTestSuite(parent);
- if (suite != null) {
- int i= 0;
- for (Enumeration e= suite.tests(); e.hasMoreElements(); i++) {
- if (child.equals(e.nextElement()))
- return i;
- }
- }
- return -1;
- }
- /**
- * Returns the root of the tree
- */
- public Object getRoot() {
- return fRoot;
- }
- /**
- * Tests if the test is a leaf.
- */
- public boolean isLeaf(Object node) {
- return isTestSuite(node) == null;
- }
- /**
- * Tests if the node is a TestSuite.
- */
- TestSuite isTestSuite(Object node) {
- if (node instanceof TestSuite)
- return (TestSuite)node;
- if (node instanceof TestDecorator) {
- Test baseTest= ((TestDecorator)node).getTest();
- return isTestSuite(baseTest);
- }
- return null;
- }
-
- /**
- * Called when the value of the model object was changed in the view
- */
- public void valueForPathChanged(TreePath path, Object newValue) {
- // we don't support direct editing of the model
- System.out.println("TreeModel.valueForPathChanged: not implemented");
- }
- /**
- * Remembers a test failure
- */
- void addFailure(Test t) {
- fFailures.put(t, t);
- }
- /**
- * Remembers a test error
- */
- void addError(Test t) {
- fErrors.put(t, t);
- }
- /**
- * Remembers that a test was run
- */
- void addRunTest(Test t) {
- fRunTests.put(t, t);
- }
- /**
- * Returns whether a test was run
- */
- boolean wasRun(Test t) {
- return fRunTests.get(t) != null;
- }
- /**
- * Tests whether a test was an error
- */
- boolean isError(Test t) {
- return (fErrors != null) && fErrors.get(t) != null;
- }
- /**
- * Tests whether a test was a failure
- */
- boolean isFailure(Test t) {
- return (fFailures != null) && fFailures.get(t) != null;
- }
- /**
- * Resets the test results
- */
- void resetResults() {
- fFailures= new Hashtable();
- fRunTests= new Hashtable();
- fErrors= new Hashtable();
- }
-} \ No newline at end of file
diff --git a/src/junit/swingui/icons/error.gif b/src/junit/swingui/icons/error.gif
deleted file mode 100644
index fe13a6a..0000000
--- a/src/junit/swingui/icons/error.gif
+++ /dev/null
Binary files differ
diff --git a/src/junit/swingui/icons/failure.gif b/src/junit/swingui/icons/failure.gif
deleted file mode 100644
index 156ecd6..0000000
--- a/src/junit/swingui/icons/failure.gif
+++ /dev/null
Binary files differ
diff --git a/src/junit/swingui/icons/hierarchy.gif b/src/junit/swingui/icons/hierarchy.gif
deleted file mode 100644
index 9f05ed2..0000000
--- a/src/junit/swingui/icons/hierarchy.gif
+++ /dev/null
Binary files differ
diff --git a/src/junit/swingui/icons/ok.gif b/src/junit/swingui/icons/ok.gif
deleted file mode 100644
index 034825b..0000000
--- a/src/junit/swingui/icons/ok.gif
+++ /dev/null
Binary files differ
diff --git a/src/junit/textui/ResultPrinter.java b/src/junit/textui/ResultPrinter.java
index 1ebb7a1..f2f01f5 100644
--- a/src/junit/textui/ResultPrinter.java
+++ b/src/junit/textui/ResultPrinter.java
@@ -51,14 +51,14 @@ public class ResultPrinter implements TestListener {
printDefects(result.failures(), result.failureCount(), "failure");
}
- protected void printDefects(Enumeration booBoos, int count, String type) {
+ protected void printDefects(Enumeration<TestFailure> booBoos, int count, String type) {
if (count == 0) return;
if (count == 1)
getWriter().println("There was " + count + " " + type + ":");
else
getWriter().println("There were " + count + " " + type + "s:");
for (int i= 1; booBoos.hasMoreElements(); i++) {
- printDefect((TestFailure) booBoos.nextElement(), i);
+ printDefect(booBoos.nextElement(), i);
}
}
diff --git a/src/junit/textui/TestRunner.java b/src/junit/textui/TestRunner.java
index 01b9d6d..046448e 100644
--- a/src/junit/textui/TestRunner.java
+++ b/src/junit/textui/TestRunner.java
@@ -4,11 +4,10 @@ package junit.textui;
import java.io.PrintStream;
import junit.framework.Test;
+import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import junit.runner.BaseTestRunner;
-import junit.runner.StandardTestSuiteLoader;
-import junit.runner.TestSuiteLoader;
import junit.runner.Version;
/**
@@ -16,16 +15,17 @@ import junit.runner.Version;
* <pre>
* java junit.textui.TestRunner [-wait] TestCaseClass
* </pre>
- * 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>
- * 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.
+ * 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>
*/
public class TestRunner extends BaseTestRunner {
private ResultPrinter fPrinter;
@@ -58,7 +58,7 @@ public class TestRunner extends BaseTestRunner {
/**
* Runs a suite extracted from a TestCase subclass.
*/
- static public void run(Class testClass) {
+ static public void run(Class<? extends TestCase> testClass) {
run(new TestSuite(testClass));
}
@@ -68,7 +68,7 @@ public class TestRunner extends BaseTestRunner {
* from your program.
* <pre>
* public static void main (String[] args) {
- * test.textui.TestRunner.run(suite());
+ * test.textui.TestRunner.run(suite());
* }
* </pre>
*/
@@ -86,20 +86,15 @@ public class TestRunner extends BaseTestRunner {
aTestRunner.doRun(suite, true);
}
- /**
- * Always use the StandardTestSuiteLoader. Overridden from
- * BaseTestRunner.
- */
- public TestSuiteLoader getLoader() {
- return new StandardTestSuiteLoader();
- }
-
+ @Override
public void testFailed(int status, Test test, Throwable t) {
}
+ @Override
public void testStarted(String testName) {
}
+ @Override
public void testEnded(String testName) {
}
@@ -189,11 +184,12 @@ public class TestRunner extends BaseTestRunner {
}
protected TestResult runSingleMethod(String testCase, String method, boolean wait) throws Exception {
- Class testClass= loadSuiteClass(testCase);
+ Class<? extends TestCase> testClass= loadSuiteClass(testCase).asSubclass(TestCase.class);
Test test= TestSuite.createTest(testClass, method);
return doRun(test, wait);
}
+ @Override
protected void runFailed(String message) {
System.err.println(message);
System.exit(FAILURE_EXIT);
diff --git a/src/junit/textui/package-info.java b/src/junit/textui/package-info.java
new file mode 100644
index 0000000..2aa5176
--- /dev/null
+++ b/src/junit/textui/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides JUnit v3.x command line based tool to run tests.
+ */
+package junit.textui; \ No newline at end of file
diff --git a/src/org/junit/After.java b/src/org/junit/After.java
new file mode 100644
index 0000000..39aa6e5
--- /dev/null
+++ b/src/org/junit/After.java
@@ -0,0 +1,40 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>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.</p>
+ *
+ * Here is a simple example:
+* <pre>
+ * public class Example {
+ * File output;
+ * &#064;Before public void createOutputFile() {
+ * output= new File(...);
+ * }
+ * &#064;Test public void something() {
+ * ...
+ * }
+ * &#064;After public void deleteOutputFile() {
+ * output.delete();
+ * }
+ * }
+ * </pre>
+ *
+ * @see org.junit.Before
+ * @see org.junit.Test
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface After {
+}
+
diff --git a/src/org/junit/AfterClass.java b/src/org/junit/AfterClass.java
new file mode 100644
index 0000000..2d6bc80
--- /dev/null
+++ b/src/org/junit/AfterClass.java
@@ -0,0 +1,41 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>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.</p>
+ *
+ * Here is a simple example:
+* <pre>
+ * public class Example {
+ * private static DatabaseConnection database;
+ * &#064;BeforeClass public static void login() {
+ * database= ...;
+ * }
+ * &#064;Test public void something() {
+ * ...
+ * }
+ * &#064;Test public void somethingElse() {
+ * ...
+ * }
+ * &#064;AfterClass public static void logout() {
+ * database.logout();
+ * }
+ * }
+ * </pre>
+ *
+ * @see org.junit.BeforeClass
+ * @see org.junit.Test
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface AfterClass {
+}
diff --git a/src/org/junit/Assert.java b/src/org/junit/Assert.java
new file mode 100644
index 0000000..b585b87
--- /dev/null
+++ b/src/org/junit/Assert.java
@@ -0,0 +1,783 @@
+package org.junit;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.StringDescription;
+import org.junit.internal.ArrayComparisonFailure;
+import org.junit.internal.ExactComparisonCriteria;
+import org.junit.internal.InexactComparisonCriteria;
+
+/**
+ * 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/>
+ *
+ * <pre>
+ * import static org.junit.Assert.*;
+ * ...
+ * assertEquals(...);
+ * </pre>
+ *
+ * @see AssertionError
+ */
+public class Assert {
+ /**
+ * Protect constructor since it is a static only class
+ */
+ protected Assert() {
+ }
+
+ /**
+ * Asserts that a condition is true. If it isn't it throws an
+ * {@link AssertionError} with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param condition
+ * condition to be checked
+ */
+ static public void assertTrue(String message, boolean condition) {
+ if (!condition)
+ fail(message);
+ }
+
+ /**
+ * Asserts that a condition is true. If it isn't it throws an
+ * {@link AssertionError} without a message.
+ *
+ * @param condition
+ * condition to be checked
+ */
+ static public void assertTrue(boolean condition) {
+ assertTrue(null, condition);
+ }
+
+ /**
+ * Asserts that a condition is false. If it isn't it throws an
+ * {@link AssertionError} with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param condition
+ * condition to be checked
+ */
+ static public void assertFalse(String message, boolean condition) {
+ assertTrue(message, !condition);
+ }
+
+ /**
+ * Asserts that a condition is false. If it isn't it throws an
+ * {@link AssertionError} without a message.
+ *
+ * @param condition
+ * condition to be checked
+ */
+ static public void assertFalse(boolean condition) {
+ assertFalse(null, condition);
+ }
+
+ /**
+ * Fails a test with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @see AssertionError
+ */
+ static public void fail(String message) {
+ if (message == null)
+ throw new AssertionError();
+ throw new AssertionError(message);
+ }
+
+ /**
+ * Fails a test with no message.
+ */
+ static public void fail() {
+ fail(null);
+ }
+
+ /**
+ * Asserts that two objects are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message. If
+ * <code>expected</code> and <code>actual</code> are <code>null</code>,
+ * they are considered equal.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expected
+ * expected value
+ * @param actual
+ * actual value
+ */
+ static public void assertEquals(String message, Object expected,
+ Object actual) {
+ if (expected == null && actual == null)
+ return;
+ if (expected != null && isEquals(expected, actual))
+ return;
+ else if (expected instanceof String && actual instanceof String) {
+ String cleanMessage= message == null ? "" : message;
+ throw new ComparisonFailure(cleanMessage, (String) expected,
+ (String) actual);
+ } else
+ failNotEquals(message, expected, actual);
+ }
+
+ private static boolean isEquals(Object expected, Object actual) {
+ return expected.equals(actual);
+ }
+
+ /**
+ * Asserts that two objects are equal. If they are not, an
+ * {@link AssertionError} without a message is thrown. If
+ * <code>expected</code> and <code>actual</code> are <code>null</code>,
+ * they are considered equal.
+ *
+ * @param expected
+ * expected value
+ * @param actual
+ * the value to check against <code>expected</code>
+ */
+ static public void assertEquals(Object expected, Object actual) {
+ assertEquals(null, expected, actual);
+ }
+
+ /**
+ * Asserts that two object 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
+ * Object array or array of arrays (multi-dimensional array) with
+ * expected values.
+ * @param actuals
+ * Object array or array of arrays (multi-dimensional array) with
+ * actual values
+ */
+ public static void assertArrayEquals(String message, Object[] expecteds,
+ Object[] actuals) throws ArrayComparisonFailure {
+ internalArrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two object 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
+ * Object array or array of arrays (multi-dimensional array) with
+ * expected values
+ * @param actuals
+ * Object array or array of arrays (multi-dimensional array) with
+ * actual values
+ */
+ public static void assertArrayEquals(Object[] expecteds, Object[] actuals) {
+ assertArrayEquals(null, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two byte arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expecteds
+ * byte array with expected values.
+ * @param actuals
+ * byte array with actual values
+ */
+ public static void assertArrayEquals(String message, byte[] expecteds,
+ byte[] actuals) throws ArrayComparisonFailure {
+ internalArrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two byte arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown.
+ *
+ * @param expecteds
+ * byte array with expected values.
+ * @param actuals
+ * byte array with actual values
+ */
+ public static void assertArrayEquals(byte[] expecteds, byte[] actuals) {
+ assertArrayEquals(null, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two char arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expecteds
+ * char array with expected values.
+ * @param actuals
+ * char array with actual values
+ */
+ public static void assertArrayEquals(String message, char[] expecteds,
+ char[] actuals) throws ArrayComparisonFailure {
+ internalArrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two char arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown.
+ *
+ * @param expecteds
+ * char array with expected values.
+ * @param actuals
+ * char array with actual values
+ */
+ public static void assertArrayEquals(char[] expecteds, char[] actuals) {
+ assertArrayEquals(null, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two short arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expecteds
+ * short array with expected values.
+ * @param actuals
+ * short array with actual values
+ */
+ public static void assertArrayEquals(String message, short[] expecteds,
+ short[] actuals) throws ArrayComparisonFailure {
+ internalArrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two short arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown.
+ *
+ * @param expecteds
+ * short array with expected values.
+ * @param actuals
+ * short array with actual values
+ */
+ public static void assertArrayEquals(short[] expecteds, short[] actuals) {
+ assertArrayEquals(null, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two int arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expecteds
+ * int array with expected values.
+ * @param actuals
+ * int array with actual values
+ */
+ public static void assertArrayEquals(String message, int[] expecteds,
+ int[] actuals) throws ArrayComparisonFailure {
+ internalArrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two int arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown.
+ *
+ * @param expecteds
+ * int array with expected values.
+ * @param actuals
+ * int array with actual values
+ */
+ public static void assertArrayEquals(int[] expecteds, int[] actuals) {
+ assertArrayEquals(null, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two long arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expecteds
+ * long array with expected values.
+ * @param actuals
+ * long array with actual values
+ */
+ public static void assertArrayEquals(String message, long[] expecteds,
+ long[] actuals) throws ArrayComparisonFailure {
+ internalArrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two long arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown.
+ *
+ * @param expecteds
+ * long array with expected values.
+ * @param actuals
+ * long array with actual values
+ */
+ public static void assertArrayEquals(long[] expecteds, long[] actuals) {
+ assertArrayEquals(null, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two double arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expecteds
+ * double array with expected values.
+ * @param actuals
+ * double array with actual values
+ */
+ public static void assertArrayEquals(String message, double[] expecteds,
+ double[] actuals, double delta) throws ArrayComparisonFailure {
+ new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two double arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown.
+ *
+ * @param expecteds
+ * double array with expected values.
+ * @param actuals
+ * double array with actual values
+ */
+ public static void assertArrayEquals(double[] expecteds, double[] actuals, double delta) {
+ assertArrayEquals(null, expecteds, actuals, delta);
+ }
+
+ /**
+ * Asserts that two float arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expecteds
+ * float array with expected values.
+ * @param actuals
+ * float array with actual values
+ */
+ public static void assertArrayEquals(String message, float[] expecteds,
+ float[] actuals, float delta) throws ArrayComparisonFailure {
+ new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two float arrays are equal. If they are not, an
+ * {@link AssertionError} is thrown.
+ *
+ * @param expecteds
+ * float array with expected values.
+ * @param actuals
+ * float array with actual values
+ */
+ public static void assertArrayEquals(float[] expecteds, float[] actuals, float delta) {
+ assertArrayEquals(null, expecteds, actuals, delta);
+ }
+
+ /**
+ * Asserts that two object 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
+ * Object array or array of arrays (multi-dimensional array) with
+ * expected values.
+ * @param actuals
+ * Object array or array of arrays (multi-dimensional array) with
+ * actual values
+ */
+ private static void internalArrayEquals(String message, Object expecteds,
+ Object actuals) throws ArrayComparisonFailure {
+ new ExactComparisonCriteria().arrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two doubles or floats are equal to within a positive delta.
+ * If they are not, an {@link AssertionError} is thrown with the given
+ * message. If the expected value is infinity then the delta value is
+ * ignored. NaNs are considered equal:
+ * <code>assertEquals(Double.NaN, Double.NaN, *)</code> passes
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param expected
+ * expected value
+ * @param actual
+ * the value to check against <code>expected</code>
+ * @param delta
+ * the maximum delta between <code>expected</code> and
+ * <code>actual</code> for which both numbers are still
+ * considered equal.
+ */
+ static public void assertEquals(String message, double expected,
+ double actual, double delta) {
+ if (Double.compare(expected, actual) == 0)
+ return;
+ if (!(Math.abs(expected - actual) <= delta))
+ failNotEquals(message, new Double(expected), new Double(actual));
+ }
+
+ /**
+ * Asserts that two longs are equal. If they are not, an
+ * {@link AssertionError} is thrown.
+ *
+ * @param expected
+ * expected long value.
+ * @param actual
+ * actual long value
+ */
+ static public void assertEquals(long expected, long actual) {
+ assertEquals(null, expected, actual);
+ }
+
+ /**
+ * Asserts that two longs are equal. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @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);
+ }
+
+ /**
+ * @deprecated Use
+ * <code>assertEquals(double expected, double actual, double delta)</code>
+ * instead
+ */
+ @Deprecated
+ static public void assertEquals(double expected, double actual) {
+ assertEquals(null, expected, actual);
+ }
+
+ /**
+ * @deprecated Use
+ * <code>assertEquals(String message, double expected, double actual, double delta)</code>
+ * instead
+ */
+ @Deprecated
+ static public void assertEquals(String message, double expected,
+ double actual) {
+ fail("Use assertEquals(expected, actual, delta) to compare floating-point numbers");
+ }
+
+ /**
+ * Asserts that two doubles or floats are equal to within a positive delta.
+ * If they are not, an {@link AssertionError} is thrown. If the expected
+ * value is infinity then the delta value is ignored.NaNs are considered
+ * equal: <code>assertEquals(Double.NaN, Double.NaN, *)</code> passes
+ *
+ * @param expected
+ * expected value
+ * @param actual
+ * the value to check against <code>expected</code>
+ * @param delta
+ * the maximum delta between <code>expected</code> and
+ * <code>actual</code> for which both numbers are still
+ * considered equal.
+ */
+ static public void assertEquals(double expected, double actual, double delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+
+ /**
+ * Asserts that an object isn't null. If it is an {@link AssertionError} is
+ * thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param object
+ * Object to check or <code>null</code>
+ */
+ static public void assertNotNull(String message, Object object) {
+ assertTrue(message, object != null);
+ }
+
+ /**
+ * Asserts that an object isn't null. If it is an {@link AssertionError} is
+ * thrown.
+ *
+ * @param object
+ * Object to check or <code>null</code>
+ */
+ static public void assertNotNull(Object object) {
+ assertNotNull(null, object);
+ }
+
+ /**
+ * Asserts that an object is null. If it is not, an {@link AssertionError}
+ * is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @param object
+ * Object to check or <code>null</code>
+ */
+ static public void assertNull(String message, Object object) {
+ assertTrue(message, object == null);
+ }
+
+ /**
+ * Asserts that an object is null. If it isn't an {@link AssertionError} is
+ * thrown.
+ *
+ * @param object
+ * Object to check or <code>null</code>
+ */
+ static public void assertNull(Object object) {
+ assertNull(null, object);
+ }
+
+ /**
+ * Asserts that two objects refer to the same object. If they are not, an
+ * {@link AssertionError} is thrown with the given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @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) {
+ if (expected == actual)
+ return;
+ failNotSame(message, expected, actual);
+ }
+
+ /**
+ * Asserts that two objects refer to the same object. If they are not the
+ * same, an {@link AssertionError} without a message is thrown.
+ *
+ * @param expected
+ * the expected object
+ * @param actual
+ * the object to compare to <code>expected</code>
+ */
+ static public void assertSame(Object expected, Object actual) {
+ assertSame(null, expected, actual);
+ }
+
+ /**
+ * Asserts that two objects do not refer to the same object. If they do
+ * refer to the same object, an {@link AssertionError} is thrown with the
+ * given message.
+ *
+ * @param message
+ * the identifying message for the {@link AssertionError} (<code>null</code>
+ * okay)
+ * @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,
+ Object actual) {
+ if (unexpected == actual)
+ failSame(message);
+ }
+
+ /**
+ * Asserts that two objects do not refer to the same object. If they do
+ * refer to the same object, an {@link AssertionError} without a message is
+ * thrown.
+ *
+ * @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) {
+ assertNotSame(null, unexpected, actual);
+ }
+
+ static private void failSame(String message) {
+ String formatted= "";
+ if (message != null)
+ formatted= message + " ";
+ fail(formatted + "expected not same");
+ }
+
+ static private void failNotSame(String message, Object expected,
+ Object actual) {
+ String formatted= "";
+ if (message != null)
+ formatted= message + " ";
+ fail(formatted + "expected same:<" + expected + "> was not:<" + actual
+ + ">");
+ }
+
+ static private 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(""))
+ formatted= message + " ";
+ String expectedString= String.valueOf(expected);
+ String actualString= String.valueOf(actual);
+ if (expectedString.equals(actualString))
+ return formatted + "expected: "
+ + formatClassAndValue(expected, expectedString)
+ + " but was: " + formatClassAndValue(actual, actualString);
+ else
+ return formatted + "expected:<" + expectedString + "> but was:<"
+ + actualString + ">";
+ }
+
+ private static String formatClassAndValue(Object value, String valueString) {
+ String className= value == null ? "null" : value.getClass().getName();
+ return className + "<" + valueString + ">";
+ }
+
+ /**
+ * Asserts that two object 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
+ * Object array or array of arrays (multi-dimensional array) with
+ * expected values.
+ * @param actuals
+ * Object array or array of arrays (multi-dimensional array) with
+ * actual values
+ * @deprecated use assertArrayEquals
+ */
+ @Deprecated
+ public static void assertEquals(String message, Object[] expecteds,
+ Object[] actuals) {
+ assertArrayEquals(message, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two object 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
+ * Object array or array of arrays (multi-dimensional array) with
+ * expected values
+ * @param actuals
+ * Object array or array of arrays (multi-dimensional array) with
+ * actual values
+ * @deprecated use assertArrayEquals
+ */
+ @Deprecated
+ public static void assertEquals(Object[] expecteds, Object[] actuals) {
+ assertArrayEquals(expecteds, actuals);
+ }
+
+ /**
+ * Asserts that <code>actual</code> satisfies the condition specified by
+ * <code>matcher</code>. If not, an {@link AssertionError} is thrown with
+ * information about the matcher and failing value. Example:
+ *
+ * <pre>
+ * assertThat(0, is(1)); // fails:
+ * // failure message:
+ * // expected: is &lt;1&gt;
+ * // got value: &lt;0&gt;
+ * assertThat(0, is(not(1))) // passes
+ * </pre>
+ *
+ * @param <T>
+ * the static type accepted by the matcher (this can flag obvious
+ * compile-time problems such as {@code assertThat(1, is("a"))}
+ * @param actual
+ * the computed value being compared
+ * @param matcher
+ * an expression, built of {@link Matcher}s, specifying allowed
+ * values
+ *
+ * @see org.hamcrest.CoreMatchers
+ * @see org.junit.matchers.JUnitMatchers
+ */
+ public static <T> void assertThat(T actual, Matcher<T> matcher) {
+ assertThat("", actual, matcher);
+ }
+
+ /**
+ * Asserts that <code>actual</code> satisfies the condition specified by
+ * <code>matcher</code>. If not, an {@link AssertionError} is thrown with
+ * the reason and information about the matcher and failing value. Example:
+ *
+ * <pre>
+ * :
+ * assertThat(&quot;Help! Integers don't work&quot;, 0, is(1)); // fails:
+ * // failure message:
+ * // Help! Integers don't work
+ * // expected: is &lt;1&gt;
+ * // got value: &lt;0&gt;
+ * assertThat(&quot;Zero is one&quot;, 0, is(not(1))) // passes
+ * </pre>
+ *
+ * @param reason
+ * additional information about the error
+ * @param <T>
+ * the static type accepted by the matcher (this can flag obvious
+ * compile-time problems such as {@code assertThat(1, is("a"))}
+ * @param actual
+ * the computed value being compared
+ * @param matcher
+ * an expression, built of {@link Matcher}s, specifying allowed
+ * values
+ *
+ * @see org.hamcrest.CoreMatchers
+ * @see org.junit.matchers.JUnitMatchers
+ */
+ public static <T> void assertThat(String reason, T actual,
+ Matcher<T> matcher) {
+ if (!matcher.matches(actual)) {
+ Description description= new StringDescription();
+ description.appendText(reason);
+ description.appendText("\nExpected: ");
+ description.appendDescriptionOf(matcher);
+ description.appendText("\n got: ");
+ description.appendValue(actual);
+ description.appendText("\n");
+ throw new java.lang.AssertionError(description.toString());
+ }
+ }
+}
diff --git a/src/org/junit/Assume.java b/src/org/junit/Assume.java
new file mode 100644
index 0000000..7b6c21a
--- /dev/null
+++ b/src/org/junit/Assume.java
@@ -0,0 +1,94 @@
+package org.junit;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import org.hamcrest.Matcher;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.internal.matchers.Each;
+
+/**
+ * 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.
+ *
+ * For example:
+ * <pre>
+ * // only provides information if database is reachable.
+ * \@Test public void calculateTotalSalary() {
+ * DBConnection dbc = Database.connect();
+ * assumeNotNull(dbc);
+ * // ...
+ * }
+ * </pre>
+ * These methods can be used directly: <code>Assume.assumeTrue(...)</code>, however, they
+ * read better if they are referenced through static import:<br/>
+ * <pre>
+ * import static org.junit.Assume.*;
+ * ...
+ * assumeTrue(...);
+ * </pre>
+ */
+public class Assume {
+ /**
+ * If called with an expression evaluating to {@code false}, the test will halt and be ignored.
+ * @param b
+ */
+ public static void assumeTrue(boolean b) {
+ assumeThat(b, is(true));
+ }
+
+ /**
+ * If called with one or more null elements in <code>objects</code>, the test will halt and be ignored.
+ * @param objects
+ */
+ public static void assumeNotNull(Object... objects) {
+ assumeThat(asList(objects), Each.each(notNullValue()));
+ }
+
+ /**
+ * Call to assume that <code>actual</code> satisfies the condition specified by <code>matcher</code>.
+ * If not, the test halts and is ignored.
+ * Example:
+ * <pre>:
+ * assumeThat(1, is(1)); // passes
+ * foo(); // will execute
+ * assumeThat(0, is(1)); // assumption failure! test halts
+ * int x = 1 / 0; // will never execute
+ * </pre>
+ *
+ * @param <T> the static type accepted by the matcher (this can flag obvious compile-time problems such as {@code assumeThat(1, is("a"))}
+ * @param actual the computed value being compared
+ * @param matcher an expression, built of {@link Matcher}s, specifying allowed values
+ *
+ * @see org.hamcrest.CoreMatchers
+ * @see org.junit.matchers.JUnitMatchers
+ */
+ public static <T> void assumeThat(T actual, Matcher<T> matcher) {
+ if (!matcher.matches(actual))
+ throw new AssumptionViolatedException(actual, matcher);
+ }
+
+ /**
+ * Use to assume that an operation completes normally. If {@code t} is non-null, the test will halt and be ignored.
+ *
+ * For example:
+ * <pre>
+ * \@Test public void parseDataFile() {
+ * DataFile file;
+ * try {
+ * file = DataFile.open("sampledata.txt");
+ * } catch (IOException e) {
+ * // stop test and ignore if data can't be opened
+ * assumeNoException(e);
+ * }
+ * // ...
+ * }
+ * </pre>
+ * @param t if non-null, the offending exception
+ */
+ public static void assumeNoException(Throwable t) {
+ assumeThat(t, nullValue());
+ }
+}
diff --git a/src/org/junit/Before.java b/src/org/junit/Before.java
new file mode 100644
index 0000000..66b34ee
--- /dev/null
+++ b/src/org/junit/Before.java
@@ -0,0 +1,39 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>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.
+ * No other ordering is defined.
+ * </p>
+ *
+ * Here is a simple example:
+ * <pre>
+ * public class Example {
+ * List empty;
+ * &#064;Before public void initialize() {
+ * empty= new ArrayList();
+ * }
+ * &#064;Test public void size() {
+ * ...
+ * }
+ * &#064;Test public void remove() {
+ * ...
+ * }
+ * }
+ * </pre>
+ *
+ * @see org.junit.BeforeClass
+ * @see org.junit.After
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Before {
+}
+
diff --git a/src/org/junit/BeforeClass.java b/src/org/junit/BeforeClass.java
new file mode 100644
index 0000000..35b7854
--- /dev/null
+++ b/src/org/junit/BeforeClass.java
@@ -0,0 +1,35 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>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.</p>
+ *
+ * For example:
+ * <pre>
+ * public class Example {
+ * &#064;BeforeClass public static void onlyOnce() {
+ * ...
+ * }
+ * &#064;Test public void one() {
+ * ...
+ * }
+ * &#064;Test public void two() {
+ * ...
+ * }
+ * }
+ * </pre>
+ * @see org.junit.AfterClass
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface BeforeClass {
+}
diff --git a/src/org/junit/ClassRule.java b/src/org/junit/ClassRule.java
new file mode 100644
index 0000000..97a111f
--- /dev/null
+++ b/src/org/junit/ClassRule.java
@@ -0,0 +1,60 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates static fields that contain rules. Such a field must be public,
+ * static, and a subtype of {@link org.junit.rules.TestRule}.
+ * 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.
+ *
+ * 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
+ * {@link org.junit.rules.ErrorCollector},
+ * {@link org.junit.rules.ExpectedException},
+ * and {@link org.junit.rules.Timeout},
+ * have undefined behavior when used as {@link ClassRule}s.
+ *
+ * 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.
+ *
+ * For example, here is a test suite that connects to a server once before
+ * all the test classes run, and disconnects after they are finished:
+ *
+ * <pre>
+ *
+ * &#064;RunWith(Suite.class)
+ * &#064;SuiteClasses({A.class, B.class, C.class})
+ * public class UsesExternalResource {
+ * public static Server myServer= new Server();
+ *
+ * &#064;ClassRule
+ * public static ExternalResource resource= new ExternalResource() {
+ * &#064;Override
+ * protected void before() throws Throwable {
+ * myServer.connect();
+ * };
+ *
+ * &#064;Override
+ * protected void after() {
+ * myServer.disconnect();
+ * };
+ * };
+ * }
+ * </pre>
+ *
+ * For more information and more examples, see {@link org.junit.rules.TestRule}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface ClassRule {
+}
diff --git a/src/org/junit/ComparisonFailure.java b/src/org/junit/ComparisonFailure.java
new file mode 100644
index 0000000..d37db4f
--- /dev/null
+++ b/src/org/junit/ComparisonFailure.java
@@ -0,0 +1,138 @@
+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.
+ *
+ * Inspired by a patch from Alex Chaffee (alex@purpletech.com)
+ */
+public class ComparisonFailure extends AssertionError {
+ /**
+ * The maximum length for fExpected and fActual. 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;
+
+ private String fExpected;
+ private String fActual;
+
+ /**
+ * Constructs a comparison failure.
+ * @param message the identifying message or null
+ * @param expected the expected string value
+ * @param actual the actual string value
+ */
+ public ComparisonFailure (String message, String expected, String actual) {
+ super (message);
+ fExpected= expected;
+ fActual= actual;
+ }
+
+ /**
+ * Returns "..." in place of common prefix and "..." in
+ * place of common suffix between expected and actual.
+ *
+ * @see Throwable#getMessage()
+ */
+ @Override
+ public String getMessage() {
+ return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage());
+ }
+
+ /**
+ * Returns the actual string value
+ * @return the actual string value
+ */
+ public String getActual() {
+ return fActual;
+ }
+ /**
+ * Returns the expected string value
+ * @return the expected string value
+ */
+ public String getExpected() {
+ return fExpected;
+ }
+
+ private static class ComparisonCompactor {
+ private static final String ELLIPSIS= "...";
+ private static final String DELTA_END= "]";
+ private static final String DELTA_START= "[";
+
+ /**
+ * The maximum length for <code>expected</code> and <code>actual</code>. 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;
+
+ /**
+ * @param contextLength the maximum length for <code>expected</code> and <code>actual</code>. When contextLength
+ * is exceeded, the Strings are shortened
+ * @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;
+ }
+
+ private String compact(String message) {
+ if (fExpected == null || fActual == null || areStringsEqual())
+ return Assert.format(message, fExpected, fActual);
+
+ 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;
+ if (fSuffix > 0)
+ result= result + computeCommonSuffix();
+ return result;
+ }
+
+ private void findCommonPrefix() {
+ fPrefix= 0;
+ int end= Math.min(fExpected.length(), fActual.length());
+ for (; fPrefix < end; fPrefix++) {
+ if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix))
+ break;
+ }
+ }
+
+ 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;
+ }
+ fSuffix= fExpected.length() - expectedSuffix;
+ }
+
+ private String computeCommonPrefix() {
+ return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix);
+ }
+
+ 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 : "");
+ }
+
+ private boolean areStringsEqual() {
+ return fExpected.equals(fActual);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/Ignore.java b/src/org/junit/Ignore.java
new file mode 100644
index 0000000..de530a9
--- /dev/null
+++ b/src/org/junit/Ignore.java
@@ -0,0 +1,39 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>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>
+ *
+ * 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/>
+ * <pre>
+ * &#064;Ignore("not ready yet") &#064;Test public void something() { ...
+ * </pre>
+ * &#064;Ignore can also be applied to the test class:<br/>
+ * <pre>
+ * &#064;Ignore public class IgnoreMe {
+ * &#064;Test public void test1() { ... }
+ * &#064;Test public void test2() { ... }
+ * }
+ * </pre>
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface Ignore {
+ /**
+ * The optional reason why the test is ignored.
+ */
+ String value() default "";
+}
diff --git a/src/org/junit/Rule.java b/src/org/junit/Rule.java
new file mode 100644
index 0000000..9e67c07
--- /dev/null
+++ b/src/org/junit/Rule.java
@@ -0,0 +1,47 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates fields that contain rules. Such a field must be public, not
+ * static, and a subtype of {@link org.junit.rules.TestRule}.
+ * The {@link org.junit.runners.model.Statement} passed
+ * to the {@link org.junit.rules.TestRule} will run any {@link Before} methods,
+ * then the {@link Test} method, and finally any {@link After} methods,
+ * throwing an exception if any of these fail. If there are multiple
+ * annotated {@link Rule}s on a class, they will be applied in an order
+ * that depends on your JVM's implementation of the reflection API, which is
+ * undefined, in general.
+ *
+ * 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
+ * public TemporaryFolder folder= new TemporaryFolder();
+ *
+ * &#064;Test
+ * public void testUsingTempFolder() throws IOException {
+ * File createdFile= folder.newFile(&quot;myfile.txt&quot;);
+ * File createdFolder= folder.newFolder(&quot;subfolder&quot;);
+ * // ...
+ * }
+ * }
+ * </pre>
+ *
+ * For more information and more examples, see
+ * {@link org.junit.rules.TestRule}.
+ *
+ * Note: for backwards compatibility, this annotation may also mark
+ * fields of type {@link org.junit.rules.MethodRule}, which will be honored. However,
+ * this is a deprecated interface and feature.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Rule {
+
+} \ No newline at end of file
diff --git a/src/org/junit/Test.java b/src/org/junit/Test.java
new file mode 100644
index 0000000..23dc78a
--- /dev/null
+++ b/src/org/junit/Test.java
@@ -0,0 +1,68 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>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:
+ * <pre>
+ * public class Example {
+ * <b>&#064;Test</b>
+ * public void method() {
+ * org.junit.Assert.assertTrue( new ArrayList().isEmpty() );
+ * }
+ * }
+ * </pre>
+ * </p>
+ *
+ * <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:
+ * <pre>
+ * &#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
+ * 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>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Test {
+
+ /**
+ * Default empty exception
+ */
+ static class None extends Throwable {
+ private static final long serialVersionUID= 1L;
+ private None() {
+ }
+ }
+
+ /**
+ * Optionally specify <code>expected</code>, a Throwable, to cause a test method to succeed iff
+ * an exception of the specified class is thrown by the method.
+ */
+ 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.*/
+ long timeout() default 0L;
+}
diff --git a/src/org/junit/experimental/ParallelComputer.java b/src/org/junit/experimental/ParallelComputer.java
new file mode 100644
index 0000000..fccb97c
--- /dev/null
+++ b/src/org/junit/experimental/ParallelComputer.java
@@ -0,0 +1,78 @@
+package org.junit.experimental;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.runner.Computer;
+import org.junit.runner.Runner;
+import org.junit.runners.ParentRunner;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+import org.junit.runners.model.RunnerScheduler;
+
+public class ParallelComputer extends Computer {
+ private final boolean fClasses;
+
+ private final boolean fMethods;
+
+ public ParallelComputer(boolean classes, boolean methods) {
+ fClasses= classes;
+ fMethods= methods;
+ }
+
+ public static Computer classes() {
+ return new ParallelComputer(true, false);
+ }
+
+ public static Computer methods() {
+ return new ParallelComputer(false, true);
+ }
+
+ private static <T> Runner parallelize(Runner runner) {
+ if (runner instanceof ParentRunner<?>) {
+ ((ParentRunner<?>) runner).setScheduler(new RunnerScheduler() {
+ private final List<Future<Object>> fResults= new ArrayList<Future<Object>>();
+
+ private final ExecutorService fService= Executors
+ .newCachedThreadPool();
+
+ public void schedule(final Runnable childStatement) {
+ fResults.add(fService.submit(new Callable<Object>() {
+ public Object call() throws Exception {
+ childStatement.run();
+ return null;
+ }
+ }));
+ }
+
+ public void finished() {
+ for (Future<Object> each : fResults)
+ try {
+ each.get();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ return runner;
+ }
+
+ @Override
+ public Runner getSuite(RunnerBuilder builder, java.lang.Class<?>[] classes)
+ throws InitializationError {
+ Runner suite= super.getSuite(builder, classes);
+ return fClasses ? parallelize(suite) : suite;
+ }
+
+ @Override
+ protected Runner getRunner(RunnerBuilder builder, Class<?> testClass)
+ throws Throwable {
+ Runner runner= super.getRunner(builder, testClass);
+ return fMethods ? parallelize(runner) : runner;
+ }
+}
diff --git a/src/org/junit/experimental/categories/Categories.java b/src/org/junit/experimental/categories/Categories.java
new file mode 100644
index 0000000..d57b4d3
--- /dev/null
+++ b/src/org/junit/experimental/categories/Categories.java
@@ -0,0 +1,192 @@
+/**
+ *
+ */
+package org.junit.experimental.categories;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * From a given set of test classes, runs only the classes and methods that are
+ * annotated with either the category given with the @IncludeCategory
+ * annotation, or a subtype of that category.
+ *
+ * Note that, for now, annotating suites with {@code @Category} has no effect.
+ * Categories must be annotated on the direct method or class.
+ *
+ * Example:
+ *
+ * <pre>
+ * public interface FastTests {
+ * }
+ *
+ * public interface SlowTests {
+ * }
+ *
+ * public static class A {
+ * &#064;Test
+ * public void a() {
+ * fail();
+ * }
+ *
+ * &#064;Category(SlowTests.class)
+ * &#064;Test
+ * public void b() {
+ * }
+ * }
+ *
+ * &#064;Category( { SlowTests.class, FastTests.class })
+ * public static class B {
+ * &#064;Test
+ * public void c() {
+ *
+ * }
+ * }
+ *
+ * &#064;RunWith(Categories.class)
+ * &#064;IncludeCategory(SlowTests.class)
+ * &#064;SuiteClasses( { A.class, B.class })
+ * // Note that Categories is a kind of Suite
+ * public static class SlowTestSuite {
+ * }
+ * </pre>
+ */
+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 {
+ public Class<?> value();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface ExcludeCategory {
+ public Class<?> value();
+ }
+
+ public static class CategoryFilter extends Filter {
+ public static CategoryFilter include(Class<?> categoryType) {
+ return new CategoryFilter(categoryType, null);
+ }
+
+ private final Class<?> fIncluded;
+
+ private final Class<?> fExcluded;
+
+ public CategoryFilter(Class<?> includedCategory,
+ Class<?> excludedCategory) {
+ fIncluded= includedCategory;
+ fExcluded= excludedCategory;
+ }
+
+ @Override
+ public String describe() {
+ return "category " + fIncluded;
+ }
+
+ @Override
+ public boolean shouldRun(Description description) {
+ if (hasCorrectCategoryAnnotation(description))
+ return true;
+ for (Description each : description.getChildren())
+ if (shouldRun(each))
+ return true;
+ return false;
+ }
+
+ private boolean hasCorrectCategoryAnnotation(Description description) {
+ List<Class<?>> categories= categories(description);
+ if (categories.isEmpty())
+ return fIncluded == null;
+ for (Class<?> each : categories)
+ if (fExcluded != null && fExcluded.isAssignableFrom(each))
+ return false;
+ for (Class<?> each : categories)
+ if (fIncluded == null || fIncluded.isAssignableFrom(each))
+ return true;
+ return false;
+ }
+
+ private List<Class<?>> categories(Description description) {
+ ArrayList<Class<?>> categories= new ArrayList<Class<?>>();
+ categories.addAll(Arrays.asList(directCategories(description)));
+ categories.addAll(Arrays.asList(directCategories(parentDescription(description))));
+ return categories;
+ }
+
+ private Description parentDescription(Description description) {
+ Class<?> testClass= description.getTestClass();
+ if (testClass == null)
+ return null;
+ return Description.createSuiteDescription(testClass);
+ }
+
+ private Class<?>[] directCategories(Description description) {
+ if (description == null)
+ return new Class<?>[0];
+ Category annotation= description.getAnnotation(Category.class);
+ if (annotation == null)
+ return new Class<?>[0];
+ return annotation.value();
+ }
+ }
+
+ public Categories(Class<?> klass, RunnerBuilder builder)
+ throws InitializationError {
+ super(klass, builder);
+ try {
+ filter(new CategoryFilter(getIncludedCategory(klass),
+ getExcludedCategory(klass)));
+ } catch (NoTestsRemainException e) {
+ throw new InitializationError(e);
+ }
+ assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription());
+ }
+
+ private Class<?> getIncludedCategory(Class<?> klass) {
+ IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class);
+ return annotation == null ? null : annotation.value();
+ }
+
+ private Class<?> getExcludedCategory(Class<?> klass) {
+ ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class);
+ return annotation == null ? null : annotation.value();
+ }
+
+ private void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError {
+ if (!canHaveCategorizedChildren(description))
+ assertNoDescendantsHaveCategoryAnnotations(description);
+ for (Description each : description.getChildren())
+ assertNoCategorizedDescendentsOfUncategorizeableParents(each);
+ }
+
+ private 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;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/categories/Category.java b/src/org/junit/experimental/categories/Category.java
new file mode 100644
index 0000000..3a4c0b9
--- /dev/null
+++ b/src/org/junit/experimental/categories/Category.java
@@ -0,0 +1,43 @@
+package org.junit.experimental.categories;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Marks a test class or test method as belonging to one or more categories of tests.
+ * The value is an array of arbitrary classes.
+ *
+ * This annotation is only interpreted by the Categories runner (at present).
+ *
+ * For example:
+<pre>
+ public interface FastTests {}
+ public interface SlowTests {}
+
+ public static class A {
+ &#064;Test
+ public void a() {
+ fail();
+ }
+
+ &#064;Category(SlowTests.class)
+ &#064;Test
+ public void b() {
+ }
+ }
+
+ &#064;Category({SlowTests.class, FastTests.class})
+ public static class B {
+ &#064;Test
+ public void c() {
+
+ }
+ }
+</pre>
+ *
+ * For more usage, see code example on {@link Categories}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Category {
+ Class<?>[] value();
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/max/CouldNotReadCoreException.java b/src/org/junit/experimental/max/CouldNotReadCoreException.java
new file mode 100644
index 0000000..03c3c8c
--- /dev/null
+++ b/src/org/junit/experimental/max/CouldNotReadCoreException.java
@@ -0,0 +1,15 @@
+package org.junit.experimental.max;
+
+/**
+ * Thrown when Max cannot read the MaxCore serialization
+ */
+public class CouldNotReadCoreException extends Exception {
+ private static final long serialVersionUID= 1L;
+
+ /**
+ * Constructs
+ */
+ public CouldNotReadCoreException(Throwable e) {
+ super(e);
+ }
+}
diff --git a/src/org/junit/experimental/max/MaxCore.java b/src/org/junit/experimental/max/MaxCore.java
new file mode 100644
index 0000000..a2a34a9
--- /dev/null
+++ b/src/org/junit/experimental/max/MaxCore.java
@@ -0,0 +1,170 @@
+package org.junit.experimental.max;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestSuite;
+
+import org.junit.internal.requests.SortingRequest;
+import org.junit.internal.runners.ErrorReportingRunner;
+import org.junit.internal.runners.JUnit38ClassRunner;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.Runner;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+
+/**
+ * A replacement for JUnitCore, which keeps track of runtime and failure history, and reorders tests
+ * to maximize the chances that a failing test occurs early in the test run.
+ *
+ * The rules for sorting are:
+ * <ol>
+ * <li> Never-run tests first, in arbitrary order
+ * <li> Group remaining tests by the date at which they most recently failed.
+ * <li> Sort groups such that the most recent failure date is first, and never-failing tests are at the end.
+ * <li> Within a group, run the fastest tests first.
+ * </ol>
+ */
+public class MaxCore {
+ private static final String MALFORMED_JUNIT_3_TEST_CLASS_PREFIX= "malformed JUnit 3 test class: ";
+
+ /**
+ * Create a new MaxCore from a serialized file stored at storedResults
+ * @deprecated use storedLocally()
+ */
+ @Deprecated
+ public static MaxCore forFolder(String folderName) {
+ return storedLocally(new File(folderName));
+ }
+
+ /**
+ * Create a new MaxCore from a serialized file stored at storedResults
+ */
+ public static MaxCore storedLocally(File storedResults) {
+ return new MaxCore(storedResults);
+ }
+
+ private final MaxHistory fHistory;
+
+ private MaxCore(File storedResults) {
+ fHistory = MaxHistory.forFolder(storedResults);
+ }
+
+ /**
+ * Run all the tests in <code>class</code>.
+ * @return a {@link Result} describing the details of the test run and the failed tests.
+ */
+ public Result run(Class<?> testClass) {
+ return run(Request.aClass(testClass));
+ }
+
+ /**
+ * Run all the tests contained in <code>request</code>.
+ * @param request the request describing tests
+ * @return a {@link Result} describing the details of the test run and the failed tests.
+ */
+ public Result run(Request request) {
+ return run(request, new JUnitCore());
+ }
+
+ /**
+ * Run all the tests contained in <code>request</code>.
+ *
+ * This variant should be used if {@code core} has attached listeners that this
+ * run should notify.
+ *
+ * @param request the request describing tests
+ * @param core a JUnitCore to delegate to.
+ * @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());
+ return core.run(sortRequest(request).getRunner());
+ }
+
+ /**
+ * @param request
+ * @return a new Request, which contains all of the same tests, but in a new order.
+ */
+ public Request sortRequest(Request request) {
+ if (request instanceof SortingRequest) // We'll pay big karma points for this
+ return request;
+ List<Description> leaves= findLeaves(request);
+ Collections.sort(leaves, fHistory.testComparator());
+ return constructLeafRequest(leaves);
+ }
+
+ private Request constructLeafRequest(List<Description> leaves) {
+ final List<Runner> runners = new ArrayList<Runner>();
+ for (Description each : leaves)
+ runners.add(buildRunner(each));
+ return new Request() {
+ @Override
+ public Runner getRunner() {
+ try {
+ return new Suite((Class<?>)null, runners) {};
+ } catch (InitializationError e) {
+ return new ErrorReportingRunner(null, e);
+ }
+ }
+ };
+ }
+
+ private Runner buildRunner(Description each) {
+ if (each.toString().equals("TestSuite with 0 tests"))
+ return Suite.emptySuite();
+ if (each.toString().startsWith(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX))
+ // This is cheating, because it runs the whole class
+ // to get the warning for this method, but we can't do better,
+ // because JUnit 3.8's
+ // thrown away which method the warning is for.
+ return new JUnit38ClassRunner(new TestSuite(getMalformedTestClass(each)));
+ Class<?> type= each.getTestClass();
+ if (type == null)
+ throw new RuntimeException("Can't build a runner from description [" + each + "]");
+ String methodName= each.getMethodName();
+ if (methodName == null)
+ return Request.aClass(type).getRunner();
+ return Request.method(type, methodName).getRunner();
+ }
+
+ private Class<?> getMalformedTestClass(Description each) {
+ try {
+ return Class.forName(each.toString().replace(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX, ""));
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @param request a request to run
+ * @return a list of method-level tests to run, sorted in the order
+ * specified in the class comment.
+ */
+ public List<Description> sortedLeavesForTest(Request request) {
+ return findLeaves(sortRequest(request));
+ }
+
+ private List<Description> findLeaves(Request request) {
+ List<Description> results= new ArrayList<Description>();
+ findLeaves(null, request.getRunner().getDescription(), results);
+ return results;
+ }
+
+ private void findLeaves(Description parent, Description description, List<Description> results) {
+ if (description.getChildren().isEmpty())
+ if (description.toString().equals("warning(junit.framework.TestSuite$1)"))
+ results.add(Description.createSuiteDescription(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX + parent));
+ else
+ results.add(description);
+ else
+ for (Description each : description.getChildren())
+ findLeaves(description, each, results);
+ }
+}
+
diff --git a/src/org/junit/experimental/max/MaxHistory.java b/src/org/junit/experimental/max/MaxHistory.java
new file mode 100644
index 0000000..e091793
--- /dev/null
+++ b/src/org/junit/experimental/max/MaxHistory.java
@@ -0,0 +1,166 @@
+package org.junit.experimental.max;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+/**
+ * Stores a subset of the history of each test:
+ * <ul>
+ * <li>Last failure timestamp
+ * <li>Duration of last execution
+ * </ul>
+ */
+public class MaxHistory implements Serializable {
+ private static final long serialVersionUID= 1L;
+
+ /**
+ * Loads a {@link MaxHistory} from {@code file}, or generates a new one that
+ * will be saved to {@code file}.
+ */
+ public static MaxHistory forFolder(File file) {
+ if (file.exists())
+ try {
+ return readHistory(file);
+ } catch (CouldNotReadCoreException e) {
+ e.printStackTrace();
+ file.delete();
+ }
+ return new MaxHistory(file);
+ }
+
+ private static MaxHistory readHistory(File storedResults)
+ throws CouldNotReadCoreException {
+ try {
+ FileInputStream file= new FileInputStream(storedResults);
+ try {
+ ObjectInputStream stream= new ObjectInputStream(file);
+ try {
+ return (MaxHistory) stream.readObject();
+ } finally {
+ stream.close();
+ }
+ } finally {
+ file.close();
+ }
+ } catch (Exception e) {
+ throw new CouldNotReadCoreException(e);
+ }
+ }
+
+ 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) {
+ fHistoryStore= storedResults;
+ }
+
+ private void save() throws IOException {
+ ObjectOutputStream stream= new ObjectOutputStream(new FileOutputStream(
+ fHistoryStore));
+ stream.writeObject(this);
+ stream.close();
+ }
+
+ Long getFailureTimestamp(Description key) {
+ return fFailureTimestamps.get(key.toString());
+ }
+
+ void putTestFailureTimestamp(Description key, long end) {
+ fFailureTimestamps.put(key.toString(), end);
+ }
+
+ boolean isNewTest(Description key) {
+ return !fDurations.containsKey(key.toString());
+ }
+
+ Long getTestDuration(Description key) {
+ return fDurations.get(key.toString());
+ }
+
+ void putTestDuration(Description description, long duration) {
+ fDurations.put(description.toString(), duration);
+ }
+
+ private final class RememberingListener extends RunListener {
+ private long overallStart= System.currentTimeMillis();
+
+ private Map<Description, Long> starts= new HashMap<Description, Long>();
+
+ @Override
+ public void testStarted(Description description) throws Exception {
+ starts.put(description, System.nanoTime()); // Get most accurate
+ // possible time
+ }
+
+ @Override
+ public void testFinished(Description description) throws Exception {
+ long end= System.nanoTime();
+ long start= starts.get(description);
+ putTestDuration(description, end - start);
+ }
+
+ @Override
+ public void testFailure(Failure failure) throws Exception {
+ putTestFailureTimestamp(failure.getDescription(), overallStart);
+ }
+
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ save();
+ }
+ }
+
+ private class TestComparator implements Comparator<Description> {
+ public int compare(Description o1, Description o2) {
+ // Always prefer new tests
+ if (isNewTest(o1))
+ return -1;
+ if (isNewTest(o2))
+ return 1;
+ // Then most recently failed first
+ int result= getFailure(o2).compareTo(getFailure(o1));
+ return result != 0 ? result
+ // Then shorter tests first
+ : getTestDuration(o1).compareTo(getTestDuration(o2));
+ }
+
+ private Long getFailure(Description key) {
+ Long result= getFailureTimestamp(key);
+ if (result == null)
+ return 0L; // 0 = "never failed (that I know about)"
+ return result;
+ }
+ }
+
+ /**
+ * @return a listener that will update this history based on the test
+ * results reported.
+ */
+ public RunListener listener() {
+ return new RememberingListener();
+ }
+
+ /**
+ * @return a comparator that ranks tests based on the JUnit Max sorting
+ * rules, as described in the {@link MaxCore} class comment.
+ */
+ public Comparator<Description> testComparator() {
+ return new TestComparator();
+ }
+}
diff --git a/src/org/junit/experimental/results/FailureList.java b/src/org/junit/experimental/results/FailureList.java
new file mode 100644
index 0000000..f4bc9b7
--- /dev/null
+++ b/src/org/junit/experimental/results/FailureList.java
@@ -0,0 +1,31 @@
+/**
+ *
+ */
+package org.junit.experimental.results;
+
+import java.util.List;
+
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+class FailureList {
+ private final List<Failure> failures;
+
+ public FailureList(List<Failure> failures) {
+ this.failures= failures;
+ }
+
+ public Result result() {
+ Result result= new Result();
+ RunListener listener= result.createListener();
+ for (Failure failure : failures) {
+ try {
+ listener.testFailure(failure);
+ } catch (Exception e) {
+ throw new RuntimeException("I can't believe this happened");
+ }
+ }
+ return result;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/results/PrintableResult.java b/src/org/junit/experimental/results/PrintableResult.java
new file mode 100644
index 0000000..8bc6f54
--- /dev/null
+++ b/src/org/junit/experimental/results/PrintableResult.java
@@ -0,0 +1,63 @@
+package org.junit.experimental.results;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+import org.junit.internal.TextListener;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+/**
+ * A test result that prints nicely in error messages.
+ * This is only intended to be used in JUnit self-tests.
+ * For example:
+ *
+ * <pre>
+ * assertThat(testResult(HasExpectedException.class), isSuccessful());
+ * </pre>
+ */
+public class PrintableResult {
+ /**
+ * The result of running JUnit on {@code type}
+ */
+ public static PrintableResult testResult(Class<?> type) {
+ return testResult(Request.aClass(type));
+ }
+
+ /**
+ * The result of running JUnit on Request {@code request}
+ */
+ public static PrintableResult testResult(Request request) {
+ return new PrintableResult(new JUnitCore().run(request));
+ }
+
+ private Result result;
+
+ /**
+ * A result that includes the given {@code failures}
+ */
+ public PrintableResult(List<Failure> failures) {
+ this(new FailureList(failures).result());
+ }
+
+ private PrintableResult(Result result) {
+ this.result = result;
+ }
+
+ @Override
+ public String toString() {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ new TextListener(new PrintStream(stream)).testRunFinished(result);
+ return stream.toString();
+ }
+
+ /**
+ * Returns the number of failures in this result.
+ */
+ public int failureCount() {
+ return result.getFailures().size();
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/results/ResultMatchers.java b/src/org/junit/experimental/results/ResultMatchers.java
new file mode 100644
index 0000000..220d0dc
--- /dev/null
+++ b/src/org/junit/experimental/results/ResultMatchers.java
@@ -0,0 +1,70 @@
+package org.junit.experimental.results;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.internal.matchers.TypeSafeMatcher;
+
+/**
+ * Matchers on a PrintableResult, to enable JUnit self-tests.
+ * For example:
+ *
+ * <pre>
+ * assertThat(testResult(HasExpectedException.class), isSuccessful());
+ * </pre>
+ */
+public class ResultMatchers {
+ /**
+ * Matches if the tests are all successful
+ */
+ public static Matcher<PrintableResult> isSuccessful() {
+ return failureCountIs(0);
+ }
+
+ /**
+ * Matches if there are {@code count} failures
+ */
+ public static Matcher<PrintableResult> failureCountIs(final int count) {
+ return new TypeSafeMatcher<PrintableResult>() {
+ public void describeTo(Description description) {
+ description.appendText("has " + count + " failures");
+ }
+
+ @Override
+ public boolean matchesSafely(PrintableResult item) {
+ return item.failureCount() == count;
+ }
+ };
+ }
+
+ /**
+ * Matches if the result has exactly one failure, and it contains {@code string}
+ */
+ public static Matcher<Object> hasSingleFailureContaining(final String string) {
+ return new BaseMatcher<Object>() {
+ public boolean matches(Object item) {
+ return item.toString().contains(string) && failureCountIs(1).matches(item);
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("has single failure containing " + string);
+ }
+ };
+ }
+
+ /**
+ * Matches if the result has one or more failures, and at least one of them
+ * contains {@code string}
+ */
+ public static Matcher<PrintableResult> hasFailureContaining(final String string) {
+ return new BaseMatcher<PrintableResult>() {
+ public boolean matches(Object item) {
+ return item.toString().contains(string);
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("has failure containing " + string);
+ }
+ };
+ }
+}
diff --git a/src/org/junit/experimental/runners/Enclosed.java b/src/org/junit/experimental/runners/Enclosed.java
new file mode 100644
index 0000000..b0560ed
--- /dev/null
+++ b/src/org/junit/experimental/runners/Enclosed.java
@@ -0,0 +1,31 @@
+package org.junit.experimental.runners;
+
+import org.junit.runners.Suite;
+import org.junit.runners.model.RunnerBuilder;
+
+
+/**
+ * If you put tests in inner classes, Ant, for example, won't find them. By running the outer class
+ * with Enclosed, the tests in the inner classes will be run. You might put tests in inner classes
+ * to group them for convenience or to share constants.
+ *
+ * So, for example:
+ * <pre>
+ * \@RunWith(Enclosed.class)
+ * public class ListTests {
+ * ...useful shared stuff...
+ * public static class OneKindOfListTest {...}
+ * public static class AnotherKind {...}
+ * }
+ * </pre>
+ *
+ * For a real example, @see org.junit.tests.manipulation.SortableTest.
+ */
+public class Enclosed extends Suite {
+ /**
+ * Only called reflectively. Do not use programmatically.
+ */
+ public Enclosed(Class<?> klass, RunnerBuilder builder) throws Throwable {
+ super(builder, klass, klass.getClasses());
+ }
+}
diff --git a/src/org/junit/experimental/theories/DataPoint.java b/src/org/junit/experimental/theories/DataPoint.java
new file mode 100644
index 0000000..2aaba6a
--- /dev/null
+++ b/src/org/junit/experimental/theories/DataPoint.java
@@ -0,0 +1,9 @@
+package org.junit.experimental.theories;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DataPoint {
+
+}
diff --git a/src/org/junit/experimental/theories/DataPoints.java b/src/org/junit/experimental/theories/DataPoints.java
new file mode 100644
index 0000000..42145e3
--- /dev/null
+++ b/src/org/junit/experimental/theories/DataPoints.java
@@ -0,0 +1,9 @@
+package org.junit.experimental.theories;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DataPoints {
+
+}
diff --git a/src/org/junit/experimental/theories/ParameterSignature.java b/src/org/junit/experimental/theories/ParameterSignature.java
new file mode 100644
index 0000000..e7150fc
--- /dev/null
+++ b/src/org/junit/experimental/theories/ParameterSignature.java
@@ -0,0 +1,90 @@
+/**
+ *
+ */
+package org.junit.experimental.theories;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ParameterSignature {
+ public static ArrayList<ParameterSignature> signatures(Method method) {
+ return signatures(method.getParameterTypes(), method
+ .getParameterAnnotations());
+ }
+
+ public static List<ParameterSignature> signatures(Constructor<?> constructor) {
+ return signatures(constructor.getParameterTypes(), constructor
+ .getParameterAnnotations());
+ }
+
+ private static ArrayList<ParameterSignature> signatures(
+ Class<?>[] parameterTypes, Annotation[][] parameterAnnotations) {
+ ArrayList<ParameterSignature> sigs= new ArrayList<ParameterSignature>();
+ for (int i= 0; i < parameterTypes.length; i++) {
+ sigs.add(new ParameterSignature(parameterTypes[i],
+ parameterAnnotations[i]));
+ }
+ return sigs;
+ }
+
+ private final Class<?> type;
+
+ private final Annotation[] annotations;
+
+ private ParameterSignature(Class<?> type, Annotation[] annotations) {
+ this.type= type;
+ this.annotations= annotations;
+ }
+
+ public boolean canAcceptType(Class<?> candidate) {
+ return type.isAssignableFrom(candidate);
+ }
+
+ public Class<?> getType() {
+ return type;
+ }
+
+ public List<Annotation> getAnnotations() {
+ 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;
+ }
+
+ public <T extends Annotation> T findDeepAnnotation(Class<T> annotationType) {
+ Annotation[] annotations2= annotations;
+ return findDeepAnnotation(annotations2, annotationType, 3);
+ }
+
+ private <T extends Annotation> T findDeepAnnotation(
+ Annotation[] annotations, Class<T> annotationType, int depth) {
+ if (depth == 0)
+ return null;
+ for (Annotation each : annotations) {
+ if (annotationType.isInstance(each))
+ return annotationType.cast(each);
+ Annotation candidate= findDeepAnnotation(each.annotationType()
+ .getAnnotations(), annotationType, depth - 1);
+ if (candidate != null)
+ return annotationType.cast(candidate);
+ }
+
+ return null;
+ }
+
+ public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+ for (Annotation each : getAnnotations())
+ if (annotationType.isInstance(each))
+ return annotationType.cast(each);
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/theories/ParameterSupplier.java b/src/org/junit/experimental/theories/ParameterSupplier.java
new file mode 100644
index 0000000..9016c91
--- /dev/null
+++ b/src/org/junit/experimental/theories/ParameterSupplier.java
@@ -0,0 +1,8 @@
+package org.junit.experimental.theories;
+
+import java.util.List;
+
+
+public abstract class ParameterSupplier {
+ public abstract List<PotentialAssignment> getValueSources(ParameterSignature sig);
+}
diff --git a/src/org/junit/experimental/theories/ParametersSuppliedBy.java b/src/org/junit/experimental/theories/ParametersSuppliedBy.java
new file mode 100644
index 0000000..8f090ef
--- /dev/null
+++ b/src/org/junit/experimental/theories/ParametersSuppliedBy.java
@@ -0,0 +1,12 @@
+package org.junit.experimental.theories;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ParametersSuppliedBy {
+
+ Class<? extends ParameterSupplier> value();
+
+}
diff --git a/src/org/junit/experimental/theories/PotentialAssignment.java b/src/org/junit/experimental/theories/PotentialAssignment.java
new file mode 100644
index 0000000..0c008d0
--- /dev/null
+++ b/src/org/junit/experimental/theories/PotentialAssignment.java
@@ -0,0 +1,31 @@
+package org.junit.experimental.theories;
+
+public abstract class PotentialAssignment {
+ public static class CouldNotGenerateValueException extends Exception {
+ private static final long serialVersionUID= 1L;
+ }
+
+ public static PotentialAssignment forValue(final String name, final Object value) {
+ return new PotentialAssignment() {
+ @Override
+ public Object getValue() throws CouldNotGenerateValueException {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%s]", value);
+ }
+
+ @Override
+ public String getDescription()
+ throws CouldNotGenerateValueException {
+ return name;
+ }
+ };
+ }
+
+ public abstract Object getValue() throws CouldNotGenerateValueException;
+
+ public abstract String getDescription() throws CouldNotGenerateValueException;
+}
diff --git a/src/org/junit/experimental/theories/Theories.java b/src/org/junit/experimental/theories/Theories.java
new file mode 100644
index 0000000..82ff98b
--- /dev/null
+++ b/src/org/junit/experimental/theories/Theories.java
@@ -0,0 +1,199 @@
+/**
+ *
+ */
+package org.junit.experimental.theories;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+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.experimental.theories.internal.Assignments;
+import org.junit.experimental.theories.internal.ParameterizedAssertionError;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+public class Theories extends BlockJUnit4ClassRunner {
+ public Theories(Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+
+ @Override
+ protected void collectInitializationErrors(List<Throwable> errors) {
+ super.collectInitializationErrors(errors);
+ validateDataPointFields(errors);
+ }
+
+ private void validateDataPointFields(List<Throwable> errors) {
+ Field[] fields= getTestClass().getJavaClass().getDeclaredFields();
+
+ for (Field each : fields)
+ if (each.getAnnotation(DataPoint.class) != null && !Modifier.isStatic(each.getModifiers()))
+ errors.add(new Error("DataPoint field " + each.getName() + " must be static"));
+ }
+
+ @Override
+ protected void validateConstructor(List<Throwable> errors) {
+ validateOnlyOneConstructor(errors);
+ }
+
+ @Override
+ protected void validateTestMethods(List<Throwable> errors) {
+ for (FrameworkMethod each : computeTestMethods())
+ if(each.getAnnotation(Theory.class) != null)
+ each.validatePublicVoid(false, errors);
+ else
+ each.validatePublicVoidNoArg(false, errors);
+ }
+
+ @Override
+ protected List<FrameworkMethod> computeTestMethods() {
+ List<FrameworkMethod> testMethods= super.computeTestMethods();
+ List<FrameworkMethod> theoryMethods= getTestClass().getAnnotatedMethods(Theory.class);
+ testMethods.removeAll(theoryMethods);
+ testMethods.addAll(theoryMethods);
+ return testMethods;
+ }
+
+ @Override
+ public Statement methodBlock(final FrameworkMethod method) {
+ return new TheoryAnchor(method, getTestClass());
+ }
+
+ public static class TheoryAnchor extends Statement {
+ private int successes= 0;
+
+ private FrameworkMethod fTestMethod;
+ private TestClass fTestClass;
+
+ private List<AssumptionViolatedException> fInvalidParameters= new ArrayList<AssumptionViolatedException>();
+
+ public TheoryAnchor(FrameworkMethod method, TestClass testClass) {
+ fTestMethod= method;
+ fTestClass= testClass;
+ }
+
+ private TestClass getTestClass() {
+ return fTestClass;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ runWithAssignment(Assignments.allUnassigned(
+ fTestMethod.getMethod(), getTestClass()));
+
+ if (successes == 0)
+ Assert
+ .fail("Never found parameters that satisfied method assumptions. Violated assumptions: "
+ + fInvalidParameters);
+ }
+
+ protected void runWithAssignment(Assignments parameterAssignment)
+ throws Throwable {
+ if (!parameterAssignment.isComplete()) {
+ runWithIncompleteAssignment(parameterAssignment);
+ } else {
+ runWithCompleteAssignment(parameterAssignment);
+ }
+ }
+
+ protected void runWithIncompleteAssignment(Assignments incomplete)
+ throws InstantiationException, IllegalAccessException,
+ Throwable {
+ for (PotentialAssignment source : incomplete
+ .potentialsForNextUnassigned()) {
+ runWithAssignment(incomplete.assignNext(source));
+ }
+ }
+
+ protected void runWithCompleteAssignment(final Assignments complete)
+ throws InstantiationException, IllegalAccessException,
+ InvocationTargetException, NoSuchMethodException, Throwable {
+ new BlockJUnit4ClassRunner(getTestClass().getJavaClass()) {
+ @Override
+ protected void collectInitializationErrors(
+ List<Throwable> errors) {
+ // do nothing
+ }
+
+ @Override
+ public Statement methodBlock(FrameworkMethod method) {
+ final Statement statement= super.methodBlock(method);
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ statement.evaluate();
+ handleDataPointSuccess();
+ } catch (AssumptionViolatedException e) {
+ handleAssumptionViolation(e);
+ } catch (Throwable e) {
+ reportParameterizedError(e, complete
+ .getArgumentStrings(nullsOk()));
+ }
+ }
+
+ };
+ }
+
+ @Override
+ protected Statement methodInvoker(FrameworkMethod method, Object test) {
+ return methodCompletesWithParameters(method, complete, test);
+ }
+
+ @Override
+ public Object createTest() throws Exception {
+ return getTestClass().getOnlyConstructor().newInstance(
+ complete.getConstructorArguments(nullsOk()));
+ }
+ }.methodBlock(fTestMethod).evaluate();
+ }
+
+ private Statement methodCompletesWithParameters(
+ final FrameworkMethod method, final Assignments complete, final Object freshInstance) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ final Object[] values= complete.getMethodArguments(
+ nullsOk());
+ method.invokeExplosively(freshInstance, values);
+ } catch (CouldNotGenerateValueException e) {
+ // ignore
+ }
+ }
+ };
+ }
+
+ protected void handleAssumptionViolation(AssumptionViolatedException e) {
+ fInvalidParameters.add(e);
+ }
+
+ protected void reportParameterizedError(Throwable e, Object... params)
+ throws Throwable {
+ if (params.length == 0)
+ throw e;
+ throw new ParameterizedAssertionError(e, fTestMethod.getName(),
+ params);
+ }
+
+ private boolean nullsOk() {
+ Theory annotation= fTestMethod.getMethod().getAnnotation(
+ Theory.class);
+ if (annotation == null)
+ return false;
+ return annotation.nullsAccepted();
+ }
+
+ protected void handleDataPointSuccess() {
+ successes++;
+ }
+ }
+}
diff --git a/src/org/junit/experimental/theories/Theory.java b/src/org/junit/experimental/theories/Theory.java
new file mode 100644
index 0000000..134fe9d
--- /dev/null
+++ b/src/org/junit/experimental/theories/Theory.java
@@ -0,0 +1,12 @@
+/**
+ *
+ */
+package org.junit.experimental.theories;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Theory {
+ boolean nullsAccepted() default true;
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/theories/internal/AllMembersSupplier.java b/src/org/junit/experimental/theories/internal/AllMembersSupplier.java
new file mode 100644
index 0000000..615cc3e
--- /dev/null
+++ b/src/org/junit/experimental/theories/internal/AllMembersSupplier.java
@@ -0,0 +1,127 @@
+/**
+ *
+ */
+package org.junit.experimental.theories.internal;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+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.FrameworkMethod;
+import org.junit.runners.model.TestClass;
+
+/**
+ * Supplies Theory parameters based on all public members of the target class.
+ */
+public class AllMembersSupplier extends ParameterSupplier {
+ static class MethodParameterValue extends PotentialAssignment {
+ private final FrameworkMethod fMethod;
+
+ private MethodParameterValue(FrameworkMethod dataPointMethod) {
+ fMethod= dataPointMethod;
+ }
+
+ @Override
+ public Object getValue() throws CouldNotGenerateValueException {
+ try {
+ return fMethod.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
+ }
+ }
+
+ @Override
+ public String getDescription() throws CouldNotGenerateValueException {
+ return fMethod.getName();
+ }
+ }
+
+ private final TestClass fClass;
+
+ /**
+ * Constructs a new supplier for {@code type}
+ */
+ public AllMembersSupplier(TestClass type) {
+ fClass= type;
+ }
+
+ @Override
+ public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+ List<PotentialAssignment> list= new ArrayList<PotentialAssignment>();
+
+ addFields(sig, list);
+ addSinglePointMethods(sig, list);
+ addMultiPointMethods(list);
+
+ return list;
+ }
+
+ private void addMultiPointMethods(List<PotentialAssignment> list) {
+ for (FrameworkMethod dataPointsMethod : fClass
+ .getAnnotatedMethods(DataPoints.class))
+ try {
+ addArrayValues(dataPointsMethod.getName(), list, dataPointsMethod.invokeExplosively(null));
+ } catch (Throwable e) {
+ // ignore and move on
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private void addSinglePointMethods(ParameterSignature sig,
+ List<PotentialAssignment> list) {
+ for (FrameworkMethod dataPointMethod : fClass
+ .getAnnotatedMethods(DataPoint.class)) {
+ Class<?> type= sig.getType();
+ if ((dataPointMethod.producesType(type)))
+ 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) {
+ addArrayValues(field.getName(), list, getStaticFieldValue(field));
+ } 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 Object getStaticFieldValue(final Field field) {
+ try {
+ return field.get(null);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(
+ "unexpected: field from getClass doesn't exist on object");
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "unexpected: getFields returned an inaccessible field");
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/theories/internal/Assignments.java b/src/org/junit/experimental/theories/internal/Assignments.java
new file mode 100644
index 0000000..bd94f00
--- /dev/null
+++ b/src/org/junit/experimental/theories/internal/Assignments.java
@@ -0,0 +1,133 @@
+/**
+ *
+ */
+package org.junit.experimental.theories.internal;
+
+import java.lang.reflect.Method;
+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.ParametersSuppliedBy;
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.experimental.theories.PotentialAssignment.CouldNotGenerateValueException;
+import org.junit.runners.model.TestClass;
+
+/**
+ * A potentially incomplete list of value assignments for a method's formal
+ * parameters
+ */
+public class Assignments {
+ private List<PotentialAssignment> fAssigned;
+
+ private final List<ParameterSignature> fUnassigned;
+
+ private final TestClass fClass;
+
+ private Assignments(List<PotentialAssignment> assigned,
+ List<ParameterSignature> unassigned, TestClass testClass) {
+ fUnassigned= unassigned;
+ fAssigned= assigned;
+ fClass= testClass;
+ }
+
+ /**
+ * Returns a new assignment list for {@code testMethod}, with no params
+ * assigned.
+ */
+ public static Assignments allUnassigned(Method testMethod,
+ TestClass testClass) throws Exception {
+ List<ParameterSignature> signatures;
+ signatures= ParameterSignature.signatures(testClass
+ .getOnlyConstructor());
+ signatures.addAll(ParameterSignature.signatures(testMethod));
+ return new Assignments(new ArrayList<PotentialAssignment>(),
+ signatures, testClass);
+ }
+
+ public boolean isComplete() {
+ return fUnassigned.size() == 0;
+ }
+
+ public ParameterSignature nextUnassigned() {
+ return fUnassigned.get(0);
+ }
+
+ public Assignments assignNext(PotentialAssignment source) {
+ List<PotentialAssignment> assigned= new ArrayList<PotentialAssignment>(
+ fAssigned);
+ assigned.add(source);
+
+ return new Assignments(assigned, fUnassigned.subList(1, fUnassigned
+ .size()), fClass);
+ }
+
+ public Object[] getActualValues(int start, int stop, boolean nullsOk)
+ 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;
+ }
+ return values;
+ }
+
+ public List<PotentialAssignment> potentialsForNextUnassigned()
+ throws InstantiationException, IllegalAccessException {
+ 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;
+
+ return new AllMembersSupplier(fClass);
+ }
+
+ public ParameterSupplier getAnnotatedSupplier(ParameterSignature unassigned)
+ throws InstantiationException, IllegalAccessException {
+ ParametersSuppliedBy annotation= unassigned
+ .findDeepAnnotation(ParametersSuppliedBy.class);
+ if (annotation == null)
+ return null;
+ return annotation.value().newInstance();
+ }
+
+ public Object[] getConstructorArguments(boolean nullsOk)
+ throws CouldNotGenerateValueException {
+ return getActualValues(0, getConstructorParameterCount(), nullsOk);
+ }
+
+ public Object[] getMethodArguments(boolean nullsOk)
+ throws CouldNotGenerateValueException {
+ return getActualValues(getConstructorParameterCount(),
+ fAssigned.size(), nullsOk);
+ }
+
+ public Object[] getAllArguments(boolean nullsOk)
+ throws CouldNotGenerateValueException {
+ return getActualValues(0, fAssigned.size(), nullsOk);
+ }
+
+ private int getConstructorParameterCount() {
+ List<ParameterSignature> signatures= ParameterSignature
+ .signatures(fClass.getOnlyConstructor());
+ int constructorParameterCount= signatures.size();
+ return constructorParameterCount;
+ }
+
+ public Object[] getArgumentStrings(boolean nullsOk)
+ throws CouldNotGenerateValueException {
+ Object[] values= new Object[fAssigned.size()];
+ for (int i= 0; i < values.length; i++) {
+ values[i]= fAssigned.get(i).getDescription();
+ }
+ return values;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/theories/internal/ParameterizedAssertionError.java b/src/org/junit/experimental/theories/internal/ParameterizedAssertionError.java
new file mode 100644
index 0000000..285bc3a
--- /dev/null
+++ b/src/org/junit/experimental/theories/internal/ParameterizedAssertionError.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package org.junit.experimental.theories.internal;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+
+public class ParameterizedAssertionError extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public ParameterizedAssertionError(Throwable targetException,
+ String methodName, Object... params) {
+ super(String.format("%s(%s)", methodName, join(", ", params)),
+ targetException);
+ }
+
+ @Override public boolean equals(Object obj) {
+ return toString().equals(obj.toString());
+ }
+
+ 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();
+ Iterator<Object> iter = values.iterator();
+ while (iter.hasNext()) {
+ Object next = iter.next();
+ buffer.append(stringValueOf(next));
+ if (iter.hasNext()) {
+ buffer.append(delimiter);
+ }
+ }
+ return buffer.toString();
+ }
+
+ private static String stringValueOf(Object next) {
+ try {
+ return String.valueOf(next);
+ } catch (Throwable e) {
+ return "[toString failed]";
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/experimental/theories/suppliers/TestedOn.java b/src/org/junit/experimental/theories/suppliers/TestedOn.java
new file mode 100644
index 0000000..d6ede64
--- /dev/null
+++ b/src/org/junit/experimental/theories/suppliers/TestedOn.java
@@ -0,0 +1,13 @@
+package org.junit.experimental.theories.suppliers;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import org.junit.experimental.theories.ParametersSuppliedBy;
+
+
+@ParametersSuppliedBy(TestedOnSupplier.class)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestedOn {
+ int[] ints();
+}
diff --git a/src/org/junit/experimental/theories/suppliers/TestedOnSupplier.java b/src/org/junit/experimental/theories/suppliers/TestedOnSupplier.java
new file mode 100644
index 0000000..f80298f
--- /dev/null
+++ b/src/org/junit/experimental/theories/suppliers/TestedOnSupplier.java
@@ -0,0 +1,23 @@
+package org.junit.experimental.theories.suppliers;
+
+import java.util.ArrayList;
+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 TestedOnSupplier extends ParameterSupplier {
+ @Override public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+ List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
+ TestedOn testedOn = sig.getAnnotation(TestedOn.class);
+ int[] ints = testedOn.ints();
+ for (final int i : ints) {
+ list.add(PotentialAssignment.forValue(Arrays.asList(ints).toString(), i));
+ }
+ return list;
+ }
+}
diff --git a/src/org/junit/internal/ArrayComparisonFailure.java b/src/org/junit/internal/ArrayComparisonFailure.java
new file mode 100644
index 0000000..08851de
--- /dev/null
+++ b/src/org/junit/internal/ArrayComparisonFailure.java
@@ -0,0 +1,59 @@
+package org.junit.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+
+/**
+ * Thrown when two array elements differ
+ * @see Assert#assertArrayEquals(String, Object[], Object[])
+ */
+public class ArrayComparisonFailure extends AssertionError {
+
+ private static final long serialVersionUID= 1L;
+
+ private 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
+ * dimension that was not equal
+ * @param cause the exception that caused the array's content to fail the assertion test
+ * @param index the array position of the objects that are not equal.
+ * @see Assert#assertArrayEquals(String, Object[], Object[])
+ */
+ public ArrayComparisonFailure(String message, AssertionError cause, int index) {
+ fMessage= message;
+ fCause= cause;
+ addDimension(index);
+ }
+
+ public void addDimension(int index) {
+ fIndices.add(0, index);
+ }
+
+ @Override
+ public String getMessage() {
+ StringBuilder builder= new StringBuilder();
+ if (fMessage != null)
+ builder.append(fMessage);
+ builder.append("arrays first differed at element ");
+ for (int each : fIndices) {
+ builder.append("[");
+ builder.append(each);
+ builder.append("]");
+ }
+ builder.append("; ");
+ builder.append(fCause.getMessage());
+ return builder.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override public String toString() {
+ return getMessage();
+ }
+}
diff --git a/src/org/junit/internal/AssumptionViolatedException.java b/src/org/junit/internal/AssumptionViolatedException.java
new file mode 100644
index 0000000..8e11268
--- /dev/null
+++ b/src/org/junit/internal/AssumptionViolatedException.java
@@ -0,0 +1,40 @@
+package org.junit.internal;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.SelfDescribing;
+import org.hamcrest.StringDescription;
+
+public class AssumptionViolatedException extends RuntimeException implements SelfDescribing {
+ private static final long serialVersionUID= 1L;
+
+ private final Object fValue;
+
+ private final Matcher<?> fMatcher;
+
+ public AssumptionViolatedException(Object value, Matcher<?> matcher) {
+ super(value instanceof Throwable ? (Throwable) value : null);
+ fValue= value;
+ fMatcher= matcher;
+ }
+
+ public AssumptionViolatedException(String assumption) {
+ this(assumption, null);
+ }
+
+ @Override
+ public String getMessage() {
+ return StringDescription.asString(this);
+ }
+
+ public void describeTo(Description description) {
+ if (fMatcher != null) {
+ description.appendText("got: ");
+ description.appendValue(fValue);
+ description.appendText(", expected: ");
+ description.appendDescriptionOf(fMatcher);
+ } else {
+ description.appendText("failed assumption: " + fValue);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/ComparisonCriteria.java b/src/org/junit/internal/ComparisonCriteria.java
new file mode 100644
index 0000000..e97011d
--- /dev/null
+++ b/src/org/junit/internal/ComparisonCriteria.java
@@ -0,0 +1,76 @@
+package org.junit.internal;
+
+import java.lang.reflect.Array;
+
+import org.junit.Assert;
+
+/**
+ * Defines criteria for finding two items "equal enough". Concrete subclasses
+ * may demand exact equality, or, for example, equality within a given delta.
+ */
+public abstract class ComparisonCriteria {
+ /**
+ * Asserts that two arrays are equal, according to the criteria defined by
+ * the concrete subclass. 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
+ * Object array or array of arrays (multi-dimensional array) with
+ * expected values.
+ * @param actuals
+ * Object array or array of arrays (multi-dimensional array) with
+ * actual values
+ */
+ public void arrayEquals(String message, Object expecteds, Object actuals)
+ throws ArrayComparisonFailure {
+ if (expecteds == actuals)
+ return;
+ String header= message == null ? "" : message + ": ";
+
+ int expectedsLength= assertArraysAreSameLength(expecteds,
+ actuals, header);
+
+ for (int i= 0; i < expectedsLength; i++) {
+ Object expected= Array.get(expecteds, i);
+ Object actual= Array.get(actuals, i);
+
+ if (isArray(expected) && isArray(actual)) {
+ try {
+ arrayEquals(message, expected, actual);
+ } catch (ArrayComparisonFailure e) {
+ e.addDimension(i);
+ throw e;
+ }
+ } else
+ try {
+ assertElementsEqual(expected, actual);
+ } catch (AssertionError e) {
+ throw new ArrayComparisonFailure(header, e, i);
+ }
+ }
+ }
+
+ private boolean isArray(Object expected) {
+ return expected != null && expected.getClass().isArray();
+ }
+
+ private int assertArraysAreSameLength(Object expecteds,
+ Object actuals, String header) {
+ if (expecteds == null)
+ Assert.fail(header + "expected array was null");
+ if (actuals == null)
+ Assert.fail(header + "actual array was null");
+ int actualsLength= Array.getLength(actuals);
+ int expectedsLength= Array.getLength(expecteds);
+ if (actualsLength != expectedsLength)
+ Assert.fail(header + "array lengths differed, expected.length="
+ + expectedsLength + " actual.length=" + actualsLength);
+ return expectedsLength;
+ }
+
+ protected abstract void assertElementsEqual(Object expected, Object actual);
+}
diff --git a/src/org/junit/internal/ExactComparisonCriteria.java b/src/org/junit/internal/ExactComparisonCriteria.java
new file mode 100644
index 0000000..0a632ff
--- /dev/null
+++ b/src/org/junit/internal/ExactComparisonCriteria.java
@@ -0,0 +1,10 @@
+package org.junit.internal;
+
+import org.junit.Assert;
+
+public class ExactComparisonCriteria extends ComparisonCriteria {
+ @Override
+ protected void assertElementsEqual(Object expected, Object actual) {
+ Assert.assertEquals(expected, actual);
+ }
+}
diff --git a/src/org/junit/internal/InexactComparisonCriteria.java b/src/org/junit/internal/InexactComparisonCriteria.java
new file mode 100644
index 0000000..ef3d7ff
--- /dev/null
+++ b/src/org/junit/internal/InexactComparisonCriteria.java
@@ -0,0 +1,19 @@
+package org.junit.internal;
+
+import org.junit.Assert;
+
+public class InexactComparisonCriteria extends ComparisonCriteria {
+ public double fDelta;
+
+ public InexactComparisonCriteria(double delta) {
+ fDelta= delta;
+ }
+
+ @Override
+ protected void assertElementsEqual(Object expected, Object actual) {
+ if (expected instanceof Double)
+ Assert.assertEquals((Double)expected, (Double)actual, fDelta);
+ else
+ Assert.assertEquals((Float)expected, (Float)actual, fDelta);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/JUnitSystem.java b/src/org/junit/internal/JUnitSystem.java
new file mode 100644
index 0000000..6d9c242
--- /dev/null
+++ b/src/org/junit/internal/JUnitSystem.java
@@ -0,0 +1,8 @@
+package org.junit.internal;
+
+import java.io.PrintStream;
+
+public interface JUnitSystem {
+ void exit(int i);
+ PrintStream out();
+}
diff --git a/src/org/junit/internal/RealSystem.java b/src/org/junit/internal/RealSystem.java
new file mode 100644
index 0000000..1067c6d
--- /dev/null
+++ b/src/org/junit/internal/RealSystem.java
@@ -0,0 +1,15 @@
+package org.junit.internal;
+
+import java.io.PrintStream;
+
+public class RealSystem implements JUnitSystem {
+
+ public void exit(int code) {
+ System.exit(code);
+ }
+
+ public PrintStream out() {
+ return System.out;
+ }
+
+}
diff --git a/src/org/junit/internal/TextListener.java b/src/org/junit/internal/TextListener.java
new file mode 100644
index 0000000..2b1c679
--- /dev/null
+++ b/src/org/junit/internal/TextListener.java
@@ -0,0 +1,98 @@
+package org.junit.internal;
+
+import java.io.PrintStream;
+import java.text.NumberFormat;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+public class TextListener extends RunListener {
+
+ private final PrintStream fWriter;
+
+ public TextListener(JUnitSystem system) {
+ this(system.out());
+ }
+
+ public TextListener(PrintStream writer) {
+ this.fWriter= writer;
+ }
+
+ @Override
+ public void testRunFinished(Result result) {
+ printHeader(result.getRunTime());
+ printFailures(result);
+ printFooter(result);
+ }
+
+ @Override
+ public void testStarted(Description description) {
+ fWriter.append('.');
+ }
+
+ @Override
+ public void testFailure(Failure failure) {
+ fWriter.append('E');
+ }
+
+ @Override
+ public void testIgnored(Description description) {
+ fWriter.append('I');
+ }
+
+ /*
+ * Internal methods
+ */
+
+ private PrintStream getWriter() {
+ return fWriter;
+ }
+
+ protected void printHeader(long runTime) {
+ getWriter().println();
+ getWriter().println("Time: " + elapsedTimeAsString(runTime));
+ }
+
+ protected void printFailures(Result result) {
+ List<Failure> failures= result.getFailures();
+ if (failures.size() == 0)
+ return;
+ if (failures.size() == 1)
+ getWriter().println("There was " + failures.size() + " failure:");
+ else
+ getWriter().println("There were " + failures.size() + " failures:");
+ int i= 1;
+ for (Failure each : failures)
+ printFailure(each, "" + i++);
+ }
+
+ protected void printFailure(Failure each, String prefix) {
+ getWriter().println(prefix + ") " + each.getTestHeader());
+ getWriter().print(each.getTrace());
+ }
+
+ protected void printFooter(Result result) {
+ if (result.wasSuccessful()) {
+ getWriter().println();
+ getWriter().print("OK");
+ getWriter().println(" (" + result.getRunCount() + " test" + (result.getRunCount() == 1 ? "" : "s") + ")");
+
+ } else {
+ getWriter().println();
+ getWriter().println("FAILURES!!!");
+ getWriter().println("Tests run: " + result.getRunCount() + ", Failures: " + result.getFailureCount());
+ }
+ getWriter().println();
+ }
+
+ /**
+ * Returns the formatted string of the elapsed time. Duplicated from
+ * BaseTestRunner. Fix it.
+ */
+ protected String elapsedTimeAsString(long runTime) {
+ return NumberFormat.getInstance().format((double) runTime / 1000);
+ }
+}
diff --git a/src/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java b/src/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java
new file mode 100644
index 0000000..d3bd50a
--- /dev/null
+++ b/src/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java
@@ -0,0 +1,57 @@
+/**
+ *
+ */
+package org.junit.internal.builders;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.runner.Runner;
+import org.junit.runners.model.RunnerBuilder;
+
+public class AllDefaultPossibilitiesBuilder extends RunnerBuilder {
+ private final boolean fCanUseSuiteMethod;
+
+ public AllDefaultPossibilitiesBuilder(boolean canUseSuiteMethod) {
+ fCanUseSuiteMethod= canUseSuiteMethod;
+ }
+
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Throwable {
+ List<RunnerBuilder> builders= Arrays.asList(
+ ignoredBuilder(),
+ annotatedBuilder(),
+ suiteMethodBuilder(),
+ junit3Builder(),
+ junit4Builder());
+
+ for (RunnerBuilder each : builders) {
+ Runner runner= each.safeRunnerForClass(testClass);
+ if (runner != null)
+ return runner;
+ }
+ return null;
+ }
+
+ protected JUnit4Builder junit4Builder() {
+ return new JUnit4Builder();
+ }
+
+ protected JUnit3Builder junit3Builder() {
+ return new JUnit3Builder();
+ }
+
+ protected AnnotatedBuilder annotatedBuilder() {
+ return new AnnotatedBuilder(this);
+ }
+
+ protected IgnoredBuilder ignoredBuilder() {
+ return new IgnoredBuilder();
+ }
+
+ protected RunnerBuilder suiteMethodBuilder() {
+ if (fCanUseSuiteMethod)
+ return new SuiteMethodBuilder();
+ return new NullBuilder();
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/builders/AnnotatedBuilder.java b/src/org/junit/internal/builders/AnnotatedBuilder.java
new file mode 100644
index 0000000..8ed9ca7
--- /dev/null
+++ b/src/org/junit/internal/builders/AnnotatedBuilder.java
@@ -0,0 +1,45 @@
+/**
+ *
+ */
+package org.junit.internal.builders;
+
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+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;
+
+ public AnnotatedBuilder(RunnerBuilder suiteBuilder) {
+ fSuiteBuilder= suiteBuilder;
+ }
+
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Exception {
+ RunWith annotation= testClass.getAnnotation(RunWith.class);
+ if (annotation != null)
+ return buildRunner(annotation.value(), testClass);
+ return null;
+ }
+
+ public Runner buildRunner(Class<? extends Runner> runnerClass,
+ Class<?> testClass) throws Exception {
+ try {
+ return runnerClass.getConstructor(Class.class).newInstance(
+ new Object[] { testClass });
+ } catch (NoSuchMethodException e) {
+ try {
+ return runnerClass.getConstructor(Class.class,
+ RunnerBuilder.class).newInstance(
+ new Object[] { testClass, fSuiteBuilder });
+ } catch (NoSuchMethodException e2) {
+ String simpleName= runnerClass.getSimpleName();
+ throw new InitializationError(String.format(
+ CONSTRUCTOR_ERROR_FORMAT, simpleName, simpleName));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/builders/IgnoredBuilder.java b/src/org/junit/internal/builders/IgnoredBuilder.java
new file mode 100644
index 0000000..6be342c
--- /dev/null
+++ b/src/org/junit/internal/builders/IgnoredBuilder.java
@@ -0,0 +1,17 @@
+/**
+ *
+ */
+package org.junit.internal.builders;
+
+import org.junit.Ignore;
+import org.junit.runner.Runner;
+import org.junit.runners.model.RunnerBuilder;
+
+public class IgnoredBuilder extends RunnerBuilder {
+ @Override
+ public Runner runnerForClass(Class<?> testClass) {
+ if (testClass.getAnnotation(Ignore.class) != null)
+ return new IgnoredClassRunner(testClass);
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/builders/IgnoredClassRunner.java b/src/org/junit/internal/builders/IgnoredClassRunner.java
new file mode 100644
index 0000000..b4200a8
--- /dev/null
+++ b/src/org/junit/internal/builders/IgnoredClassRunner.java
@@ -0,0 +1,26 @@
+/**
+ *
+ */
+package org.junit.internal.builders;
+
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+
+public class IgnoredClassRunner extends Runner {
+ private final Class<?> fTestClass;
+
+ public IgnoredClassRunner(Class<?> testClass) {
+ fTestClass= testClass;
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ notifier.fireTestIgnored(getDescription());
+ }
+
+ @Override
+ public Description getDescription() {
+ return Description.createSuiteDescription(fTestClass);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/builders/JUnit3Builder.java b/src/org/junit/internal/builders/JUnit3Builder.java
new file mode 100644
index 0000000..ddb070b
--- /dev/null
+++ b/src/org/junit/internal/builders/JUnit3Builder.java
@@ -0,0 +1,21 @@
+/**
+ *
+ */
+package org.junit.internal.builders;
+
+import org.junit.internal.runners.JUnit38ClassRunner;
+import org.junit.runner.Runner;
+import org.junit.runners.model.RunnerBuilder;
+
+public class JUnit3Builder extends RunnerBuilder {
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Throwable {
+ if (isPre4Test(testClass))
+ return new JUnit38ClassRunner(testClass);
+ return null;
+ }
+
+ boolean isPre4Test(Class<?> testClass) {
+ return junit.framework.TestCase.class.isAssignableFrom(testClass);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/builders/JUnit4Builder.java b/src/org/junit/internal/builders/JUnit4Builder.java
new file mode 100644
index 0000000..4380db7
--- /dev/null
+++ b/src/org/junit/internal/builders/JUnit4Builder.java
@@ -0,0 +1,15 @@
+/**
+ *
+ */
+package org.junit.internal.builders;
+
+import org.junit.runner.Runner;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.RunnerBuilder;
+
+public class JUnit4Builder extends RunnerBuilder {
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Throwable {
+ return new BlockJUnit4ClassRunner(testClass);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/builders/NullBuilder.java b/src/org/junit/internal/builders/NullBuilder.java
new file mode 100644
index 0000000..9d43d69
--- /dev/null
+++ b/src/org/junit/internal/builders/NullBuilder.java
@@ -0,0 +1,14 @@
+/**
+ *
+ */
+package org.junit.internal.builders;
+
+import org.junit.runner.Runner;
+import org.junit.runners.model.RunnerBuilder;
+
+public class NullBuilder extends RunnerBuilder {
+ @Override
+ public Runner runnerForClass(Class<?> each) throws Throwable {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/builders/SuiteMethodBuilder.java b/src/org/junit/internal/builders/SuiteMethodBuilder.java
new file mode 100644
index 0000000..659bf31
--- /dev/null
+++ b/src/org/junit/internal/builders/SuiteMethodBuilder.java
@@ -0,0 +1,26 @@
+/**
+ *
+ */
+package org.junit.internal.builders;
+
+import org.junit.internal.runners.SuiteMethod;
+import org.junit.runner.Runner;
+import org.junit.runners.model.RunnerBuilder;
+
+public class SuiteMethodBuilder extends RunnerBuilder {
+ @Override
+ public Runner runnerForClass(Class<?> each) throws Throwable {
+ if (hasSuiteMethod(each))
+ return new SuiteMethod(each);
+ return null;
+ }
+
+ public boolean hasSuiteMethod(Class<?> testClass) {
+ try {
+ testClass.getMethod("suite");
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ return true;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/matchers/CombinableMatcher.java b/src/org/junit/internal/matchers/CombinableMatcher.java
new file mode 100644
index 0000000..e9e6947
--- /dev/null
+++ b/src/org/junit/internal/matchers/CombinableMatcher.java
@@ -0,0 +1,34 @@
+package org.junit.internal.matchers;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.anyOf;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+public class CombinableMatcher<T> extends BaseMatcher<T> {
+
+ private final Matcher<? extends T> fMatcher;
+
+ public CombinableMatcher(Matcher<? extends T> matcher) {
+ fMatcher= matcher;
+ }
+
+ public boolean matches(Object item) {
+ return fMatcher.matches(item);
+ }
+
+ public void describeTo(Description description) {
+ description.appendDescriptionOf(fMatcher);
+ }
+
+ @SuppressWarnings("unchecked")
+ public CombinableMatcher<T> and(Matcher<? extends T> matcher) {
+ return new CombinableMatcher<T>(allOf(matcher, fMatcher));
+ }
+
+ @SuppressWarnings("unchecked")
+ public CombinableMatcher<T> or(Matcher<? extends T> matcher) {
+ return new CombinableMatcher<T>(anyOf(matcher, fMatcher));
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/matchers/Each.java b/src/org/junit/internal/matchers/Each.java
new file mode 100644
index 0000000..527db3b
--- /dev/null
+++ b/src/org/junit/internal/matchers/Each.java
@@ -0,0 +1,24 @@
+package org.junit.internal.matchers;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+public class Each {
+ public static <T> Matcher<Iterable<T>> each(final Matcher<T> individual) {
+ final Matcher<Iterable<T>> allItemsAre = not(hasItem(not(individual)));
+
+ return new BaseMatcher<Iterable<T>>() {
+ public boolean matches(Object item) {
+ return allItemsAre.matches(item);
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("each ");
+ individual.describeTo(description);
+ }
+ };
+ }
+}
diff --git a/src/org/junit/internal/matchers/IsCollectionContaining.java b/src/org/junit/internal/matchers/IsCollectionContaining.java
new file mode 100644
index 0000000..4436a83
--- /dev/null
+++ b/src/org/junit/internal/matchers/IsCollectionContaining.java
@@ -0,0 +1,67 @@
+package org.junit.internal.matchers;
+
+import static org.hamcrest.core.AllOf.allOf;
+import static org.hamcrest.core.IsEqual.equalTo;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+
+// Copied (hopefully temporarily) from hamcrest-library
+public class IsCollectionContaining<T> extends TypeSafeMatcher<Iterable<T>> {
+ private final Matcher<? extends T> elementMatcher;
+
+ public IsCollectionContaining(Matcher<? extends T> elementMatcher) {
+ this.elementMatcher = elementMatcher;
+ }
+
+ @Override
+ public boolean matchesSafely(Iterable<T> collection) {
+ for (T item : collection) {
+ if (elementMatcher.matches(item)){
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void describeTo(Description description) {
+ description
+ .appendText("a collection containing ")
+ .appendDescriptionOf(elementMatcher);
+ }
+
+ @Factory
+ public static <T> Matcher<Iterable<T>> hasItem(Matcher<? extends T> elementMatcher) {
+ return new IsCollectionContaining<T>(elementMatcher);
+ }
+
+ @Factory
+ public static <T> Matcher<Iterable<T>> hasItem(T element) {
+ return hasItem(equalTo(element));
+ }
+
+ @Factory
+ public static <T> Matcher<Iterable<T>> hasItems(Matcher<? extends T>... elementMatchers) {
+ Collection<Matcher<? extends Iterable<T>>> all
+ = new ArrayList<Matcher<? extends Iterable<T>>>(elementMatchers.length);
+ for (Matcher<? extends T> elementMatcher : elementMatchers) {
+ all.add(hasItem(elementMatcher));
+ }
+ return allOf(all);
+ }
+
+ @Factory
+ public static <T> Matcher<Iterable<T>> hasItems(T... elements) {
+ Collection<Matcher<? extends Iterable<T>>> all
+ = new ArrayList<Matcher<? extends Iterable<T>>>(elements.length);
+ for (T element : elements) {
+ all.add(hasItem(element));
+ }
+ return allOf(all);
+ }
+
+}
diff --git a/src/org/junit/internal/matchers/StringContains.java b/src/org/junit/internal/matchers/StringContains.java
new file mode 100644
index 0000000..e5f5334
--- /dev/null
+++ b/src/org/junit/internal/matchers/StringContains.java
@@ -0,0 +1,31 @@
+/* Copyright (c) 2000-2006 hamcrest.org
+ */
+package org.junit.internal.matchers;
+
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+
+/**
+ * Tests if the argument is a string that contains a substring.
+ */
+public class StringContains extends SubstringMatcher {
+ public StringContains(String substring) {
+ super(substring);
+ }
+
+ @Override
+ protected boolean evalSubstringOf(String s) {
+ return s.indexOf(substring) >= 0;
+ }
+
+ @Override
+ protected String relationship() {
+ return "containing";
+ }
+
+ @Factory
+ public static Matcher<String> containsString(String substring) {
+ return new StringContains(substring);
+ }
+
+} \ No newline at end of file
diff --git a/src/org/junit/internal/matchers/SubstringMatcher.java b/src/org/junit/internal/matchers/SubstringMatcher.java
new file mode 100644
index 0000000..1c65240
--- /dev/null
+++ b/src/org/junit/internal/matchers/SubstringMatcher.java
@@ -0,0 +1,28 @@
+package org.junit.internal.matchers;
+
+import org.hamcrest.Description;
+
+public abstract class SubstringMatcher extends TypeSafeMatcher<String> {
+
+ protected final String substring;
+
+ protected SubstringMatcher(final String substring) {
+ this.substring = substring;
+ }
+
+ @Override
+ public boolean matchesSafely(String item) {
+ return evalSubstringOf(item);
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("a string ")
+ .appendText(relationship())
+ .appendText(" ")
+ .appendValue(substring);
+ }
+
+ protected abstract boolean evalSubstringOf(String string);
+
+ protected abstract String relationship();
+} \ No newline at end of file
diff --git a/src/org/junit/internal/matchers/TypeSafeMatcher.java b/src/org/junit/internal/matchers/TypeSafeMatcher.java
new file mode 100644
index 0000000..794a174
--- /dev/null
+++ b/src/org/junit/internal/matchers/TypeSafeMatcher.java
@@ -0,0 +1,60 @@
+package org.junit.internal.matchers;
+
+import java.lang.reflect.Method;
+
+import org.hamcrest.BaseMatcher;
+
+/**
+ * Convenient base class for Matchers that require a non-null value of a specific type.
+ * This simply implements the null check, checks the type and then casts.
+ *
+ * @author Joe Walnes
+ */
+public abstract class TypeSafeMatcher<T> extends BaseMatcher<T> {
+
+ private Class<?> expectedType;
+
+ /**
+ * Subclasses should implement this. The item will already have been checked for
+ * the specific type and will never be null.
+ */
+ public abstract boolean matchesSafely(T item);
+
+ protected TypeSafeMatcher() {
+ expectedType = findExpectedType(getClass());
+ }
+
+ private static Class<?> findExpectedType(Class<?> fromClass) {
+ for (Class<?> c = fromClass; c != Object.class; c = c.getSuperclass()) {
+ for (Method method : c.getDeclaredMethods()) {
+ if (isMatchesSafelyMethod(method)) {
+ return method.getParameterTypes()[0];
+ }
+ }
+ }
+
+ throw new Error("Cannot determine correct type for matchesSafely() method.");
+ }
+
+ private static boolean isMatchesSafelyMethod(Method method) {
+ return method.getName().equals("matchesSafely")
+ && method.getParameterTypes().length == 1
+ && !method.isSynthetic();
+ }
+
+ protected TypeSafeMatcher(Class<T> expectedType) {
+ this.expectedType = expectedType;
+ }
+
+ /**
+ * Method made final to prevent accidental override.
+ * If you need to override this, there's no point on extending TypeSafeMatcher.
+ * Instead, extend the {@link BaseMatcher}.
+ */
+ @SuppressWarnings({"unchecked"})
+ public final boolean matches(Object item) {
+ return item != null
+ && expectedType.isInstance(item)
+ && matchesSafely((T) item);
+ }
+}
diff --git a/src/org/junit/internal/requests/ClassRequest.java b/src/org/junit/internal/requests/ClassRequest.java
new file mode 100644
index 0000000..53bf520
--- /dev/null
+++ b/src/org/junit/internal/requests/ClassRequest.java
@@ -0,0 +1,26 @@
+package org.junit.internal.requests;
+
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+
+public class ClassRequest extends Request {
+ private final Class<?> fTestClass;
+
+ private boolean fCanUseSuiteMethod;
+
+ public ClassRequest(Class<?> testClass, boolean canUseSuiteMethod) {
+ fTestClass= testClass;
+ fCanUseSuiteMethod= canUseSuiteMethod;
+ }
+
+ public ClassRequest(Class<?> testClass) {
+ this(testClass, true);
+ }
+
+ @Override
+ public Runner getRunner() {
+ return new AllDefaultPossibilitiesBuilder(fCanUseSuiteMethod).safeRunnerForClass(fTestClass);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/requests/FilterRequest.java b/src/org/junit/internal/requests/FilterRequest.java
new file mode 100644
index 0000000..e5d98d1
--- /dev/null
+++ b/src/org/junit/internal/requests/FilterRequest.java
@@ -0,0 +1,42 @@
+/**
+ *
+ */
+package org.junit.internal.requests;
+
+import org.junit.internal.runners.ErrorReportingRunner;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.NoTestsRemainException;
+
+/**
+ * A filtered {@link Request}.
+ */
+public final class FilterRequest extends Request {
+ private final Request fRequest;
+ private final Filter fFilter;
+
+ /**
+ * Creates a filtered Request
+ * @param classRequest a {@link Request} describing your Tests
+ * @param filter {@link Filter} to apply to the Tests described in
+ * <code>classRequest</code>
+ */
+ public FilterRequest(Request classRequest, Filter filter) {
+ fRequest= classRequest;
+ fFilter= filter;
+ }
+
+ @Override
+ public Runner getRunner() {
+ try {
+ Runner runner= fRequest.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())));
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/requests/SortingRequest.java b/src/org/junit/internal/requests/SortingRequest.java
new file mode 100644
index 0000000..3c6f4f5
--- /dev/null
+++ b/src/org/junit/internal/requests/SortingRequest.java
@@ -0,0 +1,25 @@
+package org.junit.internal.requests;
+
+import java.util.Comparator;
+
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Sorter;
+
+public class SortingRequest extends Request {
+ private final Request fRequest;
+ private final Comparator<Description> fComparator;
+
+ public SortingRequest(Request request, Comparator<Description> comparator) {
+ fRequest= request;
+ fComparator= comparator;
+ }
+
+ @Override
+ public Runner getRunner() {
+ Runner runner= fRequest.getRunner();
+ new Sorter(fComparator).apply(runner);
+ return runner;
+ }
+}
diff --git a/src/org/junit/internal/requests/package-info.java b/src/org/junit/internal/requests/package-info.java
new file mode 100644
index 0000000..66d2928
--- /dev/null
+++ b/src/org/junit/internal/requests/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Provides implementations of {@link org.junit.runner.Request}.
+ *
+ * @since 4.0
+ */
+package org.junit.internal.requests; \ No newline at end of file
diff --git a/src/org/junit/internal/runners/ClassRoadie.java b/src/org/junit/internal/runners/ClassRoadie.java
new file mode 100644
index 0000000..1f77d37
--- /dev/null
+++ b/src/org/junit/internal/runners/ClassRoadie.java
@@ -0,0 +1,79 @@
+package org.junit.internal.runners;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
+ * removed in the next 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;
+
+ public ClassRoadie(RunNotifier notifier, TestClass testClass,
+ Description description, Runnable runnable) {
+ fNotifier= notifier;
+ fTestClass= testClass;
+ fDescription= description;
+ fRunnable= runnable;
+ }
+
+ protected void runUnprotected() {
+ fRunnable.run();
+ };
+
+ protected void addFailure(Throwable targetException) {
+ fNotifier.fireTestFailure(new Failure(fDescription, targetException));
+ }
+
+ public void runProtected() {
+ try {
+ runBefores();
+ runUnprotected();
+ } catch (FailedBefore e) {
+ } finally {
+ runAfters();
+ }
+ }
+
+ private void runBefores() throws FailedBefore {
+ try {
+ try {
+ List<Method> befores= fTestClass.getBefores();
+ for (Method before : befores)
+ before.invoke(null);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ } catch (org.junit.internal.AssumptionViolatedException e) {
+ throw new FailedBefore();
+ } catch (Throwable e) {
+ addFailure(e);
+ throw new FailedBefore();
+ }
+ }
+
+ private void runAfters() {
+ List<Method> afters= fTestClass.getAfters();
+ for (Method after : afters)
+ try {
+ after.invoke(null);
+ } catch (InvocationTargetException e) {
+ addFailure(e.getTargetException());
+ } catch (Throwable e) {
+ addFailure(e); // Untested, but seems impossible
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/ErrorReportingRunner.java b/src/org/junit/internal/runners/ErrorReportingRunner.java
new file mode 100644
index 0000000..200b6f0
--- /dev/null
+++ b/src/org/junit/internal/runners/ErrorReportingRunner.java
@@ -0,0 +1,60 @@
+package org.junit.internal.runners;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.InitializationError;
+
+public class ErrorReportingRunner extends Runner {
+ private final List<Throwable> fCauses;
+
+ private final Class<?> fTestClass;
+
+ public ErrorReportingRunner(Class<?> testClass, Throwable cause) {
+ fTestClass= testClass;
+ fCauses= getCauses(cause);
+ }
+
+ @Override
+ public Description getDescription() {
+ Description description= Description.createSuiteDescription(fTestClass);
+ for (Throwable each : fCauses)
+ description.addChild(describeCause(each));
+ return description;
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ for (Throwable each : fCauses)
+ runCause(each, notifier);
+ }
+
+ @SuppressWarnings("deprecation")
+ private List<Throwable> getCauses(Throwable cause) {
+ if (cause instanceof InvocationTargetException)
+ return getCauses(cause.getCause());
+ if (cause instanceof InitializationError)
+ return ((InitializationError) cause).getCauses();
+ if (cause instanceof org.junit.internal.runners.InitializationError)
+ return ((org.junit.internal.runners.InitializationError) cause)
+ .getCauses();
+ return Arrays.asList(cause);
+ }
+
+ private Description describeCause(Throwable child) {
+ return Description.createTestDescription(fTestClass,
+ "initializationError");
+ }
+
+ private void runCause(Throwable child, RunNotifier notifier) {
+ Description description= describeCause(child);
+ notifier.fireTestStarted(description);
+ notifier.fireTestFailure(new Failure(description, child));
+ notifier.fireTestFinished(description);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/FailedBefore.java b/src/org/junit/internal/runners/FailedBefore.java
new file mode 100644
index 0000000..29dcba4
--- /dev/null
+++ b/src/org/junit/internal/runners/FailedBefore.java
@@ -0,0 +1,14 @@
+package org.junit.internal.runners;
+
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+
+/**
+ * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
+ * removed in the next release. Please use
+ * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
+ */
+@Deprecated
+class FailedBefore extends Exception {
+ private static final long serialVersionUID= 1L;
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/InitializationError.java b/src/org/junit/internal/runners/InitializationError.java
new file mode 100644
index 0000000..5715ec5
--- /dev/null
+++ b/src/org/junit/internal/runners/InitializationError.java
@@ -0,0 +1,30 @@
+package org.junit.internal.runners;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Deprecated
+/**
+ * Use the published version: {@link org.junit.runners.InitializationError}
+ * This may disappear as soon as 1 April 2009
+ */
+public class InitializationError extends Exception {
+ private static final long serialVersionUID= 1L;
+ private final List<Throwable> fErrors;
+
+ public InitializationError(List<Throwable> errors) {
+ fErrors= errors;
+ }
+
+ public InitializationError(Throwable... errors) {
+ this(Arrays.asList(errors));
+ }
+
+ public InitializationError(String string) {
+ this(new Exception(string));
+ }
+
+ public List<Throwable> getCauses() {
+ return fErrors;
+ }
+}
diff --git a/src/org/junit/internal/runners/JUnit38ClassRunner.java b/src/org/junit/internal/runners/JUnit38ClassRunner.java
new file mode 100644
index 0000000..0028d0c
--- /dev/null
+++ b/src/org/junit/internal/runners/JUnit38ClassRunner.java
@@ -0,0 +1,158 @@
+package org.junit.internal.runners;
+
+import junit.extensions.TestDecorator;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import org.junit.runner.Describable;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.Filterable;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runner.manipulation.Sortable;
+import org.junit.runner.manipulation.Sorter;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
+
+public class JUnit38ClassRunner extends Runner implements Filterable, Sortable {
+ private final class OldTestClassAdaptingListener implements
+ TestListener {
+ private final RunNotifier fNotifier;
+
+ private OldTestClassAdaptingListener(RunNotifier notifier) {
+ fNotifier= notifier;
+ }
+
+ public void endTest(Test test) {
+ fNotifier.fireTestFinished(asDescription(test));
+ }
+
+ public void startTest(Test test) {
+ fNotifier.fireTestStarted(asDescription(test));
+ }
+
+ // Implement junit.framework.TestListener
+ public void addError(Test test, Throwable t) {
+ Failure failure= new Failure(asDescription(test), t);
+ fNotifier.fireTestFailure(failure);
+ }
+
+ private Description asDescription(Test test) {
+ if (test instanceof Describable) {
+ Describable facade= (Describable) test;
+ return facade.getDescription();
+ }
+ return Description.createTestDescription(getEffectiveClass(test), getName(test));
+ }
+
+ private Class<? extends Test> getEffectiveClass(Test test) {
+ return test.getClass();
+ }
+
+ private String getName(Test test) {
+ if (test instanceof TestCase)
+ return ((TestCase) test).getName();
+ else
+ return test.toString();
+ }
+
+ public void addFailure(Test test, AssertionFailedError t) {
+ addError(test, t);
+ }
+ }
+
+ private Test fTest;
+
+ public JUnit38ClassRunner(Class<?> klass) {
+ this(new TestSuite(klass.asSubclass(TestCase.class)));
+ }
+
+ public JUnit38ClassRunner(Test test) {
+ super();
+ setTest(test);
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ TestResult result= new TestResult();
+ result.addListener(createAdaptingListener(notifier));
+ getTest().run(result);
+ }
+
+ public TestListener createAdaptingListener(final RunNotifier notifier) {
+ return new OldTestClassAdaptingListener(notifier);
+ }
+
+ @Override
+ public Description getDescription() {
+ return makeDescription(getTest());
+ }
+
+ private static Description makeDescription(Test test) {
+ if (test instanceof TestCase) {
+ TestCase tc= (TestCase) test;
+ return Description.createTestDescription(tc.getClass(), tc.getName());
+ } else if (test instanceof TestSuite) {
+ TestSuite ts= (TestSuite) test;
+ String name= ts.getName() == null ? createSuiteDescription(ts) : ts.getName();
+ Description description= Description.createSuiteDescription(name);
+ int n= ts.testCount();
+ for (int i= 0; i < n; i++) {
+ Description made= makeDescription(ts.testAt(i));
+ description.addChild(made);
+ }
+ return description;
+ } else if (test instanceof Describable) {
+ Describable adapter= (Describable) test;
+ return adapter.getDescription();
+ } else if (test instanceof TestDecorator) {
+ TestDecorator decorator= (TestDecorator) test;
+ return makeDescription(decorator.getTest());
+ } else {
+ // This is the best we can do in this case
+ return Description.createSuiteDescription(test.getClass());
+ }
+ }
+
+ private static String createSuiteDescription(TestSuite ts) {
+ int count= ts.countTestCases();
+ String example = count == 0 ? "" : String.format(" [example: %s]", ts.testAt(0));
+ return String.format("TestSuite with %s tests%s", count, example);
+ }
+
+ public void filter(Filter filter) throws NoTestsRemainException {
+ if (getTest() instanceof Filterable) {
+ Filterable adapter= (Filterable) getTest();
+ adapter.filter(filter);
+ } else if (getTest() instanceof TestSuite) {
+ TestSuite suite= (TestSuite) getTest();
+ TestSuite filtered= new TestSuite(suite.getName());
+ int n= suite.testCount();
+ for (int i= 0; i < n; i++) {
+ Test test= suite.testAt(i);
+ if (filter.shouldRun(makeDescription(test)))
+ filtered.addTest(test);
+ }
+ setTest(filtered);
+ }
+ }
+
+ public void sort(Sorter sorter) {
+ if (getTest() instanceof Sortable) {
+ Sortable adapter= (Sortable) getTest();
+ adapter.sort(sorter);
+ }
+ }
+
+ private void setTest(Test test) {
+ fTest = test;
+ }
+
+ private Test getTest() {
+ return fTest;
+ }
+}
diff --git a/src/org/junit/internal/runners/JUnit4ClassRunner.java b/src/org/junit/internal/runners/JUnit4ClassRunner.java
new file mode 100644
index 0000000..d732880
--- /dev/null
+++ b/src/org/junit/internal/runners/JUnit4ClassRunner.java
@@ -0,0 +1,145 @@
+package org.junit.internal.runners;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.Filterable;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runner.manipulation.Sortable;
+import org.junit.runner.manipulation.Sorter;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
+ * removed in the next 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;
+
+ public JUnit4ClassRunner(Class<?> klass) throws InitializationError {
+ fTestClass= new TestClass(klass);
+ fTestMethods= getTestMethods();
+ validate();
+ }
+
+ protected List<Method> getTestMethods() {
+ return fTestClass.getTestMethods();
+ }
+
+ protected void validate() throws InitializationError {
+ MethodValidator methodValidator= new MethodValidator(fTestClass);
+ methodValidator.validateMethodsForDefaultRunner();
+ methodValidator.assertValid();
+ }
+
+ @Override
+ public void run(final RunNotifier notifier) {
+ new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable() {
+ public void run() {
+ runMethods(notifier);
+ }
+ }).runProtected();
+ }
+
+ protected void runMethods(final RunNotifier notifier) {
+ for (Method method : fTestMethods)
+ invokeTestMethod(method, notifier);
+ }
+
+ @Override
+ public Description getDescription() {
+ Description spec= Description.createSuiteDescription(getName(), classAnnotations());
+ List<Method> testMethods= fTestMethods;
+ for (Method method : testMethods)
+ spec.addChild(methodDescription(method));
+ return spec;
+ }
+
+ protected Annotation[] classAnnotations() {
+ return fTestClass.getJavaClass().getAnnotations();
+ }
+
+ protected String getName() {
+ return getTestClass().getName();
+ }
+
+ protected Object createTest() throws Exception {
+ return getTestClass().getConstructor().newInstance();
+ }
+
+ protected void invokeTestMethod(Method method, RunNotifier notifier) {
+ Description description= methodDescription(method);
+ Object test;
+ try {
+ test= createTest();
+ } catch (InvocationTargetException e) {
+ testAborted(notifier, description, e.getCause());
+ return;
+ } catch (Exception e) {
+ testAborted(notifier, description, e);
+ return;
+ }
+ TestMethod testMethod= wrapMethod(method);
+ new MethodRoadie(test, testMethod, notifier, description).run();
+ }
+
+ private void testAborted(RunNotifier notifier, Description description,
+ Throwable e) {
+ notifier.fireTestStarted(description);
+ notifier.fireTestFailure(new Failure(description, e));
+ notifier.fireTestFinished(description);
+ }
+
+ protected TestMethod wrapMethod(Method method) {
+ return new TestMethod(method, fTestClass);
+ }
+
+ protected String testName(Method method) {
+ return method.getName();
+ }
+
+ protected Description methodDescription(Method method) {
+ return Description.createTestDescription(getTestClass().getJavaClass(), testName(method), testAnnotations(method));
+ }
+
+ protected Annotation[] testAnnotations(Method method) {
+ return method.getAnnotations();
+ }
+
+ public void filter(Filter filter) throws NoTestsRemainException {
+ for (Iterator<Method> iter= fTestMethods.iterator(); iter.hasNext();) {
+ Method method= iter.next();
+ if (!filter.shouldRun(methodDescription(method)))
+ iter.remove();
+ }
+ if (fTestMethods.isEmpty())
+ throw new NoTestsRemainException();
+ }
+
+ public void sort(final Sorter sorter) {
+ Collections.sort(fTestMethods, new Comparator<Method>() {
+ public int compare(Method o1, Method o2) {
+ return sorter.compare(methodDescription(o1), methodDescription(o2));
+ }
+ });
+ }
+
+ protected TestClass getTestClass() {
+ return fTestClass;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/MethodRoadie.java b/src/org/junit/internal/runners/MethodRoadie.java
new file mode 100644
index 0000000..4407821
--- /dev/null
+++ b/src/org/junit/internal/runners/MethodRoadie.java
@@ -0,0 +1,157 @@
+package org.junit.internal.runners;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
+ * removed in the next 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;
+
+ public MethodRoadie(Object test, TestMethod method, RunNotifier notifier, Description description) {
+ fTest= test;
+ fNotifier= notifier;
+ fDescription= description;
+ fTestMethod= method;
+ }
+
+ public void run() {
+ if (fTestMethod.isIgnored()) {
+ fNotifier.fireTestIgnored(fDescription);
+ return;
+ }
+ fNotifier.fireTestStarted(fDescription);
+ try {
+ long timeout= fTestMethod.getTimeout();
+ if (timeout > 0)
+ runWithTimeout(timeout);
+ else
+ runTest();
+ } finally {
+ fNotifier.fireTestFinished(fDescription);
+ }
+ }
+
+ private void runWithTimeout(final long timeout) {
+ runBeforesThenTestThenAfters(new Runnable() {
+
+ public void run() {
+ ExecutorService service= Executors.newSingleThreadExecutor();
+ Callable<Object> callable= new Callable<Object>() {
+ public Object call() throws Exception {
+ runTestMethod();
+ return null;
+ }
+ };
+ Future<Object> result= service.submit(callable);
+ service.shutdown();
+ try {
+ boolean terminated= service.awaitTermination(timeout,
+ TimeUnit.MILLISECONDS);
+ if (!terminated)
+ service.shutdownNow();
+ 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)));
+ } catch (Exception e) {
+ addFailure(e);
+ }
+ }
+ });
+ }
+
+ public void runTest() {
+ runBeforesThenTestThenAfters(new Runnable() {
+ public void run() {
+ runTestMethod();
+ }
+ });
+ }
+
+ public void runBeforesThenTestThenAfters(Runnable test) {
+ try {
+ runBefores();
+ test.run();
+ } catch (FailedBefore e) {
+ } catch (Exception e) {
+ throw new RuntimeException("test should never throw an exception to this level");
+ } finally {
+ runAfters();
+ }
+ }
+
+ protected void runTestMethod() {
+ try {
+ fTestMethod.invoke(fTest);
+ if (fTestMethod.expectsException())
+ addFailure(new AssertionError("Expected exception: " + fTestMethod.getExpectedException().getName()));
+ } catch (InvocationTargetException e) {
+ Throwable actual= e.getTargetException();
+ if (actual instanceof AssumptionViolatedException)
+ return;
+ else if (!fTestMethod.expectsException())
+ addFailure(actual);
+ else if (fTestMethod.isUnexpected(actual)) {
+ String message= "Unexpected exception, expected<" + fTestMethod.getExpectedException().getName() + "> but was<"
+ + actual.getClass().getName() + ">";
+ addFailure(new Exception(message, actual));
+ }
+ } catch (Throwable e) {
+ addFailure(e);
+ }
+ }
+
+ private void runBefores() throws FailedBefore {
+ try {
+ try {
+ List<Method> befores= fTestMethod.getBefores();
+ for (Method before : befores)
+ before.invoke(fTest);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ } catch (AssumptionViolatedException e) {
+ throw new FailedBefore();
+ } catch (Throwable e) {
+ addFailure(e);
+ throw new FailedBefore();
+ }
+ }
+
+ private void runAfters() {
+ List<Method> afters= fTestMethod.getAfters();
+ for (Method after : afters)
+ try {
+ after.invoke(fTest);
+ } catch (InvocationTargetException e) {
+ addFailure(e.getTargetException());
+ } catch (Throwable e) {
+ addFailure(e); // Untested, but seems impossible
+ }
+ }
+
+ protected void addFailure(Throwable e) {
+ fNotifier.fireTestFailure(new Failure(fDescription, e));
+ }
+}
+
diff --git a/src/org/junit/internal/runners/MethodValidator.java b/src/org/junit/internal/runners/MethodValidator.java
new file mode 100644
index 0000000..cadc93f
--- /dev/null
+++ b/src/org/junit/internal/runners/MethodValidator.java
@@ -0,0 +1,91 @@
+package org.junit.internal.runners;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+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.runners.BlockJUnit4ClassRunner;
+
+/**
+ * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
+ * removed in the next release. Please use
+ * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
+ */
+@Deprecated
+public class MethodValidator {
+
+ private final List<Throwable> fErrors= new ArrayList<Throwable>();
+
+ private TestClass fTestClass;
+
+ public MethodValidator(TestClass testClass) {
+ fTestClass = testClass;
+ }
+
+ public void validateInstanceMethods() {
+ validateTestMethods(After.class, false);
+ validateTestMethods(Before.class, false);
+ validateTestMethods(Test.class, false);
+
+ List<Method> methods= fTestClass.getAnnotatedMethods(Test.class);
+ if (methods.size() == 0)
+ fErrors.add(new Exception("No runnable methods"));
+ }
+
+ public void validateStaticMethods() {
+ validateTestMethods(BeforeClass.class, true);
+ validateTestMethods(AfterClass.class, true);
+ }
+
+ public List<Throwable> validateMethodsForDefaultRunner() {
+ validateNoArgConstructor();
+ validateStaticMethods();
+ validateInstanceMethods();
+ return fErrors;
+ }
+
+ public void assertValid() throws InitializationError {
+ if (!fErrors.isEmpty())
+ throw new InitializationError(fErrors);
+ }
+
+ public void validateNoArgConstructor() {
+ try {
+ fTestClass.getConstructor();
+ } catch (Exception e) {
+ fErrors.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);
+
+ 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"));
+ }
+ if (!Modifier.isPublic(each.getDeclaringClass().getModifiers()))
+ fErrors.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"));
+ if (each.getReturnType() != Void.TYPE)
+ fErrors.add(new Exception("Method " + each.getName()
+ + " should be void"));
+ if (each.getParameterTypes().length != 0)
+ fErrors.add(new Exception("Method " + each.getName()
+ + " should have no parameters"));
+ }
+ }
+}
diff --git a/src/org/junit/internal/runners/SuiteMethod.java b/src/org/junit/internal/runners/SuiteMethod.java
new file mode 100644
index 0000000..4e8bebc
--- /dev/null
+++ b/src/org/junit/internal/runners/SuiteMethod.java
@@ -0,0 +1,40 @@
+package org.junit.internal.runners;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import junit.framework.Test;
+
+/** Runner for use with JUnit 3.8.x-style AllTests classes
+ * (those that only implement a static <code>suite()</code>
+ * method). For example:
+ * <pre>
+ * &#064;RunWith(AllTests.class)
+ * public class ProductTests {
+ * public static junit.framework.Test suite() {
+ * ...
+ * }
+ * }
+ * </pre>
+ */
+public class SuiteMethod extends JUnit38ClassRunner {
+ public SuiteMethod(Class<?> klass) throws Throwable {
+ super(testFromSuiteMethod(klass));
+ }
+
+ public static Test testFromSuiteMethod(Class<?> klass) throws Throwable {
+ Method suiteMethod= null;
+ Test suite= null;
+ try {
+ suiteMethod= klass.getMethod("suite");
+ if (! Modifier.isStatic(suiteMethod.getModifiers())) {
+ throw new Exception(klass.getName() + ".suite() must be static");
+ }
+ suite= (Test) suiteMethod.invoke(null); // static method
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ return suite;
+ }
+}
diff --git a/src/org/junit/internal/runners/TestClass.java b/src/org/junit/internal/runners/TestClass.java
new file mode 100644
index 0000000..1ca2b9d
--- /dev/null
+++ b/src/org/junit/internal/runners/TestClass.java
@@ -0,0 +1,102 @@
+package org.junit.internal.runners;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
+ * removed in the next release. Please use
+ * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
+ */
+@Deprecated
+public class TestClass {
+ private final Class<?> fClass;
+
+ public TestClass(Class<?> klass) {
+ fClass= klass;
+ }
+
+ public List<Method> getTestMethods() {
+ return getAnnotatedMethods(Test.class);
+ }
+
+ List<Method> getBefores() {
+ return getAnnotatedMethods(BeforeClass.class);
+ }
+
+ List<Method> getAfters() {
+ return getAnnotatedMethods(AfterClass.class);
+ }
+
+ public List<Method> getAnnotatedMethods(Class<? extends Annotation> annotationClass) {
+ List<Method> results= new ArrayList<Method>();
+ for (Class<?> eachClass : getSuperClasses(fClass)) {
+ Method[] methods= eachClass.getDeclaredMethods();
+ for (Method eachMethod : methods) {
+ Annotation annotation= eachMethod.getAnnotation(annotationClass);
+ if (annotation != null && ! isShadowed(eachMethod, results))
+ results.add(eachMethod);
+ }
+ }
+ if (runsTopToBottom(annotationClass))
+ Collections.reverse(results);
+ return results;
+ }
+
+ private boolean runsTopToBottom(Class< ? extends Annotation> annotation) {
+ return annotation.equals(Before.class) || annotation.equals(BeforeClass.class);
+ }
+
+ private boolean isShadowed(Method method, List<Method> results) {
+ for (Method each : results) {
+ if (isShadowed(method, each))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isShadowed(Method current, Method previous) {
+ if (! previous.getName().equals(current.getName()))
+ return false;
+ if (previous.getParameterTypes().length != current.getParameterTypes().length)
+ return false;
+ for (int i= 0; i < previous.getParameterTypes().length; i++) {
+ if (! previous.getParameterTypes()[i].equals(current.getParameterTypes()[i]))
+ return false;
+ }
+ return true;
+ }
+
+ private List<Class<?>> getSuperClasses(Class< ?> testClass) {
+ ArrayList<Class<?>> results= new ArrayList<Class<?>>();
+ Class<?> current= testClass;
+ while (current != null) {
+ results.add(current);
+ current= current.getSuperclass();
+ }
+ return results;
+ }
+
+ public Constructor<?> getConstructor() throws SecurityException, NoSuchMethodException {
+ return fClass.getConstructor();
+ }
+
+ public Class<?> getJavaClass() {
+ return fClass;
+ }
+
+ public String getName() {
+ return fClass.getName();
+ }
+
+}
diff --git a/src/org/junit/internal/runners/TestMethod.java b/src/org/junit/internal/runners/TestMethod.java
new file mode 100644
index 0000000..a06213c
--- /dev/null
+++ b/src/org/junit/internal/runners/TestMethod.java
@@ -0,0 +1,69 @@
+package org.junit.internal.runners;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.Test.None;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
+ * removed in the next release. Please use
+ * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
+ */
+@Deprecated
+public class TestMethod {
+ private final Method fMethod;
+ private TestClass fTestClass;
+
+ public TestMethod(Method method, TestClass testClass) {
+ fMethod= method;
+ fTestClass= testClass;
+ }
+
+ public boolean isIgnored() {
+ return fMethod.getAnnotation(Ignore.class) != null;
+ }
+
+ public long getTimeout() {
+ Test annotation= fMethod.getAnnotation(Test.class);
+ if (annotation == null)
+ return 0;
+ long timeout= annotation.timeout();
+ return timeout;
+ }
+
+ protected Class<? extends Throwable> getExpectedException() {
+ Test annotation= fMethod.getAnnotation(Test.class);
+ if (annotation == null || annotation.expected() == None.class)
+ return null;
+ else
+ return annotation.expected();
+ }
+
+ boolean isUnexpected(Throwable exception) {
+ return ! getExpectedException().isAssignableFrom(exception.getClass());
+ }
+
+ boolean expectsException() {
+ return getExpectedException() != null;
+ }
+
+ List<Method> getBefores() {
+ return fTestClass.getAnnotatedMethods(Before.class);
+ }
+
+ List<Method> getAfters() {
+ return fTestClass.getAnnotatedMethods(After.class);
+ }
+
+ public void invoke(Object test) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+ fMethod.invoke(test);
+ }
+
+}
diff --git a/src/org/junit/internal/runners/model/EachTestNotifier.java b/src/org/junit/internal/runners/model/EachTestNotifier.java
new file mode 100644
index 0000000..a7d534c
--- /dev/null
+++ b/src/org/junit/internal/runners/model/EachTestNotifier.java
@@ -0,0 +1,51 @@
+/**
+ *
+ */
+package org.junit.internal.runners.model;
+
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.MultipleFailureException;
+
+public class EachTestNotifier {
+ private final RunNotifier fNotifier;
+
+ private final Description fDescription;
+
+ public EachTestNotifier(RunNotifier notifier, Description description) {
+ fNotifier= notifier;
+ fDescription= description;
+ }
+
+ public void addFailure(Throwable targetException) {
+ if (targetException instanceof MultipleFailureException) {
+ addMultipleFailureException((MultipleFailureException) targetException);
+ } else {
+ fNotifier
+ .fireTestFailure(new Failure(fDescription, targetException));
+ }
+ }
+
+ private void addMultipleFailureException(MultipleFailureException mfe) {
+ for (Throwable each : mfe.getFailures())
+ addFailure(each);
+ }
+
+ public void addFailedAssumption(AssumptionViolatedException e) {
+ fNotifier.fireTestAssumptionFailed(new Failure(fDescription, e));
+ }
+
+ public void fireTestFinished() {
+ fNotifier.fireTestFinished(fDescription);
+ }
+
+ public void fireTestStarted() {
+ fNotifier.fireTestStarted(fDescription);
+ }
+
+ public void fireTestIgnored() {
+ fNotifier.fireTestIgnored(fDescription);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/model/MultipleFailureException.java b/src/org/junit/internal/runners/model/MultipleFailureException.java
new file mode 100644
index 0000000..3316806
--- /dev/null
+++ b/src/org/junit/internal/runners/model/MultipleFailureException.java
@@ -0,0 +1,12 @@
+package org.junit.internal.runners.model;
+
+import java.util.List;
+
+@Deprecated
+public class MultipleFailureException extends org.junit.runners.model.MultipleFailureException {
+ private static final long serialVersionUID= 1L;
+
+ public MultipleFailureException(List<Throwable> errors) {
+ super(errors);
+ }
+}
diff --git a/src/org/junit/internal/runners/model/ReflectiveCallable.java b/src/org/junit/internal/runners/model/ReflectiveCallable.java
new file mode 100644
index 0000000..9150d90
--- /dev/null
+++ b/src/org/junit/internal/runners/model/ReflectiveCallable.java
@@ -0,0 +1,22 @@
+/**
+ *
+ */
+package org.junit.internal.runners.model;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * When invoked, throws the exception from the reflected method, rather than
+ * wrapping it in an InvocationTargetException.
+ */
+public abstract class ReflectiveCallable {
+ public Object run() throws Throwable {
+ try {
+ return runReflectiveCall();
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ }
+
+ protected abstract Object runReflectiveCall() throws Throwable;
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/package-info.java b/src/org/junit/internal/runners/package-info.java
new file mode 100644
index 0000000..5ab7e7b
--- /dev/null
+++ b/src/org/junit/internal/runners/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Provides implementations of {@link org.junit.runner.Runner}
+ *
+ * @since 4.0
+ */
+package org.junit.internal.runners; \ No newline at end of file
diff --git a/src/org/junit/internal/runners/rules/RuleFieldValidator.java b/src/org/junit/internal/runners/rules/RuleFieldValidator.java
new file mode 100644
index 0000000..e7df8bf
--- /dev/null
+++ b/src/org/junit/internal/runners/rules/RuleFieldValidator.java
@@ -0,0 +1,92 @@
+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.TestRule;
+import org.junit.runners.model.FrameworkField;
+import org.junit.runners.model.TestClass;
+
+/**
+ * A RuleFieldValidator validates the rule fields of a
+ * {@link org.junit.runners.model.TestClass}. All reasons for rejecting the
+ * {@code TestClass} are written to a list of errors.
+ *
+ * There are two slightly different validators. The {@link #CLASS_RULE_VALIDATOR}
+ * validates fields with a {@link ClassRule} annotation and the
+ * {@link #RULE_VALIDATOR} validates fields with a {@link Rule} annotation.
+ */
+public enum RuleFieldValidator {
+ /**
+ * Validates fields with a {@link ClassRule} annotation.
+ */
+ CLASS_RULE_VALIDATOR(ClassRule.class, true),
+ /**
+ * Validates fields with a {@link Rule} annotation.
+ */
+ RULE_VALIDATOR(Rule.class, false);
+
+ private final Class<? extends Annotation> fAnnotation;
+
+ private final boolean fOnlyStaticFields;
+
+ private RuleFieldValidator(Class<? extends Annotation> annotation,
+ boolean onlyStaticFields) {
+ this.fAnnotation= annotation;
+ this.fOnlyStaticFields= onlyStaticFields;
+ }
+
+ /**
+ * 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<FrameworkField> fields= target.getAnnotatedFields(fAnnotation);
+ for (FrameworkField each : fields)
+ validateField(each, errors);
+ }
+
+ private void validateField(FrameworkField field, List<Throwable> errors) {
+ optionallyValidateStatic(field, errors);
+ validatePublic(field, errors);
+ validateTestRuleOrMethodRule(field, errors);
+ }
+
+ private void optionallyValidateStatic(FrameworkField field,
+ List<Throwable> errors) {
+ if (fOnlyStaticFields && !field.isStatic())
+ addError(errors, field, "must be static.");
+ }
+
+ private void validatePublic(FrameworkField field, List<Throwable> errors) {
+ if (!field.isPublic())
+ addError(errors, field, "must be public.");
+ }
+
+ private void validateTestRuleOrMethodRule(FrameworkField field,
+ List<Throwable> errors) {
+ if (!isMethodRule(field) && !isTestRule(field))
+ addError(errors, field, "must implement MethodRule or TestRule.");
+ }
+
+ private boolean isTestRule(FrameworkField target) {
+ return TestRule.class.isAssignableFrom(target.getType());
+ }
+
+ @SuppressWarnings("deprecation")
+ private boolean isMethodRule(FrameworkField target) {
+ return org.junit.rules.MethodRule.class.isAssignableFrom(target
+ .getType());
+ }
+
+ private void addError(List<Throwable> errors, FrameworkField field,
+ String suffix) {
+ String message= "The @" + fAnnotation.getSimpleName() + " '"
+ + field.getName() + "' " + suffix;
+ errors.add(new Exception(message));
+ }
+}
diff --git a/src/org/junit/internal/runners/statements/ExpectException.java b/src/org/junit/internal/runners/statements/ExpectException.java
new file mode 100644
index 0000000..ddfef07
--- /dev/null
+++ b/src/org/junit/internal/runners/statements/ExpectException.java
@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package org.junit.internal.runners.statements;
+
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runners.model.Statement;
+
+public class ExpectException extends Statement {
+ private Statement fNext;
+ private final Class<? extends Throwable> fExpected;
+
+ public ExpectException(Statement next, Class<? extends Throwable> expected) {
+ fNext= next;
+ fExpected= expected;
+ }
+
+ @Override
+ public void evaluate() throws Exception {
+ boolean complete = false;
+ try {
+ fNext.evaluate();
+ complete = true;
+ } catch (AssumptionViolatedException e) {
+ throw e;
+ } catch (Throwable e) {
+ if (!fExpected.isAssignableFrom(e.getClass())) {
+ String message= "Unexpected exception, expected<"
+ + fExpected.getName() + "> but was<"
+ + e.getClass().getName() + ">";
+ throw new Exception(message, e);
+ }
+ }
+ if (complete)
+ throw new AssertionError("Expected exception: "
+ + fExpected.getName());
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/statements/Fail.java b/src/org/junit/internal/runners/statements/Fail.java
new file mode 100644
index 0000000..e7d0d5c
--- /dev/null
+++ b/src/org/junit/internal/runners/statements/Fail.java
@@ -0,0 +1,17 @@
+package org.junit.internal.runners.statements;
+
+import org.junit.runners.model.Statement;
+
+
+public class Fail extends Statement {
+ private final Throwable fError;
+
+ public Fail(Throwable e) {
+ fError= e;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ throw fError;
+ }
+}
diff --git a/src/org/junit/internal/runners/statements/FailOnTimeout.java b/src/org/junit/internal/runners/statements/FailOnTimeout.java
new file mode 100644
index 0000000..bff7c72
--- /dev/null
+++ b/src/org/junit/internal/runners/statements/FailOnTimeout.java
@@ -0,0 +1,71 @@
+/**
+ *
+ */
+package org.junit.internal.runners.statements;
+
+import org.junit.runners.model.Statement;
+
+public class FailOnTimeout extends Statement {
+ private final Statement fOriginalStatement;
+
+ private final long fTimeout;
+
+ public FailOnTimeout(Statement originalStatement, long timeout) {
+ fOriginalStatement= originalStatement;
+ fTimeout= timeout;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ StatementThread thread= evaluateStatement();
+ if (!thread.fFinished)
+ throwExceptionForUnfinishedThread(thread);
+ }
+
+ private StatementThread evaluateStatement() throws InterruptedException {
+ StatementThread thread= new StatementThread(fOriginalStatement);
+ thread.start();
+ thread.join(fTimeout);
+ thread.interrupt();
+ return thread;
+ }
+
+ private void throwExceptionForUnfinishedThread(StatementThread thread)
+ throws Throwable {
+ if (thread.fExceptionThrownByOriginalStatement != null)
+ throw thread.fExceptionThrownByOriginalStatement;
+ else
+ throwTimeoutException(thread);
+ }
+
+ private void throwTimeoutException(StatementThread thread) throws Exception {
+ Exception exception= new Exception(String.format(
+ "test timed out after %d milliseconds", fTimeout));
+ exception.setStackTrace(thread.getStackTrace());
+ throw exception;
+ }
+
+ private static class StatementThread extends Thread {
+ private final Statement fStatement;
+
+ private boolean fFinished= false;
+
+ private Throwable fExceptionThrownByOriginalStatement= null;
+
+ public StatementThread(Statement statement) {
+ fStatement= statement;
+ }
+
+ @Override
+ public void run() {
+ try {
+ fStatement.evaluate();
+ fFinished= true;
+ } catch (InterruptedException e) {
+ //don't log the InterruptedException
+ } catch (Throwable e) {
+ fExceptionThrownByOriginalStatement= e;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/statements/InvokeMethod.java b/src/org/junit/internal/runners/statements/InvokeMethod.java
new file mode 100644
index 0000000..e2e81e1
--- /dev/null
+++ b/src/org/junit/internal/runners/statements/InvokeMethod.java
@@ -0,0 +1,22 @@
+/**
+ *
+ */
+package org.junit.internal.runners.statements;
+
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+public class InvokeMethod extends Statement {
+ private final FrameworkMethod fTestMethod;
+ private Object fTarget;
+
+ public InvokeMethod(FrameworkMethod testMethod, Object target) {
+ fTestMethod= testMethod;
+ fTarget= target;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ fTestMethod.invokeExplosively(fTarget);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/statements/RunAfters.java b/src/org/junit/internal/runners/statements/RunAfters.java
new file mode 100644
index 0000000..475ec72
--- /dev/null
+++ b/src/org/junit/internal/runners/statements/RunAfters.java
@@ -0,0 +1,43 @@
+/**
+ *
+ */
+package org.junit.internal.runners.statements;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.MultipleFailureException;
+import org.junit.runners.model.Statement;
+
+public class RunAfters extends Statement {
+ private final Statement fNext;
+
+ private final Object fTarget;
+
+ private final List<FrameworkMethod> fAfters;
+
+ public RunAfters(Statement next, List<FrameworkMethod> afters, Object target) {
+ fNext= next;
+ fAfters= afters;
+ fTarget= target;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ List<Throwable> errors = new ArrayList<Throwable>();
+ try {
+ fNext.evaluate();
+ } catch (Throwable e) {
+ errors.add(e);
+ } finally {
+ for (FrameworkMethod each : fAfters)
+ try {
+ each.invokeExplosively(fTarget);
+ } catch (Throwable e) {
+ errors.add(e);
+ }
+ }
+ MultipleFailureException.assertEmpty(errors);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/internal/runners/statements/RunBefores.java b/src/org/junit/internal/runners/statements/RunBefores.java
new file mode 100644
index 0000000..66a34e1
--- /dev/null
+++ b/src/org/junit/internal/runners/statements/RunBefores.java
@@ -0,0 +1,30 @@
+/**
+ *
+ */
+package org.junit.internal.runners.statements;
+
+import java.util.List;
+
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+public class RunBefores extends Statement {
+ private final Statement fNext;
+
+ private final Object fTarget;
+
+ private final List<FrameworkMethod> fBefores;
+
+ public RunBefores(Statement next, List<FrameworkMethod> befores, Object target) {
+ fNext= next;
+ fBefores= befores;
+ fTarget= target;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ for (FrameworkMethod before : fBefores)
+ before.invokeExplosively(fTarget);
+ fNext.evaluate();
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/matchers/JUnitMatchers.java b/src/org/junit/matchers/JUnitMatchers.java
new file mode 100644
index 0000000..ec2ec4a
--- /dev/null
+++ b/src/org/junit/matchers/JUnitMatchers.java
@@ -0,0 +1,83 @@
+package org.junit.matchers;
+
+import org.hamcrest.Matcher;
+import org.junit.internal.matchers.CombinableMatcher;
+import org.junit.internal.matchers.Each;
+import org.junit.internal.matchers.IsCollectionContaining;
+import org.junit.internal.matchers.StringContains;
+
+/**
+ * Convenience import class: these are useful matchers for use with the assertThat method, but they are
+ * not currently included in the basic CoreMatchers class from hamcrest.
+ */
+public class JUnitMatchers {
+ /**
+ * @param element
+ * @return A matcher matching any collection containing element
+ */
+ public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItem(T element) {
+ return IsCollectionContaining.hasItem(element);
+ }
+
+ /**
+ * @param elementMatcher
+ * @return A matcher matching any collection containing an element matching elementMatcher
+ */
+ public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItem(org.hamcrest.Matcher<? extends T> elementMatcher) {
+ return IsCollectionContaining.hasItem(elementMatcher);
+ }
+
+ /**
+ * @param elements
+ * @return A matcher matching any collection containing every element in elements
+ */
+ public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItems(T... elements) {
+ return IsCollectionContaining.hasItems(elements);
+ }
+
+ /**
+ * @param elementMatchers
+ * @return A matcher matching any collection containing at least one element that matches
+ * each matcher in elementMatcher (this may be one element matching all matchers,
+ * or different elements matching each matcher)
+ */
+ public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItems(org.hamcrest.Matcher<? extends T>... elementMatchers) {
+ return IsCollectionContaining.hasItems(elementMatchers);
+ }
+
+ /**
+ * @param elementMatcher
+ * @return A matcher matching any collection in which every element matches elementMatcher
+ */
+ public static <T> Matcher<Iterable<T>> everyItem(final Matcher<T> elementMatcher) {
+ return Each.each(elementMatcher);
+ }
+
+ /**
+ * @param substring
+ * @return a matcher matching any string that contains substring
+ */
+ public static org.hamcrest.Matcher<java.lang.String> containsString(java.lang.String substring) {
+ return StringContains.containsString(substring);
+ }
+
+ /**
+ * This is useful for fluently combining matchers that must both pass. For example:
+ * <pre>
+ * assertThat(string, both(containsString("a")).and(containsString("b")));
+ * </pre>
+ */
+ public static <T> CombinableMatcher<T> both(Matcher<T> matcher) {
+ return new CombinableMatcher<T>(matcher);
+ }
+
+ /**
+ * This is useful for fluently combining matchers where either may pass, for example:
+ * <pre>
+ * assertThat(string, either(containsString("a")).or(containsString("b")));
+ * </pre>
+ */
+ public static <T> CombinableMatcher<T> either(Matcher<T> matcher) {
+ return new CombinableMatcher<T>(matcher);
+ }
+}
diff --git a/src/org/junit/matchers/package-info.java b/src/org/junit/matchers/package-info.java
new file mode 100644
index 0000000..71aca34
--- /dev/null
+++ b/src/org/junit/matchers/package-info.java
@@ -0,0 +1,9 @@
+/**
+ * Provides useful additional {@link org.hamcrest.Matcher}s for use with
+ * the {@link org.junit.Assert#assertThat(Object, org.hamcrest.Matcher)}
+ * statement
+ *
+ * @since 4.0
+ * @see org.junit.matchers.JUnitMatchers
+ */
+package org.junit.matchers; \ No newline at end of file
diff --git a/src/org/junit/package-info.java b/src/org/junit/package-info.java
new file mode 100644
index 0000000..bb60d0d
--- /dev/null
+++ b/src/org/junit/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * Provides JUnit core classes and annotations.
+ *
+ * Corresponds to junit.framework in Junit 3.x.
+ *
+ * @since 4.0
+ */
+package org.junit; \ No newline at end of file
diff --git a/src/org/junit/rules/ErrorCollector.java b/src/org/junit/rules/ErrorCollector.java
new file mode 100644
index 0000000..3522a65
--- /dev/null
+++ b/src/org/junit/rules/ErrorCollector.java
@@ -0,0 +1,85 @@
+/**
+ *
+ */
+package org.junit.rules;
+
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.hamcrest.Matcher;
+import org.junit.runners.model.MultipleFailureException;
+
+/**
+ * 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):
+ *
+ * <pre>
+ * public static class UsesErrorCollectorTwice {
+ * &#064;Rule
+ * public ErrorCollector collector= new ErrorCollector();
+ *
+ * &#064;Test
+ * public void example() {
+ * collector.addError(new Throwable(&quot;first thing went wrong&quot;));
+ * collector.addError(new Throwable(&quot;second thing went wrong&quot;));
+ * collector.checkThat(getResult(), not(containsString(&quot;ERROR!&quot;)));
+ * // all lines will run, and then a combined failure logged at the end.
+ * }
+ * }
+ * </pre>
+ */
+public class ErrorCollector extends Verifier {
+ private List<Throwable> errors= new ArrayList<Throwable>();
+
+ @Override
+ protected void verify() throws Throwable {
+ MultipleFailureException.assertEmpty(errors);
+ }
+
+ /**
+ * Adds a Throwable to the table. Execution continues, but the test will fail at the end.
+ */
+ public void addError(Throwable error) {
+ errors.add(error);
+ }
+
+ /**
+ * Adds a failure to the table if {@code matcher} does not match {@code value}.
+ * Execution continues, but the test will fail at the end if the match fails.
+ */
+ public <T> void checkThat(final T value, final Matcher<T> matcher) {
+ checkThat("", value, matcher);
+ }
+
+ /**
+ * Adds a failure with the given {@code reason}
+ * to the table if {@code matcher} does not match {@code value}.
+ * Execution continues, but the test will fail at the end if the match fails.
+ */
+ public <T> void checkThat(final String reason, final T value, final Matcher<T> matcher) {
+ checkSucceeds(new Callable<Object>() {
+ public Object call() throws Exception {
+ assertThat(reason, value, matcher);
+ return value;
+ }
+ });
+ }
+
+ /**
+ * Adds to the table the exception, if any, thrown from {@code callable}.
+ * Execution continues, but the test will fail at the end if
+ * {@code callable} threw an exception.
+ */
+ public Object checkSucceeds(Callable<Object> callable) {
+ try {
+ return callable.call();
+ } catch (Throwable e) {
+ addError(e);
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/rules/ExpectedException.java b/src/org/junit/rules/ExpectedException.java
new file mode 100644
index 0000000..bac2fba
--- /dev/null
+++ b/src/org/junit/rules/ExpectedException.java
@@ -0,0 +1,136 @@
+package org.junit.rules;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.matchers.JUnitMatchers.both;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.StringDescription;
+import org.junit.Assert;
+import org.junit.internal.matchers.TypeSafeMatcher;
+import org.junit.runners.model.Statement;
+
+/**
+ * The ExpectedException Rule allows in-test specification of expected exception
+ * types and messages:
+ *
+ * <pre>
+ * // These tests all pass.
+ * public static class HasExpectedException {
+ * &#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 throwsNullPointerExceptionWithMessage() {
+ * thrown.expect(NullPointerException.class);
+ * thrown.expectMessage(&quot;happened?&quot;);
+ * thrown.expectMessage(startsWith(&quot;What&quot;));
+ * throw new NullPointerException(&quot;What happened?&quot;);
+ * }
+ * }
+ * </pre>
+ */
+public class ExpectedException implements TestRule {
+ /**
+ * @return a Rule that expects no exception to be thrown
+ * (identical to behavior without this Rule)
+ */
+ public static ExpectedException none() {
+ return new ExpectedException();
+ }
+
+ private Matcher<Object> fMatcher= null;
+
+ private ExpectedException() {
+
+ }
+
+ public Statement apply(Statement base,
+ org.junit.runner.Description description) {
+ return new ExpectedExceptionStatement(base);
+ }
+
+ /**
+ * Adds {@code matcher} to the list of requirements for any thrown exception.
+ */
+ // Should be able to remove this suppression in some brave new hamcrest world.
+ @SuppressWarnings("unchecked")
+ public void expect(Matcher<?> matcher) {
+ if (fMatcher == null)
+ fMatcher= (Matcher<Object>) matcher;
+ else
+ fMatcher= both(fMatcher).and(matcher);
+ }
+
+ /**
+ * Adds to the list of requirements for any thrown exception that it
+ * should be an instance of {@code type}
+ */
+ 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}
+ */
+ public void expectMessage(String substring) {
+ expectMessage(containsString(substring));
+ }
+
+ /**
+ * Adds {@code matcher} to the list of requirements for the message
+ * returned from any thrown exception.
+ */
+ public void expectMessage(Matcher<String> matcher) {
+ expect(hasMessage(matcher));
+ }
+
+ private class ExpectedExceptionStatement extends Statement {
+ private final Statement fNext;
+
+ public ExpectedExceptionStatement(Statement base) {
+ fNext= base;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ fNext.evaluate();
+ } catch (Throwable e) {
+ if (fMatcher == null)
+ throw e;
+ Assert.assertThat(e, fMatcher);
+ return;
+ }
+ if (fMatcher != null)
+ throw new AssertionError("Expected test to throw "
+ + StringDescription.toString(fMatcher));
+ }
+ }
+
+ private Matcher<Throwable> hasMessage(final Matcher<String> matcher) {
+ return new TypeSafeMatcher<Throwable>() {
+ public void describeTo(Description description) {
+ description.appendText("exception with message ");
+ description.appendDescriptionOf(matcher);
+ }
+
+ @Override
+ public boolean matchesSafely(Throwable item) {
+ return matcher.matches(item.getMessage());
+ }
+ };
+ }
+}
diff --git a/src/org/junit/rules/ExternalResource.java b/src/org/junit/rules/ExternalResource.java
new file mode 100644
index 0000000..1fe3719
--- /dev/null
+++ b/src/org/junit/rules/ExternalResource.java
@@ -0,0 +1,68 @@
+package org.junit.rules;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * 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:
+ *
+ * <pre>
+ * public static class UsesExternalResource {
+ * Server myServer= new Server();
+ *
+ * &#064;Rule
+ * public ExternalResource resource= new ExternalResource() {
+ * &#064;Override
+ * protected void before() throws Throwable {
+ * myServer.connect();
+ * };
+ *
+ * &#064;Override
+ * protected void after() {
+ * myServer.disconnect();
+ * };
+ * };
+ *
+ * &#064;Test
+ * public void testFoo() {
+ * new Client().run(myServer);
+ * }
+ * }
+ * </pre>
+ */
+public abstract class ExternalResource implements TestRule {
+ public Statement apply(Statement base, Description description) {
+ return statement(base);
+ }
+
+ private Statement statement(final Statement base) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ before();
+ try {
+ base.evaluate();
+ } finally {
+ after();
+ }
+ }
+ };
+ }
+
+ /**
+ * Override to set up your specific external resource.
+ * @throws if setup fails (which will disable {@code after}
+ */
+ protected void before() throws Throwable {
+ // do nothing
+ }
+
+ /**
+ * Override to tear down your specific external resource.
+ */
+ protected void after() {
+ // do nothing
+ }
+}
diff --git a/src/org/junit/rules/MethodRule.java b/src/org/junit/rules/MethodRule.java
new file mode 100644
index 0000000..5167672
--- /dev/null
+++ b/src/org/junit/rules/MethodRule.java
@@ -0,0 +1,40 @@
+package org.junit.rules;
+
+import org.junit.Rule;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+/**
+ * A MethodRule is an alteration in how a test method is run and reported.
+ * Multiple {@link MethodRule}s can be applied to a test method. The
+ * {@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:
+ *
+ * <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>
+ */
+@Deprecated
+public interface MethodRule {
+ /**
+ * Modifies the method-running {@link Statement} to implement an additional
+ * test-running rule.
+ *
+ * @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.
+ * @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/org/junit/rules/RuleChain.java b/src/org/junit/rules/RuleChain.java
new file mode 100644
index 0000000..8af3c05
--- /dev/null
+++ b/src/org/junit/rules/RuleChain.java
@@ -0,0 +1,99 @@
+/**
+ *
+ */
+package org.junit.rules;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * The RuleChain rule allows ordering of TestRules. You create a
+ * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
+ * {@link #around(TestRule)}:
+ *
+ * <pre>
+ * public static class UseRuleChain {
+ * &#064;Rule
+ * public TestRule chain= RuleChain
+ * .outerRule(new LoggingRule("outer rule")
+ * .around(new LoggingRule("middle rule")
+ * .around(new LoggingRule("inner rule");
+ *
+ * &#064;Test
+ * public void example() {
+ * assertTrue(true);
+ * }
+ * }
+ * </pre>
+ *
+ * writes the log
+ *
+ * <pre>
+ * starting outer rule
+ * starting middle rule
+ * starting inner rule
+ * finished inner rule
+ * finished middle rule
+ * finished outer rule
+ * </pre>
+ */
+public class RuleChain implements TestRule {
+ private static final RuleChain EMPTY_CHAIN= new RuleChain(
+ Collections.<TestRule> emptyList());
+
+ private List<TestRule> rulesStartingWithInnerMost;
+
+ /**
+ * Returns a {@code RuleChain} without a {@link TestRule}. This method may
+ * be the starting point of a {@code RuleChain}.
+ *
+ * @return a {@code RuleChain} without a {@link TestRule}.
+ */
+ public static RuleChain emptyRuleChain() {
+ return EMPTY_CHAIN;
+ }
+
+ /**
+ * Returns a {@code RuleChain} with a single {@link TestRule}. This method
+ * is the usual starting point of a {@code RuleChain}.
+ *
+ * @param outerRule
+ * the outer rule of the {@code RuleChain}.
+ * @return a {@code RuleChain} with a single {@link TestRule}.
+ */
+ public static RuleChain outerRule(TestRule outerRule) {
+ return emptyRuleChain().around(outerRule);
+ }
+
+ private RuleChain(List<TestRule> rules) {
+ this.rulesStartingWithInnerMost= rules;
+ }
+
+ /**
+ * Create a new {@code RuleChain}, which encloses the {@code nextRule} with
+ * the rules of the current {@code RuleChain}.
+ *
+ * @param enclosedRule
+ * the rule to enclose.
+ * @return a new {@code RuleChain}.
+ */
+ public RuleChain around(TestRule enclosedRule) {
+ List<TestRule> rulesOfNewChain= new ArrayList<TestRule>();
+ rulesOfNewChain.add(enclosedRule);
+ rulesOfNewChain.addAll(rulesStartingWithInnerMost);
+ return new RuleChain(rulesOfNewChain);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Statement apply(Statement base, Description description) {
+ for (TestRule each : rulesStartingWithInnerMost)
+ base= each.apply(base, description);
+ return base;
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/rules/RunRules.java b/src/org/junit/rules/RunRules.java
new file mode 100644
index 0000000..d5905b9
--- /dev/null
+++ b/src/org/junit/rules/RunRules.java
@@ -0,0 +1,27 @@
+package org.junit.rules;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Runs a collection of rules on a statement.
+ */
+public class RunRules extends Statement {
+ private final Statement statement;
+
+ public RunRules(Statement base, Iterable<TestRule> rules, Description description) {
+ statement= applyAll(base, rules, description);
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ statement.evaluate();
+ }
+
+ private static Statement applyAll(Statement result, Iterable<TestRule> rules,
+ Description description) {
+ for (TestRule each : rules)
+ result= each.apply(result, description);
+ return result;
+ }
+}
diff --git a/src/org/junit/rules/TemporaryFolder.java b/src/org/junit/rules/TemporaryFolder.java
new file mode 100644
index 0000000..a7c82aa
--- /dev/null
+++ b/src/org/junit/rules/TemporaryFolder.java
@@ -0,0 +1,113 @@
+package org.junit.rules;
+
+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):
+ *
+ * <pre>
+ * public static class HasTempFolder {
+ * &#064;Rule
+ * public TemporaryFolder folder= new TemporaryFolder();
+ *
+ * &#064;Test
+ * public void testUsingTempFolder() throws IOException {
+ * File createdFile= folder.newFile(&quot;myfile.txt&quot;);
+ * File createdFolder= folder.newFolder(&quot;subfolder&quot;);
+ * // ...
+ * }
+ * }
+ * </pre>
+ */
+public class TemporaryFolder extends ExternalResource {
+ private File folder;
+
+ @Override
+ protected void before() throws Throwable {
+ create();
+ }
+
+ @Override
+ protected void after() {
+ delete();
+ }
+
+ // testing purposes only
+ /**
+ * for testing purposes only. Do not use.
+ */
+ public void create() throws IOException {
+ folder= newFolder();
+ }
+
+ /**
+ * Returns a new fresh file with the given name under the temporary folder.
+ */
+ public File newFile(String fileName) throws IOException {
+ File file= new File(getRoot(), fileName);
+ file.createNewFile();
+ return file;
+ }
+
+ /**
+ * Returns a new fresh file with a random name under the temporary folder.
+ */
+ public File newFile() throws IOException {
+ return File.createTempFile("junit", null, folder);
+ }
+
+ /**
+ * Returns a new fresh folder with the given name under the temporary folder.
+ */
+ public File newFolder(String... folderNames) {
+ File file = getRoot();
+ for (String folderName : folderNames) {
+ file = new File(file, folderName);
+ file.mkdir();
+ }
+ return file;
+ }
+
+ /**
+ * Returns a new fresh folder with a random name under the temporary
+ * folder.
+ */
+ public File newFolder() throws IOException {
+ File createdFolder= File.createTempFile("junit", "", folder);
+ createdFolder.delete();
+ createdFolder.mkdir();
+ return createdFolder;
+ }
+
+ /**
+ * @return the location of this temporary folder.
+ */
+ public File getRoot() {
+ if (folder == null) {
+ throw new IllegalStateException("the temporary folder has not yet been created");
+ }
+ return folder;
+ }
+
+ /**
+ * Delete all files and folders under the temporary folder.
+ * Usually not called directly, since it is automatically applied
+ * by the {@link Rule}
+ */
+ public void delete() {
+ recursiveDelete(folder);
+ }
+
+ private void recursiveDelete(File file) {
+ File[] files= file.listFiles();
+ if (files != null)
+ for (File each : files)
+ recursiveDelete(each);
+ file.delete();
+ }
+}
diff --git a/src/org/junit/rules/TestName.java b/src/org/junit/rules/TestName.java
new file mode 100644
index 0000000..c4ab9ce
--- /dev/null
+++ b/src/org/junit/rules/TestName.java
@@ -0,0 +1,39 @@
+package org.junit.rules;
+
+import org.junit.runner.Description;
+
+/**
+ * The TestName Rule makes the current test name available inside test methods:
+ *
+ * <pre>
+ * public class TestNameTest {
+ * &#064;Rule
+ * public TestName name= new TestName();
+ *
+ * &#064;Test
+ * public void testA() {
+ * assertEquals(&quot;testA&quot;, name.getMethodName());
+ * }
+ *
+ * &#064;Test
+ * public void testB() {
+ * assertEquals(&quot;testB&quot;, name.getMethodName());
+ * }
+ * }
+ * </pre>
+ */
+public class TestName extends TestWatcher {
+ private String fName;
+
+ @Override
+ protected void starting(Description d) {
+ fName= d.getMethodName();
+ }
+
+ /**
+ * @return the name of the currently-running test method
+ */
+ public String getMethodName() {
+ return fName;
+ }
+}
diff --git a/src/org/junit/rules/TestRule.java b/src/org/junit/rules/TestRule.java
new file mode 100644
index 0000000..b7760c4
--- /dev/null
+++ b/src/org/junit/rules/TestRule.java
@@ -0,0 +1,54 @@
+package org.junit.rules;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * A TestRule is an alteration in how a test method, or set of test methods,
+ * is run and reported. A {@link TestRule} may add additional checks that cause
+ * a test that would otherwise fail to pass, or it may perform necessary setup or
+ * cleanup for tests, or it may observe test execution to report it elsewhere.
+ * {@link TestRule}s can do everything that could be done previously with
+ * methods annotated with {@link org.junit.Before},
+ * {@link org.junit.After}, {@link org.junit.BeforeClass}, or
+ * {@link org.junit.AfterClass}, but they are more powerful, and more easily
+ * shared
+ * between projects and classes.
+ *
+ * The default JUnit test runners for suites and
+ * individual test cases recognize {@link TestRule}s introduced in two different
+ * ways. {@link org.junit.Rule} annotates method-level
+ * {@link TestRule}s, and {@link org.junit.ClassRule}
+ * annotates class-level {@link TestRule}s. See Javadoc for those annotations
+ * for more information.
+ *
+ * Multiple {@link TestRule}s can be applied to a test or suite execution. The
+ * {@link Statement} that executes the method or suite is passed to each annotated
+ * {@link org.junit.Rule} in turn, and each may return a substitute or modified
+ * {@link Statement}, which is passed to the next {@link org.junit.Rule}, if any. For
+ * examples of how this can be useful, see these provided TestRules,
+ * or write your own:
+ *
+ * <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 TestWatcher}: 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>
+ */
+public interface TestRule {
+ /**
+ * Modifies the method-running {@link Statement} to implement this
+ * test-running rule.
+ *
+ * @param base The {@link Statement} to be modified
+ * @param description A {@link Description} of the test implemented in {@code base}
+ * @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, Description description);
+}
diff --git a/src/org/junit/rules/TestWatcher.java b/src/org/junit/rules/TestWatcher.java
new file mode 100644
index 0000000..351b449
--- /dev/null
+++ b/src/org/junit/rules/TestWatcher.java
@@ -0,0 +1,94 @@
+package org.junit.rules;
+
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * TestWatcher 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:
+ *
+ * <pre>
+ * public static class WatchmanTest {
+ * private static String watchedLog;
+ *
+ * &#064;Rule
+ * public MethodRule watchman= new TestWatcher() {
+ * &#064;Override
+ * protected void failed(Description d) {
+ * watchedLog+= d + &quot;\n&quot;;
+ * }
+ *
+ * &#064;Override
+ * protected void succeeded(Description d) {
+ * watchedLog+= d + &quot; &quot; + &quot;success!\n&quot;;
+ * }
+ * };
+ *
+ * &#064;Test
+ * public void fails() {
+ * fail();
+ * }
+ *
+ * &#064;Test
+ * public void succeeds() {
+ * }
+ * }
+ * </pre>
+ */
+public abstract class TestWatcher implements TestRule {
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ starting(description);
+ try {
+ base.evaluate();
+ succeeded(description);
+ } catch (AssumptionViolatedException e) {
+ throw e;
+ } catch (Throwable t) {
+ failed(t, description);
+ throw t;
+ } finally {
+ finished(description);
+ }
+ }
+ };
+ }
+
+ /**
+ * Invoked when a test succeeds
+ *
+ * @param description
+ */
+ protected void succeeded(Description description) {
+ }
+
+ /**
+ * Invoked when a test fails
+ *
+ * @param e
+ * @param description
+ */
+ protected void failed(Throwable e, Description description) {
+ }
+
+ /**
+ * Invoked when a test is about to start
+ *
+ * @param description
+ */
+ protected void starting(Description description) {
+ }
+
+
+ /**
+ * Invoked when a test method finishes (whether passing or failing)
+ *
+ * @param description
+ */
+ protected void finished(Description description) {
+ }
+}
diff --git a/src/org/junit/rules/TestWatchman.java b/src/org/junit/rules/TestWatchman.java
new file mode 100644
index 0000000..15daa64
--- /dev/null
+++ b/src/org/junit/rules/TestWatchman.java
@@ -0,0 +1,100 @@
+package org.junit.rules;
+
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+/**
+ * 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:
+ *
+ * <pre>
+ * public static class WatchmanTest {
+ * private static String watchedLog;
+ *
+ * &#064;Rule
+ * public MethodRule watchman= new TestWatchman() {
+ * &#064;Override
+ * public void failed(Throwable e, FrameworkMethod method) {
+ * watchedLog+= method.getName() + &quot; &quot; + e.getClass().getSimpleName()
+ * + &quot;\n&quot;;
+ * }
+ *
+ * &#064;Override
+ * public void succeeded(FrameworkMethod method) {
+ * watchedLog+= method.getName() + &quot; &quot; + &quot;success!\n&quot;;
+ * }
+ * };
+ *
+ * &#064;Test
+ * public void fails() {
+ * fail();
+ * }
+ *
+ * &#064;Test
+ * public void succeeds() {
+ * }
+ * }
+ * </pre>
+ *
+ * @deprecated {@link MethodRule} is deprecated.
+ * Use {@link TestWatcher} implements {@link TestRule} instead.
+ */
+@Deprecated
+public class TestWatchman implements MethodRule {
+ public Statement apply(final Statement base, final FrameworkMethod method,
+ Object target) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ starting(method);
+ try {
+ base.evaluate();
+ succeeded(method);
+ } catch (AssumptionViolatedException e) {
+ throw e;
+ } catch (Throwable t) {
+ failed(t, method);
+ throw t;
+ } finally {
+ finished(method);
+ }
+ }
+ };
+ }
+
+ /**
+ * Invoked when a test method succeeds
+ *
+ * @param method
+ */
+ public void succeeded(FrameworkMethod method) {
+ }
+
+ /**
+ * Invoked when a test method fails
+ *
+ * @param e
+ * @param method
+ */
+ public void failed(Throwable e, FrameworkMethod method) {
+ }
+
+ /**
+ * Invoked when a test method is about to start
+ *
+ * @param method
+ */
+ public void starting(FrameworkMethod method) {
+ }
+
+
+ /**
+ * Invoked when a test method finishes (whether passing or failing)
+ *
+ * @param method
+ */
+ public void finished(FrameworkMethod method) {
+ }
+}
diff --git a/src/org/junit/rules/Timeout.java b/src/org/junit/rules/Timeout.java
new file mode 100644
index 0000000..85ce6d6
--- /dev/null
+++ b/src/org/junit/rules/Timeout.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package org.junit.rules;
+
+import org.junit.internal.runners.statements.FailOnTimeout;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * The Timeout Rule applies the same timeout to all test methods in a class:
+ *
+ * <pre>
+ * public static class HasGlobalTimeout {
+ * public static String log;
+ *
+ * &#064;Rule
+ * public MethodRule globalTimeout= new Timeout(20);
+ *
+ * &#064;Test
+ * public void testInfiniteLoop1() {
+ * log+= &quot;ran1&quot;;
+ * for (;;) {
+ * }
+ * }
+ *
+ * &#064;Test
+ * public void testInfiniteLoop2() {
+ * log+= &quot;ran2&quot;;
+ * for (;;) {
+ * }
+ * }
+ * }
+ * </pre>
+ */
+public class Timeout implements TestRule {
+ private final int fMillis;
+
+ /**
+ * @param millis the millisecond timeout
+ */
+ public Timeout(int millis) {
+ fMillis= millis;
+ }
+
+ public Statement apply(Statement base, Description description) {
+ return new FailOnTimeout(base, fMillis);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/rules/Verifier.java b/src/org/junit/rules/Verifier.java
new file mode 100644
index 0000000..be1a55e
--- /dev/null
+++ b/src/org/junit/rules/Verifier.java
@@ -0,0 +1,45 @@
+package org.junit.rules;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * 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
+ *
+ * <pre>
+ * public static class ErrorLogVerifier() {
+ * private ErrorLog errorLog = new ErrorLog();
+ *
+ * &#064;Rule
+ * public MethodRule verifier = new Verifier() {
+ * &#064;Override public void verify() {
+ * assertTrue(errorLog.isEmpty());
+ * }
+ * }
+ *
+ * &#064;Test public void testThatMightWriteErrorLog() {
+ * // ...
+ * }
+ * }
+ * </pre>
+ */
+public class Verifier implements TestRule {
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ base.evaluate();
+ verify();
+ }
+ };
+ }
+
+ /**
+ * Override this to add verification logic. Overrides should throw an
+ * exception to indicate that verification failed.
+ */
+ protected void verify() throws Throwable {
+ }
+}
diff --git a/src/org/junit/runner/Computer.java b/src/org/junit/runner/Computer.java
new file mode 100644
index 0000000..939f702
--- /dev/null
+++ b/src/org/junit/runner/Computer.java
@@ -0,0 +1,40 @@
+package org.junit.runner;
+
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Represents a strategy for computing runners and suites.
+ * WARNING: this class is very likely to undergo serious changes in version 4.8 and
+ * beyond.
+ */
+public class Computer {
+ /**
+ * Returns a new default computer, which runs tests in serial order
+ */
+ public static Computer serial() {
+ return new Computer();
+ }
+
+ /**
+ * Create a suite for {@code classes}, building Runners with {@code builder}.
+ * Throws an InitializationError if Runner construction fails
+ */
+ public Runner getSuite(final RunnerBuilder builder,
+ Class<?>[] classes) throws InitializationError {
+ return new Suite(new RunnerBuilder() {
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Throwable {
+ return getRunner(builder, testClass);
+ }
+ }, classes);
+ }
+
+ /**
+ * Create a single-class runner for {@code testClass}, using {@code builder}
+ */
+ protected Runner getRunner(RunnerBuilder builder, Class<?> testClass) throws Throwable {
+ return builder.runnerForClass(testClass);
+ }
+}
diff --git a/src/org/junit/runner/Describable.java b/src/org/junit/runner/Describable.java
new file mode 100644
index 0000000..e59cc01
--- /dev/null
+++ b/src/org/junit/runner/Describable.java
@@ -0,0 +1,12 @@
+package org.junit.runner;
+
+
+/**
+ * Represents an object that can describe itself
+ */
+public interface Describable {
+ /**
+ * @return a {@link Description} showing the tests to be run by the receiver
+ */
+ public abstract Description getDescription();
+} \ No newline at end of file
diff --git a/src/org/junit/runner/Description.java b/src/org/junit/runner/Description.java
new file mode 100644
index 0000000..b3083d5
--- /dev/null
+++ b/src/org/junit/runner/Description.java
@@ -0,0 +1,242 @@
+package org.junit.runner;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+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>
+ * 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
+ * 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>
+ *
+ * @see org.junit.runner.Request
+ * @see org.junit.runner.Runner
+ */
+public class Description implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Create a <code>Description</code> named <code>name</code>.
+ * Generally, you will add children to this <code>Description</code>.
+ * @param name the name of the <code>Description</code>
+ * @param annotations
+ * @return a <code>Description</code> named <code>name</code>
+ */
+ public static Description createSuiteDescription(String name, Annotation... annotations) {
+ if (name.length() == 0)
+ throw new IllegalArgumentException("name must have non-zero length");
+ return new Description(name, annotations);
+ }
+
+ /**
+ * Create a <code>Description</code> of a single test named <code>name</code> in the class <code>clazz</code>.
+ * Generally, this will be a leaf <code>Description</code>.
+ * @param clazz the class of the test
+ * @param name the name of the test (a method name for test annotated with {@link org.junit.Test})
+ * @param annotations meta-data about the test, for downstream interpreters
+ * @return a <code>Description</code> named <code>name</code>
+ */
+ public static Description createTestDescription(Class<?> clazz, String name, Annotation... annotations) {
+ return new Description(String.format("%s(%s)", name, clazz.getName()), annotations);
+ }
+
+ /**
+ * Create a <code>Description</code> of a single test named <code>name</code> in the class <code>clazz</code>.
+ * Generally, this will be a leaf <code>Description</code>.
+ * (This remains for binary compatibility with clients of JUnit 4.3)
+ * @param clazz the class of the test
+ * @param name the name of the test (a method name for test annotated with {@link org.junit.Test})
+ * @return a <code>Description</code> named <code>name</code>
+ */
+ public static Description createTestDescription(Class<?> clazz, String name) {
+ return createTestDescription(clazz, name, new Annotation[0]);
+ }
+
+ /**
+ * Create a <code>Description</code> named after <code>testClass</code>
+ * @param testClass A {@link Class} containing tests
+ * @return a <code>Description</code> of <code>testClass</code>
+ */
+ public static Description createSuiteDescription(Class<?> testClass) {
+ return new Description(testClass.getName(), testClass.getAnnotations());
+ }
+
+ /**
+ * Describes a Runner which runs no tests
+ */
+ public static final Description EMPTY= new Description("No Tests");
+
+ /**
+ * Describes a step in the test-running mechanism that goes so wrong no
+ * other description can be used (for example, an exception thrown from a Runner's
+ * constructor
+ */
+ public static final Description TEST_MECHANISM= new Description("Test mechanism");
+
+ private final ArrayList<Description> fChildren= new ArrayList<Description>();
+ private final String fDisplayName;
+
+ private final Annotation[] fAnnotations;
+
+ private Description(final String displayName, Annotation... annotations) {
+ fDisplayName= displayName;
+ fAnnotations= annotations;
+ }
+
+ /**
+ * @return a user-understandable label
+ */
+ public String getDisplayName() {
+ return fDisplayName;
+ }
+
+ /**
+ * Add <code>Description</code> as a child of the receiver.
+ * @param description the soon-to-be child.
+ */
+ public void addChild(Description description) {
+ getChildren().add(description);
+ }
+
+ /**
+ * @return the receiver's children, if any
+ */
+ public ArrayList<Description> getChildren() {
+ return fChildren;
+ }
+
+ /**
+ * @return <code>true</code> if the receiver is a suite
+ */
+ public boolean isSuite() {
+ return !isTest();
+ }
+
+ /**
+ * @return <code>true</code> if the receiver is an atomic test
+ */
+ public boolean isTest() {
+ return getChildren().isEmpty();
+ }
+
+ /**
+ * @return the total number of atomic tests in the receiver
+ */
+ public int testCount() {
+ if (isTest())
+ return 1;
+ int result= 0;
+ for (Description child : getChildren())
+ result+= child.testCount();
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return getDisplayName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Description))
+ return false;
+ Description d = (Description) obj;
+ return getDisplayName().equals(d.getDisplayName());
+ }
+
+ @Override
+ public String toString() {
+ return getDisplayName();
+ }
+
+ /**
+ * @return true if this is a description of a Runner that runs no tests
+ */
+ public boolean isEmpty() {
+ return equals(EMPTY);
+ }
+
+ /**
+ * @return a copy of this description, with no children (on the assumption that some of the
+ * children will be added back)
+ */
+ public Description childlessCopy() {
+ return new Description(fDisplayName, fAnnotations);
+ }
+
+ /**
+ * @return the annotation of type annotationType that is attached to this description node,
+ * or null if none exists
+ */
+ public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+ for (Annotation each : fAnnotations)
+ if (each.annotationType().equals(annotationType))
+ return annotationType.cast(each);
+ return null;
+ }
+
+ /**
+ * @return all of the annotations attached to this description node
+ */
+ public Collection<Annotation> getAnnotations() {
+ return Arrays.asList(fAnnotations);
+ }
+
+ /**
+ * @return If this describes a method invocation,
+ * the class of the test instance.
+ */
+ public Class<?> getTestClass() {
+ String name= getClassName();
+ if (name == null)
+ return null;
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @return If this describes a method invocation,
+ * the name of the class of the test instance
+ */
+ public String getClassName() {
+ Matcher matcher= methodStringMatcher();
+ return matcher.matches()
+ ? matcher.group(2)
+ : toString();
+ }
+
+ /**
+ * @return If this describes a method invocation,
+ * the name of the method (or null if not)
+ */
+ public String getMethodName() {
+ return parseMethod();
+ }
+
+ private String parseMethod() {
+ Matcher matcher= methodStringMatcher();
+ if (matcher.matches())
+ return matcher.group(1);
+ return null;
+ }
+
+ private Matcher methodStringMatcher() {
+ return Pattern.compile("(.*)\\((.*)\\)").matcher(toString());
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/runner/JUnitCore.java b/src/org/junit/runner/JUnitCore.java
new file mode 100644
index 0000000..2fcd3b3
--- /dev/null
+++ b/src/org/junit/runner/JUnitCore.java
@@ -0,0 +1,186 @@
+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;
+
+/**
+ * <code>JUnitCore</code> is a facade for running tests. It supports running JUnit 4 tests,
+ * JUnit 3.8.x tests, and mixtures. To run tests from the command line, run
+ * <code>java org.junit.runner.JUnitCore TestClass1 TestClass2 ...</code>.
+ * For one-shot test runs, use the static method {@link #runClasses(Class[])}.
+ * If you want to add special listeners,
+ * create an instance of {@link org.junit.runner.JUnitCore} first and use it to run the tests.
+ *
+ * @see org.junit.runner.Result
+ * @see org.junit.runner.notification.RunListener
+ * @see org.junit.runner.Request
+ */
+public class JUnitCore {
+ private RunNotifier fNotifier;
+
+ /**
+ * Create a new <code>JUnitCore</code> to run tests.
+ */
+ public JUnitCore() {
+ fNotifier= new RunNotifier();
+ }
+
+ /**
+ * Run the tests contained in the classes named in the <code>args</code>.
+ * If all tests run successfully, exit with a status of 0. Otherwise exit with a status of 1.
+ * Write feedback while tests are running and write
+ * stack traces for all failed tests after the tests all complete.
+ * @param args names of classes in which to find tests to run
+ */
+ public static void main(String... args) {
+ runMainAndExit(new RealSystem(), args);
+ }
+
+ /**
+ * Do not use. Testing purposes only.
+ * @param system
+ */
+ public static void runMainAndExit(JUnitSystem system, String... args) {
+ Result result= new JUnitCore().runMain(system, args);
+ system.exit(result.wasSuccessful() ? 0 : 1);
+ }
+
+ /**
+ * 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);
+ }
+ /**
+ * 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);
+ }
+
+ /**
+ * Do not use. Testing purposes only.
+ * @param system
+ */
+ public 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);
+ }
+ 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 the version number of this release
+ */
+ public String getVersion() {
+ return Version.id();
+ }
+
+ /**
+ * Run all the tests in <code>classes</code>.
+ * @param classes the classes containing tests
+ * @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));
+ }
+
+ /**
+ * Run all the tests in <code>classes</code>.
+ * @param computer Helps construct Runners from classes
+ * @param classes the classes containing tests
+ * @return a {@link Result} describing the details of the test run and the failed tests.
+ */
+ public Result run(Computer computer, Class<?>... classes) {
+ return run(Request.classes(computer, classes));
+ }
+
+ /**
+ * Run all the tests contained in <code>request</code>.
+ * @param request the request describing tests
+ * @return a {@link Result} describing the details of the test run and the failed tests.
+ */
+ public Result run(Request request) {
+ return run(request.getRunner());
+ }
+
+ /**
+ * Run all the tests contained in JUnit 3.8.x <code>test</code>. Here for backward compatibility.
+ * @param test the old-style test
+ * @return a {@link Result} describing the details of the test run and the failed tests.
+ */
+ public Result run(junit.framework.Test test) {
+ return run(new JUnit38ClassRunner(test));
+ }
+
+ /**
+ * Do not use. Testing purposes only.
+ */
+ public Result run(Runner runner) {
+ Result result= new Result();
+ RunListener listener= result.createListener();
+ fNotifier.addFirstListener(listener);
+ try {
+ fNotifier.fireTestRunStarted(runner.getDescription());
+ runner.run(fNotifier);
+ fNotifier.fireTestRunFinished(result);
+ } finally {
+ removeListener(listener);
+ }
+ return result;
+ }
+
+ /**
+ * Add a listener to be notified as the tests run.
+ * @param listener the listener to add
+ * @see org.junit.runner.notification.RunListener
+ */
+ public void addListener(RunListener listener) {
+ fNotifier.addListener(listener);
+ }
+
+ /**
+ * Remove a listener.
+ * @param listener the listener to remove
+ */
+ public void removeListener(RunListener listener) {
+ fNotifier.removeListener(listener);
+ }
+
+ static Computer defaultComputer() {
+ return new Computer();
+ }
+
+}
diff --git a/src/org/junit/runner/Request.java b/src/org/junit/runner/Request.java
new file mode 100644
index 0000000..310b915
--- /dev/null
+++ b/src/org/junit/runner/Request.java
@@ -0,0 +1,161 @@
+package org.junit.runner;
+
+import java.util.Comparator;
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.internal.requests.ClassRequest;
+import org.junit.internal.requests.FilterRequest;
+import org.junit.internal.requests.SortingRequest;
+import org.junit.internal.runners.ErrorReportingRunner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runners.model.InitializationError;
+
+/**
+ * <p>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>
+ *
+ * <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> ->
+ * 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>
+ */
+public abstract class Request {
+ /**
+ * Create a <code>Request</code> that, when processed, will run a single test.
+ * This is done by filtering out all other tests. This method is used to support rerunning
+ * single tests.
+ * @param clazz the class of the test
+ * @param methodName the name of the test
+ * @return a <code>Request</code> that will cause a single test be run
+ */
+ public static Request method(Class<?> clazz, String methodName) {
+ Description method= Description.createTestDescription(clazz, methodName);
+ return Request.aClass(clazz).filterWith(method);
+ }
+
+ /**
+ * Create a <code>Request</code> that, when processed, will run all the tests
+ * in a class. The odd name is necessary because <code>class</code> is a reserved word.
+ * @param clazz the class containing the tests
+ * @return a <code>Request</code> that will cause all tests in the class to be run
+ */
+ public static Request aClass(Class<?> clazz) {
+ return new ClassRequest(clazz);
+ }
+
+ /**
+ * Create a <code>Request</code> that, when processed, will run all the tests
+ * in a class. If the class has a suite() method, it will be ignored.
+ * @param clazz the class containing the tests
+ * @return a <code>Request</code> that will cause all tests in the class to be run
+ */
+ public static Request classWithoutSuiteMethod(Class<?> clazz) {
+ return new ClassRequest(clazz, false);
+ }
+
+ /**
+ * Create a <code>Request</code> that, when processed, will run all the tests
+ * in a set of classes.
+ * @param computer Helps construct Runners from classes
+ * @param classes the classes containing the tests
+ * @return a <code>Request</code> that will cause all tests in the classes to be run
+ */
+ public static Request classes(Computer computer, Class<?>... classes) {
+ try {
+ AllDefaultPossibilitiesBuilder builder= new AllDefaultPossibilitiesBuilder(true);
+ 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");
+ }
+ }
+
+ /**
+ * Create a <code>Request</code> that, when processed, will run all the tests
+ * in a set of classes with the default <code>Computer</code>.
+ * @param classes the classes containing the tests
+ * @return a <code>Request</code> that will cause all tests in the classes to be run
+ */
+ public static Request classes(Class<?>... classes) {
+ return classes(JUnitCore.defaultComputer(), classes);
+ }
+
+
+ /**
+ * Not used within JUnit. Clients should simply instantiate ErrorReportingRunner themselves
+ */
+ @Deprecated
+ public static Request errorReport(Class<?> klass, Throwable cause) {
+ return runner(new ErrorReportingRunner(klass, cause));
+ }
+
+ /**
+ * @param runner the runner to return
+ * @return a <code>Request</code> that will run the given runner when invoked
+ */
+ public static Request runner(final Runner runner) {
+ return new Request(){
+ @Override
+ public Runner getRunner() {
+ return runner;
+ }
+ };
+ }
+
+ /**
+ * Returns a {@link Runner} for this Request
+ * @return corresponding {@link Runner} for this Request
+ */
+ public abstract Runner getRunner();
+
+ /**
+ * Returns a Request that only contains those tests that should run when
+ * <code>filter</code> is applied
+ * @param filter The {@link Filter} to apply to this Request
+ * @return the filtered Request
+ */
+ public Request filterWith(Filter filter) {
+ return new FilterRequest(this, filter);
+ }
+
+ /**
+ * Returns a Request that only runs contains tests whose {@link Description}
+ * equals <code>desiredDescription</code>
+ * @param desiredDescription {@link Description} of those tests that should be run
+ * @return the filtered Request
+ */
+ public Request filterWith(final Description desiredDescription) {
+ return filterWith(Filter.matchMethodDescription(desiredDescription));
+ }
+
+ /**
+ * Returns a Request whose Tests can be run in a certain order, defined by
+ * <code>comparator</code>
+ *
+ * For example, here is code to run a test suite in alphabetical order:
+ *
+ * <pre>
+ private static Comparator<Description> forward() {
+ return new Comparator<Description>() {
+ public int compare(Description o1, Description o2) {
+ return o1.getDisplayName().compareTo(o2.getDisplayName());
+ }
+ };
+ }
+
+ public static main() {
+ new JUnitCore().run(Request.aClass(AllTests.class).sortWith(forward()));
+ }
+ * </pre>
+ *
+ * @param comparator definition of the order of the tests in this Request
+ * @return a Request with ordered Tests
+ */
+ public Request sortWith(Comparator<Description> comparator) {
+ return new SortingRequest(this, comparator);
+ }
+}
diff --git a/src/org/junit/runner/Result.java b/src/org/junit/runner/Result.java
new file mode 100644
index 0000000..edfb97c
--- /dev/null
+++ b/src/org/junit/runner/Result.java
@@ -0,0 +1,106 @@
+package org.junit.runner;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+/**
+ * A <code>Result</code> collects and summarizes information from running multiple
+ * tests. Since tests are expected to run correctly, successful tests are only noted in
+ * the count of tests that ran.
+ */
+public class Result implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private AtomicInteger fCount = new AtomicInteger();
+ private AtomicInteger fIgnoreCount= new AtomicInteger();
+ private final List<Failure> fFailures= Collections.synchronizedList(new ArrayList<Failure>());
+ private long fRunTime= 0;
+ private long fStartTime;
+
+ /**
+ * @return the number of tests run
+ */
+ public int getRunCount() {
+ return fCount.get();
+ }
+
+ /**
+ * @return the number of tests that failed during the run
+ */
+ public int getFailureCount() {
+ return fFailures.size();
+ }
+
+ /**
+ * @return the number of milliseconds it took to run the entire suite to run
+ */
+ public long getRunTime() {
+ return fRunTime;
+ }
+
+ /**
+ * @return the {@link Failure}s describing tests that failed and the problems they encountered
+ */
+ public List<Failure> getFailures() {
+ return fFailures;
+ }
+
+ /**
+ * @return the number of tests ignored during the run
+ */
+ public int getIgnoreCount() {
+ return fIgnoreCount.get();
+ }
+
+ /**
+ * @return <code>true</code> if all tests succeeded
+ */
+ public boolean wasSuccessful() {
+ return getFailureCount() == 0;
+ }
+
+ private class Listener extends RunListener {
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ fStartTime= System.currentTimeMillis();
+ }
+
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ long endTime= System.currentTimeMillis();
+ fRunTime+= endTime - fStartTime;
+ }
+
+ @Override
+ public void testFinished(Description description) throws Exception {
+ fCount.getAndIncrement();
+ }
+
+ @Override
+ public void testFailure(Failure failure) throws Exception {
+ fFailures.add(failure);
+ }
+
+ @Override
+ public void testIgnored(Description description) throws Exception {
+ fIgnoreCount.getAndIncrement();
+ }
+
+ @Override
+ public void testAssumptionFailure(Failure failure) {
+ // do nothing: same as passing (for 4.5; may change in 4.6)
+ }
+ }
+
+ /**
+ * Internal use only.
+ */
+ public RunListener createListener() {
+ return new Listener();
+ }
+}
diff --git a/src/org/junit/runner/RunWith.java b/src/org/junit/runner/RunWith.java
new file mode 100644
index 0000000..602edf0
--- /dev/null
+++ b/src/org/junit/runner/RunWith.java
@@ -0,0 +1,34 @@
+package org.junit.runner;
+
+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;
+
+/**
+ * When a class is annotated with <code>&#064;RunWith</code> or extends a class annotated
+ * with <code>&#064;RunWith</code>, JUnit will invoke the class it references to run the
+ * tests in that class instead of the runner built into JUnit. We added this feature late
+ * in development. While it seems powerful we expect the runner API to change as we learn
+ * how people really use it. Some of the classes that are currently internal will likely
+ * be refined and become public.
+ *
+ * For example, suites in JUnit 4 are built using RunWith, and a custom runner named Suite:
+ *
+ * <pre>
+ * &#064;RunWith(Suite.class)
+ * &#064;SuiteClasses({ATest.class, BTest.class, CTest.class})
+ * public class ABCSuite {
+ * }
+ * </pre>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Inherited
+public @interface RunWith {
+ /**
+ * @return a Runner class (must have a constructor that takes a single Class to run)
+ */
+ Class<? extends Runner> value();
+}
diff --git a/src/org/junit/runner/Runner.java b/src/org/junit/runner/Runner.java
new file mode 100644
index 0000000..39e424f
--- /dev/null
+++ b/src/org/junit/runner/Runner.java
@@ -0,0 +1,40 @@
+package org.junit.runner;
+
+import org.junit.runner.notification.RunNotifier;
+
+/**
+ * A <code>Runner</code> runs tests and notifies a {@link org.junit.runner.notification.RunNotifier}
+ * of significant events as it does so. You will need to subclass <code>Runner</code>
+ * when using {@link org.junit.runner.RunWith} to invoke a custom runner. When creating
+ * 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
+ * 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.
+ *
+ * @see org.junit.runner.Description
+ * @see org.junit.runner.RunWith
+ */
+public abstract class Runner implements Describable {
+ /* (non-Javadoc)
+ * @see org.junit.runner.Describable#getDescription()
+ */
+ public abstract Description getDescription();
+
+ /**
+ * Run the tests for this runner.
+ * @param notifier will be notified of events while tests are being run--tests being
+ * started, finishing, and failing
+ */
+ public abstract void run(RunNotifier notifier);
+
+ /**
+ * @return the number of tests to be run by the receiver
+ */
+ public int testCount() {
+ return getDescription().testCount();
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/runner/manipulation/Filter.java b/src/org/junit/runner/manipulation/Filter.java
new file mode 100644
index 0000000..c0f31b0
--- /dev/null
+++ b/src/org/junit/runner/manipulation/Filter.java
@@ -0,0 +1,114 @@
+package org.junit.runner.manipulation;
+
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+
+/**
+ * The canonical case of filtering is when you want to run a single test method in a class. Rather
+ * than introduce runner API just for that one case, JUnit provides a general filtering mechanism.
+ * If you want to filter the tests to be run, extend <code>Filter</code> and apply an instance of
+ * your filter to the {@link org.junit.runner.Request} before running it (see
+ * {@link org.junit.runner.JUnitCore#run(Request)}. Alternatively, apply a <code>Filter</code> to
+ * a {@link org.junit.runner.Runner} before running tests (for example, in conjunction with
+ * {@link org.junit.runner.RunWith}.
+ */
+public abstract class Filter {
+ /**
+ * A null <code>Filter</code> that passes all tests through.
+ */
+ public static Filter ALL= new Filter() {
+ @Override
+ public boolean shouldRun(Description description) {
+ return true;
+ }
+
+ @Override
+ public String describe() {
+ return "all tests";
+ }
+
+ @Override
+ public void apply(Object child) throws NoTestsRemainException {
+ // do nothing
+ }
+
+ @Override
+ public Filter intersect(Filter second) {
+ return second;
+ }
+ };
+
+ /**
+ * Returns a {@code Filter} that only runs the single method described by
+ * {@code desiredDescription}
+ */
+ public static Filter matchMethodDescription(final Description desiredDescription) {
+ return new Filter() {
+ @Override
+ public boolean shouldRun(Description description) {
+ if (description.isTest())
+ return desiredDescription.equals(description);
+
+ // explicitly check if any children want to run
+ for (Description each : description.getChildren())
+ if (shouldRun(each))
+ return true;
+ return false;
+ }
+
+ @Override
+ public String describe() {
+ return String.format("Method %s", desiredDescription.getDisplayName());
+ }
+ };
+ }
+
+
+ /**
+ * @param description the description of the test to be run
+ * @return <code>true</code> if the test should be run
+ */
+ public abstract boolean shouldRun(Description description);
+
+ /**
+ * Returns a textual description of this Filter
+ * @return a textual description of this Filter
+ */
+ public abstract String describe();
+
+ /**
+ * Invoke with a {@link org.junit.runner.Runner} to cause all tests it intends to run
+ * to first be checked with the filter. Only those that pass the filter will be run.
+ * @param child the runner to be filtered by the receiver
+ * @throws NoTestsRemainException if the receiver removes all tests
+ */
+ public void apply(Object child) throws NoTestsRemainException {
+ if (!(child instanceof Filterable))
+ return;
+ Filterable filterable= (Filterable) child;
+ filterable.filter(this);
+ }
+
+ /**
+ * Returns a new Filter that accepts the intersection of the tests accepted
+ * by this Filter and {@code second}
+ */
+ public Filter intersect(final Filter second) {
+ if (second == this || second == ALL) {
+ return this;
+ }
+ final Filter first= this;
+ return new Filter() {
+ @Override
+ public boolean shouldRun(Description description) {
+ return first.shouldRun(description)
+ && second.shouldRun(description);
+ }
+
+ @Override
+ public String describe() {
+ return first.describe() + " and " + second.describe();
+ }
+ };
+ }
+}
diff --git a/src/org/junit/runner/manipulation/Filterable.java b/src/org/junit/runner/manipulation/Filterable.java
new file mode 100644
index 0000000..782c0f7
--- /dev/null
+++ b/src/org/junit/runner/manipulation/Filterable.java
@@ -0,0 +1,16 @@
+package org.junit.runner.manipulation;
+
+/**
+ * Runners that allow filtering should implement this interface. Implement {@link #filter(Filter)}
+ * to remove tests that don't pass the filter.
+ */
+public interface Filterable {
+
+ /**
+ * Remove tests that don't pass the parameter <code>filter</code>.
+ * @param filter the {@link Filter} to apply
+ * @throws NoTestsRemainException if all tests are filtered out
+ */
+ void filter(Filter filter) throws NoTestsRemainException;
+
+}
diff --git a/src/org/junit/runner/manipulation/NoTestsRemainException.java b/src/org/junit/runner/manipulation/NoTestsRemainException.java
new file mode 100644
index 0000000..03fb3bf
--- /dev/null
+++ b/src/org/junit/runner/manipulation/NoTestsRemainException.java
@@ -0,0 +1,8 @@
+package org.junit.runner.manipulation;
+
+/**
+ * Thrown when a filter removes all tests from a runner.
+ */
+public class NoTestsRemainException extends Exception {
+ private static final long serialVersionUID = 1L;
+}
diff --git a/src/org/junit/runner/manipulation/Sortable.java b/src/org/junit/runner/manipulation/Sortable.java
new file mode 100644
index 0000000..fec1d0c
--- /dev/null
+++ b/src/org/junit/runner/manipulation/Sortable.java
@@ -0,0 +1,17 @@
+package org.junit.runner.manipulation;
+
+/**
+ * Interface for runners that allow sorting of tests. By sorting tests based on when they last failed, most recently
+ * failed first, you can reduce the average time to the first test failing. Test sorting should not be used to
+ * cope with order dependencies between tests. Tests that are isolated from each other are less
+ * expensive to maintain and can be run individually.
+ */
+public interface Sortable {
+
+ /**
+ * Sorts the tests using <code>sorter</code>
+ * @param sorter the {@link Sorter} to use for sorting the tests
+ */
+ public void sort(Sorter sorter);
+
+}
diff --git a/src/org/junit/runner/manipulation/Sorter.java b/src/org/junit/runner/manipulation/Sorter.java
new file mode 100644
index 0000000..242df14
--- /dev/null
+++ b/src/org/junit/runner/manipulation/Sorter.java
@@ -0,0 +1,46 @@
+package org.junit.runner.manipulation;
+
+import java.util.Comparator;
+
+import org.junit.runner.Description;
+
+/**
+ * A <code>Sorter</code> orders tests. In general you will not need
+ * to use a <code>Sorter</code> directly. Instead, use {@link org.junit.runner.Request#sortWith(Comparator)}.
+ *
+ *
+ */
+public class Sorter implements Comparator<Description> {
+ /**
+ * NULL is a <code>Sorter</code> that leaves elements in an undefined order
+ */
+ public static Sorter NULL= new Sorter(new Comparator<Description>() {
+ public int compare(Description o1, Description o2) {
+ return 0;
+ }});
+ private final Comparator<Description> fComparator;
+
+ /**
+ * Creates a <code>Sorter</code> that uses <code>comparator</code>
+ * to sort tests
+ * @param comparator the {@link Comparator} to use when sorting tests
+ */
+ public Sorter(Comparator<Description> comparator) {
+ fComparator= comparator;
+ }
+
+ /**
+ * Sorts the test in <code>runner</code> using <code>comparator</code>
+ * @param object
+ */
+ public void apply(Object object) {
+ if (object instanceof Sortable) {
+ Sortable sortable = (Sortable) object;
+ sortable.sort(this);
+ }
+ }
+
+ public int compare(Description o1, Description o2) {
+ return fComparator.compare(o1, o2);
+ }
+}
diff --git a/src/org/junit/runner/manipulation/package-info.java b/src/org/junit/runner/manipulation/package-info.java
new file mode 100644
index 0000000..ba5c3b2
--- /dev/null
+++ b/src/org/junit/runner/manipulation/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Provides classes to {@link org.junit.runner.manipulation.Filter filter} or {@link org.junit.runner.manipulation.Sorter sort} tests.
+ *
+ * @since 4.0
+ * @see org.junit.runner.Runner
+ */
+package org.junit.runner.manipulation; \ No newline at end of file
diff --git a/src/org/junit/runner/notification/Failure.java b/src/org/junit/runner/notification/Failure.java
new file mode 100644
index 0000000..501caa5
--- /dev/null
+++ b/src/org/junit/runner/notification/Failure.java
@@ -0,0 +1,79 @@
+package org.junit.runner.notification;
+
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.StringWriter;
+
+import org.junit.runner.Description;
+
+/**
+ * A <code>Failure</code> holds a description of the failed test and the
+ * exception that was thrown while running it. In most cases the {@link org.junit.runner.Description}
+ * will be of a single test. However, if problems are encountered while constructing the
+ * test (for example, if a {@link org.junit.BeforeClass} method is not static), it may describe
+ * something other than a single test.
+ */
+public class Failure implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private final Description fDescription;
+ private final Throwable fThrownException;
+
+ /**
+ * Constructs a <code>Failure</code> with the given description and exception.
+ * @param description a {@link org.junit.runner.Description} of the test that failed
+ * @param thrownException the exception that was thrown while running the test
+ */
+ public Failure(Description description, Throwable thrownException) {
+ fThrownException = thrownException;
+ fDescription= description;
+ }
+
+ /**
+ * @return a user-understandable label for the test
+ */
+ public String getTestHeader() {
+ return fDescription.getDisplayName();
+ }
+
+ /**
+ * @return the raw description of the context of the failure.
+ */
+ public Description getDescription() {
+ return fDescription;
+ }
+
+ /**
+ * @return the exception thrown
+ */
+
+ public Throwable getException() {
+ return fThrownException;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer= new StringBuffer();
+ buffer.append(getTestHeader() + ": "+fThrownException.getMessage());
+ return buffer.toString();
+ }
+
+ /**
+ * Convenience method
+ * @return the printed form of the exception
+ */
+ public String getTrace() {
+ StringWriter stringWriter= new StringWriter();
+ PrintWriter writer= new PrintWriter(stringWriter);
+ getException().printStackTrace(writer);
+ StringBuffer buffer= stringWriter.getBuffer();
+ return buffer.toString();
+ }
+
+ /**
+ * Convenience method
+ * @return the message of the thrown exception
+ */
+ public String getMessage() {
+ return getException().getMessage();
+ }
+}
diff --git a/src/org/junit/runner/notification/RunListener.java b/src/org/junit/runner/notification/RunListener.java
new file mode 100644
index 0000000..ffe8134
--- /dev/null
+++ b/src/org/junit/runner/notification/RunListener.java
@@ -0,0 +1,93 @@
+package org.junit.runner.notification;
+
+import org.junit.internal.AssumptionViolatedException;
+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>
+ * class that you want to make a noise whenever a test fails. You could write:
+ * <pre>
+ * public class RingingListener extends RunListener {
+ * public void testFailure(Failure failure) {
+ * Cowbell.ring();
+ * }
+ * }
+ * </pre>
+ * </p>
+ *
+ * <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();
+ * core.addListener(new RingingListener());
+ * core.run(MyTestClass.class);
+ * }
+ * </pre>
+ * </p>
+ * @see org.junit.runner.JUnitCore
+ */
+public class RunListener {
+
+ /**
+ * Called before any tests have been run.
+ * @param description describes the tests to be run
+ */
+ public void testRunStarted(Description description) throws Exception {
+ }
+
+ /**
+ * Called when all tests have finished
+ * @param result the summary of the test run, including all the tests that failed
+ */
+ public void testRunFinished(Result result) throws Exception {
+ }
+
+ /**
+ * Called when an atomic test is about to be started.
+ * @param description the description of the test that is about to be run
+ * (generally a class and method name)
+ */
+ public void testStarted(Description description) throws Exception {
+ }
+
+ /**
+ * Called when an atomic test has finished, whether the test succeeds or fails.
+ * @param description the description of the test that just ran
+ */
+ public void testFinished(Description description) throws Exception {
+ }
+
+ /**
+ * Called when an atomic test fails.
+ * @param failure describes the test that failed and the exception that was thrown
+ */
+ public void testFailure(Failure failure) throws Exception {
+ }
+
+ /**
+ * Called when an atomic test flags that it assumes a condition that is
+ * false
+ *
+ * @param failure
+ * describes the test that failed and the
+ * {@link AssumptionViolatedException} that was thrown
+ */
+ public void testAssumptionFailure(Failure failure) {
+ }
+
+ /**
+ * Called when a test will not be run, generally because a test method is annotated
+ * with {@link org.junit.Ignore}.
+ *
+ * @param description describes the test that will not be run
+ */
+ public void testIgnored(Description description) throws Exception {
+ }
+}
+
+
diff --git a/src/org/junit/runner/notification/RunNotifier.java b/src/org/junit/runner/notification/RunNotifier.java
new file mode 100644
index 0000000..d0f6c85
--- /dev/null
+++ b/src/org/junit/runner/notification/RunNotifier.java
@@ -0,0 +1,166 @@
+package org.junit.runner.notification;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+
+/**
+ * If you write custom runners, you may need to notify JUnit of your progress running tests.
+ * Do this by invoking the <code>RunNotifier</code> passed to your implementation of
+ * {@link org.junit.runner.Runner#run(RunNotifier)}. Future evolution of this class is likely to
+ * move {@link #fireTestRunStarted(Description)} and {@link #fireTestRunFinished(Result)}
+ * to a separate class since they should only be called once per run.
+ */
+public class RunNotifier {
+ private final List<RunListener> fListeners=
+ Collections.synchronizedList(new ArrayList<RunListener>());
+ private boolean fPleaseStop= false;
+
+ /** Internal use only
+ */
+ public void addListener(RunListener listener) {
+ fListeners.add(listener);
+ }
+
+ /** Internal use only
+ */
+ public void removeListener(RunListener listener) {
+ fListeners.remove(listener);
+ }
+
+ private abstract class SafeNotifier {
+ void run() {
+ synchronized (fListeners) {
+ for (Iterator<RunListener> all= fListeners.iterator(); all.hasNext();)
+ try {
+ notifyListener(all.next());
+ } catch (Exception e) {
+ all.remove(); // Remove the offending listener first to avoid an infinite loop
+ fireTestFailure(new Failure(Description.TEST_MECHANISM, e));
+ }
+ }
+ }
+
+ abstract protected void notifyListener(RunListener each) throws Exception;
+ }
+
+ /**
+ * Do not invoke.
+ */
+ public void fireTestRunStarted(final Description description) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testRunStarted(description);
+ };
+ }.run();
+ }
+
+ /**
+ * Do not invoke.
+ */
+ public void fireTestRunFinished(final Result result) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testRunFinished(result);
+ };
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test is about to start.
+ * @param description the description of the atomic test (generally a class and method name)
+ * @throws StoppedByUserException thrown if a user has requested that the test run stop
+ */
+ public void fireTestStarted(final Description description) throws StoppedByUserException {
+ if (fPleaseStop)
+ throw new StoppedByUserException();
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testStarted(description);
+ };
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test failed.
+ * @param failure the description of the test that failed and the exception thrown
+ */
+ public void fireTestFailure(final Failure failure) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testFailure(failure);
+ };
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test flagged that it assumed
+ * something false.
+ *
+ * @param failure
+ * the description of the test that failed and the
+ * {@link AssumptionViolatedException} thrown
+ */
+ public void fireTestAssumptionFailed(final Failure failure) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testAssumptionFailure(failure);
+ };
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test was ignored.
+ * @param description the description of the ignored test
+ */
+ public void fireTestIgnored(final Description description) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testIgnored(description);
+ }
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test finished. Always invoke
+ * {@link #fireTestFinished(Description)} 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
+ */
+ public void fireTestFinished(final Description description) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testFinished(description);
+ };
+ }.run();
+ }
+
+ /**
+ * Ask that the tests run stop before starting the next test. Phrased politely because
+ * the test currently running will not be interrupted. It seems a little odd to put this
+ * functionality here, but the <code>RunNotifier</code> is the only object guaranteed
+ * to be shared amongst the many runners involved.
+ */
+ public void pleaseStop() {
+ fPleaseStop= true;
+ }
+
+ /**
+ * Internal use only. The Result's listener must be first.
+ */
+ public void addFirstListener(RunListener listener) {
+ fListeners.add(0, listener);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/runner/notification/StoppedByUserException.java b/src/org/junit/runner/notification/StoppedByUserException.java
new file mode 100644
index 0000000..89be3ba
--- /dev/null
+++ b/src/org/junit/runner/notification/StoppedByUserException.java
@@ -0,0 +1,11 @@
+package org.junit.runner.notification;
+
+/**
+ * Thrown when a user has requested that the test run stop. Writers of
+ * test running GUIs should be prepared to catch a <code>StoppedByUserException</code>.
+ *
+ * @see org.junit.runner.notification.RunNotifier
+ */
+public class StoppedByUserException extends RuntimeException {
+ private static final long serialVersionUID= 1L;
+}
diff --git a/src/org/junit/runner/notification/package-info.java b/src/org/junit/runner/notification/package-info.java
new file mode 100644
index 0000000..0331c8f
--- /dev/null
+++ b/src/org/junit/runner/notification/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Provides information about a test run.
+ *
+ * @since 4.0
+ */
+package org.junit.runner.notification; \ No newline at end of file
diff --git a/src/org/junit/runner/package-info.java b/src/org/junit/runner/package-info.java
new file mode 100644
index 0000000..e19fa0b
--- /dev/null
+++ b/src/org/junit/runner/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Provides classes used to describe, collect, run and analyze multiple tests.
+ *
+ * @since 4.0
+ */
+package org.junit.runner; \ No newline at end of file
diff --git a/src/org/junit/runners/AllTests.java b/src/org/junit/runners/AllTests.java
new file mode 100644
index 0000000..50c02db
--- /dev/null
+++ b/src/org/junit/runners/AllTests.java
@@ -0,0 +1,24 @@
+package org.junit.runners;
+
+import org.junit.internal.runners.SuiteMethod;
+
+/** Runner for use with JUnit 3.8.x-style AllTests classes
+ * (those that only implement a static <code>suite()</code>
+ * method). For example:
+ * <pre>
+ * &#064;RunWith(AllTests.class)
+ * public class ProductTests {
+ * public static junit.framework.Test suite() {
+ * ...
+ * }
+ * }
+ * </pre>
+ */
+public class AllTests extends SuiteMethod {
+ /**
+ * Only called reflectively. Do not use programmatically.
+ */
+ public AllTests(Class<?> klass) throws Throwable {
+ super(klass);
+ }
+}
diff --git a/src/org/junit/runners/BlockJUnit4ClassRunner.java b/src/org/junit/runners/BlockJUnit4ClassRunner.java
new file mode 100644
index 0000000..92e0d07
--- /dev/null
+++ b/src/org/junit/runners/BlockJUnit4ClassRunner.java
@@ -0,0 +1,407 @@
+package org.junit.runners;
+
+import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_VALIDATOR;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.Test.None;
+import org.junit.internal.runners.model.ReflectiveCallable;
+import org.junit.internal.runners.statements.ExpectException;
+import org.junit.internal.runners.statements.Fail;
+import org.junit.internal.runners.statements.FailOnTimeout;
+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.RunRules;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.MultipleFailureException;
+import org.junit.runners.model.Statement;
+
+/**
+ * Implements the JUnit 4 standard test case class model, as defined by the
+ * 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}).
+ *
+ * BlockJUnit4ClassRunner has advantages for writers of custom JUnit runners
+ * that are slight changes to the default behavior, however:
+ *
+ * <ul>
+ * <li>It has a much simpler implementation based on {@link Statement}s,
+ * allowing new operations to be inserted into the appropriate point in the
+ * execution flow.
+ *
+ * <li>It is published, and extension and reuse are encouraged, whereas {@code
+ * JUnit4ClassRunner} was in an internal package, and is now deprecated.
+ * </ul>
+ */
+public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
+ /**
+ * Creates a BlockJUnit4ClassRunner to run {@code klass}
+ *
+ * @throws InitializationError
+ * if the test class is malformed.
+ */
+ public BlockJUnit4ClassRunner(Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+
+ //
+ // Implementation of ParentRunner
+ //
+
+ @Override
+ protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
+ Description description= describeChild(method);
+ if (method.getAnnotation(Ignore.class) != null) {
+ notifier.fireTestIgnored(description);
+ } else {
+ runLeaf(methodBlock(method), description, notifier);
+ }
+ }
+
+ @Override
+ protected Description describeChild(FrameworkMethod method) {
+ return Description.createTestDescription(getTestClass().getJavaClass(),
+ testName(method), method.getAnnotations());
+ }
+
+ @Override
+ protected List<FrameworkMethod> getChildren() {
+ return computeTestMethods();
+ }
+
+ //
+ // Override in subclasses
+ //
+
+ /**
+ * Returns the methods that run tests. Default implementation returns all
+ * methods annotated with {@code @Test} on this class and superclasses that
+ * are not overridden.
+ */
+ protected List<FrameworkMethod> computeTestMethods() {
+ return getTestClass().getAnnotatedMethods(Test.class);
+ }
+
+ @Override
+ protected void collectInitializationErrors(List<Throwable> errors) {
+ super.collectInitializationErrors(errors);
+
+ validateNoNonStaticInnerClass(errors);
+ validateConstructor(errors);
+ validateInstanceMethods(errors);
+ validateFields(errors);
+ }
+
+ protected void validateNoNonStaticInnerClass(List<Throwable> errors) {
+ if (getTestClass().isANonStaticInnerClass()) {
+ String gripe= "The inner class " + getTestClass().getName()
+ + " is not static.";
+ errors.add(new Exception(gripe));
+ }
+ }
+
+ /**
+ * Adds to {@code errors} if the test class has more than one constructor,
+ * or if the constructor takes parameters. Override if a subclass requires
+ * different validation rules.
+ */
+ protected void validateConstructor(List<Throwable> errors) {
+ validateOnlyOneConstructor(errors);
+ validateZeroArgConstructor(errors);
+ }
+
+ /**
+ * Adds to {@code errors} if the test class has more than one constructor
+ * (do not override)
+ */
+ protected void validateOnlyOneConstructor(List<Throwable> errors) {
+ if (!hasOneConstructor()) {
+ String gripe= "Test class should have exactly one public constructor";
+ errors.add(new Exception(gripe));
+ }
+ }
+
+ /**
+ * Adds to {@code errors} if the test class's single constructor takes
+ * parameters (do not override)
+ */
+ protected void validateZeroArgConstructor(List<Throwable> errors) {
+ if (!getTestClass().isANonStaticInnerClass()
+ && hasOneConstructor()
+ && (getTestClass().getOnlyConstructor().getParameterTypes().length != 0)) {
+ String gripe= "Test class should have exactly one public zero-argument constructor";
+ errors.add(new Exception(gripe));
+ }
+ }
+
+ private boolean hasOneConstructor() {
+ return getTestClass().getJavaClass().getConstructors().length == 1;
+ }
+
+ /**
+ * 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
+ protected void validateInstanceMethods(List<Throwable> errors) {
+ validatePublicVoidNoArgMethods(After.class, false, errors);
+ validatePublicVoidNoArgMethods(Before.class, false, errors);
+ validateTestMethods(errors);
+
+ if (computeTestMethods().size() == 0)
+ errors.add(new Exception("No runnable methods"));
+ }
+
+ private void validateFields(List<Throwable> errors) {
+ RULE_VALIDATOR.validate(getTestClass(), errors);
+ }
+
+ /**
+ * Adds to {@code errors} for each method annotated with {@code @Test}that
+ * is not a public, void instance method with no arguments.
+ */
+ protected void validateTestMethods(List<Throwable> errors) {
+ validatePublicVoidNoArgMethods(Test.class, false, errors);
+ }
+
+ /**
+ * Returns a new fixture for running a test. Default implementation executes
+ * the test class's no-argument constructor (validation should have ensured
+ * one exists).
+ */
+ protected Object createTest() throws Exception {
+ return getTestClass().getOnlyConstructor().newInstance();
+ }
+
+ /**
+ * Returns the name that describes {@code method} for {@link Description}s.
+ * Default implementation is the method's name
+ */
+ protected String testName(FrameworkMethod method) {
+ return method.getName();
+ }
+
+ /**
+ * Returns a Statement that, when executed, either returns normally if
+ * {@code method} passes, or throws an exception if {@code method} fails.
+ *
+ * Here is an outline of the default implementation:
+ *
+ * <ul>
+ * <li>Invoke {@code method} on the result of {@code createTest()}, 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
+ * exception of the correct type, and throw an exception otherwise.
+ * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code
+ * timeout} attribute, throw an exception if the previous step takes more
+ * than the specified number of milliseconds.
+ * <li>ALWAYS run all non-overridden {@code @Before} methods on this class
+ * and superclasses before any of the previous steps; if any throws an
+ * Exception, stop execution and pass the exception on.
+ * <li>ALWAYS run all non-overridden {@code @After} methods on this class
+ * and superclasses after any of the previous steps; all After methods are
+ * always executed: exceptions thrown by previous steps are combined, if
+ * necessary, with exceptions from After methods into a
+ * {@link MultipleFailureException}.
+ * <li>ALWAYS allow {@code @Rule} fields to modify the execution of the
+ * above steps. A {@code Rule} may prevent all execution of the above steps,
+ * or add additional behavior before and after, or modify thrown exceptions.
+ * For more information, see {@link TestRule}
+ * </ul>
+ *
+ * This can be overridden in subclasses, either by overriding this method,
+ * or the implementations creating each sub-statement.
+ */
+ protected Statement methodBlock(FrameworkMethod method) {
+ Object test;
+ try {
+ test= new ReflectiveCallable() {
+ @Override
+ protected Object runReflectiveCall() throws Throwable {
+ return createTest();
+ }
+ }.run();
+ } catch (Throwable e) {
+ return new Fail(e);
+ }
+
+ Statement statement= methodInvoker(method, test);
+ statement= possiblyExpectingExceptions(method, test, statement);
+ statement= withPotentialTimeout(method, test, statement);
+ statement= withBefores(method, test, statement);
+ statement= withAfters(method, test, statement);
+ statement= withRules(method, test, statement);
+ return statement;
+ }
+
+ //
+ // Statement builders
+ //
+
+ /**
+ * Returns a {@link Statement} that invokes {@code method} on {@code test}
+ */
+ protected Statement methodInvoker(FrameworkMethod method, Object test) {
+ return new InvokeMethod(method, test);
+ }
+
+ /**
+ * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation
+ * 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);
+ return expectsException(annotation) ? new ExpectException(next,
+ getExpectedException(annotation)) : next;
+ }
+
+ /**
+ * 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
+ protected Statement withPotentialTimeout(FrameworkMethod method,
+ Object test, Statement next) {
+ long timeout= getTimeout(method.getAnnotation(Test.class));
+ return timeout > 0 ? new FailOnTimeout(next, timeout) : next;
+ }
+
+ /**
+ * Returns a {@link Statement}: run all non-overridden {@code @Before}
+ * methods on this class and superclasses before running {@code next}; if
+ * any throws an Exception, stop execution and pass the exception on.
+ *
+ * @deprecated Will be private soon: use Rules instead
+ */
+ @Deprecated
+ protected Statement withBefores(FrameworkMethod method, Object target,
+ Statement statement) {
+ List<FrameworkMethod> befores= getTestClass().getAnnotatedMethods(
+ Before.class);
+ return befores.isEmpty() ? statement : new RunBefores(statement,
+ befores, target);
+ }
+
+ /**
+ * Returns a {@link Statement}: run all non-overridden {@code @After}
+ * methods on this class and superclasses before running {@code next}; all
+ * After methods are always executed: exceptions thrown by previous steps
+ * are combined, if necessary, with exceptions from After methods into a
+ * {@link MultipleFailureException}.
+ *
+ * @deprecated Will be private soon: use Rules instead
+ */
+ @Deprecated
+ protected Statement withAfters(FrameworkMethod method, Object target,
+ Statement statement) {
+ List<FrameworkMethod> afters= getTestClass().getAnnotatedMethods(
+ After.class);
+ return afters.isEmpty() ? statement : new RunAfters(statement, afters,
+ target);
+ }
+
+ private Statement withRules(FrameworkMethod method, Object target,
+ Statement statement) {
+ Statement result= statement;
+ result= withMethodRules(method, target, result);
+ result= withTestRules(method, target, result);
+ return result;
+ }
+
+ @SuppressWarnings("deprecation")
+ private Statement withMethodRules(FrameworkMethod method, Object target,
+ Statement result) {
+ List<TestRule> testRules= getTestRules(target);
+ for (org.junit.rules.MethodRule each : getMethodRules(target))
+ if (! testRules.contains(each))
+ result= each.apply(result, method, target);
+ return result;
+ }
+
+ @SuppressWarnings("deprecation")
+ private List<org.junit.rules.MethodRule> getMethodRules(Object target) {
+ return rules(target);
+ }
+
+ /**
+ * @param target
+ * the test case instance
+ * @return a list of MethodRules that should be applied when executing this
+ * test
+ * @deprecated {@link org.junit.rules.MethodRule} is a deprecated interface. Port to
+ * {@link TestRule} and
+ * {@link BlockJUnit4ClassRunner#getTestRules(Object)}
+ */
+ @Deprecated
+ protected List<org.junit.rules.MethodRule> rules(Object target) {
+ return getTestClass().getAnnotatedFieldValues(target, Rule.class,
+ org.junit.rules.MethodRule.class);
+ }
+
+ /**
+ * Returns a {@link Statement}: apply all non-static {@link Value} fields
+ * annotated with {@link Rule}.
+ *
+ * @param statement The base statement
+ * @return a RunRules statement if any class-level {@link Rule}s are
+ * found, or the base statement
+ */
+ private Statement withTestRules(FrameworkMethod method, Object target,
+ Statement statement) {
+ List<TestRule> testRules= getTestRules(target);
+ return testRules.isEmpty() ? statement :
+ new RunRules(statement, testRules, describeChild(method));
+ }
+
+ /**
+ * @param target
+ * the test case instance
+ * @return a list of TestRules that should be applied when executing this
+ * test
+ */
+ protected List<TestRule> getTestRules(Object target) {
+ return getTestClass().getAnnotatedFieldValues(target,
+ Rule.class, TestRule.class);
+ }
+
+ private Class<? extends Throwable> getExpectedException(Test annotation) {
+ if (annotation == null || annotation.expected() == None.class)
+ return null;
+ else
+ return annotation.expected();
+ }
+
+ private boolean expectsException(Test annotation) {
+ return getExpectedException(annotation) != null;
+ }
+
+ private long getTimeout(Test annotation) {
+ if (annotation == null)
+ return 0;
+ return annotation.timeout();
+ }
+}
diff --git a/src/org/junit/runners/JUnit4.java b/src/org/junit/runners/JUnit4.java
new file mode 100644
index 0000000..1e1f347
--- /dev/null
+++ b/src/org/junit/runners/JUnit4.java
@@ -0,0 +1,22 @@
+package org.junit.runners;
+
+import org.junit.runners.model.InitializationError;
+
+/**
+ * Aliases the current default JUnit 4 class runner, for future-proofing. If
+ * future versions of JUnit change the default Runner class, they will also
+ * change the definition of this class. Developers wanting to explicitly tag a
+ * class as a JUnit 4 class should use {@code @RunWith(JUnit4.class)}, not,
+ * for example in JUnit 4.5, {@code @RunWith(BlockJUnit4ClassRunner.class)}.
+ * This is the only way this class should be used--any extension that
+ * depends on the implementation details of this class is likely to break
+ * in future versions.
+ */
+public final class JUnit4 extends BlockJUnit4ClassRunner {
+ /**
+ * Constructs a new instance of the default runner
+ */
+ public JUnit4(Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+}
diff --git a/src/org/junit/runners/Parameterized.java b/src/org/junit/runners/Parameterized.java
new file mode 100644
index 0000000..3ebfead
--- /dev/null
+++ b/src/org/junit/runners/Parameterized.java
@@ -0,0 +1,167 @@
+package org.junit.runners;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+/**
+ * <p>
+ * 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:
+ *
+ * <pre>
+ * &#064;RunWith(Parameterized.class)
+ * public class FibonacciTest {
+ * &#064;Parameters
+ * public static List&lt;Object[]&gt; data() {
+ * return Arrays.asList(new Object[][] {
+ * { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
+ * });
+ * }
+ *
+ * private int fInput;
+ *
+ * private int fExpected;
+ *
+ * public FibonacciTest(int input, int expected) {
+ * fInput= input;
+ * fExpected= expected;
+ * }
+ *
+ * &#064;Test
+ * public void test() {
+ * assertEquals(fExpected, Fibonacci.compute(fInput));
+ * }
+ * }
+ * </pre>
+ *
+ * <p>
+ * Each instance of <code>FibonacciTest</code> will be constructed using the
+ * two-argument constructor and the data values in the
+ * <code>&#064;Parameters</code> method.
+ * </p>
+ */
+public class Parameterized extends Suite {
+ /**
+ * Annotation for a method which provides parameters to be injected into the
+ * test class constructor by <code>Parameterized</code>
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public static @interface Parameters {
+ }
+
+ private class TestClassRunnerForParameters extends
+ BlockJUnit4ClassRunner {
+ private final int fParameterSetNumber;
+
+ private final List<Object[]> fParameterList;
+
+ TestClassRunnerForParameters(Class<?> type,
+ List<Object[]> parameterList, int i) throws InitializationError {
+ super(type);
+ fParameterList= parameterList;
+ fParameterSetNumber= i;
+ }
+
+ @Override
+ public Object createTest() throws Exception {
+ return getTestClass().getOnlyConstructor().newInstance(
+ computeParams());
+ }
+
+ private Object[] computeParams() throws Exception {
+ try {
+ return fParameterList.get(fParameterSetNumber);
+ } catch (ClassCastException e) {
+ throw new Exception(String.format(
+ "%s.%s() must return a Collection of arrays.",
+ getTestClass().getName(), getParametersMethod(
+ getTestClass()).getName()));
+ }
+ }
+
+ @Override
+ protected String getName() {
+ return String.format("[%s]", fParameterSetNumber);
+ }
+
+ @Override
+ protected String testName(final FrameworkMethod method) {
+ return String.format("%s[%s]", method.getName(),
+ fParameterSetNumber);
+ }
+
+ @Override
+ protected void validateConstructor(List<Throwable> errors) {
+ validateOnlyOneConstructor(errors);
+ }
+
+ @Override
+ protected Statement classBlock(RunNotifier notifier) {
+ return childrenInvoker(notifier);
+ }
+
+ @Override
+ protected Annotation[] getRunnerAnnotations() {
+ return new Annotation[0];
+ }
+ }
+
+ private final ArrayList<Runner> runners= new ArrayList<Runner>();
+
+ /**
+ * Only called reflectively. Do not use programmatically.
+ */
+ public Parameterized(Class<?> klass) throws Throwable {
+ super(klass, Collections.<Runner>emptyList());
+ List<Object[]> parametersList= getParametersList(getTestClass());
+ for (int i= 0; i < parametersList.size(); i++)
+ runners.add(new TestClassRunnerForParameters(getTestClass().getJavaClass(),
+ parametersList, i));
+ }
+
+ @Override
+ protected List<Runner> getChildren() {
+ return runners;
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<Object[]> getParametersList(TestClass klass)
+ throws Throwable {
+ return (List<Object[]>) getParametersMethod(klass).invokeExplosively(
+ null);
+ }
+
+ private FrameworkMethod getParametersMethod(TestClass testClass)
+ throws Exception {
+ List<FrameworkMethod> methods= testClass
+ .getAnnotatedMethods(Parameters.class);
+ for (FrameworkMethod each : methods) {
+ int modifiers= each.getMethod().getModifiers();
+ if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
+ return each;
+ }
+
+ throw new Exception("No public static parameters method on class "
+ + testClass.getName());
+ }
+
+}
diff --git a/src/org/junit/runners/ParentRunner.java b/src/org/junit/runners/ParentRunner.java
new file mode 100644
index 0000000..a41aad3
--- /dev/null
+++ b/src/org/junit/runners/ParentRunner.java
@@ -0,0 +1,378 @@
+package org.junit.runners;
+
+import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_VALIDATOR;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.internal.runners.model.EachTestNotifier;
+import org.junit.internal.runners.statements.RunAfters;
+import org.junit.internal.runners.statements.RunBefores;
+import org.junit.rules.RunRules;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.Filterable;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runner.manipulation.Sortable;
+import org.junit.runner.manipulation.Sorter;
+import org.junit.runner.notification.RunNotifier;
+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;
+
+/**
+ * Provides most of the functionality specific to a Runner that implements a
+ * "parent node" in the test tree, with children defined by objects of some data
+ * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is
+ * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses
+ * must implement finding the children of the node, describing each child, and
+ * running each child. ParentRunner will filter and sort children, handle
+ * {@code @BeforeClass} and {@code @AfterClass} methods,
+ * handle annotated {@link ClassRule}s, create a composite
+ * {@link Description}, and run children sequentially.
+ */
+public abstract class ParentRunner<T> extends Runner implements Filterable,
+ Sortable {
+ private final TestClass fTestClass;
+
+ private Sorter fSorter= Sorter.NULL;
+
+ private List<T> fFilteredChildren= null;
+
+ private RunnerScheduler fScheduler= new RunnerScheduler() {
+ public void schedule(Runnable childStatement) {
+ childStatement.run();
+ }
+
+ public void finished() {
+ // do nothing
+ }
+ };
+
+ /**
+ * Constructs a new {@code ParentRunner} that will run {@code @TestClass}
+ * @throws InitializationError
+ */
+ protected ParentRunner(Class<?> testClass) throws InitializationError {
+ fTestClass= new TestClass(testClass);
+ validate();
+ }
+
+ //
+ // Must be overridden
+ //
+
+ /**
+ * Returns a list of objects that define the children of this Runner.
+ */
+ protected abstract List<T> getChildren();
+
+ /**
+ * Returns a {@link Description} for {@code child}, which can be assumed to
+ * be an element of the list returned by {@link ParentRunner#getChildren()}
+ */
+ protected abstract Description describeChild(T child);
+
+ /**
+ * Runs the test corresponding to {@code child}, which can be assumed to be
+ * an element of the list returned by {@link ParentRunner#getChildren()}.
+ * Subclasses are responsible for making sure that relevant test events are
+ * reported through {@code notifier}
+ */
+ protected abstract void runChild(T child, RunNotifier notifier);
+
+ //
+ // May be overridden
+ //
+
+ /**
+ * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}).
+ * Default implementation adds an error for each method annotated with
+ * {@code @BeforeClass} or {@code @AfterClass} that is not
+ * {@code public static void} with no arguments.
+ */
+ protected void collectInitializationErrors(List<Throwable> errors) {
+ validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
+ validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
+ validateClassRules(errors);
+ }
+
+ /**
+ * Adds to {@code errors} if any method in this class is annotated with
+ * {@code annotation}, but:
+ * <ul>
+ * <li>is not public, or
+ * <li>takes parameters, or
+ * <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}).
+ */
+ protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation,
+ boolean isStatic, List<Throwable> errors) {
+ List<FrameworkMethod> methods= getTestClass().getAnnotatedMethods(annotation);
+
+ for (FrameworkMethod eachTestMethod : methods)
+ eachTestMethod.validatePublicVoidNoArg(isStatic, errors);
+ }
+
+ private void validateClassRules(List<Throwable> errors) {
+ CLASS_RULE_VALIDATOR.validate(getTestClass(), errors);
+ }
+
+ /**
+ * Constructs a {@code Statement} to run all of the tests in the test class. Override to add pre-/post-processing.
+ * Here is an outline of the implementation:
+ * <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
+ * necessary, with exceptions from AfterClass methods into a
+ * {@link MultipleFailureException}.
+ * </ul>
+ * @param notifier
+ * @return {@code Statement}
+ */
+ protected Statement classBlock(final RunNotifier notifier) {
+ Statement statement= childrenInvoker(notifier);
+ statement= withBeforeClasses(statement);
+ statement= withAfterClasses(statement);
+ statement= withClassRules(statement);
+ return statement;
+ }
+
+ /**
+ * 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
+ .getAnnotatedMethods(BeforeClass.class);
+ return befores.isEmpty() ? statement :
+ new RunBefores(statement, befores, null);
+ }
+
+ /**
+ * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class
+ * 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}.
+ */
+ protected Statement withAfterClasses(Statement statement) {
+ List<FrameworkMethod> afters= fTestClass
+ .getAnnotatedMethods(AfterClass.class);
+ return afters.isEmpty() ? statement :
+ new RunAfters(statement, afters, null);
+ }
+
+ /**
+ * Returns a {@link Statement}: apply all
+ * static fields assignable to {@link TestRule}
+ * annotated with {@link ClassRule}.
+ *
+ * @param statement
+ * the base statement
+ * @return a RunRules statement if any class-level {@link Rule}s are
+ * found, or the base statement
+ */
+ private Statement withClassRules(Statement statement) {
+ List<TestRule> classRules= classRules();
+ return classRules.isEmpty() ? statement :
+ new RunRules(statement, classRules, getDescription());
+ }
+
+ /**
+ * @return the {@code ClassRule}s that can transform the block that runs
+ * each method in the tested class.
+ */
+ protected List<TestRule> classRules() {
+ return fTestClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class);
+ }
+
+ /**
+ * Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)}
+ * on each object returned by {@link #getChildren()} (subject to any imposed
+ * filter and sort)
+ */
+ protected Statement childrenInvoker(final RunNotifier notifier) {
+ return new Statement() {
+ @Override
+ public void evaluate() {
+ runChildren(notifier);
+ }
+ };
+ }
+
+ private void runChildren(final RunNotifier notifier) {
+ for (final T each : getFilteredChildren())
+ fScheduler.schedule(new Runnable() {
+ public void run() {
+ ParentRunner.this.runChild(each, notifier);
+ }
+ });
+ fScheduler.finished();
+ }
+
+ /**
+ * Returns a name used to describe this Runner
+ */
+ protected String getName() {
+ return fTestClass.getName();
+ }
+
+ //
+ // Available for subclasses
+ //
+
+ /**
+ * Returns a {@link TestClass} object wrapping the class to be executed.
+ */
+ public final TestClass getTestClass() {
+ return fTestClass;
+ }
+
+ /**
+ * Runs a {@link Statement} that represents a leaf (aka atomic) test.
+ */
+ protected final void runLeaf(Statement statement, Description description,
+ RunNotifier notifier) {
+ EachTestNotifier eachNotifier= new EachTestNotifier(notifier, description);
+ eachNotifier.fireTestStarted();
+ try {
+ statement.evaluate();
+ } catch (AssumptionViolatedException e) {
+ eachNotifier.addFailedAssumption(e);
+ } catch (Throwable e) {
+ eachNotifier.addFailure(e);
+ } finally {
+ eachNotifier.fireTestFinished();
+ }
+ }
+
+ /**
+ * @return the annotations that should be attached to this runner's
+ * description.
+ */
+ protected Annotation[] getRunnerAnnotations() {
+ return fTestClass.getAnnotations();
+ }
+
+ //
+ // Implementation of Runner
+ //
+
+ @Override
+ public Description getDescription() {
+ Description description= Description.createSuiteDescription(getName(),
+ getRunnerAnnotations());
+ for (T child : getFilteredChildren())
+ description.addChild(describeChild(child));
+ return description;
+ }
+
+ @Override
+ public void run(final RunNotifier notifier) {
+ EachTestNotifier testNotifier= new EachTestNotifier(notifier,
+ getDescription());
+ try {
+ Statement statement= classBlock(notifier);
+ statement.evaluate();
+ } catch (AssumptionViolatedException e) {
+ testNotifier.fireTestIgnored();
+ } catch (StoppedByUserException e) {
+ throw e;
+ } catch (Throwable e) {
+ testNotifier.addFailure(e);
+ }
+ }
+
+ //
+ // Implementation of Filterable and Sortable
+ //
+
+ 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) {
+ iter.remove();
+ }
+ else
+ iter.remove();
+ }
+ if (getFilteredChildren().isEmpty()) {
+ throw new NoTestsRemainException();
+ }
+ }
+
+ public void sort(Sorter sorter) {
+ fSorter= sorter;
+ for (T each : getFilteredChildren())
+ sortChild(each);
+ Collections.sort(getFilteredChildren(), comparator());
+ }
+
+ //
+ // Private implementation
+ //
+
+ private void validate() throws InitializationError {
+ List<Throwable> errors= new ArrayList<Throwable>();
+ collectInitializationErrors(errors);
+ if (!errors.isEmpty())
+ throw new InitializationError(errors);
+ }
+
+ private List<T> getFilteredChildren() {
+ if (fFilteredChildren == null)
+ fFilteredChildren = new ArrayList<T>(getChildren());
+ return fFilteredChildren;
+ }
+
+ private void sortChild(T child) {
+ fSorter.apply(child);
+ }
+
+ private boolean shouldRun(Filter filter, T each) {
+ return filter.shouldRun(describeChild(each));
+ }
+
+ private Comparator<? super T> comparator() {
+ return new Comparator<T>() {
+ public int compare(T o1, T o2) {
+ return fSorter.compare(describeChild(o1), describeChild(o2));
+ }
+ };
+ }
+
+ /**
+ * Sets a scheduler that determines the order and parallelization
+ * of children. Highly experimental feature that may change.
+ */
+ public void setScheduler(RunnerScheduler scheduler) {
+ this.fScheduler = scheduler;
+ }
+}
diff --git a/src/org/junit/runners/Suite.java b/src/org/junit/runners/Suite.java
new file mode 100644
index 0000000..1b3bb48
--- /dev/null
+++ b/src/org/junit/runners/Suite.java
@@ -0,0 +1,130 @@
+package org.junit.runners;
+
+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.util.List;
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Using <code>Suite</code> as a runner allows you to manually
+ * build a suite containing tests from many classes. It is the JUnit 4 equivalent of the JUnit 3.8.x
+ * static {@link junit.framework.Test} <code>suite()</code> method. To use it, annotate a class
+ * with <code>@RunWith(Suite.class)</code> and <code>@SuiteClasses({TestClass1.class, ...})</code>.
+ * When you run this class, it will run all the tests in all the suite classes.
+ */
+public class Suite extends ParentRunner<Runner> {
+ /**
+ * Returns an empty suite.
+ */
+ public static Runner emptySuite() {
+ try {
+ return new Suite((Class<?>)null, new Class<?>[0]);
+ } catch (InitializationError e) {
+ throw new RuntimeException("This shouldn't be possible");
+ }
+ }
+
+ /**
+ * The <code>SuiteClasses</code> annotation specifies the classes to be run when a class
+ * annotated with <code>@RunWith(Suite.class)</code> is run.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ @Inherited
+ public @interface SuiteClasses {
+ /**
+ * @return the classes to be run
+ */
+ public Class<?>[] value();
+ }
+
+ private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError {
+ SuiteClasses annotation= klass.getAnnotation(SuiteClasses.class);
+ if (annotation == null)
+ throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", klass.getName()));
+ return annotation.value();
+ }
+
+ private final List<Runner> fRunners;
+
+ /**
+ * Called reflectively on classes annotated with <code>@RunWith(Suite.class)</code>
+ *
+ * @param klass the root class
+ * @param builder builds runners for classes in the suite
+ * @throws InitializationError
+ */
+ public Suite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
+ this(builder, klass, getAnnotatedClasses(klass));
+ }
+
+ /**
+ * Call this when there is no single root class (for example, multiple class names
+ * passed on the command line to {@link org.junit.runner.JUnitCore}
+ *
+ * @param builder builds runners for classes in the suite
+ * @param classes the classes in the suite
+ * @throws InitializationError
+ */
+ public Suite(RunnerBuilder builder, Class<?>[] classes) throws InitializationError {
+ this(null, builder.runners(null, classes));
+ }
+
+ /**
+ * Call this when the default builder is good enough. Left in for compatibility with JUnit 4.4.
+ * @param klass the root of the suite
+ * @param suiteClasses the classes in the suite
+ * @throws InitializationError
+ */
+ protected Suite(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
+ this(new AllDefaultPossibilitiesBuilder(true), klass, suiteClasses);
+ }
+
+ /**
+ * Called by this class and subclasses once the classes making up the suite have been determined
+ *
+ * @param builder builds runners for classes in the suite
+ * @param klass the root of the suite
+ * @param suiteClasses the classes in the suite
+ * @throws InitializationError
+ */
+ protected Suite(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
+ this(klass, builder.runners(klass, suiteClasses));
+ }
+
+ /**
+ * Called by this class and subclasses once the runners making up the suite have been determined
+ *
+ * @param klass root of the suite
+ * @param runners for each class in the suite, a {@link Runner}
+ * @throws InitializationError
+ */
+ protected Suite(Class<?> klass, List<Runner> runners) throws InitializationError {
+ super(klass);
+ fRunners = runners;
+ }
+
+ @Override
+ protected List<Runner> getChildren() {
+ return fRunners;
+ }
+
+ @Override
+ protected Description describeChild(Runner child) {
+ return child.getDescription();
+ }
+
+ @Override
+ protected void runChild(Runner runner, final RunNotifier notifier) {
+ runner.run(notifier);
+ }
+}
diff --git a/src/org/junit/runners/model/FrameworkField.java b/src/org/junit/runners/model/FrameworkField.java
new file mode 100644
index 0000000..4a4d4a4
--- /dev/null
+++ b/src/org/junit/runners/model/FrameworkField.java
@@ -0,0 +1,65 @@
+package org.junit.runners.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * Represents a field on a test class (currently used only for Rules in
+ * {@link BlockJUnit4ClassRunner}, but custom runners can make other uses)
+ */
+public class FrameworkField extends FrameworkMember<FrameworkField> {
+ private final Field fField;
+
+ FrameworkField(Field field) {
+ fField= field;
+ }
+
+ public String getName() {
+ return getField().getName();
+ }
+
+ @Override
+ public Annotation[] getAnnotations() {
+ return fField.getAnnotations();
+ }
+
+ public boolean isPublic() {
+ int modifiers= fField.getModifiers();
+ return Modifier.isPublic(modifiers);
+ }
+
+ @Override
+ public boolean isShadowedBy(FrameworkField otherMember) {
+ return otherMember.getName().equals(getName());
+ }
+
+ public boolean isStatic() {
+ int modifiers= fField.getModifiers();
+ return Modifier.isStatic(modifiers);
+ }
+
+ /**
+ * @return the underlying java Field
+ */
+ public Field getField() {
+ return fField;
+ }
+
+ /**
+ * @return the underlying Java Field type
+ * @see java.lang.reflect.Field#getType()
+ */
+ public Class<?> getType() {
+ return fField.getType();
+ }
+
+ /**
+ * Attempts to retrieve the value of this field on {@code target}
+ */
+ public Object get(Object target) throws IllegalArgumentException, IllegalAccessException {
+ return fField.get(target);
+ }
+}
diff --git a/src/org/junit/runners/model/FrameworkMember.java b/src/org/junit/runners/model/FrameworkMember.java
new file mode 100644
index 0000000..9cccd4b
--- /dev/null
+++ b/src/org/junit/runners/model/FrameworkMember.java
@@ -0,0 +1,20 @@
+package org.junit.runners.model;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+abstract class FrameworkMember<T extends FrameworkMember<T>> {
+ /**
+ * Returns the annotations on this method
+ */
+ abstract Annotation[] getAnnotations();
+
+ abstract boolean isShadowedBy(T otherMember);
+
+ boolean isShadowedBy(List<T> members) {
+ for (T each : members)
+ if (isShadowedBy(each))
+ return true;
+ return false;
+ }
+}
diff --git a/src/org/junit/runners/model/FrameworkMethod.java b/src/org/junit/runners/model/FrameworkMethod.java
new file mode 100644
index 0000000..81c8963
--- /dev/null
+++ b/src/org/junit/runners/model/FrameworkMethod.java
@@ -0,0 +1,156 @@
+package org.junit.runners.model;
+
+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;
+
+import org.junit.internal.runners.model.ReflectiveCallable;
+
+/**
+ * Represents a method on a test class to be invoked at the appropriate point in
+ * test execution. These methods are usually marked with an annotation (such as
+ * {@code @Test}, {@code @Before}, {@code @After}, {@code @BeforeClass},
+ * {@code @AfterClass}, etc.)
+ */
+public class FrameworkMethod extends FrameworkMember<FrameworkMethod> {
+ final Method fMethod;
+
+ /**
+ * Returns a new {@code FrameworkMethod} for {@code method}
+ */
+ public FrameworkMethod(Method method) {
+ fMethod= method;
+ }
+
+ /**
+ * Returns the underlying Java method
+ */
+ public Method getMethod() {
+ return fMethod;
+ }
+
+ /**
+ * Returns the result of invoking this method on {@code target} with
+ * parameters {@code params}. {@link InvocationTargetException}s thrown are
+ * unwrapped, and their causes rethrown.
+ */
+ public Object invokeExplosively(final Object target, final Object... params)
+ throws Throwable {
+ return new ReflectiveCallable() {
+ @Override
+ protected Object runReflectiveCall() throws Throwable {
+ return fMethod.invoke(target, params);
+ }
+ }.run();
+ }
+
+ /**
+ * Returns the method's name
+ */
+ public String getName() {
+ return fMethod.getName();
+ }
+
+ /**
+ * Adds to {@code errors} if this method:
+ * <ul>
+ * <li>is not public, or
+ * <li>takes parameters, or
+ * <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}).
+ */
+ 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"));
+ }
+
+
+ /**
+ * Adds to {@code errors} if this method:
+ * <ul>
+ * <li>is not public, or
+ * <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}).
+ */
+ public void validatePublicVoid(boolean isStatic, List<Throwable> errors) {
+ if (Modifier.isStatic(fMethod.getModifiers()) != isStatic) {
+ String state= isStatic ? "should" : "should not";
+ errors.add(new Exception("Method " + fMethod.getName() + "() " + state + " be static"));
+ }
+ if (!Modifier.isPublic(fMethod.getDeclaringClass().getModifiers()))
+ errors.add(new Exception("Class " + fMethod.getDeclaringClass().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"));
+ }
+
+ public void validateNoTypeParametersOnArgs(List<Throwable> errors) {
+ new NoGenericTypeParametersValidator(fMethod).validate(errors);
+ }
+
+ @Override
+ public boolean isShadowedBy(FrameworkMethod other) {
+ if (!other.getName().equals(getName()))
+ return false;
+ if (other.getParameterTypes().length != getParameterTypes().length)
+ return false;
+ for (int i= 0; i < other.getParameterTypes().length; i++)
+ if (!other.getParameterTypes()[i].equals(getParameterTypes()[i]))
+ return false;
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!FrameworkMethod.class.isInstance(obj))
+ return false;
+ return ((FrameworkMethod) obj).fMethod.equals(fMethod);
+ }
+
+ @Override
+ public int hashCode() {
+ return fMethod.hashCode();
+ }
+
+ /**
+ * Returns true iff this is a no-arg method that returns a value assignable
+ * to {@code type}
+ *
+ * @deprecated This is used only by the Theories runner, and does not
+ * use all the generic type info that it ought to. It will be replaced
+ * with a forthcoming ParameterSignature#canAcceptResultOf(FrameworkMethod)
+ * once Theories moves to junit-contrib.
+ */
+ @Deprecated
+ public boolean producesType(Type type) {
+ return getParameterTypes().length == 0 && type instanceof Class<?>
+ && ((Class<?>) type).isAssignableFrom(fMethod.getReturnType());
+ }
+
+ private Class<?>[] getParameterTypes() {
+ return fMethod.getParameterTypes();
+ }
+
+ /**
+ * Returns the annotations on this method
+ */
+ @Override
+ public Annotation[] getAnnotations() {
+ return fMethod.getAnnotations();
+ }
+
+ /**
+ * Returns the annotation of type {@code annotationType} on this method, if
+ * one exists.
+ */
+ public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+ return fMethod.getAnnotation(annotationType);
+ }
+}
diff --git a/src/org/junit/runners/model/InitializationError.java b/src/org/junit/runners/model/InitializationError.java
new file mode 100644
index 0000000..4de9ea7
--- /dev/null
+++ b/src/org/junit/runners/model/InitializationError.java
@@ -0,0 +1,39 @@
+package org.junit.runners.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents one or more problems encountered while initializing a Runner
+ */
+public class InitializationError extends Exception {
+ private static final long serialVersionUID= 1L;
+ private final List<Throwable> fErrors;
+
+ /**
+ * Construct a new {@code InitializationError} with one or more
+ * errors {@code errors} as causes
+ */
+ public InitializationError(List<Throwable> errors) {
+ fErrors= errors;
+ }
+
+ public InitializationError(Throwable error) {
+ this(Arrays.asList(error));
+ }
+
+ /**
+ * Construct a new {@code InitializationError} with one cause
+ * with message {@code string}
+ */
+ public InitializationError(String string) {
+ this(new Exception(string));
+ }
+
+ /**
+ * Returns one or more Throwables that led to this initialization error.
+ */
+ public List<Throwable> getCauses() {
+ return fErrors;
+ }
+}
diff --git a/src/org/junit/runners/model/MultipleFailureException.java b/src/org/junit/runners/model/MultipleFailureException.java
new file mode 100644
index 0000000..6d70ca0
--- /dev/null
+++ b/src/org/junit/runners/model/MultipleFailureException.java
@@ -0,0 +1,60 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package org.junit.runners.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Collects multiple {@code Throwable}s into one exception.
+ */
+public class MultipleFailureException extends Exception {
+ private static final long serialVersionUID= 1L;
+
+ private final List<Throwable> fErrors;
+
+ public MultipleFailureException(List<Throwable> errors) {
+ fErrors= new ArrayList<Throwable>(errors);
+ }
+
+ public List<Throwable> getFailures() {
+ return Collections.unmodifiableList(fErrors);
+ }
+
+ @Override
+ public String getMessage() {
+ StringBuilder sb = new StringBuilder(
+ String.format("There were %d errors:", fErrors.size()));
+ for (Throwable e : fErrors) {
+ sb.append(String.format("\n %s(%s)", e.getClass().getName(), e.getMessage()));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Asserts that a list of throwables is empty. If it isn't empty,
+ * will throw {@link MultipleFailureException} (if there are
+ * multiple throwables in the list) or the first element in the list
+ * (if there is only one element).
+ *
+ * @param errors list to check
+ * @throws Throwable if the list is not empty
+ */
+ @SuppressWarnings("deprecation")
+ public static void assertEmpty(List<Throwable> errors) throws Throwable {
+ if (errors.isEmpty())
+ return;
+ if (errors.size() == 1)
+ throw errors.get(0);
+
+ /*
+ * Many places in the code are documented to throw
+ * org.junit.internal.runners.model.MultipleFailureException.
+ * That class now extends this one, so we throw the internal
+ * exception in case developers have tests that catch
+ * MultipleFailureException.
+ */
+ throw new org.junit.internal.runners.model.MultipleFailureException(errors);
+ }
+}
diff --git a/src/org/junit/runners/model/NoGenericTypeParametersValidator.java b/src/org/junit/runners/model/NoGenericTypeParametersValidator.java
new file mode 100644
index 0000000..77662b8
--- /dev/null
+++ b/src/org/junit/runners/model/NoGenericTypeParametersValidator.java
@@ -0,0 +1,53 @@
+package org.junit.runners.model;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+
+class NoGenericTypeParametersValidator {
+ private final Method fMethod;
+
+ NoGenericTypeParametersValidator(Method method) {
+ this.fMethod = method;
+ }
+
+ void validate(List<Throwable> errors) {
+ for (Type each : fMethod.getGenericParameterTypes())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnType(Type type, List<Throwable> errors) {
+ if (type instanceof TypeVariable<?>) {
+ errors.add(new Exception("Method " + fMethod.getName()
+ + "() contains unresolved type variable " + type));
+ } else if (type instanceof ParameterizedType)
+ validateNoTypeParameterOnParameterizedType((ParameterizedType) type, errors);
+ else if (type instanceof WildcardType)
+ validateNoTypeParameterOnWildcardType((WildcardType) type, errors);
+ else if (type instanceof GenericArrayType)
+ validateNoTypeParameterOnGenericArrayType((GenericArrayType) type, errors);
+ }
+
+ private void validateNoTypeParameterOnParameterizedType(ParameterizedType parameterized,
+ List<Throwable> errors) {
+ for (Type each : parameterized.getActualTypeArguments())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnWildcardType(WildcardType wildcard,
+ List<Throwable> errors) {
+ for (Type each : wildcard.getUpperBounds())
+ validateNoTypeParameterOnType(each, errors);
+ for (Type each : wildcard.getLowerBounds())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnGenericArrayType(
+ GenericArrayType arrayType, List<Throwable> errors) {
+ validateNoTypeParameterOnType(arrayType.getGenericComponentType(), errors);
+ }
+} \ No newline at end of file
diff --git a/src/org/junit/runners/model/RunnerBuilder.java b/src/org/junit/runners/model/RunnerBuilder.java
new file mode 100644
index 0000000..3a334be
--- /dev/null
+++ b/src/org/junit/runners/model/RunnerBuilder.java
@@ -0,0 +1,104 @@
+package org.junit.runners.model;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.internal.runners.ErrorReportingRunner;
+import org.junit.runner.Runner;
+
+/**
+ * A RunnerBuilder is a strategy for constructing runners for classes.
+ *
+ * Only writers of custom runners should use <code>RunnerBuilder</code>s. A custom runner class with a constructor taking
+ * a <code>RunnerBuilder</code> parameter will be passed the instance of <code>RunnerBuilder</code> used to build that runner itself.
+ * For example,
+ * imagine a custom runner that builds suites based on a list of classes in a text file:
+ *
+ * <pre>
+ * \@RunWith(TextFileSuite.class)
+ * \@SuiteSpecFile("mysuite.txt")
+ * class MySuite {}
+ * </pre>
+ *
+ * The implementation of TextFileSuite might include:
+ *
+ * <pre>
+ * public TextFileSuite(Class testClass, RunnerBuilder builder) {
+ * // ...
+ * for (String className : readClassNames())
+ * addRunner(builder.runnerForClass(Class.forName(className)));
+ * // ...
+ * }
+ * </pre>
+ *
+ * @see org.junit.runners.Suite
+ */
+public abstract class RunnerBuilder {
+ private final Set<Class<?>> parents= new HashSet<Class<?>>();
+
+ /**
+ * Override to calculate the correct runner for a test class at runtime.
+ *
+ * @param testClass class to be run
+ * @return a Runner
+ * @throws Throwable if a runner cannot be constructed
+ */
+ public abstract Runner runnerForClass(Class<?> testClass) throws Throwable;
+
+ /**
+ * Always returns a runner, even if it is just one that prints an error instead of running tests.
+ * @param testClass class to be run
+ * @return a Runner
+ */
+ public Runner safeRunnerForClass(Class<?> testClass) {
+ try {
+ return runnerForClass(testClass);
+ } catch (Throwable e) {
+ return new ErrorReportingRunner(testClass, e);
+ }
+ }
+
+ Class<?> addParent(Class<?> parent) throws InitializationError {
+ if (!parents.add(parent))
+ throw new InitializationError(String.format("class '%s' (possibly indirectly) contains itself as a SuiteClass", parent.getName()));
+ return parent;
+ }
+
+ void removeParent(Class<?> klass) {
+ parents.remove(klass);
+ }
+
+ /**
+ * Constructs and returns a list of Runners, one for each child class in
+ * {@code children}. Care is taken to avoid infinite recursion:
+ * this builder will throw an exception if it is requested for another
+ * runner for {@code parent} before this call completes.
+ */
+ public List<Runner> runners(Class<?> parent, Class<?>[] children)
+ throws InitializationError {
+ addParent(parent);
+
+ try {
+ return runners(children);
+ } finally {
+ removeParent(parent);
+ }
+ }
+
+ public List<Runner> runners(Class<?> parent, List<Class<?>> children)
+ throws InitializationError {
+ return runners(parent, children.toArray(new Class<?>[0]));
+ }
+
+ private List<Runner> runners(Class<?>[] children) {
+ ArrayList<Runner> runners= new ArrayList<Runner>();
+ for (Class<?> each : children) {
+ Runner childRunner= safeRunnerForClass(each);
+ if (childRunner != null)
+ runners.add(childRunner);
+ }
+ return runners;
+ }
+}
diff --git a/src/org/junit/runners/model/RunnerScheduler.java b/src/org/junit/runners/model/RunnerScheduler.java
new file mode 100644
index 0000000..fbc25a4
--- /dev/null
+++ b/src/org/junit/runners/model/RunnerScheduler.java
@@ -0,0 +1,21 @@
+package org.junit.runners.model;
+
+/**
+ * Represents a strategy for scheduling when individual test methods
+ * should be run (in serial or parallel)
+ *
+ * WARNING: still experimental, may go away.
+ */
+public interface RunnerScheduler {
+ /**
+ * Schedule a child statement to run
+ */
+ void schedule(Runnable childStatement);
+
+ /**
+ * Override to implement any behavior that must occur
+ * after all children have been scheduled (for example,
+ * waiting for them all to finish)
+ */
+ void finished();
+}
diff --git a/src/org/junit/runners/model/Statement.java b/src/org/junit/runners/model/Statement.java
new file mode 100644
index 0000000..a7c5478
--- /dev/null
+++ b/src/org/junit/runners/model/Statement.java
@@ -0,0 +1,16 @@
+/**
+ *
+ */
+package org.junit.runners.model;
+
+
+/**
+ * Represents one or more actions to be taken at runtime in the course
+ * of running a JUnit test suite.
+ */
+public abstract class Statement {
+ /**
+ * Run the action, throwing a {@code Throwable} if anything goes wrong.
+ */
+ public abstract void evaluate() throws Throwable;
+} \ No newline at end of file
diff --git a/src/org/junit/runners/model/TestClass.java b/src/org/junit/runners/model/TestClass.java
new file mode 100644
index 0000000..362a13a
--- /dev/null
+++ b/src/org/junit/runners/model/TestClass.java
@@ -0,0 +1,159 @@
+package org.junit.runners.model;
+
+import static java.lang.reflect.Modifier.isStatic;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+/**
+ * Wraps a class to be run, providing method validation and annotation searching
+ */
+public class TestClass {
+ private final Class<?> fClass;
+
+ private Map<Class<?>, List<FrameworkMethod>> fMethodsForAnnotations= new HashMap<Class<?>, List<FrameworkMethod>>();
+
+ private Map<Class<?>, List<FrameworkField>> fFieldsForAnnotations= new HashMap<Class<?>, List<FrameworkField>>();
+
+ /**
+ * Creates a {@code TestClass} wrapping {@code klass}. 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)
+ throw new IllegalArgumentException(
+ "Test class can only have one constructor");
+
+ for (Class<?> eachClass : getSuperClasses(fClass)) {
+ for (Method eachMethod : eachClass.getDeclaredMethods())
+ addToAnnotationLists(new FrameworkMethod(eachMethod),
+ fMethodsForAnnotations);
+ for (Field eachField : eachClass.getDeclaredFields())
+ addToAnnotationLists(new FrameworkField(eachField),
+ fFieldsForAnnotations);
+ }
+ }
+
+ private <T extends FrameworkMember<T>> void addToAnnotationLists(T member,
+ Map<Class<?>, List<T>> map) {
+ for (Annotation each : member.getAnnotations()) {
+ Class<? extends Annotation> type= each.annotationType();
+ List<T> members= getAnnotatedMembers(map, type);
+ if (member.isShadowedBy(members))
+ return;
+ if (runsTopToBottom(type))
+ members.add(0, member);
+ else
+ members.add(member);
+ }
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Returns, efficiently, all the non-overridden fields in this class and its
+ * superclasses that are annotated with {@code annotationClass}.
+ */
+ public List<FrameworkField> getAnnotatedFields(
+ Class<? extends Annotation> annotationClass) {
+ return getAnnotatedMembers(fFieldsForAnnotations, annotationClass);
+ }
+
+ private <T> List<T> getAnnotatedMembers(Map<Class<?>, List<T>> map,
+ Class<? extends Annotation> type) {
+ if (!map.containsKey(type))
+ map.put(type, new ArrayList<T>());
+ return map.get(type);
+ }
+
+ private 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<?>>();
+ Class<?> current= testClass;
+ while (current != null) {
+ results.add(current);
+ current= current.getSuperclass();
+ }
+ return results;
+ }
+
+ /**
+ * Returns the underlying Java class.
+ */
+ public Class<?> getJavaClass() {
+ return fClass;
+ }
+
+ /**
+ * Returns the class's name.
+ */
+ public String getName() {
+ if (fClass == null)
+ return "null";
+ return fClass.getName();
+ }
+
+ /**
+ * Returns the only public constructor in the class, or throws an {@code
+ * AssertionError} if there are more or less than one.
+ */
+
+ public Constructor<?> getOnlyConstructor() {
+ Constructor<?>[] constructors= fClass.getConstructors();
+ Assert.assertEquals(1, constructors.length);
+ return constructors[0];
+ }
+
+ /**
+ * Returns the annotations on this class
+ */
+ public Annotation[] getAnnotations() {
+ if (fClass == null)
+ return new Annotation[0];
+ return fClass.getAnnotations();
+ }
+
+ public <T> List<T> getAnnotatedFieldValues(Object test,
+ Class<? extends Annotation> annotationClass, Class<T> valueClass) {
+ List<T> results= new ArrayList<T>();
+ for (FrameworkField each : getAnnotatedFields(annotationClass)) {
+ try {
+ Object fieldValue= each.get(test);
+ if (valueClass.isInstance(fieldValue))
+ results.add(valueClass.cast(fieldValue));
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "How did getFields return a field we couldn't access?", e);
+ }
+ }
+ return results;
+ }
+
+ public boolean isANonStaticInnerClass() {
+ return fClass.isMemberClass() && !isStatic(fClass.getModifiers());
+ }
+}
diff --git a/src/org/junit/runners/package-info.java b/src/org/junit/runners/package-info.java
new file mode 100644
index 0000000..418acaf
--- /dev/null
+++ b/src/org/junit/runners/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * Provides standard {@link org.junit.runner.Runner Runner} implementations.
+ *
+ * @since 4.0
+ * @see org.junit.runner.Runner
+ * @see org.junit.runners.BlockJUnit4ClassRunner
+ */
+package org.junit.runners; \ No newline at end of file
diff --git a/version b/version
index a08ffae..8d39259 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-3.8.2
+4.10