summaryrefslogtreecommitdiffstats
path: root/junit4
diff options
context:
space:
mode:
authorYohann Roussel <yroussel@google.com>2014-03-19 16:25:37 +0100
committerYohann Roussel <yroussel@google.com>2014-03-20 15:13:33 +0100
commit4eceb95409e844fdc33c9c706e1dc307bfd40303 (patch)
treeee9f4f3fc79f757c79081c336bce4f1782c6ccd8 /junit4
parent3d2402901b1a6462e2cf47a6fd09711f327961c3 (diff)
downloadtoolchain_jack-4eceb95409e844fdc33c9c706e1dc307bfd40303.zip
toolchain_jack-4eceb95409e844fdc33c9c706e1dc307bfd40303.tar.gz
toolchain_jack-4eceb95409e844fdc33c9c706e1dc307bfd40303.tar.bz2
Initial Jack import.
Change-Id: I953cf0a520195a7187d791b2885848ad0d5a9b43
Diffstat (limited to 'junit4')
-rw-r--r--junit4/.classpath8
-rw-r--r--junit4/.cvsignore10
-rw-r--r--junit4/.gitignore12
-rw-r--r--junit4/.project18
-rw-r--r--junit4/.settings/org.eclipse.jdt.core.prefs357
-rw-r--r--junit4/.settings/org.eclipse.jdt.ui.prefs13
-rw-r--r--junit4/Android.mk44
-rw-r--r--junit4/BUILDING14
-rw-r--r--junit4/LICENSE218
-rw-r--r--junit4/NOTICE218
-rw-r--r--junit4/README1
-rw-r--r--junit4/README.android5
-rw-r--r--junit4/README.html672
-rw-r--r--junit4/acknowledgements.txt159
-rw-r--r--junit4/build.xml317
-rw-r--r--junit4/build/.cvsignore4
-rw-r--r--junit4/build/.releaserc8
-rw-r--r--junit4/build/Markdown.pl1450
-rw-r--r--junit4/build/github_upload.rb211
-rw-r--r--junit4/build/lib/ant-contrib-1.0b3.jarbin0 -> 224277 bytes
-rw-r--r--junit4/build/lib/commons-net-1.4.1.jarbin0 -> 180792 bytes
-rw-r--r--junit4/build/lib/jakarta-oro-2.0.8.jarbin0 -> 65261 bytes
-rw-r--r--junit4/build/lib/maven-ant-tasks-2.1.1.jarbin0 -> 1314262 bytes
-rw-r--r--junit4/build/maven/pom-template.xml69
-rw-r--r--junit4/build/maven/post_maven_tests.sh49
-rw-r--r--junit4/build/maven/sample_project_template/pom.xml61
-rw-r--r--junit4/build/maven/sample_project_template/src/test/java/JunitDependencyTest.java33
-rw-r--r--junit4/build/profile_junit.sh2
-rw-r--r--junit4/build/release389
-rw-r--r--junit4/build/run_tests.sh36
-rw-r--r--junit4/build/upload_docs.sh2
-rw-r--r--junit4/build_tests.sh76
-rw-r--r--junit4/cpl-v10.html125
-rw-r--r--junit4/doc/ReleaseNotes4.10.html93
-rw-r--r--junit4/doc/ReleaseNotes4.10.txt84
-rw-r--r--junit4/doc/ReleaseNotes4.4.html271
-rw-r--r--junit4/doc/ReleaseNotes4.4.txt295
-rw-r--r--junit4/doc/ReleaseNotes4.5.txt96
-rw-r--r--junit4/doc/ReleaseNotes4.6.html106
-rw-r--r--junit4/doc/ReleaseNotes4.6.txt100
-rw-r--r--junit4/doc/ReleaseNotes4.7.html229
-rw-r--r--junit4/doc/ReleaseNotes4.7.txt194
-rw-r--r--junit4/doc/ReleaseNotes4.8.1.html9
-rw-r--r--junit4/doc/ReleaseNotes4.8.1.txt7
-rw-r--r--junit4/doc/ReleaseNotes4.8.2.html10
-rw-r--r--junit4/doc/ReleaseNotes4.8.2.txt8
-rw-r--r--junit4/doc/ReleaseNotes4.8.html59
-rw-r--r--junit4/doc/ReleaseNotes4.8.txt56
-rw-r--r--junit4/doc/ReleaseNotes4.9.1.txt14
-rw-r--r--junit4/doc/ReleaseNotes4.9.html96
-rw-r--r--junit4/doc/ReleaseNotes4.9.txt89
-rw-r--r--junit4/doc/building-junit.txt19
-rw-r--r--junit4/doc/cookbook/cookbook.htm143
-rw-r--r--junit4/doc/cookbook/logo.gifbin0 -> 964 bytes
-rw-r--r--junit4/doc/cookstour/Image1.gifbin0 -> 1820 bytes
-rw-r--r--junit4/doc/cookstour/Image2.gifbin0 -> 2490 bytes
-rw-r--r--junit4/doc/cookstour/Image3.gifbin0 -> 2946 bytes
-rw-r--r--junit4/doc/cookstour/Image4.gifbin0 -> 3694 bytes
-rw-r--r--junit4/doc/cookstour/Image5.gifbin0 -> 4858 bytes
-rw-r--r--junit4/doc/cookstour/Image6.gifbin0 -> 8950 bytes
-rw-r--r--junit4/doc/cookstour/Image7.gifbin0 -> 5295 bytes
-rw-r--r--junit4/doc/cookstour/cookstour.htm668
-rw-r--r--junit4/doc/faq/faq.htm2380
-rw-r--r--junit4/doc/homepage.html115
-rw-r--r--junit4/doc/index.htm21
-rw-r--r--junit4/doc/markdown.sh1
-rw-r--r--junit4/doc/testinfected/IMG00001.GIFbin0 -> 6426 bytes
-rw-r--r--junit4/doc/testinfected/IMG00002.GIFbin0 -> 6934 bytes
-rw-r--r--junit4/doc/testinfected/IMG00003.GIFbin0 -> 5992 bytes
-rw-r--r--junit4/doc/testinfected/logo.gifbin0 -> 964 bytes
-rw-r--r--junit4/doc/testinfected/testing.htm617
-rw-r--r--junit4/done.txt50
-rw-r--r--junit4/src/main/java/junit/extensions/ActiveTestSuite.java70
-rw-r--r--junit4/src/main/java/junit/extensions/RepeatedTest.java38
-rw-r--r--junit4/src/main/java/junit/extensions/TestDecorator.java43
-rw-r--r--junit4/src/main/java/junit/extensions/TestSetup.java42
-rw-r--r--junit4/src/main/java/junit/extensions/package-info.java4
-rw-r--r--junit4/src/main/java/junit/framework/Assert.java296
-rw-r--r--junit4/src/main/java/junit/framework/AssertionFailedError.java20
-rw-r--r--junit4/src/main/java/junit/framework/ComparisonCompactor.java72
-rw-r--r--junit4/src/main/java/junit/framework/ComparisonFailure.java52
-rw-r--r--junit4/src/main/java/junit/framework/JUnit4TestAdapter.java85
-rw-r--r--junit4/src/main/java/junit/framework/JUnit4TestAdapterCache.java81
-rw-r--r--junit4/src/main/java/junit/framework/JUnit4TestCaseFacade.java33
-rw-r--r--junit4/src/main/java/junit/framework/Protectable.java14
-rw-r--r--junit4/src/main/java/junit/framework/Test.java17
-rw-r--r--junit4/src/main/java/junit/framework/TestCase.java212
-rw-r--r--junit4/src/main/java/junit/framework/TestFailure.java58
-rw-r--r--junit4/src/main/java/junit/framework/TestListener.java23
-rw-r--r--junit4/src/main/java/junit/framework/TestResult.java169
-rw-r--r--junit4/src/main/java/junit/framework/TestSuite.java307
-rw-r--r--junit4/src/main/java/junit/framework/package-info.java4
-rw-r--r--junit4/src/main/java/junit/runner/BaseTestRunner.java318
-rw-r--r--junit4/src/main/java/junit/runner/TestRunListener.java19
-rw-r--r--junit4/src/main/java/junit/runner/Version.java18
-rw-r--r--junit4/src/main/java/junit/runner/Version.java.template18
-rw-r--r--junit4/src/main/java/junit/runner/logo.gifbin0 -> 964 bytes
-rw-r--r--junit4/src/main/java/junit/runner/package-info.java4
-rw-r--r--junit4/src/main/java/junit/runner/smalllogo.gifbin0 -> 883 bytes
-rw-r--r--junit4/src/main/java/junit/textui/ResultPrinter.java139
-rw-r--r--junit4/src/main/java/junit/textui/TestRunner.java203
-rw-r--r--junit4/src/main/java/junit/textui/package-info.java4
-rw-r--r--junit4/src/main/java/org/junit/After.java40
-rw-r--r--junit4/src/main/java/org/junit/AfterClass.java41
-rw-r--r--junit4/src/main/java/org/junit/Assert.java783
-rw-r--r--junit4/src/main/java/org/junit/Assume.java94
-rw-r--r--junit4/src/main/java/org/junit/Before.java39
-rw-r--r--junit4/src/main/java/org/junit/BeforeClass.java35
-rw-r--r--junit4/src/main/java/org/junit/ClassRule.java60
-rw-r--r--junit4/src/main/java/org/junit/ComparisonFailure.java138
-rw-r--r--junit4/src/main/java/org/junit/Ignore.java39
-rw-r--r--junit4/src/main/java/org/junit/Rule.java47
-rw-r--r--junit4/src/main/java/org/junit/Test.java68
-rw-r--r--junit4/src/main/java/org/junit/experimental/ParallelComputer.java78
-rw-r--r--junit4/src/main/java/org/junit/experimental/categories/Categories.java192
-rw-r--r--junit4/src/main/java/org/junit/experimental/categories/Category.java43
-rw-r--r--junit4/src/main/java/org/junit/experimental/max/CouldNotReadCoreException.java15
-rw-r--r--junit4/src/main/java/org/junit/experimental/max/MaxCore.java170
-rw-r--r--junit4/src/main/java/org/junit/experimental/max/MaxHistory.java166
-rw-r--r--junit4/src/main/java/org/junit/experimental/results/FailureList.java31
-rw-r--r--junit4/src/main/java/org/junit/experimental/results/PrintableResult.java63
-rw-r--r--junit4/src/main/java/org/junit/experimental/results/ResultMatchers.java70
-rw-r--r--junit4/src/main/java/org/junit/experimental/runners/Enclosed.java31
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/DataPoint.java9
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/DataPoints.java9
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/ParameterSignature.java90
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/ParameterSupplier.java8
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java12
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/PotentialAssignment.java31
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/Theories.java199
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/Theory.java12
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java127
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/internal/Assignments.java133
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java49
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java13
-rw-r--r--junit4/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java23
-rw-r--r--junit4/src/main/java/org/junit/internal/ArrayComparisonFailure.java59
-rw-r--r--junit4/src/main/java/org/junit/internal/AssumptionViolatedException.java40
-rw-r--r--junit4/src/main/java/org/junit/internal/ComparisonCriteria.java76
-rw-r--r--junit4/src/main/java/org/junit/internal/ExactComparisonCriteria.java10
-rw-r--r--junit4/src/main/java/org/junit/internal/InexactComparisonCriteria.java19
-rw-r--r--junit4/src/main/java/org/junit/internal/JUnitSystem.java8
-rw-r--r--junit4/src/main/java/org/junit/internal/RealSystem.java15
-rw-r--r--junit4/src/main/java/org/junit/internal/TextListener.java98
-rw-r--r--junit4/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java57
-rw-r--r--junit4/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java45
-rw-r--r--junit4/src/main/java/org/junit/internal/builders/IgnoredBuilder.java17
-rw-r--r--junit4/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java26
-rw-r--r--junit4/src/main/java/org/junit/internal/builders/JUnit3Builder.java21
-rw-r--r--junit4/src/main/java/org/junit/internal/builders/JUnit4Builder.java15
-rw-r--r--junit4/src/main/java/org/junit/internal/builders/NullBuilder.java14
-rw-r--r--junit4/src/main/java/org/junit/internal/builders/SuiteMethodBuilder.java26
-rw-r--r--junit4/src/main/java/org/junit/internal/matchers/CombinableMatcher.java34
-rw-r--r--junit4/src/main/java/org/junit/internal/matchers/Each.java24
-rw-r--r--junit4/src/main/java/org/junit/internal/matchers/IsCollectionContaining.java67
-rw-r--r--junit4/src/main/java/org/junit/internal/matchers/StringContains.java31
-rw-r--r--junit4/src/main/java/org/junit/internal/matchers/SubstringMatcher.java28
-rw-r--r--junit4/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java60
-rw-r--r--junit4/src/main/java/org/junit/internal/requests/ClassRequest.java26
-rw-r--r--junit4/src/main/java/org/junit/internal/requests/FilterRequest.java42
-rw-r--r--junit4/src/main/java/org/junit/internal/requests/SortingRequest.java25
-rw-r--r--junit4/src/main/java/org/junit/internal/requests/package-info.java6
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/ClassRoadie.java79
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java60
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/FailedBefore.java14
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/InitializationError.java30
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java158
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java145
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/MethodRoadie.java157
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/MethodValidator.java91
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/SuiteMethod.java40
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/TestClass.java102
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/TestMethod.java69
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java51
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/model/MultipleFailureException.java12
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/model/ReflectiveCallable.java22
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/package-info.java6
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java92
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/statements/ExpectException.java38
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/statements/Fail.java17
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java71
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java22
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/statements/RunAfters.java43
-rw-r--r--junit4/src/main/java/org/junit/internal/runners/statements/RunBefores.java30
-rw-r--r--junit4/src/main/java/org/junit/matchers/JUnitMatchers.java83
-rw-r--r--junit4/src/main/java/org/junit/matchers/package-info.java9
-rw-r--r--junit4/src/main/java/org/junit/package-info.java8
-rw-r--r--junit4/src/main/java/org/junit/rules/ErrorCollector.java85
-rw-r--r--junit4/src/main/java/org/junit/rules/ExpectedException.java136
-rw-r--r--junit4/src/main/java/org/junit/rules/ExternalResource.java68
-rw-r--r--junit4/src/main/java/org/junit/rules/MethodRule.java40
-rw-r--r--junit4/src/main/java/org/junit/rules/RuleChain.java99
-rw-r--r--junit4/src/main/java/org/junit/rules/RunRules.java27
-rw-r--r--junit4/src/main/java/org/junit/rules/TemporaryFolder.java113
-rw-r--r--junit4/src/main/java/org/junit/rules/TestName.java39
-rw-r--r--junit4/src/main/java/org/junit/rules/TestRule.java54
-rw-r--r--junit4/src/main/java/org/junit/rules/TestWatcher.java94
-rw-r--r--junit4/src/main/java/org/junit/rules/TestWatchman.java100
-rw-r--r--junit4/src/main/java/org/junit/rules/Timeout.java49
-rw-r--r--junit4/src/main/java/org/junit/rules/Verifier.java45
-rw-r--r--junit4/src/main/java/org/junit/runner/Computer.java40
-rw-r--r--junit4/src/main/java/org/junit/runner/Describable.java12
-rw-r--r--junit4/src/main/java/org/junit/runner/Description.java242
-rw-r--r--junit4/src/main/java/org/junit/runner/JUnitCore.java186
-rw-r--r--junit4/src/main/java/org/junit/runner/Request.java161
-rw-r--r--junit4/src/main/java/org/junit/runner/Result.java106
-rw-r--r--junit4/src/main/java/org/junit/runner/RunWith.java34
-rw-r--r--junit4/src/main/java/org/junit/runner/Runner.java40
-rw-r--r--junit4/src/main/java/org/junit/runner/manipulation/Filter.java114
-rw-r--r--junit4/src/main/java/org/junit/runner/manipulation/Filterable.java16
-rw-r--r--junit4/src/main/java/org/junit/runner/manipulation/NoTestsRemainException.java8
-rw-r--r--junit4/src/main/java/org/junit/runner/manipulation/Sortable.java17
-rw-r--r--junit4/src/main/java/org/junit/runner/manipulation/Sorter.java46
-rw-r--r--junit4/src/main/java/org/junit/runner/manipulation/package-info.java7
-rw-r--r--junit4/src/main/java/org/junit/runner/notification/Failure.java79
-rw-r--r--junit4/src/main/java/org/junit/runner/notification/RunListener.java93
-rw-r--r--junit4/src/main/java/org/junit/runner/notification/RunNotifier.java166
-rw-r--r--junit4/src/main/java/org/junit/runner/notification/StoppedByUserException.java11
-rw-r--r--junit4/src/main/java/org/junit/runner/notification/package-info.java6
-rw-r--r--junit4/src/main/java/org/junit/runner/package-info.java6
-rw-r--r--junit4/src/main/java/org/junit/runners/AllTests.java24
-rw-r--r--junit4/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java407
-rw-r--r--junit4/src/main/java/org/junit/runners/JUnit4.java22
-rw-r--r--junit4/src/main/java/org/junit/runners/Parameterized.java167
-rw-r--r--junit4/src/main/java/org/junit/runners/ParentRunner.java378
-rw-r--r--junit4/src/main/java/org/junit/runners/Suite.java130
-rw-r--r--junit4/src/main/java/org/junit/runners/model/FrameworkField.java65
-rw-r--r--junit4/src/main/java/org/junit/runners/model/FrameworkMember.java20
-rw-r--r--junit4/src/main/java/org/junit/runners/model/FrameworkMethod.java156
-rw-r--r--junit4/src/main/java/org/junit/runners/model/InitializationError.java39
-rw-r--r--junit4/src/main/java/org/junit/runners/model/MultipleFailureException.java60
-rw-r--r--junit4/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java53
-rw-r--r--junit4/src/main/java/org/junit/runners/model/RunnerBuilder.java104
-rw-r--r--junit4/src/main/java/org/junit/runners/model/RunnerScheduler.java21
-rw-r--r--junit4/src/main/java/org/junit/runners/model/Statement.java16
-rw-r--r--junit4/src/main/java/org/junit/runners/model/TestClass.java159
-rw-r--r--junit4/src/main/java/org/junit/runners/package-info.java8
-rw-r--r--junit4/src/test/java/junit/samples/AllTests.java22
-rw-r--r--junit4/src/test/java/junit/samples/ListTest.java63
-rw-r--r--junit4/src/test/java/junit/samples/SimpleTest.java68
-rw-r--r--junit4/src/test/java/junit/samples/money/IMoney.java45
-rw-r--r--junit4/src/test/java/junit/samples/money/Money.java78
-rw-r--r--junit4/src/test/java/junit/samples/money/MoneyBag.java124
-rw-r--r--junit4/src/test/java/junit/samples/money/MoneyTest.java143
-rw-r--r--junit4/src/test/java/junit/samples/money/package-info.java4
-rw-r--r--junit4/src/test/java/junit/samples/package-info.java4
-rw-r--r--junit4/src/test/java/junit/tests/AllTests.java23
-rw-r--r--junit4/src/test/java/junit/tests/WasRun.java15
-rw-r--r--junit4/src/test/java/junit/tests/extensions/ActiveTestTest.java64
-rw-r--r--junit4/src/test/java/junit/tests/extensions/AllTests.java23
-rw-r--r--junit4/src/test/java/junit/tests/extensions/ExtensionTest.java98
-rw-r--r--junit4/src/test/java/junit/tests/extensions/RepeatedTestTest.java63
-rw-r--r--junit4/src/test/java/junit/tests/extensions/package-info.java4
-rw-r--r--junit4/src/test/java/junit/tests/framework/AllTests.java32
-rw-r--r--junit4/src/test/java/junit/tests/framework/AssertTest.java171
-rw-r--r--junit4/src/test/java/junit/tests/framework/AssertionFailedErrorTest.java23
-rw-r--r--junit4/src/test/java/junit/tests/framework/ComparisonCompactorTest.java102
-rw-r--r--junit4/src/test/java/junit/tests/framework/ComparisonFailureTest.java47
-rw-r--r--junit4/src/test/java/junit/tests/framework/DoublePrecisionAssertTest.java55
-rw-r--r--junit4/src/test/java/junit/tests/framework/Failure.java14
-rw-r--r--junit4/src/test/java/junit/tests/framework/FloatAssertTest.java63
-rw-r--r--junit4/src/test/java/junit/tests/framework/InheritedTestCase.java9
-rw-r--r--junit4/src/test/java/junit/tests/framework/NoArgTestCaseTest.java9
-rw-r--r--junit4/src/test/java/junit/tests/framework/NoTestCaseClass.java10
-rw-r--r--junit4/src/test/java/junit/tests/framework/NoTestCases.java11
-rw-r--r--junit4/src/test/java/junit/tests/framework/NotPublicTestCase.java13
-rw-r--r--junit4/src/test/java/junit/tests/framework/NotVoidTestCase.java14
-rw-r--r--junit4/src/test/java/junit/tests/framework/OneTestCase.java15
-rw-r--r--junit4/src/test/java/junit/tests/framework/OverrideTestCase.java10
-rw-r--r--junit4/src/test/java/junit/tests/framework/Success.java17
-rw-r--r--junit4/src/test/java/junit/tests/framework/SuiteTest.java105
-rw-r--r--junit4/src/test/java/junit/tests/framework/TestCaseTest.java190
-rw-r--r--junit4/src/test/java/junit/tests/framework/TestImplementorTest.java54
-rw-r--r--junit4/src/test/java/junit/tests/framework/TestListenerTest.java73
-rw-r--r--junit4/src/test/java/junit/tests/framework/ThreeTestCases.java15
-rw-r--r--junit4/src/test/java/junit/tests/framework/package-info.java4
-rw-r--r--junit4/src/test/java/junit/tests/package-info.java4
-rw-r--r--junit4/src/test/java/junit/tests/runner/AllTests.java31
-rw-r--r--junit4/src/test/java/junit/tests/runner/BaseTestRunnerTest.java53
-rw-r--r--junit4/src/test/java/junit/tests/runner/ResultTest.java37
-rw-r--r--junit4/src/test/java/junit/tests/runner/StackFilterTest.java46
-rw-r--r--junit4/src/test/java/junit/tests/runner/TextFeedbackTest.java109
-rw-r--r--junit4/src/test/java/junit/tests/runner/TextRunnerSingleMethodTest.java39
-rw-r--r--junit4/src/test/java/junit/tests/runner/TextRunnerTest.java61
-rw-r--r--junit4/src/test/java/junit/tests/runner/package-info.java4
-rw-r--r--junit4/src/test/java/org/junit/samples/ListTest.java77
-rw-r--r--junit4/src/test/java/org/junit/samples/SimpleTest.java41
-rw-r--r--junit4/src/test/java/org/junit/samples/money/MoneyTest.java158
-rw-r--r--junit4/src/test/java/org/junit/samples/money/package-info.java7
-rw-r--r--junit4/src/test/java/org/junit/samples/package-info.java6
-rw-r--r--junit4/src/test/java/org/junit/tests/AllTests.java163
-rw-r--r--junit4/src/test/java/org/junit/tests/ObjectContractTest.java46
-rw-r--r--junit4/src/test/java/org/junit/tests/TestSystem.java31
-rw-r--r--junit4/src/test/java/org/junit/tests/assertion/AssertionTest.java486
-rw-r--r--junit4/src/test/java/org/junit/tests/assertion/BothTest.java71
-rw-r--r--junit4/src/test/java/org/junit/tests/assertion/EachTest.java13
-rw-r--r--junit4/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java60
-rw-r--r--junit4/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java54
-rw-r--r--junit4/src/test/java/org/junit/tests/description/AnnotatedDescriptionTest.java96
-rw-r--r--junit4/src/test/java/org/junit/tests/description/SuiteDescriptionTest.java35
-rw-r--r--junit4/src/test/java/org/junit/tests/description/TestDescriptionTest.java11
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/AssumptionTest.java177
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/AssumptionViolatedExceptionTest.java52
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/ExperimentalTests.java28
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/MatcherTest.java43
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java123
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/categories/CategoryTest.java254
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/max/DescriptionTest.java24
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/max/JUnit38SortingTest.java53
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/max/MaxStarterTest.java293
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/parallel/ParallelClassTest.java54
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/parallel/ParallelMethodTest.java44
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/results/PrintableResultTest.java51
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/results/ResultMatchersTest.java21
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java93
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java101
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionRuleTest.java232
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/ExternalResourceRuleTest.java37
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java32
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java275
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/NameRulesTest.java50
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/RuleChainTest.java60
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java96
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java200
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java289
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java52
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java72
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java39
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java133
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/AllMembersSupplierTest.java34
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java57
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/ParameterizedAssertionErrorTest.java75
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Correspondent.java7
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Guesser.java122
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/GuesserQueue.java57
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/MethodCall.java54
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/ReguessableValue.java16
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StringableObject.java27
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Stub.java8
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheories.java65
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java1
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/runner/SuccessfulWithDataPointFields.java204
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/runner/TheoriesPerformanceTest.java37
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java126
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/runner/WhenNoParametersMatch.java50
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java152
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java146
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithOnlyTestAnnotations.java80
-rw-r--r--junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java177
-rw-r--r--junit4/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java110
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/AllTestsTest.java81
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/ClassRequestTest.java19
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityPrintingTest.java89
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityTest.java222
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/InitializationErrorForwardCompatibilityTest.java100
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/JUnit38ClassRunnerTest.java79
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/OldTestClassAdaptingListenerTest.java27
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/OldTests.java11
-rw-r--r--junit4/src/test/java/org/junit/tests/junit3compatibility/SuiteMethodTest.java123
-rw-r--r--junit4/src/test/java/org/junit/tests/listening/ListenerTest.java33
-rw-r--r--junit4/src/test/java/org/junit/tests/listening/RunnerTest.java69
-rw-r--r--junit4/src/test/java/org/junit/tests/listening/TestListenerTest.java63
-rw-r--r--junit4/src/test/java/org/junit/tests/listening/TextListenerTest.java65
-rw-r--r--junit4/src/test/java/org/junit/tests/listening/UserStopTest.java28
-rw-r--r--junit4/src/test/java/org/junit/tests/manipulation/FilterTest.java49
-rw-r--r--junit4/src/test/java/org/junit/tests/manipulation/FilterableTest.java62
-rw-r--r--junit4/src/test/java/org/junit/tests/manipulation/SingleMethodTest.java168
-rw-r--r--junit4/src/test/java/org/junit/tests/manipulation/SortableTest.java149
-rw-r--r--junit4/src/test/java/org/junit/tests/package-info.java8
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java33
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/EnclosedTest.java40
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/IgnoreClassTest.java26
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java216
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/ParentRunnerFilteringTest.java171
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java139
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/RunWithTest.java85
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/SuiteTest.java167
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/TestClassTest.java121
-rw-r--r--junit4/src/test/java/org/junit/tests/running/classes/UseSuiteAsASuperclassTest.java44
-rw-r--r--junit4/src/test/java/org/junit/tests/running/core/CommandLineTest.java67
-rw-r--r--junit4/src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java39
-rw-r--r--junit4/src/test/java/org/junit/tests/running/core/SystemExitTest.java30
-rw-r--r--junit4/src/test/java/org/junit/tests/running/methods/AnnotationTest.java520
-rw-r--r--junit4/src/test/java/org/junit/tests/running/methods/ExpectedTest.java58
-rw-r--r--junit4/src/test/java/org/junit/tests/running/methods/InheritedTestTest.java31
-rw-r--r--junit4/src/test/java/org/junit/tests/running/methods/ParameterizedTestMethodTest.java102
-rw-r--r--junit4/src/test/java/org/junit/tests/running/methods/TestMethodTest.java147
-rw-r--r--junit4/src/test/java/org/junit/tests/running/methods/TimeoutTest.java170
-rw-r--r--junit4/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java68
-rw-r--r--junit4/src/test/java/org/junit/tests/validation/FailedConstructionTest.java28
-rw-r--r--junit4/src/test/java/org/junit/tests/validation/InaccessibleBaseClassTest.java13
-rw-r--r--junit4/src/test/java/org/junit/tests/validation/ValidationTest.java34
-rw-r--r--junit4/src/test/java/org/junit/tests/validation/anotherpackage/Sub.java5
-rw-r--r--junit4/src/test/java/org/junit/tests/validation/anotherpackage/Super.java7
-rw-r--r--junit4/stylesheet.css1
-rw-r--r--junit4/to-do.txt31
396 files changed, 34295 insertions, 0 deletions
diff --git a/junit4/.classpath b/junit4/.classpath
new file mode 100644
index 0000000..9cecf51
--- /dev/null
+++ b/junit4/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/test/java"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry exported="true" kind="lib" path="lib/hamcrest-core-1.1.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/junit4/.cvsignore b/junit4/.cvsignore
new file mode 100644
index 0000000..a23e28c
--- /dev/null
+++ b/junit4/.cvsignore
@@ -0,0 +1,10 @@
+bin
+junit4.1
+junit*-SNAPSHOT-*
+target
+reports
+buildfile
+java.hprof.txt
+junit4.5-RC1
+junit4.*
+*.ser
diff --git a/junit4/.gitignore b/junit4/.gitignore
new file mode 100644
index 0000000..ad531ef
--- /dev/null
+++ b/junit4/.gitignore
@@ -0,0 +1,12 @@
+MaxCore.ser
+bin
+junit4.*
+target
+MaxCore.max
+# IntelliJ
+.idea
+*.ipr
+*.iml
+*.iws
+out
+java.hprof.txt \ No newline at end of file
diff --git a/junit4/.project b/junit4/.project
new file mode 100644
index 0000000..8875688
--- /dev/null
+++ b/junit4/.project
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>junit</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.team.cvs.core.cvsnature</nature>
+ </natures>
+</projectDescription>
diff --git a/junit4/.settings/org.eclipse.jdt.core.prefs b/junit4/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..0125987
--- /dev/null
+++ b/junit4/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,357 @@
+#Mon Oct 12 21:57:10 EDT 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=f
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=ignore
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=no_tag
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled
+org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL,HIGH,NORMAL
+org.eclipse.jdt.core.compiler.taskTags=TODO,REVISIT,HACK,QUESTION
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=1
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/junit4/.settings/org.eclipse.jdt.ui.prefs b/junit4/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..dd34e34
--- /dev/null
+++ b/junit4/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,13 @@
+#Tue Jul 22 09:31:38 PDT 2008
+eclipse.preferences.version=1
+formatter_profile=_junit
+formatter_settings_version=11
+internal.default.compliance=default
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;com;
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/>
diff --git a/junit4/Android.mk b/junit4/Android.mk
new file mode 100644
index 0000000..89f3a07
--- /dev/null
+++ b/junit4/Android.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
+
+LOCAL_MODULE := junit4-jack
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := hamcrest-core-jack
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
+
+LOCAL_JAVA_LIBRARIES := core-hostdex
+
+LOCAL_STATIC_JAVA_LIBRARIES := hamcrest-core-jack
+
+LOCAL_MODULE := junit4-hostdex-jack
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_BUILD_HOST_DEX := true
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/junit4/BUILDING b/junit4/BUILDING
new file mode 100644
index 0000000..6a347ea
--- /dev/null
+++ b/junit4/BUILDING
@@ -0,0 +1,14 @@
+BUILDING FROM GITHUB:
+=====================
+
+git clone https://github.com/KentBeck/junit.git
+cd junit
+ant dist
+
+BUILDING FROM JARS OR ZIPS:
+===========================
+
+The contents of the zip and jar files are largely maintained for historical
+reasons. We do not at this time have an official way to build from the src
+jar or zip. If this is an important missing feature, please let us know
+at http://github.com/KentBeck/junit/issues \ No newline at end of file
diff --git a/junit4/LICENSE b/junit4/LICENSE
new file mode 100644
index 0000000..1aba77a
--- /dev/null
+++ b/junit4/LICENSE
@@ -0,0 +1,218 @@
+JUnit
+
+Common Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
+CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+ a) in the case of the initial Contributor, the initial code and
+ documentation distributed under this Agreement, and
+ b) in the case of each subsequent Contributor:
+
+ i) changes to the Program, and
+
+ ii) additions to the Program;
+
+ where such changes and/or additions to the Program originate from and are
+distributed by that particular Contributor. A Contribution 'originates' from a
+Contributor if it was added to the Program by such Contributor itself or anyone
+acting on such Contributor's behalf. Contributions do not include additions to
+the Program which: (i) are separate modules of software distributed in
+conjunction with the Program under their own license agreement, and (ii) are
+not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are
+necessarily infringed by the use or sale of its Contribution alone or when
+combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement,
+including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide, royalty-free copyright license to
+reproduce, prepare derivative works of, publicly display, publicly perform,
+distribute and sublicense the Contribution of such Contributor, if any, and
+such derivative works, in source code and object code form.
+
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide, royalty-free patent license under
+Licensed Patents to make, use, sell, offer to sell, import and otherwise
+transfer the Contribution of such Contributor, if any, in source code and
+object code form. This patent license shall apply to the combination of the
+Contribution and the Program if, at the time the Contribution is added by the
+Contributor, such addition of the Contribution causes such combination to be
+covered by the Licensed Patents. The patent license shall not apply to any
+other combinations which include the Contribution. No hardware per se is
+licensed hereunder.
+
+ c) Recipient understands that although each Contributor grants the
+licenses to its Contributions set forth herein, no assurances are provided by
+any Contributor that the Program does not infringe the patent or other
+intellectual property rights of any other entity. Each Contributor disclaims
+any liability to Recipient for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a condition to
+exercising the rights and licenses granted hereunder, each Recipient hereby
+assumes sole responsibility to secure any other intellectual property rights
+needed, if any. For example, if a third party patent license is required to
+allow Recipient to distribute the Program, it is Recipient's responsibility to
+acquire that license before distributing the Program.
+
+ d) Each Contributor represents that to its knowledge it has sufficient
+copyright rights in its Contribution, if any, to grant the copyright license
+set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under
+its own license agreement, provided that:
+
+ a) it complies with the terms and conditions of this Agreement; and
+
+ b) its license agreement:
+
+ i) effectively disclaims on behalf of all Contributors all warranties and
+conditions, express and implied, including warranties or conditions of title
+and non-infringement, and implied warranties or conditions of merchantability
+and fitness for a particular purpose;
+
+ ii) effectively excludes on behalf of all Contributors all liability for
+damages, including direct, indirect, special, incidental and consequential
+damages, such as lost profits;
+
+ iii) states that any provisions which differ from this Agreement are
+offered by that Contributor alone and not by any other party; and
+
+ iv) states that source code for the Program is available from such
+Contributor, and informs licensees how to obtain it in a reasonable manner on
+or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+ a) it must be made available under this Agreement; and
+
+ b) a copy of this Agreement must be included with each copy of the
+Program.
+
+Contributors may not remove or alter any copyright notices contained within the
+Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if
+any, in a manner that reasonably allows subsequent Recipients to identify the
+originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with
+respect to end users, business partners and the like. While this license is
+intended to facilitate the commercial use of the Program, the Contributor who
+includes the Program in a commercial product offering should do so in a manner
+which does not create potential liability for other Contributors. Therefore, if
+a Contributor includes the Program in a commercial product offering, such
+Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+every other Contributor ("Indemnified Contributor") against any losses, damages
+and costs (collectively "Losses") arising from claims, lawsuits and other legal
+actions brought by a third party against the Indemnified Contributor to the
+extent caused by the acts or omissions of such Commercial Contributor in
+connection with its distribution of the Program in a commercial product
+offering. The obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In order
+to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor
+to control, and cooperate with the Commercial Contributor in, the defense and
+any related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product
+offering, Product X. That Contributor is then a Commercial Contributor. If that
+Commercial Contributor then makes performance claims, or offers warranties
+related to Product X, those performance claims and warranties are such
+Commercial Contributor's responsibility alone. Under this section, the
+Commercial Contributor would have to defend claims against the other
+Contributors related to those performance claims and warranties, and if a court
+requires any other Contributor to pay any damages as a result, the Commercial
+Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
+Recipient is solely responsible for determining the appropriateness of using
+and distributing the Program and assumes all risks associated with its exercise
+of rights under this Agreement, including but not limited to the risks and
+costs of program errors, compliance with applicable laws, damage to or loss of
+data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
+GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable
+law, it shall not affect the validity or enforceability of the remainder of the
+terms of this Agreement, and without further action by the parties hereto, such
+provision shall be reformed to the minimum extent necessary to make such
+provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with respect to
+a patent applicable to software (including a cross-claim or counterclaim in a
+lawsuit), then any patent licenses granted by that Contributor to such
+Recipient under this Agreement shall terminate as of the date such litigation
+is filed. In addition, if Recipient institutes patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software or
+hardware) infringes such Recipient's patent(s), then such Recipient's rights
+granted under Section 2(b) shall terminate as of the date such litigation is
+filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to
+comply with any of the material terms or conditions of this Agreement and does
+not cure such failure in a reasonable period of time after becoming aware of
+such noncompliance. If all Recipient's rights under this Agreement terminate,
+Recipient agrees to cease use and distribution of the Program as soon as
+reasonably practicable. However, Recipient's obligations under this Agreement
+and any licenses granted by Recipient relating to the Program shall continue
+and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in
+order to avoid inconsistency the Agreement is copyrighted and may only be
+modified in the following manner. The Agreement Steward reserves the right to
+publish new versions (including revisions) of this Agreement from time to time.
+No one other than the Agreement Steward has the right to modify this Agreement.
+IBM is the initial Agreement Steward. IBM may assign the responsibility to
+serve as the Agreement Steward to a suitable separate entity. Each new version
+of the Agreement will be given a distinguishing version number. The Program
+(including Contributions) may always be distributed subject to the version of
+the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program
+(including its Contributions) under the new version. Except as expressly stated
+in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether
+expressly, by implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the
+intellectual property laws of the United States of America. No party to this
+Agreement will bring a legal action under this Agreement more than one year
+after the cause of action arose. Each party waives its rights to a jury trial
+in any resulting litigation.
+
diff --git a/junit4/NOTICE b/junit4/NOTICE
new file mode 100644
index 0000000..1aba77a
--- /dev/null
+++ b/junit4/NOTICE
@@ -0,0 +1,218 @@
+JUnit
+
+Common Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
+CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+ a) in the case of the initial Contributor, the initial code and
+ documentation distributed under this Agreement, and
+ b) in the case of each subsequent Contributor:
+
+ i) changes to the Program, and
+
+ ii) additions to the Program;
+
+ where such changes and/or additions to the Program originate from and are
+distributed by that particular Contributor. A Contribution 'originates' from a
+Contributor if it was added to the Program by such Contributor itself or anyone
+acting on such Contributor's behalf. Contributions do not include additions to
+the Program which: (i) are separate modules of software distributed in
+conjunction with the Program under their own license agreement, and (ii) are
+not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are
+necessarily infringed by the use or sale of its Contribution alone or when
+combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement,
+including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide, royalty-free copyright license to
+reproduce, prepare derivative works of, publicly display, publicly perform,
+distribute and sublicense the Contribution of such Contributor, if any, and
+such derivative works, in source code and object code form.
+
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide, royalty-free patent license under
+Licensed Patents to make, use, sell, offer to sell, import and otherwise
+transfer the Contribution of such Contributor, if any, in source code and
+object code form. This patent license shall apply to the combination of the
+Contribution and the Program if, at the time the Contribution is added by the
+Contributor, such addition of the Contribution causes such combination to be
+covered by the Licensed Patents. The patent license shall not apply to any
+other combinations which include the Contribution. No hardware per se is
+licensed hereunder.
+
+ c) Recipient understands that although each Contributor grants the
+licenses to its Contributions set forth herein, no assurances are provided by
+any Contributor that the Program does not infringe the patent or other
+intellectual property rights of any other entity. Each Contributor disclaims
+any liability to Recipient for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a condition to
+exercising the rights and licenses granted hereunder, each Recipient hereby
+assumes sole responsibility to secure any other intellectual property rights
+needed, if any. For example, if a third party patent license is required to
+allow Recipient to distribute the Program, it is Recipient's responsibility to
+acquire that license before distributing the Program.
+
+ d) Each Contributor represents that to its knowledge it has sufficient
+copyright rights in its Contribution, if any, to grant the copyright license
+set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under
+its own license agreement, provided that:
+
+ a) it complies with the terms and conditions of this Agreement; and
+
+ b) its license agreement:
+
+ i) effectively disclaims on behalf of all Contributors all warranties and
+conditions, express and implied, including warranties or conditions of title
+and non-infringement, and implied warranties or conditions of merchantability
+and fitness for a particular purpose;
+
+ ii) effectively excludes on behalf of all Contributors all liability for
+damages, including direct, indirect, special, incidental and consequential
+damages, such as lost profits;
+
+ iii) states that any provisions which differ from this Agreement are
+offered by that Contributor alone and not by any other party; and
+
+ iv) states that source code for the Program is available from such
+Contributor, and informs licensees how to obtain it in a reasonable manner on
+or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+ a) it must be made available under this Agreement; and
+
+ b) a copy of this Agreement must be included with each copy of the
+Program.
+
+Contributors may not remove or alter any copyright notices contained within the
+Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if
+any, in a manner that reasonably allows subsequent Recipients to identify the
+originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with
+respect to end users, business partners and the like. While this license is
+intended to facilitate the commercial use of the Program, the Contributor who
+includes the Program in a commercial product offering should do so in a manner
+which does not create potential liability for other Contributors. Therefore, if
+a Contributor includes the Program in a commercial product offering, such
+Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+every other Contributor ("Indemnified Contributor") against any losses, damages
+and costs (collectively "Losses") arising from claims, lawsuits and other legal
+actions brought by a third party against the Indemnified Contributor to the
+extent caused by the acts or omissions of such Commercial Contributor in
+connection with its distribution of the Program in a commercial product
+offering. The obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In order
+to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor
+to control, and cooperate with the Commercial Contributor in, the defense and
+any related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product
+offering, Product X. That Contributor is then a Commercial Contributor. If that
+Commercial Contributor then makes performance claims, or offers warranties
+related to Product X, those performance claims and warranties are such
+Commercial Contributor's responsibility alone. Under this section, the
+Commercial Contributor would have to defend claims against the other
+Contributors related to those performance claims and warranties, and if a court
+requires any other Contributor to pay any damages as a result, the Commercial
+Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
+Recipient is solely responsible for determining the appropriateness of using
+and distributing the Program and assumes all risks associated with its exercise
+of rights under this Agreement, including but not limited to the risks and
+costs of program errors, compliance with applicable laws, damage to or loss of
+data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
+GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable
+law, it shall not affect the validity or enforceability of the remainder of the
+terms of this Agreement, and without further action by the parties hereto, such
+provision shall be reformed to the minimum extent necessary to make such
+provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with respect to
+a patent applicable to software (including a cross-claim or counterclaim in a
+lawsuit), then any patent licenses granted by that Contributor to such
+Recipient under this Agreement shall terminate as of the date such litigation
+is filed. In addition, if Recipient institutes patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software or
+hardware) infringes such Recipient's patent(s), then such Recipient's rights
+granted under Section 2(b) shall terminate as of the date such litigation is
+filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to
+comply with any of the material terms or conditions of this Agreement and does
+not cure such failure in a reasonable period of time after becoming aware of
+such noncompliance. If all Recipient's rights under this Agreement terminate,
+Recipient agrees to cease use and distribution of the Program as soon as
+reasonably practicable. However, Recipient's obligations under this Agreement
+and any licenses granted by Recipient relating to the Program shall continue
+and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in
+order to avoid inconsistency the Agreement is copyrighted and may only be
+modified in the following manner. The Agreement Steward reserves the right to
+publish new versions (including revisions) of this Agreement from time to time.
+No one other than the Agreement Steward has the right to modify this Agreement.
+IBM is the initial Agreement Steward. IBM may assign the responsibility to
+serve as the Agreement Steward to a suitable separate entity. Each new version
+of the Agreement will be given a distinguishing version number. The Program
+(including Contributions) may always be distributed subject to the version of
+the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program
+(including its Contributions) under the new version. Except as expressly stated
+in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether
+expressly, by implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the
+intellectual property laws of the United States of America. No party to this
+Agreement will bring a legal action under this Agreement more than one year
+after the cause of action arose. Each party waives its rights to a jury trial
+in any resulting litigation.
+
diff --git a/junit4/README b/junit4/README
new file mode 100644
index 0000000..3533670
--- /dev/null
+++ b/junit4/README
@@ -0,0 +1 @@
+Please read README.html \ No newline at end of file
diff --git a/junit4/README.android b/junit4/README.android
new file mode 100644
index 0000000..daadc17
--- /dev/null
+++ b/junit4/README.android
@@ -0,0 +1,5 @@
+URL: http://www.junit.org/
+Tag: r4.10
+License: CPL
+Description: JUnit test framework.
+Local Modifications: the lib folder was not imported.
diff --git a/junit4/README.html b/junit4/README.html
new file mode 100644
index 0000000..42f29a6
--- /dev/null
+++ b/junit4/README.html
@@ -0,0 +1,672 @@
+<!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, 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
+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>
+<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>
+
+<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><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>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>Fixed overly permissive @DataPoint processing (2191102)</li>
+<li>Fixed bug in test counting after an ignored method (2106324)</li>
+</ul>
+
+<h2>Summary of Changes in version 4.5</h2>
+
+<h3>Installation</h3>
+
+<ul>
+<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>Basic JUnit operation</h3>
+
+<ul>
+<li><p>JUnitCore now more often exits with the correct exit code (0 for
+success, 1 for failure)</p></li>
+<li><p>Badly formed test classes (exceptions in constructors, classes
+without tests, multiple constructors, Suite without @SuiteClasses)
+produce more helpful error messages</p></li>
+<li><p>Test classes whose only test methods are inherited from superclasses
+now run.</p></li>
+<li><p>Optimization to annotation processing can cut JUnit overhead by more than half
+on large test classes, especially when using Theories. [Bug 1796847]</p></li>
+<li><p>A failing assumption in a constructor ignores the class</p></li>
+<li><p>Correct results when comparing the string "null" with potentially
+null values. [Bug 1857283]</p></li>
+<li><p>Annotating a class with <code>@RunWith(JUnit4.class)</code> will always invoke the
+default JUnit 4 runner in the current version of JUnit. This default changed
+from <code>JUnit4ClassRunner</code> in 4.4 to <code>BlockJUnit4ClassRunner</code> in 4.5 (see below),
+and may change again.</p></li>
+</ul>
+
+<h3>Extension</h3>
+
+<ul>
+<li><p><code>BlockJUnit4Runner</code> is a new implementation of the standard JUnit 4
+test class functionality. In contrast to <code>JUnit4ClassRunner</code> (the old
+implementation):</p>
+
+<ul>
+<li><p><code>BlockJUnit4Runner</code> has a much simpler implementation based on
+Statements, allowing new operations to be inserted into the
+appropriate point in the execution flow.</p></li>
+<li><p><code>BlockJUnit4Runner</code> is published, and extension and reuse are
+encouraged, whereas <code>JUnit4ClassRunner</code> was in an internal package,
+and is now deprecated.</p></li>
+</ul></li>
+<li><p><code>ParentRunner</code> is a base class for runners that iterate over
+a list of "children", each an object representing a test or suite to run.
+<code>ParentRunner</code> provides filtering, sorting, <code>@BeforeClass</code>, <code>@AfterClass</code>,
+and method validation to subclasses.</p></li>
+<li><p><code>TestClass</code> wraps a class to be run, providing efficient, repeated access
+to all methods with a given annotation.</p></li>
+<li><p>The new <code>RunnerBuilder</code> API allows extending the behavior of
+Suite-like custom runners.</p></li>
+<li><p><code>AssumptionViolatedException.toString()</code> is more informative</p></li>
+</ul>
+
+<h3>Extra Runners</h3>
+
+<ul>
+<li><p><code>Parameterized.eachOne()</code> has been removed</p></li>
+<li><p>New runner <code>Enclosed</code> runs all static inner classes of an outer class.</p></li>
+</ul>
+
+<h3>Theories</h3>
+
+<ul>
+<li><p><code>@Before</code> and <code>@After</code> methods are run before and after each set of attempted parameters
+on a Theory, and each set of parameters is run on a new instance of the test class.</p></li>
+<li><p>Exposed API's <code>ParameterSignature.getType()</code> and <code>ParameterSignature.getAnnotations()</code></p></li>
+<li><p>An array of data points can be introduced by a field or method
+marked with the new annotation <code>@DataPoints</code></p></li>
+<li><p>The Theories custom runner has been refactored to make it faster and
+easier to extend</p></li>
+</ul>
+
+<h3>Development</h3>
+
+<ul>
+<li><p>Source has been split into directories <code>src/main/java</code> and
+<code>src/test/java</code>, making it easier to exclude tests from builds, and
+making JUnit more maven-friendly</p></li>
+<li><p>Test classes in <code>org.junit.tests</code> have been organized into
+subpackages, hopefully making finding tests easier.</p></li>
+<li><p><code>ResultMatchers</code> has more informative descriptions.</p></li>
+<li><p><code>TestSystem</code> allows testing return codes and other system-level interactions.</p></li>
+</ul>
+
+<h2>Summary of Changes in version 4.4</h2>
+
+<p>JUnit is designed to efficiently capture developers' intentions about
+their code, and quickly check their code matches those intentions.
+Over the last year, we've been talking about what things developers
+would like to say about their code that have been difficult in the
+past, and how we can make them easier.</p>
+
+<h3>assertThat</h3>
+
+<p>Two years ago, Joe Walnes built a <a href="http://joe.truemesh.com/blog/000511.html">new assertion mechanism</a> on top of what was
+then <a href="http://www.jmock.org/download.html">JMock 1</a>. The method name was <code>assertThat</code>, and the syntax looked like this:</p>
+
+<pre><code>assertThat(x, is(3));
+assertThat(x, is(not(4)));
+assertThat(responseString, either(containsString("color")).or(containsString("colour")));
+assertThat(myList, hasItem("3"));
+</code></pre>
+
+<p>More generally:</p>
+
+<pre><code>assertThat([value], [matcher statement]);
+</code></pre>
+
+<p>Advantages of this assertion syntax include:</p>
+
+<ul>
+<li><p>More readable and typeable: this syntax allows you to think in terms of subject, verb, object
+(assert "x is 3") rathern than <code>assertEquals</code>, which uses verb, object, subject (assert "equals 3 x")</p></li>
+<li><p>Combinations: any matcher statement <code>s</code> can be negated (<code>not(s)</code>), combined (<code>either(s).or(t)</code>),
+mapped to a collection (<code>each(s)</code>), or used in custom combinations (<code>afterFiveSeconds(s)</code>)</p></li>
+<li><p>Readable failure messages. Compare</p>
+
+<pre><code>assertTrue(responseString.contains("color") || responseString.contains("colour"));
+// ==&gt; failure message:
+// java.lang.AssertionError:
+
+
+assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
+// ==&gt; failure message:
+// java.lang.AssertionError:
+// Expected: (a string containing "color" or a string containing "colour")
+// got: "Please choose a font"
+</code></pre></li>
+<li><p>Custom Matchers. By implementing the <code>Matcher</code> interface yourself, you can get all of the
+above benefits for your own custom assertions.</p></li>
+<li><p>For a more thorough description of these points, see <a href="http://joe.truemesh.com/blog/000511.html">Joe Walnes's
+original post</a>.:</p></li>
+</ul>
+
+<p>We have decided to include this API directly in JUnit.
+It's an extensible and readable syntax, and because it enables
+new features, like <a href="#assumptions">assumptions</a> and <a href="#theories">theories</a>.</p>
+
+<p>Some notes:</p>
+
+<ul>
+<li>The old assert methods are never, ever, going away. <br />
+Developers may continue using the old <code>assertEquals</code>, <code>assertTrue</code>, and
+so on.</li>
+<li><p>The second parameter of an <code>assertThat</code> statement is a <code>Matcher</code>.
+We include the Matchers we want as static imports, like this:</p>
+
+<pre><code>import static org.hamcrest.CoreMatchers.is;
+</code></pre>
+
+<p>or:</p>
+
+<pre><code>import static org.hamcrest.CoreMatchers.*;
+</code></pre></li>
+<li><p>Manually importing <code>Matcher</code> methods can be frustrating. [Eclipse
+3.3][] includes the ability to
+define
+"Favorite" classes to import static methods from, which makes it easier
+(Search for "Favorites" in the Preferences dialog).
+We expect that support for static imports will improve in all Java IDEs in the future.</p></li>
+<li><p>To allow compatibility with a wide variety of possible matchers,
+we have decided to include the classes from hamcrest-core,
+from the <a href="http://code.google.com/p/hamcrest/">Hamcrest</a> project. This is the first time that
+third-party classes have been included in JUnit. </p></li>
+<li><p>To allow developers to maintain full control of the classpath contents, the JUnit distribution also provides an unbundled junit-dep jar,
+ie without hamcrest-core classes included. This is intended for situations when using other libraries that also depend on hamcrest-core, to
+avoid classloading conflicts or issues. Developers using junit-dep should ensure a compatible version of hamcrest-core jar (ie 1.1+) is present in the classpath.</p></li>
+<li><p>JUnit currently ships with a few matchers, defined in
+<code>org.hamcrest.CoreMatchers</code> and <code>org.junit.matchers.JUnitMatchers</code>. <br />
+To use many, many more, consider downloading the <a href="http://hamcrest.googlecode.com/files/hamcrest-all-1.1.jar">full hamcrest package</a>.</p></li>
+<li><p>JUnit contains special support for comparing string and array
+values, giving specific information on how they differ. This is not
+yet available using the <code>assertThat</code> syntax, but we hope to bring
+the two assert methods into closer alignment in future releases.</p></li>
+</ul>
+
+<h3>assumeThat</h3>
+
+<p><a name="assumptions" />
+Ideally, the developer writing a test has control of all of the forces that might cause a test to fail.
+If this isn't immediately possible, making dependencies explicit can often improve a design. <br />
+For example, if a test fails when run in a different locale than the developer intended,
+it can be fixed by explicitly passing a locale to the domain code.</p>
+
+<p>However, sometimes this is not desirable or possible. <br />
+It's good to be able to run a test against the code as it is currently written,
+implicit assumptions and all, or to write a test that exposes a known bug.
+For these situations, JUnit now includes the ability to express "assumptions":</p>
+
+<pre><code>import static org.junit.Assume.*
+
+@Test public void filenameIncludesUsername() {
+ assumeThat(File.separatorChar, is('/'));
+ assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg"));
+}
+
+@Test public void correctBehaviorWhenFilenameIsNull() {
+ assumeTrue(bugFixed("13356")); // bugFixed is not included in JUnit
+ assertThat(parse(null), is(new NullDocument()));
+}
+</code></pre>
+
+<p>With this beta release, a failed assumption will lead to the test being marked as passing,
+regardless of what the code below the assumption may assert.
+In the future, this may change, and a failed assumption may lead to the test being ignored:
+however, third-party runners do not currently allow this option.</p>
+
+<p>We have included <code>assumeTrue</code> for convenience, but thanks to the
+inclusion of Hamcrest, we do not need to create <code>assumeEquals</code>,
+<code>assumeSame</code>, and other analogues to the <code>assert*</code> methods. All of
+those functionalities are subsumed in assumeThat, with the appropriate
+matcher.</p>
+
+<p>A failing assumption in a <code>@Before</code> or <code>@BeforeClass</code> method will have the same effect
+as a failing assumption in each <code>@Test</code> method of the class.</p>
+
+<h3>Theories</h3>
+
+<p><a name="theories" />
+More flexible and expressive assertions, combined with the ability to
+state assumptions clearly, lead to a new kind of statement of intent,
+which we call a "Theory". A test captures the intended behavior in
+one particular scenario. A theory allows a developer to be
+as precise as desired about the behavior of the code in possibly
+infinite numbers of possible scenarios. For example:</p>
+
+<pre><code>@RunWith(Theories.class)
+public class UserTest {
+ @DataPoint public static String GOOD_USERNAME = "optimus";
+ @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";
+
+ @Theory public void filenameIncludesUsername(String username) {
+ assumeThat(username, not(containsString("/")));
+ assertThat(new User(username).configFileName(), containsString(username));
+ }
+}
+</code></pre>
+
+<p>This makes it clear that the user's filename should be included in the
+config file name, only if it doesn't contain a slash. Another test
+or theory might define what happens when a username does contain a slash.</p>
+
+<p><code>UserTest</code> will attempt to run <code>filenameIncludesUsername</code> on
+every compatible <code>DataPoint</code> defined in the class. If any of the
+assumptions fail, the data point is silently ignored. If all of the
+assumptions pass, but an assertion fails, the test fails.</p>
+
+<p>The support for Theories has been absorbed from the <a href="http://popper.tigris.org">Popper</a>
+project, and <a href="http://popper.tigris.org/tutorial.html">more complete documentation</a> can be found
+there.</p>
+
+<p>Defining general statements in this way can jog the developer's memory
+about other potential data points and tests, also allows <a href="http://www.junitfactory.org">automated
+tools</a> to <a href="http://shareandenjoy.saff.net/2007/04/popper-and-junitfactory.html">search</a> for new, unexpected data
+points that expose bugs.</p>
+
+<h3>Other changes</h3>
+
+<p>This release contains other bug fixes and new features. Among them:</p>
+
+<ul>
+<li><p>Annotated descriptions</p>
+
+<p>Runner UIs, Filters, and Sorters operate on Descriptions of test
+methods and test classes. These Descriptions now include the
+annotations on the original Java source element, allowing for richer
+display of test results, and easier development of annotation-based
+filters.</p></li>
+<li><p>Bug fix (1715326): assertEquals now compares all Numbers using their
+native implementation of <code>equals</code>. This assertion, which passed in
+4.3, will now fail:</p>
+
+<p>assertEquals(new Integer(1), new Long(1));</p>
+
+<p>Non-integer Numbers (Floats, Doubles, BigDecimals, etc),
+which were compared incorrectly in 4.3, are now fixed.</p></li>
+<li><p><code>assertEquals(long, long)</code> and <code>assertEquals(double, double)</code> have
+been re-introduced to the <code>Assert</code> class, to take advantage of
+Java's native widening conversions. Therefore, this still passes:</p>
+
+<p>assertEquals(1, 1L);</p></li>
+<li><p>The default runner for JUnit 4 test classes has been refactored.
+The old version was named <code>TestClassRunner</code>, and the new is named
+<code>JUnit4ClassRunner</code>. Likewise, <code>OldTestClassRunner</code> is now
+<code>JUnit3ClassRunner</code>. The new design allows variations in running
+individual test classes to be expressed with fewer custom classes.
+For a good example, see the source to
+<code>org.junit.experimental.theories.Theories</code>.</p></li>
+<li><p>The rules for determining which runner is applied by default to a
+test class have been simplified:</p>
+
+<ol>
+<li><p>If the class has a <code>@RunWith</code> annotation, the annotated runner
+class is used.</p></li>
+<li><p>If the class can be run with the JUnit 3 test runner (it
+subclasses <code>TestCase</code>, or contains a <code>public static Test suite()</code>
+method), JUnit38ClassRunner is used.</p></li>
+<li><p>Otherwise, JUnit4ClassRunner is used.</p></li>
+</ol>
+
+<p>This default guess can always be overridden by an explicit
+<code>@RunWith(JUnit4ClassRunner.class)</code> or
+<code>@RunWith(JUnit38ClassRunner.class)</code> annotation.</p>
+
+<p>The old class names <code>TestClassRunner</code> and <code>OldTestClassRunner</code>
+remain as deprecated.</p></li>
+<li><p>Bug fix (1739095): Filters and Sorters work correctly on test
+classes that contain a <code>suite</code> method like:</p>
+
+<p>public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(MyTest.class);
+}</p></li>
+<li><p>Bug fix (1745048): @After methods are now correctly called
+after a test method times out.</p></li>
+</ul>
+
+<h2>
+<a NAME="Summary of"></a>Summary of Changes in version 4.3.1</h2>
+<p>
+<ul>
+<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>
+<a NAME="Summary of"></a>Summary of Changes with version 4.3</h2>
+<p>
+<ul>
+<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>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>
+</ul>
+</p>
+
+<h2>
+<a NAME="Summary of"></a>Summary of Changes with version 4.2</h2>
+<p>
+<ul>
+<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>
+<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>
+<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>
+<a NAME="Installation"></a>Installation</h2>
+Below are the installation steps for installing JUnit:
+<ol>
+<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>
+<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.
+<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>
+SimpleTest.java - some simple test cases</li>
+
+<li>
+VectorTest.java - test cases for java.util.Vector</li>
+</ul>
+
+<h2>
+<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
+with JUnit.
+<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/junit4/acknowledgements.txt b/junit4/acknowledgements.txt
new file mode 100644
index 0000000..4d7ee6c
--- /dev/null
+++ b/junit4/acknowledgements.txt
@@ -0,0 +1,159 @@
+2006 March 9
+ Matthias Schmidt: improved org.junit package javadoc
+
+2006 August 3
+ giovanni: better test for TestCase without a name.
+ Matthias Pfau: better error message when test case constructor fails
+
+2006 November 21
+ dakcalouro: Found defect with comparing ints and longs (1555161)
+ Ben Maurer: Found defect with timeouts taking twice as long as specified (1536198)
+
+2007 February 08
+ Kazimierz Pogoda: Found defect with null array elements (1438163)
+
+2007 July 09
+ wangqq: Found defect with @After not running after a timeout (1745048)
+
+2007 July 18
+ Andrew Dick: Found defect with assertEquals comparing non-Integer Numbers (1715326)
+ Michael Schechter: Found defect with Filters and suite() methods (1739095)
+
+2008 February 5
+ Walter Gildersleeve: Found assertEquals(null, "null") defect (1857283)
+
+2008 July 1
+ Johannes Link: Submitted test for running subclasses of Suite
+
+2008 July 23
+ Daniel Brolund: Submitted patch for build.xml, fixing 1.5 compatibility (2021396)
+
+2008 Aug 1
+ Nat Pryce: Found defect in treatment of validation errors from custom
+ subclasses of the legacy JUnit4ClassRunner.
+
+2008 Aug 18
+ Nir Soffer: Suggested adding to the cookbook information about running
+ running JUnit from the command line.
+
+2008 Aug 19
+ Jack Woehr: Discovered build.xml was missing from junit-4.x.zip
+
+2009 Jan 5
+ Amanda Robinson: Fixed overly permissive @DataPoint processing.
+
+2009 Feb 9
+ Mark Shapiro: Discovered bug in test counting after an ignored method (2106324)
+
+2009 Apr 20
+ Chris Felaco: Discovered regression in handling suite() methods with JUnit 3 runner (1812200)
+ Toby Byron: Suggested updating linking in javadoc (2090230)
+ Raphael Parree: Improved docs on Parameterized (2186792)
+ Robin de Silva Jayasinghe: Fixed Javadoc code sample for AfterClass (2126279)
+
+2009 May 04
+ James Abbley: Submitted a patch that fixed the 2-second limit on Parallel execution.
+
+2009 Nov 16
+ Kristian Rosenvold: Submitted a patch (github#16) that improves thread-safety of
+ result counting
+2010 Feb 08
+ Paul Holser: Submitted additional test for TestName rule.
+
+2010 May 03
+ jonas22@github: Found bug (github#98) with assumptions and expected exceptions.
+
+2011 Jan 03
+ jens.schauder@freenet.de: Found bug (github#74) with Categories and
+ Parameterized.
+
+2011 Jan 18
+ Markus Keller: Reported bug (github#163):
+ Bad comparison failure message when using assertEquals(String, String)
+
+ Kevin Cooney (kcooney@github):
+ Patches for runLeaf, public multiple failure exception,
+ assertion messages and null.
+
+2011 Mar 04
+ Jerome Lacoste (lacostej@github) for initial patch for GH-191.
+
+2011 Apr 15
+ reinholdfuereder@github For initial test for GH-39
+
+2011 Apr 15
+ ububenheimer@github for bug report https://github.com/KentBeck/junit/issues/208
+
+2011 Apr 29
+ reinholdfuereder@github: bug report, test, and fix for GH-38:
+ ParentRunner filtering
+2011 Apr 29
+ Markus Keller (mkeller@github): Report for GH-187:
+ Unintentional dependency on Java 6
+
+2011 May 31
+ Kevin Cooney (kcooney@github): Patches for filtering test suites:
+ copy List returned by getChildren() before mutating it;
+ optimize ParentRunner.filter for nested suites;
+ optimize Filter.intersect for common cases
+
+2011 Jun 06
+ Vampire@github: Report for GH-235: 4.7 release notes incorrect.
+
+2011 Jun 24
+ Samuel Le Berrigaud (sleberrigaud@github): Report for GH-248:
+ protected BlockJUnit4ClassRunner#rules method removed from 4.8.2
+
+2011 Jun 24
+ Daniel Rothmaler (drothmaler@github):
+ #299: random temp file/folder creation
+ #300: ErrorCollector.checkThat overload
+
+2011 Jul 06
+ Stefan Birkner: Fixed wrong documentation of ClassRule (github#254).
+
+2011 Jul 08
+ Paul Holser (pholser@alumni.rice.edu): Beginnings of fix for GH-64:
+ Theories doesn't honor parameterized types
+
+2011 Jul 09
+ Nigel Charman: Reported Rules bugs github#257 and gihub#258.
+
+2011 Jul 09
+ Stefan Birkner: Fixed rules bugs (github#257, gihub#258, github#260).
+
+2011 Jul 09
+ Stefan Birkner: Fixed rules bugs (github#257, gihub#258, github#260).
+
+2011 Jul 16
+ Rob Dawson: Submitted a patch that makes Results serlializable.
+
+2011 Jul 20
+ Asaf Ary, Stefan Birkner: Fixed FailOnTimeout class (github#265).
+
+2011 Jul 22
+ Andreas Köhler, Stefan Birkner: Fixed wrong documentation of Parameterized (github#89).
+
+2011 Jul 28
+ electrickery, Stefan Birkner: Fixed typo in JavaDoc (github#134).
+
+2011 Aug 07
+ Esko Luontola: Fixed TemporaryFolder creating files in the current working directory (github#278).
+
+2011 Aug 09
+ Stefan Birkner: Fixed JavaDoc links.
+
+2011 Aug 10
+ rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders.
+
+2011 Aug 12
+ Esko Luontola: Fixed syntax error in Parameterized's usage example (github#285).
+
+2011 Sep 09
+ Robert Munteanu, Stefan Birkner:
+ TestWatcher and TestWatchman don't call failed when assumption is violated (github#296).
+ digulla@github, Stefan Birkner: Removed useless code (github#289).
+
+== NOTE: as of September 2011, we have stopped recording contributions here.
+ For a full list of everyone who has contributed great bug reports and code, please see
+ http://github.com/KentBeck/junit
diff --git a/junit4/build.xml b/junit4/build.xml
new file mode 100644
index 0000000..8f69e91
--- /dev/null
+++ b/junit4/build.xml
@@ -0,0 +1,317 @@
+<project name="junit" default="dist" basedir="."
+ xmlns:artifact="antlib:org.apache.maven.artifact.ant">
+ <tstamp />
+ <taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
+
+ <property file="${user.home}/.junit.properties" />
+ <property name="src" value="src/main/java" />
+ <property name="target" location="target" />
+ <property name="bin" location="${target}/main" />
+ <property name="version-base" value="4.10" />
+ <property name="version-status" value="" />
+ <property name="version" value="${version-base}${version-status}" />
+ <property name="dist" value="junit${version}" />
+ <property name="versionfile" value="${src}/junit/runner/Version.java" />
+ <property name="zipfile" value="${dist}/${dist}.zip" />
+ <property name="testsrc" location="src/test/java" />
+ <property name="testbin" location="${target}/test/java" />
+ <property name="unjarred"
+ value="**/*.jar, ${testfiles}, doc/**, README.html, .classpath, .project, cpl-v10.html" />
+
+ <property name="binjar" value="junit-${version}.jar" />
+ <property name="srcjar" value="junit-${version}-src.jar" />
+ <property name="docjar" value="junit-${version}-javadoc.jar" />
+
+ <property name="depjar" value="junit-dep-${version}.jar" />
+ <property name="depsrcjar" value="junit-dep-${version}-src.jar" />
+ <property name="depdocjar" value="junit-dep-${version}-javadoc.jar" />
+
+ <property name="javadocdir" location="${dist}/javadoc" />
+ <property name="javadoczip" location="${dist}-javadoc.zip" />
+ <property name="hamcrestlib" location="lib/hamcrest-core-1.1.jar" />
+ <property name="hamcrestsrc" location="${dist}/temp.hamcrest.source" />
+
+ <target name="init">
+ <tstamp/>
+ </target>
+
+ <target name="versiontag" depends="init">
+ <filter token="version" value="${version}" />
+
+ <copy
+ file="${versionfile}.template"
+ tofile="${versionfile}"
+ filtering="on"
+ overwrite="true"
+ />
+ </target>
+
+ <target name="clean">
+ <!-- If two builds are made within a minute -->
+ <delete dir="${dist}" quiet="true" />
+ <!-- Delete all previous temporary build artifacts -->
+ <delete dir="${target}" quiet="true" />
+
+ <delete file="${zipfile}" quiet="true"/>
+ <delete file="${javadoczip}" />
+ </target>
+
+ <macrodef name="junit_compilation">
+ <attribute name="srcdir"/>
+ <attribute name="destdir"/>
+ <attribute name="classpath"/>
+ <sequential>
+ <mkdir dir="@{destdir}"/>
+ <javac
+ srcdir="@{srcdir}"
+ destdir="@{destdir}"
+ debug="on"
+ classpath="@{classpath}"
+ includeantruntime="false"
+ target="1.5"
+ >
+ <compilerarg value="-Xlint:unchecked" />
+ </javac>
+ </sequential>
+ </macrodef>
+
+ <target name="build" depends="versiontag">
+ <junit_compilation srcdir="${src}" destdir="${bin}" classpath="${hamcrestlib}"/>
+ <unjar src="${hamcrestlib}" dest="${bin}" />
+ <junit_compilation srcdir="${testsrc}" destdir="${testbin}" classpath="${hamcrestlib};${bin}"/>
+ </target>
+
+ <target name="jars" depends="build">
+ <mkdir dir="${dist}" />
+ <jar
+ jarfile="${dist}/${srcjar}"
+ basedir="${src}"
+ excludes="${unjarred}, **/*.class"
+ />
+ <jar
+ jarfile="${dist}/${binjar}"
+ basedir="${bin}"
+ excludes="${unjarred}, **/*.java, build.xml"
+ />
+ <jar
+ jarfile="${dist}/${depjar}"
+ basedir="${bin}"
+ excludes="${unjarred}, org/hamcrest/**, **/*.java, build.xml"
+ />
+ </target>
+
+ <target name="all.maven.jars" depends="jars,javadoc">
+ <mkdir dir="${dist}" />
+ <jar
+ jarfile="${dist}/${docjar}"
+ basedir="${javadocdir}"
+ excludes="${unjarred}"
+ />
+ <jar
+ jarfile="${dist}/${depsrcjar}"
+ basedir="${src}"
+ excludes="${unjarred}, **/*.class"
+ />
+ <jar
+ jarfile="${dist}/${depdocjar}"
+ basedir="${javadocdir}"
+ excludes="${unjarred}, org/hamcrest/**"
+ />
+ </target>
+
+ <target name="samples-and-tests">
+ <copy todir="${dist}">
+ <fileset dir="${testbin}" />
+ <fileset dir="${testsrc}" />
+ </copy>
+ </target>
+
+ <target name="unjar.hamcrest">
+ <unjar src="${hamcrestlib}" dest="${hamcrestsrc}" />
+ </target>
+
+ <target name="release-notes">
+ <property name="basename" value="doc/ReleaseNotes${version-base}" />
+ <exec executable="build/Markdown.pl" failonerror="true">
+ <arg file="${basename}.txt"/>
+ <redirector output="${basename}.html" />
+ </exec>
+ </target>
+
+ <target name="javadoc" depends="unjar.hamcrest">
+ <javadoc destdir="${javadocdir}"
+ author="false"
+ version="false"
+ use="false"
+ windowtitle="JUnit API"
+ stylesheetfile="stylesheet.css"
+ >
+ <excludepackage name="junit.*" />
+ <excludepackage name="org.junit.internal.*" />
+ <excludepackage name="org.junit.experimental.theories.internal.*" />
+
+ <sourcepath location="${src}" />
+ <sourcepath location="${hamcrestsrc}" />
+ <link href="http://java.sun.com/javase/6/docs/api/" />
+ </javadoc>
+ </target>
+
+ <target name="javadoczip">
+ <delete file="${javadoczip}" />
+ <antcall target="javadoc" />
+ <zip basedir="${javadocdir}" file="${javadoczip}" />
+ </target>
+
+ <target name="populate-dist"
+ depends="clean, build, jars, samples-and-tests, javadoc, release-notes"
+ >
+ <copy todir="${dist}/doc">
+ <fileset dir="doc"/>
+ </copy>
+ <copy file="README.html" tofile="${dist}/README.html" />
+ <copy file="BUILDING" tofile="${dist}/BUILDING" />
+ <copy file="cpl-v10.html" tofile="${dist}/cpl-v10.html" />
+ <copy file="build.xml" tofile="${dist}/build.xml" />
+ </target>
+
+ <macrodef name="run-tests">
+ <element name="extra-args" implicit="yes" />
+ <sequential>
+ <java classname="org.junit.runner.JUnitCore" fork="yes" failonerror="true">
+ <extra-args />
+ <arg value="org.junit.tests.AllTests"/>
+ <classpath>
+ <pathelement location="${dist}" />
+ <pathelement location="${dist}/${binjar}" />
+ </classpath>
+ </java>
+ </sequential>
+ </macrodef>
+
+ <target name="dist" depends="populate-dist">
+ <run-tests>
+ <jvmarg value="-Dignore.this=ignored" />
+ </run-tests>
+ </target>
+
+ <target name="profile" depends="populate-dist">
+ <run-tests>
+ <jvmarg value="-agentlib:hprof=cpu=samples"/>
+ </run-tests>
+ </target>
+
+ <target name="zip" depends="dist">
+ <zip zipfile="${zipfile}" basedir="." includes="${dist}/**" />
+ </target>
+
+ <target name="upload.to.sourceforge" depends="zip">
+ <ftp server="upload.sourceforge.net"
+ userid="anonymous"
+ password="saff@mit.edu"
+ remotedir="incoming"
+ >
+ <fileset dir="${dist}" includes="*.jar" />
+ <fileset file="${zipfile}" />
+ </ftp>
+ <echo message="To upload docs, use build/upload_docs.sh" />
+ </target>
+
+ <!-- to do automatic build upload, you need the maven ant tasks jar. -->
+ <!-- therefore, you must run ant as ant -lib build/lib stage.maven -->
+ <macrodef name="push.maven.jar">
+ <attribute name="jar" />
+ <attribute name="pom" />
+ <attribute name="url" />
+ <attribute name="repo.id" />
+ <element name="artifact.args" implicit="true" optional="true" />
+ <sequential>
+ <echo message="Pushing to maven: @{jar} -> @{url}" />
+ <artifact:mvn failonerror="true">
+ <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file" />
+ <arg value="-Durl=@{url}" />
+ <arg value="-DrepositoryId=@{repo.id}" />
+ <arg value="-DpomFile=@{pom}" />
+ <arg value="-Dfile=@{jar}" />
+ <artifact.args />
+ <arg value="-Pgpg" />
+ </artifact:mvn>
+ </sequential>
+ </macrodef>
+
+ <macrodef name="push.maven.artifact">
+ <attribute name="artifactId" />
+ <attribute name="url" />
+ <attribute name="repo.id" />
+ <attribute name="is.snapshot" default="false" />
+ <sequential>
+ <local name="m.prefix" />
+ <property name="m.prefix" value="${dist}/@{artifactId}-${version}" />
+ <local name="m.jar" />
+ <property name="m.jar" value="${m.prefix}.jar" />
+ <local name="m.sources.jar" />
+ <property name="m.sources.jar" value="${m.prefix}-src.jar" />
+ <local name="m.javadoc.jar" />
+ <property name="m.javadoc.jar" value="${m.prefix}-javadoc.jar" />
+ <local name="m.pom" />
+ <property name="m.pom" value="${dist}/pom-@{artifactId}.xml" />
+
+ <filter token="version" value="${version}" />
+ <filter token="artifactId" value="@{artifactId}" />
+
+ <copy
+ file="build/maven/pom-template.xml"
+ tofile="${m.pom}"
+ filtering="on"
+ overwrite="true"
+ />
+
+ <push.maven.jar jar="${m.jar}" pom="${m.pom}"
+ url="@{url}" repo.id="@{repo.id}" />
+
+ <if>
+ <equals arg1="${is.snapshot}" arg2="false" />
+ <then>
+ <push.maven.jar jar="${m.sources.jar}" pom="${m.pom}"
+ url="@{url}" repo.id="@{repo.id}">
+ <arg value="-Dclassifier=sources" />
+ </push.maven.jar>
+
+ <push.maven.jar jar="${m.javadoc.jar}" pom="${m.pom}"
+ url="@{url}" repo.id="@{repo.id}">
+ <arg value="-Dclassifier=javadoc" />
+ </push.maven.jar>
+ </then>
+ </if>
+ </sequential>
+ </macrodef>
+
+ <target name="stage.maven" depends="all.maven.jars">
+ <property name="stage.url"
+ value="https://oss.sonatype.org/service/local/staging/deploy/maven2/" />
+ <property name="stage.repo.id" value="sonatype-nexus-staging" />
+
+ <push.maven.artifact artifactId="junit"
+ url="${stage.url}"
+ repo.id="${stage.repo.id}" />
+ <push.maven.artifact artifactId="junit-dep"
+ url="${stage.url}"
+ repo.id="${stage.repo.id}" />
+ </target>
+
+ <target name="snapshot.maven" depends="all.maven.jars">
+ <property name="snapshot.url"
+ value="https://oss.sonatype.org/content/repositories/snapshots/" />
+ <property name="snapshot.repo.id" value="sonatype-nexus-snapshots" />
+
+ <push.maven.artifact artifactId="junit"
+ url="${snapshot.url}"
+ repo.id="${snapshot.repo.id}" />
+ <push.maven.artifact artifactId="junit-dep"
+ url="${snapshot.url}"
+ repo.id="${snapshot.repo.id}" />
+ </target>
+
+ <target name="print.version">
+ <echo message="${version}" />
+ </target>
+</project>
diff --git a/junit4/build/.cvsignore b/junit4/build/.cvsignore
new file mode 100644
index 0000000..5d6a3e2
--- /dev/null
+++ b/junit4/build/.cvsignore
@@ -0,0 +1,4 @@
+Changes
+java.hprof.txt
+historical_javadoc
+compare_with_44.sh
diff --git a/junit4/build/.releaserc b/junit4/build/.releaserc
new file mode 100644
index 0000000..b1dc30f
--- /dev/null
+++ b/junit4/build/.releaserc
@@ -0,0 +1,8 @@
+sf_user = dsaff
+sf_group_id = 15278
+sf_package_id = 226053
+cpan_user = <none>
+sf_release_match = junit-(.*).jar
+sf_release_replace = $1
+sf_type_id = 2601
+sf_processor_id = 8500 \ No newline at end of file
diff --git a/junit4/build/Markdown.pl b/junit4/build/Markdown.pl
new file mode 100644
index 0000000..e4c8469
--- /dev/null
+++ b/junit4/build/Markdown.pl
@@ -0,0 +1,1450 @@
+#!/usr/bin/perl
+
+#
+# Markdown -- A text-to-HTML conversion tool for web writers
+#
+# Copyright (c) 2004 John Gruber
+# <http://daringfireball.net/projects/markdown/>
+#
+
+
+package Markdown;
+require 5.006_000;
+use strict;
+use warnings;
+
+use Digest::MD5 qw(md5_hex);
+use vars qw($VERSION);
+$VERSION = '1.0.1';
+# Tue 14 Dec 2004
+
+## Disabled; causes problems under Perl 5.6.1:
+# use utf8;
+# binmode( STDOUT, ":utf8" ); # c.f.: http://acis.openlib.org/dev/perl-unicode-struggle.html
+
+
+#
+# Global default settings:
+#
+my $g_empty_element_suffix = " />"; # Change to ">" for HTML output
+my $g_tab_width = 4;
+
+
+#
+# Globals:
+#
+
+# Regex to match balanced [brackets]. See Friedl's
+# "Mastering Regular Expressions", 2nd Ed., pp. 328-331.
+my $g_nested_brackets;
+$g_nested_brackets = qr{
+ (?> # Atomic matching
+ [^\[\]]+ # Anything other than brackets
+ |
+ \[
+ (??{ $g_nested_brackets }) # Recursive set of nested brackets
+ \]
+ )*
+}x;
+
+
+# Table of hash values for escaped characters:
+my %g_escape_table;
+foreach my $char (split //, '\\`*_{}[]()>#+-.!') {
+ $g_escape_table{$char} = md5_hex($char);
+}
+
+
+# Global hashes, used by various utility routines
+my %g_urls;
+my %g_titles;
+my %g_html_blocks;
+
+# Used to track when we're inside an ordered or unordered list
+# (see _ProcessListItems() for details):
+my $g_list_level = 0;
+
+
+#### Blosxom plug-in interface ##########################################
+
+# Set $g_blosxom_use_meta to 1 to use Blosxom's meta plug-in to determine
+# which posts Markdown should process, using a "meta-markup: markdown"
+# header. If it's set to 0 (the default), Markdown will process all
+# entries.
+my $g_blosxom_use_meta = 0;
+
+sub start { 1; }
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ if ( (! $g_blosxom_use_meta) or
+ (defined($meta::markup) and ($meta::markup =~ /^\s*markdown\s*$/i))
+ ){
+ $$body_ref = Markdown($$body_ref);
+ }
+ 1;
+}
+
+
+#### Movable Type plug-in interface #####################################
+eval {require MT}; # Test to see if we're running in MT.
+unless ($@) {
+ require MT;
+ import MT;
+ require MT::Template::Context;
+ import MT::Template::Context;
+
+ eval {require MT::Plugin}; # Test to see if we're running >= MT 3.0.
+ unless ($@) {
+ require MT::Plugin;
+ import MT::Plugin;
+ my $plugin = new MT::Plugin({
+ name => "Markdown",
+ description => "A plain-text-to-HTML formatting plugin. (Version: $VERSION)",
+ doc_link => 'http://daringfireball.net/projects/markdown/'
+ });
+ MT->add_plugin( $plugin );
+ }
+
+ MT::Template::Context->add_container_tag(MarkdownOptions => sub {
+ my $ctx = shift;
+ my $args = shift;
+ my $builder = $ctx->stash('builder');
+ my $tokens = $ctx->stash('tokens');
+
+ if (defined ($args->{'output'}) ) {
+ $ctx->stash('markdown_output', lc $args->{'output'});
+ }
+
+ defined (my $str = $builder->build($ctx, $tokens) )
+ or return $ctx->error($builder->errstr);
+ $str; # return value
+ });
+
+ MT->add_text_filter('markdown' => {
+ label => 'Markdown',
+ docs => 'http://daringfireball.net/projects/markdown/',
+ on_format => sub {
+ my $text = shift;
+ my $ctx = shift;
+ my $raw = 0;
+ if (defined $ctx) {
+ my $output = $ctx->stash('markdown_output');
+ if (defined $output && $output =~ m/^html/i) {
+ $g_empty_element_suffix = ">";
+ $ctx->stash('markdown_output', '');
+ }
+ elsif (defined $output && $output eq 'raw') {
+ $raw = 1;
+ $ctx->stash('markdown_output', '');
+ }
+ else {
+ $raw = 0;
+ $g_empty_element_suffix = " />";
+ }
+ }
+ $text = $raw ? $text : Markdown($text);
+ $text;
+ },
+ });
+
+ # If SmartyPants is loaded, add a combo Markdown/SmartyPants text filter:
+ my $smartypants;
+
+ {
+ no warnings "once";
+ $smartypants = $MT::Template::Context::Global_filters{'smarty_pants'};
+ }
+
+ if ($smartypants) {
+ MT->add_text_filter('markdown_with_smartypants' => {
+ label => 'Markdown With SmartyPants',
+ docs => 'http://daringfireball.net/projects/markdown/',
+ on_format => sub {
+ my $text = shift;
+ my $ctx = shift;
+ if (defined $ctx) {
+ my $output = $ctx->stash('markdown_output');
+ if (defined $output && $output eq 'html') {
+ $g_empty_element_suffix = ">";
+ }
+ else {
+ $g_empty_element_suffix = " />";
+ }
+ }
+ $text = Markdown($text);
+ $text = $smartypants->($text, '1');
+ },
+ });
+ }
+}
+else {
+#### BBEdit/command-line text filter interface ##########################
+# Needs to be hidden from MT (and Blosxom when running in static mode).
+
+ # We're only using $blosxom::version once; tell Perl not to warn us:
+ no warnings 'once';
+ unless ( defined($blosxom::version) ) {
+ use warnings;
+
+ #### Check for command-line switches: #################
+ my %cli_opts;
+ use Getopt::Long;
+ Getopt::Long::Configure('pass_through');
+ GetOptions(\%cli_opts,
+ 'version',
+ 'shortversion',
+ 'html4tags',
+ );
+ if ($cli_opts{'version'}) { # Version info
+ print "\nThis is Markdown, version $VERSION.\n";
+ print "Copyright 2004 John Gruber\n";
+ print "http://daringfireball.net/projects/markdown/\n\n";
+ exit 0;
+ }
+ if ($cli_opts{'shortversion'}) { # Just the version number string.
+ print $VERSION;
+ exit 0;
+ }
+ if ($cli_opts{'html4tags'}) { # Use HTML tag style instead of XHTML
+ $g_empty_element_suffix = ">";
+ }
+
+
+ #### Process incoming text: ###########################
+ my $text;
+ {
+ local $/; # Slurp the whole file
+ $text = <>;
+ }
+ print Markdown($text);
+ }
+}
+
+
+
+sub Markdown {
+#
+# Main function. The order in which other subs are called here is
+# essential. Link and image substitutions need to happen before
+# _EscapeSpecialChars(), so that any *'s or _'s in the <a>
+# and <img> tags get encoded.
+#
+ my $text = shift;
+
+ # Clear the global hashes. If we don't clear these, you get conflicts
+ # from other articles when generating a page which contains more than
+ # one article (e.g. an index page that shows the N most recent
+ # articles):
+ %g_urls = ();
+ %g_titles = ();
+ %g_html_blocks = ();
+
+
+ # Standardize line endings:
+ $text =~ s{\r\n}{\n}g; # DOS to Unix
+ $text =~ s{\r}{\n}g; # Mac to Unix
+
+ # Make sure $text ends with a couple of newlines:
+ $text .= "\n\n";
+
+ # Convert all tabs to spaces.
+ $text = _Detab($text);
+
+ # Strip any lines consisting only of spaces and tabs.
+ # This makes subsequent regexen easier to write, because we can
+ # match consecutive blank lines with /\n+/ instead of something
+ # contorted like /[ \t]*\n+/ .
+ $text =~ s/^[ \t]+$//mg;
+
+ # Turn block-level HTML blocks into hash entries
+ $text = _HashHTMLBlocks($text);
+
+ # Strip link definitions, store in hashes.
+ $text = _StripLinkDefinitions($text);
+
+ $text = _RunBlockGamut($text);
+
+ $text = _UnescapeSpecialChars($text);
+
+ return $text . "\n";
+}
+
+
+sub _StripLinkDefinitions {
+#
+# Strips link definitions from text, stores the URLs and titles in
+# hash references.
+#
+ my $text = shift;
+ my $less_than_tab = $g_tab_width - 1;
+
+ # Link defs are in the form: ^[id]: url "optional title"
+ while ($text =~ s{
+ ^[ ]{0,$less_than_tab}\[(.+)\]: # id = $1
+ [ \t]*
+ \n? # maybe *one* newline
+ [ \t]*
+ <?(\S+?)>? # url = $2
+ [ \t]*
+ \n? # maybe one newline
+ [ \t]*
+ (?:
+ (?<=\s) # lookbehind for whitespace
+ ["(]
+ (.+?) # title = $3
+ [")]
+ [ \t]*
+ )? # title is optional
+ (?:\n+|\Z)
+ }
+ {}mx) {
+ $g_urls{lc $1} = _EncodeAmpsAndAngles( $2 ); # Link IDs are case-insensitive
+ if ($3) {
+ $g_titles{lc $1} = $3;
+ $g_titles{lc $1} =~ s/"/&quot;/g;
+ }
+ }
+
+ return $text;
+}
+
+
+sub _HashHTMLBlocks {
+ my $text = shift;
+ my $less_than_tab = $g_tab_width - 1;
+
+ # Hashify HTML blocks:
+ # We only want to do this for block-level HTML tags, such as headers,
+ # lists, and tables. That's because we still want to wrap <p>s around
+ # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
+ # phrase emphasis, and spans. The list of tags we're looking for is
+ # hard-coded:
+ my $block_tags_a = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del/;
+ my $block_tags_b = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math/;
+
+ # First, look for nested blocks, e.g.:
+ # <div>
+ # <div>
+ # tags for inner block must be indented.
+ # </div>
+ # </div>
+ #
+ # The outermost tags must start at the left margin for this to match, and
+ # the inner nested divs must be indented.
+ # We need to do this before the next, more liberal match, because the next
+ # match will start at the first `<div>` and stop at the first `</div>`.
+ $text =~ s{
+ ( # save in $1
+ ^ # start of line (with /m)
+ <($block_tags_a) # start tag = $2
+ \b # word break
+ (.*\n)*? # any number of lines, minimally matching
+ </\2> # the matching end tag
+ [ \t]* # trailing spaces/tabs
+ (?=\n+|\Z) # followed by a newline or end of document
+ )
+ }{
+ my $key = md5_hex($1);
+ $g_html_blocks{$key} = $1;
+ "\n\n" . $key . "\n\n";
+ }egmx;
+
+
+ #
+ # Now match more liberally, simply from `\n<tag>` to `</tag>\n`
+ #
+ $text =~ s{
+ ( # save in $1
+ ^ # start of line (with /m)
+ <($block_tags_b) # start tag = $2
+ \b # word break
+ (.*\n)*? # any number of lines, minimally matching
+ .*</\2> # the matching end tag
+ [ \t]* # trailing spaces/tabs
+ (?=\n+|\Z) # followed by a newline or end of document
+ )
+ }{
+ my $key = md5_hex($1);
+ $g_html_blocks{$key} = $1;
+ "\n\n" . $key . "\n\n";
+ }egmx;
+ # Special case just for <hr />. It was easier to make a special case than
+ # to make the other regex more complicated.
+ $text =~ s{
+ (?:
+ (?<=\n\n) # Starting after a blank line
+ | # or
+ \A\n? # the beginning of the doc
+ )
+ ( # save in $1
+ [ ]{0,$less_than_tab}
+ <(hr) # start tag = $2
+ \b # word break
+ ([^<>])*? #
+ /?> # the matching end tag
+ [ \t]*
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
+ )
+ }{
+ my $key = md5_hex($1);
+ $g_html_blocks{$key} = $1;
+ "\n\n" . $key . "\n\n";
+ }egx;
+
+ # Special case for standalone HTML comments:
+ $text =~ s{
+ (?:
+ (?<=\n\n) # Starting after a blank line
+ | # or
+ \A\n? # the beginning of the doc
+ )
+ ( # save in $1
+ [ ]{0,$less_than_tab}
+ (?s:
+ <!
+ (--.*?--\s*)+
+ >
+ )
+ [ \t]*
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
+ )
+ }{
+ my $key = md5_hex($1);
+ $g_html_blocks{$key} = $1;
+ "\n\n" . $key . "\n\n";
+ }egx;
+
+
+ return $text;
+}
+
+
+sub _RunBlockGamut {
+#
+# These are all the transformations that form block-level
+# tags like paragraphs, headers, and list items.
+#
+ my $text = shift;
+
+ $text = _DoHeaders($text);
+
+ # Do Horizontal Rules:
+ $text =~ s{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}{\n<hr$g_empty_element_suffix\n}gmx;
+ $text =~ s{^[ ]{0,2}([ ]? -[ ]?){3,}[ \t]*$}{\n<hr$g_empty_element_suffix\n}gmx;
+ $text =~ s{^[ ]{0,2}([ ]? _[ ]?){3,}[ \t]*$}{\n<hr$g_empty_element_suffix\n}gmx;
+
+ $text = _DoLists($text);
+
+ $text = _DoCodeBlocks($text);
+
+ $text = _DoBlockQuotes($text);
+
+ # We already ran _HashHTMLBlocks() before, in Markdown(), but that
+ # was to escape raw HTML in the original Markdown source. This time,
+ # we're escaping the markup we've just created, so that we don't wrap
+ # <p> tags around block-level tags.
+ $text = _HashHTMLBlocks($text);
+
+ $text = _FormParagraphs($text);
+
+ return $text;
+}
+
+
+sub _RunSpanGamut {
+#
+# These are all the transformations that occur *within* block-level
+# tags like paragraphs, headers, and list items.
+#
+ my $text = shift;
+
+ $text = _DoCodeSpans($text);
+
+ $text = _EscapeSpecialChars($text);
+
+ # Process anchor and image tags. Images must come first,
+ # because ![foo][f] looks like an anchor.
+ $text = _DoImages($text);
+ $text = _DoAnchors($text);
+
+ # Make links out of things like `<http://example.com/>`
+ # Must come after _DoAnchors(), because you can use < and >
+ # delimiters in inline links like [this](<url>).
+ $text = _DoAutoLinks($text);
+
+ $text = _EncodeAmpsAndAngles($text);
+
+ $text = _DoItalicsAndBold($text);
+
+ # Do hard breaks:
+ $text =~ s/ {2,}\n/ <br$g_empty_element_suffix\n/g;
+
+ return $text;
+}
+
+
+sub _EscapeSpecialChars {
+ my $text = shift;
+ my $tokens ||= _TokenizeHTML($text);
+
+ $text = ''; # rebuild $text from the tokens
+# my $in_pre = 0; # Keep track of when we're inside <pre> or <code> tags.
+# my $tags_to_skip = qr!<(/?)(?:pre|code|kbd|script|math)[\s>]!;
+
+ foreach my $cur_token (@$tokens) {
+ if ($cur_token->[0] eq "tag") {
+ # Within tags, encode * and _ so they don't conflict
+ # with their use in Markdown for italics and strong.
+ # We're replacing each such character with its
+ # corresponding MD5 checksum value; this is likely
+ # overkill, but it should prevent us from colliding
+ # with the escape values by accident.
+ $cur_token->[1] =~ s! \* !$g_escape_table{'*'}!gx;
+ $cur_token->[1] =~ s! _ !$g_escape_table{'_'}!gx;
+ $text .= $cur_token->[1];
+ } else {
+ my $t = $cur_token->[1];
+ $t = _EncodeBackslashEscapes($t);
+ $text .= $t;
+ }
+ }
+ return $text;
+}
+
+
+sub _DoAnchors {
+#
+# Turn Markdown link shortcuts into XHTML <a> tags.
+#
+ my $text = shift;
+
+ #
+ # First, handle reference-style links: [link text] [id]
+ #
+ $text =~ s{
+ ( # wrap whole match in $1
+ \[
+ ($g_nested_brackets) # link text = $2
+ \]
+
+ [ ]? # one optional space
+ (?:\n[ ]*)? # one optional newline followed by spaces
+
+ \[
+ (.*?) # id = $3
+ \]
+ )
+ }{
+ my $result;
+ my $whole_match = $1;
+ my $link_text = $2;
+ my $link_id = lc $3;
+
+ if ($link_id eq "") {
+ $link_id = lc $link_text; # for shortcut links like [this][].
+ }
+
+ if (defined $g_urls{$link_id}) {
+ my $url = $g_urls{$link_id};
+ $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid
+ $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold.
+ $result = "<a href=\"$url\"";
+ if ( defined $g_titles{$link_id} ) {
+ my $title = $g_titles{$link_id};
+ $title =~ s! \* !$g_escape_table{'*'}!gx;
+ $title =~ s! _ !$g_escape_table{'_'}!gx;
+ $result .= " title=\"$title\"";
+ }
+ $result .= ">$link_text</a>";
+ }
+ else {
+ $result = $whole_match;
+ }
+ $result;
+ }xsge;
+
+ #
+ # Next, inline-style links: [link text](url "optional title")
+ #
+ $text =~ s{
+ ( # wrap whole match in $1
+ \[
+ ($g_nested_brackets) # link text = $2
+ \]
+ \( # literal paren
+ [ \t]*
+ <?(.*?)>? # href = $3
+ [ \t]*
+ ( # $4
+ (['"]) # quote char = $5
+ (.*?) # Title = $6
+ \5 # matching quote
+ )? # title is optional
+ \)
+ )
+ }{
+ my $result;
+ my $whole_match = $1;
+ my $link_text = $2;
+ my $url = $3;
+ my $title = $6;
+
+ $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid
+ $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold.
+ $result = "<a href=\"$url\"";
+
+ if (defined $title) {
+ $title =~ s/"/&quot;/g;
+ $title =~ s! \* !$g_escape_table{'*'}!gx;
+ $title =~ s! _ !$g_escape_table{'_'}!gx;
+ $result .= " title=\"$title\"";
+ }
+
+ $result .= ">$link_text</a>";
+
+ $result;
+ }xsge;
+
+ return $text;
+}
+
+
+sub _DoImages {
+#
+# Turn Markdown image shortcuts into <img> tags.
+#
+ my $text = shift;
+
+ #
+ # First, handle reference-style labeled images: ![alt text][id]
+ #
+ $text =~ s{
+ ( # wrap whole match in $1
+ !\[
+ (.*?) # alt text = $2
+ \]
+
+ [ ]? # one optional space
+ (?:\n[ ]*)? # one optional newline followed by spaces
+
+ \[
+ (.*?) # id = $3
+ \]
+
+ )
+ }{
+ my $result;
+ my $whole_match = $1;
+ my $alt_text = $2;
+ my $link_id = lc $3;
+
+ if ($link_id eq "") {
+ $link_id = lc $alt_text; # for shortcut links like ![this][].
+ }
+
+ $alt_text =~ s/"/&quot;/g;
+ if (defined $g_urls{$link_id}) {
+ my $url = $g_urls{$link_id};
+ $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid
+ $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold.
+ $result = "<img src=\"$url\" alt=\"$alt_text\"";
+ if (defined $g_titles{$link_id}) {
+ my $title = $g_titles{$link_id};
+ $title =~ s! \* !$g_escape_table{'*'}!gx;
+ $title =~ s! _ !$g_escape_table{'_'}!gx;
+ $result .= " title=\"$title\"";
+ }
+ $result .= $g_empty_element_suffix;
+ }
+ else {
+ # If there's no such link ID, leave intact:
+ $result = $whole_match;
+ }
+
+ $result;
+ }xsge;
+
+ #
+ # Next, handle inline images: ![alt text](url "optional title")
+ # Don't forget: encode * and _
+
+ $text =~ s{
+ ( # wrap whole match in $1
+ !\[
+ (.*?) # alt text = $2
+ \]
+ \( # literal paren
+ [ \t]*
+ <?(\S+?)>? # src url = $3
+ [ \t]*
+ ( # $4
+ (['"]) # quote char = $5
+ (.*?) # title = $6
+ \5 # matching quote
+ [ \t]*
+ )? # title is optional
+ \)
+ )
+ }{
+ my $result;
+ my $whole_match = $1;
+ my $alt_text = $2;
+ my $url = $3;
+ my $title = '';
+ if (defined($6)) {
+ $title = $6;
+ }
+
+ $alt_text =~ s/"/&quot;/g;
+ $title =~ s/"/&quot;/g;
+ $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid
+ $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold.
+ $result = "<img src=\"$url\" alt=\"$alt_text\"";
+ if (defined $title) {
+ $title =~ s! \* !$g_escape_table{'*'}!gx;
+ $title =~ s! _ !$g_escape_table{'_'}!gx;
+ $result .= " title=\"$title\"";
+ }
+ $result .= $g_empty_element_suffix;
+
+ $result;
+ }xsge;
+
+ return $text;
+}
+
+
+sub _DoHeaders {
+ my $text = shift;
+
+ # Setext-style headers:
+ # Header 1
+ # ========
+ #
+ # Header 2
+ # --------
+ #
+ $text =~ s{ ^(.+)[ \t]*\n=+[ \t]*\n+ }{
+ "<h1>" . _RunSpanGamut($1) . "</h1>\n\n";
+ }egmx;
+
+ $text =~ s{ ^(.+)[ \t]*\n-+[ \t]*\n+ }{
+ "<h2>" . _RunSpanGamut($1) . "</h2>\n\n";
+ }egmx;
+
+
+ # atx-style headers:
+ # # Header 1
+ # ## Header 2
+ # ## Header 2 with closing hashes ##
+ # ...
+ # ###### Header 6
+ #
+ $text =~ s{
+ ^(\#{1,6}) # $1 = string of #'s
+ [ \t]*
+ (.+?) # $2 = Header text
+ [ \t]*
+ \#* # optional closing #'s (not counted)
+ \n+
+ }{
+ my $h_level = length($1);
+ "<h$h_level>" . _RunSpanGamut($2) . "</h$h_level>\n\n";
+ }egmx;
+
+ return $text;
+}
+
+
+sub _DoLists {
+#
+# Form HTML ordered (numbered) and unordered (bulleted) lists.
+#
+ my $text = shift;
+ my $less_than_tab = $g_tab_width - 1;
+
+ # Re-usable patterns to match list item bullets and number markers:
+ my $marker_ul = qr/[*+-]/;
+ my $marker_ol = qr/\d+[.]/;
+ my $marker_any = qr/(?:$marker_ul|$marker_ol)/;
+
+ # Re-usable pattern to match any entirel ul or ol list:
+ my $whole_list = qr{
+ ( # $1 = whole list
+ ( # $2
+ [ ]{0,$less_than_tab}
+ (${marker_any}) # $3 = first list item marker
+ [ \t]+
+ )
+ (?s:.+?)
+ ( # $4
+ \z
+ |
+ \n{2,}
+ (?=\S)
+ (?! # Negative lookahead for another list item marker
+ [ \t]*
+ ${marker_any}[ \t]+
+ )
+ )
+ )
+ }mx;
+
+ # We use a different prefix before nested lists than top-level lists.
+ # See extended comment in _ProcessListItems().
+ #
+ # Note: There's a bit of duplication here. My original implementation
+ # created a scalar regex pattern as the conditional result of the test on
+ # $g_list_level, and then only ran the $text =~ s{...}{...}egmx
+ # substitution once, using the scalar as the pattern. This worked,
+ # everywhere except when running under MT on my hosting account at Pair
+ # Networks. There, this caused all rebuilds to be killed by the reaper (or
+ # perhaps they crashed, but that seems incredibly unlikely given that the
+ # same script on the same server ran fine *except* under MT. I've spent
+ # more time trying to figure out why this is happening than I'd like to
+ # admit. My only guess, backed up by the fact that this workaround works,
+ # is that Perl optimizes the substition when it can figure out that the
+ # pattern will never change, and when this optimization isn't on, we run
+ # afoul of the reaper. Thus, the slightly redundant code to that uses two
+ # static s/// patterns rather than one conditional pattern.
+
+ if ($g_list_level) {
+ $text =~ s{
+ ^
+ $whole_list
+ }{
+ my $list = $1;
+ my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol";
+ # Turn double returns into triple returns, so that we can make a
+ # paragraph for the last item in a list, if necessary:
+ $list =~ s/\n{2,}/\n\n\n/g;
+ my $result = _ProcessListItems($list, $marker_any);
+ $result = "<$list_type>\n" . $result . "</$list_type>\n";
+ $result;
+ }egmx;
+ }
+ else {
+ $text =~ s{
+ (?:(?<=\n\n)|\A\n?)
+ $whole_list
+ }{
+ my $list = $1;
+ my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol";
+ # Turn double returns into triple returns, so that we can make a
+ # paragraph for the last item in a list, if necessary:
+ $list =~ s/\n{2,}/\n\n\n/g;
+ my $result = _ProcessListItems($list, $marker_any);
+ $result = "<$list_type>\n" . $result . "</$list_type>\n";
+ $result;
+ }egmx;
+ }
+
+
+ return $text;
+}
+
+
+sub _ProcessListItems {
+#
+# Process the contents of a single ordered or unordered list, splitting it
+# into individual list items.
+#
+
+ my $list_str = shift;
+ my $marker_any = shift;
+
+
+ # The $g_list_level global keeps track of when we're inside a list.
+ # Each time we enter a list, we increment it; when we leave a list,
+ # we decrement. If it's zero, we're not in a list anymore.
+ #
+ # We do this because when we're not inside a list, we want to treat
+ # something like this:
+ #
+ # I recommend upgrading to version
+ # 8. Oops, now this line is treated
+ # as a sub-list.
+ #
+ # As a single paragraph, despite the fact that the second line starts
+ # with a digit-period-space sequence.
+ #
+ # Whereas when we're inside a list (or sub-list), that line will be
+ # treated as the start of a sub-list. What a kludge, huh? This is
+ # an aspect of Markdown's syntax that's hard to parse perfectly
+ # without resorting to mind-reading. Perhaps the solution is to
+ # change the syntax rules such that sub-lists must start with a
+ # starting cardinal number; e.g. "1." or "a.".
+
+ $g_list_level++;
+
+ # trim trailing blank lines:
+ $list_str =~ s/\n{2,}\z/\n/;
+
+
+ $list_str =~ s{
+ (\n)? # leading line = $1
+ (^[ \t]*) # leading whitespace = $2
+ ($marker_any) [ \t]+ # list marker = $3
+ ((?s:.+?) # list item text = $4
+ (\n{1,2}))
+ (?= \n* (\z | \2 ($marker_any) [ \t]+))
+ }{
+ my $item = $4;
+ my $leading_line = $1;
+ my $leading_space = $2;
+
+ if ($leading_line or ($item =~ m/\n{2,}/)) {
+ $item = _RunBlockGamut(_Outdent($item));
+ }
+ else {
+ # Recursion for sub-lists:
+ $item = _DoLists(_Outdent($item));
+ chomp $item;
+ $item = _RunSpanGamut($item);
+ }
+
+ "<li>" . $item . "</li>\n";
+ }egmx;
+
+ $g_list_level--;
+ return $list_str;
+}
+
+
+
+sub _DoCodeBlocks {
+#
+# Process Markdown `<pre><code>` blocks.
+#
+
+ my $text = shift;
+
+ $text =~ s{
+ (?:\n\n|\A)
+ ( # $1 = the code block -- one or more lines, starting with a space/tab
+ (?:
+ (?:[ ]{$g_tab_width} | \t) # Lines must start with a tab or a tab-width of spaces
+ .*\n+
+ )+
+ )
+ ((?=^[ ]{0,$g_tab_width}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
+ }{
+ my $codeblock = $1;
+ my $result; # return value
+
+ $codeblock = _EncodeCode(_Outdent($codeblock));
+ $codeblock = _Detab($codeblock);
+ $codeblock =~ s/\A\n+//; # trim leading newlines
+ $codeblock =~ s/\s+\z//; # trim trailing whitespace
+
+ $result = "\n\n<pre><code>" . $codeblock . "\n</code></pre>\n\n";
+
+ $result;
+ }egmx;
+
+ return $text;
+}
+
+
+sub _DoCodeSpans {
+#
+# * Backtick quotes are used for <code></code> spans.
+#
+# * You can use multiple backticks as the delimiters if you want to
+# include literal backticks in the code span. So, this input:
+#
+# Just type ``foo `bar` baz`` at the prompt.
+#
+# Will translate to:
+#
+# <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
+#
+# There's no arbitrary limit to the number of backticks you
+# can use as delimters. If you need three consecutive backticks
+# in your code, use four for delimiters, etc.
+#
+# * You can use spaces to get literal backticks at the edges:
+#
+# ... type `` `bar` `` ...
+#
+# Turns to:
+#
+# ... type <code>`bar`</code> ...
+#
+
+ my $text = shift;
+
+ $text =~ s@
+ (`+) # $1 = Opening run of `
+ (.+?) # $2 = The code block
+ (?<!`)
+ \1 # Matching closer
+ (?!`)
+ @
+ my $c = "$2";
+ $c =~ s/^[ \t]*//g; # leading whitespace
+ $c =~ s/[ \t]*$//g; # trailing whitespace
+ $c = _EncodeCode($c);
+ "<code>$c</code>";
+ @egsx;
+
+ return $text;
+}
+
+
+sub _EncodeCode {
+#
+# Encode/escape certain characters inside Markdown code runs.
+# The point is that in code, these characters are literals,
+# and lose their special Markdown meanings.
+#
+ local $_ = shift;
+
+ # Encode all ampersands; HTML entities are not
+ # entities within a Markdown code span.
+ s/&/&amp;/g;
+
+ # Encode $'s, but only if we're running under Blosxom.
+ # (Blosxom interpolates Perl variables in article bodies.)
+ {
+ no warnings 'once';
+ if (defined($blosxom::version)) {
+ s/\$/&#036;/g;
+ }
+ }
+
+
+ # Do the angle bracket song and dance:
+ s! < !&lt;!gx;
+ s! > !&gt;!gx;
+
+ # Now, escape characters that are magic in Markdown:
+ s! \* !$g_escape_table{'*'}!gx;
+ s! _ !$g_escape_table{'_'}!gx;
+ s! { !$g_escape_table{'{'}!gx;
+ s! } !$g_escape_table{'}'}!gx;
+ s! \[ !$g_escape_table{'['}!gx;
+ s! \] !$g_escape_table{']'}!gx;
+ s! \\ !$g_escape_table{'\\'}!gx;
+
+ return $_;
+}
+
+
+sub _DoItalicsAndBold {
+ my $text = shift;
+
+ # <strong> must go first:
+ $text =~ s{ (\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1 }
+ {<strong>$2</strong>}gsx;
+
+ $text =~ s{ (\*|_) (?=\S) (.+?) (?<=\S) \1 }
+ {<em>$2</em>}gsx;
+
+ return $text;
+}
+
+
+sub _DoBlockQuotes {
+ my $text = shift;
+
+ $text =~ s{
+ ( # Wrap whole match in $1
+ (
+ ^[ \t]*>[ \t]? # '>' at the start of a line
+ .+\n # rest of the first line
+ (.+\n)* # subsequent consecutive lines
+ \n* # blanks
+ )+
+ )
+ }{
+ my $bq = $1;
+ $bq =~ s/^[ \t]*>[ \t]?//gm; # trim one level of quoting
+ $bq =~ s/^[ \t]+$//mg; # trim whitespace-only lines
+ $bq = _RunBlockGamut($bq); # recurse
+
+ $bq =~ s/^/ /g;
+ # These leading spaces screw with <pre> content, so we need to fix that:
+ $bq =~ s{
+ (\s*<pre>.+?</pre>)
+ }{
+ my $pre = $1;
+ $pre =~ s/^ //mg;
+ $pre;
+ }egsx;
+
+ "<blockquote>\n$bq\n</blockquote>\n\n";
+ }egmx;
+
+
+ return $text;
+}
+
+
+sub _FormParagraphs {
+#
+# Params:
+# $text - string to process with html <p> tags
+#
+ my $text = shift;
+
+ # Strip leading and trailing lines:
+ $text =~ s/\A\n+//;
+ $text =~ s/\n+\z//;
+
+ my @grafs = split(/\n{2,}/, $text);
+
+ #
+ # Wrap <p> tags.
+ #
+ foreach (@grafs) {
+ unless (defined( $g_html_blocks{$_} )) {
+ $_ = _RunSpanGamut($_);
+ s/^([ \t]*)/<p>/;
+ $_ .= "</p>";
+ }
+ }
+
+ #
+ # Unhashify HTML blocks
+ #
+ foreach (@grafs) {
+ if (defined( $g_html_blocks{$_} )) {
+ $_ = $g_html_blocks{$_};
+ }
+ }
+
+ return join "\n\n", @grafs;
+}
+
+
+sub _EncodeAmpsAndAngles {
+# Smart processing for ampersands and angle brackets that need to be encoded.
+
+ my $text = shift;
+
+ # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
+ # http://bumppo.net/projects/amputator/
+ $text =~ s/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/&amp;/g;
+
+ # Encode naked <'s
+ $text =~ s{<(?![a-z/?\$!])}{&lt;}gi;
+
+ return $text;
+}
+
+
+sub _EncodeBackslashEscapes {
+#
+# Parameter: String.
+# Returns: The string, with after processing the following backslash
+# escape sequences.
+#
+ local $_ = shift;
+
+ s! \\\\ !$g_escape_table{'\\'}!gx; # Must process escaped backslashes first.
+ s! \\` !$g_escape_table{'`'}!gx;
+ s! \\\* !$g_escape_table{'*'}!gx;
+ s! \\_ !$g_escape_table{'_'}!gx;
+ s! \\\{ !$g_escape_table{'{'}!gx;
+ s! \\\} !$g_escape_table{'}'}!gx;
+ s! \\\[ !$g_escape_table{'['}!gx;
+ s! \\\] !$g_escape_table{']'}!gx;
+ s! \\\( !$g_escape_table{'('}!gx;
+ s! \\\) !$g_escape_table{')'}!gx;
+ s! \\> !$g_escape_table{'>'}!gx;
+ s! \\\# !$g_escape_table{'#'}!gx;
+ s! \\\+ !$g_escape_table{'+'}!gx;
+ s! \\\- !$g_escape_table{'-'}!gx;
+ s! \\\. !$g_escape_table{'.'}!gx;
+ s{ \\! }{$g_escape_table{'!'}}gx;
+
+ return $_;
+}
+
+
+sub _DoAutoLinks {
+ my $text = shift;
+
+ $text =~ s{<((https?|ftp):[^'">\s]+)>}{<a href="$1">$1</a>}gi;
+
+ # Email addresses: <address@domain.foo>
+ $text =~ s{
+ <
+ (?:mailto:)?
+ (
+ [-.\w]+
+ \@
+ [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
+ )
+ >
+ }{
+ _EncodeEmailAddress( _UnescapeSpecialChars($1) );
+ }egix;
+
+ return $text;
+}
+
+
+sub _EncodeEmailAddress {
+#
+# Input: an email address, e.g. "foo@example.com"
+#
+# Output: the email address as a mailto link, with each character
+# of the address encoded as either a decimal or hex entity, in
+# the hopes of foiling most address harvesting spam bots. E.g.:
+#
+# <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;
+# x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;
+# &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>
+#
+# Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
+# mailing list: <http://tinyurl.com/yu7ue>
+#
+
+ my $addr = shift;
+
+ srand;
+ my @encode = (
+ sub { '&#' . ord(shift) . ';' },
+ sub { '&#x' . sprintf( "%X", ord(shift) ) . ';' },
+ sub { shift },
+ );
+
+ $addr = "mailto:" . $addr;
+
+ $addr =~ s{(.)}{
+ my $char = $1;
+ if ( $char eq '@' ) {
+ # this *must* be encoded. I insist.
+ $char = $encode[int rand 1]->($char);
+ } elsif ( $char ne ':' ) {
+ # leave ':' alone (to spot mailto: later)
+ my $r = rand;
+ # roughly 10% raw, 45% hex, 45% dec
+ $char = (
+ $r > .9 ? $encode[2]->($char) :
+ $r < .45 ? $encode[1]->($char) :
+ $encode[0]->($char)
+ );
+ }
+ $char;
+ }gex;
+
+ $addr = qq{<a href="$addr">$addr</a>};
+ $addr =~ s{">.+?:}{">}; # strip the mailto: from the visible part
+
+ return $addr;
+}
+
+
+sub _UnescapeSpecialChars {
+#
+# Swap back in all the special characters we've hidden.
+#
+ my $text = shift;
+
+ while( my($char, $hash) = each(%g_escape_table) ) {
+ $text =~ s/$hash/$char/g;
+ }
+ return $text;
+}
+
+
+sub _TokenizeHTML {
+#
+# Parameter: String containing HTML markup.
+# Returns: Reference to an array of the tokens comprising the input
+# string. Each token is either a tag (possibly with nested,
+# tags contained therein, such as <a href="<MTFoo>">, or a
+# run of text between tags. Each element of the array is a
+# two-element array; the first is either 'tag' or 'text';
+# the second is the actual value.
+#
+#
+# Derived from the _tokenize() subroutine from Brad Choate's MTRegex plugin.
+# <http://www.bradchoate.com/past/mtregex.php>
+#
+
+ my $str = shift;
+ my $pos = 0;
+ my $len = length $str;
+ my @tokens;
+
+ my $depth = 6;
+ my $nested_tags = join('|', ('(?:<[a-z/!$](?:[^<>]') x $depth) . (')*>)' x $depth);
+ my $match = qr/(?s: <! ( -- .*? -- \s* )+ > ) | # comment
+ (?s: <\? .*? \?> ) | # processing instruction
+ $nested_tags/ix; # nested tags
+
+ while ($str =~ m/($match)/g) {
+ my $whole_tag = $1;
+ my $sec_start = pos $str;
+ my $tag_start = $sec_start - length $whole_tag;
+ if ($pos < $tag_start) {
+ push @tokens, ['text', substr($str, $pos, $tag_start - $pos)];
+ }
+ push @tokens, ['tag', $whole_tag];
+ $pos = pos $str;
+ }
+ push @tokens, ['text', substr($str, $pos, $len - $pos)] if $pos < $len;
+ \@tokens;
+}
+
+
+sub _Outdent {
+#
+# Remove one level of line-leading tabs or spaces
+#
+ my $text = shift;
+
+ $text =~ s/^(\t|[ ]{1,$g_tab_width})//gm;
+ return $text;
+}
+
+
+sub _Detab {
+#
+# Cribbed from a post by Bart Lateur:
+# <http://www.nntp.perl.org/group/perl.macperl.anyperl/154>
+#
+ my $text = shift;
+
+ $text =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge;
+ return $text;
+}
+
+
+1;
+
+__END__
+
+
+=pod
+
+=head1 NAME
+
+B<Markdown>
+
+
+=head1 SYNOPSIS
+
+B<Markdown.pl> [ B<--html4tags> ] [ B<--version> ] [ B<-shortversion> ]
+ [ I<file> ... ]
+
+
+=head1 DESCRIPTION
+
+Markdown is a text-to-HTML filter; it translates an easy-to-read /
+easy-to-write structured text format into HTML. Markdown's text format
+is most similar to that of plain text email, and supports features such
+as headers, *emphasis*, code blocks, blockquotes, and links.
+
+Markdown's syntax is designed not as a generic markup language, but
+specifically to serve as a front-end to (X)HTML. You can use span-level
+HTML tags anywhere in a Markdown document, and you can use block level
+HTML tags (like <div> and <table> as well).
+
+For more information about Markdown's syntax, see:
+
+ http://daringfireball.net/projects/markdown/
+
+
+=head1 OPTIONS
+
+Use "--" to end switch parsing. For example, to open a file named "-z", use:
+
+ Markdown.pl -- -z
+
+=over 4
+
+
+=item B<--html4tags>
+
+Use HTML 4 style for empty element tags, e.g.:
+
+ <br>
+
+instead of Markdown's default XHTML style tags, e.g.:
+
+ <br />
+
+
+=item B<-v>, B<--version>
+
+Display Markdown's version number and copyright information.
+
+
+=item B<-s>, B<--shortversion>
+
+Display the short-form version number.
+
+
+=back
+
+
+
+=head1 BUGS
+
+To file bug reports or feature requests (other than topics listed in the
+Caveats section above) please send email to:
+
+ support@daringfireball.net
+
+Please include with your report: (1) the example input; (2) the output
+you expected; (3) the output Markdown actually produced.
+
+
+=head1 VERSION HISTORY
+
+See the readme file for detailed release notes for this version.
+
+1.0.1 - 14 Dec 2004
+
+1.0 - 28 Aug 2004
+
+
+=head1 AUTHOR
+
+ John Gruber
+ http://daringfireball.net
+
+ PHP port and other contributions by Michel Fortin
+ http://michelf.com
+
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2003-2004 John Gruber
+<http://daringfireball.net/>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name "Markdown" nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as
+is" and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed. In no event shall the copyright owner
+or contributors be liable for any direct, indirect, incidental, special,
+exemplary, or consequential damages (including, but not limited to,
+procurement of substitute goods or services; loss of use, data, or
+profits; or business interruption) however caused and on any theory of
+liability, whether in contract, strict liability, or tort (including
+negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+=cut
diff --git a/junit4/build/github_upload.rb b/junit4/build/github_upload.rb
new file mode 100644
index 0000000..ad5df46
--- /dev/null
+++ b/junit4/build/github_upload.rb
@@ -0,0 +1,211 @@
+# require
+require 'rubygems'
+
+#### INLINE: fixed version of https://github.com/github/upload ####
+
+require 'tempfile'
+require 'nokogiri'
+require 'httpclient'
+require 'stringio'
+require 'json'
+require 'faster_xml_simple'
+
+module Net
+ module GitHub
+ class Upload
+ VERSION = '0.0.5'
+ def initialize params=nil
+ @login = params[:login]
+ @token = params[:token]
+
+ if @login.empty? or @token.empty?
+ raise "login or token is empty"
+ end
+ end
+
+ def upload info
+ unless info[:repos]
+ raise "required repository name"
+ end
+ info[:repos] = @login + '/' + info[:repos] unless info[:repos].include? '/'
+
+ if info[:file]
+ file = info[:file]
+ unless File.exist?(file) && File.readable?(file)
+ raise "file does not exsits or readable"
+ end
+ info[:name] ||= File.basename(file)
+ end
+ unless info[:file] || info[:data]
+ raise "required file or data parameter to upload"
+ end
+
+ unless info[:name]
+ raise "required name parameter for filename with data parameter"
+ end
+
+ if info[:replace]
+ list_files(info[:repos]).each { |obj|
+ next unless obj[:name] == info[:name]
+ delete info[:repos], obj[:id]
+ }
+ elsif list_files(info[:repos]).any?{|obj| obj[:name] == info[:name]}
+ raise "file '#{info[:name]}' is already uploaded. please try different name"
+ end
+
+ info[:content_type] ||= 'application/octet-stream'
+ stat = HTTPClient.post("https://github.com/#{info[:repos]}/downloads", {
+ "file_size" => info[:file] ? File.stat(info[:file]).size : info[:data].size,
+ "content_type" => info[:content_type],
+ "file_name" => info[:name],
+ "description" => info[:description] || '',
+ "login" => @login,
+ "token" => @token
+ })
+
+ unless stat.code == 200
+ raise "Failed to post file info"
+ end
+
+ upload_info = JSON.parse(stat.content)
+ if info[:file]
+ f = File.open(info[:file], 'rb')
+ else
+ f = Tempfile.open('net-github-upload')
+ f << info[:data]
+ f.flush
+ end
+ stat = HTTPClient.post("http://github.s3.amazonaws.com/", [
+ ['Filename', info[:name]],
+ ['policy', upload_info['policy']],
+ ['success_action_status', 201],
+ ['key', upload_info['path']],
+ ['AWSAccessKeyId', upload_info['accesskeyid']],
+ ['Content-Type', upload_info['content_type'] || 'application/octet-stream'],
+ ['signature', upload_info['signature']],
+ ['acl', upload_info['acl']],
+ ['file', f]
+ ])
+ f.close
+
+ if stat.code == 201
+ return FasterXmlSimple.xml_in(stat.content)['PostResponse']['Location']
+ else
+ raise 'Failed to upload' + extract_error_message(stat)
+ end
+ end
+
+ def replace info
+ upload info.merge( :replace => true )
+ end
+
+ def delete_all repos
+ unless repos
+ raise "required repository name"
+ end
+ repos = @login + '/' + repos unless repos.include? '/'
+ list_files(repos).each { |obj|
+ delete repos, obj[:id]
+ }
+ end
+
+ private
+
+ def extract_error_message(stat)
+ # @see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/ErrorResponses.html
+ error = FasterXmlSimple.xml_in(stat.content)['Error']
+ " due to #{error['Code']} (#{error['Message']})"
+ rescue
+ ''
+ end
+
+ def delete repos, id
+ HTTPClient.post("https://github.com/#{repos}/downloads/#{id.gsub( "download_", '')}", {
+ "_method" => "delete",
+ "login" => @login,
+ "token" => @token
+ })
+ end
+
+ def list_files repos
+ raise "required repository name" unless repos
+ res = HTTPClient.get_content("https://github.com/#{repos}/downloads", {
+ "login" => @login,
+ "token" => @token
+ })
+ Nokogiri::HTML(res).xpath('id("manual_downloads")/li').map do |fileinfo|
+ obj = {
+ :description => fileinfo.at_xpath('descendant::h4').text,
+ :date => fileinfo.at_xpath('descendant::p/time').attribute('title').text,
+ :size => fileinfo.at_xpath('descendant::p/strong').text,
+ :id => /\d+$/.match(fileinfo.at_xpath('a').attribute('href').text)[0]
+ }
+ anchor = fileinfo.at_xpath('descendant::h4/a')
+ obj[:link] = anchor.attribute('href').text
+ obj[:name] = anchor.text
+ obj
+ end
+ end
+ end
+ end
+end
+
+#### END INLINE ####
+
+# setup
+login = `git config github.user`.chomp # your login for github
+token = `git config github.token`.chomp # your token for github
+repos = 'KentBeck/junit' # your repos name (like 'taberareloo')
+gh = Net::GitHub::Upload.new(
+ :login => login,
+ :token => token
+)
+
+version = ARGV[0]
+
+def upload(gh, version, repos, filename, description)
+ gh.upload(:repos => repos,
+ :file => "junit#{version}/#{filename}",
+ :description => description)
+end
+
+upload(gh, version, repos, "junit-#{version}-src.jar", 'Source jar')
+upload(gh, version, repos, "junit-#{version}.jar", 'Basic jar')
+upload(gh, version, repos, "junit-dep-#{version}.jar", 'Jar without hamcrest')
+upload(gh, version, repos, "junit#{version}.zip", 'Source zip')
+
+# # file upload
+# direct_link = gh.upload(
+# :repos => repos,
+# :file => 'test/test',
+# :description => "test file"
+# )
+# # direct link is link to Amazon S3.
+# # Because GitHub refrection for file changing is async,
+# # if you get changed file synchronously, you use this "direct_link"
+#
+# # data upload
+# # you can define content_type => Amazon S3 Content-Type
+# time = Time.now.to_i
+# direct_link = gh.upload(
+# :repos => repos,
+# :data => 'test',
+# :name => "test_#{time}.txt",
+# :content_type => 'text/plain',
+# :description => "test file2"
+# )
+#
+# # replace file or data
+# # thx id:rngtng !
+# direct_link = gh.replace(
+# :repos => repos,
+# :file => 'test/test',
+# :description => "test file"
+# )
+# direct_link = gh.replace(
+# :repos => repos,
+# :data => 'test',
+# :name => "test_#{time}.txt",
+# :content_type => 'text/plain',
+# :description => "test file2"
+# )
diff --git a/junit4/build/lib/ant-contrib-1.0b3.jar b/junit4/build/lib/ant-contrib-1.0b3.jar
new file mode 100644
index 0000000..0625376
--- /dev/null
+++ b/junit4/build/lib/ant-contrib-1.0b3.jar
Binary files differ
diff --git a/junit4/build/lib/commons-net-1.4.1.jar b/junit4/build/lib/commons-net-1.4.1.jar
new file mode 100644
index 0000000..9666a92
--- /dev/null
+++ b/junit4/build/lib/commons-net-1.4.1.jar
Binary files differ
diff --git a/junit4/build/lib/jakarta-oro-2.0.8.jar b/junit4/build/lib/jakarta-oro-2.0.8.jar
new file mode 100644
index 0000000..23488d2
--- /dev/null
+++ b/junit4/build/lib/jakarta-oro-2.0.8.jar
Binary files differ
diff --git a/junit4/build/lib/maven-ant-tasks-2.1.1.jar b/junit4/build/lib/maven-ant-tasks-2.1.1.jar
new file mode 100644
index 0000000..7810a54
--- /dev/null
+++ b/junit4/build/lib/maven-ant-tasks-2.1.1.jar
Binary files differ
diff --git a/junit4/build/maven/pom-template.xml b/junit4/build/maven/pom-template.xml
new file mode 100644
index 0000000..0f8ed50
--- /dev/null
+++ b/junit4/build/maven/pom-template.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>junit</groupId>
+ <artifactId>@artifactId@</artifactId>
+ <version>@version@</version>
+ <name>JUnit</name>
+ <url>http://junit.org</url>
+ <description>
+ JUnit is a regression testing framework written by Erich Gamma and Kent Beck.
+ It is used by the developer who implements unit tests in Java.
+ </description>
+ <organization>
+ <name>JUnit</name>
+ <url>http://www.junit.org</url>
+ </organization>
+ <mailingLists>
+ <mailingList>
+ <name>JUnit Mailing List</name>
+ <post>junit@yahoogroups.com</post>
+ <archive>
+ http://tech.groups.yahoo.com/group/junit/
+ </archive>
+ </mailingList>
+ </mailingLists>
+ <licenses>
+ <license>
+ <name>Common Public License Version 1.0</name>
+ <url>http://www.opensource.org/licenses/cpl1.0.txt</url>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:git:git://github.com/KentBeck/junit.git</connection>
+ <developerConnection>scm:git:git@github.com:KentBeck/junit.git</developerConnection>
+ <url>http://github.com/KentBeck/junit/tree/master</url>
+ </scm>
+ <developers>
+ <developer>
+ <id>dsaff</id>
+ <name>David Saff</name>
+ <email>david@saff.net</email>
+ </developer>
+ </developers>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <encoding>ISO-8859-1</encoding>
+ <source>${jdk.version}</source>
+ <target>${jdk.version}</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-core</artifactId>
+ <version>1.1</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <properties>
+ <jdk.version>1.5</jdk.version>
+ </properties>
+</project> \ No newline at end of file
diff --git a/junit4/build/maven/post_maven_tests.sh b/junit4/build/maven/post_maven_tests.sh
new file mode 100644
index 0000000..c7510f5
--- /dev/null
+++ b/junit4/build/maven/post_maven_tests.sh
@@ -0,0 +1,49 @@
+set -e
+set -o pipefail
+
+function TEST_junit_dep_49_plays_not_nicely_with_later_hamcrest {
+ # Make sure our system notices the bug (this broke because of a bad push)
+ ! runs_with_newer_hamcrest junit-dep 4.9
+}
+
+function TEST_junit_dep_snapshot_plays_nicely_with_later_hamcrest {
+ runs_with_newer_hamcrest junit-dep LATEST
+}
+
+function TEST_junit_snapshot_plays_not_nicely_with_later_hamcrest {
+ ! runs_with_newer_hamcrest junit LATEST
+}
+
+function runs_with_newer_hamcrest {
+ local artifact_id=$1
+ local version=$2
+ rm -rf ~/.m2/repository/junit
+ rm -rf uses_junit
+ cp -r sample_project_template uses_junit
+ sed -i '' -e "s/___ARTIFACT_ID___/$artifact_id/" uses_junit/pom.xml
+ sed -i '' -e "s/___VERSION___/$version/" uses_junit/pom.xml
+ in_dir uses_junit mvn test
+ finally rm -rf uses_junit
+}
+
+### <copied src="https://gist.github.com/1206506">
+function in_dir {
+ local dir=$1
+ shift
+ if [ ! -e $dir ]; then
+ echo "$dir does not exist"
+ return 1
+ fi
+ pushd $dir >/dev/null
+ "$@"
+ finally popd >/dev/null
+}
+
+function finally {
+ local return_this=$?
+ "$@"
+ return $return_this
+}
+### </copied>
+
+source ../run_tests.sh \ No newline at end of file
diff --git a/junit4/build/maven/sample_project_template/pom.xml b/junit4/build/maven/sample_project_template/pom.xml
new file mode 100644
index 0000000..5d8c6f7
--- /dev/null
+++ b/junit4/build/maven/sample_project_template/pom.xml
@@ -0,0 +1,61 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.example</groupId>
+ <artifactId>junit-dependency-test</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <version.hamcrest>1.2.1</version.hamcrest>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>___ARTIFACT_ID___</artifactId>
+ <version>___VERSION___</version>
+ </dependency>
+
+ <!--
+ This dependency must be included *before* junit, because said JAR
+ contains an old hamcrest-core version. This is problematic at
+ runtime; see JunitDependencyTest.
+ If junit-dep has the right contents, the order should not matter.
+ -->
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-core</artifactId>
+ <version>${version.hamcrest}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ <version>${version.hamcrest}</version>
+ </dependency>
+ </dependencies>
+
+ <repositories>
+ <repository>
+ <id>Sonatype</id>
+ <url>https://oss.sonatype.org/content/groups/public</url>
+ <snapshots><enabled>true</enabled></snapshots>
+ <releases><enabled>true</enabled></releases>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/junit4/build/maven/sample_project_template/src/test/java/JunitDependencyTest.java b/junit4/build/maven/sample_project_template/src/test/java/JunitDependencyTest.java
new file mode 100644
index 0000000..f6db3f5
--- /dev/null
+++ b/junit4/build/maven/sample_project_template/src/test/java/JunitDependencyTest.java
@@ -0,0 +1,33 @@
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+public final class JunitDependencyTest {
+ /**
+ * JUnit dependency test.
+ *
+ * This class has three dependencies. These can be on the classpath in
+ * different orders. Of the two orderings below, the first one will cause a
+ * NoSuchMethodError, while the second one allows the test to pass
+ * successfully. See the explanation below for more information.
+ *
+ * Ordering 1: junit-4.9, hamcrest-core-1.2.1, hamcrest-library-1.2.1.
+ * Ordering 2: hamcrest-core-1.2.1, junit-4.9, hamcrest-library-1.2.1.
+ */
+ @Test
+ public void test() {
+ /*
+ * Note that we call Matchers#anyOf(Matcher<T>, Matcher<? super T>).
+ * This method is provided by hamcrest-library-1.2.1. Said module is
+ * compiled against hamcrest-core-1.2.1. Matchers#anyOf calls
+ * AnyOf#anyOf(Matcher<T>, Matcher<? super T>). The latter method is
+ * provided by hamcrest-core-1.2.1, but *not* by hamcrest-core-1.1.
+ *
+ * However, hamcrest-core-1.1 *does* contain a class called AnyOf. Now,
+ * since junit-4.9 incorporates hamcrest-core-1.1 we must make sure that
+ * hamcrest-core-1.2.1 is placed *before* junit-4.9 on the classpath.
+ * Failure to do so will cause the wrong AnyOf class to be used. The
+ * result is a NoSuchMethodError.
+ */
+ Matchers.anyOf(Matchers.nullValue(), Matchers.notNullValue());
+ }
+}
diff --git a/junit4/build/profile_junit.sh b/junit4/build/profile_junit.sh
new file mode 100644
index 0000000..660dcc0
--- /dev/null
+++ b/junit4/build/profile_junit.sh
@@ -0,0 +1,2 @@
+java -classpath ../bin:../lib/hamcrest-core-1.1.jar -agentlib:hprof=cpu=samples,depth=18 org.junit.runner.JUnitCore org.junit.tests.AllTests
+cat java.hprof.txt \ No newline at end of file
diff --git a/junit4/build/release b/junit4/build/release
new file mode 100644
index 0000000..53bdf75
--- /dev/null
+++ b/junit4/build/release
@@ -0,0 +1,389 @@
+#!/usr/bin/perl
+
+eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if 0; # not running under some shell
+use strict;
+use warnings;
+
+# $Id: release,v 1.1 2007/09/04 17:59:38 dsaff Exp $
+
+=head1 NAME
+
+release - upload files to the CPAN and SourceForge.net
+
+=head1 SYNOPSIS
+
+ release [ LOCAL_FILE [ REMOTE_FILE ] ]
+
+ # try a dry run without uploading anything
+ release -t
+
+ # print a help message
+ release -h
+
+ # print debugging information
+ release -d
+
+=head1 DESCRIPTION
+
+This is the prototype program for using Module::Release. You should
+modify it to fit your needs.
+
+This program automates Perl module releases. It makes the
+distribution, tests it, checks that source control is up to date, tags
+source control, uploads it to the PAUSE anonymous FTP directory and to
+the incoming directory for SourceForge.net, claims it on PAUSE for
+your CPAN account, and releases it on SourceForge.net.
+
+By default this script assumes that you use CVS, but recognizes SVN
+and switches when appropriate.
+
+=head2 Process
+
+The release script checks many things before it actually releases the
+file. Some of these are annoying, but they are also the last line of
+defense against releasing bad distributions.
+
+=over 4
+
+=item Read the configuration data
+
+Look in the current working directory for C<.releaserc>. See the
+Configuration section. If release cannot find the configuration file,
+it dies.
+
+=item Test and make the distribution
+
+Run make realclean, perl Makefile.PL, make test, make dist, make
+disttest. If testing fails, release dies. make dist provides the
+name of the distribution if LOCAL_FILE is not provided on the command
+line.
+
+=item Check that source control is up-to-date
+
+If there are modified files, added files, or extra files so that
+source control complains, fail.
+
+=item Upload to PAUSE and SourceForge.net
+
+Simply drop the distribution in the incoming/ directory of these
+servers.
+
+=item Claim the file on PAUSE
+
+Connect to the PAUSE web thingy and claim the uploaded file for your
+CPAN account.
+
+=item Tag the repository
+
+Use the version number (in the distribution name) to tag the
+repository. You should be able to checkout the code from any release.
+
+=item Release to SourceForge.net
+
+The release name is the distribution name without the .tar.gz. The
+file name is the distribution name. SourceForge.net divides things
+into projects (with project IDs) and packages within the project (with
+package IDs). Specify these in the configuration file.
+
+=back
+
+=head2 Configuration
+
+The release script uses a configuration file in the current working
+directory. The file name is F<.releaserc>. Although most of the
+information is the same for all of your projects, the C<sf_package_id>
+is probably different. You can get the C<sf_package_id> from the data
+in the Quick Release Form.
+
+release's own F<.releaserc> looks like this:
+
+ sf_user comdog
+ sf_group_id 36221
+ sf_package_id 56559
+ cpan_user BDFOY
+
+=over 4
+
+=item cpan_user
+
+=item sf_user
+
+If C<cpan_user> or C<sf_user> is set to C<< <none> >>, the program will
+skip releasing for that system. You must release for at least one system.
+
+=item sf_group_id
+
+=item sf_package_id
+
+=item sf_processor_id
+
+=item sf_type_id
+
+=item sf_release_match
+
+=item sf_release_replace
+
+To find C<sf_package_id> and C<sf_group_id>, go to the Add/Edit
+Release page for your project. The link for "[Add Release]" might
+look something like this (this is the link for the F<release> package
+itself):
+
+ https://sourceforge.net/project/admin/newrelease.php?package_id=56559&group_id=36221
+
+so C<sf_package_id> is 56559 and C<sf_group_id> is 36221.
+
+C<sf_processor_id> and C<sf_type_id> are optional, and default to "Any"
+and "Source .gz". See the HTML in a file release form on SourceForge.net
+for other options.
+
+C<sf_release_match> and C<sf_release_replace> are for defining the release
+name, if you don't like the default. For example, the default would
+set the name for this program to something like "release-0.10".
+But if you want the name to be only the version number, set
+C<sf_release_match=^.+-([\d.]+)$> and C<sf_release_replace=$1>.
+
+=item passive_ftp
+
+Set C<passive_ftp> to "y" or "yes" for passive FTP transfers. Usually
+this is to get around a firewall issue.
+
+=item release_subclass
+
+Specify the name of a subclass to use instead of Module::Release. The
+subclass can override any of the Module::Release methods. This makes
+it possible to maintain your own local releasing procedures. For
+instance, one such subclass might look like this:
+
+ package Module::Release::KWILLIAMS;
+ use base qw(Module::Release);
+
+ sub make_cvs_tag {
+ my $self = shift;
+ (my $version) = $self->{remote} =~ / - (\d[\w.]*) \.tar \.gz $/x;
+ $version =~ s/[^a-z0-9_]/_/gi;
+ return "release-$version";
+ }
+ 1;
+
+To use this subclass, you'd put it in your C<@INC> somewhere, then set
+C<release_subclass> to C<Module::Release::KWILLIAMS>.
+
+=back
+
+=head2 Environment
+
+=over 4
+
+=item * CPAN_PASS
+
+=item * SF_PASS
+
+release reads the C<CPAN_PASS> and C<SF_PASS> environment variables to
+set the passwords for PAUSE and SourceForge.net, respectively. Of course,
+you don't need to set the password for a system you're not uploading to.
+
+=item * RELEASE_DEBUG
+
+The C<RELEASE_DEBUG> environment variable sets the debugging value,
+which is 0 by default. Set C<RELEASE_DEBUG> to a true value to get
+debugging output.
+
+=item * PERL
+
+The C<PERL> environment variable sets the path to perl for use in the
+make; otherwise, the perl used to run release will be used.
+
+=back
+
+=head1 TO DO
+
+=over 4
+
+=item * check make disttest (to catch MANIFEST errors) -- needs error catching and reporting
+
+=back
+
+=head1 SOURCE AVAILABILITY
+
+This source is part of a SourceForge.net project which always has the
+latest sources in CVS, as well as all of the previous releases.
+
+ http://sourceforge.net/projects/brian-d-foy/
+
+If, for some reason, I disappear from the world, one of the other
+members of the project can shepherd this software appropriately.
+
+=head1 AUTHOR
+
+brian d foy, C<< <bdfoy@cpan.org> >>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2002-2007, brian d foy, All rights reserved.
+
+You may use this software under the same terms as Perl itself.
+
+=head1 CREDITS
+
+Ken Williams turned the original release(1) script into a module.
+
+Andy Lester contributed to the module and script.
+
+=cut
+
+use Getopt::Std;
+use Module::Release;
+
+my $class = "Module::Release";
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+my %opts;
+getopts('hdt', \%opts) or $opts{h} = 1;
+
+if( $opts{h} )
+ {
+ print <<"USE";
+
+Use: release -hdt [ LOCAL_FILE [ REMOTE_FILE ] ]
+
+Will upload current release LOCAL_FILE, naming it REMOTE_FILE. Will
+get LOCAL_FILE and REMOTE_FILE automatically (using same name for
+both) if not supplied.
+
+ -h This help
+ -d Print extra debugging information
+ -t Just make and test distribution, don't tag/upload
+
+The program works in the current directory, and looks for a .releaserc
+or releaserc file and the environment for its preferences. See
+`perldoc $0`, for more information.
+
+USE
+
+ exit;
+ }
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+if( -d '.svn' )
+ {
+ $class = "Module::Release::Subversion";
+
+ print STDERR "I see an .svn directory, so I'm loading $class"
+ if $opts{d};
+
+ eval "use Module::Release::Subversion";
+ die "Could not load $class: $@\n" if $@;
+ }
+
+my( $script_version ) =
+ sprintf "%1.%02d", q$Revision: 1.1 $ =~ m/ (\d+) /xg;
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+my %params;
+$params{local} = shift @ARGV if @ARGV;
+
+if( @ARGV )
+ {
+ $params{remote} = shift @ARGV;
+ }
+elsif( $params{local} )
+ {
+ $params{remote} = $params{local};
+ }
+
+$params{debug} = 1 if $opts{d};
+
+my $release = $class->new( %params );
+
+print STDERR "release $script_version, using $class " . $class->VERSION . "\n"
+ if $release->debug;
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+$release->clean;
+$release->build_makefile;
+$release->test;
+$release->dist;
+$release->check_kwalitee;
+$release->dist_test;
+# $release->check_cvs;
+
+my $Version = $release->dist_version;
+
+print STDERR "dist version is $Version\n" if $release->debug;
+
+exit if $opts{t};
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+my $Changes = do {
+ my $changes = "Changes";
+ my $bak = $changes . ".bak";
+
+ die "Changes file does not exist!\n" unless -e $changes;
+
+ print "\n", "-" x 73, "\n", "Enter Changes section\n\n> ";
+
+ my $str = $Version . " - " . localtime() . "\n";
+
+ while( <STDIN> )
+ {
+ $_ =~ s/^(\S)/\t$1/; # always indent
+
+ $str .= $_;
+ print "> ";
+ }
+
+ $str .= "\n";
+
+ rename $changes, $bak or die "Could not backup $changes. $!\n";
+ open my $in, $bak or die "Could not read old $changes file! $!\n";
+ open my $out, ">", $changes;
+
+ while( <$in> )
+ {
+ print $out $_;
+ last unless m/\S/;
+ }
+
+ print $out $str;
+
+ print $out $_ while( <$in> );
+
+ close $in;
+ close $out;
+
+ my $command = do {
+ if( -d 'CVS' ) { 'cvs' }
+ elsif( -d '.svn' ) { 'svn' }
+ };
+
+ my $cvs_commit = `$command commit -m "* for version $Version" 2>&1`;
+
+ print $cvs_commit;
+
+ $str;
+ };
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+$release->clean;
+$release->build_makefile;
+$release->dist;
+
+$release->check_for_passwords;
+$release->ftp_upload;
+$release->pause_claim;
+$release->cvs_tag;
+
+$release->sf_login;
+$release->sf_qrs;
+$release->sf_release;
+
+print "Done.\n";
+
+__END__
diff --git a/junit4/build/run_tests.sh b/junit4/build/run_tests.sh
new file mode 100644
index 0000000..79b96fd
--- /dev/null
+++ b/junit4/build/run_tests.sh
@@ -0,0 +1,36 @@
+# See maven/post_maven_tests.sh for an example use
+
+SCRIPT_NAME=$0
+TEST_NAME=${1:-ALL}
+
+function get_tests() {
+ if [ $TEST_NAME == "ALL" ]; then
+ part1=function
+ part2=TEST_
+ grep "$part1 $part2" $SCRIPT_NAME | sed 's/.*\(TEST_[A-Za-z0-9_]*\).*/\1/'
+ else
+ echo "TEST_${TEST_NAME}"
+ fi
+}
+
+function run_tests() {
+ local exit_code=0
+
+ for t in $(get_tests); do
+ echo "RUNNING: $t"
+ if "$t"; then
+ echo "PASSED: $t"
+ else
+ echo "FAILED: $t"
+ return 1
+ fi
+ done
+}
+
+if run_tests; then
+ echo "ALL TESTS PASSED"
+ exit 0
+else
+ echo "A TEST FAILED"
+ exit 1
+fi
diff --git a/junit4/build/upload_docs.sh b/junit4/build/upload_docs.sh
new file mode 100644
index 0000000..b9f402b
--- /dev/null
+++ b/junit4/build/upload_docs.sh
@@ -0,0 +1,2 @@
+scp -r ../doc/* dsaff@web.sourceforge.net:/home/groups/j/ju/junit/htdocs/doc
+scp ../doc/homepage.html dsaff@web.sourceforge.net:/home/groups/j/ju/junit/htdocs/index.html \ No newline at end of file
diff --git a/junit4/build_tests.sh b/junit4/build_tests.sh
new file mode 100644
index 0000000..d6485e5
--- /dev/null
+++ b/junit4/build_tests.sh
@@ -0,0 +1,76 @@
+set -e
+set -o pipefail
+
+function TEST_BUILDING_in_zip {
+ version=$(get_junit_version)
+ ant zip
+ unzip -l junit${version}/junit${version}.zip | grep BUILDING >/dev/null
+}
+
+function TEST_get_junit_version {
+ version=$(get_junit_version)
+ if [[ ! ($version == 4.*) ]]; then
+ echo "Bad version: $version"
+ return 1
+ fi
+}
+
+function TEST_ant_dist {
+ version=$(get_junit_version)
+ ant dist
+ ls junit${version}/junit-${version}.jar
+}
+
+function TEST_ant_profile {
+ rm -rf java.hprof.txt
+ ant profile
+ ls java.hprof.txt
+}
+
+function TEST_jars {
+ version=$(get_junit_version)
+ binjar=junit${version}/junit-${version}.jar
+ srcjar=junit${version}/junit-${version}-src.jar
+ depjar=junit${version}/junit-dep-${version}.jar
+
+ ant clean
+ ant jars
+
+ jar tf $binjar | grep -q class \
+ && jar tf $srcjar | grep -q java \
+ && jar tf $depjar | grep -q class \
+ && jar tf $depjar | not grep hamcrest
+}
+
+function TEST_all_maven_jars {
+ version=$(get_junit_version)
+ binjar=junit${version}/junit-${version}.jar
+ srcjar=junit${version}/junit-${version}-src.jar
+ docjar=junit${version}/junit-${version}-javadoc.jar
+ depbin=junit${version}/junit-dep-${version}.jar
+ depsrc=junit${version}/junit-dep-${version}-src.jar
+ depdoc=junit${version}/junit-dep-${version}-javadoc.jar
+
+ ant clean
+ ant all.maven.jars
+
+ jar tf $binjar | grep -q class \
+ && jar tf $srcjar | grep -q java \
+ && jar tf $docjar | grep -q html \
+ && jar tf $depbin | grep -q class \
+ && jar tf $depsrc | grep -q java \
+ && jar tf $depdoc | grep -q html \
+ && jar tf $depbin | not grep hamcrest \
+ && jar tf $depsrc | not grep hamcrest \
+ && jar tf $depdoc | not grep hamcrest
+}
+
+function not {
+ ! "$@"
+}
+
+function get_junit_version {
+ ant print.version | grep echo | sed 's/.*echo..\([1-9].*\)/\1/'
+}
+
+source build/run_tests.sh \ No newline at end of file
diff --git a/junit4/cpl-v10.html b/junit4/cpl-v10.html
new file mode 100644
index 0000000..36aa208
--- /dev/null
+++ b/junit4/cpl-v10.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<HTML>
+<HEAD>
+<TITLE>Common Public License - v 1.0</TITLE>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</HEAD>
+
+<BODY BGCOLOR="#FFFFFF" VLINK="#800000">
+
+
+<P ALIGN="CENTER"><B>Common Public License - v 1.0</B>
+<P><B></B><FONT SIZE="3"></FONT>
+<P><FONT SIZE="3"></FONT><FONT SIZE="2">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>1. DEFINITIONS</B></FONT>
+<P><FONT SIZE="2">"Contribution" means:</FONT>
+
+<UL><FONT SIZE="2">a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and<BR CLEAR="LEFT">
+b) in the case of each subsequent Contributor:</FONT></UL>
+
+
+<UL><FONT SIZE="2">i) changes to the Program, and</FONT></UL>
+
+
+<UL><FONT SIZE="2">ii) additions to the Program;</FONT></UL>
+
+
+<UL><FONT SIZE="2">where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. </FONT><FONT SIZE="2">A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. </FONT><FONT SIZE="2">Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. </FONT></UL>
+
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Contributor" means any person or entity that distributes the Program.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. </FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">"Program" means the Contributions distributed in accordance with this Agreement.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.</FONT>
+<P><FONT SIZE="2"><B></B></FONT>
+<P><FONT SIZE="2"><B>2. GRANT OF RIGHTS</B></FONT>
+
+<UL><FONT SIZE="2"></FONT><FONT SIZE="2">a) </FONT><FONT SIZE="2">Subject to the terms of this Agreement, each Contributor hereby grants</FONT><FONT SIZE="2"> Recipient a non-exclusive, worldwide, royalty-free copyright license to</FONT><FONT SIZE="2" COLOR="#FF0000"> </FONT><FONT SIZE="2">reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.</FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT><FONT SIZE="2">b) Subject to the terms of this Agreement, each Contributor hereby grants </FONT><FONT SIZE="2">Recipient a non-exclusive, worldwide,</FONT><FONT SIZE="2" COLOR="#008000"> </FONT><FONT SIZE="2">royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. </FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2">c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.</FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+
+<UL><FONT SIZE="2">d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. </FONT></UL>
+
+
+<UL><FONT SIZE="2"></FONT></UL>
+
+<P><FONT SIZE="2"><B>3. REQUIREMENTS</B></FONT>
+<P><FONT SIZE="2"><B></B>A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:</FONT>
+
+<UL><FONT SIZE="2">a) it complies with the terms and conditions of this Agreement; and</FONT></UL>
+
+
+<UL><FONT SIZE="2">b) its license agreement:</FONT></UL>
+
+
+<UL><FONT SIZE="2">i) effectively disclaims</FONT><FONT SIZE="2"> on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; </FONT></UL>
+
+
+<UL><FONT SIZE="2">ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; </FONT></UL>
+
+
+<UL><FONT SIZE="2">iii)</FONT><FONT SIZE="2"> states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and</FONT></UL>
+
+
+<UL><FONT SIZE="2">iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.</FONT><FONT SIZE="2" COLOR="#0000FF"> </FONT><FONT SIZE="2" COLOR="#FF0000"></FONT></UL>
+
+
+<UL><FONT SIZE="2" COLOR="#FF0000"></FONT><FONT SIZE="2"></FONT></UL>
+
+<P><FONT SIZE="2">When the Program is made available in source code form:</FONT>
+
+<UL><FONT SIZE="2">a) it must be made available under this Agreement; and </FONT></UL>
+
+
+<UL><FONT SIZE="2">b) a copy of this Agreement must be included with each copy of the Program. </FONT></UL>
+
+<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT>
+<P><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT><FONT SIZE="2">Contributors may not remove or alter any copyright notices contained within the Program. </FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. </FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>4. COMMERCIAL DISTRIBUTION</B></FONT>
+<P><FONT SIZE="2">Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"></FONT>
+<P><FONT SIZE="2" COLOR="#0000FF"></FONT><FONT SIZE="2"><B>5. NO WARRANTY</B></FONT>
+<P><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is</FONT><FONT SIZE="2"> solely responsible for determining the appropriateness of using and distributing </FONT><FONT SIZE="2">the Program</FONT><FONT SIZE="2"> and assumes all risks associated with its exercise of rights under this Agreement</FONT><FONT SIZE="2">, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, </FONT><FONT SIZE="2">programs or equipment, and unavailability or interruption of operations</FONT><FONT SIZE="2">. </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"><B>6. DISCLAIMER OF LIABILITY</B></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES </FONT><FONT SIZE="2">(INCLUDING WITHOUT LIMITATION LOST PROFITS),</FONT><FONT SIZE="2"> HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"><B>7. GENERAL</B></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. </FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2">Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to </FONT><FONT SIZE="2">publish new versions (including revisions) of this Agreement from time to </FONT><FONT SIZE="2">time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. </FONT><FONT SIZE="2">Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new </FONT><FONT SIZE="2">version. </FONT><FONT SIZE="2">Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, </FONT><FONT SIZE="2">by implication, estoppel or otherwise</FONT><FONT SIZE="2">.</FONT><FONT SIZE="2"> All rights in the Program not expressly granted under this Agreement are reserved.</FONT>
+<P><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2">This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.</FONT>
+<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
+<P><FONT SIZE="2"></FONT>
+
+</BODY>
+
+</HTML> \ No newline at end of file
diff --git a/junit4/doc/ReleaseNotes4.10.html b/junit4/doc/ReleaseNotes4.10.html
new file mode 100644
index 0000000..ebf4174
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.10.html
@@ -0,0 +1,93 @@
+<h2>Summary of Changes in version 4.10 [unreleased!]</h2>
+
+<p>A full summary of commits between 4.9 and 4.10 is on <a href="https://github.com/KentBeck/junit/compare/r4.9...4.10">github</a></p>
+
+<h3>junit-dep has correct contents</h3>
+
+<p>junit-dep-4.9.jar incorrectly contained hamcrest classes, which could lead to version conflicts in projects that depend on hamcrest directly. This is fixed in 4.10 [@dsaff, closing gh-309]</p>
+
+<h3>RuleChain</h3>
+
+<p>The RuleChain rule allows ordering of TestRules:</p>
+
+<pre><code>public static class UseRuleChain {
+ @Rule
+ public TestRule chain= RuleChain
+ .outerRule(new LoggingRule("outer rule")
+ .around(new LoggingRule("middle rule")
+ .around(new LoggingRule("inner rule");
+
+ @Test
+ public void example() {
+ assertTrue(true);
+ }
+}
+</code></pre>
+
+<p>writes the log</p>
+
+<pre><code>starting outer rule
+starting middle rule
+starting inner rule
+finished inner rule
+finished middle rule
+finished outer rule
+</code></pre>
+
+<h3>TemporaryFolder</h3>
+
+<ul>
+<li><code>TemporaryFolder#newFolder(String... folderNames)</code> creates recursively deep temporary folders
+[@rodolfoliviero, closing gh-283]</li>
+<li><code>TemporaryFolder#newFile()</code> creates a randomly named new file, and <code>#newFolder()</code> creates a randomly named new folder
+[@Daniel Rothmaler, closing gh-299]</li>
+</ul>
+
+<h3>Theories</h3>
+
+<p>The <code>Theories</code> runner does not anticipate theory parameters that have generic
+types, as reported by github#64. Fixing this won't happen until <code>Theories</code> is
+moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the
+necessary machinery to the runner classes, and deprecates a method that only
+the <code>Theories</code> runner uses, <code>FrameworkMethod</code>#producesType().
+The Common Public License that JUnit is released under is now included
+in the source repository.</p>
+
+<p>Thanks to <code>@pholser</code> for identifying a potential resolution for github#64
+and initiating work on it.</p>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>Built-in Rules implementations
+<ul>
+<li>TemporaryFolder should not create files in the current working directory if applying the rule fails
+[@orfjackal, fixing gh-278]</li>
+<li>TestWatcher and TestWatchman should not call failed for AssumptionViolatedExceptions
+[@stefanbirkner, fixing gh-296]</li>
+</ul></li>
+<li>Javadoc bugs
+<ul>
+<li>Assert documentation [@stefanbirkner, fixing gh-134]</li>
+<li>ClassRule [@stefanbirkner, fixing gh-254]</li>
+<li>Parameterized [@stefanbirkner, fixing gh-89]</li>
+<li>Parameterized, again [@orfjackal, fixing gh-285]</li>
+</ul></li>
+<li>Miscellaneous
+<ul>
+<li>Useless code in RunAfters [@stefanbirkner, fixing gh-289]</li>
+<li>Parameterized test classes should be able to have <code>@Category</code> annotations
+[@dsaff, fixing gh-291]</li>
+<li>Error count should be initialized in junit.tests.framework.TestListenerTest [@stefanbirkner, fixing gh-225]</li>
+<li>AssertionFailedError constructor shouldn't call super with null message [@stefanbirkner, fixing gh-318]</li>
+<li>Clearer error message for non-static inner test classes [@stefanbirkner, fixing gh-42]</li>
+</ul></li>
+</ul>
+
+<h3>Minor changes</h3>
+
+<ul>
+<li>Description, Result and Failure are Serializable [@ephox-rob, closing gh-101]</li>
+<li>FailOnTimeout is reusable, allowing for retrying Rules [@stefanbirkner, closing gh-265]</li>
+<li>New <code>ErrorCollector.checkThat</code> overload, that allows you to specify a reason [@drothmaler, closing gh-300]</li>
+</ul>
diff --git a/junit4/doc/ReleaseNotes4.10.txt b/junit4/doc/ReleaseNotes4.10.txt
new file mode 100644
index 0000000..ccf8625
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.10.txt
@@ -0,0 +1,84 @@
+## Summary of Changes in version 4.10 ##
+
+Thanks to a full cast of contributors of bug fixes and new features.
+
+A full summary of commits between 4.9 and 4.10 is on [github](https://github.com/KentBeck/junit/compare/r4.9...4.10)
+
+### junit-dep has correct contents ###
+
+junit-dep-4.9.jar incorrectly contained hamcrest classes, which could lead to version conflicts in projects that depend on hamcrest directly. This is fixed in 4.10 [@dsaff, closing gh-309]
+
+### RuleChain ###
+
+The RuleChain rule allows ordering of TestRules:
+
+ public static class UseRuleChain {
+ @Rule
+ public TestRule chain= RuleChain
+ .outerRule(new LoggingRule("outer rule")
+ .around(new LoggingRule("middle rule")
+ .around(new LoggingRule("inner rule");
+
+ @Test
+ public void example() {
+ assertTrue(true);
+ }
+ }
+
+writes the log
+
+ starting outer rule
+ starting middle rule
+ starting inner rule
+ finished inner rule
+ finished middle rule
+ finished outer rule
+
+### TemporaryFolder ###
+
+- `TemporaryFolder#newFolder(String... folderNames)` creates recursively deep temporary folders
+ [@rodolfoliviero, closing gh-283]
+- `TemporaryFolder#newFile()` creates a randomly named new file, and `#newFolder()` creates a randomly named new folder
+ [@Daniel Rothmaler, closing gh-299]
+
+### Theories ###
+
+The `Theories` runner does not anticipate theory parameters that have generic
+types, as reported by github#64. Fixing this won't happen until `Theories` is
+moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the
+necessary machinery to the runner classes, and deprecates a method that only
+the `Theories` runner uses, `FrameworkMethod`#producesType().
+The Common Public License that JUnit is released under is now included
+in the source repository.
+
+Thanks to `@pholser` for identifying a potential resolution for github#64
+and initiating work on it.
+
+### Bug fixes ###
+
+- Built-in Rules implementations
+ - TemporaryFolder should not create files in the current working directory if applying the rule fails
+ [@orfjackal, fixing gh-278]
+ - TestWatcher and TestWatchman should not call failed for AssumptionViolatedExceptions
+ [@stefanbirkner, fixing gh-296]
+- Javadoc bugs
+ - Assert documentation [@stefanbirkner, fixing gh-134]
+ - ClassRule [@stefanbirkner, fixing gh-254]
+ - Parameterized [@stefanbirkner, fixing gh-89]
+ - Parameterized, again [@orfjackal, fixing gh-285]
+- Miscellaneous
+ - Useless code in RunAfters [@stefanbirkner, fixing gh-289]
+ - Parameterized test classes should be able to have `@Category` annotations
+ [@dsaff, fixing gh-291]
+ - Error count should be initialized in junit.tests.framework.TestListenerTest [@stefanbirkner, fixing gh-225]
+ - AssertionFailedError constructor shouldn't call super with null message [@stefanbirkner, fixing gh-318]
+ - Clearer error message for non-static inner test classes [@stefanbirkner, fixing gh-42]
+
+### Minor changes ###
+
+- Description, Result and Failure are Serializable [@ephox-rob, closing gh-101]
+- FailOnTimeout is reusable, allowing for retrying Rules [@stefanbirkner, closing gh-265]
+- New `ErrorCollector.checkThat` overload, that allows you to specify a reason [@drothmaler, closing gh-300]
+
+
+
diff --git a/junit4/doc/ReleaseNotes4.4.html b/junit4/doc/ReleaseNotes4.4.html
new file mode 100644
index 0000000..3736b46
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.4.html
@@ -0,0 +1,271 @@
+<h2>Summary of Changes in version 4.5</h2>
+
+<h3>Categories</h3>
+
+<p>Each test method and test class can be annotated as belonging to a <em>category</em>:</p>
+
+<pre><code>public static class SomeUITests {
+ @Category(UserAvailable.class)
+ @Test
+ public void askUserToPressAKey() { }
+
+ @Test
+ public void simulatePressingKey() { }
+}
+
+@Category(InternetConnected.class)
+public static class InternetTests {
+ @Test
+ public void pingServer() { }
+}
+</code></pre>
+
+<p>To run all of the tests in a particular category, you must currently explicitly create a custom request:</p>
+
+<pre><code>new JUnitCore().run(Request.aClass(SomeUITests.class).inCategories(UserAvailable.class));
+</code></pre>
+
+<p>This feature will very likely be improved before the final release of JUnit 4.5</p>
+
+<h3>Miscellaneous</h3>
+
+<ul>
+<li><p><code>@Before</code> and <code>@After</code> methods are run before and after each set of attempted parameters
+on a Theory</p></li>
+<li><p>Refactoring removed duplication that used to exist in classes MethodRoadie and ClassRoadie</p></li>
+<li><p>Exposed API <code>ParameterSignature.getType()</code></p></li>
+</ul>
+
+<h2>Summary of Changes in version 4.4</h2>
+
+<p>JUnit is designed to efficiently capture developers' intentions about
+their code, and quickly check their code matches those intentions.
+Over the last year, we've been talking about what things developers
+would like to say about their code that have been difficult in the
+past, and how we can make them easier.</p>
+
+<p><a href="http://sourceforge.net/project/showfiles.php?group_id=15278">Download</a></p>
+
+<h3>assertThat</h3>
+
+<p>Two years ago, Joe Walnes built a <a href="http://joe.truemesh.com/blog/000511.html">new assertion mechanism</a> on top of what was
+then <a href="http://www.jmock.org/download.html">JMock 1</a>. The method name was <code>assertThat</code>, and the syntax looked like this:</p>
+
+<pre><code>assertThat(x, is(3));
+assertThat(x, is(not(4)));
+assertThat(responseString, either(containsString("color")).or(containsString("colour")));
+assertThat(myList, hasItem("3"));
+</code></pre>
+
+<p>More generally:</p>
+
+<pre><code>assertThat([value], [matcher statement]);
+</code></pre>
+
+<p>Advantages of this assertion syntax include:</p>
+
+<ul>
+<li><p>More readable and typeable: this syntax allows you to think in terms of subject, verb, object
+(assert "x is 3") rather than <code>assertEquals</code>, which uses verb, object, subject (assert "equals 3 x")</p></li>
+<li><p>Combinations: any matcher statement <code>s</code> can be negated (<code>not(s)</code>), combined (<code>either(s).or(t)</code>),
+mapped to a collection (<code>each(s)</code>), or used in custom combinations (<code>afterFiveSeconds(s)</code>)</p></li>
+<li><p>Readable failure messages. Compare</p>
+
+<pre><code>assertTrue(responseString.contains("color") || responseString.contains("colour"));
+// ==&gt; failure message:
+// java.lang.AssertionError:
+
+
+assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
+// ==&gt; failure message:
+// java.lang.AssertionError:
+// Expected: (a string containing "color" or a string containing "colour")
+// got: "Please choose a font"
+</code></pre></li>
+<li><p>Custom Matchers. By implementing the <code>Matcher</code> interface yourself, you can get all of the
+above benefits for your own custom assertions.</p></li>
+<li><p>For a more thorough description of these points, see <a href="http://joe.truemesh.com/blog/000511.html">Joe Walnes's
+original post</a>.</p></li>
+</ul>
+
+<p>We have decided to include this API directly in JUnit.
+It's an extensible and readable syntax, and it enables
+new features, like <a href="#assumptions">assumptions</a> and <a href="#theories">theories</a>.</p>
+
+<p>Some notes:</p>
+
+<ul>
+<li>The old assert methods are never, ever, going away. 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. <a href="http://www.eclipse.org/downloads/">Eclipse 3.3</a> 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>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>
+
+<p><a name="assumptions" /></p>
+
+<h3>Assumptions</h3>
+
+<p>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 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 <code>assumeThat</code>, 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>
+
+<p><a name="theories" /></p>
+
+<h3>Theories</h3>
+
+<p>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 captures some aspect of the
+intended behavior in possibly
+infinite numbers of potential scenarios. For example:</p>
+
+<pre><code>@RunWith(Theories.class)
+public class UserTest {
+ @DataPoint public static String GOOD_USERNAME = "optimus";
+ @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";
+
+ @Theory public void filenameIncludesUsername(String username) {
+ assumeThat(username, not(containsString("/")));
+ assertThat(new User(username).configFileName(), containsString(username));
+ }
+}
+</code></pre>
+
+<p>This makes it clear that the user's filename should be included in the
+config file name, only if it doesn't contain a slash. Another test
+or theory might define what happens when a username does contain a slash.</p>
+
+<p><code>UserTest</code> will attempt to run <code>filenameIncludesUsername</code> on
+every compatible <code>DataPoint</code> defined in the class. If any of the
+assumptions fail, the data point is silently ignored. If all of the
+assumptions pass, but an assertion fails, the test fails.</p>
+
+<p>The support for Theories has been absorbed from the <a href="http://popper.tigris.org">Popper</a>
+project, and <a href="http://popper.tigris.org/tutorial.html">more complete documentation</a> can be found
+there.</p>
+
+<p>Defining general statements in this way can jog the developer's memory
+about other potential data points and tests, also allows <a href="http://www.junitfactory.org">automated
+tools</a> to <a href="http://shareandenjoy.saff.net/2007/04/popper-and-junitfactory.html">search</a> for new, unexpected data
+points that expose bugs.</p>
+
+<h3>Other changes</h3>
+
+<p>This release contains other bug fixes and new features. Among them:</p>
+
+<ul>
+<li><p>Annotated descriptions</p>
+
+<p>Runner UIs, Filters, and Sorters operate on Descriptions of test
+methods and test classes. These Descriptions now include the
+annotations on the original Java source element, allowing for richer
+display of test results, and easier development of annotation-based
+filters.</p></li>
+<li><p>Bug fix (1715326): assertEquals now compares all Numbers using their
+native implementation of <code>equals</code>. This assertion, which passed in
+4.3, will now fail:</p>
+
+<pre><code>assertEquals(new Integer(1), new Long(1));
+</code></pre>
+
+<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>
+
+<pre><code>assertEquals(1, 1L);
+</code></pre></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>
+
+<pre><code>public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(MyTest.class);
+}
+</code></pre></li>
+<li><p>Bug fix (1745048): @After methods are now correctly called
+after a test method times out.</p></li>
+</ul>
diff --git a/junit4/doc/ReleaseNotes4.4.txt b/junit4/doc/ReleaseNotes4.4.txt
new file mode 100644
index 0000000..98d9ddd
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.4.txt
@@ -0,0 +1,295 @@
+## Summary of Changes in version 4.5 ##
+
+### Categories ###
+Each test method and test class can be annotated as belonging to a _category_:
+
+ public static class SomeUITests {
+ @Category(UserAvailable.class)
+ @Test
+ public void askUserToPressAKey() { }
+
+ @Test
+ public void simulatePressingKey() { }
+ }
+
+ @Category(InternetConnected.class)
+ public static class InternetTests {
+ @Test
+ public void pingServer() { }
+ }
+
+To run all of the tests in a particular category, you must currently explicitly create a custom request:
+
+ new JUnitCore().run(Request.aClass(SomeUITests.class).inCategories(UserAvailable.class));
+
+This feature will very likely be improved before the final release of JUnit 4.5
+
+### Theories ###
+
+- `@Before` and `@After` 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.
+
+- Exposed API's `ParameterSignature.getType()` and `ParameterSignature.getAnnotations()`
+
+- An array of data points can be introduced by a field or method marked with the new annotation `@DataPoints`
+
+- The Theories custom runner has been refactored to make it easier to extend
+
+### JUnit 4 Runner API ###
+
+- There has been a drastic rewrite of the API for custom Runners in 4.5. This
+ needs to be written up separately before release.
+
+- Tests with failed assumptions are now marked as Ignored, rather than silently passing.
+ This may change behavior in some client tests, and also will require some new support
+ on the part of IDE's.
+
+## Summary of Changes in version 4.4 ##
+
+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.
+
+[Download][]
+
+[Download]: http://sourceforge.net/project/showfiles.php?group_id=15278
+
+### assertThat ###
+
+Two years ago, Joe Walnes built a [new assertion mechanism][walnes] on top of what was
+then [JMock 1][]. The method name was `assertThat`, and the syntax looked like this:
+
+[walnes]: http://joe.truemesh.com/blog/000511.html
+[JMock 1]: http://www.jmock.org/download.html
+
+ assertThat(x, is(3));
+ assertThat(x, is(not(4)));
+ assertThat(responseString, either(containsString("color")).or(containsString("colour")));
+ assertThat(myList, hasItem("3"));
+
+More generally:
+
+ assertThat([value], [matcher statement]);
+
+Advantages of this assertion syntax include:
+
+- More readable and typeable: this syntax allows you to think in terms of subject, verb, object
+ (assert "x is 3") rather than `assertEquals`, which uses verb, object, subject (assert "equals 3 x")
+
+- Combinations: any matcher statement `s` can be negated (`not(s)`), combined (`either(s).or(t)`),
+ mapped to a collection (`each(s)`), or used in custom combinations (`afterFiveSeconds(s)`)
+
+- Readable failure messages. Compare
+
+ assertTrue(responseString.contains("color") || responseString.contains("colour"));
+ // ==> failure message:
+ // java.lang.AssertionError:
+
+ assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
+ // ==> failure message:
+ // java.lang.AssertionError:
+ // Expected: (a string containing "color" or a string containing "colour")
+ // got: "Please choose a font"
+
+- Custom Matchers. By implementing the `Matcher` interface yourself, you can get all of the
+ above benefits for your own custom assertions.
+
+- For a more thorough description of these points, see [Joe Walnes's
+ original post][walnes].
+
+We have decided to include this API directly in JUnit.
+It's an extensible and readable syntax, and it enables
+new features, like [assumptions][] and [theories][].
+
+[assumptions]: #assumptions
+[theories]: #theories
+
+Some notes:
+
+- The old assert methods are never, ever, going away. Developers may
+ continue using the old `assertEquals`, `assertTrue`, and so on.
+- The second parameter of an `assertThat` statement is a `Matcher`.
+ We include the Matchers we want as static imports, like this:
+
+ import static org.hamcrest.CoreMatchers.is;
+
+ or:
+
+ import static org.hamcrest.CoreMatchers.*;
+
+- Manually importing `Matcher` 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.
+
+[Eclipse 3.3]: http://www.eclipse.org/downloads/
+
+- To allow compatibility with a wide variety of possible matchers,
+ we have decided to include the classes from hamcrest-core,
+ from the [Hamcrest][] project. This is the first time that
+ third-party classes have been included in JUnit.
+
+[Hamcrest]: http://code.google.com/p/hamcrest/
+
+- JUnit currently ships with a few matchers, defined in
+ `org.hamcrest.CoreMatchers` and `org.junit.matchers.JUnitMatchers`.
+ To use many, many more, consider downloading the [full hamcrest package][].
+
+[full hamcrest package]: http://hamcrest.googlecode.com/files/hamcrest-all-1.1.jar
+
+- JUnit contains special support for comparing string and array
+ values, giving specific information on how they differ. This is not
+ yet available using the `assertThat` syntax, but we hope to bring
+ the two assert methods into closer alignment in future releases.
+
+<a name="assumptions" />
+### 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.
+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.
+
+However, sometimes this is not desirable or possible.
+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":
+
+ 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()));
+ }
+
+With this release, a failed assumption will lead to the test being marked as passing,
+regardless of what the code below the assumption may assert.
+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.
+
+We have included `assumeTrue` for convenience, but thanks to the
+inclusion of Hamcrest, we do not need to create `assumeEquals`,
+`assumeSame`, and other analogues to the `assert*` methods. All of
+those functionalities are subsumed in `assumeThat`, with the appropriate
+matcher.
+
+A failing assumption in a `@Before` or `@BeforeClass` method will have the same effect
+as a failing assumption in each `@Test` method of the class.
+
+<a name="theories" />
+### 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 captures some aspect of the
+intended behavior in possibly
+infinite numbers of potential scenarios. For example:
+
+ @RunWith(Theories.class)
+ public class UserTest {
+ @DataPoint public static String GOOD_USERNAME = "optimus";
+ @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";
+
+ @Theory public void filenameIncludesUsername(String username) {
+ assumeThat(username, not(containsString("/")));
+ assertThat(new User(username).configFileName(), containsString(username));
+ }
+ }
+
+This makes it clear that the user's filename should be included in the
+config file name, only if it doesn't contain a slash. Another test
+or theory might define what happens when a username does contain a slash.
+
+`UserTest` will attempt to run `filenameIncludesUsername` on
+every compatible `DataPoint` 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.
+
+The support for Theories has been absorbed from the [Popper][]
+project, and [more complete documentation][popper-docs] can be found
+there.
+
+[Popper]: http://popper.tigris.org
+[popper-docs]: http://popper.tigris.org/tutorial.html
+
+Defining general statements in this way can jog the developer's memory
+about other potential data points and tests, also allows [automated
+tools][junit-factory] to [search][my-blog] for new, unexpected data
+points that expose bugs.
+
+[junit-factory]: http://www.junitfactory.org
+[my-blog]: http://shareandenjoy.saff.net/2007/04/popper-and-junitfactory.html
+
+### Other changes ###
+
+This release contains other bug fixes and new features. Among them:
+
+- Annotated descriptions
+
+ 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.
+
+- Bug fix (1715326): assertEquals now compares all Numbers using their
+ native implementation of `equals`. This assertion, which passed in
+ 4.3, will now fail:
+
+ assertEquals(new Integer(1), new Long(1));
+
+ Non-integer Numbers (Floats, Doubles, BigDecimals, etc),
+ which were compared incorrectly in 4.3, are now fixed.
+
+- `assertEquals(long, long)` and `assertEquals(double, double)` have
+ been re-introduced to the `Assert` class, to take advantage of
+ Java's native widening conversions. Therefore, this still passes:
+
+ assertEquals(1, 1L);
+
+- The default runner for JUnit 4 test classes has been refactored.
+ The old version was named `TestClassRunner`, and the new is named
+ `JUnit4ClassRunner`. Likewise, `OldTestClassRunner` is now
+ `JUnit3ClassRunner`. 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
+ `org.junit.experimental.theories.Theories`.
+
+- The rules for determining which runner is applied by default to a
+ test class have been simplified:
+
+ 1. If the class has a `@RunWith` annotation, the annotated runner
+ class is used.
+
+ 2. If the class can be run with the JUnit 3 test runner (it
+ subclasses `TestCase`, or contains a `public static Test suite()`
+ method), JUnit38ClassRunner is used.
+
+ 3. Otherwise, JUnit4ClassRunner is used.
+
+ This default guess can always be overridden by an explicit
+ `@RunWith(JUnit4ClassRunner.class)` or
+ `@RunWith(JUnit38ClassRunner.class)` annotation.
+
+ The old class names `TestClassRunner` and `OldTestClassRunner`
+ remain as deprecated.
+
+- Bug fix (1739095): Filters and Sorters work correctly on test
+ classes that contain a `suite` method like:
+
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(MyTest.class);
+ }
+
+- Bug fix (1745048): @After methods are now correctly called
+ after a test method times out.
+
diff --git a/junit4/doc/ReleaseNotes4.5.txt b/junit4/doc/ReleaseNotes4.5.txt
new file mode 100644
index 0000000..66aac70
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.5.txt
@@ -0,0 +1,96 @@
+## Summary of Changes in version 4.5 ##
+
+### Installation ###
+
+- We are releasing `junit-4.5.jar`, which contains all the classes
+ necessary to run JUnit, and `junit-dep-4.5.jar`, which leaves out
+ hamcrest classes, for developers who already use hamcrest outside of
+ JUnit.
+
+### Basic JUnit operation ###
+
+- JUnitCore now more often exits with the correct exit code (0 for
+ success, 1 for failure)
+
+- Badly formed test classes (exceptions in constructors, classes
+ without tests, multiple constructors, Suite without @SuiteClasses)
+ produce more helpful error messages
+
+- Test classes whose only test methods are inherited from superclasses
+ now run.
+
+- Optimization to annotation processing can cut JUnit overhead by more than half
+ on large test classes, especially when using Theories. [Bug 1796847]
+
+- A failing assumption in a constructor ignores the class
+
+- Correct results when comparing the string "null" with potentially
+ null values. [Bug 1857283]
+
+- Annotating a class with `@RunWith(JUnit4.class)` will always invoke the
+ default JUnit 4 runner in the current version of JUnit. This default changed
+ from `JUnit4ClassRunner` in 4.4 to `BlockJUnit4ClassRunner` in 4.5 (see below),
+ and may change again.
+
+### Extension ###
+
+- `BlockJUnit4Runner` is a new implementation of the standard JUnit 4
+ test class functionality. In contrast to `JUnit4ClassRunner` (the old
+ implementation):
+
+ - `BlockJUnit4Runner` has a much simpler implementation based on
+ Statements, allowing new operations to be inserted into the
+ appropriate point in the execution flow.
+
+ - `BlockJUnit4Runner` is published, and extension and reuse are
+ encouraged, whereas `JUnit4ClassRunner` was in an internal package,
+ and is now deprecated.
+
+- `ParentRunner` is a base class for runners that iterate over
+ a list of "children", each an object representing a test or suite to run.
+ `ParentRunner` provides filtering, sorting, `@BeforeClass`, `@AfterClass`,
+ and method validation to subclasses.
+
+- `TestClass` wraps a class to be run, providing efficient, repeated access
+ to all methods with a given annotation.
+
+- The new `RunnerBuilder` API allows extending the behavior of
+ Suite-like custom runners.
+
+- `AssumptionViolatedException.toString()` is more informative
+
+### Extra Runners ###
+
+- `Parameterized.eachOne()` has been removed
+
+- New runner `Enclosed` runs all static inner classes of an outer class.
+
+### Theories ###
+
+- `@Before` and `@After` 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.
+
+- Exposed API's `ParameterSignature.getType()` and `ParameterSignature.getAnnotations()`
+
+- An array of data points can be introduced by a field or method
+ marked with the new annotation `@DataPoints`
+
+- The Theories custom runner has been refactored to make it faster and
+ easier to extend
+
+### Development ###
+
+- Source has been split into directories `src/main/java` and
+ `src/test/java`, making it easier to exclude tests from builds, and
+ making JUnit more maven-friendly
+
+- Test classes in `org.junit.tests` have been organized into
+ subpackages, hopefully making finding tests easier.
+
+- `ResultMatchers` has more informative descriptions.
+
+- `TestSystem` allows testing return codes and other system-level interactions.
+
+### Incompatible changes ###
+
+- Removed Request.classes(String, Class<?>...) factory method
diff --git a/junit4/doc/ReleaseNotes4.6.html b/junit4/doc/ReleaseNotes4.6.html
new file mode 100644
index 0000000..36c432a
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.6.html
@@ -0,0 +1,106 @@
+<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><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>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>Fixed overly permissive @DataPoint processing (2191102)</li>
+<li>Fixed bug in test counting after an ignored method (2106324)</li>
+</ul>
diff --git a/junit4/doc/ReleaseNotes4.6.txt b/junit4/doc/ReleaseNotes4.6.txt
new file mode 100644
index 0000000..a5decac
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.6.txt
@@ -0,0 +1,100 @@
+## Summary of Changes in version 4.6 ##
+
+### Max ###
+
+JUnit now includes a new experimental Core, `MaxCore`. `MaxCore`
+remembers the results of previous test runs in order to run new
+tests out of order. `MaxCore` 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
+`MaxCore` included in JUnit, but there is a UI included in the JUnit
+Max Eclipse plug-in at:
+
+ http://www.junitmax.com/junitmax/subscribe.html
+
+Example:
+
+ 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<Failure> failures= useHistory.run(TwoUnEqualTests.class)
+ .getFailures();
+ assertEquals("fast", failures.get(0).getDescription().getMethodName());
+ assertEquals("slow", failures.get(1).getDescription().getMethodName());
+ }
+
+### Test scheduling strategies ###
+
+`JUnitCore` now includes an experimental method that allows you to
+specify a model of the `Computer` that runs your tests. Currently,
+the only built-in Computers are the default, serial runner, and two
+runners provided in the `ParallelRunner` class:
+`ParallelRunner.classes()`, which runs classes in parallel, and
+`ParallelRunner.methods()`, which runs classes and methods in parallel.
+
+This feature is currently less stable than MaxCore, and may be
+merged with MaxCore in some way in the future.
+
+Example:
+
+ 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));
+ }
+
+### Comparing double arrays ###
+
+Arrays of doubles can be compared, using a delta allowance for equality:
+
+ @Test
+ public void doubleArraysAreEqual() {
+ assertArrayEquals(new double[] {1.0, 2.0}, new double[] {1.0, 2.0}, 0.01);
+ }
+
+### `Filter.matchDescription` API ###
+
+Since 4.0, it has been possible to run a single method using the `Request.method`
+API. In 4.6, the filter that implements this is exposed as `Filter.matchDescription`.
+
+### Documentation ###
+
+- A couple classes and packages that once had empty javadoc have been
+ doc'ed.
+
+- Added how to run JUnit from the command line to the cookbook.
+
+- junit-4.x.zip now contains build.xml
+
+### Bug fixes ###
+- Fixed overly permissive @DataPoint processing (2191102)
+- Fixed bug in test counting after an ignored method (2106324)
diff --git a/junit4/doc/ReleaseNotes4.7.html b/junit4/doc/ReleaseNotes4.7.html
new file mode 100644
index 0000000..69b66c6
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.7.html
@@ -0,0 +1,229 @@
+<h2>Summary of Changes in version 4.7</h2>
+
+<h3>Rules</h3>
+
+<ul>
+<li><p>Rules allow very flexible addition or redefinition of the behavior
+of each test method in a test class. Testers can reuse or extend one of the
+provided Rules below, or write their own.</p>
+
+<p>For more on this feature, see http://www.threeriversinstitute.org/blog/?p=155</p></li>
+<li><p>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):</p>
+
+<p>public static class HasTempFolder {
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();</p>
+
+<pre><code>@Test
+public void testUsingTempFolder() throws IOException {
+ File createdFile= folder.newFile("myfile.txt");
+ File createdFolder= folder.newFolder("subfolder");
+ // ...
+}
+</code></pre>
+
+<p>}</p></li>
+<li><p>ExternalResource is a base class for Rules (like TemporaryFolder)
+that set up an external resource before a test (a file, socket, server,
+database connection, etc.), and guarantee to tear it down afterward:</p>
+
+<p>public static class UsesExternalResource {
+ Server myServer = new Server();</p>
+
+<pre><code>@Rule public ExternalResource resource = new ExternalResource() {
+ @Override
+ protected void before() throws Throwable {
+ myServer.connect();
+ };
+
+
+<pre><code>@Override
+protected void after() {
+ myServer.disconnect();
+};
+</code></pre>
+
+};
+
+
+@Test public void testFoo() {
+ new Client().run(myServer);
+}
+</code></pre>
+
+<p>}</p></li>
+<li><p>The ErrorCollector Rule allows execution of a test to continue
+after the first problem is found (for example, to collect <em>all</em> the
+incorrect rows in a table, and report them all at once):</p>
+
+<p>public static class UsesErrorCollectorTwice {
+ @Rule
+ public ErrorCollector collector= new ErrorCollector();</p>
+
+<pre><code>@Test public void example() {
+ collector.addError(new Throwable("first thing went wrong"));
+ collector.addError(new Throwable("second thing went wrong"));
+}
+</code></pre>
+
+<p>}</p></li>
+<li><p>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</p>
+
+<p>public static class ErrorLogVerifier() {
+ private ErrorLog errorLog = new ErrorLog();</p>
+
+<p>@Rule
+ public MethodRule verifier = new Verifier() {
+ @Override public void verify() {
+ assertTrue(errorLog.isEmpty());
+ }
+ }</p>
+
+<p>@Test public void testThatMightWriteErrorLog() {
+ // ...
+ }
+}</p></li>
+<li><p>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:</p>
+
+<p>public static class WatchmanTest {
+ private static String watchedLog;</p>
+
+<pre><code>@Rule
+public MethodRule watchman= new TestWatchman() {
+ @Override
+ public void failed(Throwable e, FrameworkMethod method) {
+ watchedLog+= method.getName() + " "
+ + e.getClass().getSimpleName() + "\n";
+ }
+
+
+<pre><code>@Override
+public void succeeded(FrameworkMethod method) {
+ watchedLog+= method.getName() + " " + "success!\n";
+}
+</code></pre>
+
+};
+
+
+@Test
+public void fails() {
+ fail();
+}
+
+
+@Test
+public void succeeds() {
+}
+</code></pre>
+
+<p>}</p></li>
+<li><p>The TestName Rule makes the current test name available inside test methods:</p>
+
+<p>public class NameRuleTest {
+ @Rule public TestName name = new TestName();</p>
+
+<pre><code>@Test public void testA() {
+ assertEquals("testA", name.getMethodName());
+}
+
+
+@Test public void testB() {
+ assertEquals("testB", name.getMethodName());
+}
+</code></pre>
+
+<p>}</p></li>
+<li><p>The Timeout Rule applies the same timeout to all test methods in a class:</p>
+
+<p>public static class HasGlobalTimeout {
+ public static String log;</p>
+
+<pre><code>@Rule public MethodRule globalTimeout = new Timeout(20);
+
+
+@Test public void testInfiniteLoop1() {
+ log+= "ran1";
+ for(;;) {}
+}
+
+
+@Test public void testInfiniteLoop2() {
+ log+= "ran2";
+ for(;;) {}
+}
+</code></pre>
+
+<p>}</p></li>
+<li><p>The ExpectedException Rule allows in-test specification
+of expected exception types and messages:</p>
+
+<p>public static class HasExpectedException {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();</p>
+
+<pre><code>@Test
+public void throwsNothing() {
+
+
+}
+
+
+@Test
+public void throwsNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ throw new NullPointerException();
+}
+
+
+@Test
+public void throwsNullPointerExceptionWithMessage() {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("happened?");
+ thrown.expectMessage(startsWith("What"));
+ throw new NullPointerException("What happened?");
+}
+</code></pre>
+
+<p>}</p></li>
+</ul>
+
+<h3>Timeouts</h3>
+
+<ul>
+<li>Tests that time out now show the stack trace of the test thread.</li>
+</ul>
+
+<h3>Matchers</h3>
+
+<ul>
+<li>Due to typing incompatibilities, JUnit is still including the 1.1 release
+of hamcrest. This is not a change from 4.6, but is a change from
+pre-beta releases of 4.7. Due to this incompatibility, tests using
+Hamcrest 1.2 must still use the MatcherAssert.assertThat method from
+Hamcrest, not Assert.assertThat from JUnit.</li>
+</ul>
+
+<h3>Docs</h3>
+
+<ul>
+<li>Javadocs now link to online JDK javadocs (bug 2090230)</li>
+<li>Parameterized runner javadocs improved (bug 2186792)</li>
+<li>Fixed Javadoc code sample for AfterClass (2126279)</li>
+<li>Fixed Javadoc for assertArraysEqual(float[], float[])</li>
+</ul>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>Fixed: BaseTestRunner.getTest() requires class to extend TestCase (1812200)</li>
+<li>Fixed: Suite does not allow for inheritance in annotations (2783118)</li>
+<li>Fixed: ParallelComputer skipped tests that took longer than 2 seconds</li>
+</ul>
diff --git a/junit4/doc/ReleaseNotes4.7.txt b/junit4/doc/ReleaseNotes4.7.txt
new file mode 100644
index 0000000..11b70c1
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.7.txt
@@ -0,0 +1,194 @@
+## Summary of Changes in version 4.7 ##
+
+### Rules ###
+
+- Rules allow very flexible addition or redefinition of the behavior
+ of each test method in a test class. Testers can reuse or extend one of the
+ provided Rules below, or write their own.
+
+ For more on this feature, see http://www.threeriversinstitute.org/blog/?p=155
+
+- 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):
+
+ public static class HasTempFolder {
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testUsingTempFolder() throws IOException {
+ File createdFile= folder.newFile("myfile.txt");
+ File createdFolder= folder.newFolder("subfolder");
+ // ...
+ }
+ }
+
+- ExternalResource is a base class for Rules (like TemporaryFolder)
+ that set up an external resource before a test (a file, socket, server,
+ database connection, etc.), and guarantee to tear it down afterward:
+
+ public static class UsesExternalResource {
+ Server myServer = new Server();
+
+ @Rule public ExternalResource resource = new ExternalResource() {
+ @Override
+ protected void before() throws Throwable {
+ myServer.connect();
+ };
+
+ @Override
+ protected void after() {
+ myServer.disconnect();
+ };
+ };
+
+ @Test public void testFoo() {
+ new Client().run(myServer);
+ }
+ }
+
+- The ErrorCollector Rule allows execution of a test to continue
+ after the first problem is found (for example, to collect _all_ the
+ incorrect rows in a table, and report them all at once):
+
+ public static class UsesErrorCollectorTwice {
+ @Rule
+ public ErrorCollector collector= new ErrorCollector();
+
+ @Test public void example() {
+ collector.addError(new Throwable("first thing went wrong"));
+ collector.addError(new Throwable("second thing went wrong"));
+ }
+ }
+
+- Verifier is a base class for Rules like ErrorCollector, which
+ can turn otherwise passing test methods into failing tests if a verification
+ check is failed
+
+ public static class ErrorLogVerifier() {
+ private ErrorLog errorLog = new ErrorLog();
+
+ @Rule
+ public MethodRule verifier = new Verifier() {
+ @Override public void verify() {
+ assertTrue(errorLog.isEmpty());
+ }
+ }
+
+ @Test public void testThatMightWriteErrorLog() {
+ // ...
+ }
+ }
+
+- TestWatchman is a base class for Rules that take note
+ of the testing action, without modifying it.
+ For example, this class will keep a log of each passing and failing
+ test:
+
+ public static class WatchmanTest {
+ private static String watchedLog;
+
+ @Rule
+ public MethodRule watchman= new TestWatchman() {
+ @Override
+ public void failed(Throwable e, FrameworkMethod method) {
+ watchedLog+= method.getName() + " "
+ + e.getClass().getSimpleName() + "\n";
+ }
+
+ @Override
+ public void succeeded(FrameworkMethod method) {
+ watchedLog+= method.getName() + " " + "success!\n";
+ }
+ };
+
+ @Test
+ public void fails() {
+ fail();
+ }
+
+ @Test
+ public void succeeds() {
+ }
+ }
+
+- The TestName Rule makes the current test name available inside test methods:
+
+ public class NameRuleTest {
+ @Rule public TestName name = new TestName();
+
+ @Test public void testA() {
+ assertEquals("testA", name.getMethodName());
+ }
+
+ @Test public void testB() {
+ assertEquals("testB", name.getMethodName());
+ }
+ }
+
+- The Timeout Rule applies the same timeout to all test methods in a class:
+
+ public static class HasGlobalTimeout {
+ public static String log;
+
+ @Rule public MethodRule globalTimeout = new Timeout(20);
+
+ @Test public void testInfiniteLoop1() {
+ log+= "ran1";
+ for(;;) {}
+ }
+
+ @Test public void testInfiniteLoop2() {
+ log+= "ran2";
+ for(;;) {}
+ }
+ }
+
+- The ExpectedException Rule allows in-test specification
+ of expected exception types and messages:
+
+ public static class HasExpectedException {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsNothing() {
+
+ }
+
+ @Test
+ public void throwsNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ throw new NullPointerException();
+ }
+
+ @Test
+ public void throwsNullPointerExceptionWithMessage() {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("happened?");
+ thrown.expectMessage(startsWith("What"));
+ throw new NullPointerException("What happened?");
+ }
+ }
+
+### Timeouts ###
+- Tests that time out now show the stack trace of the test thread.
+
+### Matchers ###
+- Due to typing incompatibilities, JUnit is still including the 1.1 release
+ of hamcrest. This is not a change from 4.6, but is a change from
+ pre-beta releases of 4.7. Due to this incompatibility, tests using
+ Hamcrest 1.2 must still use the MatcherAssert.assertThat method from
+ Hamcrest, not Assert.assertThat from JUnit.
+
+### Docs ###
+- Javadocs now link to online JDK javadocs (bug 2090230)
+- Parameterized runner javadocs improved (bug 2186792)
+- Fixed Javadoc code sample for AfterClass (2126279)
+- Fixed Javadoc for assertArraysEqual(float[], float[])
+
+### Bug fixes ###
+- Fixed: BaseTestRunner.getTest() requires class to extend TestCase (1812200)
+- Fixed: Suite does not allow for inheritance in annotations (2783118)
+- Fixed: ParallelComputer skipped tests that took longer than 2 seconds
diff --git a/junit4/doc/ReleaseNotes4.8.1.html b/junit4/doc/ReleaseNotes4.8.1.html
new file mode 100644
index 0000000..32e36a6
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.8.1.html
@@ -0,0 +1,9 @@
+<h2>Summary of Changes in version 4.8.1</h2>
+
+<p>This was a quick bugfix release for an important bug</p>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>github#61: Category annotations on classes were not honored.</li>
+</ul>
diff --git a/junit4/doc/ReleaseNotes4.8.1.txt b/junit4/doc/ReleaseNotes4.8.1.txt
new file mode 100644
index 0000000..bc13f26
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.8.1.txt
@@ -0,0 +1,7 @@
+## Summary of Changes in version 4.8.1 ##
+
+This was a quick bugfix release for an important bug
+
+### Bug fixes ###
+
+- github#61: Category annotations on classes were not honored. \ No newline at end of file
diff --git a/junit4/doc/ReleaseNotes4.8.2.html b/junit4/doc/ReleaseNotes4.8.2.html
new file mode 100644
index 0000000..273f03b
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.8.2.html
@@ -0,0 +1,10 @@
+<h2>Summary of Changes in version 4.8.2</h2>
+
+<p>This was a quick bugfix release</p>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>github#96: TestSuite(MyTestCase.class) should dynamically detect if MyTestCase
+is a TestCase</li>
+</ul>
diff --git a/junit4/doc/ReleaseNotes4.8.2.txt b/junit4/doc/ReleaseNotes4.8.2.txt
new file mode 100644
index 0000000..8631275
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.8.2.txt
@@ -0,0 +1,8 @@
+## Summary of Changes in version 4.8.2 ##
+
+This was a quick bugfix release
+
+### Bug fixes ###
+
+- github#96: TestSuite(MyTestCase.class) should dynamically detect if MyTestCase
+ is a TestCase
diff --git a/junit4/doc/ReleaseNotes4.8.html b/junit4/doc/ReleaseNotes4.8.html
new file mode 100644
index 0000000..086f5d0
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.8.html
@@ -0,0 +1,59 @@
+<h2>Summary of Changes in version 4.8</h2>
+
+<h3>Categories</h3>
+
+<p>From a given set of test classes, the <code>Categories</code> runner
+runs only the classes and methods
+that are annotated with either the category given with the <code>@IncludeCategory</code>
+annotation, or a subtype of that category. Either classes or interfaces can be
+used as categories. Subtyping works, so if you say <code>@IncludeCategory(SuperClass.class)</code>,
+a test marked <code>@Category({SubClass.class})</code> will be run.</p>
+
+<p>You can also exclude categories by using the <code>@ExcludeCategory</code> annotation</p>
+
+<p>Example:</p>
+
+<pre><code>public interface FastTests { /* category marker */ }
+public interface SlowTests { /* category marker */ }
+
+public class A {
+ @Test
+ public void a() {
+ fail();
+ }
+
+ @Category(SlowTests.class)
+ @Test
+ public void b() {
+ }
+}
+
+@Category({SlowTests.class, FastTests.class})
+public class B {
+ @Test
+ public void c() {
+
+ }
+}
+
+@RunWith(Categories.class)
+@IncludeCategory(SlowTests.class)
+@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
+public class SlowTestSuite {
+ // Will run A.b and B.c, but not A.a
+}
+
+@RunWith(Categories.class)
+@IncludeCategory(SlowTests.class)
+@ExcludeCategory(FastTests.class)
+@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
+public class SlowTestSuite {
+ // Will run A.b, but not A.a or B.c
+}
+</code></pre>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>github#16: thread safety of Result counting</li>
+</ul>
diff --git a/junit4/doc/ReleaseNotes4.8.txt b/junit4/doc/ReleaseNotes4.8.txt
new file mode 100644
index 0000000..4a30db6
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.8.txt
@@ -0,0 +1,56 @@
+## Summary of Changes in version 4.8 ##
+
+### Categories ###
+
+From a given set of test classes, the `Categories` runner
+runs only the classes and methods
+that are annotated with either the category given with the `@IncludeCategory`
+annotation, or a subtype of that category. Either classes or interfaces can be
+used as categories. Subtyping works, so if you say `@IncludeCategory(SuperClass.class)`,
+a test marked `@Category({SubClass.class})` will be run.
+
+You can also exclude categories by using the `@ExcludeCategory` annotation
+
+Example:
+
+ public interface FastTests { /* category marker */ }
+ public interface SlowTests { /* category marker */ }
+
+ public class A {
+ @Test
+ public void a() {
+ fail();
+ }
+
+ @Category(SlowTests.class)
+ @Test
+ public void b() {
+ }
+ }
+
+ @Category({SlowTests.class, FastTests.class})
+ public class B {
+ @Test
+ public void c() {
+
+ }
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(SlowTests.class)
+ @SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
+ public class SlowTestSuite {
+ // Will run A.b and B.c, but not A.a
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(SlowTests.class)
+ @ExcludeCategory(FastTests.class)
+ @SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
+ public class SlowTestSuite {
+ // Will run A.b, but not A.a or B.c
+ }
+
+### Bug fixes ###
+
+- github#16: thread safety of Result counting \ No newline at end of file
diff --git a/junit4/doc/ReleaseNotes4.9.1.txt b/junit4/doc/ReleaseNotes4.9.1.txt
new file mode 100644
index 0000000..eded783
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.9.1.txt
@@ -0,0 +1,14 @@
+## Summary of Changes in version 4.9.1 [unreleased!] ##
+
+### Theories ###
+
+The `Theories` runner does not anticipate theory parameters that have generic
+types, as reported by github#64. Fixing this won't happen until `Theories` is
+moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the
+necessary machinery to the runner classes, and deprecates a method that only
+the `Theories` runner uses, `FrameworkMethod`#producesType().
+The Common Public License that JUnit is released under is now included
+in the source repository.
+
+Thanks to `@pholser` for identifying a potential resolution for github#64
+and initiating work on it.
diff --git a/junit4/doc/ReleaseNotes4.9.html b/junit4/doc/ReleaseNotes4.9.html
new file mode 100644
index 0000000..3692102
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.9.html
@@ -0,0 +1,96 @@
+<h2>Summary of Changes in version 4.9, final</h2>
+
+<p>Release theme: Test-class and suite level Rules.</p>
+
+<h3>ClassRule</h3>
+
+<p>The <code>ClassRule</code> annotation extends the idea of method-level Rules,
+adding static fields that can affect the operation of a whole class. Any
+subclass of <code>ParentRunner</code>, including the standard <code>BlockJUnit4ClassRunner</code>
+and <code>Suite</code> classes, will support <code>ClassRule</code>s.</p>
+
+<p>For example, here is a test suite that connects to a server once before
+all the test classes run, and disconnects after they are finished:</p>
+
+<pre><code>@RunWith(Suite.class)
+@SuiteClasses({A.class, B.class, C.class})
+public class UsesExternalResource {
+ public static Server myServer= new Server();
+
+ @ClassRule
+ public static ExternalResource resource= new ExternalResource() {
+ @Override
+ protected void before() throws Throwable {
+ myServer.connect();
+ };
+
+ @Override
+ protected void after() {
+ myServer.disconnect();
+ };
+ };
+}
+</code></pre>
+
+<h3>TestRule</h3>
+
+<p>In JUnit 4.9, fields that can be annotated with either <code>@Rule</code> or <code>@ClassRule</code>
+should be of type <code>TestRule</code>. The old <code>MethodRule</code> type, which only made sense
+for method-level rules, will still work, but is deprecated.</p>
+
+<p>Most built-in Rules have been moved to the new type already, in a way that
+should be transparent to most users. <code>TestWatchman</code> has been deprecated,
+and replaced by <code>TestWatcher</code>, which has the same functionality, but implements
+the new type.</p>
+
+<h3>Maven support</h3>
+
+<p>Maven bundles have, in the past, been uploaded by kind volunteers. Starting
+with this release, the JUnit team is attempting to perform this task ourselves.</p>
+
+<h3>LICENSE checked in</h3>
+
+<p>The Common Public License that JUnit is released under is now included
+in the source repository.</p>
+
+<h3>Bug fixes</h3>
+
+<ul>
+<li>github#98: assumeTrue() does not work with expected exceptions</li>
+<li><p>github#74: Categories + Parameterized</p>
+
+<p>In JUnit 4.8.2, the Categories runner would fail to run correctly
+if any contained test class had a custom Runner with a structure
+significantly different from the built-in Runner. With this fix,
+such classes can be assigned one or more categories at the class level,
+and will be run correctly. Trying to assign categories to methods within
+such a class will flag an error.</p></li>
+<li><p>github#38: ParentRunner filters more than once</p>
+
+<p>Thanks to <code>@reinholdfuereder</code></p></li>
+<li><p>github#248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2</p></li>
+<li>github#187: Accidental dependency on Java 6</li>
+</ul>
+
+<p>Thanks to <code>@kcooney</code> for:</p>
+
+<ul>
+<li>github#163: Bad comparison failure message when using assertEquals(String, String)</li>
+<li>github#227: ParentRunner now assumes that getChildren() returns a modifiable list</li>
+</ul>
+
+<h3>Minor changes</h3>
+
+<ul>
+<li>Backed out unused folder "experimental-use-of-antunit", replaced by
+bash-based script at build_tests.sh</li>
+<li>Various Javadoc fixes</li>
+</ul>
+
+<p>Thanks to <code>@kcooney</code> for:</p>
+
+<ul>
+<li>Made MultipleFailureException public, to assist extension writers.</li>
+<li>github#240: Add "test" target to build.xml, for faster ant-driven testing.</li>
+<li>github#247: Give InitializationError a useful message</li>
+</ul>
diff --git a/junit4/doc/ReleaseNotes4.9.txt b/junit4/doc/ReleaseNotes4.9.txt
new file mode 100644
index 0000000..8b2a63d
--- /dev/null
+++ b/junit4/doc/ReleaseNotes4.9.txt
@@ -0,0 +1,89 @@
+## Summary of Changes in version 4.9, final ##
+
+Release theme: Test-class and suite level Rules.
+
+### ClassRule ###
+
+The `ClassRule` annotation extends the idea of method-level Rules,
+adding static fields that can affect the operation of a whole class. Any
+subclass of `ParentRunner`, including the standard `BlockJUnit4ClassRunner`
+and `Suite` classes, will support `ClassRule`s.
+
+For example, here is a test suite that connects to a server once before
+all the test classes run, and disconnects after they are finished:
+
+ @RunWith(Suite.class)
+ @SuiteClasses({A.class, B.class, C.class})
+ public class UsesExternalResource {
+ public static Server myServer= new Server();
+
+ @ClassRule
+ public static ExternalResource resource= new ExternalResource() {
+ @Override
+ protected void before() throws Throwable {
+ myServer.connect();
+ };
+
+ @Override
+ protected void after() {
+ myServer.disconnect();
+ };
+ };
+ }
+
+### TestRule ###
+
+In JUnit 4.9, fields that can be annotated with either `@Rule` or `@ClassRule`
+should be of type `TestRule`. The old `MethodRule` type, which only made sense
+for method-level rules, will still work, but is deprecated.
+
+Most built-in Rules have been moved to the new type already, in a way that
+should be transparent to most users. `TestWatchman` has been deprecated,
+and replaced by `TestWatcher`, which has the same functionality, but implements
+the new type.
+
+### Maven support ###
+
+Maven bundles have, in the past, been uploaded by kind volunteers. Starting
+with this release, the JUnit team is attempting to perform this task ourselves.
+
+### LICENSE checked in ###
+
+The Common Public License that JUnit is released under is now included
+in the source repository.
+
+### Bug fixes ###
+
+- github#98: assumeTrue() does not work with expected exceptions
+- github#74: Categories + Parameterized
+
+ In JUnit 4.8.2, the Categories runner would fail to run correctly
+ if any contained test class had a custom Runner with a structure
+ significantly different from the built-in Runner. With this fix,
+ such classes can be assigned one or more categories at the class level,
+ and will be run correctly. Trying to assign categories to methods within
+ such a class will flag an error.
+
+- github#38: ParentRunner filters more than once
+
+ Thanks to `@reinholdfuereder`
+
+- github#248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2
+- github#187: Accidental dependency on Java 6
+
+Thanks to `@kcooney` for:
+
+- github#163: Bad comparison failure message when using assertEquals(String, String)
+- github#227: ParentRunner now assumes that getChildren() returns a modifiable list
+
+### Minor changes ###
+
+- Backed out unused folder "experimental-use-of-antunit", replaced by
+ bash-based script at build_tests.sh
+- Various Javadoc fixes
+
+Thanks to `@kcooney` for:
+
+- Made MultipleFailureException public, to assist extension writers.
+- github#240: Add "test" target to build.xml, for faster ant-driven testing.
+- github#247: Give InitializationError a useful message
diff --git a/junit4/doc/building-junit.txt b/junit4/doc/building-junit.txt
new file mode 100644
index 0000000..e785b05
--- /dev/null
+++ b/junit4/doc/building-junit.txt
@@ -0,0 +1,19 @@
+Steps to build junit:
+
+- Must be manual
+ - Write release notes
+ - Update version in build.xml
+- Not too tedious:
+ - Push to github (dsaff _and_ KentBeck)
+ - Run the ant zip task
+ - Upload stuff to github (including tag)
+ - Push to maven
+ - ant -lib build/lib stage.maven
+ - Promote
+- Tedious:
+ - Update SourceForge if major release
+ - Update javadocs on github site (and "latest" link)
+ - Update javadocs on junit.org
+ - Put release notes on github.
+ - Announce on blog, user list, dev list, announce list, junit.org, twitter
+- Profit!
diff --git a/junit4/doc/cookbook/cookbook.htm b/junit4/doc/cookbook/cookbook.htm
new file mode 100644
index 0000000..2cf8eec
--- /dev/null
+++ b/junit4/doc/cookbook/cookbook.htm
@@ -0,0 +1,143 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Microsoft FrontPage 4.0">
+ <meta name="Author" content="Erich Gamma">
+ <title>JUnit Cookbook</title>
+</head>
+<body>
+
+<h1>
+<font color="#33FF33">J</font><font color="#CC0000">U</font>nit Cookbook</h1>
+
+<p>
+Kent Beck, Erich Gamma</p>
+
+<hr WIDTH="100%">
+<br>Here is a short cookbook showing you the steps you can follow in writing
+and organizing your own tests using JUnit.
+<h2>
+Simple Test Case</h2>
+How do you write testing code?
+<p>The simplest way is as an expression in a debugger. You can change debug
+expressions without recompiling, and you can wait to decide what to write
+until you have seen the running objects. You can also write test expressions
+as statements which print to the standard output stream. Both styles of
+tests are limited because they require human judgment to analyze their
+results. Also, they don't compose nicely- you can only execute one debug
+expression at a time and a program with too many print statements causes
+the dreaded "Scroll Blindness".
+<p>JUnit tests do not require human judgment to interpret, and it is easy
+to run many of them at the same time. When you need to test something,
+here is what you do:
+<ol>
+<li>
+Annotate a method with @org.junit.Test
+
+<li>
+When you want to check a value, import org.junit.Assert.* statically, call <tt>assertTrue</tt>() and pass a boolean
+that is true if the test succeeds</li>
+</ol>
+For example, to test that the sum of two Moneys with the same currency
+contains a value which is the sum of the values of the two Moneys, write:
+<blockquote>
+<pre><tt>@Test public void simpleAdd() {
+&nbsp;&nbsp;&nbsp; Money m12CHF= new Money(12, &quot;CHF&quot;);&nbsp;
+&nbsp;&nbsp;&nbsp; Money m14CHF= new Money(14, &quot;CHF&quot;);&nbsp;
+&nbsp;&nbsp;&nbsp; Money expected= new Money(26, &quot;CHF&quot;);&nbsp;
+&nbsp;&nbsp;&nbsp; Money result= m12CHF.add(m14CHF);&nbsp;
+&nbsp;&nbsp;&nbsp; assertTrue(expected.equals(result));
+}</tt></pre>
+</blockquote>
+If you want to write a test similar to one you have already written, write
+a Fixture instead.
+<h2>
+Fixture</h2>
+What if you have two or more tests that operate on the same or similar
+sets of objects?
+<p>Tests need to run against the background of a known set of objects.
+This set of objects is called a test fixture. When you are writing tests
+you will often find that you spend more time writing the code to set up
+the fixture than you do in actually testing values.
+<p>To some extent, you can make writing the fixture code easier by paying
+careful attention to the constructors you write. However, a much bigger
+savings comes from sharing fixture code. Often, you will be able to use
+the same fixture for several different tests. Each case will send slightly
+different messages or parameters to the fixture and will check for different
+results.
+<p>When you have a common fixture, here is what you do:
+<ol>
+
+<li>
+Add a field for each part of the fixture</li>
+
+<li>
+Annotate a method with @org.junit.Before
+and initialize the variables in that method</li>
+
+<li>
+Annotate a method with @org.junit.After
+to release any permanent resources you allocated in setUp</li>
+</ol>
+For example, to write several test cases that want to work with different
+combinations of 12 Swiss Francs, 14 Swiss Francs, and 28 US Dollars, first
+create a fixture:
+<pre><tt>public class MoneyTest {&nbsp;
+&nbsp;&nbsp;&nbsp; private Money f12CHF;&nbsp;
+&nbsp;&nbsp;&nbsp; private Money f14CHF;&nbsp;
+&nbsp;&nbsp;&nbsp; private Money f28USD;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; @Before public void setUp() {&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f12CHF= new Money(12, &quot;CHF&quot;);&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f14CHF= new Money(14, &quot;CHF&quot;);&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f28USD= new Money(28, &quot;USD&quot;);&nbsp;
+&nbsp;&nbsp;&nbsp; }
+}</tt></pre>
+Once you have the Fixture in place, you can write as many Test Cases as
+you'd like. Add as many test methods (annotated with @Test) as you'd like.
+<h2>Running Tests</h2>
+How do you run your tests and collect their results?
+<p>Once you have tests, you'll want to run them. JUnit provides tools
+to define the suite to be run and to display its results. To run tests and see the
+results on the console, run this from a Java program:
+<blockquote>
+<pre>
+org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...);
+</pre>
+</blockquote>
+or this from the command line, with both your test class and junit on the classpath:
+<blockquote>
+<pre>
+java org.junit.runner.JUnitCore TestClass1.class [...other test classes...]
+</pre>
+</blockquote>
+
+You make your JUnit 4 test classes accessible to a TestRunner designed to work with earlier versions of JUnit,
+declare a static method <i>suite</i>
+that returns a test.
+<blockquote>
+<pre><tt>public static junit.framework.Test suite() {&nbsp;
+&nbsp;&nbsp;&nbsp; return new JUnit4TestAdapter(Example.class);&nbsp;
+}</tt></pre>
+</blockquote>
+<h2>
+Expected Exceptions</h2>
+How do you verify that code throws exceptions as expected?
+<p>Verifying that code completes normally is only part of programming. Making sure the code
+behaves as expected in exceptional situations is part of the craft of programming too. For example:
+<blockquote>
+<pre><tt>new ArrayList&lt;Object&gt;().get(0);&nbsp;
+</tt></pre>
+</blockquote>
+This code should throw an IndexOutOfBoundsException. The @Test annotation has an optional parameter "expected"
+that takes as values subclasses of Throwable. If we wanted to verify that ArrayList throws the correct exception,
+we would write:
+<blockquote>
+<pre><tt>@Test(expected= IndexOutOfBoundsException.class) public void empty() {&nbsp;
+&nbsp;&nbsp;&nbsp; new ArrayList&lt;Object&gt;().get(0);&nbsp;
+}</tt></pre>
+</blockquote>
+<hr WIDTH="100%">
+</body>
+</html>
diff --git a/junit4/doc/cookbook/logo.gif b/junit4/doc/cookbook/logo.gif
new file mode 100644
index 0000000..d0e1547
--- /dev/null
+++ b/junit4/doc/cookbook/logo.gif
Binary files differ
diff --git a/junit4/doc/cookstour/Image1.gif b/junit4/doc/cookstour/Image1.gif
new file mode 100644
index 0000000..398d4cc
--- /dev/null
+++ b/junit4/doc/cookstour/Image1.gif
Binary files differ
diff --git a/junit4/doc/cookstour/Image2.gif b/junit4/doc/cookstour/Image2.gif
new file mode 100644
index 0000000..072149f
--- /dev/null
+++ b/junit4/doc/cookstour/Image2.gif
Binary files differ
diff --git a/junit4/doc/cookstour/Image3.gif b/junit4/doc/cookstour/Image3.gif
new file mode 100644
index 0000000..dbf6649
--- /dev/null
+++ b/junit4/doc/cookstour/Image3.gif
Binary files differ
diff --git a/junit4/doc/cookstour/Image4.gif b/junit4/doc/cookstour/Image4.gif
new file mode 100644
index 0000000..b0b1f2b
--- /dev/null
+++ b/junit4/doc/cookstour/Image4.gif
Binary files differ
diff --git a/junit4/doc/cookstour/Image5.gif b/junit4/doc/cookstour/Image5.gif
new file mode 100644
index 0000000..5393c63
--- /dev/null
+++ b/junit4/doc/cookstour/Image5.gif
Binary files differ
diff --git a/junit4/doc/cookstour/Image6.gif b/junit4/doc/cookstour/Image6.gif
new file mode 100644
index 0000000..6804925
--- /dev/null
+++ b/junit4/doc/cookstour/Image6.gif
Binary files differ
diff --git a/junit4/doc/cookstour/Image7.gif b/junit4/doc/cookstour/Image7.gif
new file mode 100644
index 0000000..6af54a6
--- /dev/null
+++ b/junit4/doc/cookstour/Image7.gif
Binary files differ
diff --git a/junit4/doc/cookstour/cookstour.htm b/junit4/doc/cookstour/cookstour.htm
new file mode 100644
index 0000000..597dcd8
--- /dev/null
+++ b/junit4/doc/cookstour/cookstour.htm
@@ -0,0 +1,668 @@
+<!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 Word 97">
+ <meta name="GENERATOR" content="Mozilla/4.5 [en] (Win95; I) [Netscape]">
+ <meta name="Author" content="ERICH GAMMA">
+ <title>JUnit: A Cook’s Tour</title>
+</head>
+<body>
+
+<h1>
+<font color="#33FF33">J</font><font color="#CC0000">U</font>nit A Cook's
+Tour</h1>
+<br>Note: this article is based on JUnit 3.8.x.
+<hr WIDTH="100%">
+<p><b><font face="Arial"><font size=+1>1. Introduction</font></font></b>
+<p><font size=-1>In an earlier article (see Test Infected: Programmers
+Love Writing Tests, Java Report, July 1998, Volume 3, Number 7), we described
+how to use a simple framework to write repeatable tests. In this article,
+we will take a peek under the covers and show you how the framework itself
+is constructed.</font>
+<p><font size=-1>We carefully studied the JUnit framework and reflected
+on how we constructed it. We found lessons at many different levels. In
+this article we will try communicate them all at once, a hopeless task,
+but at least we will do it in the context of showing you the design and
+construction of a piece of software with proven value.</font>
+<p><font size=-1>We open with a discussion of the goals of the framework.
+The goals will reappear in many small details during the presentation of
+the framework itself. Following this, we present the design and implementation
+of the framework. The design will be described in terms of patterns (surprise,
+surprise), the implementation as a literate program. We conclude with a
+few choice thoughts about framework development.</font>
+<p><b><font face="Arial"><font size=+1>2. Goals</font></font></b>
+<p><font size=-1>What are the goals of JUnit?</font>
+<p><font size=-1>First, we have to get back to the assumptions of development.
+If a program feature lacks an automated test, we assume it doesn’t work.
+This seems much safer than the prevailing assumption, that if a developer
+assures us a program feature works, then it works now and forever.</font>
+<p><font size=-1>From this perspective, developers aren’t done when they
+write and debug the code, they must also write tests that demonstrate that
+the program works. However, everybody is too busy, they have too much to
+do, they don’t have enough time, to screw around with testing. I have too
+much code to write already, how am I supposed write test code, too? Answer
+me that, Mr. Hard-case Project Manager.</font>
+<p><font size=-1>So, the number one goal is to write a framework within
+which we have some glimmer of hope that developers will actually write
+tests. The framework has to use familiar tools, so there is little new
+to learn. It has to require no more work than absolutely necessary to write
+a new test. It has to eliminate duplicated effort.</font>
+<p><font size=-1>If this was all tests had to do, you would be done just
+by writing expressions in a debugger. However, this isn’t sufficient for
+testing. Telling me that your program works now doesn’t help me, because
+it doesn’t assure me that your program will work one minute from now after
+I integrate, and it doesn’t assure me that your program will still work
+in five years, when you are long gone.</font>
+<p><font size=-1>So, the second goal of testing is creating tests that
+retain their value over time. Someone other than the original author has
+to be able to execute the tests and interpret the results. It should be
+possible to combine tests from various authors and run them together without
+fear of interference.</font>
+<p><font size=-1>Finally, it has to be possible to leverage existing tests
+to create new ones. Creating a setup or fixture is expensive and a framework
+has to enable reusing fixtures to run different tests. Oh, is that all?</font>
+<p><b><font face="Arial"><font size=+1>3. The Design of JUnit</font></font></b>
+<p><font size=-1>The design of JUnit will be presented in a style first
+used in (see "Patterns Generate Architectures", Kent Beck and Ralph Johnson,
+ECOOP 94). The idea is to explain the design of a system by starting with
+nothing and applying patterns, one after another, until you have the architecture
+of the system. We will present the architectural problem to be solved,
+summarize the pattern that solves it, and then show how the pattern was
+applied to JUnit.</font>
+<p><b><i><font face="Arial">3.1 Getting started- TestCase</font></i></b>
+<p><font size=-1>First we have to make an object to represent our basic
+concept, the TestCase. Developers often have tests cases in mind, but they
+realize them in many different ways-</font>
+<ul>
+<li>
+<font size=-1>print statements,</font></li>
+
+<li>
+<font size=-1>debugger expressions,</font></li>
+
+<li>
+<font size=-1>test scripts.</font></li>
+</ul>
+<font size=-1>If we want to make manipulating tests easy, we have to make
+them objects. This takes a test that was only implicit in the developer’s
+mind and makes it concrete, supporting our goal of creating tests that
+retain their value over time. At the same time, object developers are used
+to, well, developing with objects, so the decision to make tests into objects
+supports our goal of making test writing more inviting (or at least less
+imposing).</font>
+<p><font size=-1>The Command pattern (see Gamma, E., et al. Design Patterns:
+Elements of Reusable Object-Oriented Software, Addison-Wesley, Reading,
+MA, 1995) fits our needs quite nicely. Quoting from the intent, "Encapsulate
+a request as an object, thereby letting you… queue or log requests…" Command
+tells us to create an object for an operation and give it a method "execute".
+Here is the code for the class definition of TestCase:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public abstract class <b>TestCase</b>
+implements Test {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; …</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>Because we expect this class to be reused through inheritance,
+we declare it "public abstract". For now, ignore the fact that it implements
+the Test interface. For the purposes of our current design, you can think
+of TestCase as a lone class.</font>
+<p><font size=-1>Every TestCase is created with a name, so if a test fails,
+you can identify which test failed.</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public abstract class <b>TestCase</b>
+implements Test {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; private final String
+fName;</font></font>
+<p><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; public <b>TestCase</b>(String
+name) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+fName= name;</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<p><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; public abstract
+void <b>run</b>();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+…</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>To illustrate the evolution of JUnit, we use diagrams that
+show snapshots of the architecture. The notation we use is simple. It annotates
+classes with shaded boxes containing the associated pattern. When the role
+of the class in the pattern is obvious then only the pattern name is shown.
+If the role isn’t clear then the shaded box is augmented by the name of
+the participant this class corresponds to. This notation minimizes the
+clutter in diagrams and was first shown in (see Gamma, E., Applying Design
+Patterns in Java, in Java Gems, SIGS Reference Library, 1997) Figure 1
+shows this notation applied to TestCase. Since we are dealing with a single
+class and there can be no ambiguities just the pattern name is shown.</font>
+<center>
+<p><img SRC="Image1.gif" height=92 width=238>
+<p><font size=-1><b>Figure 1</b> TestCase applies Command</font></center>
+
+<p><b><i><font face="Arial">3.2 Blanks to fill in- run()</font></i></b>
+<p><font size=-1>The next problem to solve is giving the developer a convenient
+"place" to put their fixture code and their test code. The declaration
+of TestCase as abstract says that the developer is expected to reuse TestCase
+by subclassing. However, if all we could do was provide a superclass with
+one variable and no behavior, we wouldn’t be doing much to satisfy our
+first goal, making tests easier to write.</font>
+<p><font size=-1>Fortunately, there is a common structure to all tests-
+they set up a test fixture, run some code against the fixture, check some
+results, and then clean up the fixture. This means that each test will
+run with a fresh fixture and the results of one test can’t influence the
+result of another. This supports the goal of maximizing the value of the
+tests.</font>
+<p><font size=-1>Template Method addresses our problem quite nicely. Quoting
+from the intent, "Define the skeleton of an algorithm in an operation,
+deferring some steps to subclasses. Template Method lets subclasses redefine
+certain steps of an algorithm without changing the algorithm’s structure."
+This is exactly right. We want the developer to be able to separately consider
+how to write the fixture (set up and tear down) code and how to write the
+testing code. The execution of this sequence, however, will remain the
+same for all tests, no matter how the fixture code is written or how the
+testing code is written.</font>
+<p><font size=-1>Here is the template method:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public void <b>run</b>() {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; setUp();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; runTest();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; tearDown();</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>The default implementations of these methods do nothing:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>protected void <b>runTest</b>() {</font></font>
+<br><font face="Arial"><font size=-2>}</font></font>
+<p><font face="Arial"><font size=-2>protected void <b>setUp</b>() {</font></font>
+<br><font face="Arial"><font size=-2>}</font></font>
+<p><font face="Arial"><font size=-2>protected void <b>tearDown</b>() {</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>Since setUp and tearDown are intended to be overridden but
+will be called by the framework we declare them as protected. The second
+snapshot of our tour is depicted in Figure 2.</font>
+<center>
+<p><img SRC="Image2.gif" height=142 width=270>
+<p><font size=-1><b>Figure 2</b> TestCase.run() applies Template Method</font></center>
+
+<p><b><i><font face="Arial">3.3 Reporting results- TestResult</font></i></b>
+<p><font size=-1>If a TestCase runs in a forest, does anyone care about
+the result? Sure- you run tests to make sure they run. After the test has
+run, you want a record, a summary of what did and didn’t work.</font>
+<p><font size=-1>If tests had equal chances of succeeding or failing, or
+if we only ever ran one test, we could just set a flag in the TestCase
+object and go look at the flag when the test completed. However, tests
+are (intended to be) highly asymmetric- they usually work. Therefore, we
+only want to record the failures and a highly condensed summary of the
+successes.</font>
+<p><font size=-1>The Smalltalk Best Practice Patterns (see Beck, K. Smalltalk
+Best Practice Patterns, Prentice Hall, 1996) has a pattern that is applicable.
+It is called <i>Collecting Parameter</i>. It suggests that when you need
+to collect results over several methods, you should add a parameter to
+the method and pass an object that will collect the results for you. We
+create a new object, TestResult, to collect the results of running tests.</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public class <b>TestResult</b> extends
+Object {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; protected int fRunTests;</font></font>
+<p><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; public <b>TestResult</b>()
+{</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+fRunTests= 0;</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>This simple version of TestResult only counts the number
+of tests run. To use it, we have to add a parameter to the TestCase.run()
+method and notify the TestResult that the test is running:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public void <b>run</b>(TestResult
+result) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; result.startTest(this);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; setUp();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; runTest();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; tearDown();</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>And the TestResult has to keep track of the number of tests
+run:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public synchronized void <b>startTest</b>(Test
+test) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; fRunTests++;</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>We declare the TestResult method startTest as synchronized
+so that a single TestResult can collect the results safely when the tests
+are run in different threads. Finally, we want to retain the simple external
+interface of TestCase, so we create a no-parameter version of run() that
+creates its own TestResult:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public TestResult <b>run</b>() {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; TestResult result=
+createResult();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; run(result);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; return result;</font></font>
+<br><font face="Arial"><font size=-2>}</font></font>
+<p><font face="Arial"><font size=-2>protected TestResult <b>createResult</b>()
+{</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; return new TestResult();</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>Figure 3 shows our next design snapshot.</font>
+<center>
+<p><img SRC="Image3.gif" height=149 width=325>
+<p><font size=-1>Figure 3: TestResult applies Collecting Parameter</font></center>
+
+<p><font size=-1>If tests always ran correctly, then we wouldn’t have to
+write them. Tests are interesting when they fail, especially if we didn’t
+expect them to fail. What’s more, tests can fail in ways that we expect,
+for example by computing an incorrect result, or they can fail in more
+spectacular ways, for example by writing outside the bounds of an array.
+No matter how the test fails we want to execute the following tests.</font>
+<p><font size=-1>JUnit distinguishes between <i>failures</i> and <i>errors</i>.
+The possibility of a failure is anticipated and checked for with assertions.
+Errors are unanticipated problems like an ArrayIndexOutOfBoundsException.
+Failures are signaled with an AssertionFailedError error. To distinguish
+an unanticipated error from a failure, failures are caught in an extra
+catch clause (1). The second clause (2) catches all other exceptions and
+ensures that our test run continues..</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public void <b>run</b>(TestResult
+result) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; result.startTest(this);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; setUp();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; try {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+runTest();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; catch (AssertionFailedError
+e) { //1</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+result.addFailure(this, e);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<p><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; catch (Throwable
+e) { // 2</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+result.addError(this, e);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; finally {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+tearDown();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>An AssertionFailedError is triggered by the assert methods
+provided by TestCase. JUnit provides a set of assert methods for different
+purposes. Here is the simplest one:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>protected void <b>assertTrue</b>(boolean
+condition) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; if (!condition)</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+throw new AssertionFailedError();</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>The AssertionFailedError is not meant to be caught by the
+client (a testing method inside a TestCase) but inside the Template Method
+TestCase.run(). We therefore derive AssertionFailedError from Error.</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public class <b>AssertionFailedError</b>
+extends Error {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; public AssertionFailedError
+() {}</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>The methods to collect the errors in TestResult are shown
+below:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public synchronized void <b>addError</b>(Test
+test, Throwable t) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; fErrors.addElement(new
+TestFailure(test, t));</font></font>
+<br><font face="Arial"><font size=-2>}</font></font>
+<p><font face="Arial"><font size=-2>public synchronized void <b>addFailure</b>(Test
+test, Throwable t) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; fFailures.addElement(new
+TestFailure(test, t));</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>TestFailure is a little framework internal helper class to
+bind together the failed test and the signaled exception for later reporting.</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public class <b>TestFailure</b> extends
+Object {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; protected Test
+fFailedTest;</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; protected Throwable
+fThrownException;</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>The canonical form of collecting parameter requires us to
+pass the collecting parameter to each method. If we followed this advice,
+each of the testing methods would require a parameter for the TestResult.
+This results in a "pollution" of these method signatures. As a benevolent
+side effect of using exceptions to signal failures we can avoid this signature
+pollution. A test case method, or a helper method called from it, can throw
+an exception without having to know about the TestResult. As a refresher
+here is a sample test method from our MoneyTest suite. It illustrates how
+a testing method doesn’t have to know anything about a TestResult:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public void <b>testMoneyEquals</b>()
+{</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; assertTrue(!f12CHF.equals(null));</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; assertEquals(f12CHF,
+f12CHF);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; assertEquals(f12CHF,
+new Money(12, "CHF"));</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; assertTrue(!f12CHF.equals(f14CHF));</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>JUnit comes with different implementations of TestResult.
+The default implementation counts the number of failures and errors and
+collects the results. TextTestResult collects the results and presents
+them in a textual form. Finally, UITestResult is used by the graphical
+version of the JUnit Test Runner to update the graphical test status.</font>
+<p><font size=-1>TestResult is an extension point of the framework. Clients
+can define their own custom TestResult classes, for example, an HTMLTestResult
+reports the results as an HTML document.</font>
+<p><b><i><font face="Arial">3.4 No stupid subclasses - TestCase again</font></i></b>
+<p><font size=-1>We have applied Command to represent a test. Command relies
+on a single method like execute() (called run() in TestCase) to invoke
+it. This simple interface allows us to invoke different implementations
+of a command through the same interface.</font>
+<p><font size=-1>We need an interface to generically run our tests. However,
+all test cases are implemented as different methods in the same class.
+This avoids the unnecessary proliferation of classes. A given test case
+class may implement many different methods, each defining a single test
+case. Each test case has a descriptive name like testMoneyEquals or testMoneyAdd.
+The test cases don’t conform to a simple command interface. Different instances
+of the same Command class need to be invoked with different methods. Therefore
+our next problem is make all the test cases look the same from the point
+of view of the invoker of the test.</font>
+<p><font size=-1>Reviewing the problems addressed by available design patterns,
+the Adapter pattern springs to mind. Adapter has the following intent "Convert
+the interface of a class into another interface clients expect". This sounds
+like a good match. Adapter tells us different ways to do this. One of them
+is a class adapter, which uses subclassing to adapt the interface. For
+example, to adapt testMoneyEquals to runTest we implement a subclass of
+MoneyTest and override runTest to invoke testMoneyEquals.</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public class <b>TestMoneyEquals</b>
+extends MoneyTest {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; public TestMoneyEquals()
+{ super("testMoneyEquals"); }</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; protected void
+runTest () { testMoneyEquals(); }</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>The use of subclassing requires us to implement a subclass
+for each test case. This puts an additional burden on the tester. This
+is against the JUnit goal that the framework should make it as simple as
+possible to add a test case. In addition, creating a subclass for each
+testing method results in class bloat. Many classes with only a single
+method are not worth their costs and it will be difficult to come up with
+meaningful names.</font>
+<p><font size=-1>Java provides anonymous inner classes which provide an
+interesting Java-specific solution to the class naming problem. With anonymous
+inner classes we can create an Adapter without having to invent a class
+name:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>TestCase test= new MoneyTest("testMoneyEquals
+") {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; protected void
+runTest() { testMoneyEquals(); }</font></font>
+<br><font face="Arial"><font size=-2>};</font></font></dir>
+</dir>
+<font size=-1>This is much more convenient than full subclassing. It preserves
+compile-time type checking at the cost of some burden on the developer.
+Smalltalk Best Practice Patterns describes another solution for the problem
+of different instances behaving differently under the common heading of<i>
+pluggable behavior</i>. The idea is to use a single class which can be
+parameterized to perform different logic without requiring subclassing.</font>
+<p><font size=-1>The simplest form of pluggable behavior is the <i>Pluggable
+Selector</i>. Pluggable Selector stores a Smalltalk method selector in
+an instance variable. This idea is not limited to Smalltalk. It is also
+applicable to Java. In Java there is no notion of a method selector. However,
+the Java reflection API allows us to invoke a method from a string representing
+the method’s name. We can use this feature to implement a pluggable selector
+in Java. As an aside, we usually don’t use reflection in ordinary application
+code. In our case we are dealing with an infrastructure framework and it
+is therefore OK to wear the reflection hat.</font>
+<p><font size=-1>JUnit offers the client the choice of using pluggable
+selector or implementing an anonymous adapter class as shown above. To
+do so, we provide the pluggable selector as the default implementation
+of the runTest method. In this case the name of the test case has to correspond
+to the name of a test method. We use reflection to invoke the method as
+shown below. First we look up the Method object. Once we have the method
+object we can invoke it and pass its arguments. Since our test methods
+take no arguments we can pass an empty argument array:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>protected void <b>runTest</b>() throws
+Throwable {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; Method runMethod=
+null;</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; try {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+runMethod= getClass().getMethod(fName, new Class[0]);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; } catch (NoSuchMethodException
+e) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+assertTrue("Method \""+fName+"\" not found", false);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; try {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+runMethod.invoke(this, new Class[0]);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; // catch InvocationTargetException
+and IllegalAccessException</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>The JDK 1.1 reflection API only allows us to find public
+methods. For this reason you have to declare the test methods as public,
+otherwise you will get a NoSuchMethodException.</font>
+<p><font size=-1>Here is the next design snapshot, with Adapter and Pluggable
+Selector added.</font>
+<center>
+<p><img SRC="Image4.gif" height=271 width=278>
+<p><font size=-1>Figure 4: TestCase applies either Adapter with an anonymous
+inner class or Pluggable Selector</font></center>
+
+<p><b><i><font face="Arial">3.5 Don’t care about one or many - TestSuite</font></i></b>
+<p><font size=-1>To get confidence in the state of a system we need to
+run many tests. Up to this point JUnit can run a single test case and report
+the result in a TestResult. Our next challenge is to extend it so that
+it can run many different tests. This problem can be solved easily when
+the invoker of the tests doesn’t have to care about whether it runs one
+or many test cases. A popular pattern to pull out in such a situation is
+Composite. To quote its intent "Compose objects into tree structures to
+represent part-whole hierarchies. Composite lets clients treat individual
+objects and compositions of objects uniformly." The point about part-whole
+hierarchies is of interest here. We want to support suites of suites of
+suites of tests.</font>
+<p><font size=-1>Composite introduces the following participants:</font>
+<ul>
+<li>
+<font size=-1>Component: declares the interface we want to use to interact
+with our tests.</font></li>
+
+<li>
+<font size=-1>Composite: implements this interface and maintains a collection
+of tests.</font></li>
+
+<li>
+<font size=-1>Leaf: represents a test case in a composition that conforms
+to the Component interface.</font></li>
+</ul>
+<font size=-1>The pattern tells us to introduce an abstract class which
+defines the common interface for single and composite objects. The primary
+purpose of the class is to define an interface. When applying Composite
+in Java we prefer to define an interface and not an abstract class. Using
+an interface avoids committing JUnit to a specific base class for tests.
+All that is required is that the tests conform to this interface. We therefore
+tweak the pattern description and introduce a Test interface:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public interface <b>Test</b> {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; public abstract
+void run(TestResult result);</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>TestCase corresponds to a Leaf in Composite and implements
+this interface as we have seen above.</font>
+<p><font size=-1>Next, we introduce the Composite participant. We name
+the class TestSuite. A TestSuite keeps its child tests in a Vector:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public class <b>TestSuite</b> implements
+<b>Test</b>
+{</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; private Vector
+fTests= new Vector();</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>The run() method delegates to its children:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public void <b>run</b>(TestResult
+result) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; for (Enumeration
+e= fTests.elements(); e.hasMoreElements(); ) {</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test test= (Test)e.nextElement();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+test.run(result);</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; }</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+
+<center><img SRC="Image5.gif" height=241 width=562>
+<p><font size=-1>Figure 5: TestSuite applies Composite</font></center>
+
+<p><font size=-1>Finally, clients have to be able to add tests to a suite,
+they can do so with the method addTest:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public void <b>addTest</b>(Test test)
+{</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; fTests.addElement(test);</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>Notice how all of the above code only depends on the Test
+interface. Since both TestCase and TestSuite conform to the Test interface
+we can recursively compose suites of test suites. All developers can create
+their own TestSuites. We can run them all by creating a TestSuite composed
+of those suites.</font>
+<p><font size=-1>Here is an example of creating a TestSuite:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public static Test <b>suite</b>()
+{</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; TestSuite suite=
+new TestSuite();</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; suite.addTest(new
+MoneyTest("testMoneyEquals"));</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; suite.addTest(new
+MoneyTest("testSimpleAdd"));</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>This works fine, but it requires us to add all the tests
+to a suite manually. Early adopters of JUnit told us this was stupid. Whenever
+you write a new test case you have to remember to add it to a static suite()
+method, otherwise it will not be run. We added a convenience constructor
+to TestSuite which takes the test case class as an argument. Its purpose
+is to extract the test methods and create a suite containing them. The
+test methods must follow the simple convention that they start with the
+prefix "test" and take no arguments. The convenience constructor uses this
+convention, constructing the test objects by using reflection to find the
+testing methods. Using this constructor the above code is simplified to:</font>
+<dir>
+<dir><font face="Arial"><font size=-2>public static Test <b>suite</b>()
+{</font></font>
+<br><font face="Arial"><font size=-2>&nbsp;&nbsp;&nbsp; return new TestSuite(MoneyTest.class);</font></font>
+<br><font face="Arial"><font size=-2>}</font></font></dir>
+</dir>
+<font size=-1>The original way is still useful when you want to run a subset
+of the test cases only.</font>
+<p><b><i><font face="Arial">3.6 Summary</font></i></b>
+<p><font size=-1>We are at the end of our cook’s tour through JUnit. The
+following figure shows the design of JUnit at a glance explained with patterns.</font>
+<center>
+<p><img SRC="Image6.gif" height=394 width=605>
+<p><font size=-1>Figure 6: JUnit Patterns Summary</font></center>
+
+<p><font size=-1>Notice how TestCase, the central abstraction in the framework,
+is involved in four patterns. Pictures of mature object designs show this
+same "pattern density". The star of the design has a rich set of relationships
+with the supporting players.</font>
+<p><font size=-1>Here is another way of looking at all of the patterns
+in JUnit. In this storyboard you see an abstract representation of the
+effect of each of the patterns in turn. So, the Command pattern creates
+the TestCase class, the Template Method pattern creates the run method,
+and so on. (The notation of the storyboard is the notation of figure 6
+with all the text deleted).</font>
+<center>
+<p><img SRC="Image7.gif" height=231 width=792>
+<p><font size=-1>Figure 7: JUnit Pattern Storyboard</font></center>
+
+<p><font size=-1>One point to notice about the storyboard is how the complexity
+of the picture jumps when we apply Composite. This is pictorial corroboration
+for our intuition that Composite is a powerful pattern, but that it "complicates
+the picture." It should therefore be used with caution.</font>
+<p><b><font face="Arial"><font size=+1>4. Conclusion</font></font></b>
+<p><font size=-1>To conclude, let’s make some general observations:</font>
+<ul>
+<li>
+<i><font size=-1>Patterns</font></i></li>
+
+<br><font size=-1>We found discussing the design in terms of patterns to
+be invaluable, both as we were developing the framework and as we try to
+explain it to others. You are now in a perfect position to judge whether
+describing a framework with patterns is effective. If you liked the discussion
+above, try the same style of presentation for your own system.</font>
+<li>
+<i><font size=-1>Pattern density</font></i></li>
+
+<br><font size=-1>There is a high pattern "density" around TestCase, which
+is the key abstraction of JUnit. Designs with high pattern density are
+easier to use but harder to change. We have found that such a high pattern
+density around key abstractions is common for mature frameworks. The opposite
+should be true of immature frameworks - they should have low pattern density.
+Once you discover what problem you are really solving, then you can begin
+to "compress" the solution, leading to a denser and denser field of patterns
+where they provide leverage.</font>
+<li>
+<i><font size=-1>Eat your own dog food</font></i></li>
+
+<br><font size=-1>As soon as we had the base unit testing functionality
+implemented, we applied it ourselves. A TestTest verifies that the framework
+reports the correct results for errors, successes, and failures. We found
+this invaluable as we continued to evolve the design of the framework.
+We found that the most challenging application of JUnit was testing its
+own behavior.</font>
+<li>
+<i><font size=-1>Intersection, not union</font></i></li>
+
+<br><font size=-1>There is a temptation in framework development to include
+every feature you can. After all, you want to make the framework as valuable
+as possible. However, there is a counteracting force- developers have to
+decide to use your framework. The fewer features the framework has, the
+easier it is to learn, the more likely a developer will use it. JUnit is
+written in this style. It implements only those features absolutely essential
+to running tests- running suites of tests, isolating the execution of tests
+from each other, and running tests automatically. Sure, we couldn’t resist
+adding some features but we were careful to put them into their own extensions
+package (test.extensions). A notable member of this package is a TestDecorator
+allowing execution of additional code before and after a test.</font>
+<li>
+<i><font size=-1>Framework writers read their code</font></i></li>
+
+<br><font size=-1>We spent far more time reading the JUnit code than we
+spent writing it, and nearly as much time removing duplicate functionality
+as we spent adding new functionality. We experimented aggressively with
+the design, adding new classes and moving responsibility around in as many
+different ways as we could imagine. We were rewarded (and are still being
+rewarded) for our monomania by a continuous flow of insights into JUnit,
+testing, object design, framework development, and opportunities for further
+articles.</font></ul>
+<font size=-1>The latest version of JUnit can be downloaded from http://www.junit.org.</font>
+<p><b><font face="Arial"><font size=+1>5. Acknowledgements</font></font></b>
+<p><font size=-1>Thanks to John Vlissides, Ralph Johnson, and Nick Edgar
+for careful reading and gentle correction.</font>
+</body>
+</html>
diff --git a/junit4/doc/faq/faq.htm b/junit4/doc/faq/faq.htm
new file mode 100644
index 0000000..783557e
--- /dev/null
+++ b/junit4/doc/faq/faq.htm
@@ -0,0 +1,2380 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
+ <title>JUnit FAQ</title>
+
+ <style type="text/css">
+
+ body {
+ font-style: normal;
+ font-weight: normal;
+ margin-left: 10pt;
+ margin-right: 10pt;
+ }
+
+ a {
+ text-decoration: none;
+ }
+
+ a:hover {
+ text-decoration: underline;
+ }
+
+ .header {
+ color: black;
+ font-size: 125%;
+ font-weight: bold;
+ background: #33ff33;
+ padding-top: 2px;
+ padding-bottom: 2px;
+ padding-left: 5px;
+ margin-top: 25px;
+ }
+
+ .code {
+ background: white;
+ border-left: 5px solid #33ff33;
+ }
+
+ .code-red {
+ background: white;
+ border-left: 5px solid #cc0000;
+ }
+
+ </style>
+
+</head>
+
+<body>
+
+<h1>
+ <font color="#33ff33">J</font><font color="#cc0000">U</font>nit FAQ
+</h1>
+<hr size="1"/>
+
+
+<!--
+
+ Summary
+
+-->
+<p>
+<i>
+JUnit is a simple, open source framework to write and run repeatable
+tests. It is an instance of the xUnit architecture for unit testing
+frameworks.
+</i>
+</p>
+<hr size="1"/>
+<p>
+Edited by <a href="mailto:mike@clarkware.com">Mike Clark</a>
+(<a href="http://www.clarkware.com">http://clarkware.com</a>)
+</p>
+<p>
+Last modified on February 20, 2006
+</p>
+
+<hr/>
+
+<!--
+
+ Table of Contents
+
+-->
+
+<div class="header">
+Table of Contents
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a href="#faqinfo">FAQ Info</a></b>
+ </p>
+ <ol>
+ <li><a href="#faqinfo_1">Who is responsible for this FAQ?</a></li>
+ <li><a href="#faqinfo_2">How can I contribute to this FAQ?</a></li>
+ <li><a href="#faqinfo_3">Where do I get the latest version of
+ this FAQ?</a></li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a href="#overview">Overview</a></b>
+ </p>
+ <ol>
+ <li><a href="#overview_1">What is JUnit?</a></li>
+ <li><a href="#overview_2">Where is the JUnit home page?</a></li>
+ <li><a href="#overview_3">Where are the JUnit mailing lists and
+ forums?</a></li>
+ <li><a href="#overview_4">Where is the JUnit documentation?</a></li>
+ <li><a href="#overview_5">Where can I find articles on JUnit?</a></li>
+ <li><a href="#overview_6">What's the latest news on JUnit?</a></li>
+ <li><a href="#overview_7">How is JUnit licensed?</a></li>
+ <li><a href="#overview_8">What awards has JUnit won?</a></li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a href="#started">Getting Started</a></b>
+ </p>
+ <ol>
+ <li><a href="#started_1">Where do I download JUnit?</a></li>
+ <li><a href="#started_2">How do I install JUnit?</a></li>
+ <li><a href="#started_3">How do I uninstall JUnit?</a></li>
+ <li><a href="#started_4">How do I ask questions?</a></li>
+ <li><a href="#started_5">How do I submit bugs, patches, or
+ feature requests?</a></li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a href="#tests">Writing Tests</a></b>
+ </p>
+ <ol>
+ <li><a href="#tests_1">How do I write and run a simple test?</a></li>
+ <li><a href="#tests_2">How do I use a test fixture?</a></li>
+ <li><a href="#tests_4">How do I test a method that doesn't
+ return anything?</a></li>
+ <li><a href="#tests_5">Under what conditions should I test get()
+ and set() methods?</a></li>
+ <li><a href="#tests_6">Under what conditions should I not test
+ get() and set() methods?</a></li>
+ <li><a href="#tests_7">How do I write a test that passes when an
+ expected exception is thrown?</a></li>
+ <li><a href="#tests_8">How do I write a test that fails when an
+ unexpected exception is thrown?</a></li>
+ <li><a href="#tests_10">How do I test protected methods?</a></li>
+ <li><a href="#tests_11">How do I test private methods?</a></li>
+ <li><a href="#tests_12">Why does JUnit only report the first
+ failure in a single test?</a></li>
+ <li><a href="#tests_13">In Java 1.4, 'assert' is a
+ keyword. Won't this conflict with JUnit's assert()
+ method?</a></li>
+ <li><a href="#tests_14">How do I test things that must be run in
+ a J2EE container (e.g. servlets, EJBs)?</a></li>
+ <li><a href="#tests_15">Do I need to write a test class for
+ every class I need to test?</a></li>
+ <li><a href="#tests_16">Is there a basic template I can use to
+ create a test?</a></li>
+ <li><a href="#tests_17">How do I write a test for an abstract
+ class?</a></li>
+ <li><a href="#tests_18">When are tests garbage collected?</a></li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a href="#organize">Organizing Tests</a></b>
+ </p>
+ <ol>
+ <li><a href="#organize_1">Where should I put my test files?</a></li>
+ <li><a href="#organize_3">How can I run setUp() and tearDown()
+ code once for all of my tests?</a></li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a href="#running">Running Tests</a></b>
+ </p>
+ <ol>
+ <li><a href="#running_1">What CLASSPATH settings are needed to
+ run JUnit?</a></li>
+ <li><a href="#running_2">Why do I get a NoClassDefFoundError
+ when trying to test JUnit or run the samples?</a>
+ </li>
+ <li><a href="#running_4">How do I run JUnit from my command window?</a>
+ </li>
+ <li><a href="#running_5">How do I run JUnit using Ant?</a>
+ </li>
+ <li><a href="#running_6">How do I use Ant to create HTML test reports?</a>
+ </li>
+ <li><a href="#running_7">How do I pass command-line arguments to a test execution?</a>
+ </li>
+ <li><a href="#running_9">Why do I get a LinkageError when using
+ XML interfaces in my test class?</a>
+ </li>
+ <li><a href="#running_11">Why do I get the warning "AssertionFailedError: No
+ tests found in XXX" when I run my test?</a>
+ </li>
+ <li><a href="#running_12">Why do I see "Unknown Source" in the stack trace of
+ a test failure, rather than the source file's line number?</a>
+ </li>
+ <li><a href="#running_15">How do I organize all test classes in a TestSuite
+ automatically and not use or manage a TestSuite explicitly?</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a href="#best">Best Practices</a></b>
+ </p>
+ <ol>
+ <li><a href="#best_1">When should tests be written?</a></li>
+ <li><a href="#best_2">Do I have to write a test for
+ everything?</a></li>
+ <li><a href="#best_3">How simple is 'too simple to break'?</a></li>
+ <li><a href="#best_4">How often should I run my tests?</a></li>
+ <li><a href="#best_5">What do I do when a defect is reported?</a></li>
+ <li><a href="#best_6">Why not just use System.out.println()?</a></li>
+ <li><a href="#best_7">Why not just use a debugger?</a></li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a href="#misc">Miscellaneous</a></b>
+ </p>
+ <ol>
+ <li><a href="#misc_1">How do I integrate JUnit with my IDE?</a></li>
+ <li><a href="#misc_2">How do I launch a debugger when a test
+ fails?</a></li>
+ <li><a href="#misc_3">Where can I find unit testing frameworks
+ similar to JUnit for other languages?</a></li>
+ </ol>
+ </li>
+ </ol>
+
+<!--
+
+ FAQ Info
+
+-->
+<div class="header">
+<a name="faqinfo">FAQ Info</a>
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a name="faqinfo_1">Who is responsible for this FAQ?</a></b>
+ </p>
+ <p>
+ The current version of this FAQ is maintained
+ by <a href="mailto:mike@clarkware.com">Mike Clark</a>.
+ </p>
+ <p>
+ Most of the wisdom contained in this FAQ comes from the
+ collective insights and hard-won experiences of the many good
+ folks who participate on the JUnit mailing list and the JUnit
+ community at large.
+ </p>
+ <p>
+ If you see your genius represented anywhere in this FAQ without
+ due credit to you, please send me an email and I'll make things
+ right.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="faqinfo_2">How can I contribute to this FAQ?</a></b>
+ </p>
+ <p>
+ Your contributions to this FAQ are greatly appreciated! The
+ JUnit community thanks you in advance.
+ </p>
+ <p>
+ To contribute to this FAQ, simply write a JUnit-related question
+ and answer, then send the unformatted text
+ to <a href="mailto:mike@clarkware.com">Mike Clark</a>.
+ Corrections to this FAQ are always appreciated, as well.
+ </p>
+ <p>
+ No reasonable contribution will be denied. Your name will
+ always appear along with any contribution you make.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="faqinfo_3">Where do I get the latest version of this
+ FAQ?</a></b>
+ </p>
+ <p>
+ The master copy of this FAQ is available
+ at <a
+ href="http://junit.sourceforge.net/doc/faq/faq.htm">http://junit.sourceforge.net/doc/faq/faq.htm</a>.
+ </p>
+ <p>
+ The JUnit distribution also includes this FAQ in
+ the <code>doc</code> directory.
+ </p>
+ </li>
+
+</ol>
+
+
+<!--
+
+ Overview
+
+-->
+<div class="header">
+<a name="overview">Overview</a>
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a name="overview_1">What is JUnit?</a></b>
+ </p>
+ <p>
+ JUnit is a simple, open source framework to write and run
+ repeatable tests. It is an instance of the xUnit architecture
+ for unit testing frameworks. JUnit features include:
+ </p>
+ <ul>
+ <li>Assertions for testing expected results</li>
+ <li>Test fixtures for sharing common test data</li>
+ <li>Test runners for running tests</li>
+ </ul>
+ <p>
+ JUnit was originally written by Erich Gamma and Kent Beck.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="overview_2">Where is the JUnit home page?</a></b>
+ </p>
+ <p>
+ The official JUnit home page is <a
+ href="http://junit.org">http://junit.org</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="overview_3">Where are the JUnit mailing lists and
+ forums?</a></b>
+ </p>
+ <p>
+ There are 3 mailing lists dedicated to everything JUnit:
+ </p>
+ <ul>
+ <li>
+ <a href="http://groups.yahoo.com/group/junit/">JUnit user
+ list</a>. (Search it for answers to frequently asked
+ questions not included here.)
+ </li>
+ <li>
+ <a
+ href="http://lists.sourceforge.net/lists/listinfo/junit-announce">JUnit
+ announcements</a>
+ </li>
+ <li>
+ <a
+ href="http://lists.sourceforge.net/lists/listinfo/junit-devel">JUnit
+ developer list</a>
+ </li>
+ </ul>
+ </li>
+ <li>
+ <p>
+ <b><a name="overview_4">Where is the JUnit
+ documentation?</a></b>
+ </p>
+ <p>
+ The following documents are included in the JUnit distribution
+ in the <code>doc</code> directory:
+ </p>
+ <ul>
+ <li>
+ <a
+ href="http://junit.sourceforge.net/doc/testinfected/testing.htm">JUnit
+ Test Infected: Programmers Love Writing Tests</a>
+ </li>
+ <li>
+ <a
+ href="http://junit.sourceforge.net/doc/cookbook/cookbook.htm">JUnit
+ Cookbook</a>
+ </li>
+ <li>
+ <a
+ href="http://junit.sourceforge.net/doc/cookstour/cookstour.htm">JUnit
+ - A Cook's Tour</a>
+ </li>
+ <li>
+ <a href="http://junit.sourceforge.net/doc/faq/faq.htm">JUnit
+ FAQ</a>
+ </li>
+ </ul>
+ </li>
+ <li>
+ <p>
+ <b><a name="overview_5">Where can I find articles on
+ JUnit?</a></b>
+ </p>
+ <p>
+ The JUnit home page maintains a list
+ of <a href="http://www.junit.org/news/article/index.htm">JUnit
+ articles</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="overview_6">What's the latest news on JUnit?</a></b>
+ </p>
+ <p>
+ The JUnit home page publishes
+ the <a href="http://www.junit.org/news/index.htm">latest JUnit
+ news</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="overview_7">How is JUnit licensed?</a></b>
+ </p>
+ <p>
+ JUnit is <a href="http://www.opensource.org/">Open Source
+ Software</a>, released
+ under <a
+ href="http://oss.software.ibm.com/developerworks/oss/license-cpl.html">IBM's
+ Common Public License Version 0.5</a> and hosted
+ on <a
+ href="http://sourceforge.net/projects/junit/">SourceForge</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="overview_8">What awards has JUnit won?</a></b>
+ </p>
+ <ul>
+ <li>
+ <p> <a
+ href="http://www.javaworld.com/javaworld/jw-03-2002/jw-0326-awards.html">2002
+ JavaWorld Editors' Choice Awards (ECA)</a>
+ </p>
+ <p>
+ Best Java Performance Monitoring/Testing Tool
+ </p>
+ </li>
+ <li>
+ <p>
+ <a
+ href="http://www.javaworld.com/javaworld/jw-06-2001/j1-01-awards.html">2001
+ JavaWorld Editors' Choice Awards (ECA)</a>
+ </p>
+ <p>
+ Best Java Performance Monitoring/Testing Tool
+ </p>
+ </li>
+ </ul>
+ </li>
+</ol>
+
+
+<!--
+
+ Getting Started
+
+-->
+<div class="header">
+<a name="started">Getting Started</a>
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a name="started_1">Where do I download JUnit?</a></b>
+ </p>
+ <p>
+ The latest version of JUnit is available
+ on <a
+ href="http://sourceforge.net/project/showfiles.php?group_id=15278">SourceForge</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="started_2">How do I install JUnit?</a></b>
+ </p>
+ <ol>
+ <li>
+ <p>
+ First, <a
+ href="http://sourceforge.net/project/showfiles.php?group_id=15278">download</a>
+ the
+ latest version of JUnit, referred to below
+ as <code>junit.zip</code>.
+ </p>
+ </li>
+ <li>
+ <p>
+ Then install JUnit on your platform of choice:
+ </p>
+ <p>
+ <u>Windows</u>
+ </p>
+ <p>
+ To install JUnit on Windows, follow these steps:
+ </p>
+ <ol>
+ <li>
+ <p>
+ Unzip the <code>junit.zip</code> distribution file to
+ a directory referred to as <code>%JUNIT_HOME%</code>.
+ </p>
+ </li>
+ <li>Add JUnit to the classpath:
+ <p>
+ <code>set CLASSPATH=%CLASSPATH%;%JUNIT_HOME%\junit.jar</code>
+ </p>
+ </li>
+ </ol>
+ <p>
+ <u>Unix (bash)</u>
+ </p>
+ <p>
+ To install JUnit on Unix, follow these steps:
+ </p>
+ <ol>
+ <li>
+ <p>
+ Unzip the <code>junit.zip</code> distribution file to
+ a directory referred to as <code>$JUNIT_HOME</code>.
+ </p>
+ </li>
+ <li>
+ <p>
+ Add JUnit to the classpath:
+ </p>
+ <p>
+ <code>export CLASSPATH=$CLASSPATH:$JUNIT_HOME/junit.jar</code>
+ </p>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <i>(Optional)</i> Unzip
+ the <code>$JUNIT_HOME/src.jar</code> file.
+ </p>
+ </li>
+ <li>
+ <p>
+ Test the installation by running the sample tests
+ distributed with JUnit. Note that the sample tests are
+ located in the installation directory directly, not
+ the <code>junit.jar</code> file. Therefore, make sure that
+ the JUnit installation directory is on your CLASSPATH. Then
+ simply type:
+ </p>
+ <div>
+ <blockquote><code>
+ java org.junit.runner.JUnitCore org.junit.tests.AllTests
+ </code></blockquote>
+ </div>
+ <p>
+ All the tests should pass with an "OK" message.
+ </p>
+ <p>
+ <i>
+ If the tests don't pass, verify
+ that <code>junit.jar</code> is in the CLASSPATH.
+ </i>
+ </p>
+ </li>
+ <li>
+ <p>
+ Finally, <a href="#overview_4">read</a> the documentation.
+ </p>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a name="started_3">How do I uninstall JUnit?</a></b>
+ </p>
+ <ol>
+ <li>
+ <p>
+ Delete the directory structure where you unzipped the JUnit
+ distribution.
+ </p>
+ </li>
+ <li>
+ <p>
+ Remove <code>junit.jar</code> from the CLASSPATH.
+ </p>
+ </li>
+ </ol>
+ <p>
+ JUnit does not modify the registry so simply removing all the
+ files will fully uninstall it.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="started_4">How do I ask questions?</a></b>
+ </p>
+ <p>
+ Questions that are not answered in
+ the <a
+ href="http://junit.sourceforge.net/doc/faq/faq.htm">FAQ</a> or
+ in the <a href="#overview_4">documentation</a> should be posted
+ to
+ the <a
+ href="http://www.jguru.com/forums/home.jsp?topic=JUnit">jGuru
+ discussion forum</a> or the <a
+ href="http://groups.yahoo.com/group/junit/">JUnit user mailing
+ list</a>.
+ </p>
+ <p>
+ Please stick to technical issues on the discussion forum and
+ mailing lists. Keep in mind that these are public, so
+ do <b>not</b> include any confidental information in your
+ questions!
+ </p>
+ <p>
+ You should also
+ read <a
+ href="http://www.catb.org/~esr/faqs/smart-questions.html">"How
+ to ask questions the smart way"</a> by Eric Raymond before
+ participating in the discussion forum and mailing lists.
+ </p>
+ <p>
+ <i>
+ NOTE: <br/> Please do NOT submit bugs, patches, or feature
+ requests to the discussion forum or mailing lists. <br/>
+ Refer instead to <a href="#started_5">"How do I submit bugs,
+ patches, or feature requests?"</a>.
+ </i>
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="started_5">How do I submit bugs, patches, or
+ feature requests?</a></b>
+ </p>
+ <p>
+ JUnit celebrates programmers testing their own software. In this
+ spirit, bugs, patches, and feature requests that include JUnit
+ tests have a better chance of being addressed than those
+ without.
+ </p>
+ <p>
+ JUnit is hosted
+ on <a
+ href="http://sourceforge.net/projects/junit">SourceForge</a>.
+ Please use the tools provided by SourceForge for your
+ submissions.
+ </p>
+ </li>
+</ol>
+
+
+<!--
+
+ Writing Tests
+
+-->
+<div class="header">
+<a name="tests">Writing Tests</a>
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a name="tests_1"></a>How do I write and run a simple test?</b>
+ </p>
+ <ol>
+ <li>
+ <p>
+ Create a class:
+ </p>
+ <div class="code">
+ <pre><code>
+
+ package junitfaq;
+
+ import org.junit.*;
+ import static org.junit.Assert.*;
+
+ import java.util.*;
+
+ public class SimpleTest {
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ Write a test method (annotated with <code>@Test</code>) that
+ asserts expected results on the object under test:
+ </p>
+ <div class="code">
+ <pre><code>
+
+ @Test
+ public void testEmptyCollection() {
+ Collection collection = new ArrayList();
+ assertTrue(collection.isEmpty());
+ }
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ If you are running your JUnit 4 tests with a JUnit 3.x runner,
+ write a <code>suite()</code> method that uses the
+ <code>JUnit4TestAdapter</code> class to create a suite
+ containing all of your test methods:
+ </p>
+ <div class="code">
+ <pre><code>
+
+ public static junit.framework.Test suite() {
+ return new junit.framework.JUnit4TestAdapter(SimpleTest.class);
+ }
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ Although writing a <code>main()</code> method to run the
+ test is much less important with the advent of IDE runners,
+ it's still possible:
+ </p>
+ <div class="code">
+ <pre><code>
+
+ public static void main(String args[]) {
+ org.junit.runner.JUnitCore.main("junitfaq.SimpleTest");
+ }
+ }
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ Run the test:
+ </p>
+ <ul>
+ <li>
+ <p>
+ To run the test from the console, type:
+ </p>
+ <div>
+ <blockquote><code>
+java org.junit.runner.JUnitCore junitfaq.SimpleTest
+ </code></blockquote>
+ </div>
+ </li>
+ <li>
+ <p>
+ To run the test with the test runner used
+ in <code>main()</code>, type:
+ </p>
+ <div>
+ <blockquote><code>
+java junitfaq.SimpleTest
+ </code></blockquote>
+ </div>
+ </li>
+ </ul>
+ <p>
+ The passing test results in the following textual output:
+ </p>
+ <div>
+ <blockquote>
+ <pre><code>
+ .
+Time: 0
+
+OK (1 tests)
+ </code></pre>
+ </blockquote>
+ </div>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_2"></a>How do I use a test fixture?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Jeff Nielsen)</i>
+ </p>
+ <p>
+ A test fixture is useful if you have two or more tests for a
+ common set of objects. Using a test fixture avoids duplicating
+ the code necessary to initialize (and cleanup) the common
+ objects.
+ </p>
+ <p>
+ Tests can use the objects (variables) in a test fixture, with
+ each test invoking different methods on objects in the fixture
+ and asserting different expected results. Each test runs in its
+ own test fixture to isolate tests from the changes made by other
+ tests. That is, <em>tests don't share the state of objects in
+ the test fixture</em>. Because the tests are isolated, they can
+ be run in any order.
+ </p>
+ <p>
+ To create a test fixture, declare instance variables for the
+ common objects. Initialize these objects in a <code>public
+ void</code> method annotated with <code>@Before</code>. The
+ JUnit framework automatically invokes any <code>@Before</code>
+ methods before each test is run.
+ </p>
+ <p>
+ The following example shows a test fixture with a common
+ <code>Collection</code> object.
+ </p>
+ <div class="code">
+ <pre><code>
+ package junitfaq;
+
+ import org.junit.*;
+ import static org.junit.Assert.*;
+ import java.util.*;
+
+ public class SimpleTest {
+
+ private Collection&lt;Object&gt; collection;
+
+ @Before
+ public void setUp() {
+ collection = new ArrayList&lt;Object&gt;();
+ }
+
+ @Test
+ public void testEmptyCollection() {
+ assertTrue(collection.isEmpty());
+ }
+
+
+ @Test
+ public void testOneItemCollection() {
+ collection.add("itemA");
+ assertEquals(1, collection.size());
+ }
+ }
+ </code></pre>
+ </div>
+
+ <p>
+ Given this test, the methods might execute in the following
+ order:
+ </p>
+ <blockquote>
+ <pre><code>setUp()
+testEmptyCollection()
+setUp()
+testOneItemCollection()</code></pre>
+ </blockquote>
+ <p>
+ The ordering of test-method invocations is not guaranteed, so
+ <code>testOneItemCollection()</code> might be executed before
+ <code>testEmptyCollection()</code>. But it doesn't matter,
+ because each method gets its own instance of the
+ <code>collection</code>.
+ </p>
+
+ <p>
+ Although JUnit provides a new instance of the fixture objects
+ for each test method, if you allocate any <em>external</em>
+ resources in a <code>@Before</code> method, you should release
+ them after the test runs by annotating a method with
+ <code>@After</code>. The JUnit framework automatically invokes
+ any <code>@After</code> methods after each test is run. For
+ example:
+ </p>
+
+ <div class="code">
+ <pre><code>
+ package junitfaq;
+
+ import org.junit.*;
+ import static org.junit.Assert.*;
+ import java.io.*;
+
+ public class OutputTest {
+
+ private File output;
+
+ @Before
+ public void createOutputFile() {
+ output = new File(...);
+ }
+
+ @After
+ public void deleteOutputFile() {
+ output.delete();
+ }
+
+ @Test
+ public void testSomethingWithFile() {
+ ...
+ }
+ }
+ </code></pre>
+ </div>
+ <p>
+ With this test, the methods will execute in the following order:
+ </p>
+ <div>
+ <blockquote>
+ <pre><code>
+createOutputFile()
+testSomethingWithFile()
+deleteOutputFile()
+ </code></pre>
+ </blockquote>
+ </div>
+
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_4"></a>How do I test a method that doesn't
+ return anything?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Dave Astels)</i>
+ </p>
+ <p>
+ Often if a method doesn't return a value, it will have some side
+ effect. Actually, if it doesn't return a value AND doesn't have
+ a side effect, it isn't doing anything.
+ </p>
+ <p>
+ There may be a way to verify that the side effect actually
+ occurred as expected. For example, consider
+ the <code>add()</code> method in the Collection classes. There
+ are ways of verifying that the side effect happened (i.e. the
+ object was added). You can check the size and assert that it is
+ what is expected:
+ </p>
+ <div class="code">
+ <pre><code>
+
+ @Test
+ public void testCollectionAdd() {
+ Collection collection = new ArrayList();
+ assertEquals(0, collection.size());
+ collection.add("itemA");
+ assertEquals(1, collection.size());
+ collection.add("itemB");
+ assertEquals(2, collection.size());
+ }
+ </code></pre>
+ </div>
+ <p>
+ Another approach is to make use of <a
+ href="http://www.mockobjects.com">MockObjects</a>.
+ </p>
+ <p>
+ A related issue is to design for testing. For example, if you
+ have a method that is meant to output to a file, don't pass in a
+ filename, or even a <code>FileWriter</code>. Instead, pass in
+ a <code>Writer</code>. That way you can pass in
+ a <code>StringWriter</code> to capture the output for testing
+ purposes. Then you can add a method
+ (e.g. <code>writeToFileNamed(String filename)</code>) to
+ encapsulate the <code>FileWriter</code> creation.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_5"></a>Under what conditions should I test
+ get() and set() methods?</b>
+ </p>
+ <p>
+ Unit tests are intended to alleviate fear that something might
+ break. If you think a <code>get()</code> or <code>set()</code>
+ method could reasonably break, or has in fact contributed to a
+ defect, then by all means write a test.
+ </p>
+ <p>
+ In short, test until you're confident. What you choose to test
+ is subjective, based on your experiences and confidence level.
+ Remember to be practical and maximize your testing investment.
+ </p>
+ <p>
+ Refer also to <a href="#best_3">"How simple is 'too simple to
+ break'?"</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_6"></a>Under what conditions should I not test
+ get() and set() methods?</b>
+ </p>
+ <p>
+ <i>(Submitted by: J. B. Rainsberger)</i>
+ </p>
+ <p>
+ Most of the time, get/set methods just can't break, and if they
+ can't break, then why test them? While it is usually better to
+ test more, there is a definite curve of diminishing returns on
+ test effort versus "code coverage". Remember the maxim: "Test
+ until fear turns to boredom."
+ </p>
+ <p>
+ Assume that the <code>getX()</code> method only does "return x;"
+ and that the <code>setX()</code> method only does "this.x =
+ x;". If you write this test:
+ </p>
+ <div>
+ <blockquote><pre>
+@Test
+public void testGetSetX() {
+ setX(23);
+ assertEquals(23, getX());
+}
+ </pre></blockquote>
+ </div>
+ <p>
+ then you are testing the equivalent of the following:
+ </p>
+ <div>
+ <blockquote><pre>
+@Test
+public void testGetSetX() {
+ x = 23;
+ assertEquals(23, x);
+}
+</pre></blockquote>
+ </div>
+ <p>
+ or, if you prefer,
+ </p>
+ <div>
+ <blockquote><pre>
+@Test
+public void testGetSetX() {
+ assertEquals(23, 23);
+}
+</pre></blockquote>
+ </div>
+ <p>
+ At this point, you are testing the Java compiler, or possibly
+ the interpreter, and not your component or application. There is
+ generally no need for you to do Java's testing for them.
+ </p>
+ <p>
+ If you are concerned about whether a property has already been
+ set at the point you wish to call <code>getX()</code>, then you
+ want to test the constructor, and not the <code>getX()</code>
+ method. This kind of test is especially useful if you have
+ multiple constructors:
+ </p>
+ <div>
+ <blockquote><pre>
+@Test
+public void testCreate() {
+ assertEquals(23, new MyClass(23).getX());
+}
+ </pre></blockquote>
+ </div>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_7"></a>How do I write a test that passes when
+ an expected exception is thrown?</b>
+ </p>
+ <p>
+ Add the optional <code>expected</code> attribute to
+ the <code>@Test</code> annotation. The following is an example
+ test that passes when the
+ expected <code>IndexOutOfBoundsException</code> is raised:
+ </p>
+ <div class="code">
+ <pre><code>
+
+ @Test(expected=IndexOutOfBoundsException.class)
+ public void testIndexOutOfBoundsException() {
+ ArrayList emptyList = new ArrayList();
+ Object o = emptyList.get(0);
+ }
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_8"></a>How do I write a test that fails when
+ an unexpected exception is thrown?</b>
+ </p>
+ <p>
+ Declare the exception in the <code>throws</code> clause of the
+ test method and don't catch the exception within the test
+ method. Uncaught exceptions will cause the test to fail with an
+ error.
+ </p>
+ <p>
+ The following is an example test that fails when
+ the <code>IndexOutOfBoundsException</code> is raised:
+ </p>
+ <div class="code-red">
+ <pre><code>
+
+ @Test
+ public void testIndexOutOfBoundsExceptionNotRaised()
+ throws IndexOutOfBoundsException {
+
+ ArrayList emptyList = new ArrayList();
+ Object o = emptyList.get(0);
+ }
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_10"></a>How do I test protected methods?</b>
+ </p>
+ <p>
+ Place your tests in the same package as the classes under test.
+ </p>
+ <p>
+ Refer to <a href="#organize_1">"Where should I put my test
+ files?"</a> for examples of how to organize tests for protected
+ method access.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_11"></a>How do I test private methods?</b>
+ </p>
+ <p>
+ Testing private methods may be an indication that those methods
+ should be moved into another class to promote reusability.
+ </p>
+ <p>
+ But if you must...
+ </p>
+ <p>
+ If you are using JDK 1.3 or higher, you can use reflection to
+ subvert the access control mechanism with the aid of
+ the <a
+ href="http://sourceforge.net/projects/privaccessor/">PrivilegedAccessor</a>.
+ For details on how to use it,
+ read <a
+ href="http://www.onjava.com/pub/a/onjava/2003/11/12/reflection.html">this
+ article</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_12"></a>Why does JUnit only report the first
+ failure in a single test?</b>
+ </p>
+ <p>
+ <i>(Submitted by: J. B. Rainsberger)</i>
+ </p>
+ <p>
+ Reporting multiple failures in a single test is generally a sign
+ that the test does too much, compared to what a unit test ought
+ to do. Usually this means either that the test is really a
+ functional/acceptance/customer test or, if it is a unit test,
+ then it is too big a unit test.
+ </p>
+ <p>
+ JUnit is designed to work best with a number of small tests. It
+ executes each test within a separate instance of the test
+ class. It reports failure on each test. Shared setup code is
+ most natural when sharing between tests. This is a design
+ decision that permeates JUnit, and when you decide to report
+ multiple failures per test, you begin to fight against
+ JUnit. This is not recommended.
+ </p>
+ <p>
+ Long tests are a design smell and indicate the likelihood of a
+ design problem. Kent Beck is fond of saying in this case that
+ "there is an opportunity to learn something about your design."
+ We would like to see a pattern language develop around these
+ problems, but it has not yet been written down.
+ </p>
+ <p>
+ Finally, note that a single test with multiple assertions is
+ isomorphic to a test case with multiple tests:
+ </p>
+ <p>
+ One test method, three assertions:
+ </p>
+ <div>
+ <blockquote><pre><code>
+public class MyTestCase {
+ @Test
+ public void testSomething() {
+ // Set up for the test, manipulating local variables
+ assertTrue(condition1);
+ assertTrue(condition2);
+ assertTrue(condition3);
+ }
+}
+ </code></pre></blockquote>
+ </div>
+ <p>
+ Three test methods, one assertion each:
+ </p>
+ <div>
+ <blockquote><pre><code>
+public class MyTestCase {
+ // Local variables become instance variables
+
+ @Before
+ public void setUp() {
+ // Set up for the test, manipulating instance variables
+ }
+
+ @Test
+ public void testCondition1() {
+ assertTrue(condition1);
+ }
+
+ @Test
+ public void testCondition2() {
+ assertTrue(condition2);
+ }
+
+ @Test
+ public void testCondition3() {
+ assertTrue(condition3);
+ }
+}
+ </code></pre></blockquote>
+ </div>
+ <p>
+ The resulting tests use JUnit's natural execution and reporting
+ mechanism and, failure in one test does not affect the execution
+ of the other tests. You generally want exactly one test to fail
+ for any given bug, if you can manage it.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_13"></a>In Java 1.4, <code>assert</code> is a
+ keyword. Won't this conflict
+ with JUnit's <code>assert()</code> method?</b>
+ </p>
+ <p>
+ JUnit 3.7 deprecated <code>assert()</code> and replaced it
+ with <code>assertTrue()</code>, which works exactly the same
+ way.
+ </p>
+ <p>
+ JUnit 4 is compatible with the <code>assert</code> keyword. If
+ you run with the <code>-ea</code> JVM switch, assertions that
+ fail will be reported by JUnit.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_14"></a>How do I test things that must be run
+ in a J2EE container (e.g. servlets, EJBs)?</b>
+ </p>
+ <p>
+ Refactoring J2EE components to delegate functionality to other
+ objects that don't have to be run in a J2EE container will
+ improve the design and testability of the software.
+ </p>
+ <p>
+ <a href="http://jakarta.apache.org/cactus/index.html">Cactus</a>
+ is an open source JUnit extension that can be used to test J2EE
+ components in their natural environment.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_15"></a>Do I need to write
+ a test class for every class I need to
+ test?</b>
+ </p>
+ <p>
+ <i>(Submitted by: J. B. Rainsberger)</i>
+ </p>
+ <p>
+ No. It is a convention to start with one test
+ class per class under test, but it is not necessary.
+ </p>
+ <p>
+ Test classes only provide a way to organize tests, nothing more.
+ Generally you will start with one test class per class under
+ test, but then you may find that a small group of tests belong
+ together with their own common test fixture.[1] In this case,
+ you may move those tests to a new test class. This is a simple
+ object-oriented refactoring: separating responsibilities of an
+ object that does too much.
+ </p>
+ <p>
+ Another point to consider is that the <code>TestSuite</code> is
+ the smallest execution unit in JUnit: you cannot execute
+ anything smaller than a TestSuite at one time without changing
+ source code. In this case, you probably do not want to put tests
+ in the same test class unless they somehow "belong together".
+ If you have two groups of tests that you think you'd like to
+ execute separately from one another, it is wise to place them in
+ separate test classes.
+ </p>
+ <p>
+ <i>
+ [1] A test fixture is a common set of test data and
+ collaborating objects shared by many tests. Generally they are
+ implemented as instance variables in the test class.
+ </i>
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_16"></a>Is there a basic template I can use to
+ create a test?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Eric Armstrong)</i>
+ </p>
+ <p>
+ The following templates are a good starting point. Copy/paste
+ and edit these templates to suit your coding style.
+ </p>
+ <p>
+ SampleTest is a basic test template:
+ </p>
+ <div>
+ <blockquote><pre><code>
+import org.junit.*;
+import static org.junit.Assert.*;
+
+public class SampleTest {
+
+ private java.util.List emptyList;
+
+ /**
+ * Sets up the test fixture.
+ * (Called before every test case method.)
+ */
+ @Before
+ public void setUp() {
+ emptyList = new java.util.ArrayList();
+ }
+
+ /**
+ * Tears down the test fixture.
+ * (Called after every test case method.)
+ */
+ @After
+ public void tearDown() {
+ emptyList = null;
+ }
+
+ @Test
+ public void testSomeBehavior() {
+ assertEquals("Empty list should have 0 elements", 0, emptyList.size());
+ }
+
+ @Test(expected=IndexOutOfBoundsException.class)
+ public void testForException() {
+ Object o = emptyList.get(0);
+ }
+}
+ </code></pre></blockquote>
+ </div>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_17"></a>How do I write a test for an abstract
+ class?</b>
+ </p>
+ <p>
+ Refer to <a
+ href="http://c2.com/cgi/wiki?AbstractTestCases">http://c2.com/cgi/wiki?AbstractTestCases</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="tests_18"></a>When are tests garbage collected?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Timothy Wall and Kent Beck)</i>
+ </p>
+ <p>
+ By design, the tree of Test instances is built in one pass, then
+ the tests are executed in a second pass. The test runner holds
+ strong references to all Test instances for the duration of the
+ test execution. This means that for a very long test run with
+ many Test instances, none of the tests may be garbage collected
+ until the end of the entire test run.
+ </p>
+ <p>
+ Therefore, if you allocate external or limited resources in a
+ test, you are responsible for freeing those resources.
+ Explicitly setting an object to <code>null</code> in
+ the <code>tearDown()</code> method, for example, allows it to be
+ garbage collected before the end of the entire test run.
+ </p>
+ </li>
+</ol>
+
+
+<!--
+
+ Organizing Tests
+
+-->
+<div class="header">
+<a name="organize">Organizing Tests</a>
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a name="organize_1"></a>Where should I put my test files?</b>
+ </p>
+ <p>
+ You can place your tests in the same package and directory as
+ the classes under test.
+ </p>
+ <p>
+ For example:
+ </p>
+ <div>
+ <blockquote><pre>
+src
+ com
+ xyz
+ SomeClass.java
+ SomeClassTest.java
+ </pre></blockquote>
+ </div>
+ <p>
+ While adequate for small projects, many developers feel that
+ this approach clutters the source directory, and makes it hard
+ to package up client deliverables without also including
+ unwanted test code, or writing unnecessarily complex packaging
+ tasks.
+ </p>
+ <p>
+ An arguably better way is to place the tests in a separate
+ parallel directory structure with package alignment.
+ </p>
+ <p>
+ For example:
+ </p>
+ <div>
+ <blockquote><pre>
+src
+ com
+ xyz
+ SomeClass.java
+test
+ com
+ xyz
+ SomeClassTest.java
+ </pre></blockquote>
+ </div>
+ <p>
+ These approaches allow the tests to access to all the public and
+ package visible methods of the classes under test.
+ </p>
+ <p>
+ Some developers have argued in favor of putting the tests in a
+ sub-package of the classes under test (e.g. com.xyz.test). The
+ author of this FAQ sees no clear advantage to adopting this
+ approach and believes that said developers also put their curly
+ braces on the wrong line. :-)
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="organize_3"></a>How can I run setUp() and tearDown()
+ code once for all of my tests?</b>
+ </p>
+ <p>
+ The desire to do this is usually a symptom of excessive coupling
+ in your design. If two or more tests must share the same test
+ fixture state, then the tests may be trying to tell you that the
+ classes under test have some undesirable dependencies.
+ </p>
+ <p>
+ Refactoring the design to further decouple the classes under
+ test and eliminate code duplication is usually a better
+ investment than setting up a shared test fixture.
+ </p>
+ <p>
+ But if you must...
+ </p>
+ <p>
+ You can add a <code>@BeforeClass</code> annotation to a method
+ to be run before all the tests in a class, and
+ a <code>@AfterClass</code> annotation to a method to be run
+ after all the tests in a class. Here's an example:
+ </p>
+ <div class="code">
+ <pre><code>
+
+ package junitfaq;
+
+ import org.junit.*;
+ import static org.junit.Assert.*;
+ import java.util.*;
+
+ public class SimpleTest {
+
+ private Collection collection;
+
+ @BeforeClass
+ public static void oneTimeSetUp() {
+ // one-time initialization code
+ }
+
+ @AfterClass
+ public static void oneTimeTearDown() {
+ // one-time cleanup code
+ }
+
+ @Before
+ public void setUp() {
+ collection = new ArrayList();
+ }
+
+ @After
+ public void tearDown() {
+ collection.clear();
+ }
+
+ @Test
+ public void testEmptyCollection() {
+ assertTrue(collection.isEmpty());
+ }
+
+ @Test
+ public void testOneItemCollection() {
+ collection.add("itemA");
+ assertEquals(1, collection.size());
+ }
+ }
+ </code></pre>
+ </div>
+ <p>
+ Given this test, the methods will execute in the following
+ order:
+ </p>
+ <div>
+ <blockquote>
+ <pre><code>
+oneTimeSetUp()
+setUp()
+testEmptyCollection()
+tearDown()
+setUp()
+testOneItemCollection()
+tearDown()
+oneTimeTearDown()
+ </code></pre>
+ </blockquote>
+ </div>
+
+ </li>
+</ol>
+
+
+<!--
+
+ Running Tests
+
+-->
+<div class="header">
+<a name="running">Running Tests</a>
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a name="running_1"></a>What CLASSPATH settings are needed to
+ run JUnit?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Eric Armstrong)</i>
+ </p>
+ <p>
+ To run your JUnit tests, you'll need the following elemements in
+ your CLASSPATH:
+ </p>
+ <ul>
+ <li>JUnit class files</li>
+ <li>Your class files, including your JUnit test classes</li>
+ <li>Libraries your class files depend on</li>
+ </ul>
+ <p>
+ If attempting to run your tests results in
+ a <code>NoClassDefFoundError</code>, then something is missing
+ from your CLASSPATH.
+ </p>
+ <p>
+ <u>Windows Example:</u>
+ </p>
+ <p>
+ <code>set
+ CLASSPATH=%JUNIT_HOME%\junit.jar;c:\myproject\classes;c:\myproject\lib\something.jar</code>
+ </p>
+ <p>
+ <u>Unix (bash) Example:</u>
+ </p>
+ <p>
+ <code>export CLASSPATH=$JUNIT_HOME/junit.jar:/myproject/classes:/myproject/lib/something.jar</code>
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_2"></a>Why do I get
+ a <code>NoClassDefFoundError</code> when trying to test JUnit
+ or run the samples?</b>
+ </p>
+ <p>
+ <i>(Submitted by: J.B. Rainsberger and Jason Rogers)</i>
+ </p>
+ <p>
+ Most likely your CLASSPATH doesn't include the JUnit
+ installation directory.
+ </p>
+ <p>
+ Refer to <a href="#running_1">"What CLASSPATH settings are
+ needed to run JUnit?"</a> for more guidance.
+ </p>
+ <p>
+ Also consider running <a
+ href="http://www.clarkware.com/software/WhichJUnit.zip">WhichJunit</a>
+ to print the absolute location of the JUnit class files required
+ to run and test JUnit and its samples.
+ </p>
+ <p>
+ If the CLASSPATH seems mysterious, read <a
+ href="http://java.sun.com/j2se/1.4/docs/tooldocs/findingclasses.html">this</a>!
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_4"></a>How do I run JUnit from my command window?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Eric Armstrong)</i>
+ </p>
+ <ol>
+ <li>
+ <p>
+ <a href="#running_1">Set your CLASSPATH</a>
+ </p>
+ </li>
+ <li>
+ <p>
+ Invoke the runner:
+ </p>
+ <p>
+ <code>
+ java org.junit.runner.JUnitCore &lt;test class name&gt;
+ </code>
+ </p>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_5"></a>How do I run JUnit using Ant?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Eric Armstrong)</i>
+ </p>
+ <ol>
+ <li>
+ <p>
+ Define any necessary Ant properties:
+ </p>
+ <div>
+ <pre><code>
+&lt;property name="src" value="./src" /&gt;
+&lt;property name="lib" value="./lib" /&gt;
+&lt;property name="classes" value="./classes" /&gt;
+&lt;property name="test.class.name" value="com.xyz.MyTestSuite" /&gt;
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ Set up the CLASSPATH to be used by JUnit:
+ </p>
+ <div>
+ <pre><code>
+&lt;path id="test.classpath"&gt;
+ &lt;pathelement location="${classes}" /&gt;
+ &lt;pathelement location="/path/to/junit.jar" /&gt;
+ &lt;fileset dir="${lib}">
+ &lt;include name="**/*.jar"/&gt;
+ &lt;/fileset&gt;
+&lt;/path&gt;
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ Define the Ant task for running JUnit:
+ </p>
+ <div>
+ <pre><code>
+&lt;target name="test"&gt;
+ &lt;junit fork="yes" haltonfailure="yes"&gt;
+ &lt;test name="${test.class.name}" /&gt;
+ &lt;formatter type="plain" usefile="false" /&gt;
+ &lt;classpath refid="test.classpath" /&gt;
+ &lt;/junit&gt;
+&lt;/target&gt;
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ Run the test:
+ </p>
+ <div>
+ <code>
+ ant test
+ </code>
+ </div>
+ </li>
+ </ol>
+ <p>
+ Refer to the <a
+ href="http://jakarta.apache.org/ant/manual/OptionalTasks/junit.html">JUnit
+ Ant Task</a> for more information.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_6"></a>How do I use Ant to create HTML test
+ reports?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Eric Armstrong and Steffen Gemkow)</i>
+ </p>
+ <ol>
+ <li>
+ <p>
+ Ensure that Ant's <code>optional.jar</code> file is either
+ in your CLASSPATH or exists in
+ your <code>$ANT_HOME/lib</code> directory.
+ </p>
+ </li>
+ <li>
+ <p>
+ Add an ANT property for the directory containing the HTML reports:
+ </p>
+ <div>
+ <code>
+&lt;property name="test.reports" value="./reports" /&gt;
+ </code>
+ </div>
+ </li>
+ <li>
+ <p>
+ Define the Ant task for running JUnit and generating reports:
+ </p>
+ <div>
+ <pre><code>
+&lt;target name="test-html"&gt;
+ &lt;junit fork="yes" printsummary="no" haltonfailure="no"&gt;
+ &lt;batchtest fork="yes" todir="${test.reports}" &gt;
+ &lt;fileset dir="${classes}"&gt;
+ &lt;include name="**/*Test.class" /&gt;
+ &lt;/fileset&gt;
+ &lt;/batchtest&gt;
+ &lt;formatter type="xml" /&gt;
+ &lt;classpath refid="test.classpath" /&gt;
+ &lt;/junit&gt;
+
+ &lt;junitreport todir="${test.reports}"&gt;
+ &lt;fileset dir="${test.reports}"&gt;
+ &lt;include name="TEST-*.xml" /&gt;
+ &lt;/fileset&gt;
+ &lt;report todir="${test.reports}" /&gt;
+ &lt;/junitreport&gt;
+&lt;/target&gt;
+ </code></pre>
+ </div>
+ </li>
+ <li>
+ <p>
+ Run the test:
+ </p>
+ <div>
+ <code>
+ ant test-html
+ </code>
+ </div>
+ </li>
+ </ol>
+ <p>
+ Refer to the
+ <a href="http://jakarta.apache.org/ant/manual/OptionalTasks/junit.html">JUnit Ant Task</a>
+ for more information.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_7"></a>How do I pass command-line arguments
+ to a test execution?</b>
+ </p>
+ <p>
+ Use the <tt>-D</tt> JVM command-line options, as in:
+ </p>
+ <div>
+ <blockquote><code>
+-DparameterName=parameterValue
+ </code></blockquote>
+ </div>
+ <p>
+ If the number of parameters on the command line gets unweildy,
+ pass in the location of a property file that defines a set of
+ parameters. Alternatively, the <a
+ href="http://junit-addons.sf.net">JUnit-addons package</a>
+ contains the <tt>XMLPropertyManager</tt>
+ and <tt>PropertyManager</tt> classes that allow you to define a
+ property file (or XML file) containing test parameters.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_9"></a>Why do I get
+ a <code>LinkageError</code> when using
+ XML interfaces in my test?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Scott Stirling)</i>
+ </p>
+ <p>
+ The workaround as of JUnit 3.7 is to
+ add <code>org.w3c.dom.*</code> and <code>org.xml.sax.*</code> to
+ your <code>excluded.properties</code>.
+ </p>
+ <p>
+ It's just a matter of time before this fix becomes incorporated
+ into the released version of
+ JUnit's <code>excluded.properties</code>, since JAXP is a
+ standard part of JDK 1.4. It will be just like
+ excluding <code>org.omg.*</code>. By the way, if you download
+ the JUnit source from its Sourceforge CVS, you will find that
+ these patterns have already been added to the default
+ excluded.properties and so has a pattern for JINI. In fact, here
+ is the current version in CVS, which demonstrates how to add
+ exclusions to the list too:
+ </p>
+ <div>
+ <blockquote><pre>
+#
+# The list of excluded package paths for the TestCaseClassLoader
+#
+excluded.0=sun.*
+excluded.1=com.sun.*
+excluded.2=org.omg.*
+excluded.3=javax.*
+excluded.4=sunw.*
+excluded.5=java.*
+excluded.6=org.w3c.dom.*
+excluded.7=org.xml.sax.*
+excluded.8=net.jini.*
+ </pre></blockquote>
+ </div>
+ <p>
+ This is the most common case where the
+ default <code>excluded.properties</code> list needs
+ modification. The cause of the <code>LinkageError</code> is
+ related to using JAXP in your test cases. By JAXP I mean the
+ whole set of <code>javax.xml.*</code> classes and the
+ supporting <code>org.w3c.dom.*</code>
+ and <code>org.xml.sax.*</code> classes.
+ </p>
+ <p>
+ As stated above, the JUnit GUI TestRunners' classloader relies
+ on the <code>excluded.properties</code> for classes it should
+ delegate to the system classloader. JAXP is an unusual case
+ because it is a standard Java extension library dependent on
+ classes whose package names (<code>org.w3c.dom.*</code>
+ and <code>org.xml.sax.*</code>) do not begin with a standard
+ Java or Sun prefix. This is similar to the relationship
+ between <code>javax.rmi.*</code> and the <code>org.omg.*</code>
+ classes, which have been excluded by default in
+ JUnit'ss <code>excluded.properties</code> for a while.
+ </p>
+ <p>
+ What can happen, and frequently does when using the JUnit Swing
+ or AWT UI with test cases that reference, use or depend on JAXP
+ classes, such as Log4J, Apache SOAP, Axis, Cocoon, etc., is that
+ the JUnit class loader (properly)
+ delegates <code>javax.xml.*</code> classes it &quot;sees&quot;
+ to the system loader. But then the system loader, in the process
+ of initializing and loading that JAXP class, links and loads up
+ a bunch of <code>org.w3c.dom</code>/<code>org.xml.sax</code>
+ classes. When it does so, the JUnit custom classloader is not
+ involved at all because the system classloader never delegates
+ &quot;down&quot; or checks with custom classloaders to see if a
+ class is already loaded. At any point after this, if the JUnit
+ loader is asked to load
+ an <code>org.w3c.dom</code>/<code>org.xml.sax</code> class that
+ it's never seen before, it will try to load it because the
+ class' name doesn't match any of the patterns in the default
+ exclude list. That's when a <code>LinkageError</code>
+ occurs. This is really a flaw in the JUnit classloader design,
+ but there is the workaround given above.
+ </p>
+ <p>
+ Java 2 JVMs keep classes (remember, classes and objects, though
+ related, are different entities to the JVM - I'm talking
+ about classes here, not object instances) in namespaces,
+ identifying them by their fully qualified classname plus the
+ instance of their defining (not initiating) loader. The JVM will
+ attempt to assign all unloaded classes referenced by an already
+ defined and loaded class to that class's defining loader. The
+ JVM's classresolver routine (implemented as a C function in the
+ JVM source code) keeps track of all these class loading events
+ and &quot;sees&quot; if another classloader (such as the JUnit
+ custom loader) attempts to define a class that has already been
+ defined by the system loader. According to the rules of Java 2
+ loader constraints, in case a class has already been defined by
+ the system loader, any attempts to load a class should first be
+ delegated to the system loader. A &quot;proper&quot; way for
+ JUnit to handle this feature would be to load classes from a
+ repository other than the CLASSPATH that the system classloader
+ knows nothing about. And then the JUnit custom classloader could
+ follow the standard Java 2 delegation model, which is to always
+ delegate class loading to the system loader, and only attempt to
+ load if that fails. Since they both load from the CLASSPATH in
+ the current model, if the JUnit loader delegated like it's
+ supposed to, it would never get to load any classes since the
+ system loader would always find them.
+ </p>
+ <p>
+ You could try to hack around this in the JUnit source by
+ catching the <code>LinkageError</code> in
+ TestCaseClassLoader's <code>loadClass()</code> method and then
+ making a recovery call to <code>findSystemClass()</code> --
+ thereby delegating to the system loader after the violation has
+ been caught. But this hack only works some of the time, because
+ now you can have the reverse problem where the JUnit loader will
+ load a host of <code>org.w3c.dom</code>/<code>org.xml.sax</code>
+ classes, and then the system loader violates the loader
+ contraints at some point when it tries to do exactly what I
+ described above with JAXP because it doesn't ever delegate to
+ its logical child (the JUnit loader). Inevitably, if your test
+ cases use many JAXP and related XML classes, one or the other
+ classloader will end up violating the constraints whatever you
+ do.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_11"></a>Why do I get the warning
+ "AssertionFailedError: No
+ tests found in XXX" when I run my test?</b>
+ </p>
+ <p>
+ Make sure you have more or more method annotated with <code>@Test</code>.
+ </p>
+ <p>
+ For example:
+ </p>
+ <div>
+ <blockquote><pre>
+@Test
+public void testSomething() {
+}
+ </pre></blockquote>
+ </div>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_12"></a>Why do I see "Unknown Source" in the
+ stack trace of
+a test failure, rather than the source file's line number?</b>
+ </p>
+ <p>
+ The debug option for the Java compiler must be enabled in order
+ to see source file and line number information in a stack trace.
+ </p>
+ <p>
+ When invoking the Java compiler from the command line, use
+ the <code>-g</code> option to generate all debugging info.
+ </p>
+ <p>
+ When invoking the Java compiler from an
+ <a href="http://jakarta.apache.org/ant/index.html">Ant</a> task, use the
+ <code>debug="on"</code> attribute. For example:
+ </p>
+ <div>
+ <blockquote><code>
+&lt;javac srcdir="${src}" destdir="${build}" debug="on" /&gt;
+ </code></blockquote>
+ </div>
+ <p>
+ When using older JVMs pre-Hotspot (JDK 1.1 and most/all 1.2),
+ run JUnit with the <code>-DJAVA_COMPILER=none</code> JMV command
+ line argument to prevent runtime JIT compilation from obscuring
+ line number info.
+ </p>
+ <p>
+ Compiling the test source with debug enabled will show the line
+ where the assertion failed. Compiling the non-test source with
+ debug enabled will show the line where an exception was raised
+ in the class under test.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="running_15"></a>How do I organize all test classes
+ in a TestSuite automatically and not use or manage a TestSuite
+ explicitly?</b>
+ </p>
+ <p>
+ <i>(Submitted by: Bill de hora)</i>
+ </p>
+ <p>
+ There are a number of ways to do this:
+ </p>
+ <ol>
+ <li>
+ <p>
+ In Ant, use the <code>junit</code> task and
+ the <code>batchtest</code> element:
+ </p>
+ <div>
+ <pre><code>
+&lt;junit printsummary="yes" haltonfailure="yes"&gt;
+ ...
+ &lt;batchtest fork="yes"&gt;
+ &lt;fileset dir="${src.dir}"&gt;
+ &lt;include name="**/*Test.java" /&gt;
+ &lt;include name="**/Test*.java" /&gt;
+ &lt;/fileset&gt;
+ &lt;/batchtest&gt;
+&lt;/junit&gt;
+ </code></pre>
+ </div>
+ <p>
+ Idiomatic naming patterns for unit tests
+ are <code>Test*.java</code> and <code>*Test.java</code>.
+ Documentation and examples are at <a
+ href="http://ant.apache.org/manual/OptionalTasks/junit.html">http://ant.apache.org/manual/OptionalTasks/junit.html</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ Use the <code>DirectorySuiteBuilder</code>
+ and <code>ArchiveSuiteBuilder</code> (for jar/zip files)
+ classes provided by JUnit-addons project:
+ </p>
+ <div>
+ <blockquote><pre>
+DirectorySuiteBuilder builder = new DirectorySuiteBuilder();
+builder.setSuffix("Test");
+Test suite = builer.suite("/home/project/myproject/tests");
+ </pre></blockquote>
+ </div>
+ <p>
+ Documentation and examples are at <a
+ href="http://junit-addons.sourceforge.net/">http://junit-addons.sourceforge.net</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ Write your own custom suite builder.
+ </p>
+ <p>
+ Have your test classes implement an interface and write a
+ treewalker to load each class in a directory, inspect the
+ class, and add any classes that implement the interface to a
+ TestSuite.
+ </p>
+ <p>
+ You might only want to do this if you are <b>very</b>
+ uncomfortable with using a naming convention for test
+ classes. Aside from being slow for larger suites, ultimately
+ it's arguable whether it's more effort to follow a naming
+ convention that have test classes implement an interface!
+ </p>
+ <p>
+ An example of this approach is at
+ <a href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html">http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html</a>.
+ </p>
+ </li>
+ </ol>
+ </li>
+</ol>
+
+<!--
+
+ Best Practices
+
+-->
+<div class="header">
+<a name="best">Best Practices</a>
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a name="best_1"></a>When should tests be written?</b>
+ </p>
+ <p>
+ Tests should be written before the code. Test-first programming
+ is practiced by only writing new code when an automated test is
+ failing.
+ </p>
+ <p>
+ Good tests tell you how to best design the system for its
+ intended use. They effectively communicate in an executable
+ format how to use the software. They also prevent tendencies to
+ over-build the system based on speculation. When all the tests
+ pass, you know you're done!
+ </p>
+ <p>
+ Whenever a customer test fails or a bug is reported, first write
+ the necessary unit test(s) to expose the bug(s), <em>then</em>
+ fix them. This makes it almost impossible for that particular
+ bug to resurface later.
+ </p>
+ <p>
+ Test-driven development is a lot more fun than writing tests
+ after the code seems to be working. Give it a try!
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="best_2"></a>Do I have to write a test for
+ everything?</b>
+ </p>
+ <p>
+ No, just test everything that could reasonably break.
+ </p>
+ <p>
+ Be practical and maximize your testing investment. Remember
+ that investments in testing are equal investments in design. If
+ defects aren't being reported and your design responds well to
+ change, then you're probably testing enough. If you're spending
+ a lot of time fixing defects and your design is difficult to
+ grow, you should write more tests.
+ </p>
+ <p>
+ If something is difficult to test, it's usually an opportunity
+ for a design improvement. Look to improve the design so that
+ it's easier to test, and by doing so a better design will
+ usually emerge.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="best_3"></a>How simple is 'too simple to break'?</b>
+ </p>
+ <p>
+ <i>(Submitted by: J. B. Rainsberger)</i>
+ </p>
+ <p>
+ The general philosophy is this: if it can't break <em>on its
+ own</em>, it's too simple to break.
+ </p>
+ <p>
+ First example is the <code>getX()</code> method. Suppose
+ the <code>getX()</code> method only answers the value of an
+ instance variable. In that case, <code>getX()</code> cannot
+ break unless either the compiler or the interpreter is also
+ broken. For that reason, don't test <code>getX()</code>; there
+ is no benefit. The same is true of the <code>setX()</code>
+ method, although if your <code>setX()</code> method does any
+ parameter validation or has any side effects, you likely need to
+ test it.
+ </p>
+ <p>
+ Next example: suppose you have written a method that does
+ nothing but forward parameters into a method called on another
+ object. That method is too simple to break.
+ </p>
+ <div>
+ <blockquote><pre>
+public void myMethod(final int a, final String b) {
+ myCollaborator.anotherMethod(a, b);
+}
+ </pre></blockquote>
+ </div>
+ <p>
+ <code>myMethod</code> cannot possibly break because it does nothing: it
+ forwards its input to another object and that's all.
+ </p>
+ <p>
+ The only precondition for this method is "myCollaborator !=
+ null", but that is generally the responsibility of the
+ constructor, and not of myMethod. If you are concerned, add a
+ test to verify that myCollaborator is always set to something
+ non-null by every constructor.
+ </p>
+ <p>
+ The only way myMethod could break would be
+ if <code>myCollaborator.anotherMethod()</code> were broken. In
+ that case, test <code>myCollaborator</code>, and not the current
+ class.
+ </p>
+ <p>
+ It is true that adding tests for even these simple methods
+ guards against the possibility that someone refactors and makes
+ the methods "not-so-simple" anymore. In that case, though, the
+ refactorer needs to be aware that the method is now complex
+ enough to break, and should write tests for it -- and preferably
+ before the refactoring.
+ </p>
+ <p>
+ Another example: suppose you have a JSP and, like a good
+ programmer, you have removed all business logic from it. All it
+ does is provide a layout for a number of JavaBeans and never
+ does anything that could change the value of any object. That
+ JSP is too simple to break, and since JSPs are notoriously
+ annoying to test, you should strive to make all your JSPs too
+ simple to break.
+ </p>
+ <p>
+ Here's the way testing goes:
+ </p>
+ <div>
+ <blockquote><pre>
+becomeTimidAndTestEverything
+while writingTheSameThingOverAndOverAgain
+ becomeMoreAggressive
+ writeFewerTests
+ writeTestsForMoreInterestingCases
+ if getBurnedByStupidDefect
+ feelStupid
+ becomeTimidAndTestEverything
+ end
+end
+ </pre></blockquote>
+ </div>
+ <p>
+ The loop, as you can see, never terminates.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="best_4"></a>How often should I run my tests?</b>
+ </p>
+ <p>
+ Run all your unit tests as often as possible, ideally every time
+ the code is changed. Make sure all your unit tests always run
+ at 100%. Frequent testing gives you confidence that your
+ changes didn't break anything and generally lowers the stress of
+ programming in the dark.
+ </p>
+ <p>
+ For larger systems, you may just run specific test suites that
+ are relevant to the code you're working on.
+ </p>
+ <p>
+ Run all your acceptance, integration, stress, and unit tests at
+ least once per day (or night).
+ </p>
+ <p>
+ If you're using Eclipse, be sure to check out David Saff's
+ <a href="http://pag.csail.mit.edu/continuoustesting/">continuous
+ testing plug-in</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="best_5"></a>What do I do when a defect is reported?</b>
+ </p>
+ <p>
+ Test-driven development generally lowers the defect density of
+ software. But we're all fallible, so sometimes a defect will
+ slip through. When this happens, write a failing test that
+ exposes the defect. When the test passes, you know the defect
+ is fixed!
+ </p>
+ <p>
+ Don't forget to use this as a learning opportunity. Perhaps the
+ defect could have been prevented by being more aggressive about
+ testing everything that could reasonably break.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="best_6"></a>Why not just use <code>System.out.println()</code>?</b>
+ </p>
+ <p>
+ Inserting debug statements into code is a low-tech method for
+ debugging it. It usually requires that output be scanned
+ manually every time the program is run to ensure that the code
+ is doing what's expected.
+ </p>
+ <p>
+ It generally takes less time in the long run to codify
+ expectations in the form of an automated JUnit test that retains
+ its value over time. If it's difficult to write a test to
+ assert expectations, the tests may be telling you that shorter
+ and more cohesive methods would improve your design.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="best_7"></a>Why not just use a debugger?</b>
+ </p>
+ <p>
+ Debuggers are commonly used to step through code and inspect
+ that the variables along the way contain the expected values.
+ But stepping through a program in a debugger is a manual process
+ that requires tedious visual inspections. In essence, the
+ debugging session is nothing more than a manual check of
+ expected vs. actual results. Moreover, every time the program
+ changes we must manually step back through the program in the
+ debugger to ensure that nothing broke.
+ </p>
+ <p>
+ It generally takes less time to codify expectations in the form
+ of an automated JUnit test that retains its value over time. If
+ it's difficult to write a test to assert expected values, the
+ tests may be telling you that shorter and more cohesive methods
+ would improve your design.
+ </p>
+ </li>
+</ol>
+
+<!--
+
+ Miscellaneous
+
+-->
+<div class="header">
+<a name="misc">Miscellaneous</a>
+</div>
+<ol>
+ <li>
+ <p>
+ <b><a name="misc_1"></a>How do I integrate JUnit with my IDE?</b>
+ </p>
+ <p>
+ The JUnit home page maintains a list of <a
+ href="http://www.junit.org/news/ide/index.htm">IDE integration
+ instructions</a>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="misc_2"></a>How do I launch a debugger when a test fails?</b>
+ </p>
+ <p>
+ Start the <code>TestRunner</code> under the debugger and
+ configure the debugger so that it catches
+ the <code>junit.framework.AssertionFailedError</code>.
+ </p>
+ <p>
+ How you configure this depends on the debugger you prefer to
+ use. Most Java debuggers provide support to stop the program
+ when a specific exception is raised.
+ </p>
+ <p>
+ Notice that this will only launch the debugger when an expected
+ failure occurs.
+ </p>
+ </li>
+ <li>
+ <p>
+ <b><a name="misc_3"></a>Where can I find unit testing frameworks
+ similar to JUnit for other languages?</b>
+ </p>
+ <p>
+ XProgramming.com maintains a complete list of available <a
+ href="http://www.xprogramming.com/software.htm">xUnit testing
+ frameworks</a>.
+ </p>
+ </li>
+</ol>
+
+<br/>
+
+<div align="right">
+ <a href="http://validator.w3.org/check?uri=referer">
+ <img src="http://www.w3.org/Icons/valid-xhtml10"
+ alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+</div>
+
+</body>
+</html>
diff --git a/junit4/doc/homepage.html b/junit4/doc/homepage.html
new file mode 100644
index 0000000..ff2a027
--- /dev/null
+++ b/junit4/doc/homepage.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!-- saved from url=(0029)http://junit.sourceforge.net/ -->
+<HTML><HEAD><TITLE>JUnit</TITLE>
+<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
+<META content="MSHTML 6.00.2712.300" name=GENERATOR>
+<META content="Erich Gamma" name=Author></HEAD>
+<BODY>
+<H1><B><FONT color=#00cc00>J</FONT><FONT color=#ff0000>U</FONT><FONT
+color=#000000>nit </FONT></B></H1>
+<P>JUnit is a simple framework to write repeatable tests. It is an instance of
+the xUnit architecture for unit testing frameworks.
+<UL>
+ <LI><A href="http://junit.sourceforge.net/#Getting">Getting Started</A>
+
+ <LI><A href="http://junit.sourceforge.net/#Documentation">Documentation</A>
+ <LI><A href="http://junit.sourceforge.net/#Related">JUnit related
+ sites/projects</A> </LI>
+ <LI><A href="http://junit.sourceforge.net/#Mail">Mailing Lists</A></LI>
+ <LI><A href="http://junit.sourceforge.net/#Developer">Get Involved</A></LI>
+</UL>
+
+<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>
+SimpleTest.java - some simple test cases</li>
+
+<li>
+VectorTest.java - test cases for java.util.Vector</li>
+</ul>
+<P>JUnit 4.x only comes with a textual TestRunner. For graphical feedback,
+most major IDE's support
+JUnit 4. If necessary, you can run JUnit 4 tests in a JUnit 3
+environment by adding the following method to each test class:
+<pre>
+public static Test suite() {
+ return new JUnit4TestAdapter(ThisClass.class);
+}
+
+</pre>
+
+<h2>
+<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_40/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="README.html">Release notes</a>
+<br>&nbsp;&nbsp;&nbsp; Latest JUnit release notes
+<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="junit3.8.1/index.html">The JUnit 3.8 version of this homepage</a>
+<br><a href="doc/testinfected/testing.htm">Test Infected - Programmers
+Love Writing Tests</a>
+<br>&nbsp;&nbsp;&nbsp; An article demonstrating the development process
+with JUnit.
+
+<br><a href="doc/cookstour/cookstour.htm">JUnit - A cooks tour</a>
+</blockquote>
+
+<H2><A name=Related></A>JUnit Related Projects/Sites</H2>
+<UL>
+ <LI><A href="http://www.junit.org/">junit.org</A> - a site for software
+ developers using JUnit. It provides instructions for how to integrate JUnit
+ with development tools like JBuilder and VisualAge/Java. As well as articles
+ about and extensions to JUnit.</LI>
+ <LI><A href="http://www.xprogramming.com/software.htm">XProgramming.com</A> -
+ various implementations of the xUnit testing framework architecture.&nbsp;</LI>
+
+</UL>
+<H2><A name=Mail></A>Mailing Lists</H2>
+There are three junit mailing lists:
+<UL>
+ <LI>JUnit announce: junit-announce@lists.sourceforge.net <A
+ href="http://lists.sourceforge.net/lists/listinfo/junit-announce">Archives/Subscribe/Unsubscribe</A></LI>
+ <LI>JUnit users list: junit@yahoogroups.com <A
+ href="http://groups.yahoo.com/group/junit/">Archives/Subscribe/Unsubscribe</A></LI>
+ <LI>JUnit developer list: junit-devel@lists.sourceforge.net <A
+ href="http://lists.sourceforge.net/lists/listinfo/junit-devel">Archives/Subscribe/Unsubscribe</A></LI>
+
+ </UL>
+
+ <H2><A name=Developer></A>Get Involved</H2>
+ JUnit celebrates programmers testing their own software. As a result
+ bugs, patches, and feature requests which include JUnit TestCases have a
+ better
+ chance of being addressed than those without.
+
+ <br/>
+ JUnit is forged on
+ Sourceforge please use the tools <A
+ href="http://sf.net/projects/junit">provided</A> for your submissions.
+
+ <br/>
+ JUnit source code is now hosted on <a href="http://github.com/KentBeck/junit">GitHub</a>.
+
+<hr WIDTH="100%">
+<font size="1">
+hosted by </font> <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>
+</font>
+
+</BODY></HTML>
diff --git a/junit4/doc/index.htm b/junit4/doc/index.htm
new file mode 100644
index 0000000..dd19ff3
--- /dev/null
+++ b/junit4/doc/index.htm
@@ -0,0 +1,21 @@
+<!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="Author" content="Erich Gamma">
+ <title>JUnit Documentation</title>
+</head>
+<body>
+
+<h1>
+<font color="#33FF33">J</font><font color="#CC0000">U</font>nit Documentation</h1>
+
+<p>
+Kent Beck, Erich Gamma, David Saff</p>
+
+<hr WIDTH="100%">
+We have just begun documenting the new JUnit 4 architecture. The <a href="cookbook/cookbook.htm">cookbook</a> has already been updated. You can find the javadoc <a href="../javadoc/index.html">here</a>.
+The JUnit home page is <a href="http://www.junit.org">here</a>.
+<hr WIDTH="100%">
+</body>
+</html>
diff --git a/junit4/doc/markdown.sh b/junit4/doc/markdown.sh
new file mode 100644
index 0000000..e235b63
--- /dev/null
+++ b/junit4/doc/markdown.sh
@@ -0,0 +1 @@
+~/bin/Markdown.pl ReleaseNotes4.8.txt >ReleaseNotes4.8.html \ No newline at end of file
diff --git a/junit4/doc/testinfected/IMG00001.GIF b/junit4/doc/testinfected/IMG00001.GIF
new file mode 100644
index 0000000..ca491c1
--- /dev/null
+++ b/junit4/doc/testinfected/IMG00001.GIF
Binary files differ
diff --git a/junit4/doc/testinfected/IMG00002.GIF b/junit4/doc/testinfected/IMG00002.GIF
new file mode 100644
index 0000000..2fc614f
--- /dev/null
+++ b/junit4/doc/testinfected/IMG00002.GIF
Binary files differ
diff --git a/junit4/doc/testinfected/IMG00003.GIF b/junit4/doc/testinfected/IMG00003.GIF
new file mode 100644
index 0000000..2695af3
--- /dev/null
+++ b/junit4/doc/testinfected/IMG00003.GIF
Binary files differ
diff --git a/junit4/doc/testinfected/logo.gif b/junit4/doc/testinfected/logo.gif
new file mode 100644
index 0000000..d0e1547
--- /dev/null
+++ b/junit4/doc/testinfected/logo.gif
Binary files differ
diff --git a/junit4/doc/testinfected/testing.htm b/junit4/doc/testinfected/testing.htm
new file mode 100644
index 0000000..d11c11c
--- /dev/null
+++ b/junit4/doc/testinfected/testing.htm
@@ -0,0 +1,617 @@
+<!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="Mozilla/4.75 [en] (Windows NT 5.0; U) [Netscape]">
+ <title>Test Infected: </title>
+</head>
+<body>
+
+<h1>
+<b><font color="#00CC00">J</font><font color="#FF0000">U</font><font color="#000000">nit</font> <font size=+3>Test
+Infected: Programmers Love Writing Tests</font></b></h1>
+<br>Note: this article describes JUnit 3.8.x.
+
+<hr WIDTH="100%">
+<p>Testing is not closely integrated with development. This prevents you
+from measuring the progress of development- you can't tell when something
+starts working or when something stops working. Using <i>JUnit</i> you
+can cheaply and incrementally build a test suite that will help you measure
+your progress, spot unintended side effects, and focus your development
+efforts.
+<h1>
+Contents</h1>
+
+<ul>
+<li>
+<a href="#TheProblem">The Problem</a></li>
+
+<li>
+<a href="#Example">Example</a></li>
+
+<li>
+<a href="#TestingPractices">Testing Practices</a></li>
+
+<li>
+<a href="#Conclusion">Conclusions</a></li>
+</ul>
+
+<h1>
+<a NAME="TheProblem"></a>The Problem</h1>
+Every programmer knows they should write tests for their code. Few do.
+The universal response to "Why not?" is "I'm in too much of a hurry." This
+quickly becomes a vicious cycle- the more pressure you feel, the fewer
+tests you write. The fewer tests you write, the less productive you are
+and the less stable your code becomes. The less productive and accurate
+you are, the more pressure you feel.
+<p>Programmers burn out from just such cycles. Breaking out requires an
+outside influence. We found the outside influence we needed in a simple
+testing framework that lets us do a little testing that makes a big difference.
+<p>The best way to convince you of the value of writing your own tests
+would be to sit down with you and do a bit of development. Along the way,
+we would encounter new bugs, catch them with tests, fix them, have them
+come back, fix them again, and so on. You would see the value of the immediate
+feedback you get from writing and saving and rerunning your own unit tests.
+<p>Unfortunately, this is an article, not an office overlooking charming
+old-town Z&uuml;rich, with the bustle of medieval commerce outside and
+the thump of techno from the record store downstairs, so we'll have to
+simulate the process of development. We'll write a simple program and its
+tests, and show you the results of running the tests. This way you can
+get a feel for the process we use and advocate without having to pay for
+our presence.
+<h1>
+<a NAME="Example"></a>Example</h1>
+As you read, pay attention to the interplay of the code and the tests.
+The style here is to write a few lines of code, then a test that should
+run, or even better, to write a test that won't run, then write the code
+that will make it run.
+<p>The program we write will solve the problem of representing arithmetic
+with multiple currencies. Arithmetic between single currencies is trivial,
+you can just add the two amounts. Simple numbers suffice. You can ignore
+the presence of currencies altogether.
+<p>Things get more interesting once multiple currencies are involved. You
+cannot just convert one currency into another for doing arithmetic since
+there is no single conversion rate- you may need to compare the value of
+a portfolio at yesterday's rate and today's rate.
+<p>Let's start simple and define a class <a href="#classMoney">Money</a>
+to represent a value in a single currency. We represent the amount by a
+simple int. To get full accuracy you would probably use double or java.math.BigDecimal
+to store arbitrary-precision signed decimal numbers. We represent a currency
+as a string holding the ISO three letter abbreviation (USD, CHF, etc.).
+In more complex implementations, currency might deserve its own object.
+<pre><a NAME="classMoney"></a><tt>class Money {
+&nbsp;&nbsp;&nbsp; private int fAmount;
+&nbsp;&nbsp;&nbsp; private String fCurrency;</tt></pre>
+
+<pre><tt>&nbsp;&nbsp;&nbsp; public Money(int amount, String currency) {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fAmount= amount;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fCurrency= currency;
+&nbsp;&nbsp;&nbsp; }
+
+&nbsp;&nbsp;&nbsp; public int amount() {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fAmount;
+&nbsp;&nbsp;&nbsp; }
+
+&nbsp;&nbsp;&nbsp; public String currency() {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fCurrency;
+&nbsp;&nbsp;&nbsp; }
+}</tt></pre>
+When<font size=-1> </font>you add two Moneys of the same currency, the
+resulting Money has as its amount the sum of the other two amounts.
+<pre><a NAME="MoneyAdd"></a><tt>public Money add(Money m) {
+&nbsp;&nbsp;&nbsp; return new Money(amount()+m.amount(), currency());
+}</tt></pre>
+Now, instead of just coding on, we want to get immediate feedback and practice
+"code a little, test a little, code a little, test a little". To implement
+our tests we use the JUnit framework. To write tests you need to get the
+<a href="http://sourceforge.net/projects/junit/">latest
+copy</a> JUnit (or write your own equivalent- it's not so much work).
+<p>JUnit defines how to structure your test cases and provides the tools
+to run them. You implement a test in a subclass of TestCase. To test our
+Money implementation we therefore define <a href="#class MoneyTest">MoneyTest</a>
+as a subclass of TestCase. In Java, classes are contained in packages and
+we have to decide where to put MoneyTest. Our current practice is to put
+MoneyTest in the same package as the classes under test. In this way a
+test case has access to the package private methods. We add a test method
+testSimpleAdd, that will exercise the simple version of <a href="#MoneyAdd">Money.add()</a>
+above. A JUnit test method is an ordinary method without any parameters.
+<pre><a NAME="class MoneyTest"></a><tt>public class MoneyTest extends TestCase {
+&nbsp;&nbsp;&nbsp; //…
+&nbsp;&nbsp;&nbsp; public void testSimpleAdd() {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money m12CHF= new Money(12, "CHF");&nbsp; //&nbsp;<a NAME="MoneyTest1"></a>(1)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money m14CHF= new Money(14, "CHF");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money expected= new Money(26, "CHF");
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money result= m12CHF.add(m14CHF);&nbsp;&nbsp;&nbsp; //&nbsp;<a NAME="MoneyTest2"></a>(2)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Assert.assertTrue(expected.equals(result));&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;<a NAME="MoneyTest3"></a>(3)
+&nbsp;&nbsp;&nbsp; }
+}</tt></pre>
+The testSimpleAdd() test case consists of:
+<ol>
+<li>
+<a href="#MoneyTest1">Code</a> which creates the objects we will interact
+with during the test. This testing context is commonly referred to as a
+test's<i> fixture</i>. All we need for the testSimpleAdd test are some
+Money objects.</li>
+
+<li>
+<a href="#MoneyTest2">Code</a> which exercises the objects in the fixture.</li>
+
+<li>
+<a href="#MoneyTest3">Code</a> which verifies the result.</li>
+</ol>
+Before we can verify the result we have to digress a little since we need
+a way to test that two Money objects are equal. The Java idiom to do so
+is to override the method <i>equals</i> defined in Object. Before we implement
+equals let's a write a test for equals in MoneyTest.
+<pre><tt>public void testEquals() {
+&nbsp;&nbsp;&nbsp; Money m12CHF= new Money(12, "CHF");
+&nbsp;&nbsp;&nbsp; Money m14CHF= new Money(14, "CHF");
+
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(!m12CHF.equals(null));
+&nbsp;&nbsp;&nbsp; Assert.assertEquals(m12CHF, m12CHF);
+&nbsp;&nbsp;&nbsp; Assert.assertEquals(m12CHF, new Money(12, "CHF")); //&nbsp;<a NAME="TestEquals1"></a>(1)
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(!m12CHF.equals(m14CHF));
+}</tt></pre>
+The equals method in Object returns true when both objects are the same.
+However, Money is a <i>value object</i>. Two Monies are considered equal
+if they have the same currency and value. To test this property we have
+added a test <a href="#TestEquals1">(1)</a> to verify that Monies are equal
+when they have the same value but are not the same object.
+<p>Next let's write the equals method in Money:
+<pre><tt>public boolean equals(Object anObject) {
+&nbsp;&nbsp;&nbsp; if (anObject instanceof Money) {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money aMoney= (Money)anObject;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return aMoney.currency().equals(currency())
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; amount() == aMoney.amount();
+&nbsp;&nbsp;&nbsp; }
+&nbsp;&nbsp;&nbsp; return false;
+}</tt></pre>
+Since equals can receive any kind of object as its argument we first have
+to check its type before we cast it as a Money. As an aside, it is a recommended
+practice to also override the method hashCode whenever you override method
+equals. However, we want to get back to our test case.
+<p>With an equals method in hand we can verify the outcome of testSimpleAdd.
+In JUnit you do so by a calling
+<A HREF="../../javadoc/junit/framework/Assert.html#assertTrue(boolean)">Assert.assertTrue</a>,
+which triggers a failure that is recorded by JUnit when the argument isn't
+true. Since assertions for equality are very common, there is also
+an Assert.assertEquals convenience method. In addition to testing for equality
+with equals, it reports the printed value of the two objects in the case they
+differ. This lets us immediately see why a test failed in a JUnit test
+result report. The value a string representation created by
+the toString converter method.
+There are <a href="../../javadoc/junit/framework/Assert.html">
+other asertXXXX variants</a> not discussed here.
+<p>Now that we have implemented two test cases we notice some code duplication
+for setting-up the tests. It would be nice to reuse some of this test set-up
+code. In other words, we would like to have a common fixture for running
+the tests. With JUnit you can do so by storing the fixture's objects in
+instance variables of your
+<a href="../../javadoc/junit/framework/TestCase.html">TestCase</a>
+subclass and initialize them by overridding
+the setUp method. The symmetric operation to setUp is tearDown which you
+can override to clean up the test fixture at the end of a test. Each test
+runs in its own fixture and JUnit calls setUp and tearDown for each test
+so that there can be no side effects among test runs.
+<pre><tt>public class MoneyTest extends TestCase {
+&nbsp;&nbsp;&nbsp; private Money f12CHF;
+&nbsp;&nbsp;&nbsp; private Money f14CHF;&nbsp;&nbsp;&nbsp;
+
+&nbsp;&nbsp;&nbsp; protected void setUp() {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f12CHF= new Money(12, "CHF");
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f14CHF= new Money(14, "CHF");
+&nbsp;&nbsp;&nbsp; }
+}</tt></pre>
+We can rewrite the two test case methods, removing the common setup code:
+<pre><tt>public void testEquals() {
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(!f12CHF.equals(null));
+&nbsp;&nbsp;&nbsp; Assert.assertEquals(f12CHF, f12CHF);
+&nbsp;&nbsp;&nbsp; Assert.assertEquals(f12CHF, new Money(12, "CHF"));
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(!f12CHF.equals(f14CHF));
+}
+
+public void testSimpleAdd() {
+&nbsp;&nbsp;&nbsp; Money expected= new Money(26, "CHF");
+&nbsp;&nbsp;&nbsp; Money result= f12CHF.add(f14CHF);
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(expected.equals(result));
+}</tt></pre>
+Two additional steps are needed to run the two test cases:
+<ol>
+<li>
+define how to run an individual test case,</li>
+
+<li>
+define how to run a <i>test suite</i>.</li>
+</ol>
+JUnit supports two ways of running single tests:
+<ul>
+<li>
+static</li>
+
+<li>
+dynamic</li>
+</ul>
+In the static way you override the runTest method inherited from TestCase
+and call the desired test case. A convenient way to do this is with an
+anonymous inner class. Note that each test must be given a name, so you
+can identify it if it fails.
+<pre><tt>TestCase test= new MoneyTest("simple add") {
+&nbsp;&nbsp;&nbsp; public void runTest() {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; testSimpleAdd();
+&nbsp;&nbsp;&nbsp; }
+};</tt></pre>
+A template method<a href="#Gamma, E., et al. Design Patterns: Elements of">[1]</a>
+in the superclass will make sure runTest is executed when the time comes.
+<p>The dynamic way to create a test case to be run uses reflection to implement
+runTest. It assumes the name of the test is the name of the test case method
+to invoke. It dynamically finds and invokes the test method. To invoke
+the testSimpleAdd test we therefore construct a MoneyTest as shown below:
+<pre><tt>TestCase test= new MoneyTest("testSimpleAdd");</tt></pre>
+The dynamic way is more compact to write but it is less static type safe.
+An error in the name of the test case goes unnoticed until you run it and
+get a NoSuchMethodException. Since both approaches have advantages, we
+decided to leave the choice of which to use up to you.
+<p>As the last step to getting both test cases to run together, we have
+to define a test suite. In JUnit this requires the definition of a static
+method called suite. The suite method is like a main method that is specialized
+to run tests. Inside suite you add the tests to be run to a
+<a href="../../javadoc/junit/framework/TestSuite.html">TestSuite</a> object
+and return it. A TestSuite can run a collection of tests. TestSuite and
+TestCase both implement an interface called Test which defines the methods
+to run a test. This enables the creation of test suites by composing arbitrary
+TestCases and TestSuites. In short TestSuite is a Composite <a href="#Gamma, E., et al. Design Patterns: Elements of">[1].</a>
+The code below illustrates the creation of a test suite with the dynamic
+way to run a test.
+<pre><tt>public static Test suite() {
+&nbsp;&nbsp;&nbsp; TestSuite suite= new TestSuite();
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testEquals"));
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testSimpleAdd"));
+&nbsp;&nbsp;&nbsp; return suite;
+}</tt></pre>
+Since JUnit 2.0 there is an even simpler dynamic way. You only pass the
+class with the tests to a TestSuite and it extracts the test methods automatically.
+<p><tt>public static Test suite() {<br>
+&nbsp;&nbsp;&nbsp; return new TestSuite(MoneyTest.class);<br>
+}</tt><tt></tt>
+<p>Here is the corresponding code using the static way.
+<pre><tt>public static Test suite() {
+&nbsp;&nbsp;&nbsp; TestSuite suite= new TestSuite();
+&nbsp;&nbsp;&nbsp; suite.addTest(
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new MoneyTest("money equals") {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void runTest() { testEquals(); }
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
+&nbsp;&nbsp;&nbsp; );
+&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; suite.addTest(
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new MoneyTest("simple add") {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void runTest() { testSimpleAdd(); }
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
+&nbsp;&nbsp;&nbsp; );
+&nbsp;&nbsp;&nbsp; return suite;
+}</tt></pre>
+Now we are ready to run our tests. JUnit comes with a graphical&nbsp; interface
+to run tests. Type the name of your test class in the field at the top
+of the window. Press the Run button. While the test is run JUnit shows
+its progress with a progress bar below the input field. The bar is initially
+green but turns into red as soon as there is an unsuccessful test. Failed
+tests are shown in a list at the bottom. <a href="#Figure1">Figure 1</a>
+shows the TestRunner window after we run our trivial test suite.
+<center><img SRC="IMG00001.GIF" >
+<br><a NAME="Figure1"></a><b>Figure 1</b>: A Successful Run</center>
+
+<p>After having verified that the simple currency case works we move on
+to multiple currencies. As mentioned above the problem of mixed currency
+arithmetic is that there isn't a single exchange rate. To avoid this problem
+we introduce a MoneyBag which defers exchange rate conversions. For example
+adding 12 Swiss Francs to 14 US Dollars is represented as a bag containing
+the two Monies 12 CHF and 14 USD. Adding another 10 Swiss francs gives
+a bag with 22 CHF and 14 USD. We can later evaluate a MoneyBag with different
+exchange rates.
+<p>A MoneyBag is represented as a list of Monies and provides different
+constructors to create a MoneyBag. Note, that the constructors are package
+private since MoneyBags are created behind the scenes when doing currency
+arithmetic.
+<pre><tt>class MoneyBag {
+&nbsp;&nbsp;&nbsp; private Vector fMonies= new Vector();
+
+&nbsp;&nbsp;&nbsp; MoneyBag(Money m1, Money m2) {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appendMoney(m1);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appendMoney(m2);
+&nbsp;&nbsp;&nbsp; }
+
+&nbsp;&nbsp;&nbsp; MoneyBag(Money bag[]) {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i= 0; i &lt; bag.length; i++)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appendMoney(bag[i]);
+&nbsp;&nbsp;&nbsp; }
+}</tt></pre>
+The method appendMoney is an internal helper method that adds a Money to
+the list of Moneys and takes care of consolidating Monies with the same
+currency. MoneyBag also needs an equals method together with a corresponding
+test. We skip the implementation of equals and only show the testBagEquals
+method. In a first step we extend the fixture to include two MoneyBags.
+<pre><tt>protected void setUp() {
+&nbsp;&nbsp;&nbsp; f12CHF= new Money(12, "CHF");
+&nbsp;&nbsp;&nbsp; f14CHF= new Money(14, "CHF");
+&nbsp;&nbsp;&nbsp; f7USD=&nbsp; new Money( 7, "USD");
+&nbsp;&nbsp;&nbsp; f21USD= new Money(21, "USD");
+&nbsp;&nbsp;&nbsp; fMB1= new MoneyBag(f12CHF, f7USD);
+&nbsp;&nbsp;&nbsp; fMB2= new MoneyBag(f14CHF, f21USD);
+}</tt></pre>
+With this fixture the testBagEquals test case becomes:
+<pre><tt>public void testBagEquals() {
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(!fMB1.equals(null));
+&nbsp;&nbsp;&nbsp; Assert.assertEquals(fMB1, fMB1);
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(!fMB1.equals(f12CHF));
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(!f12CHF.equals(fMB1));
+&nbsp;&nbsp;&nbsp; Assert.assertTrue(!fMB1.equals(fMB2));
+}</tt></pre>
+Following "code a little, test a little" we run our extended test with
+JUnit and verify that we are still doing fine. With MoneyBag in hand, we
+can now fix the add method in Money.
+<pre><tt>public Money add(Money m) {
+&nbsp;&nbsp;&nbsp; if (m.currency().equals(currency()) )
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new Money(amount()+m.amount(), currency());
+&nbsp;&nbsp;&nbsp; return new MoneyBag(this, m);
+}</tt></pre>
+As defined above this method will not compile since it expects a Money
+and not a MoneyBag as its return value. With the introduction of MoneyBag
+there are now two representations for Moneys which we would like to hide
+from the client code. To do so we introduce an interface IMoney that both
+representations implement. Here is the IMoney interface:
+<pre><tt>interface IMoney {
+&nbsp;&nbsp;&nbsp; public abstract IMoney add(IMoney aMoney);
+&nbsp;&nbsp;&nbsp; //…
+}</tt></pre>
+To fully hide the different representations from the client we have to
+support arithmetic between all combinations of Moneys with MoneyBags. Before
+we code on, we therefore define a couple more test cases. The expected
+MoneyBag results use the convenience constructor shown above, initializing
+a MoneyBag from an array.
+<pre><tt>public void testMixedSimpleAdd() {&nbsp;
+&nbsp;&nbsp;&nbsp; // [12 CHF] + [7 USD] == {[12 CHF][7 USD]}&nbsp;
+&nbsp;&nbsp;&nbsp; Money bag[]= { f12CHF, f7USD };&nbsp;
+&nbsp;&nbsp;&nbsp; MoneyBag expected= new MoneyBag(bag);&nbsp;
+&nbsp;&nbsp;&nbsp; Assert.assertEquals(expected, f12CHF.add(f7USD));&nbsp;
+}</tt></pre>
+The other tests follow the same pattern:
+<menu>
+<li>
+testBagSimpleAdd - to add a MoneyBag to a simple Money</li>
+
+<li>
+testSimpleBagAdd - to add a simple Money to a MoneyBag</li>
+
+<li>
+testBagBagAdd - to add two MoneyBags</li>
+</menu>
+Next, we extend our test suite accordingly:
+<pre><tt>public static Test suite() {
+&nbsp;&nbsp;&nbsp; TestSuite suite= new TestSuite();
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testMoneyEquals"));
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testBagEquals"));
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testSimpleAdd"));
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testMixedSimpleAdd"));
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testBagSimpleAdd"));
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testSimpleBagAdd"));
+&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testBagBagAdd"));
+&nbsp;&nbsp;&nbsp; return suite;
+}</tt></pre>
+Having defined the test cases we can start to implement them. The implementation
+challenge here is dealing with all the different combinations of Money
+with MoneyBag. Double dispatch <a href="#Beck, K. Smalltalk Best Practice Patterns,">[2]</a>
+is an elegant way to solve this problem. The idea behind double dispatch
+is to use an additional call to discover the kind of argument we are dealing
+with. We call a method on the argument with the name of the original method
+followed by the class name of the receiver. The add method in Money and
+MoneyBag becomes:
+<pre><tt>class Money implements IMoney {
+&nbsp;&nbsp;&nbsp; public IMoney add(IMoney m) {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m.addMoney(this);
+&nbsp;&nbsp;&nbsp; }
+&nbsp;&nbsp;&nbsp; //…
+}</tt></pre>
+
+<pre><tt>class MoneyBag implements IMoney {
+&nbsp;&nbsp;&nbsp; public IMoney add(IMoney m) {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m.addMoneyBag(this);
+&nbsp;&nbsp;&nbsp; }
+&nbsp;&nbsp;&nbsp; //…
+}</tt></pre>
+In order to get this to compile we need to extend the interface of IMoney
+with the two helper methods:
+<pre><tt>interface IMoney {
+//…
+&nbsp;&nbsp;&nbsp; IMoney addMoney(Money aMoney);
+&nbsp;&nbsp;&nbsp; IMoney addMoneyBag(MoneyBag aMoneyBag);
+}</tt></pre>
+To complete the implementation of double dispatch, we have to implement
+these methods in Money and MoneyBag. This is the implementation in Money.
+<pre><tt>public IMoney addMoney(Money m) {
+&nbsp;&nbsp;&nbsp; if (m.currency().equals(currency()) )
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new Money(amount()+m.amount(), currency());
+&nbsp;&nbsp;&nbsp; return new MoneyBag(this, m);
+}
+
+public IMoney addMoneyBag(MoneyBag s) {
+&nbsp;&nbsp;&nbsp; return s.addMoney(this);
+}</tt></pre>
+Here is the implemenation in MoneyBag which assumes additional constructors
+to create a MoneyBag from a Money and a MoneyBag and from two MoneyBags.
+<pre><tt>public IMoney addMoney(Money m) {
+&nbsp;&nbsp;&nbsp; return new MoneyBag(m, this);
+}
+
+public IMoney addMoneyBag(MoneyBag s) {
+&nbsp;&nbsp;&nbsp; return new MoneyBag(s, this);
+}</tt></pre>
+We run the tests, and they pass. However, while reflecting on the implementation
+we discover another interesting case. What happens when as the result of
+an addition a MoneyBag turns into a bag with only one Money? For example,
+adding -12 CHF to a Moneybag holding 7 USD and 12 CHF results in a bag
+with just 7 USD. Obviously, such a bag should be equal with a single Money
+of 7 USD. To verify the problem let's implement a test case and run it.
+<pre><tt>public void testSimplify() {
+&nbsp;&nbsp;&nbsp; // {[12 CHF][7 USD]} + [-12 CHF] == [7 USD]
+&nbsp;&nbsp;&nbsp; Money expected= new Money(7, "USD");
+&nbsp;&nbsp;&nbsp; Assert.assertEquals(expected, fMB1.add(new Money(-12, "CHF")));
+}</tt></pre>
+When you are developing in this style you will often have a thought and
+turn immediately to writing a test, rather than going straight to the code.
+<p>It comes to no surprise that our test run ends with a red progress bar
+indicating the failure. So we fix the code in MoneyBag to get back to a
+green state.
+<pre><tt>public IMoney addMoney(Money m) {
+&nbsp;&nbsp;&nbsp; return (new MoneyBag(m, this)).simplify();
+}
+
+public IMoney addMoneyBag(MoneyBag s) {
+&nbsp;&nbsp;&nbsp; return (new MoneyBag(s, this)).simplify();
+}
+
+private IMoney simplify() {
+&nbsp;&nbsp;&nbsp; if (fMonies.size() == 1)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (IMoney)fMonies.firstElement()
+&nbsp;&nbsp;&nbsp; return this;
+}</tt></pre>
+Now we run our tests again and voila we end up with green.
+<p>The code above solves only a small portion of the multi-currency arithmetic
+problem. We have to represent different exchange rates, print formatting,
+and the other arithmetic operations, and do it all with reasonable speed.
+However, we hope you can see how you could develop the rest of the objects
+one test at a time- a little test, a little code, a little test, a little
+code.
+<p>In particular, review how in the development above:
+<ul>
+<li>
+We wrote the first test, testSimpleAdd, immediately after we had written
+add(). In general, your development will go much smoother if you write
+tests a little at a time as you develop. It is at the moment that you are
+coding that you are imagining how that code will work. That's the perfect
+time to capture your thoughts in a test.</li>
+
+<li>
+We refactored the existing tests, testSimpleAdd and testEqual, as soon
+as we introduced the common setUp code. Test code is just like model code
+in working best if it is factored well. When you see you have the same
+test code in two places, try to find a way to refactor it so it only appears
+once.</li>
+
+<li>
+We created a suite method, then extended it when we applied Double Dispatch.
+Keeping old tests running is just as important as making new ones run.
+The ideal is to always run all of your tests. Sometimes that will be too
+slow to do 10 times an hour. Make sure you run all of your tests at least
+daily.</li>
+
+<li>
+We created a new test immediately when we thought of the requirement that
+a one element MoneyBag should just return its element. It can be difficult
+to learn to switch gears like this, but we have found it valuable. When
+you are struck by an idea of what your system should do, defer thinking
+about the implementation. Instead, first write the test. Then run it (you
+never know, it might already work). Then work on the implementation.</li>
+</ul>
+
+<h1>
+<a NAME="TestingPractices"></a>Testing Practices</h1>
+Martin Fowler makes this easy for you. He says, "Whenever you are tempted
+to type something into a print statement or a debugger expression, write
+it as a test instead." At first you will find that you have to create a
+new fixtures all the time, and testing will seem to slow you down a little.
+Soon, however, you will begin reusing your library of fixtures and new
+tests will usually be as simple as adding a method to an existing TestCase
+subclass.
+<p>You can always write more tests. However, you will quickly find that
+only a fraction of the tests you can imagine are actually useful. What
+you want is to write tests that fail even though you think they should
+work, or tests that succeed even though you think they should fail. Another
+way to think of it is in cost/benefit terms. You want to write tests that
+will pay you back with information.
+<p>Here are a couple of the times that you will receive a reasonable return
+on your testing investment:
+<ul>
+<li>
+During Development- When you need to add new functionality to the system,
+write the tests first. Then, you will be done developing when the test
+runs.</li>
+
+<li>
+During Debugging- When someone discovers a defect in your code, first write
+a test that will succeed if the code is working. Then debug until the test
+succeeds.</li>
+</ul>
+One word of caution about your tests. Once you get them running, make sure
+they stay running. There is a huge difference between having your suite
+running and having it broken. Ideally, you would run every test in your
+suite every time you change a method. Practically, your suite will soon
+grow too large to run all the time. Try to optimize your setup code so
+you can run all the tests. Or, at the very least, create special suites
+that contain all the tests that might possibly be affected by your current
+development. Then, run the suite every time you compile. And make sure
+you run every test at least once a day: overnight, during lunch, during
+one of those long meetings….
+<h1>
+<a NAME="Conclusion"></a>Conclusion</h1>
+This article only scratches the surface of testing. However, it focuses
+on a style of testing that with a remarkably small investment will make
+you a faster, more productive, more predictable, and less stressed developer.
+<p>Once you've been test infected, your attitude toward development is
+likely to change. Here are some of the changes we have noticed:
+<p>There is a huge difference between tests that are all running correctly
+and tests that aren't. Part of being test infected is not being able to
+go home if your tests aren't 100%. If you run your suite ten or a hundred
+times an hour, though, you won't be able to create enough havoc to make
+you late for supper.
+<p>Sometimes you just won't feel like writing tests, especially at first.
+Don't. However, pay attention to how much more trouble you get into, how
+much more time you spend debugging, and how much more stress you feel when
+you don't have tests. We have been amazed at how much more fun programming
+is and how much more aggressive we are willing to be and how much less
+stress we feel when we are supported by tests. The difference is dramatic
+enough to keep us writing tests even when we don't feel like it.
+<p>You will be able to refactor much more aggressively once you have the
+tests. You won't understand at first just how much you can do, though.
+Try to catch yourself saying, "Oh, I see, I should have designed this thus
+and so. I can't change it now. I don't want to break anything." When you
+say this, save a copy of your current code and give yourself a couple of
+hours to clean up. (This part works best you can get a buddy to look over
+your shoulder while you work.) Make your changes, all the while running
+your tests. You will be surprised at how much ground you can cover in a
+couple of hours if you aren't worrying every second about what you might
+be breaking.
+<p>For example, we switched from the Vector-based implementation of MoneyBag
+to one based on HashTable. We were able to make the switch very quickly
+and confidently because we had so many tests to rely on. If the tests all
+worked, we were sure we hadn't changed the answers the system produced
+at all.
+<p>You will want to get the rest of your team writing tests. The best way
+we have found to spread the test infection is through direct contact. The
+next time someone asks you for help debugging, get them to talk about the
+problem in terms of a fixture and expected results. Then say, "I'd like
+to write down what you just told me in a form we can use." Have them watch
+while you write one little test. Run it. Fix it. Write another. Pretty
+soon they will be writing their own.
+<p>So- give JUnit a try. If you make it better, please send us the changes
+so we can spread them around. Our next article will double click on the
+JUnit framework itself. We will show you how it is constructed, and talk
+a little about our philosophy of framework development.
+<p>We would like to thank Martin Fowler, as good a programmer as any analyst
+can ever hope to be, for his helpful comments in spite of being subjected
+to early versions of JUnit.
+<h1>
+References</h1>
+
+<ol>
+<li>
+<a NAME="Gamma, E., et al. Design Patterns: Elements of"></a>Gamma, E.,
+et al. Design Patterns: Elements of Reusable Object-Oriented Software,
+Addison-Wesley, Reading, MA, 1995</li>
+
+<li>
+<a NAME="Beck, K. Smalltalk Best Practice Patterns,"></a>Beck, K. Smalltalk
+Best Practice Patterns, Prentice Hall, 1996</li>
+</ol>
+
+<hr SIZE=1 WIDTH="100%">
+</body>
+</html>
diff --git a/junit4/done.txt b/junit4/done.txt
new file mode 100644
index 0000000..0a89d46
--- /dev/null
+++ b/junit4/done.txt
@@ -0,0 +1,50 @@
+* name space of JUnit4 is org.junit
+* JUnit4 requires J2SE 5.0
+ leverage J2SE 5.0 features
+* @Test annotation
+ @Test(expected=IndexOutOfBoundsException.class)
+ @Test(timeout= 1000)
+* @Ignore(reason= "...")
+* @Before, @After setup/teardown
+* @BeforeClass, @AfterClass one-time setup/teardown
+* provide ForwardCompatibility so that existing test Runners can
+ run JUnit4 tests:
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(ListTest.class);
+ }
+* add assertEquals(Object[], Object[])
+* Add backward compatibility for old JUnit tests in the new Runner
+* support the assert keyword and use AssertionError
+* remove the old graphical runners
+* simplify: get rid of failures and errors distinction
+* Annotation for runner strategy
+* Parameterized test
+* Should RunNotifier be API?
+* Runner should be abstract class.
+* Run single method with @BeforeClass and @AfterClass
+* Stopping a test run (there was support for this in 3.8 - TestResult.shouldStop())
+
+* Suite annotation example:
+ @Suite(tests={MoneyTest.class, SimpleTest.class})
+ or with filters
+ @Suite(pattern="*Test"}
+ @Suite(package="org.junit.test.*")
+ @Suite
+
+* be able to run all tests simply from the command line
+* get rid of JUnit4TestCaseAdapter (use JUnit4RunnerStrategy in JUnit4TestAdapter)
+* enable tighter and more flexible IDE integration
+ * enable test reordering/prioritization
+ * test categorization & filtering (<- seems like a runner issue) @Category(short, integration) @Test(category=windowsOnly)
+* make sure TestListener is symmetric and meets needs of runner developers
+ * TestRunEvent
+* Decide how we ship JUnit-- 1.5 only or hybrid
+ * README.html
+* add javadoc to API interfaces and Annotations
+ http://java.sun.com/j2se/javadoc/writingapispecs/index.html
+* Merge branch back into head
+* review Ant scripts
+* make suites simpler for both the IDE providers and the users
+* ClassRequest should search up the hierarchy for the requested Class to look for @RunWith
+
+ \ No newline at end of file
diff --git a/junit4/src/main/java/junit/extensions/ActiveTestSuite.java b/junit4/src/main/java/junit/extensions/ActiveTestSuite.java
new file mode 100644
index 0000000..0623565
--- /dev/null
+++ b/junit4/src/main/java/junit/extensions/ActiveTestSuite.java
@@ -0,0 +1,70 @@
+package junit.extensions;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+/**
+ * A TestSuite for active Tests. It runs each
+ * test in a separate thread and waits until all
+ * threads have terminated.
+ * -- Aarhus Radisson Scandinavian Center 11th floor
+ */
+public class ActiveTestSuite extends TestSuite {
+ private volatile int fActiveTestDeathCount;
+
+ public ActiveTestSuite() {
+ }
+
+ public ActiveTestSuite(Class<? extends TestCase> theClass) {
+ super(theClass);
+ }
+
+ public ActiveTestSuite(String name) {
+ super (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
+ //ActiveTestSuite.super.runTest(test, result);
+ test.run(result);
+ } finally {
+ ActiveTestSuite.this.runFinished();
+ }
+ }
+ };
+ t.start();
+ }
+
+ synchronized void waitUntilFinished() {
+ while (fActiveTestDeathCount < testCount()) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ return; // ignore
+ }
+ }
+ }
+
+ synchronized public void runFinished() {
+ fActiveTestDeathCount++;
+ notifyAll();
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/extensions/RepeatedTest.java b/junit4/src/main/java/junit/extensions/RepeatedTest.java
new file mode 100644
index 0000000..3b687a5
--- /dev/null
+++ b/junit4/src/main/java/junit/extensions/RepeatedTest.java
@@ -0,0 +1,38 @@
+package junit.extensions;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+/**
+ * A Decorator that runs a test repeatedly.
+ *
+ */
+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");
+ fTimesRepeat= repeat;
+ }
+
+ @Override
+ public int countTestCases() {
+ return super.countTestCases() * fTimesRepeat;
+ }
+
+ @Override
+ public void run(TestResult result) {
+ for (int i= 0; i < fTimesRepeat; i++) {
+ if (result.shouldStop())
+ break;
+ super.run(result);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "(repeated)";
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/extensions/TestDecorator.java b/junit4/src/main/java/junit/extensions/TestDecorator.java
new file mode 100644
index 0000000..d9ae474
--- /dev/null
+++ b/junit4/src/main/java/junit/extensions/TestDecorator.java
@@ -0,0 +1,43 @@
+package junit.extensions;
+
+import junit.framework.Assert;
+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.
+ *
+ */
+public class TestDecorator extends Assert implements Test {
+ protected Test fTest;
+
+ 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();
+ }
+
+ public Test getTest() {
+ return fTest;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/extensions/TestSetup.java b/junit4/src/main/java/junit/extensions/TestSetup.java
new file mode 100644
index 0000000..00dcd21
--- /dev/null
+++ b/junit4/src/main/java/junit/extensions/TestSetup.java
@@ -0,0 +1,42 @@
+package junit.extensions;
+
+import junit.framework.Protectable;
+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.
+ */
+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 {
+ setUp();
+ basicRun(result);
+ tearDown();
+ }
+ };
+ result.runProtected(this, p);
+ }
+
+ /**
+ * 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.
+ */
+ protected void tearDown() throws Exception {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/extensions/package-info.java b/junit4/src/main/java/junit/extensions/package-info.java
new file mode 100644
index 0000000..a1c5bb4
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/junit/framework/Assert.java b/junit4/src/main/java/junit/framework/Assert.java
new file mode 100644
index 0000000..3dcc23d
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/Assert.java
@@ -0,0 +1,296 @@
+package junit.framework;
+
+/**
+ * A set of assert methods. Messages are only displayed when an assert fails.
+ */
+
+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 AssertionFailedError with the given message.
+ */
+ 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 AssertionFailedError.
+ */
+ static public void assertTrue(boolean condition) {
+ assertTrue(null, condition);
+ }
+ /**
+ * Asserts that a condition is false. If it isn't it throws
+ * an AssertionFailedError with the given message.
+ */
+ static public void assertFalse(String message, boolean condition) {
+ assertTrue(message, !condition);
+ }
+ /**
+ * Asserts that a condition is false. If it isn't it throws
+ * an AssertionFailedError.
+ */
+ static public void assertFalse(boolean condition) {
+ assertFalse(null, condition);
+ }
+ /**
+ * Fails a test with the given message.
+ */
+ static public void fail(String message) {
+ if (message == null) {
+ throw new AssertionFailedError();
+ }
+ throw new AssertionFailedError(message);
+ }
+ /**
+ * Fails a test with no message.
+ */
+ static public void fail() {
+ fail(null);
+ }
+ /**
+ * Asserts that two objects are equal. If they are not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertEquals(String message, Object expected, Object actual) {
+ if (expected == null && actual == null)
+ return;
+ if (expected != null && expected.equals(actual))
+ return;
+ failNotEquals(message, expected, actual);
+ }
+ /**
+ * Asserts that two objects are equal. If they are not
+ * an AssertionFailedError is thrown.
+ */
+ static public void assertEquals(Object expected, Object actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two Strings are equal.
+ */
+ static public void assertEquals(String message, String expected, String actual) {
+ if (expected == null && actual == null)
+ return;
+ if (expected != null && expected.equals(actual))
+ return;
+ String cleanMessage= message == null ? "" : message;
+ throw new ComparisonFailure(cleanMessage, expected, actual);
+ }
+ /**
+ * Asserts that two Strings are equal.
+ */
+ static public void assertEquals(String expected, String actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two doubles 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.
+ */
+ 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 doubles are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(double expected, double actual, double delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+ /**
+ * 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) {
+ if (Float.compare(expected, actual) == 0)
+ return;
+ 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
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(float expected, float actual, float delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+ /**
+ * Asserts that two longs are equal. If they are not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertEquals(String message, long expected, long actual) {
+ assertEquals(message, new Long(expected), new Long(actual));
+ }
+ /**
+ * Asserts that two longs are equal.
+ */
+ static public void assertEquals(long expected, long actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two booleans are equal. If they are not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertEquals(String message, boolean expected, boolean actual) {
+ assertEquals(message, Boolean.valueOf(expected), Boolean.valueOf(actual));
+ }
+ /**
+ * Asserts that two booleans are equal.
+ */
+ static public void assertEquals(boolean expected, boolean actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two bytes are equal. If they are not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertEquals(String message, byte expected, byte actual) {
+ assertEquals(message, new Byte(expected), new Byte(actual));
+ }
+ /**
+ * Asserts that two bytes are equal.
+ */
+ static public void assertEquals(byte expected, byte actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two chars are equal. If they are not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertEquals(String message, char expected, char actual) {
+ assertEquals(message, new Character(expected), new Character(actual));
+ }
+ /**
+ * Asserts that two chars are equal.
+ */
+ static public void assertEquals(char expected, char actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two shorts are equal. If they are not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertEquals(String message, short expected, short actual) {
+ assertEquals(message, new Short(expected), new Short(actual));
+ }
+ /**
+ * Asserts that two shorts are equal.
+ */
+ static public void assertEquals(short expected, short actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two ints are equal. If they are not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertEquals(String message, int expected, int actual) {
+ assertEquals(message, new Integer(expected), new Integer(actual));
+ }
+ /**
+ * Asserts that two ints are equal.
+ */
+ static public void assertEquals(int expected, int actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that an object isn't null.
+ */
+ static public void assertNotNull(Object object) {
+ assertNotNull(null, object);
+ }
+ /**
+ * Asserts that an object isn't null. If it is
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertNotNull(String message, Object object) {
+ assertTrue(message, object != 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) {
+ String message = "Expected: <null> but was: " + String.valueOf(object);
+ assertNull(message, object);
+ }
+ /**
+ * Asserts that an object is null. If it is not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ static public void assertNull(String message, Object object) {
+ assertTrue(message, object == null);
+ }
+ /**
+ * Asserts that two objects refer to the same object. If they are not
+ * an AssertionFailedError is thrown with the given message.
+ */
+ 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 AssertionFailedError is thrown.
+ */
+ 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 AssertionFailedError is thrown with the
+ * given message.
+ */
+ static public void assertNotSame(String message, Object expected, Object actual) {
+ if (expected == actual)
+ failSame(message);
+ }
+ /**
+ * Asserts that two objects do not refer to the same object. If they do
+ * refer to the same object an AssertionFailedError is thrown.
+ */
+ static public void assertNotSame(Object expected, Object actual) {
+ assertNotSame(null, expected, actual);
+ }
+
+ static public void failSame(String message) {
+ String formatted= "";
+ if (message != null)
+ formatted= message+" ";
+ fail(formatted+"expected not same");
+ }
+
+ static public void failNotSame(String message, Object expected, Object actual) {
+ String formatted= "";
+ if (message != null)
+ formatted= message+" ";
+ fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">");
+ }
+
+ static public void failNotEquals(String message, Object expected, Object actual) {
+ fail(format(message, expected, actual));
+ }
+
+ public static String format(String message, Object expected, Object actual) {
+ String formatted= "";
+ if (message != null && message.length() > 0)
+ formatted= message+" ";
+ return formatted+"expected:<"+expected+"> but was:<"+actual+">";
+ }
+}
diff --git a/junit4/src/main/java/junit/framework/AssertionFailedError.java b/junit4/src/main/java/junit/framework/AssertionFailedError.java
new file mode 100644
index 0000000..0d7802c
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/AssertionFailedError.java
@@ -0,0 +1,20 @@
+package junit.framework;
+
+/**
+ * Thrown when an assertion failed.
+ */
+public class AssertionFailedError extends AssertionError {
+
+ private static final long serialVersionUID= 1L;
+
+ public AssertionFailedError() {
+ }
+
+ public AssertionFailedError(String message) {
+ super(defaultString(message));
+ }
+
+ private static String defaultString(String message) {
+ return message == null ? "" : message;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/framework/ComparisonCompactor.java b/junit4/src/main/java/junit/framework/ComparisonCompactor.java
new file mode 100644
index 0000000..bbc3ba1
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/ComparisonCompactor.java
@@ -0,0 +1,72 @@
+package junit.framework;
+
+public class ComparisonCompactor {
+
+ private static final String ELLIPSIS= "...";
+ private static final String DELTA_END= "]";
+ private static final String DELTA_START= "[";
+
+ private int fContextLength;
+ private String fExpected;
+ private String fActual;
+ private int fPrefix;
+ private int fSuffix;
+
+ public ComparisonCompactor(int contextLength, String expected, String actual) {
+ fContextLength= contextLength;
+ fExpected= expected;
+ fActual= actual;
+ }
+
+ public 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);
+ }
+}
diff --git a/junit4/src/main/java/junit/framework/ComparisonFailure.java b/junit4/src/main/java/junit/framework/ComparisonFailure.java
new file mode 100644
index 0000000..5077993
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/ComparisonFailure.java
@@ -0,0 +1,52 @@
+package junit.framework;
+
+/**
+ * Thrown when an assert equals for Strings failed.
+ *
+ * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com
+ */
+public class ComparisonFailure extends AssertionFailedError {
+ 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());
+ }
+
+ /**
+ * Gets the actual string value
+ * @return the actual string value
+ */
+ public String getActual() {
+ return fActual;
+ }
+ /**
+ * Gets the expected string value
+ * @return the expected string value
+ */
+ public String getExpected() {
+ return fExpected;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/framework/JUnit4TestAdapter.java b/junit4/src/main/java/junit/framework/JUnit4TestAdapter.java
new file mode 100644
index 0000000..a05a313
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/junit/framework/JUnit4TestAdapterCache.java b/junit4/src/main/java/junit/framework/JUnit4TestAdapterCache.java
new file mode 100644
index 0000000..26175c5
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/junit/framework/JUnit4TestCaseFacade.java b/junit4/src/main/java/junit/framework/JUnit4TestCaseFacade.java
new file mode 100644
index 0000000..fd43822
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/junit/framework/Protectable.java b/junit4/src/main/java/junit/framework/Protectable.java
new file mode 100644
index 0000000..e143237
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/Protectable.java
@@ -0,0 +1,14 @@
+package junit.framework;
+
+/**
+ * A <em>Protectable</em> can be run and can throw a Throwable.
+ *
+ * @see TestResult
+ */
+public interface Protectable {
+
+ /**
+ * Run the the following method protected.
+ */
+ public abstract void protect() throws Throwable;
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/framework/Test.java b/junit4/src/main/java/junit/framework/Test.java
new file mode 100644
index 0000000..a016ee8
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/Test.java
@@ -0,0 +1,17 @@
+package junit.framework;
+
+/**
+ * A <em>Test</em> can be run and collect its results.
+ *
+ * @see TestResult
+ */
+public interface Test {
+ /**
+ * Counts the number of test cases that will be run by this test.
+ */
+ public abstract int countTestCases();
+ /**
+ * Runs a test and collects its result in a TestResult instance.
+ */
+ public abstract void run(TestResult result);
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/framework/TestCase.java b/junit4/src/main/java/junit/framework/TestCase.java
new file mode 100644
index 0000000..b047ec9
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/TestCase.java
@@ -0,0 +1,212 @@
+package junit.framework;
+
+import java.lang.reflect.InvocationTargetException;
+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/>
+ * <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 void setUp() {
+ * 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 {@link junit.framework.Assert#assertTrue(String, boolean)} with a boolean.
+ * <pre>
+ * public void testAdd() {
+ * 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();
+ * }
+ * };
+ * test.run();
+ * </pre>
+ *
+ * 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.
+ * <pre>
+ * 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;
+ * }
+ * </pre>
+ * @see TestResult
+ * @see TestSuite
+ */
+public abstract class TestCase extends Assert implements Test {
+ /**
+ * the name of the test case
+ */
+ private String fName;
+
+ /**
+ * No-arg constructor to enable serialization. This method
+ * is not intended to be used by mere mortals without calling setName().
+ */
+ public TestCase() {
+ fName= null;
+ }
+ /**
+ * Constructs a test case with the given name.
+ */
+ public TestCase(String name) {
+ fName= name;
+ }
+ /**
+ * Counts the number of test cases executed by run(TestResult result).
+ */
+ public int countTestCases() {
+ return 1;
+ }
+ /**
+ * Creates a default TestResult object
+ *
+ * @see TestResult
+ */
+ protected TestResult createResult() {
+ return new TestResult();
+ }
+ /**
+ * A convenience method to run this test, collecting the results with a
+ * default TestResult object.
+ *
+ * @see TestResult
+ */
+ public TestResult run() {
+ TestResult result= createResult();
+ run(result);
+ return result;
+ }
+ /**
+ * Runs the test case and collects the results in TestResult.
+ */
+ public void run(TestResult result) {
+ result.run(this);
+ }
+ /**
+ * Runs the bare test sequence.
+ * @throws Throwable if any exception is thrown
+ */
+ public void runBare() throws Throwable {
+ Throwable exception= null;
+ setUp();
+ try {
+ runTest();
+ } catch (Throwable running) {
+ exception= running;
+ }
+ finally {
+ try {
+ tearDown();
+ } catch (Throwable tearingDown) {
+ if (exception == null) exception= tearingDown;
+ }
+ }
+ if (exception != null) throw exception;
+ }
+ /**
+ * Override to run the test and assert its state.
+ * @throws Throwable if any exception is thrown
+ */
+ protected void runTest() throws Throwable {
+ 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
+ // methods. getDeclaredMethods returns all
+ // methods of this class but excludes the
+ // inherited ones.
+ runMethod= getClass().getMethod(fName, (Class[])null);
+ } catch (NoSuchMethodException e) {
+ fail("Method \""+fName+"\" not found");
+ }
+ if (!Modifier.isPublic(runMethod.getModifiers())) {
+ fail("Method \""+fName+"\" should be public");
+ }
+
+ try {
+ runMethod.invoke(this);
+ }
+ catch (InvocationTargetException e) {
+ e.fillInStackTrace();
+ throw e.getTargetException();
+ }
+ catch (IllegalAccessException e) {
+ e.fillInStackTrace();
+ throw e;
+ }
+ }
+ /**
+ * Sets up the fixture, for example, open a network connection.
+ * This method is called before a test is executed.
+ */
+ protected void setUp() throws Exception {
+ }
+ /**
+ * Tears down the fixture, for example, close a network connection.
+ * This method is called after a test is executed.
+ */
+ protected void tearDown() throws Exception {
+ }
+ /**
+ * Returns a string representation of the test case
+ */
+ @Override
+ public String toString() {
+ return getName() + "(" + getClass().getName() + ")";
+ }
+ /**
+ * Gets the name of a TestCase
+ * @return the name of the TestCase
+ */
+ public String getName() {
+ return fName;
+ }
+ /**
+ * Sets the name of a TestCase
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ fName= name;
+ }
+}
diff --git a/junit4/src/main/java/junit/framework/TestFailure.java b/junit4/src/main/java/junit/framework/TestFailure.java
new file mode 100644
index 0000000..6662b1f
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/TestFailure.java
@@ -0,0 +1,58 @@
+package junit.framework;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+
+/**
+ * A <code>TestFailure</code> collects a failed test together with
+ * the caught exception.
+ * @see TestResult
+ */
+public class TestFailure extends Object {
+ protected Test fFailedTest;
+ protected Throwable fThrownException;
+
+
+ /**
+ * Constructs a TestFailure with the given test and exception.
+ */
+ public TestFailure(Test failedTest, Throwable thrownException) {
+ fFailedTest= failedTest;
+ fThrownException= thrownException;
+ }
+ /**
+ * Gets the failed test.
+ */
+ public Test failedTest() {
+ return fFailedTest;
+ }
+ /**
+ * Gets the thrown exception.
+ */
+ public Throwable thrownException() {
+ return fThrownException;
+ }
+ /**
+ * Returns a short description of the failure.
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer= new StringBuffer();
+ buffer.append(fFailedTest+": "+fThrownException.getMessage());
+ return buffer.toString();
+ }
+ public String trace() {
+ StringWriter stringWriter= new StringWriter();
+ PrintWriter writer= new PrintWriter(stringWriter);
+ thrownException().printStackTrace(writer);
+ StringBuffer buffer= stringWriter.getBuffer();
+ return buffer.toString();
+ }
+ public String exceptionMessage() {
+ return thrownException().getMessage();
+ }
+ public boolean isFailure() {
+ return thrownException() instanceof AssertionFailedError;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/framework/TestListener.java b/junit4/src/main/java/junit/framework/TestListener.java
new file mode 100644
index 0000000..9b69443
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/TestListener.java
@@ -0,0 +1,23 @@
+package junit.framework;
+
+/**
+ * A Listener for test progress
+ */
+public interface TestListener {
+ /**
+ * An error occurred.
+ */
+ public void addError(Test test, Throwable t);
+ /**
+ * A failure occurred.
+ */
+ public void addFailure(Test test, AssertionFailedError t);
+ /**
+ * A test ended.
+ */
+ public void endTest(Test test);
+ /**
+ * A test started.
+ */
+ public void startTest(Test test);
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/framework/TestResult.java b/junit4/src/main/java/junit/framework/TestResult.java
new file mode 100644
index 0000000..5768e9a
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/TestResult.java
@@ -0,0 +1,169 @@
+package junit.framework;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+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 {@link ArrayIndexOutOfBoundsException}.
+ *
+ * @see Test
+ */
+public class TestResult extends Object {
+ protected List<TestFailure> fFailures;
+ protected List<TestFailure> fErrors;
+ protected List<TestListener> fListeners;
+ protected int fRunTests;
+ private boolean fStop;
+
+ public TestResult() {
+ fFailures= new ArrayList<TestFailure>();
+ fErrors= new ArrayList<TestFailure>();
+ fListeners= new ArrayList<TestListener>();
+ fRunTests= 0;
+ fStop= false;
+ }
+ /**
+ * Adds an error to the list of errors. The passed in exception
+ * caused the error.
+ */
+ public synchronized void addError(Test test, Throwable t) {
+ fErrors.add(new TestFailure(test, t));
+ 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.add(new TestFailure(test, t));
+ for (TestListener each : cloneListeners())
+ each.addFailure(test, t);
+ }
+ /**
+ * Registers a TestListener
+ */
+ public synchronized void addListener(TestListener listener) {
+ fListeners.add(listener);
+ }
+ /**
+ * Unregisters a TestListener
+ */
+ public synchronized void removeListener(TestListener listener) {
+ fListeners.remove(listener);
+ }
+ /**
+ * Returns a copy of the listeners.
+ */
+ 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 (TestListener each : cloneListeners())
+ each.endTest(test);
+ }
+ /**
+ * Gets the number of detected errors.
+ */
+ public synchronized int errorCount() {
+ return fErrors.size();
+ }
+ /**
+ * Returns an Enumeration for the errors
+ */
+ public synchronized Enumeration<TestFailure> errors() {
+ return Collections.enumeration(fErrors);
+ }
+
+
+ /**
+ * Gets the number of detected failures.
+ */
+ public synchronized int failureCount() {
+ return fFailures.size();
+ }
+ /**
+ * Returns an Enumeration for the failures
+ */
+ public synchronized Enumeration<TestFailure> failures() {
+ return Collections.enumeration(fFailures);
+ }
+
+ /**
+ * Runs a TestCase.
+ */
+ protected void run(final TestCase test) {
+ startTest(test);
+ Protectable p= new Protectable() {
+ public void protect() throws Throwable {
+ test.runBare();
+ }
+ };
+ runProtected(test, p);
+
+ endTest(test);
+ }
+ /**
+ * Gets the number of run tests.
+ */
+ public synchronized int runCount() {
+ return fRunTests;
+ }
+ /**
+ * Runs a TestCase.
+ */
+ public void runProtected(final Test test, Protectable p) {
+ try {
+ p.protect();
+ }
+ catch (AssertionFailedError e) {
+ addFailure(test, e);
+ }
+ catch (ThreadDeath e) { // don't catch ThreadDeath by accident
+ throw e;
+ }
+ catch (Throwable e) {
+ addError(test, e);
+ }
+ }
+ /**
+ * Checks whether the test run should stop
+ */
+ public synchronized boolean shouldStop() {
+ return fStop;
+ }
+ /**
+ * Informs the result that a test will be started.
+ */
+ public void startTest(Test test) {
+ final int count= test.countTestCases();
+ synchronized(this) {
+ fRunTests+= count;
+ }
+ for (TestListener each : cloneListeners())
+ each.startTest(test);
+ }
+ /**
+ * Marks that the test run should stop.
+ */
+ public synchronized void stop() {
+ fStop= true;
+ }
+ /**
+ * Returns whether the entire test was successful or not.
+ */
+ public synchronized boolean wasSuccessful() {
+ return failureCount() == 0 && errorCount() == 0;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/framework/TestSuite.java b/junit4/src/main/java/junit/framework/TestSuite.java
new file mode 100644
index 0000000..336efd1
--- /dev/null
+++ b/junit4/src/main/java/junit/framework/TestSuite.java
@@ -0,0 +1,307 @@
+package junit.framework;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+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;
+
+/**
+ * <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>
+ * TestSuite suite= new TestSuite();
+ * suite.addTest(new MathTest("testAdd"));
+ * suite.addTest(new MathTest("testDivideByZero"));
+ * </pre>
+ * </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>
+ * </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
+ */
+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;
+ try {
+ constructor= getTestConstructor(theClass);
+ } catch (NoSuchMethodException e) {
+ return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()");
+ }
+ Object test;
+ try {
+ if (constructor.getParameterTypes().length == 0) {
+ test= constructor.newInstance(new Object[0]);
+ if (test instanceof TestCase)
+ ((TestCase) test).setName(name);
+ } else {
+ test= constructor.newInstance(new Object[]{name});
+ }
+ } catch (InstantiationException e) {
+ return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")"));
+ } catch (InvocationTargetException e) {
+ return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")"));
+ } catch (IllegalAccessException e) {
+ return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")"));
+ }
+ return (Test) 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 {
+ try {
+ return theClass.getConstructor(String.class);
+ } catch (NoSuchMethodException e) {
+ // fall through
+ }
+ return theClass.getConstructor(new Class[0]);
+ }
+
+ /**
+ * Returns a test which will fail and log a warning message.
+ */
+ public static Test warning(final String message) {
+ return new TestCase("warning") {
+ @Override
+ protected void runTest() {
+ fail(message);
+ }
+ };
+ }
+
+ /**
+ * Converts the stack trace into a string
+ */
+ private static String exceptionToString(Throwable t) {
+ StringWriter stringWriter= new StringWriter();
+ PrintWriter writer= new PrintWriter(stringWriter);
+ t.printStackTrace(writer);
+ return stringWriter.toString();
+ }
+
+ private String fName;
+
+ 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.
+ */
+ public TestSuite() {
+ }
+
+ /**
+ * Constructs a TestSuite from the given class. Adds all the methods
+ * starting with "test" as test cases to the suite.
+ * Parts of this method were written at 2337 meters in the Hueffihuette,
+ * Kanton Uri
+ */
+ public TestSuite(final Class<?> theClass) {
+ addTestsFromTestCase(theClass);
+ }
+
+ private void addTestsFromTestCase(final Class<?> theClass) {
+ fName= theClass.getName();
+ try {
+ getTestConstructor(theClass); // Avoid generating multiple error messages
+ } catch (NoSuchMethodException e) {
+ addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"));
+ return;
+ }
+
+ if (!Modifier.isPublic(theClass.getModifiers())) {
+ addTest(warning("Class "+theClass.getName()+" is not public"));
+ return;
+ }
+
+ Class<?> superClass= theClass;
+ List<String> names= new ArrayList<String>();
+ while (Test.class.isAssignableFrom(superClass)) {
+ for (Method each : superClass.getDeclaredMethods())
+ addTestMethod(each, names, theClass);
+ superClass= superClass.getSuperclass();
+ }
+ if (fTests.size() == 0)
+ addTest(warning("No tests found in "+theClass.getName()));
+ }
+
+ /**
+ * Constructs a TestSuite from the given class with the given name.
+ * @see TestSuite#TestSuite(Class)
+ */
+ public TestSuite(Class<? extends TestCase> theClass, String name) {
+ this(theClass);
+ setName(name);
+ }
+
+ /**
+ * Constructs an empty TestSuite.
+ */
+ public TestSuite(String name) {
+ setName(name);
+ }
+
+ /**
+ * Constructs a TestSuite from the given array of classes.
+ * @param classes {@link TestCase}s
+ */
+ 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<? extends TestCase>[] classes, String name) {
+ this(classes);
+ setName(name);
+ }
+
+ /**
+ * Adds a test to the suite.
+ */
+ public void addTest(Test test) {
+ fTests.add(test);
+ }
+
+ /**
+ * Adds the tests from the given class to the suite
+ */
+ public void addTestSuite(Class<? extends TestCase> testClass) {
+ addTest(new TestSuite(testClass));
+ }
+
+ /**
+ * Counts the number of test cases that will be run by this test.
+ */
+ public int countTestCases() {
+ int count= 0;
+ for (Test each : fTests)
+ count+= each.countTestCases();
+ return count;
+ }
+
+ /**
+ * Returns the name of the suite. Not all
+ * test suites have a name and this method
+ * can return null.
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * Runs the tests and collects their result in a TestResult.
+ */
+ public void run(TestResult result) {
+ for (Test each : fTests) {
+ if (result.shouldStop() )
+ break;
+ runTest(each, result);
+ }
+ }
+
+ public void runTest(Test test, TestResult result) {
+ test.run(result);
+ }
+
+ /**
+ * Sets the name of the suite.
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ fName= name;
+ }
+
+ /**
+ * Returns the test at the given index
+ */
+ public Test testAt(int index) {
+ return fTests.get(index);
+ }
+
+ /**
+ * Returns the number of tests in this suite
+ */
+ public int testCount() {
+ return fTests.size();
+ }
+
+ /**
+ * Returns the tests as an enumeration
+ */
+ public Enumeration<Test> tests() {
+ return fTests.elements();
+ }
+
+ /**
+ */
+ @Override
+ public String toString() {
+ if (getName() != null)
+ return getName();
+ return super.toString();
+ }
+
+ 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() + "(" + theClass.getCanonicalName() + ")"));
+ return;
+ }
+ names.add(name);
+ addTest(createTest(theClass, name));
+ }
+
+ private boolean isPublicTestMethod(Method m) {
+ return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
+ }
+
+ private boolean isTestMethod(Method m) {
+ return
+ m.getParameterTypes().length == 0 &&
+ m.getName().startsWith("test") &&
+ m.getReturnType().equals(Void.TYPE);
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/framework/package-info.java b/junit4/src/main/java/junit/framework/package-info.java
new file mode 100644
index 0000000..153a1c8
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/junit/runner/BaseTestRunner.java b/junit4/src/main/java/junit/runner/BaseTestRunner.java
new file mode 100644
index 0000000..6a4b090
--- /dev/null
+++ b/junit4/src/main/java/junit/runner/BaseTestRunner.java
@@ -0,0 +1,318 @@
+package junit.runner;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.text.NumberFormat;
+import java.util.Properties;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestListener;
+import junit.framework.TestSuite;
+
+/**
+ * Base class for all test runners.
+ * This class was born live on stage in Sardinia during XP2000.
+ */
+public abstract class BaseTestRunner implements TestListener {
+ public static final String SUITE_METHODNAME= "suite";
+
+ private static Properties fPreferences;
+ static int fgMaxMessageLength= 500;
+ static boolean fgFilterStack= true;
+ boolean fLoading= true;
+
+ /*
+ * Implementation of TestListener
+ */
+ public synchronized void startTest(Test test) {
+ testStarted(test.toString());
+ }
+
+ protected static void setPreferences(Properties preferences) {
+ fPreferences= preferences;
+ }
+
+ protected static Properties getPreferences() {
+ if (fPreferences == null) {
+ fPreferences= new Properties();
+ fPreferences.put("loading", "true");
+ fPreferences.put("filterstack", "true");
+ readPreferences();
+ }
+ return fPreferences;
+ }
+
+ public static void savePreferences() throws IOException {
+ FileOutputStream fos= new FileOutputStream(getPreferencesFile());
+ try {
+ getPreferences().store(fos, "");
+ } finally {
+ fos.close();
+ }
+ }
+
+ public static void setPreference(String key, String value) {
+ getPreferences().put(key, value);
+ }
+
+ public synchronized void endTest(Test test) {
+ testEnded(test.toString());
+ }
+
+ public synchronized void addError(final Test test, final Throwable t) {
+ testFailed(TestRunListener.STATUS_ERROR, test, t);
+ }
+
+ public synchronized void addFailure(final Test test, final AssertionFailedError t) {
+ testFailed(TestRunListener.STATUS_FAILURE, test, t);
+ }
+
+ // TestRunListener implementation
+
+ public abstract void testStarted(String testName);
+
+ public abstract void testEnded(String testName);
+
+ public abstract void testFailed(int status, Test test, Throwable t);
+
+ /**
+ * Returns the Test corresponding to the given suite. This is
+ * a template method, subclasses override runFailed(), clearStatus().
+ */
+ public Test getTest(String suiteClassName) {
+ if (suiteClassName.length() <= 0) {
+ clearStatus();
+ return null;
+ }
+ Class<?> testClass= null;
+ try {
+ testClass= loadSuiteClass(suiteClassName);
+ } catch (ClassNotFoundException e) {
+ String clazz= e.getMessage();
+ if (clazz == null)
+ clazz= suiteClassName;
+ runFailed("Class not found \""+clazz+"\"");
+ return null;
+ } catch(Exception e) {
+ runFailed("Error: "+e.toString());
+ return null;
+ }
+ Method suiteMethod= null;
+ try {
+ suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
+ } catch(Exception e) {
+ // try to extract a test suite automatically
+ clearStatus();
+ return new TestSuite(testClass);
+ }
+ if (! Modifier.isStatic(suiteMethod.getModifiers())) {
+ runFailed("Suite() method must be static");
+ return null;
+ }
+ Test test= null;
+ try {
+ test= (Test)suiteMethod.invoke(null, (Object[])new Class[0]); // static method
+ if (test == null)
+ return test;
+ }
+ catch (InvocationTargetException e) {
+ runFailed("Failed to invoke suite():" + e.getTargetException().toString());
+ return null;
+ }
+ catch (IllegalAccessException e) {
+ runFailed("Failed to invoke suite():" + e.toString());
+ return null;
+ }
+
+ clearStatus();
+ return test;
+ }
+
+ /**
+ * Returns the formatted string of the elapsed time.
+ */
+ public String elapsedTimeAsString(long runTime) {
+ return NumberFormat.getInstance().format((double)runTime/1000);
+ }
+
+ /**
+ * Processes the command line arguments and
+ * returns the name of the suite class to run or null
+ */
+ protected String processArguments(String[] args) {
+ String suiteName= null;
+ for (int i= 0; i < args.length; i++) {
+ if (args[i].equals("-noloading")) {
+ setLoading(false);
+ } else if (args[i].equals("-nofilterstack")) {
+ fgFilterStack= false;
+ } else if (args[i].equals("-c")) {
+ if (args.length > i+1)
+ suiteName= extractClassName(args[i+1]);
+ else
+ System.out.println("Missing Test class name");
+ i++;
+ } else {
+ suiteName= args[i];
+ }
+ }
+ return suiteName;
+ }
+
+ /**
+ * Sets the loading behaviour of the test runner
+ */
+ public void setLoading(boolean enable) {
+ fLoading= enable;
+ }
+ /**
+ * Extract the class name from a String in VA/Java style
+ */
+ public String extractClassName(String className) {
+ if(className.startsWith("Default package for"))
+ return className.substring(className.lastIndexOf(".")+1);
+ return className;
+ }
+
+ /**
+ * Truncates a String to the maximum length.
+ */
+ public static String truncate(String s) {
+ if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength)
+ s= s.substring(0, fgMaxMessageLength)+"...";
+ return s;
+ }
+
+ /**
+ * Override to define how to handle a failed loading of
+ * a test suite.
+ */
+ protected abstract void runFailed(String message);
+
+ /**
+ * Returns the loaded Class for a suite name.
+ */
+ protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
+ return Class.forName(suiteClassName);
+ }
+
+ /**
+ * Clears the status message.
+ */
+ protected void clearStatus() { // Belongs in the GUI TestRunner class
+ }
+
+ protected boolean useReloadingTestSuiteLoader() {
+ return getPreference("loading").equals("true") && fLoading;
+ }
+
+ private static File getPreferencesFile() {
+ String home= System.getProperty("user.home");
+ return new File(home, "junit.properties");
+ }
+
+ private static void readPreferences() {
+ InputStream is= null;
+ try {
+ is= new FileInputStream(getPreferencesFile());
+ setPreferences(new Properties(getPreferences()));
+ getPreferences().load(is);
+ } catch (IOException e) {
+ try {
+ if (is != null)
+ is.close();
+ } catch (IOException e1) {
+ }
+ }
+ }
+
+ public static String getPreference(String key) {
+ return getPreferences().getProperty(key);
+ }
+
+ public static int getPreference(String key, int dflt) {
+ String value= getPreference(key);
+ int intValue= dflt;
+ if (value == null)
+ return intValue;
+ try {
+ intValue= Integer.parseInt(value);
+ } catch (NumberFormatException ne) {
+ }
+ return intValue;
+ }
+
+ /**
+ * Returns a filtered stack trace
+ */
+ public static String getFilteredTrace(Throwable t) {
+ StringWriter stringWriter= new StringWriter();
+ PrintWriter writer= new PrintWriter(stringWriter);
+ t.printStackTrace(writer);
+ StringBuffer buffer= stringWriter.getBuffer();
+ String trace= buffer.toString();
+ return BaseTestRunner.getFilteredTrace(trace);
+ }
+
+ /**
+ * Filters stack frames from internal JUnit classes
+ */
+ public static String getFilteredTrace(String stack) {
+ if (showStackRaw())
+ return stack;
+
+ StringWriter sw= new StringWriter();
+ PrintWriter pw= new PrintWriter(sw);
+ StringReader sr= new StringReader(stack);
+ BufferedReader br= new BufferedReader(sr);
+
+ String line;
+ try {
+ while ((line= br.readLine()) != null) {
+ if (!filterLine(line))
+ pw.println(line);
+ }
+ } catch (Exception IOException) {
+ return stack; // return the stack unfiltered
+ }
+ return sw.toString();
+ }
+
+ protected static boolean showStackRaw() {
+ return !getPreference("filterstack").equals("true") || fgFilterStack == false;
+ }
+
+ static boolean filterLine(String line) {
+ String[] patterns= new String[] {
+ "junit.framework.TestCase",
+ "junit.framework.TestResult",
+ "junit.framework.TestSuite",
+ "junit.framework.Assert.", // don't filter AssertionFailure
+ "junit.swingui.TestRunner",
+ "junit.awtui.TestRunner",
+ "junit.textui.TestRunner",
+ "java.lang.reflect.Method.invoke("
+ };
+ for (int i= 0; i < patterns.length; i++) {
+ if (line.indexOf(patterns[i]) > 0)
+ return true;
+ }
+ return false;
+ }
+
+ static {
+ fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
+ }
+
+}
diff --git a/junit4/src/main/java/junit/runner/TestRunListener.java b/junit4/src/main/java/junit/runner/TestRunListener.java
new file mode 100644
index 0000000..b11ef07
--- /dev/null
+++ b/junit4/src/main/java/junit/runner/TestRunListener.java
@@ -0,0 +1,19 @@
+package junit.runner;
+/**
+ * A listener interface for observing the
+ * execution of a test run. Unlike TestListener,
+ * this interface using only primitive objects,
+ * making it suitable for remote test execution.
+ */
+ public interface TestRunListener {
+ /* test status constants*/
+ public static final int STATUS_ERROR= 1;
+ public static final int STATUS_FAILURE= 2;
+
+ public void testRunStarted(String testSuiteName, int testCount);
+ public void testRunEnded(long elapsedTime);
+ public void testRunStopped(long elapsedTime);
+ public void testStarted(String testName);
+ public void testEnded(String testName);
+ public void testFailed(int status, String testName, String trace);
+}
diff --git a/junit4/src/main/java/junit/runner/Version.java b/junit4/src/main/java/junit/runner/Version.java
new file mode 100644
index 0000000..21aabfa
--- /dev/null
+++ b/junit4/src/main/java/junit/runner/Version.java
@@ -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 "4.10-SNAPSHOT";
+ }
+
+ public static void main(String[] args) {
+ System.out.println(id());
+ }
+}
diff --git a/junit4/src/main/java/junit/runner/Version.java.template b/junit4/src/main/java/junit/runner/Version.java.template
new file mode 100644
index 0000000..3182cfd
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/junit/runner/logo.gif b/junit4/src/main/java/junit/runner/logo.gif
new file mode 100644
index 0000000..d0e1547
--- /dev/null
+++ b/junit4/src/main/java/junit/runner/logo.gif
Binary files differ
diff --git a/junit4/src/main/java/junit/runner/package-info.java b/junit4/src/main/java/junit/runner/package-info.java
new file mode 100644
index 0000000..b746185
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/junit/runner/smalllogo.gif b/junit4/src/main/java/junit/runner/smalllogo.gif
new file mode 100644
index 0000000..7b25eaf
--- /dev/null
+++ b/junit4/src/main/java/junit/runner/smalllogo.gif
Binary files differ
diff --git a/junit4/src/main/java/junit/textui/ResultPrinter.java b/junit4/src/main/java/junit/textui/ResultPrinter.java
new file mode 100644
index 0000000..f2f01f5
--- /dev/null
+++ b/junit4/src/main/java/junit/textui/ResultPrinter.java
@@ -0,0 +1,139 @@
+
+package junit.textui;
+
+import java.io.PrintStream;
+import java.text.NumberFormat;
+import java.util.Enumeration;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.runner.BaseTestRunner;
+
+public class ResultPrinter implements TestListener {
+ PrintStream fWriter;
+ int fColumn= 0;
+
+ public ResultPrinter(PrintStream writer) {
+ fWriter= writer;
+ }
+
+ /* API for use by textui.TestRunner
+ */
+
+ synchronized void print(TestResult result, long runTime) {
+ printHeader(runTime);
+ printErrors(result);
+ printFailures(result);
+ printFooter(result);
+ }
+
+ void printWaitPrompt() {
+ getWriter().println();
+ getWriter().println("<RETURN> to continue");
+ }
+
+ /* Internal methods
+ */
+
+ protected void printHeader(long runTime) {
+ getWriter().println();
+ getWriter().println("Time: "+elapsedTimeAsString(runTime));
+ }
+
+ protected void printErrors(TestResult result) {
+ printDefects(result.errors(), result.errorCount(), "error");
+ }
+
+ protected void printFailures(TestResult result) {
+ printDefects(result.failures(), result.failureCount(), "failure");
+ }
+
+ 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(booBoos.nextElement(), i);
+ }
+ }
+
+ public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes
+ printDefectHeader(booBoo, count);
+ printDefectTrace(booBoo);
+ }
+
+ protected void printDefectHeader(TestFailure booBoo, int count) {
+ // I feel like making this a println, then adding a line giving the throwable a chance to print something
+ // before we get to the stack trace.
+ getWriter().print(count + ") " + booBoo.failedTest());
+ }
+
+ protected void printDefectTrace(TestFailure booBoo) {
+ getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace()));
+ }
+
+ protected void printFooter(TestResult result) {
+ if (result.wasSuccessful()) {
+ getWriter().println();
+ getWriter().print("OK");
+ getWriter().println (" (" + result.runCount() + " test" + (result.runCount() == 1 ? "": "s") + ")");
+
+ } else {
+ getWriter().println();
+ getWriter().println("FAILURES!!!");
+ getWriter().println("Tests run: "+result.runCount()+
+ ", Failures: "+result.failureCount()+
+ ", Errors: "+result.errorCount());
+ }
+ 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);
+ }
+
+ public PrintStream getWriter() {
+ return fWriter;
+ }
+ /**
+ * @see junit.framework.TestListener#addError(Test, Throwable)
+ */
+ public void addError(Test test, Throwable t) {
+ getWriter().print("E");
+ }
+
+ /**
+ * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
+ */
+ public void addFailure(Test test, AssertionFailedError t) {
+ getWriter().print("F");
+ }
+
+ /**
+ * @see junit.framework.TestListener#endTest(Test)
+ */
+ public void endTest(Test test) {
+ }
+
+ /**
+ * @see junit.framework.TestListener#startTest(Test)
+ */
+ public void startTest(Test test) {
+ getWriter().print(".");
+ if (fColumn++ >= 40) {
+ getWriter().println();
+ fColumn= 0;
+ }
+ }
+
+}
diff --git a/junit4/src/main/java/junit/textui/TestRunner.java b/junit4/src/main/java/junit/textui/TestRunner.java
new file mode 100644
index 0000000..046448e
--- /dev/null
+++ b/junit4/src/main/java/junit/textui/TestRunner.java
@@ -0,0 +1,203 @@
+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.Version;
+
+/**
+ * A command line based tool to run tests.
+ * <pre>
+ * java junit.textui.TestRunner [-wait] TestCaseClass
+ * </pre>
+ *
+ * <p>TestRunner expects the name of a TestCase class as argument.
+ * If this class defines a static <code>suite</code> method it
+ * will be invoked and the returned test is run. Otherwise all
+ * the methods starting with "test" having no arguments are run.</p>
+ *
+ * <p> When the wait command line argument is given TestRunner
+ * waits until the users types RETURN.</p>
+ *
+ * <p>TestRunner prints a trace as the tests are executed followed by a
+ * summary at the end.</p>
+ */
+public class TestRunner extends BaseTestRunner {
+ private ResultPrinter fPrinter;
+
+ public static final int SUCCESS_EXIT= 0;
+ public static final int FAILURE_EXIT= 1;
+ public static final int EXCEPTION_EXIT= 2;
+
+ /**
+ * Constructs a TestRunner.
+ */
+ public TestRunner() {
+ this(System.out);
+ }
+
+ /**
+ * Constructs a TestRunner using the given stream for all the output
+ */
+ public TestRunner(PrintStream writer) {
+ this(new ResultPrinter(writer));
+ }
+
+ /**
+ * Constructs a TestRunner using the given ResultPrinter all the output
+ */
+ public TestRunner(ResultPrinter printer) {
+ fPrinter= printer;
+ }
+
+ /**
+ * Runs a suite extracted from a TestCase subclass.
+ */
+ static public void run(Class<? extends TestCase> testClass) {
+ run(new TestSuite(testClass));
+ }
+
+ /**
+ * Runs a single test and collects its results.
+ * This method can be used to start a test run
+ * from your program.
+ * <pre>
+ * public static void main (String[] args) {
+ * test.textui.TestRunner.run(suite());
+ * }
+ * </pre>
+ */
+ static public TestResult run(Test test) {
+ TestRunner runner= new TestRunner();
+ return runner.doRun(test);
+ }
+
+ /**
+ * Runs a single test and waits until the user
+ * types RETURN.
+ */
+ static public void runAndWait(Test suite) {
+ TestRunner aTestRunner= new TestRunner();
+ aTestRunner.doRun(suite, true);
+ }
+
+ @Override
+ public void testFailed(int status, Test test, Throwable t) {
+ }
+
+ @Override
+ public void testStarted(String testName) {
+ }
+
+ @Override
+ public void testEnded(String testName) {
+ }
+
+ /**
+ * Creates the TestResult to be used for the test run.
+ */
+ protected TestResult createTestResult() {
+ return new TestResult();
+ }
+
+ public TestResult doRun(Test test) {
+ return doRun(test, false);
+ }
+
+ public TestResult doRun(Test suite, boolean wait) {
+ TestResult result= createTestResult();
+ result.addListener(fPrinter);
+ long startTime= System.currentTimeMillis();
+ suite.run(result);
+ long endTime= System.currentTimeMillis();
+ long runTime= endTime-startTime;
+ fPrinter.print(result, runTime);
+
+ pause(wait);
+ return result;
+ }
+
+ protected void pause(boolean wait) {
+ if (!wait) return;
+ fPrinter.printWaitPrompt();
+ try {
+ System.in.read();
+ }
+ catch(Exception e) {
+ }
+ }
+
+ public static void main(String args[]) {
+ TestRunner aTestRunner= new TestRunner();
+ try {
+ TestResult r= aTestRunner.start(args);
+ if (!r.wasSuccessful())
+ System.exit(FAILURE_EXIT);
+ System.exit(SUCCESS_EXIT);
+ } catch(Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(EXCEPTION_EXIT);
+ }
+ }
+
+ /**
+ * Starts a test run. Analyzes the command line arguments and runs the given
+ * test suite.
+ */
+ public TestResult start(String args[]) throws Exception {
+ String testCase= "";
+ String method= "";
+ boolean wait= false;
+
+ for (int i= 0; i < args.length; i++) {
+ if (args[i].equals("-wait"))
+ wait= true;
+ else if (args[i].equals("-c"))
+ testCase= extractClassName(args[++i]);
+ else if (args[i].equals("-m")) {
+ String arg= args[++i];
+ int lastIndex= arg.lastIndexOf('.');
+ testCase= arg.substring(0, lastIndex);
+ method= arg.substring(lastIndex + 1);
+ } else if (args[i].equals("-v"))
+ System.err.println("JUnit " + Version.id() + " by Kent Beck and Erich Gamma");
+ else
+ testCase= args[i];
+ }
+
+ if (testCase.equals(""))
+ throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class");
+
+ try {
+ if (!method.equals(""))
+ return runSingleMethod(testCase, method, wait);
+ Test suite= getTest(testCase);
+ return doRun(suite, wait);
+ } catch (Exception e) {
+ throw new Exception("Could not create and run test suite: " + e);
+ }
+ }
+
+ protected TestResult runSingleMethod(String testCase, String method, boolean wait) throws Exception {
+ 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);
+ }
+
+ public void setPrinter(ResultPrinter printer) {
+ fPrinter= printer;
+ }
+
+
+} \ No newline at end of file
diff --git a/junit4/src/main/java/junit/textui/package-info.java b/junit4/src/main/java/junit/textui/package-info.java
new file mode 100644
index 0000000..2aa5176
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/After.java b/junit4/src/main/java/org/junit/After.java
new file mode 100644
index 0000000..39aa6e5
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/AfterClass.java b/junit4/src/main/java/org/junit/AfterClass.java
new file mode 100644
index 0000000..2d6bc80
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/Assert.java b/junit4/src/main/java/org/junit/Assert.java
new file mode 100644
index 0000000..b585b87
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/Assume.java b/junit4/src/main/java/org/junit/Assume.java
new file mode 100644
index 0000000..7b6c21a
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/Before.java b/junit4/src/main/java/org/junit/Before.java
new file mode 100644
index 0000000..66b34ee
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/BeforeClass.java b/junit4/src/main/java/org/junit/BeforeClass.java
new file mode 100644
index 0000000..35b7854
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/ClassRule.java b/junit4/src/main/java/org/junit/ClassRule.java
new file mode 100644
index 0000000..97a111f
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/ComparisonFailure.java b/junit4/src/main/java/org/junit/ComparisonFailure.java
new file mode 100644
index 0000000..d37db4f
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/Ignore.java b/junit4/src/main/java/org/junit/Ignore.java
new file mode 100644
index 0000000..de530a9
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/Rule.java b/junit4/src/main/java/org/junit/Rule.java
new file mode 100644
index 0000000..9e67c07
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/Test.java b/junit4/src/main/java/org/junit/Test.java
new file mode 100644
index 0000000..23dc78a
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/ParallelComputer.java b/junit4/src/main/java/org/junit/experimental/ParallelComputer.java
new file mode 100644
index 0000000..fccb97c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/categories/Categories.java b/junit4/src/main/java/org/junit/experimental/categories/Categories.java
new file mode 100644
index 0000000..d57b4d3
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/categories/Category.java b/junit4/src/main/java/org/junit/experimental/categories/Category.java
new file mode 100644
index 0000000..3a4c0b9
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/max/CouldNotReadCoreException.java b/junit4/src/main/java/org/junit/experimental/max/CouldNotReadCoreException.java
new file mode 100644
index 0000000..03c3c8c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/max/MaxCore.java b/junit4/src/main/java/org/junit/experimental/max/MaxCore.java
new file mode 100644
index 0000000..a2a34a9
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/max/MaxHistory.java b/junit4/src/main/java/org/junit/experimental/max/MaxHistory.java
new file mode 100644
index 0000000..e091793
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/results/FailureList.java b/junit4/src/main/java/org/junit/experimental/results/FailureList.java
new file mode 100644
index 0000000..f4bc9b7
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/results/PrintableResult.java b/junit4/src/main/java/org/junit/experimental/results/PrintableResult.java
new file mode 100644
index 0000000..8bc6f54
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/results/ResultMatchers.java b/junit4/src/main/java/org/junit/experimental/results/ResultMatchers.java
new file mode 100644
index 0000000..220d0dc
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/runners/Enclosed.java b/junit4/src/main/java/org/junit/experimental/runners/Enclosed.java
new file mode 100644
index 0000000..b0560ed
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/DataPoint.java b/junit4/src/main/java/org/junit/experimental/theories/DataPoint.java
new file mode 100644
index 0000000..2aaba6a
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/DataPoints.java b/junit4/src/main/java/org/junit/experimental/theories/DataPoints.java
new file mode 100644
index 0000000..42145e3
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/ParameterSignature.java b/junit4/src/main/java/org/junit/experimental/theories/ParameterSignature.java
new file mode 100644
index 0000000..e7150fc
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/ParameterSupplier.java b/junit4/src/main/java/org/junit/experimental/theories/ParameterSupplier.java
new file mode 100644
index 0000000..9016c91
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java b/junit4/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java
new file mode 100644
index 0000000..8f090ef
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/PotentialAssignment.java b/junit4/src/main/java/org/junit/experimental/theories/PotentialAssignment.java
new file mode 100644
index 0000000..0c008d0
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/Theories.java b/junit4/src/main/java/org/junit/experimental/theories/Theories.java
new file mode 100644
index 0000000..82ff98b
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/Theory.java b/junit4/src/main/java/org/junit/experimental/theories/Theory.java
new file mode 100644
index 0000000..134fe9d
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java b/junit4/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java
new file mode 100644
index 0000000..615cc3e
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/internal/Assignments.java b/junit4/src/main/java/org/junit/experimental/theories/internal/Assignments.java
new file mode 100644
index 0000000..bd94f00
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java b/junit4/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java
new file mode 100644
index 0000000..285bc3a
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java b/junit4/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java
new file mode 100644
index 0000000..d6ede64
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java b/junit4/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java
new file mode 100644
index 0000000..f80298f
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/ArrayComparisonFailure.java b/junit4/src/main/java/org/junit/internal/ArrayComparisonFailure.java
new file mode 100644
index 0000000..08851de
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/AssumptionViolatedException.java b/junit4/src/main/java/org/junit/internal/AssumptionViolatedException.java
new file mode 100644
index 0000000..8e11268
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/ComparisonCriteria.java b/junit4/src/main/java/org/junit/internal/ComparisonCriteria.java
new file mode 100644
index 0000000..e97011d
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/ExactComparisonCriteria.java b/junit4/src/main/java/org/junit/internal/ExactComparisonCriteria.java
new file mode 100644
index 0000000..0a632ff
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/InexactComparisonCriteria.java b/junit4/src/main/java/org/junit/internal/InexactComparisonCriteria.java
new file mode 100644
index 0000000..ef3d7ff
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/JUnitSystem.java b/junit4/src/main/java/org/junit/internal/JUnitSystem.java
new file mode 100644
index 0000000..6d9c242
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/RealSystem.java b/junit4/src/main/java/org/junit/internal/RealSystem.java
new file mode 100644
index 0000000..1067c6d
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/TextListener.java b/junit4/src/main/java/org/junit/internal/TextListener.java
new file mode 100644
index 0000000..2b1c679
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java b/junit4/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java
new file mode 100644
index 0000000..d3bd50a
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java b/junit4/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java
new file mode 100644
index 0000000..8ed9ca7
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/builders/IgnoredBuilder.java b/junit4/src/main/java/org/junit/internal/builders/IgnoredBuilder.java
new file mode 100644
index 0000000..6be342c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java b/junit4/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java
new file mode 100644
index 0000000..b4200a8
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/builders/JUnit3Builder.java b/junit4/src/main/java/org/junit/internal/builders/JUnit3Builder.java
new file mode 100644
index 0000000..ddb070b
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/builders/JUnit4Builder.java b/junit4/src/main/java/org/junit/internal/builders/JUnit4Builder.java
new file mode 100644
index 0000000..4380db7
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/builders/NullBuilder.java b/junit4/src/main/java/org/junit/internal/builders/NullBuilder.java
new file mode 100644
index 0000000..9d43d69
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/builders/SuiteMethodBuilder.java b/junit4/src/main/java/org/junit/internal/builders/SuiteMethodBuilder.java
new file mode 100644
index 0000000..659bf31
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/matchers/CombinableMatcher.java b/junit4/src/main/java/org/junit/internal/matchers/CombinableMatcher.java
new file mode 100644
index 0000000..e9e6947
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/matchers/Each.java b/junit4/src/main/java/org/junit/internal/matchers/Each.java
new file mode 100644
index 0000000..527db3b
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/matchers/IsCollectionContaining.java b/junit4/src/main/java/org/junit/internal/matchers/IsCollectionContaining.java
new file mode 100644
index 0000000..4436a83
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/matchers/StringContains.java b/junit4/src/main/java/org/junit/internal/matchers/StringContains.java
new file mode 100644
index 0000000..e5f5334
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/matchers/SubstringMatcher.java b/junit4/src/main/java/org/junit/internal/matchers/SubstringMatcher.java
new file mode 100644
index 0000000..1c65240
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java b/junit4/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java
new file mode 100644
index 0000000..794a174
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/requests/ClassRequest.java b/junit4/src/main/java/org/junit/internal/requests/ClassRequest.java
new file mode 100644
index 0000000..53bf520
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/requests/FilterRequest.java b/junit4/src/main/java/org/junit/internal/requests/FilterRequest.java
new file mode 100644
index 0000000..e5d98d1
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/requests/SortingRequest.java b/junit4/src/main/java/org/junit/internal/requests/SortingRequest.java
new file mode 100644
index 0000000..3c6f4f5
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/requests/package-info.java b/junit4/src/main/java/org/junit/internal/requests/package-info.java
new file mode 100644
index 0000000..66d2928
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/ClassRoadie.java b/junit4/src/main/java/org/junit/internal/runners/ClassRoadie.java
new file mode 100644
index 0000000..1f77d37
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java b/junit4/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java
new file mode 100644
index 0000000..200b6f0
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/FailedBefore.java b/junit4/src/main/java/org/junit/internal/runners/FailedBefore.java
new file mode 100644
index 0000000..29dcba4
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/InitializationError.java b/junit4/src/main/java/org/junit/internal/runners/InitializationError.java
new file mode 100644
index 0000000..5715ec5
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java b/junit4/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java
new file mode 100644
index 0000000..0028d0c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java b/junit4/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java
new file mode 100644
index 0000000..d732880
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/MethodRoadie.java b/junit4/src/main/java/org/junit/internal/runners/MethodRoadie.java
new file mode 100644
index 0000000..4407821
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/MethodValidator.java b/junit4/src/main/java/org/junit/internal/runners/MethodValidator.java
new file mode 100644
index 0000000..cadc93f
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/SuiteMethod.java b/junit4/src/main/java/org/junit/internal/runners/SuiteMethod.java
new file mode 100644
index 0000000..4e8bebc
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/TestClass.java b/junit4/src/main/java/org/junit/internal/runners/TestClass.java
new file mode 100644
index 0000000..1ca2b9d
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/TestMethod.java b/junit4/src/main/java/org/junit/internal/runners/TestMethod.java
new file mode 100644
index 0000000..a06213c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java b/junit4/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java
new file mode 100644
index 0000000..a7d534c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/model/MultipleFailureException.java b/junit4/src/main/java/org/junit/internal/runners/model/MultipleFailureException.java
new file mode 100644
index 0000000..3316806
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/model/ReflectiveCallable.java b/junit4/src/main/java/org/junit/internal/runners/model/ReflectiveCallable.java
new file mode 100644
index 0000000..9150d90
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/package-info.java b/junit4/src/main/java/org/junit/internal/runners/package-info.java
new file mode 100644
index 0000000..5ab7e7b
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java b/junit4/src/main/java/org/junit/internal/runners/rules/RuleFieldValidator.java
new file mode 100644
index 0000000..e7df8bf
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/statements/ExpectException.java b/junit4/src/main/java/org/junit/internal/runners/statements/ExpectException.java
new file mode 100644
index 0000000..ddfef07
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/statements/Fail.java b/junit4/src/main/java/org/junit/internal/runners/statements/Fail.java
new file mode 100644
index 0000000..e7d0d5c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/junit4/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
new file mode 100644
index 0000000..bff7c72
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java b/junit4/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java
new file mode 100644
index 0000000..e2e81e1
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/statements/RunAfters.java b/junit4/src/main/java/org/junit/internal/runners/statements/RunAfters.java
new file mode 100644
index 0000000..475ec72
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/internal/runners/statements/RunBefores.java b/junit4/src/main/java/org/junit/internal/runners/statements/RunBefores.java
new file mode 100644
index 0000000..66a34e1
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/matchers/JUnitMatchers.java b/junit4/src/main/java/org/junit/matchers/JUnitMatchers.java
new file mode 100644
index 0000000..ec2ec4a
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/matchers/package-info.java b/junit4/src/main/java/org/junit/matchers/package-info.java
new file mode 100644
index 0000000..71aca34
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/package-info.java b/junit4/src/main/java/org/junit/package-info.java
new file mode 100644
index 0000000..bb60d0d
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/ErrorCollector.java b/junit4/src/main/java/org/junit/rules/ErrorCollector.java
new file mode 100644
index 0000000..3522a65
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/ExpectedException.java b/junit4/src/main/java/org/junit/rules/ExpectedException.java
new file mode 100644
index 0000000..bac2fba
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/ExternalResource.java b/junit4/src/main/java/org/junit/rules/ExternalResource.java
new file mode 100644
index 0000000..1fe3719
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/MethodRule.java b/junit4/src/main/java/org/junit/rules/MethodRule.java
new file mode 100644
index 0000000..5167672
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/RuleChain.java b/junit4/src/main/java/org/junit/rules/RuleChain.java
new file mode 100644
index 0000000..8af3c05
--- /dev/null
+++ b/junit4/src/main/java/org/junit/rules/RuleChain.java
@@ -0,0 +1,99 @@
+/**
+ *
+ */
+package org.junit.rules;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * The RuleChain rule allows ordering of TestRules. You create a
+ * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
+ * {@link #around(TestRule)}:
+ *
+ * <pre>
+ * public static class UseRuleChain {
+ * &#064;Rule
+ * public TestRule chain= RuleChain
+ * .outerRule(new LoggingRule("outer rule")
+ * .around(new LoggingRule("middle rule")
+ * .around(new LoggingRule("inner rule");
+ *
+ * &#064;Test
+ * public void example() {
+ * assertTrue(true);
+ * }
+ * }
+ * </pre>
+ *
+ * writes the log
+ *
+ * <pre>
+ * starting outer rule
+ * starting middle rule
+ * starting inner rule
+ * finished inner rule
+ * finished middle rule
+ * finished outer rule
+ * </pre>
+ */
+public class RuleChain implements TestRule {
+ private static final RuleChain EMPTY_CHAIN= new RuleChain(
+ Collections.<TestRule> emptyList());
+
+ private List<TestRule> rulesStartingWithInnerMost;
+
+ /**
+ * Returns a {@code RuleChain} without a {@link TestRule}. This method may
+ * be the starting point of a {@code RuleChain}.
+ *
+ * @return a {@code RuleChain} without a {@link TestRule}.
+ */
+ public static RuleChain emptyRuleChain() {
+ return EMPTY_CHAIN;
+ }
+
+ /**
+ * Returns a {@code RuleChain} with a single {@link TestRule}. This method
+ * is the usual starting point of a {@code RuleChain}.
+ *
+ * @param outerRule
+ * the outer rule of the {@code RuleChain}.
+ * @return a {@code RuleChain} with a single {@link TestRule}.
+ */
+ public static RuleChain outerRule(TestRule outerRule) {
+ return emptyRuleChain().around(outerRule);
+ }
+
+ private RuleChain(List<TestRule> rules) {
+ this.rulesStartingWithInnerMost= rules;
+ }
+
+ /**
+ * Create a new {@code RuleChain}, which encloses the {@code nextRule} with
+ * the rules of the current {@code RuleChain}.
+ *
+ * @param enclosedRule
+ * the rule to enclose.
+ * @return a new {@code RuleChain}.
+ */
+ public RuleChain around(TestRule enclosedRule) {
+ List<TestRule> rulesOfNewChain= new ArrayList<TestRule>();
+ rulesOfNewChain.add(enclosedRule);
+ rulesOfNewChain.addAll(rulesStartingWithInnerMost);
+ return new RuleChain(rulesOfNewChain);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Statement apply(Statement base, Description description) {
+ for (TestRule each : rulesStartingWithInnerMost)
+ base= each.apply(base, description);
+ return base;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/main/java/org/junit/rules/RunRules.java b/junit4/src/main/java/org/junit/rules/RunRules.java
new file mode 100644
index 0000000..d5905b9
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/TemporaryFolder.java b/junit4/src/main/java/org/junit/rules/TemporaryFolder.java
new file mode 100644
index 0000000..a7c82aa
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/TestName.java b/junit4/src/main/java/org/junit/rules/TestName.java
new file mode 100644
index 0000000..c4ab9ce
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/TestRule.java b/junit4/src/main/java/org/junit/rules/TestRule.java
new file mode 100644
index 0000000..b7760c4
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/TestWatcher.java b/junit4/src/main/java/org/junit/rules/TestWatcher.java
new file mode 100644
index 0000000..351b449
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/TestWatchman.java b/junit4/src/main/java/org/junit/rules/TestWatchman.java
new file mode 100644
index 0000000..15daa64
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/Timeout.java b/junit4/src/main/java/org/junit/rules/Timeout.java
new file mode 100644
index 0000000..85ce6d6
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/rules/Verifier.java b/junit4/src/main/java/org/junit/rules/Verifier.java
new file mode 100644
index 0000000..be1a55e
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/Computer.java b/junit4/src/main/java/org/junit/runner/Computer.java
new file mode 100644
index 0000000..939f702
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/Describable.java b/junit4/src/main/java/org/junit/runner/Describable.java
new file mode 100644
index 0000000..e59cc01
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/Description.java b/junit4/src/main/java/org/junit/runner/Description.java
new file mode 100644
index 0000000..b3083d5
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/JUnitCore.java b/junit4/src/main/java/org/junit/runner/JUnitCore.java
new file mode 100644
index 0000000..2fcd3b3
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/Request.java b/junit4/src/main/java/org/junit/runner/Request.java
new file mode 100644
index 0000000..310b915
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/Result.java b/junit4/src/main/java/org/junit/runner/Result.java
new file mode 100644
index 0000000..edfb97c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/RunWith.java b/junit4/src/main/java/org/junit/runner/RunWith.java
new file mode 100644
index 0000000..602edf0
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/Runner.java b/junit4/src/main/java/org/junit/runner/Runner.java
new file mode 100644
index 0000000..39e424f
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/manipulation/Filter.java b/junit4/src/main/java/org/junit/runner/manipulation/Filter.java
new file mode 100644
index 0000000..c0f31b0
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/manipulation/Filterable.java b/junit4/src/main/java/org/junit/runner/manipulation/Filterable.java
new file mode 100644
index 0000000..782c0f7
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/manipulation/NoTestsRemainException.java b/junit4/src/main/java/org/junit/runner/manipulation/NoTestsRemainException.java
new file mode 100644
index 0000000..03fb3bf
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/manipulation/Sortable.java b/junit4/src/main/java/org/junit/runner/manipulation/Sortable.java
new file mode 100644
index 0000000..fec1d0c
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/manipulation/Sorter.java b/junit4/src/main/java/org/junit/runner/manipulation/Sorter.java
new file mode 100644
index 0000000..242df14
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/manipulation/package-info.java b/junit4/src/main/java/org/junit/runner/manipulation/package-info.java
new file mode 100644
index 0000000..ba5c3b2
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/notification/Failure.java b/junit4/src/main/java/org/junit/runner/notification/Failure.java
new file mode 100644
index 0000000..501caa5
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/notification/RunListener.java b/junit4/src/main/java/org/junit/runner/notification/RunListener.java
new file mode 100644
index 0000000..ffe8134
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/notification/RunNotifier.java b/junit4/src/main/java/org/junit/runner/notification/RunNotifier.java
new file mode 100644
index 0000000..d0f6c85
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/notification/StoppedByUserException.java b/junit4/src/main/java/org/junit/runner/notification/StoppedByUserException.java
new file mode 100644
index 0000000..89be3ba
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/notification/package-info.java b/junit4/src/main/java/org/junit/runner/notification/package-info.java
new file mode 100644
index 0000000..0331c8f
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runner/package-info.java b/junit4/src/main/java/org/junit/runner/package-info.java
new file mode 100644
index 0000000..e19fa0b
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/AllTests.java b/junit4/src/main/java/org/junit/runners/AllTests.java
new file mode 100644
index 0000000..50c02db
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java b/junit4/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
new file mode 100644
index 0000000..92e0d07
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/JUnit4.java b/junit4/src/main/java/org/junit/runners/JUnit4.java
new file mode 100644
index 0000000..1e1f347
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/Parameterized.java b/junit4/src/main/java/org/junit/runners/Parameterized.java
new file mode 100644
index 0000000..3ebfead
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/ParentRunner.java b/junit4/src/main/java/org/junit/runners/ParentRunner.java
new file mode 100644
index 0000000..a41aad3
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/Suite.java b/junit4/src/main/java/org/junit/runners/Suite.java
new file mode 100644
index 0000000..1b3bb48
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/FrameworkField.java b/junit4/src/main/java/org/junit/runners/model/FrameworkField.java
new file mode 100644
index 0000000..4a4d4a4
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/FrameworkMember.java b/junit4/src/main/java/org/junit/runners/model/FrameworkMember.java
new file mode 100644
index 0000000..9cccd4b
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/FrameworkMethod.java b/junit4/src/main/java/org/junit/runners/model/FrameworkMethod.java
new file mode 100644
index 0000000..81c8963
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/InitializationError.java b/junit4/src/main/java/org/junit/runners/model/InitializationError.java
new file mode 100644
index 0000000..4de9ea7
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/MultipleFailureException.java b/junit4/src/main/java/org/junit/runners/model/MultipleFailureException.java
new file mode 100644
index 0000000..6d70ca0
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java b/junit4/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
new file mode 100644
index 0000000..77662b8
--- /dev/null
+++ b/junit4/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
@@ -0,0 +1,53 @@
+package org.junit.runners.model;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+
+class NoGenericTypeParametersValidator {
+ private final Method fMethod;
+
+ NoGenericTypeParametersValidator(Method method) {
+ this.fMethod = method;
+ }
+
+ void validate(List<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/junit4/src/main/java/org/junit/runners/model/RunnerBuilder.java b/junit4/src/main/java/org/junit/runners/model/RunnerBuilder.java
new file mode 100644
index 0000000..3a334be
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/RunnerScheduler.java b/junit4/src/main/java/org/junit/runners/model/RunnerScheduler.java
new file mode 100644
index 0000000..fbc25a4
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/Statement.java b/junit4/src/main/java/org/junit/runners/model/Statement.java
new file mode 100644
index 0000000..a7c5478
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/model/TestClass.java b/junit4/src/main/java/org/junit/runners/model/TestClass.java
new file mode 100644
index 0000000..362a13a
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/main/java/org/junit/runners/package-info.java b/junit4/src/main/java/org/junit/runners/package-info.java
new file mode 100644
index 0000000..418acaf
--- /dev/null
+++ b/junit4/src/main/java/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/junit4/src/test/java/junit/samples/AllTests.java b/junit4/src/test/java/junit/samples/AllTests.java
new file mode 100644
index 0000000..2fb7628
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/AllTests.java
@@ -0,0 +1,22 @@
+package junit.samples;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * TestSuite that runs all the sample tests
+ *
+ */
+public class AllTests {
+
+ public static void main (String[] args) {
+ junit.textui.TestRunner.run (suite());
+ }
+ public static Test suite ( ) {
+ TestSuite suite= new TestSuite("All JUnit Tests");
+ suite.addTest(ListTest.suite());
+ suite.addTest(new TestSuite(junit.samples.money.MoneyTest.class));
+ suite.addTest(junit.tests.AllTests.suite());
+ return suite;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/samples/ListTest.java b/junit4/src/test/java/junit/samples/ListTest.java
new file mode 100644
index 0000000..eac850d
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/ListTest.java
@@ -0,0 +1,63 @@
+package junit.samples;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * A sample test case, testing {@link java.util.Vector}.
+ *
+ */
+public class ListTest extends TestCase {
+ protected List<Integer> fEmpty;
+ protected List<Integer> fFull;
+
+ public static void main (String[] args) {
+ junit.textui.TestRunner.run (suite());
+ }
+ @Override
+ protected void setUp() {
+ fEmpty= new ArrayList<Integer>();
+ fFull= new ArrayList<Integer>();
+ fFull.add(1);
+ fFull.add(2);
+ fFull.add(3);
+ }
+ public static Test suite() {
+ return new TestSuite(ListTest.class);
+ }
+ public void testCapacity() {
+ int size= fFull.size();
+ for (int i= 0; i < 100; i++)
+ fFull.add(new Integer(i));
+ assertTrue(fFull.size() == 100+size);
+ }
+ public void testContains() {
+ assertTrue(fFull.contains(1));
+ assertTrue(!fEmpty.contains(1));
+ }
+ public void testElementAt() {
+ int i= fFull.get(0);
+ assertTrue(i == 1);
+
+ try {
+ fFull.get(fFull.size());
+ } catch (IndexOutOfBoundsException e) {
+ return;
+ }
+ fail("Should raise an ArrayIndexOutOfBoundsException");
+ }
+ public void testRemoveAll() {
+ fFull.removeAll(fFull);
+ fEmpty.removeAll(fEmpty);
+ assertTrue(fFull.isEmpty());
+ assertTrue(fEmpty.isEmpty());
+ }
+ public void testRemoveElement() {
+ fFull.remove(new Integer(3));
+ assertTrue(!fFull.contains(3) );
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/samples/SimpleTest.java b/junit4/src/test/java/junit/samples/SimpleTest.java
new file mode 100644
index 0000000..f745021
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/SimpleTest.java
@@ -0,0 +1,68 @@
+package junit.samples;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Some simple tests.
+ *
+ */
+public class SimpleTest extends TestCase {
+ protected int fValue1;
+ protected int fValue2;
+
+ @Override
+ protected void setUp() {
+ fValue1= 2;
+ fValue2= 3;
+ }
+ public static Test suite() {
+
+ /*
+ * the type safe way
+ *
+ TestSuite suite= new TestSuite();
+ suite.addTest(
+ new SimpleTest("add") {
+ protected void runTest() { testAdd(); }
+ }
+ );
+
+ suite.addTest(
+ new SimpleTest("testDivideByZero") {
+ protected void runTest() { testDivideByZero(); }
+ }
+ );
+ return suite;
+ */
+
+ /*
+ * the dynamic way
+ */
+ return new TestSuite(SimpleTest.class);
+ }
+ public void testAdd() {
+ double result= fValue1 + fValue2;
+ // forced failure result == 5
+ assertTrue(result == 6);
+ }
+
+ public int unused;
+ public void testDivideByZero() {
+ int zero= 0;
+ int result= 8/zero;
+ unused= result; // avoid warning for not using result
+ }
+ public void testEquals() {
+ assertEquals(12, 12);
+ assertEquals(12L, 12L);
+ assertEquals(new Long(12), new Long(12));
+
+ assertEquals("Size", 12, 13);
+ assertEquals("Capacity", 12.0, 11.99, 0.0);
+ }
+ public static void main (String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/samples/money/IMoney.java b/junit4/src/test/java/junit/samples/money/IMoney.java
new file mode 100644
index 0000000..b8f9496
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/money/IMoney.java
@@ -0,0 +1,45 @@
+package junit.samples.money;
+
+/**
+ * The common interface for simple Monies and MoneyBags
+ *
+ */
+public interface IMoney {
+ /**
+ * Adds a money to this money.
+ */
+ public abstract IMoney add(IMoney m);
+ /**
+ * Adds a simple Money to this money. This is a helper method for
+ * implementing double dispatch
+ */
+ public abstract IMoney addMoney(Money m);
+ /**
+ * Adds a MoneyBag to this money. This is a helper method for
+ * implementing double dispatch
+ */
+ public abstract IMoney addMoneyBag(MoneyBag s);
+ /**
+ * Tests whether this money is zero
+ */
+ public abstract boolean isZero();
+ /**
+ * Multiplies a money by the given factor.
+ */
+ public abstract IMoney multiply(int factor);
+ /**
+ * Negates this money.
+ */
+ public abstract IMoney negate();
+ /**
+ * Subtracts a money from this money.
+ */
+ public abstract IMoney subtract(IMoney m);
+ /**
+ * Append this to a MoneyBag m.
+ * appendTo() needs to be public because it is used
+ * polymorphically, but it should not be used by clients
+ * because it modifies the argument m.
+ */
+ public abstract void appendTo(MoneyBag m);
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/samples/money/Money.java b/junit4/src/test/java/junit/samples/money/Money.java
new file mode 100644
index 0000000..3d8c2fd
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/money/Money.java
@@ -0,0 +1,78 @@
+package junit.samples.money;
+
+/**
+ * A simple Money.
+ *
+ */
+public class Money implements IMoney {
+
+ private int fAmount;
+ private String fCurrency;
+
+ /**
+ * Constructs a money from the given amount and currency.
+ */
+ public Money(int amount, String currency) {
+ fAmount= amount;
+ fCurrency= currency;
+ }
+ /**
+ * Adds a money to this money. Forwards the request to the addMoney helper.
+ */
+ public IMoney add(IMoney m) {
+ return m.addMoney(this);
+ }
+ public IMoney addMoney(Money m) {
+ if (m.currency().equals(currency()) )
+ return new Money(amount()+m.amount(), currency());
+ return MoneyBag.create(this, m);
+ }
+ public IMoney addMoneyBag(MoneyBag s) {
+ return s.addMoney(this);
+ }
+ public int amount() {
+ return fAmount;
+ }
+ public String currency() {
+ return fCurrency;
+ }
+ @Override
+ public boolean equals(Object anObject) {
+ if (isZero())
+ if (anObject instanceof IMoney)
+ return ((IMoney)anObject).isZero();
+ if (anObject instanceof Money) {
+ Money aMoney= (Money)anObject;
+ return aMoney.currency().equals(currency())
+ && amount() == aMoney.amount();
+ }
+ return false;
+ }
+ @Override
+ public int hashCode() {
+ if (fAmount == 0)
+ return 0;
+ return fCurrency.hashCode()+fAmount;
+ }
+ public boolean isZero() {
+ return amount() == 0;
+ }
+ public IMoney multiply(int factor) {
+ return new Money(amount()*factor, currency());
+ }
+ public IMoney negate() {
+ return new Money(-amount(), currency());
+ }
+ public IMoney subtract(IMoney m) {
+ return add(m.negate());
+ }
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("["+amount()+" "+currency()+"]");
+ return buffer.toString();
+ }
+ public /*this makes no sense*/ void appendTo(MoneyBag m) {
+ m.appendMoney(this);
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/samples/money/MoneyBag.java b/junit4/src/test/java/junit/samples/money/MoneyBag.java
new file mode 100644
index 0000000..edc73b5
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/money/MoneyBag.java
@@ -0,0 +1,124 @@
+package junit.samples.money;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A MoneyBag defers exchange rate conversions. For example adding
+ * 12 Swiss Francs to 14 US Dollars is represented as a bag
+ * containing the two Monies 12 CHF and 14 USD. Adding another
+ * 10 Swiss francs gives a bag with 22 CHF and 14 USD. Due to
+ * the deferred exchange rate conversion we can later value a
+ * MoneyBag with different exchange rates.
+ *
+ * A MoneyBag is represented as a list of Monies and provides
+ * different constructors to create a MoneyBag.
+ */
+public class MoneyBag implements IMoney {
+ private List<Money> fMonies= new ArrayList<Money>(5);
+
+ public static IMoney create(IMoney m1, IMoney m2) {
+ MoneyBag result= new MoneyBag();
+ m1.appendTo(result);
+ m2.appendTo(result);
+ return result.simplify();
+ }
+ public IMoney add(IMoney m) {
+ return m.addMoneyBag(this);
+ }
+ public IMoney addMoney(Money m) {
+ return MoneyBag.create(m, this);
+ }
+ public IMoney addMoneyBag(MoneyBag s) {
+ return MoneyBag.create(s, this);
+ }
+ void appendBag(MoneyBag aBag) {
+ for (Money each : aBag.fMonies)
+ appendMoney(each);
+ }
+ void appendMoney(Money aMoney) {
+ if (aMoney.isZero()) return;
+ IMoney old= findMoney(aMoney.currency());
+ if (old == null) {
+ fMonies.add(aMoney);
+ return;
+ }
+ fMonies.remove(old);
+ Money sum= (Money) old.add(aMoney);
+ if (sum.isZero())
+ return;
+ fMonies.add(sum);
+ }
+ @Override
+ public boolean equals(Object anObject) {
+ if (isZero())
+ if (anObject instanceof IMoney)
+ return ((IMoney)anObject).isZero();
+
+ if (anObject instanceof MoneyBag) {
+ MoneyBag aMoneyBag= (MoneyBag)anObject;
+ if (aMoneyBag.fMonies.size() != fMonies.size())
+ return false;
+
+ for (Money each : fMonies)
+ if (! aMoneyBag.contains(each))
+ return false;
+ return true;
+ }
+ return false;
+ }
+ private Money findMoney(String currency) {
+ for (Money each : fMonies)
+ if (each.currency().equals(currency))
+ return each;
+ return null;
+ }
+ private boolean contains(Money m) {
+ Money found= findMoney(m.currency());
+ if (found == null) return false;
+ return found.amount() == m.amount();
+ }
+ @Override
+ public int hashCode() {
+ int hash= 0;
+ for (Money each : fMonies)
+ hash^= each.hashCode();
+ return hash;
+ }
+ public boolean isZero() {
+ return fMonies.size() == 0;
+ }
+ public IMoney multiply(int factor) {
+ MoneyBag result= new MoneyBag();
+ if (factor != 0)
+ for (Money each : fMonies)
+ result.appendMoney((Money) each.multiply(factor));
+ return result;
+ }
+ public IMoney negate() {
+ MoneyBag result= new MoneyBag();
+ for (Money each : fMonies)
+ result.appendMoney((Money) each.negate());
+ return result;
+ }
+ private IMoney simplify() {
+ if (fMonies.size() == 1)
+ return fMonies.iterator().next();
+ return this;
+ }
+ public IMoney subtract(IMoney m) {
+ return add(m.negate());
+ }
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("{");
+ for (Money each : fMonies)
+ buffer.append(each);
+ buffer.append("}");
+ return buffer.toString();
+ }
+ public void appendTo(MoneyBag m) {
+ m.appendBag(this);
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/samples/money/MoneyTest.java b/junit4/src/test/java/junit/samples/money/MoneyTest.java
new file mode 100644
index 0000000..043798d
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/money/MoneyTest.java
@@ -0,0 +1,143 @@
+package junit.samples.money;
+
+import junit.framework.TestCase;
+
+public class MoneyTest extends TestCase {
+ private Money f12CHF;
+ private Money f14CHF;
+ private Money f7USD;
+ private Money f21USD;
+
+ private IMoney fMB1;
+ private IMoney fMB2;
+
+ public static void main(String args[]) {
+ junit.textui.TestRunner.run(MoneyTest.class);
+ }
+ @Override
+ protected void setUp() {
+ f12CHF= new Money(12, "CHF");
+ f14CHF= new Money(14, "CHF");
+ f7USD= new Money( 7, "USD");
+ f21USD= new Money(21, "USD");
+
+ fMB1= MoneyBag.create(f12CHF, f7USD);
+ fMB2= MoneyBag.create(f14CHF, f21USD);
+ }
+ public void testBagMultiply() {
+ // {[12 CHF][7 USD]} *2 == {[24 CHF][14 USD]}
+ IMoney expected= MoneyBag.create(new Money(24, "CHF"), new Money(14, "USD"));
+ assertEquals(expected, fMB1.multiply(2));
+ assertEquals(fMB1, fMB1.multiply(1));
+ assertTrue(fMB1.multiply(0).isZero());
+ }
+ public void testBagNegate() {
+ // {[12 CHF][7 USD]} negate == {[-12 CHF][-7 USD]}
+ IMoney expected= MoneyBag.create(new Money(-12, "CHF"), new Money(-7, "USD"));
+ assertEquals(expected, fMB1.negate());
+ }
+ public void testBagSimpleAdd() {
+ // {[12 CHF][7 USD]} + [14 CHF] == {[26 CHF][7 USD]}
+ IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(7, "USD"));
+ assertEquals(expected, fMB1.add(f14CHF));
+ }
+ public void testBagSubtract() {
+ // {[12 CHF][7 USD]} - {[14 CHF][21 USD] == {[-2 CHF][-14 USD]}
+ IMoney expected= MoneyBag.create(new Money(-2, "CHF"), new Money(-14, "USD"));
+ assertEquals(expected, fMB1.subtract(fMB2));
+ }
+ public void testBagSumAdd() {
+ // {[12 CHF][7 USD]} + {[14 CHF][21 USD]} == {[26 CHF][28 USD]}
+ IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(28, "USD"));
+ assertEquals(expected, fMB1.add(fMB2));
+ }
+ public void testIsZero() {
+ assertTrue(fMB1.subtract(fMB1).isZero());
+ assertTrue(MoneyBag.create(new Money (0, "CHF"), new Money (0, "USD")).isZero());
+ }
+ public void testMixedSimpleAdd() {
+ // [12 CHF] + [7 USD] == {[12 CHF][7 USD]}
+ IMoney expected= MoneyBag.create(f12CHF, f7USD);
+ assertEquals(expected, f12CHF.add(f7USD));
+ }
+ public void testBagNotEquals() {
+ IMoney bag= MoneyBag.create(f12CHF, f7USD);
+ assertFalse(bag.equals(new Money(12, "DEM").add(f7USD)));
+ }
+ public void testMoneyBagEquals() {
+ assertTrue(!fMB1.equals(null));
+
+ assertEquals(fMB1, fMB1);
+ IMoney equal= MoneyBag.create(new Money(12, "CHF"), new Money(7, "USD"));
+ assertTrue(fMB1.equals(equal));
+ assertTrue(!fMB1.equals(f12CHF));
+ assertTrue(!f12CHF.equals(fMB1));
+ assertTrue(!fMB1.equals(fMB2));
+ }
+ public void testMoneyBagHash() {
+ IMoney equal= MoneyBag.create(new Money(12, "CHF"), new Money(7, "USD"));
+ assertEquals(fMB1.hashCode(), equal.hashCode());
+ }
+ public void testMoneyEquals() {
+ assertTrue(!f12CHF.equals(null));
+ Money equalMoney= new Money(12, "CHF");
+ assertEquals(f12CHF, f12CHF);
+ assertEquals(f12CHF, equalMoney);
+ assertEquals(f12CHF.hashCode(), equalMoney.hashCode());
+ assertTrue(!f12CHF.equals(f14CHF));
+ }
+ public void testMoneyHash() {
+ assertTrue(!f12CHF.equals(null));
+ Money equal= new Money(12, "CHF");
+ assertEquals(f12CHF.hashCode(), equal.hashCode());
+ }
+ public void testSimplify() {
+ IMoney money= MoneyBag.create(new Money(26, "CHF"), new Money(28, "CHF"));
+ assertEquals(new Money(54, "CHF"), money);
+ }
+ public void testNormalize2() {
+ // {[12 CHF][7 USD]} - [12 CHF] == [7 USD]
+ Money expected= new Money(7, "USD");
+ assertEquals(expected, fMB1.subtract(f12CHF));
+ }
+ public void testNormalize3() {
+ // {[12 CHF][7 USD]} - {[12 CHF][3 USD]} == [4 USD]
+ IMoney ms1= MoneyBag.create(new Money(12, "CHF"), new Money(3, "USD"));
+ Money expected= new Money(4, "USD");
+ assertEquals(expected, fMB1.subtract(ms1));
+ }
+ public void testNormalize4() {
+ // [12 CHF] - {[12 CHF][3 USD]} == [-3 USD]
+ IMoney ms1= MoneyBag.create(new Money(12, "CHF"), new Money(3, "USD"));
+ Money expected= new Money(-3, "USD");
+ assertEquals(expected, f12CHF.subtract(ms1));
+ }
+ public void testPrint() {
+ assertEquals("[12 CHF]", f12CHF.toString());
+ }
+ public void testSimpleAdd() {
+ // [12 CHF] + [14 CHF] == [26 CHF]
+ Money expected= new Money(26, "CHF");
+ assertEquals(expected, f12CHF.add(f14CHF));
+ }
+ public void testSimpleBagAdd() {
+ // [14 CHF] + {[12 CHF][7 USD]} == {[26 CHF][7 USD]}
+ IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(7, "USD"));
+ assertEquals(expected, f14CHF.add(fMB1));
+ }
+ public void testSimpleMultiply() {
+ // [14 CHF] *2 == [28 CHF]
+ Money expected= new Money(28, "CHF");
+ assertEquals(expected, f14CHF.multiply(2));
+ }
+ public void testSimpleNegate() {
+ // [14 CHF] negate == [-14 CHF]
+ Money expected= new Money(-14, "CHF");
+ assertEquals(expected, f14CHF.negate());
+ }
+ public void testSimpleSubtract() {
+ // [14 CHF] - [12 CHF] == [2 CHF]
+ Money expected= new Money(2, "CHF");
+ assertEquals(expected, f14CHF.subtract(f12CHF));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/samples/money/package-info.java b/junit4/src/test/java/junit/samples/money/package-info.java
new file mode 100644
index 0000000..eb37dd8
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/money/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Example "Money" for JUnit v3.x.
+ */
+package junit.samples.money; \ No newline at end of file
diff --git a/junit4/src/test/java/junit/samples/package-info.java b/junit4/src/test/java/junit/samples/package-info.java
new file mode 100644
index 0000000..7b9ea8f
--- /dev/null
+++ b/junit4/src/test/java/junit/samples/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * JUnit v3.x examples.
+ */
+package junit.samples; \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/AllTests.java b/junit4/src/test/java/junit/tests/AllTests.java
new file mode 100644
index 0000000..00bbe56
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/AllTests.java
@@ -0,0 +1,23 @@
+package junit.tests;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * TestSuite that runs all the JUnit tests
+ *
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite= new TestSuite("Framework Tests");
+ suite.addTest(junit.tests.framework.AllTests.suite());
+ suite.addTest(junit.tests.runner.AllTests.suite());
+ suite.addTest(junit.tests.extensions.AllTests.suite());
+ return suite;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/WasRun.java b/junit4/src/test/java/junit/tests/WasRun.java
new file mode 100644
index 0000000..98b83bb
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/WasRun.java
@@ -0,0 +1,15 @@
+package junit.tests;
+
+import junit.framework.TestCase;
+
+/**
+ * A helper test case for testing whether the testing method
+ * is run.
+ */
+public class WasRun extends TestCase {
+ public boolean fWasRun= false;
+ @Override
+ protected void runTest() {
+ fWasRun= true;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/extensions/ActiveTestTest.java b/junit4/src/test/java/junit/tests/extensions/ActiveTestTest.java
new file mode 100644
index 0000000..48987dd
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/extensions/ActiveTestTest.java
@@ -0,0 +1,64 @@
+package junit.tests.extensions;
+
+import junit.extensions.ActiveTestSuite;
+import junit.extensions.RepeatedTest;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+/**
+ * Testing the ActiveTest support
+ */
+
+public class ActiveTestTest extends TestCase {
+
+ public static class SuccessTest extends TestCase {
+ @Override
+ public void runTest() {
+ }
+ }
+
+ public void testActiveTest() {
+ Test test= createActiveTestSuite();
+ TestResult result= new TestResult();
+ test.run(result);
+ assertEquals(100, result.runCount());
+ assertEquals(0, result.failureCount());
+ assertEquals(0, result.errorCount());
+ }
+
+ public void testActiveRepeatedTest() {
+ Test test= new RepeatedTest(createActiveTestSuite(), 5);
+ TestResult result= new TestResult();
+ test.run(result);
+ assertEquals(500, result.runCount());
+ assertEquals(0, result.failureCount());
+ assertEquals(0, result.errorCount());
+ }
+
+ public void testActiveRepeatedTest0() {
+ Test test= new RepeatedTest(createActiveTestSuite(), 0);
+ TestResult result= new TestResult();
+ test.run(result);
+ assertEquals(0, result.runCount());
+ assertEquals(0, result.failureCount());
+ assertEquals(0, result.errorCount());
+ }
+
+ public void testActiveRepeatedTest1() {
+ Test test= new RepeatedTest(createActiveTestSuite(), 1);
+ TestResult result= new TestResult();
+ test.run(result);
+ assertEquals(100, result.runCount());
+ assertEquals(0, result.failureCount());
+ assertEquals(0, result.errorCount());
+ }
+
+ ActiveTestSuite createActiveTestSuite() {
+ ActiveTestSuite suite= new ActiveTestSuite();
+ for (int i= 0; i < 100; i++)
+ suite.addTest(new SuccessTest());
+ return suite;
+ }
+
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/extensions/AllTests.java b/junit4/src/test/java/junit/tests/extensions/AllTests.java
new file mode 100644
index 0000000..92de10b
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/extensions/AllTests.java
@@ -0,0 +1,23 @@
+package junit.tests.extensions;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * TestSuite that runs all the extension tests
+ *
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() { // Collect tests manually because we have to test class collection code
+ TestSuite suite= new TestSuite("Framework Tests");
+ suite.addTestSuite(ExtensionTest.class);
+ suite.addTestSuite(ActiveTestTest.class);
+ suite.addTestSuite(RepeatedTestTest.class);
+ return suite;
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/extensions/ExtensionTest.java b/junit4/src/test/java/junit/tests/extensions/ExtensionTest.java
new file mode 100644
index 0000000..d8a5c09
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/extensions/ExtensionTest.java
@@ -0,0 +1,98 @@
+package junit.tests.extensions;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.tests.WasRun;
+
+/**
+ * A test case testing the extensions to the testing framework.
+ *
+ */
+public class ExtensionTest extends TestCase {
+ static class TornDown extends TestSetup {
+ boolean fTornDown= false;
+
+ TornDown(Test test) {
+ super(test);
+ }
+ @Override
+ protected void tearDown() {
+ fTornDown= true;
+ }
+ }
+ public void testRunningErrorInTestSetup() {
+ TestCase test= new TestCase("failure") {
+ @Override
+ public void runTest() {
+ fail();
+ }
+ };
+
+ TestSetup wrapper= new TestSetup(test);
+
+ TestResult result= new TestResult();
+ wrapper.run(result);
+ assertTrue(!result.wasSuccessful());
+ }
+ public void testRunningErrorsInTestSetup() {
+ TestCase failure= new TestCase("failure") {
+ @Override
+ public void runTest() {
+ fail();
+ }
+ };
+
+ TestCase error= new TestCase("error") {
+ @Override
+ public void runTest() {
+ throw new Error();
+ }
+ };
+
+ TestSuite suite= new TestSuite();
+ suite.addTest(failure);
+ suite.addTest(error);
+
+ TestSetup wrapper= new TestSetup(suite);
+
+ TestResult result= new TestResult();
+ wrapper.run(result);
+
+ assertEquals(1, result.failureCount());
+ assertEquals(1, result.errorCount());
+ }
+ public void testSetupErrorDontTearDown() {
+ WasRun test= new WasRun();
+
+ TornDown wrapper= new TornDown(test) {
+ @Override
+ public void setUp() {
+ fail();
+ }
+ };
+
+ TestResult result= new TestResult();
+ wrapper.run(result);
+
+ assertTrue(!wrapper.fTornDown);
+ }
+ public void testSetupErrorInTestSetup() {
+ WasRun test= new WasRun();
+
+ TestSetup wrapper= new TestSetup(test) {
+ @Override
+ public void setUp() {
+ fail();
+ }
+ };
+
+ TestResult result= new TestResult();
+ wrapper.run(result);
+
+ assertTrue(!test.fWasRun);
+ assertTrue(!result.wasSuccessful());
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/extensions/RepeatedTestTest.java b/junit4/src/test/java/junit/tests/extensions/RepeatedTestTest.java
new file mode 100644
index 0000000..9e53bfa
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/extensions/RepeatedTestTest.java
@@ -0,0 +1,63 @@
+package junit.tests.extensions;
+
+import junit.extensions.RepeatedTest;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+/**
+ * Testing the RepeatedTest support.
+ */
+
+public class RepeatedTestTest extends TestCase {
+ private TestSuite fSuite;
+
+ public static class SuccessTest extends TestCase {
+
+ @Override
+ public void runTest() {
+ }
+ }
+
+ public RepeatedTestTest(String name) {
+ super(name);
+ fSuite= new TestSuite();
+ fSuite.addTest(new SuccessTest());
+ fSuite.addTest(new SuccessTest());
+ }
+
+ public void testRepeatedOnce() {
+ Test test= new RepeatedTest(fSuite, 1);
+ assertEquals(2, test.countTestCases());
+ TestResult result= new TestResult();
+ test.run(result);
+ assertEquals(2, result.runCount());
+ }
+
+ public void testRepeatedMoreThanOnce() {
+ Test test= new RepeatedTest(fSuite, 3);
+ assertEquals(6, test.countTestCases());
+ TestResult result= new TestResult();
+ test.run(result);
+ assertEquals(6, result.runCount());
+ }
+
+ public void testRepeatedZero() {
+ Test test= new RepeatedTest(fSuite, 0);
+ assertEquals(0, test.countTestCases());
+ TestResult result= new TestResult();
+ test.run(result);
+ assertEquals(0, result.runCount());
+ }
+
+ public void testRepeatedNegative() {
+ try {
+ new RepeatedTest(fSuite, -1);
+ } catch (IllegalArgumentException e) {
+ assertTrue(e.getMessage().contains(">="));
+ return;
+ }
+ fail("Should throw an IllegalArgumentException");
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/extensions/package-info.java b/junit4/src/test/java/junit/tests/extensions/package-info.java
new file mode 100644
index 0000000..acc0194
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/extensions/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Tests for the JUnit v3.x extension functionality.
+ */
+package junit.tests.extensions; \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/AllTests.java b/junit4/src/test/java/junit/tests/framework/AllTests.java
new file mode 100644
index 0000000..6ec9891
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/AllTests.java
@@ -0,0 +1,32 @@
+package junit.tests.framework;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * TestSuite that runs all the sample tests
+ *
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite= new TestSuite("Framework Tests");
+ suite.addTestSuite(TestCaseTest.class);
+ suite.addTest(SuiteTest.suite()); // Tests suite building, so can't use automatic test extraction
+ suite.addTestSuite(TestListenerTest.class);
+ suite.addTestSuite(AssertionFailedErrorTest.class);
+ suite.addTestSuite(AssertTest.class);
+ suite.addTestSuite(TestImplementorTest.class);
+ suite.addTestSuite(NoArgTestCaseTest.class);
+ suite.addTestSuite(ComparisonCompactorTest.class);
+ suite.addTestSuite(ComparisonFailureTest.class);
+ suite.addTestSuite(DoublePrecisionAssertTest.class);
+ suite.addTestSuite(FloatAssertTest.class);
+ return suite;
+ }
+
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/AssertTest.java b/junit4/src/test/java/junit/tests/framework/AssertTest.java
new file mode 100644
index 0000000..de33ff6
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/AssertTest.java
@@ -0,0 +1,171 @@
+package junit.tests.framework;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.ComparisonFailure;
+import junit.framework.TestCase;
+
+public class AssertTest extends TestCase {
+
+ /* In the tests that follow, we can't use standard formatting
+ * for exception tests:
+ * try {
+ * somethingThatShouldThrow();
+ * fail();
+ * catch (AssertionFailedError e) {
+ * }
+ * because fail() would never be reported.
+ */
+ public void testFail() {
+ // Also, we are testing fail, so we can't rely on fail() working.
+ // We have to throw the exception manually.
+ try {
+ fail();
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ throw new AssertionFailedError();
+ }
+
+ public void testAssertionFailedErrorToStringWithNoMessage() {
+ // Also, we are testing fail, so we can't rely on fail() working.
+ // We have to throw the exception manually.
+ try {
+ fail();
+ } catch (AssertionFailedError e) {
+ assertEquals("junit.framework.AssertionFailedError", e.toString());
+ return;
+ }
+ throw new AssertionFailedError();
+ }
+
+ public void testAssertionFailedErrorToStringWithMessage() {
+ // Also, we are testing fail, so we can't rely on fail() working.
+ // We have to throw the exception manually.
+ try {
+ fail("woops!");
+ } catch (AssertionFailedError e) {
+ assertEquals("junit.framework.AssertionFailedError: woops!", e.toString());
+ return;
+ }
+ throw new AssertionFailedError();
+ }
+
+ public void testAssertEquals() {
+ Object o= new Object();
+ assertEquals(o, o);
+ try {
+ assertEquals(new Object(), new Object());
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ fail();
+ }
+
+ public void testAssertEqualsNull() {
+ assertEquals((Object) null, (Object) null);
+ }
+
+ public void testAssertStringEquals() {
+ assertEquals("a", "a");
+ }
+
+ public void testAssertNullNotEqualsString() {
+ try {
+ assertEquals(null, "foo");
+ fail();
+ } catch (ComparisonFailure e) {
+ }
+ }
+
+ public void testAssertStringNotEqualsNull() {
+ try {
+ assertEquals("foo", null);
+ fail();
+ } catch (ComparisonFailure e) {
+ e.getMessage(); // why no assertion?
+ }
+ }
+
+ public void testAssertNullNotEqualsNull() {
+ try {
+ assertEquals(null, new Object());
+ } catch (AssertionFailedError e) {
+ e.getMessage(); // why no assertion?
+ return;
+ }
+ fail();
+ }
+
+ public void testAssertNull() {
+ assertNull(null);
+ try {
+ assertNull(new Object());
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ fail();
+ }
+
+ public void testAssertNotNull() {
+ assertNotNull(new Object());
+ try {
+ assertNotNull(null);
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ fail();
+ }
+
+ public void testAssertTrue() {
+ assertTrue(true);
+ try {
+ assertTrue(false);
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ fail();
+ }
+
+ public void testAssertFalse() {
+ assertFalse(false);
+ try {
+ assertFalse(true);
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ fail();
+ }
+
+ public void testAssertSame() {
+ Object o= new Object();
+ assertSame(o, o);
+ try {
+ assertSame(new Integer(1), new Integer(1));
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ fail();
+ }
+
+ public void testAssertNotSame() {
+ assertNotSame(new Integer(1), null);
+ assertNotSame(null, new Integer(1));
+ assertNotSame(new Integer(1), new Integer(1));
+ try {
+ Integer obj= new Integer(1);
+ assertNotSame(obj, obj);
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ fail();
+ }
+
+ public void testAssertNotSameFailsNull() {
+ try {
+ assertNotSame(null, null);
+ } catch (AssertionFailedError e) {
+ return;
+ }
+ fail();
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/AssertionFailedErrorTest.java b/junit4/src/test/java/junit/tests/framework/AssertionFailedErrorTest.java
new file mode 100644
index 0000000..3dd6b1f
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/AssertionFailedErrorTest.java
@@ -0,0 +1,23 @@
+package junit.tests.framework;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+public class AssertionFailedErrorTest extends TestCase {
+ private static final String ARBITRARY_MESSAGE= "arbitrary message";
+
+ public void testCreateErrorWithoutMessage() throws Exception {
+ AssertionFailedError error= new AssertionFailedError();
+ assertNull(error.getMessage());
+ }
+
+ public void testCreateErrorWithMessage() throws Exception {
+ AssertionFailedError error= new AssertionFailedError(ARBITRARY_MESSAGE);
+ assertEquals(ARBITRARY_MESSAGE, error.getMessage());
+ }
+
+ public void testCreateErrorWithoutMessageInsteadOfNull() throws Exception {
+ AssertionFailedError error= new AssertionFailedError(null);
+ assertEquals("", error.getMessage());
+ }
+}
diff --git a/junit4/src/test/java/junit/tests/framework/ComparisonCompactorTest.java b/junit4/src/test/java/junit/tests/framework/ComparisonCompactorTest.java
new file mode 100644
index 0000000..6edaefe
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/ComparisonCompactorTest.java
@@ -0,0 +1,102 @@
+package junit.tests.framework;
+
+import junit.framework.ComparisonCompactor;
+import junit.framework.TestCase;
+
+public class ComparisonCompactorTest extends TestCase {
+
+ public void testMessage() {
+ String failure= new ComparisonCompactor(0, "b", "c").compact("a");
+ assertTrue("a expected:<[b]> but was:<[c]>".equals(failure));
+ }
+
+ public void testStartSame() {
+ String failure= new ComparisonCompactor(1, "ba", "bc").compact(null);
+ assertEquals("expected:<b[a]> but was:<b[c]>", failure);
+ }
+
+ public void testEndSame() {
+ String failure= new ComparisonCompactor(1, "ab", "cb").compact(null);
+ assertEquals("expected:<[a]b> but was:<[c]b>", failure);
+ }
+
+ public void testSame() {
+ String failure= new ComparisonCompactor(1, "ab", "ab").compact(null);
+ assertEquals("expected:<ab> but was:<ab>", failure);
+ }
+
+ public void testNoContextStartAndEndSame() {
+ String failure= new ComparisonCompactor(0, "abc", "adc").compact(null);
+ assertEquals("expected:<...[b]...> but was:<...[d]...>", failure);
+ }
+
+ public void testStartAndEndContext() {
+ String failure= new ComparisonCompactor(1, "abc", "adc").compact(null);
+ assertEquals("expected:<a[b]c> but was:<a[d]c>", failure);
+ }
+
+ public void testStartAndEndContextWithEllipses() {
+ String failure= new ComparisonCompactor(1, "abcde", "abfde").compact(null);
+ assertEquals("expected:<...b[c]d...> but was:<...b[f]d...>", failure);
+ }
+
+ public void testComparisonErrorStartSameComplete() {
+ String failure= new ComparisonCompactor(2, "ab", "abc").compact(null);
+ assertEquals("expected:<ab[]> but was:<ab[c]>", failure);
+ }
+
+ public void testComparisonErrorEndSameComplete() {
+ String failure= new ComparisonCompactor(0, "bc", "abc").compact(null);
+ assertEquals("expected:<[]...> but was:<[a]...>", failure);
+ }
+
+ public void testComparisonErrorEndSameCompleteContext() {
+ String failure= new ComparisonCompactor(2, "bc", "abc").compact(null);
+ assertEquals("expected:<[]bc> but was:<[a]bc>", failure);
+ }
+
+ public void testComparisonErrorOverlapingMatches() {
+ String failure= new ComparisonCompactor(0, "abc", "abbc").compact(null);
+ assertEquals("expected:<...[]...> but was:<...[b]...>", failure);
+ }
+
+ public void testComparisonErrorOverlapingMatchesContext() {
+ String failure= new ComparisonCompactor(2, "abc", "abbc").compact(null);
+ assertEquals("expected:<ab[]c> but was:<ab[b]c>", failure);
+ }
+
+ public void testComparisonErrorOverlapingMatches2() {
+ String failure= new ComparisonCompactor(0, "abcdde", "abcde").compact(null);
+ assertEquals("expected:<...[d]...> but was:<...[]...>", failure);
+ }
+
+ public void testComparisonErrorOverlapingMatches2Context() {
+ String failure= new ComparisonCompactor(2, "abcdde", "abcde").compact(null);
+ assertEquals("expected:<...cd[d]e> but was:<...cd[]e>", failure);
+ }
+
+ public void testComparisonErrorWithActualNull() {
+ String failure= new ComparisonCompactor(0, "a", null).compact(null);
+ assertEquals("expected:<a> but was:<null>", failure);
+ }
+
+ public void testComparisonErrorWithActualNullContext() {
+ String failure= new ComparisonCompactor(2, "a", null).compact(null);
+ assertEquals("expected:<a> but was:<null>", failure);
+ }
+
+ public void testComparisonErrorWithExpectedNull() {
+ String failure= new ComparisonCompactor(0, null, "a").compact(null);
+ assertEquals("expected:<null> but was:<a>", failure);
+ }
+
+ public void testComparisonErrorWithExpectedNullContext() {
+ String failure= new ComparisonCompactor(2, null, "a").compact(null);
+ assertEquals("expected:<null> but was:<a>", failure);
+ }
+
+ public void testBug609972() {
+ String failure= new ComparisonCompactor(10, "S&P500", "0").compact(null);
+ assertEquals("expected:<[S&P50]0> but was:<[]0>", failure);
+ }
+}
diff --git a/junit4/src/test/java/junit/tests/framework/ComparisonFailureTest.java b/junit4/src/test/java/junit/tests/framework/ComparisonFailureTest.java
new file mode 100644
index 0000000..8a1e5f2
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/ComparisonFailureTest.java
@@ -0,0 +1,47 @@
+package junit.tests.framework;
+
+import junit.framework.ComparisonFailure;
+import junit.framework.TestCase;
+
+public class ComparisonFailureTest extends TestCase {
+
+ // Most of the tests are in ComparisonCompactorTest
+ public void testConnection() {
+ ComparisonFailure failure= new ComparisonFailure("warning", "Mary had a little lamb", "Mary had the little lamb");
+ assertEquals("warning expected:<Mary had [a] little lamb> but was:<Mary had [the] little lamb>", failure.getMessage());
+ }
+
+ // This is like an instanceof test.
+ public void testThrowing() {
+ try {
+ assertEquals("a", "b");
+ } catch (ComparisonFailure e) {
+ return;
+ }
+ fail();
+ }
+
+ public void testExceptionToStringWithMessage() {
+ try {
+ assertEquals("woops!", "a", "b");
+ } catch (ComparisonFailure e) {
+ if (!e.toString().startsWith("junit.framework.ComparisonFailure: woops! expected:<")) {
+ fail("Unexpected message: " + e);
+ }
+ return;
+ }
+ fail();
+ }
+
+ public void testExceptionToStringWithoutMessage() {
+ try {
+ assertEquals("a", "b");
+ } catch (ComparisonFailure e) {
+ if (!e.toString().startsWith("junit.framework.ComparisonFailure: expected:<")) {
+ fail("Unexpected message: " + e);
+ }
+ return;
+ }
+ fail();
+ }
+}
diff --git a/junit4/src/test/java/junit/tests/framework/DoublePrecisionAssertTest.java b/junit4/src/test/java/junit/tests/framework/DoublePrecisionAssertTest.java
new file mode 100644
index 0000000..9df3560
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/DoublePrecisionAssertTest.java
@@ -0,0 +1,55 @@
+package junit.tests.framework;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+public class DoublePrecisionAssertTest extends TestCase {
+
+ /**
+ * Test for the special Double.NaN value.
+ */
+ public void testAssertEqualsNaNFails() {
+ try {
+ assertEquals(1.234, Double.NaN, 0.0);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+ public void testAssertNaNEqualsFails() {
+ try {
+ assertEquals(Double.NaN, 1.234, 0.0);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+ public void testAssertNaNEqualsNaN() {
+ assertEquals(Double.NaN, Double.NaN, 0.0);
+ }
+
+ public void testAssertPosInfinityNotEqualsNegInfinity() {
+ try {
+ assertEquals(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+ public void testAssertPosInfinityNotEquals() {
+ try {
+ assertEquals(Double.POSITIVE_INFINITY, 1.23, 0.0);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+ public void testAssertPosInfinityEqualsInfinity() {
+ assertEquals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 0.0);
+ }
+
+ public void testAssertNegInfinityEqualsInfinity() {
+ assertEquals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0);
+ }
+
+}
diff --git a/junit4/src/test/java/junit/tests/framework/Failure.java b/junit4/src/test/java/junit/tests/framework/Failure.java
new file mode 100644
index 0000000..4dd9c8c
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/Failure.java
@@ -0,0 +1,14 @@
+package junit.tests.framework;
+
+import junit.framework.TestCase;
+
+/**
+ * A test case testing the testing framework.
+ *
+ */
+public class Failure extends TestCase {
+ @Override
+ public void runTest() {
+ fail();
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/FloatAssertTest.java b/junit4/src/test/java/junit/tests/framework/FloatAssertTest.java
new file mode 100644
index 0000000..2d22549
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/FloatAssertTest.java
@@ -0,0 +1,63 @@
+package junit.tests.framework;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+public class FloatAssertTest extends TestCase {
+
+ /**
+ * Test for the special Double.NaN value.
+ */
+ public void testAssertEqualsNaNFails() {
+ try {
+ assertEquals(1.234f, Float.NaN, 0.0);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+ public void testAssertNaNEqualsFails() {
+ try {
+ assertEquals(Float.NaN, 1.234f, 0.0);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+ public void testAssertNaNEqualsNaN() {
+ assertEquals(Float.NaN, Float.NaN, 0.0);
+ }
+
+ public void testAssertPosInfinityNotEqualsNegInfinity() {
+ try {
+ assertEquals(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, 0.0);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+ public void testAssertPosInfinityNotEquals() {
+ try {
+ assertEquals(Float.POSITIVE_INFINITY, 1.23f, 0.0);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+ public void testAssertPosInfinityEqualsInfinity() {
+ assertEquals(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, 0.0);
+ }
+
+ public void testAssertNegInfinityEqualsInfinity() {
+ assertEquals(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, 0.0);
+ }
+
+ public void testAllInfinities() {
+ try {
+ assertEquals(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
+ fail();
+ } catch (AssertionFailedError e) {
+ }
+ }
+
+}
diff --git a/junit4/src/test/java/junit/tests/framework/InheritedTestCase.java b/junit4/src/test/java/junit/tests/framework/InheritedTestCase.java
new file mode 100644
index 0000000..f272d77
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/InheritedTestCase.java
@@ -0,0 +1,9 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+public class InheritedTestCase extends OneTestCase {
+ public void test2() {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/NoArgTestCaseTest.java b/junit4/src/test/java/junit/tests/framework/NoArgTestCaseTest.java
new file mode 100644
index 0000000..70281e6
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/NoArgTestCaseTest.java
@@ -0,0 +1,9 @@
+
+package junit.tests.framework;
+
+import junit.framework.TestCase;
+
+public class NoArgTestCaseTest extends TestCase {
+ public void testNothing() { // If this compiles, the no arg ctor is there
+ }
+}
diff --git a/junit4/src/test/java/junit/tests/framework/NoTestCaseClass.java b/junit4/src/test/java/junit/tests/framework/NoTestCaseClass.java
new file mode 100644
index 0000000..5fea04d
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/NoTestCaseClass.java
@@ -0,0 +1,10 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+
+public class NoTestCaseClass extends Object {
+ public void testSuccess() {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/NoTestCases.java b/junit4/src/test/java/junit/tests/framework/NoTestCases.java
new file mode 100644
index 0000000..fec60d0
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/NoTestCases.java
@@ -0,0 +1,11 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+import junit.framework.TestCase;
+
+public class NoTestCases extends TestCase {
+ public void noTestCase() {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/NotPublicTestCase.java b/junit4/src/test/java/junit/tests/framework/NotPublicTestCase.java
new file mode 100644
index 0000000..085f985
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/NotPublicTestCase.java
@@ -0,0 +1,13 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+import junit.framework.TestCase;
+
+public class NotPublicTestCase extends TestCase {
+ protected void testNotPublic() {
+ }
+ public void testPublic() {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/NotVoidTestCase.java b/junit4/src/test/java/junit/tests/framework/NotVoidTestCase.java
new file mode 100644
index 0000000..eca1a63
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/NotVoidTestCase.java
@@ -0,0 +1,14 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+import junit.framework.TestCase;
+
+public class NotVoidTestCase extends TestCase {
+ public int testNotVoid() {
+ return 1;
+ }
+ public void testVoid() {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/OneTestCase.java b/junit4/src/test/java/junit/tests/framework/OneTestCase.java
new file mode 100644
index 0000000..b4ca560
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/OneTestCase.java
@@ -0,0 +1,15 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+import junit.framework.TestCase;
+
+public class OneTestCase extends TestCase {
+ public void noTestCase() {
+ }
+ public void testCase() {
+ }
+ public void testCase(int arg) {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/OverrideTestCase.java b/junit4/src/test/java/junit/tests/framework/OverrideTestCase.java
new file mode 100644
index 0000000..043ef81
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/OverrideTestCase.java
@@ -0,0 +1,10 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+public class OverrideTestCase extends OneTestCase {
+ @Override
+ public void testCase() {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/Success.java b/junit4/src/test/java/junit/tests/framework/Success.java
new file mode 100644
index 0000000..ed4d1b6
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/Success.java
@@ -0,0 +1,17 @@
+package junit.tests.framework;
+
+import junit.framework.TestCase;
+
+/**
+ * A test case testing the testing framework.
+ *
+ */
+public class Success extends TestCase {
+
+ @Override
+ public void runTest() {
+ }
+
+ public void testSuccess() {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/SuiteTest.java b/junit4/src/test/java/junit/tests/framework/SuiteTest.java
new file mode 100644
index 0000000..3953f4f
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/SuiteTest.java
@@ -0,0 +1,105 @@
+package junit.tests.framework;
+
+import java.util.Collections;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+/**
+ * A fixture for testing the "auto" test suite feature.
+ *
+ */
+public class SuiteTest extends TestCase {
+ protected TestResult fResult;
+ public SuiteTest(String name) {
+ super(name);
+ }
+ @Override
+ protected void setUp() {
+ fResult= new TestResult();
+ }
+ public static Test suite() {
+ TestSuite suite= new TestSuite("Suite Tests");
+ // build the suite manually, because some of the suites are testing
+ // the functionality that automatically builds suites
+ suite.addTest(new SuiteTest("testNoTestCases"));
+ suite.addTest(new SuiteTest("testOneTestCase"));
+ suite.addTest(new SuiteTest("testNotPublicTestCase"));
+ suite.addTest(new SuiteTest("testNotVoidTestCase"));
+ suite.addTest(new SuiteTest("testNotExistingTestCase"));
+ suite.addTest(new SuiteTest("testInheritedTests"));
+ suite.addTest(new SuiteTest("testOneTestCaseEclipseSeesSameStructureAs381"));
+ suite.addTest(new SuiteTest("testNoTestCaseClass"));
+ suite.addTest(new SuiteTest("testShadowedTests"));
+ suite.addTest(new SuiteTest("testAddTestSuite"));
+ suite.addTest(new SuiteTest("testCreateSuiteFromArray"));
+
+ return suite;
+ }
+ public void testInheritedTests() {
+ TestSuite suite= new TestSuite(InheritedTestCase.class);
+ suite.run(fResult);
+ assertTrue(fResult.wasSuccessful());
+ assertEquals(2, fResult.runCount());
+ }
+ public void testNoTestCaseClass() {
+ Test t= new TestSuite(NoTestCaseClass.class);
+ t.run(fResult);
+ assertEquals(1, fResult.runCount()); // warning test
+ assertTrue(! fResult.wasSuccessful());
+ }
+ public void testNoTestCases() {
+ Test t= new TestSuite(NoTestCases.class);
+ t.run(fResult);
+ assertTrue(fResult.runCount() == 1); // warning test
+ assertTrue(fResult.failureCount() == 1);
+ assertTrue(! fResult.wasSuccessful());
+ }
+ public void testNotExistingTestCase() {
+ Test t= new SuiteTest("notExistingMethod");
+ t.run(fResult);
+ assertTrue(fResult.runCount() == 1);
+ assertTrue(fResult.failureCount() == 1);
+ assertTrue(fResult.errorCount() == 0);
+ }
+ public void testNotPublicTestCase() {
+ TestSuite suite= new TestSuite(NotPublicTestCase.class);
+ // 1 public test case + 1 warning for the non-public test case
+ assertEquals(2, suite.countTestCases());
+ }
+ public void testNotVoidTestCase() {
+ TestSuite suite= new TestSuite(NotVoidTestCase.class);
+ assertTrue(suite.countTestCases() == 1);
+ }
+ public void testOneTestCase() {
+ TestSuite t= new TestSuite(OneTestCase.class);
+ t.run(fResult);
+ assertTrue(fResult.runCount() == 1);
+ assertTrue(fResult.failureCount() == 0);
+ assertTrue(fResult.errorCount() == 0);
+ assertTrue(fResult.wasSuccessful());
+ }
+ public void testOneTestCaseEclipseSeesSameStructureAs381() {
+ TestSuite t= new TestSuite(ThreeTestCases.class);
+ assertEquals(3, Collections.list(t.tests()).size());
+ }
+ public void testShadowedTests() {
+ TestSuite suite= new TestSuite(OverrideTestCase.class);
+ suite.run(fResult);
+ assertEquals(1, fResult.runCount());
+ }
+ public void testAddTestSuite() {
+ TestSuite suite= new TestSuite();
+ suite.addTestSuite(OneTestCase.class);
+ suite.run(fResult);
+ assertEquals(1, fResult.runCount());
+ }
+ public void testCreateSuiteFromArray() {
+ TestSuite suite = new TestSuite(OneTestCase.class, DoublePrecisionAssertTest.class);
+ assertEquals(2, suite.testCount());
+ assertEquals("junit.tests.framework.DoublePrecisionAssertTest" , ((TestSuite)suite.testAt(1)).getName());
+ assertEquals("junit.tests.framework.OneTestCase" , ((TestSuite)suite.testAt(0)).getName());
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/TestCaseTest.java b/junit4/src/test/java/junit/tests/framework/TestCaseTest.java
new file mode 100644
index 0000000..91b91e6
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/TestCaseTest.java
@@ -0,0 +1,190 @@
+package junit.tests.framework;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.tests.WasRun;
+
+/**
+ * A test case testing the testing framework.
+ *
+ */
+public class TestCaseTest extends TestCase {
+
+ static class TornDown extends TestCase {
+ boolean fTornDown= false;
+
+ @Override
+ protected void tearDown() {
+ fTornDown= true;
+ }
+ @Override
+ protected void runTest() {
+ throw new Error("running");
+ }
+ }
+
+ public void testCaseToString() {
+ // This test wins the award for twisted snake tail eating while
+ // writing self tests. And you thought those weird anonymous
+ // inner classes were bad...
+ assertEquals("testCaseToString(junit.tests.framework.TestCaseTest)", toString());
+ }
+ public void testError() {
+ TestCase error= new TestCase("error") {
+ @Override
+ protected void runTest() {
+ throw new Error();
+ }
+ };
+ verifyError(error);
+ }
+ public void testRunAndTearDownFails() {
+ TornDown fails= new TornDown() {
+ @Override
+ protected void tearDown() {
+ super.tearDown();
+ throw new Error();
+ }
+ @Override
+ protected void runTest() {
+ throw new Error();
+ }
+ };
+ verifyError(fails);
+ assertTrue(fails.fTornDown);
+ }
+ public void testSetupFails() {
+ TestCase fails= new TestCase("success") {
+ @Override
+ protected void setUp() {
+ throw new Error();
+ }
+ @Override
+ protected void runTest() {
+ }
+ };
+ verifyError(fails);
+ }
+ public void testSuccess() {
+ TestCase success= new TestCase("success") {
+ @Override
+ protected void runTest() {
+ }
+ };
+ verifySuccess(success);
+ }
+ public void testFailure() {
+ TestCase failure= new TestCase("failure") {
+ @Override
+ protected void runTest() {
+ fail();
+ }
+ };
+ verifyFailure(failure);
+ }
+
+ public void testTearDownAfterError() {
+ TornDown fails= new TornDown();
+ verifyError(fails);
+ assertTrue(fails.fTornDown);
+ }
+
+ public void testTearDownFails() {
+ TestCase fails= new TestCase("success") {
+ @Override
+ protected void tearDown() {
+ throw new Error();
+ }
+ @Override
+ protected void runTest() {
+ }
+ };
+ verifyError(fails);
+ }
+ public void testTearDownSetupFails() {
+ TornDown fails= new TornDown() {
+ @Override
+ protected void setUp() {
+ throw new Error();
+ }
+ };
+ verifyError(fails);
+ assertTrue(!fails.fTornDown);
+ }
+ public void testWasRun() {
+ WasRun test= new WasRun();
+ test.run();
+ assertTrue(test.fWasRun);
+ }
+ public void testExceptionRunningAndTearDown() {
+ // With 1.4, we should
+ // wrap the exception thrown while running with the exception thrown
+ // while tearing down
+ Test t= new TornDown() {
+ @Override
+ public void tearDown() {
+ throw new Error("tearingDown");
+ }
+ };
+ TestResult result= new TestResult();
+ t.run(result);
+ TestFailure failure= result.errors().nextElement();
+ assertEquals("running", failure.thrownException().getMessage());
+ }
+
+ public void testErrorTearingDownDoesntMaskErrorRunning() {
+ final Exception running= new Exception("Running");
+ TestCase t= new TestCase() {
+ @Override
+ protected void runTest() throws Throwable {
+ throw running;
+ }
+ @Override
+ protected void tearDown() throws Exception {
+ throw new Error("Tearing down");
+ }
+ };
+ try {
+ t.runBare();
+ } catch (Throwable thrown) {
+ assertSame(running, thrown);
+ }
+ }
+
+ public void testNoArgTestCasePasses() {
+ Test t= new TestSuite(NoArgTestCaseTest.class);
+ TestResult result= new TestResult();
+ t.run(result);
+ assertTrue(result.runCount() == 1);
+ assertTrue(result.failureCount() == 0);
+ assertTrue(result.errorCount() == 0);
+ }
+
+ public void testNamelessTestCase() {
+ TestCase t= new TestCase() {};
+ TestResult result = t.run();
+ assertEquals(1, result.failureCount());
+ }
+
+ void verifyError(TestCase test) {
+ TestResult result= test.run();
+ assertTrue(result.runCount() == 1);
+ assertTrue(result.failureCount() == 0);
+ assertTrue(result.errorCount() == 1);
+ }
+ void verifyFailure(TestCase test) {
+ TestResult result= test.run();
+ assertTrue(result.runCount() == 1);
+ assertTrue(result.failureCount() == 1);
+ assertTrue(result.errorCount() == 0);
+ }
+ void verifySuccess(TestCase test) {
+ TestResult result= test.run();
+ assertTrue(result.runCount() == 1);
+ assertTrue(result.failureCount() == 0);
+ assertTrue(result.errorCount() == 0);
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/TestImplementorTest.java b/junit4/src/test/java/junit/tests/framework/TestImplementorTest.java
new file mode 100644
index 0000000..a5f0962
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/TestImplementorTest.java
@@ -0,0 +1,54 @@
+package junit.tests.framework;
+
+import junit.framework.Protectable;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+/**
+ * Test an implementor of junit.framework.Test other than TestCase or TestSuite
+ */
+public class TestImplementorTest extends TestCase {
+ public static class DoubleTestCase implements Test {
+ private TestCase fTestCase;
+
+ public DoubleTestCase(TestCase testCase) {
+ fTestCase= testCase;
+ }
+
+ public int countTestCases() {
+ return 2;
+ }
+
+ public void run(TestResult result) {
+ result.startTest(this);
+ Protectable p= new Protectable() {
+ public void protect() throws Throwable {
+ fTestCase.runBare();
+ fTestCase.runBare();
+ }
+ };
+ result.runProtected(this, p);
+ result.endTest(this);
+ }
+ }
+
+ private DoubleTestCase fTest;
+
+ public TestImplementorTest() {
+ TestCase testCase= new TestCase() {
+ @Override
+ public void runTest() {
+ }
+ };
+ fTest= new DoubleTestCase(testCase);
+ }
+
+ public void testSuccessfulRun() {
+ TestResult result= new TestResult();
+ fTest.run(result);
+ assertEquals(fTest.countTestCases(), result.runCount());
+ assertEquals(0, result.errorCount());
+ assertEquals(0, result.failureCount());
+ }
+}
diff --git a/junit4/src/test/java/junit/tests/framework/TestListenerTest.java b/junit4/src/test/java/junit/tests/framework/TestListenerTest.java
new file mode 100644
index 0000000..1da2af5
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/TestListenerTest.java
@@ -0,0 +1,73 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+
+public class TestListenerTest extends TestCase implements TestListener {
+ private TestResult fResult;
+ private int fStartCount;
+ private int fEndCount;
+ private int fFailureCount;
+ private int fErrorCount;
+
+ public void addError(Test test, Throwable t) {
+ fErrorCount++;
+ }
+ public void addFailure(Test test, AssertionFailedError t) {
+ fFailureCount++;
+ }
+ public void endTest(Test test) {
+ fEndCount++;
+ }
+ @Override
+ protected void setUp() {
+ fResult= new TestResult();
+ fResult.addListener(this);
+
+ fStartCount= 0;
+ fEndCount= 0;
+ fFailureCount= 0;
+ fErrorCount= 0;
+ }
+ public void startTest(Test test) {
+ fStartCount++;
+ }
+ public void testError() {
+ TestCase test= new TestCase("noop") {
+ @Override
+ public void runTest() {
+ throw new Error();
+ }
+ };
+ test.run(fResult);
+ assertEquals(1, fErrorCount);
+ assertEquals(1, fEndCount);
+ }
+ public void testFailure() {
+ TestCase test= new TestCase("noop") {
+ @Override
+ public void runTest() {
+ fail();
+ }
+ };
+ test.run(fResult);
+ assertEquals(1, fFailureCount);
+ assertEquals(1, fEndCount);
+ }
+ public void testStartStop() {
+ TestCase test= new TestCase("noop") {
+ @Override
+ public void runTest() {
+ }
+ };
+ test.run(fResult);
+ assertEquals(1, fStartCount);
+ assertEquals(1, fEndCount);
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/ThreeTestCases.java b/junit4/src/test/java/junit/tests/framework/ThreeTestCases.java
new file mode 100644
index 0000000..c58bece
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/ThreeTestCases.java
@@ -0,0 +1,15 @@
+package junit.tests.framework;
+
+/**
+ * Test class used in SuiteTest
+ */
+import junit.framework.TestCase;
+
+public class ThreeTestCases extends TestCase {
+ public void testCase() {
+ }
+ public void testCase2() {
+ }
+ public void testCase3thisTimeItsPersonal() {
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/framework/package-info.java b/junit4/src/test/java/junit/tests/framework/package-info.java
new file mode 100644
index 0000000..9cc0024
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/framework/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Tests the JUnit v3.x core classes.
+ */
+package junit.tests.framework; \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/package-info.java b/junit4/src/test/java/junit/tests/package-info.java
new file mode 100644
index 0000000..d23121b
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Tests the JUnit v3.x framework.
+ */
+package junit.tests; \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/runner/AllTests.java b/junit4/src/test/java/junit/tests/runner/AllTests.java
new file mode 100644
index 0000000..a0aa116
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/runner/AllTests.java
@@ -0,0 +1,31 @@
+package junit.tests.runner;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * TestSuite that runs all the sample tests
+ *
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() { // Collect tests manually because we have to test class collection code
+ TestSuite suite= new TestSuite("Framework Tests");
+ suite.addTestSuite(StackFilterTest.class);
+ suite.addTestSuite(ResultTest.class);
+ suite.addTestSuite(BaseTestRunnerTest.class);
+ suite.addTestSuite(TextFeedbackTest.class);
+ suite.addTestSuite(TextRunnerSingleMethodTest.class);
+ suite.addTestSuite(TextRunnerTest.class);
+ return suite;
+ }
+
+ static boolean isJDK11() {
+ String version= System.getProperty("java.version");
+ return version.startsWith("1.1");
+ }
+}
diff --git a/junit4/src/test/java/junit/tests/runner/BaseTestRunnerTest.java b/junit4/src/test/java/junit/tests/runner/BaseTestRunnerTest.java
new file mode 100644
index 0000000..8943da9
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/runner/BaseTestRunnerTest.java
@@ -0,0 +1,53 @@
+
+package junit.tests.runner;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.runner.BaseTestRunner;
+
+public class BaseTestRunnerTest extends TestCase {
+ public static class MockRunner extends BaseTestRunner {
+ private boolean fRunFailed = false;
+
+ @Override
+ protected void runFailed(String message) {
+ fRunFailed = true;
+ }
+
+ @Override
+ public void testEnded(String testName) {
+ }
+
+ @Override
+ public void testFailed(int status, Test test, Throwable t) {
+ }
+
+ @Override
+ public void testStarted(String testName) {
+ }
+ }
+
+ public static class NonStatic {
+ public Test suite() {
+ return null;
+ }
+ }
+
+ public void testInvokeNonStaticSuite() {
+ BaseTestRunner runner= new MockRunner();
+ runner.getTest("junit.tests.runner.BaseTestRunnerTest$NonStatic"); // Used to throw NullPointerException
+ }
+
+ public static class DoesntExtendTestCase {
+ public static Test suite() {
+ return new TestSuite();
+ }
+ }
+
+ public void testInvokeSuiteOnNonSubclassOfTestCase() {
+ MockRunner runner= new MockRunner();
+ runner.getTest(DoesntExtendTestCase.class.getName());
+ assertFalse(runner.fRunFailed);
+ }
+}
diff --git a/junit4/src/test/java/junit/tests/runner/ResultTest.java b/junit4/src/test/java/junit/tests/runner/ResultTest.java
new file mode 100644
index 0000000..ba3b509
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/runner/ResultTest.java
@@ -0,0 +1,37 @@
+package junit.tests.runner;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import junit.framework.TestCase;
+import junit.tests.framework.Success;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.tests.running.methods.AnnotationTest;
+
+public class ResultTest extends TestCase {
+
+ public void testRunFailureResultCanBeSerialised() throws Exception {
+ JUnitCore runner = new JUnitCore();
+ Result result = runner.run(AnnotationTest.FailureTest.class);
+ assertResultSerializable(result);
+ }
+
+ public void testRunSuccessResultCanBeSerialised() throws Exception {
+ JUnitCore runner = new JUnitCore();
+ Result result = runner.run(Success.class);
+ assertResultSerializable(result);
+ }
+
+ private void assertResultSerializable(Result result) throws IOException, ClassNotFoundException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ new ObjectOutputStream(byteArrayOutputStream).writeObject(result);
+ byte[] bytes = byteArrayOutputStream.toByteArray();
+ ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
+ Result fromStream = (Result) objectInputStream.readObject();
+ assertNotNull(fromStream);
+ }
+}
diff --git a/junit4/src/test/java/junit/tests/runner/StackFilterTest.java b/junit4/src/test/java/junit/tests/runner/StackFilterTest.java
new file mode 100644
index 0000000..e70ea23
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/runner/StackFilterTest.java
@@ -0,0 +1,46 @@
+package junit.tests.runner;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+import junit.runner.BaseTestRunner;
+
+public class StackFilterTest extends TestCase {
+ String fFiltered;
+ String fUnfiltered;
+
+ @Override
+ protected void setUp() {
+ StringWriter swin= new StringWriter();
+ PrintWriter pwin= new PrintWriter(swin);
+ pwin.println("junit.framework.AssertionFailedError");
+ pwin.println(" at junit.framework.Assert.fail(Assert.java:144)");
+ pwin.println(" at junit.framework.Assert.assert(Assert.java:19)");
+ pwin.println(" at junit.framework.Assert.assert(Assert.java:26)");
+ pwin.println(" at MyTest.f(MyTest.java:13)");
+ pwin.println(" at MyTest.testStackTrace(MyTest.java:8)");
+ pwin.println(" at java.lang.reflect.Method.invoke(Native Method)");
+ pwin.println(" at junit.framework.TestCase.runTest(TestCase.java:156)");
+ pwin.println(" at junit.framework.TestCase.runBare(TestCase.java:130)");
+ pwin.println(" at junit.framework.TestResult$1.protect(TestResult.java:100)");
+ pwin.println(" at junit.framework.TestResult.runProtected(TestResult.java:118)");
+ pwin.println(" at junit.framework.TestResult.run(TestResult.java:103)");
+ pwin.println(" at junit.framework.TestCase.run(TestCase.java:121)");
+ pwin.println(" at junit.framework.TestSuite.runTest(TestSuite.java:157)");
+ pwin.println(" at junit.framework.TestSuite.run(TestSuite.java, Compiled Code)");
+ pwin.println(" at junit.swingui.TestRunner$17.run(TestRunner.java:669)");
+ fUnfiltered= swin.toString();
+
+ StringWriter swout= new StringWriter();
+ PrintWriter pwout= new PrintWriter(swout);
+ pwout.println("junit.framework.AssertionFailedError");
+ pwout.println(" at MyTest.f(MyTest.java:13)");
+ pwout.println(" at MyTest.testStackTrace(MyTest.java:8)");
+ fFiltered= swout.toString();
+ }
+
+ public void testFilter() {
+ assertEquals(fFiltered, BaseTestRunner.getFilteredTrace(fUnfiltered));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/runner/TextFeedbackTest.java b/junit4/src/test/java/junit/tests/runner/TextFeedbackTest.java
new file mode 100644
index 0000000..fa2dbb2
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/runner/TextFeedbackTest.java
@@ -0,0 +1,109 @@
+
+package junit.tests.runner;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.textui.ResultPrinter;
+import junit.textui.TestRunner;
+
+public class TextFeedbackTest extends TestCase {
+ OutputStream output;
+ TestRunner runner;
+
+ static class TestResultPrinter extends ResultPrinter {
+ TestResultPrinter(PrintStream writer) {
+ super(writer);
+ }
+
+ /* Spoof printing time so the tests are deterministic
+ */
+ @Override
+ protected String elapsedTimeAsString(long runTime) {
+ return "0";
+ }
+ }
+
+ public static void main(String[] args) {
+ TestRunner.run(TextFeedbackTest.class);
+ }
+
+ @Override
+ public void setUp() {
+ output= new ByteArrayOutputStream();
+ runner= new TestRunner(new TestResultPrinter(new PrintStream(output)));
+ }
+
+ public void testEmptySuite() {
+ String expected= expected(new String[]{"", "Time: 0", "", "OK (0 tests)", ""});
+ runner.doRun(new TestSuite());
+ assertEquals(expected, output.toString());
+ }
+
+
+ public void testOneTest() {
+ String expected= expected(new String[]{".", "Time: 0", "", "OK (1 test)", ""});
+ TestSuite suite = new TestSuite();
+ suite.addTest(new TestCase() { @Override
+ public void runTest() {}});
+ runner.doRun(suite);
+ assertEquals(expected, output.toString());
+ }
+
+ public void testTwoTests() {
+ String expected= expected(new String[]{"..", "Time: 0", "", "OK (2 tests)", ""});
+ TestSuite suite = new TestSuite();
+ suite.addTest(new TestCase() { @Override
+ public void runTest() {}});
+ suite.addTest(new TestCase() { @Override
+ public void runTest() {}});
+ runner.doRun(suite);
+ assertEquals(expected, output.toString());
+ }
+
+ public void testFailure() {
+ String expected= expected(new String[]{".F", "Time: 0", "Failures here", "", "FAILURES!!!", "Tests run: 1, Failures: 1, Errors: 0", ""});
+ ResultPrinter printer= new TestResultPrinter(new PrintStream(output)) {
+ @Override
+ public void printFailures(TestResult result) {
+ getWriter().println("Failures here");
+ }
+ };
+ runner.setPrinter(printer);
+ TestSuite suite = new TestSuite();
+ suite.addTest(new TestCase() { @Override
+ public void runTest() {throw new AssertionFailedError();}});
+ runner.doRun(suite);
+ assertEquals(expected, output.toString());
+ }
+
+ public void testError() {
+ String expected= expected(new String[]{".E", "Time: 0", "Errors here", "", "FAILURES!!!", "Tests run: 1, Failures: 0, Errors: 1", ""});
+ ResultPrinter printer= new TestResultPrinter(new PrintStream(output)) {
+ @Override
+ public void printErrors(TestResult result) {
+ getWriter().println("Errors here");
+ }
+ };
+ runner.setPrinter(printer);
+ TestSuite suite = new TestSuite();
+ suite.addTest(new TestCase() { @Override
+ public void runTest() throws Exception {throw new Exception();}});
+ runner.doRun(suite);
+ assertEquals(expected, output.toString());
+ }
+
+ private String expected(String[] lines) {
+ OutputStream expected= new ByteArrayOutputStream();
+ PrintStream expectedWriter= new PrintStream(expected);
+ for (int i= 0; i < lines.length; i++)
+ expectedWriter.println(lines[i]);
+ return expected.toString();
+ }
+
+}
diff --git a/junit4/src/test/java/junit/tests/runner/TextRunnerSingleMethodTest.java b/junit4/src/test/java/junit/tests/runner/TextRunnerSingleMethodTest.java
new file mode 100644
index 0000000..1034fdd
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/runner/TextRunnerSingleMethodTest.java
@@ -0,0 +1,39 @@
+package junit.tests.runner;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import junit.framework.TestCase;
+import junit.textui.ResultPrinter;
+import junit.textui.TestRunner;
+
+/**
+ * Test invoking a single test method of a TestCase.
+ */
+public class TextRunnerSingleMethodTest extends TestCase {
+
+ static boolean fgWasInvoked;
+
+ public static class InvocationTest extends TestCase {
+
+ public void testWasInvoked() {
+ TextRunnerSingleMethodTest.fgWasInvoked= true;
+ }
+
+ public void testNotInvoked() {
+ fail("Shouldn't get here.");
+ }
+ }
+
+ public void testSingle() throws Exception {
+ TestRunner t= new TestRunner();
+ t.setPrinter(new ResultPrinter(new PrintStream(new ByteArrayOutputStream())));
+ String[] args= {
+ "-m", "junit.tests.runner.TextRunnerSingleMethodTest$InvocationTest.testWasInvoked"
+ };
+ fgWasInvoked= false;
+ t.start(args);
+ assertTrue(fgWasInvoked);
+ }
+
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/runner/TextRunnerTest.java b/junit4/src/test/java/junit/tests/runner/TextRunnerTest.java
new file mode 100644
index 0000000..d7b5941
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/runner/TextRunnerTest.java
@@ -0,0 +1,61 @@
+package junit.tests.runner;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+public class TextRunnerTest extends TestCase {
+
+ public void testFailure() throws Exception {
+ execTest("junit.tests.framework.Failure", false);
+ }
+
+ public void testSuccess() throws Exception {
+ execTest("junit.tests.framework.Success", true);
+ }
+
+ public void testError() throws Exception {
+ execTest("junit.tests.BogusDude", false);
+ }
+
+ void execTest(String testClass, boolean success) throws Exception {
+ String java= System.getProperty("java.home")+File.separator+"bin"+File.separator+"java";
+ String cp= System.getProperty("java.class.path");
+ //use -classpath for JDK 1.1.7 compatibility
+ String [] cmd= { java, "-classpath", cp, "junit.textui.TestRunner", testClass};
+ Process p= Runtime.getRuntime().exec(cmd);
+ InputStream i= p.getInputStream();
+ while((i.read()) != -1)
+ ; //System.out.write(b);
+ assertTrue((p.waitFor() == 0) == success);
+ if (success)
+ assertTrue(p.exitValue() == 0);
+ else
+ assertFalse(p.exitValue() == 0);
+ }
+
+ public void testRunReturnsResult() {
+ PrintStream oldOut= System.out;
+ System.setOut(new PrintStream (
+ new OutputStream() {
+ @Override
+ public void write(int arg0) throws IOException {
+ }
+ }
+ ));
+ try {
+ TestResult result= junit.textui.TestRunner.run(new TestSuite());
+ assertTrue(result.wasSuccessful());
+ } finally {
+ System.setOut(oldOut);
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/junit4/src/test/java/junit/tests/runner/package-info.java b/junit4/src/test/java/junit/tests/runner/package-info.java
new file mode 100644
index 0000000..fc44e8a
--- /dev/null
+++ b/junit4/src/test/java/junit/tests/runner/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Tests for the JUnit v3.x runner functionality.
+ */
+package junit.tests.runner; \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/samples/ListTest.java b/junit4/src/test/java/org/junit/samples/ListTest.java
new file mode 100644
index 0000000..732037d
--- /dev/null
+++ b/junit4/src/test/java/org/junit/samples/ListTest.java
@@ -0,0 +1,77 @@
+package org.junit.samples;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.JUnit4TestAdapter;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * A sample test case, testing {@link java.util.Vector}.
+ *
+ */
+public class ListTest {
+ protected List<Integer> fEmpty;
+ protected List<Integer> fFull;
+ protected static List<Integer> fgHeavy;
+
+ public static void main (String... args) {
+ junit.textui.TestRunner.run (suite());
+ }
+
+ @BeforeClass public static void setUpOnce() {
+ fgHeavy= new ArrayList<Integer>();
+ for(int i= 0; i < 1000; i++)
+ fgHeavy.add(i);
+ }
+
+ @Before public void setUp() {
+ fEmpty= new ArrayList<Integer>();
+ fFull= new ArrayList<Integer>();
+ fFull.add(1);
+ fFull.add(2);
+ fFull.add(3);
+ }
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(ListTest.class);
+ }
+ @Ignore("not today") @Test public void capacity() {
+ int size= fFull.size();
+ for (int i= 0; i < 100; i++)
+ fFull.add(i);
+ assertTrue(fFull.size() == 100+size);
+ }
+
+ @Test public void testCopy() {
+ List<Integer> copy= new ArrayList<Integer>(fFull.size());
+ copy.addAll(fFull);
+ assertTrue(copy.size() == fFull.size());
+ assertTrue(copy.contains(1));
+ }
+
+ @Test public void contains() {
+ assertTrue(fFull.contains(1));
+ assertTrue(!fEmpty.contains(1));
+ }
+ @Test (expected=IndexOutOfBoundsException.class) public void elementAt() {
+ int i= fFull.get(0);
+ assertTrue(i == 1);
+ fFull.get(fFull.size()); // Should throw IndexOutOfBoundsException
+ }
+
+ @Test public void removeAll() {
+ fFull.removeAll(fFull);
+ fEmpty.removeAll(fEmpty);
+ assertTrue(fFull.isEmpty());
+ assertTrue(fEmpty.isEmpty());
+ }
+ @Test public void removeElement() {
+ fFull.remove(new Integer(3));
+ assertTrue(!fFull.contains(3));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/samples/SimpleTest.java b/junit4/src/test/java/org/junit/samples/SimpleTest.java
new file mode 100644
index 0000000..3202a7b
--- /dev/null
+++ b/junit4/src/test/java/org/junit/samples/SimpleTest.java
@@ -0,0 +1,41 @@
+package org.junit.samples;
+
+import static org.junit.Assert.assertEquals;
+import junit.framework.JUnit4TestAdapter;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Some simple tests.
+ *
+ */
+public class SimpleTest {
+ protected int fValue1;
+ protected int fValue2;
+
+ @Before public void setUp() {
+ fValue1= 2;
+ fValue2= 3;
+ }
+
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(SimpleTest.class);
+ }
+
+ public int unused;
+ @Test public void divideByZero() {
+ int zero= 0;
+ int result= 8/zero;
+ unused= result; // avoid warning for not using result
+ }
+
+ @Test public void testEquals() {
+ assertEquals(12, 12);
+ assertEquals(12L, 12L);
+ assertEquals(new Long(12), new Long(12));
+
+ assertEquals("Size", 12, 13);
+ assertEquals("Capacity", 12.0, 11.99, 0.0);
+ }
+
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/samples/money/MoneyTest.java b/junit4/src/test/java/org/junit/samples/money/MoneyTest.java
new file mode 100644
index 0000000..f3f8317
--- /dev/null
+++ b/junit4/src/test/java/org/junit/samples/money/MoneyTest.java
@@ -0,0 +1,158 @@
+package org.junit.samples.money;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import junit.framework.JUnit4TestAdapter;
+import junit.samples.money.IMoney;
+import junit.samples.money.Money;
+import junit.samples.money.MoneyBag;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MoneyTest {
+ private Money f12CHF;
+ private Money f14CHF;
+ private Money f7USD;
+ private Money f21USD;
+
+ private IMoney fMB1;
+ private IMoney fMB2;
+
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(MoneyTest.class);
+ }
+
+ @Before public void setUp() {
+ f12CHF= new Money(12, "CHF");
+ f14CHF= new Money(14, "CHF");
+ f7USD= new Money( 7, "USD");
+ f21USD= new Money(21, "USD");
+
+ fMB1= MoneyBag.create(f12CHF, f7USD);
+ fMB2= MoneyBag.create(f14CHF, f21USD);
+ }
+
+ @Test public void testBagMultiply() {
+ // {[12 CHF][7 USD]} *2 == {[24 CHF][14 USD]}
+ IMoney expected= MoneyBag.create(new Money(24, "CHF"), new Money(14, "USD"));
+ assertEquals(expected, fMB1.multiply(2));
+ assertEquals(fMB1, fMB1.multiply(1));
+ assertTrue(fMB1.multiply(0).isZero());
+ }
+ @Test public void testBagNegate() {
+ // {[12 CHF][7 USD]} negate == {[-12 CHF][-7 USD]}
+ IMoney expected= MoneyBag.create(new Money(-12, "CHF"), new Money(-7, "USD"));
+ assertEquals(expected, fMB1.negate());
+ }
+ @Test public void testBagSimpleAdd() {
+ // {[12 CHF][7 USD]} + [14 CHF] == {[26 CHF][7 USD]}
+ IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(7, "USD"));
+ assertEquals(expected, fMB1.add(f14CHF));
+ }
+ @Test public void testBagSubtract() {
+ // {[12 CHF][7 USD]} - {[14 CHF][21 USD] == {[-2 CHF][-14 USD]}
+ IMoney expected= MoneyBag.create(new Money(-2, "CHF"), new Money(-14, "USD"));
+ assertEquals(expected, fMB1.subtract(fMB2));
+ }
+ @Test public void testBagSumAdd() {
+ // {[12 CHF][7 USD]} + {[14 CHF][21 USD]} == {[26 CHF][28 USD]}
+ IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(28, "USD"));
+ assertEquals(expected, fMB1.add(fMB2));
+ }
+ @Test public void testIsZero() {
+ assertTrue(fMB1.subtract(fMB1).isZero());
+ assertTrue(MoneyBag.create(new Money (0, "CHF"), new Money (0, "USD")).isZero());
+ }
+ @Test public void testMixedSimpleAdd() {
+ // [12 CHF] + [7 USD] == {[12 CHF][7 USD]}
+ IMoney expected= MoneyBag.create(f12CHF, f7USD);
+ assertEquals(expected, f12CHF.add(f7USD));
+ }
+ @Test public void testBagNotEquals() {
+ IMoney bag= MoneyBag.create(f12CHF, f7USD);
+ assertFalse(bag.equals(new Money(12, "DEM").add(f7USD)));
+ }
+ @Test public void testMoneyBagEquals() {
+ assertTrue(!fMB1.equals(null));
+
+ assertEquals(fMB1, fMB1);
+ IMoney equal= MoneyBag.create(new Money(12, "CHF"), new Money(7, "USD"));
+ assertTrue(fMB1.equals(equal));
+ assertTrue(!fMB1.equals(f12CHF));
+ assertTrue(!f12CHF.equals(fMB1));
+ assertTrue(!fMB1.equals(fMB2));
+ }
+ @Test public void testMoneyBagHash() {
+ IMoney equal= MoneyBag.create(new Money(12, "CHF"), new Money(7, "USD"));
+ assertEquals(fMB1.hashCode(), equal.hashCode());
+ }
+ @Test public void testMoneyEquals() {
+ assertTrue(!f12CHF.equals(null));
+ Money equalMoney= new Money(12, "CHF");
+ assertEquals(f12CHF, f12CHF);
+ assertEquals(f12CHF, equalMoney);
+ assertEquals(f12CHF.hashCode(), equalMoney.hashCode());
+ assertTrue(!f12CHF.equals(f14CHF));
+ }
+ @Test public void zeroMoniesAreEqualRegardlessOfCurrency() {
+ Money zeroDollars= new Money(0, "USD");
+ Money zeroFrancs= new Money(0, "CHF");
+
+ assertEquals(zeroDollars, zeroFrancs);
+ assertEquals(zeroDollars.hashCode(), zeroFrancs.hashCode());
+ }
+ @Test public void testMoneyHash() {
+ assertTrue(!f12CHF.equals(null));
+ Money equal= new Money(12, "CHF");
+ assertEquals(f12CHF.hashCode(), equal.hashCode());
+ }
+ @Test public void testSimplify() {
+ IMoney money= MoneyBag.create(new Money(26, "CHF"), new Money(28, "CHF"));
+ assertEquals(new Money(54, "CHF"), money);
+ }
+ @Test public void testNormalize2() {
+ // {[12 CHF][7 USD]} - [12 CHF] == [7 USD]
+ Money expected= new Money(7, "USD");
+ assertEquals(expected, fMB1.subtract(f12CHF));
+ }
+ @Test public void testNormalize3() {
+ // {[12 CHF][7 USD]} - {[12 CHF][3 USD]} == [4 USD]
+ IMoney ms1= MoneyBag.create(new Money(12, "CHF"), new Money(3, "USD"));
+ Money expected= new Money(4, "USD");
+ assertEquals(expected, fMB1.subtract(ms1));
+ }
+ @Test public void testNormalize4() { // [12 CHF] - {[12 CHF][3 USD]} == [-3 USD]
+ IMoney ms1= MoneyBag.create(new Money(12, "CHF"), new Money(3, "USD"));
+ Money expected= new Money(-3, "USD");
+ assertEquals(expected, f12CHF.subtract(ms1));
+ }
+ @Test public void testPrint() {
+ assertEquals("[12 CHF]", f12CHF.toString());
+ }
+ @Test public void testSimpleAdd() {
+ // [12 CHF] + [14 CHF] == [26 CHF]
+ Money expected= new Money(26, "CHF");
+ assertEquals(expected, f12CHF.add(f14CHF));
+ }
+ @Test public void testSimpleBagAdd() {
+ // [14 CHF] + {[12 CHF][7 USD]} == {[26 CHF][7 USD]}
+ IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(7, "USD"));
+ assertEquals(expected, f14CHF.add(fMB1));
+ }
+ @Test public void testSimpleMultiply() {
+ // [14 CHF] *2 == [28 CHF]
+ Money expected= new Money(28, "CHF");
+ assertEquals(expected, f14CHF.multiply(2));
+ }
+ @Test public void testSimpleNegate() {
+ // [14 CHF] negate == [-14 CHF]
+ Money expected= new Money(-14, "CHF");
+ assertEquals(expected, f14CHF.negate());
+ }
+ @Test public void testSimpleSubtract() {
+ // [14 CHF] - [12 CHF] == [2 CHF]
+ Money expected= new Money(2, "CHF");
+ assertEquals(expected, f14CHF.subtract(f12CHF));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/samples/money/package-info.java b/junit4/src/test/java/org/junit/samples/money/package-info.java
new file mode 100644
index 0000000..2429514
--- /dev/null
+++ b/junit4/src/test/java/org/junit/samples/money/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * JUnit v4.x Test for the Money example.
+ *
+ * @since 4.0
+ * @see junit.samples.money.Money
+ */
+package org.junit.samples.money; \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/samples/package-info.java b/junit4/src/test/java/org/junit/samples/package-info.java
new file mode 100644
index 0000000..ec52263
--- /dev/null
+++ b/junit4/src/test/java/org/junit/samples/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Provides examples on how to use JUnit 4.
+ *
+ * @since 4.0
+ */
+package org.junit.samples; \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/AllTests.java b/junit4/src/test/java/org/junit/tests/AllTests.java
new file mode 100644
index 0000000..2d459f1
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/AllTests.java
@@ -0,0 +1,163 @@
+package org.junit.tests;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+import org.junit.tests.assertion.AssertionTest;
+import org.junit.tests.assertion.BothTest;
+import org.junit.tests.assertion.EachTest;
+import org.junit.tests.assertion.MultipleFailureExceptionTest;
+import org.junit.tests.deprecated.JUnit4ClassRunnerTest;
+import org.junit.tests.description.AnnotatedDescriptionTest;
+import org.junit.tests.description.SuiteDescriptionTest;
+import org.junit.tests.description.TestDescriptionTest;
+import org.junit.tests.experimental.AssumptionTest;
+import org.junit.tests.experimental.AssumptionViolatedExceptionTest;
+import org.junit.tests.experimental.ExperimentalTests;
+import org.junit.tests.experimental.MatcherTest;
+import org.junit.tests.experimental.categories.CategoriesAndParameterizedTest;
+import org.junit.tests.experimental.categories.CategoryTest;
+import org.junit.tests.experimental.max.JUnit38SortingTest;
+import org.junit.tests.experimental.max.MaxStarterTest;
+import org.junit.tests.experimental.parallel.ParallelClassTest;
+import org.junit.tests.experimental.parallel.ParallelMethodTest;
+import org.junit.tests.experimental.rules.BlockJUnit4ClassRunnerOverrideTest;
+import org.junit.tests.experimental.rules.ClassRulesTest;
+import org.junit.tests.experimental.rules.ExpectedExceptionRuleTest;
+import org.junit.tests.experimental.rules.ExternalResourceRuleTest;
+import org.junit.tests.experimental.rules.MethodRulesTest;
+import org.junit.tests.experimental.rules.NameRulesTest;
+import org.junit.tests.experimental.rules.RuleChainTest;
+import org.junit.tests.experimental.rules.TempFolderRuleTest;
+import org.junit.tests.experimental.rules.TestRuleTest;
+import org.junit.tests.experimental.rules.TimeoutRuleTest;
+import org.junit.tests.experimental.rules.VerifierRuleTest;
+import org.junit.tests.experimental.theories.AllMembersSupplierTest;
+import org.junit.tests.experimental.theories.runner.TheoriesPerformanceTest;
+import org.junit.tests.junit3compatibility.AllTestsTest;
+import org.junit.tests.junit3compatibility.ClassRequestTest;
+import org.junit.tests.junit3compatibility.ForwardCompatibilityTest;
+import org.junit.tests.junit3compatibility.InitializationErrorForwardCompatibilityTest;
+import org.junit.tests.junit3compatibility.JUnit38ClassRunnerTest;
+import org.junit.tests.junit3compatibility.OldTestClassAdaptingListenerTest;
+import org.junit.tests.junit3compatibility.OldTests;
+import org.junit.tests.junit3compatibility.SuiteMethodTest;
+import org.junit.tests.listening.ListenerTest;
+import org.junit.tests.listening.RunnerTest;
+import org.junit.tests.listening.TestListenerTest;
+import org.junit.tests.listening.TextListenerTest;
+import org.junit.tests.listening.UserStopTest;
+import org.junit.tests.manipulation.FilterTest;
+import org.junit.tests.manipulation.FilterableTest;
+import org.junit.tests.manipulation.SingleMethodTest;
+import org.junit.tests.manipulation.SortableTest;
+import org.junit.tests.running.classes.BlockJUnit4ClassRunnerTest;
+import org.junit.tests.running.classes.EnclosedTest;
+import org.junit.tests.running.classes.IgnoreClassTest;
+import org.junit.tests.running.classes.ParameterizedTestTest;
+import org.junit.tests.running.classes.ParentRunnerFilteringTest;
+import org.junit.tests.running.classes.ParentRunnerTest;
+import org.junit.tests.running.classes.RunWithTest;
+import org.junit.tests.running.classes.SuiteTest;
+import org.junit.tests.running.classes.TestClassTest;
+import org.junit.tests.running.classes.UseSuiteAsASuperclassTest;
+import org.junit.tests.running.core.CommandLineTest;
+import org.junit.tests.running.core.JUnitCoreReturnsCorrectExitCodeTest;
+import org.junit.tests.running.core.SystemExitTest;
+import org.junit.tests.running.methods.AnnotationTest;
+import org.junit.tests.running.methods.ExpectedTest;
+import org.junit.tests.running.methods.InheritedTestTest;
+import org.junit.tests.running.methods.ParameterizedTestMethodTest;
+import org.junit.tests.running.methods.TestMethodTest;
+import org.junit.tests.running.methods.TimeoutTest;
+import org.junit.tests.validation.BadlyFormedClassesTest;
+import org.junit.tests.validation.FailedConstructionTest;
+import org.junit.tests.validation.InaccessibleBaseClassTest;
+import org.junit.tests.validation.ValidationTest;
+
+// These test files need to be cleaned. See
+// https://sourceforge.net/pm/task.php?func=detailtask&project_task_id=136507&group_id=15278&group_project_id=51407
+
+@SuppressWarnings("deprecation")
+@RunWith(Suite.class)
+@SuiteClasses({
+ AssumptionTest.class,
+ ClassRequestTest.class,
+ ListenerTest.class,
+ FailedConstructionTest.class,
+ TestDescriptionTest.class,
+ SuiteDescriptionTest.class,
+ AllTestsTest.class,
+ AnnotationTest.class,
+ AssertionTest.class,
+ CommandLineTest.class,
+ ExpectedTest.class,
+ MultipleFailureExceptionTest.class,
+ ForwardCompatibilityTest.class,
+ OldTests.class,
+ ParameterizedTestTest.class,
+ RunWithTest.class,
+ RunnerTest.class,
+ SuiteTest.class,
+ TestListenerTest.class,
+ TestMethodTest.class,
+ TextListenerTest.class,
+ TimeoutTest.class,
+ EnclosedTest.class,
+ ParameterizedTestMethodTest.class,
+ InitializationErrorForwardCompatibilityTest.class,
+ SingleMethodTest.class,
+ ValidationTest.class,
+ UserStopTest.class,
+ SortableTest.class,
+ JUnit38ClassRunnerTest.class,
+ SystemExitTest.class,
+ JUnitCoreReturnsCorrectExitCodeTest.class,
+ InaccessibleBaseClassTest.class,
+ SuiteMethodTest.class,
+ BadlyFormedClassesTest.class,
+ IgnoreClassTest.class,
+ OldTestClassAdaptingListenerTest.class,
+ AnnotatedDescriptionTest.class,
+ BothTest.class,
+ AssumptionViolatedExceptionTest.class,
+ EachTest.class,
+ ExperimentalTests.class,
+ InheritedTestTest.class,
+ TestClassTest.class,
+ AllMembersSupplierTest.class,
+ MatcherTest.class,
+ ObjectContractTest.class,
+ TheoriesPerformanceTest.class,
+ JUnit4ClassRunnerTest.class,
+ UseSuiteAsASuperclassTest.class,
+ FilterableTest.class,
+ FilterTest.class,
+ MaxStarterTest.class,
+ JUnit38SortingTest.class,
+ MethodRulesTest.class,
+ TestRuleTest.class,
+ TimeoutRuleTest.class,
+ ParallelClassTest.class,
+ ParallelMethodTest.class,
+ ParentRunnerTest.class,
+ NameRulesTest.class,
+ ClassRulesTest.class,
+ ExpectedExceptionRuleTest.class,
+ TempFolderRuleTest.class,
+ ExternalResourceRuleTest.class,
+ VerifierRuleTest.class,
+ CategoryTest.class,
+ CategoriesAndParameterizedTest.class,
+ ParentRunnerFilteringTest.class,
+ RuleChainTest.class,
+ BlockJUnit4ClassRunnerTest.class,
+ BlockJUnit4ClassRunnerOverrideTest.class
+})
+public class AllTests {
+ public static Test suite() {
+ return new JUnit4TestAdapter(AllTests.class);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/ObjectContractTest.java b/junit4/src/test/java/org/junit/tests/ObjectContractTest.java
new file mode 100644
index 0000000..1239527
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/ObjectContractTest.java
@@ -0,0 +1,46 @@
+package org.junit.tests;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeThat;
+
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+import org.junit.Test.None;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.FrameworkMethod;
+
+@RunWith(Theories.class)
+public class ObjectContractTest {
+ @DataPoints
+ public static Object[] objects= { new FrameworkMethod(toStringMethod()),
+ new FrameworkMethod(toStringMethod()), 3, null };
+
+ @Theory
+ @Test(expected= None.class)
+ public void equalsThrowsNoException(Object a, Object b) {
+ assumeNotNull(a);
+ a.equals(b);
+ }
+
+ @Theory
+ public void equalsMeansEqualHashCodes(Object a, Object b) {
+ assumeNotNull(a, b);
+ assumeThat(a, is(b));
+ assertThat(a.hashCode(), is(b.hashCode()));
+ }
+
+ private static Method toStringMethod() {
+ try {
+ return Object.class.getMethod("toString");
+ } catch (SecurityException e) {
+ } catch (NoSuchMethodException e) {
+ }
+ return null;
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/TestSystem.java b/junit4/src/test/java/org/junit/tests/TestSystem.java
new file mode 100644
index 0000000..9271d3b
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/TestSystem.java
@@ -0,0 +1,31 @@
+package org.junit.tests;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.junit.internal.JUnitSystem;
+
+public class TestSystem implements JUnitSystem {
+ private PrintStream out;
+ public int fCode;
+ private ByteArrayOutputStream fOutContents;
+
+ public TestSystem() {
+ fOutContents= new ByteArrayOutputStream();
+ out= new PrintStream(fOutContents);
+ }
+
+ public void exit(int code) {
+ fCode= code;
+ }
+
+ public PrintStream out() {
+ return out;
+ }
+
+ public OutputStream outContents() {
+ return fOutContents;
+ }
+
+}
diff --git a/junit4/src/test/java/org/junit/tests/assertion/AssertionTest.java b/junit4/src/test/java/org/junit/tests/assertion/AssertionTest.java
new file mode 100644
index 0000000..dabf065
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/assertion/AssertionTest.java
@@ -0,0 +1,486 @@
+package org.junit.tests.assertion;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+
+import org.junit.Assert;
+import org.junit.ComparisonFailure;
+import org.junit.Test;
+import org.junit.internal.ArrayComparisonFailure;
+
+/**
+ * Tests for {@link org.junit.Assert}
+ */
+public class AssertionTest {
+// If you want to use 1.4 assertions, they will be reported correctly.
+// However, you need to add the -ea VM argument when running.
+
+// @Test (expected=AssertionError.class) public void error() {
+// assert false;
+// }
+
+ @Test(expected=AssertionError.class) public void fails() {
+ Assert.fail();
+ }
+
+ @Test public void failWithNoMessageToString() {
+ try {
+ Assert.fail();
+ } catch (AssertionError exception) {
+ assertEquals("java.lang.AssertionError", exception.toString());
+ }
+ }
+
+ @Test public void failWithMessageToString() {
+ try {
+ Assert.fail("woops!");
+ } catch (AssertionError exception) {
+ assertEquals("java.lang.AssertionError: woops!", exception.toString());
+ }
+ }
+
+ @Test(expected= AssertionError.class) public void arraysNotEqual() {
+ assertArrayEquals((new Object[] {new Object()}), (new Object[] {new Object()}));
+ }
+
+ @Test(expected= AssertionError.class) public void arraysNotEqualWithMessage() {
+ assertArrayEquals("not equal", (new Object[] {new Object()}), (new Object[] {new Object()}));
+ }
+
+ @Test public void arraysExpectedNullMessage() {
+ try {
+ assertArrayEquals("not equal", null, (new Object[] {new Object()}));
+ } catch (AssertionError exception) {
+ assertEquals("not equal: expected array was null", exception.getMessage());
+ }
+ }
+
+ @Test public void arraysActualNullMessage() {
+ try {
+ assertArrayEquals("not equal", (new Object[] {new Object()}), null);
+ } catch (AssertionError exception) {
+ assertEquals("not equal: actual array was null", exception.getMessage());
+ }
+ }
+
+ @Test public void arraysDifferentLengthMessage() {
+ try {
+ assertArrayEquals("not equal", (new Object[0]), (new Object[1]));
+ } catch (AssertionError exception) {
+ assertEquals("not equal: array lengths differed, expected.length=0 actual.length=1", exception.getMessage());
+ }
+ }
+
+ @Test(expected=ArrayComparisonFailure.class) public void arraysElementsDiffer() {
+ assertArrayEquals("not equal", (new Object[] {"this is a very long string in the middle of an array"}), (new Object[] {"this is another very long string in the middle of an array"}));
+ }
+
+ @Test public void arraysDifferAtElement0nullMessage() {
+ try {
+ assertArrayEquals((new Object[] { true }), (new Object[] { false }));
+ } catch (AssertionError exception) {
+ assertEquals("arrays first differed at element [0]; expected:<true> but was:<false>", exception
+ .getMessage());
+ }
+ }
+
+ @Test public void arraysDifferAtElement1nullMessage() {
+ try {
+ assertArrayEquals((new Object[] { true, true }), (new Object[] { true,
+ false }));
+ } catch (AssertionError exception) {
+ assertEquals("arrays first differed at element [1]; expected:<true> but was:<false>", exception
+ .getMessage());
+ }
+ }
+
+ @Test public void arraysDifferAtElement0withMessage() {
+ try {
+ assertArrayEquals("message", (new Object[] { true }), (new Object[] { false }));
+ } catch (AssertionError exception) {
+ assertEquals("message: arrays first differed at element [0]; expected:<true> but was:<false>", exception
+ .getMessage());
+ }
+ }
+
+ @Test public void arraysDifferAtElement1withMessage() {
+ try {
+ assertArrayEquals("message", (new Object[] {true, true}), (new Object[] {true, false}));
+ fail();
+ } catch (AssertionError exception) {
+ assertEquals("message: arrays first differed at element [1]; expected:<true> but was:<false>", exception.getMessage());
+ }
+ }
+
+ @Test public void multiDimensionalArraysAreEqual() {
+ assertArrayEquals((new Object[][]{{true, true}, {false, false}}), (new Object[][]{{true, true}, {false, false}}));
+ }
+
+ @Test
+ public void multiDimensionalIntArraysAreEqual() {
+ int[][] int1= { { 1, 2, 3 }, { 4, 5, 6 } };
+ int[][] int2= { { 1, 2, 3 }, { 4, 5, 6 } };
+ assertArrayEquals(int1, int2);
+ }
+
+ @Test
+ public void oneDimensionalPrimitiveArraysAreEqual() {
+ assertArrayEquals(new byte[] {1}, new byte[] {1});
+ assertArrayEquals(new char[] {1}, new char[] {1});
+ assertArrayEquals(new short[] {1}, new short[] {1});
+ assertArrayEquals(new int[] {1}, new int[] {1});
+ assertArrayEquals(new long[] {1}, new long[] {1});
+ assertArrayEquals(new double[] {1.0}, new double[] {1.0}, 1.0);
+ assertArrayEquals(new float[] {1.0f}, new float[] {1.0f}, 1.0f);
+ }
+
+ @Test(expected=AssertionError.class)
+ public void oneDimensionalDoubleArraysAreNotEqual() {
+ assertArrayEquals(new double[] {1.0}, new double[] {2.5}, 1.0);
+ }
+
+ @Test(expected=AssertionError.class)
+ public void oneDimensionalFloatArraysAreNotEqual() {
+ assertArrayEquals(new float[] {1.0f}, new float[] {2.5f}, 1.0f);
+ }
+
+ @Test(expected=AssertionError.class)
+ public void IntegerDoesNotEqualLong() {
+ assertEquals(new Integer(1), new Long(1));
+ }
+
+ @Test public void intsEqualLongs() {
+ assertEquals(1, 1L);
+ }
+
+ @Test public void multiDimensionalArraysDeclaredAsOneDimensionalAreEqual() {
+ assertArrayEquals((new Object[]{new Object[] {true, true}, new Object[] {false, false}}), (new Object[]{new Object[] {true, true}, new Object[] {false, false}}));
+ }
+
+ @Test public void multiDimensionalArraysAreNotEqual() {
+ try {
+ assertArrayEquals("message", (new Object[][]{{true, true}, {false, false}}), (new Object[][]{{true, true}, {true, false}}));
+ fail();
+ } catch (AssertionError exception) {
+ assertEquals("message: arrays first differed at element [1][0]; expected:<false> but was:<true>", exception.getMessage());
+ }
+ }
+
+ @Test public void multiDimensionalArraysAreNotEqualNoMessage() {
+ try {
+ assertArrayEquals((new Object[][]{{true, true}, {false, false}}), (new Object[][]{{true, true}, {true, false}}));
+ fail();
+ } catch (AssertionError exception) {
+ assertEquals("arrays first differed at element [1][0]; expected:<false> but was:<true>", exception.getMessage());
+ }
+ }
+
+ @Test public void arraysWithNullElementEqual() {
+ Object[] objects1 = new Object[] {null};
+ Object[] objects2 = new Object[] {null};
+ assertArrayEquals(objects1, objects2);
+ }
+
+ @Test public void stringsDifferWithUserMessage() {
+ try {
+ assertEquals("not equal", "one", "two");
+ } catch (Throwable exception) {
+ assertEquals("not equal expected:<[one]> but was:<[two]>", exception.getMessage());
+ }
+ }
+
+ @Test public void arraysEqual() {
+ Object element= new Object();
+ Object[] objects1= new Object[] {element};
+ Object[] objects2= new Object[] {element};
+ assertArrayEquals(objects1, objects2);
+ }
+
+ @Test public void arraysEqualWithMessage() {
+ Object element= new Object();
+ Object[] objects1= new Object[] {element};
+ Object[] objects2= new Object[] {element};
+ assertArrayEquals("equal", objects1, objects2);
+ }
+
+ @Test public void equals() {
+ Object o= new Object();
+ assertEquals(o, o);
+ assertEquals("abc", "abc");
+ assertEquals(true, true);
+ assertEquals((byte) 1, (byte) 1);
+ assertEquals('a', 'a');
+ assertEquals((short) 1, (short) 1);
+ assertEquals(1, 1); // int by default, cast is unnecessary
+ assertEquals(1l, 1l);
+ assertEquals(1.0, 1.0, 0.0);
+ assertEquals(1.0d, 1.0d, 0.0d);
+ }
+
+ @Test(expected= AssertionError.class) public void notEqualsObjectWithNull() {
+ assertEquals(new Object(), null);
+ }
+
+ @Test(expected= AssertionError.class) public void notEqualsNullWithObject() {
+ assertEquals(null, new Object());
+ }
+
+ @Test public void notEqualsObjectWithNullWithMessage() {
+ Object o = new Object();
+ try {
+ assertEquals("message", null, o);
+ fail();
+ }
+ catch(AssertionError e) {
+ assertEquals("message expected:<null> but was:<" + o.toString() + ">", e.getMessage());
+ }
+ }
+
+ @Test public void notEqualsNullWithObjectWithMessage() {
+ Object o = new Object();
+ try {
+ assertEquals("message", o, null);
+ fail();
+ }
+ catch(AssertionError e) {
+ assertEquals("message expected:<"+ o.toString() + "> but was:<null>", e.getMessage());
+ }
+ }
+
+ @Test(expected= AssertionError.class) public void objectsNotEquals() {
+ assertEquals(new Object(), new Object());
+ }
+
+ @Test(expected= ComparisonFailure.class) public void stringsNotEqual() {
+ assertEquals("abc", "def");
+ }
+
+ @Test(expected= AssertionError.class) public void booleansNotEqual() {
+ assertEquals(true, false);
+ }
+
+ @Test(expected= AssertionError.class) public void bytesNotEqual() {
+ assertEquals((byte) 1, (byte) 2);
+ }
+
+ @Test(expected= AssertionError.class) public void charsNotEqual() {
+ assertEquals('a', 'b');
+ }
+
+ @Test(expected= AssertionError.class) public void shortsNotEqual() {
+ assertEquals((short) 1, (short) 2);
+ }
+
+ @Test(expected= AssertionError.class) public void intsNotEqual() {
+ assertEquals(1, 2);
+ }
+
+ @Test(expected= AssertionError.class) public void longsNotEqual() {
+ assertEquals(1l, 2l);
+ }
+
+ @Test(expected= AssertionError.class) public void floatsNotEqual() {
+ assertEquals(1.0, 2.0, 0.9);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test(expected= AssertionError.class) public void floatsNotEqualWithoutDelta() {
+ assertEquals(1.0, 1.1);
+ }
+
+ @Test(expected= AssertionError.class) public void bigDecimalsNotEqual() {
+ assertEquals(new BigDecimal("123.4"), new BigDecimal("123.0"));
+ }
+
+
+ @Test(expected= AssertionError.class) public void doublesNotEqual() {
+ assertEquals(1.0d, 2.0d, 0.9d);
+ }
+
+ @Test public void naNsAreEqual() {
+ assertEquals(Float.NaN, Float.NaN, Float.POSITIVE_INFINITY);
+ assertEquals(Double.NaN, Double.NaN, Double.POSITIVE_INFINITY);
+ }
+
+ @Test public void same() {
+ Object o1= new Object();
+ assertSame(o1, o1);
+ }
+
+ @Test public void notSame() {
+ Object o1= new Object();
+ Object o2= new Object();
+ assertNotSame(o1, o2);
+ }
+
+ @Test(expected= AssertionError.class) public void objectsNotSame() {
+ assertSame(new Object(), new Object());
+ }
+
+ @Test(expected= AssertionError.class) public void objectsAreSame() {
+ Object o= new Object();
+ assertNotSame(o, o);
+ }
+
+ @Test public void sameWithMessage() {
+ try {
+ assertSame("not same", "hello", "good-bye");
+ fail();
+ } catch (AssertionError exception) {
+ assertEquals("not same expected same:<hello> was not:<good-bye>",
+ exception.getMessage());
+ }
+ }
+
+ @Test public void sameNullMessage() {
+ try {
+ assertSame("hello", "good-bye");
+ fail();
+ } catch (AssertionError exception) {
+ assertEquals("expected same:<hello> was not:<good-bye>", exception.getMessage());
+ }
+ }
+
+ @Test public void notSameWithMessage() {
+ Object o= new Object();
+ try {
+ assertNotSame("message", o, o);
+ fail();
+ } catch (AssertionError exception) {
+ assertEquals("message expected not same", exception.getMessage());
+ }
+ }
+
+ @Test public void notSameNullMessage() {
+ Object o= new Object();
+ try {
+ assertNotSame(o, o);
+ fail();
+ } catch (AssertionError exception) {
+ assertEquals("expected not same", exception.getMessage());
+ }
+ }
+
+ @Test public void nullMessage() {
+ try {
+ fail(null);
+ } catch (AssertionError exception) {
+ // we used to expect getMessage() to return ""; see failWithNoMessageToString()
+ assertNull(exception.getMessage());
+ }
+ }
+
+ @Test public void nullMessageDisappearsWithStringAssertEquals() {
+ try {
+ assertEquals(null, "a", "b");
+ fail();
+ } catch (ComparisonFailure e) {
+ assertEquals("expected:<[a]> but was:<[b]>", e.getMessage());
+ }
+ }
+
+ @Test public void nullMessageDisappearsWithAssertEquals() {
+ try {
+ assertEquals(null, 1, 2);
+ fail();
+ } catch (AssertionError e) {
+ assertEquals("expected:<1> but was:<2>", e.getMessage());
+ }
+ }
+
+ @Test(expected=AssertionError.class)
+ public void arraysDeclaredAsObjectAreComparedAsObjects() {
+ Object a1= new Object[] {"abc"};
+ Object a2= new Object[] {"abc"};
+ assertEquals(a1, a2);
+ }
+
+ @Test public void implicitTypecastEquality() {
+ byte b = 1;
+ short s = 1;
+ int i = 1;
+ long l = 1L;
+ float f = 1.0f;
+ double d = 1.0;
+
+ assertEquals(b, s);
+ assertEquals(b, i);
+ assertEquals(b, l);
+ assertEquals(s, i);
+ assertEquals(s, l);
+ assertEquals(i, l);
+ assertEquals(f, d, 0);
+ }
+
+ @Test public void errorMessageDistinguishesDifferentValuesWithSameToString() {
+ try {
+ assertEquals("4", new Integer(4));
+ } catch (AssertionError e) {
+ assertEquals("expected: java.lang.String<4> but was: java.lang.Integer<4>", e.getMessage());
+ }
+ }
+
+ @Test public void assertThatIncludesDescriptionOfTestedValueInErrorMessage() {
+ String expected = "expected";
+ String actual = "actual";
+
+ String expectedMessage = "identifier\nExpected: \"expected\"\n got: \"actual\"\n";
+
+ try {
+ assertThat("identifier", actual, equalTo(expected));
+ } catch (AssertionError e) {
+ assertEquals(expectedMessage, e.getMessage());
+ }
+ }
+
+ @Test public void assertThatIncludesAdvancedMismatch() {
+ String expectedMessage = "identifier\nExpected: is an instance of java.lang.Integer\n got: \"actual\"\n";
+
+ try {
+ assertThat("identifier", "actual", is(Integer.class));
+ } catch (AssertionError e) {
+ assertEquals(expectedMessage, e.getMessage());
+ }
+ }
+
+ @Test public void assertThatDescriptionCanBeElided() {
+ String expected = "expected";
+ String actual = "actual";
+
+ String expectedMessage = "\nExpected: \"expected\"\n got: \"actual\"\n";
+
+ try {
+ assertThat(actual, equalTo(expected));
+ } catch (AssertionError e) {
+ assertEquals(expectedMessage, e.getMessage());
+ }
+ }
+
+ @Test public void nullAndStringNullPrintCorrectError() {
+ try {
+ assertEquals(null, "null");
+ } catch (AssertionError e) {
+ assertEquals("expected: null<null> but was: java.lang.String<null>", e.getMessage());
+ }
+ }
+
+ @Test(expected=AssertionError.class) public void stringNullAndNullWorksToo() {
+ assertEquals("null", null);
+ }
+
+ @Test(expected=AssertionError.class)
+ public void compareBigDecimalAndInteger() {
+ final BigDecimal bigDecimal = new BigDecimal("1.2");
+ final Integer integer = Integer.valueOf("1");
+ assertEquals(bigDecimal, integer);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/assertion/BothTest.java b/junit4/src/test/java/org/junit/tests/assertion/BothTest.java
new file mode 100644
index 0000000..fd51a09
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/assertion/BothTest.java
@@ -0,0 +1,71 @@
+package org.junit.tests.assertion;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.matchers.JUnitMatchers.both;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.junit.matchers.JUnitMatchers.either;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class BothTest {
+ @DataPoint
+ public static Matcher<Integer> IS_3= is(3);
+
+ @DataPoint
+ public static Matcher<Integer> IS_4= is(4);
+
+ @DataPoint
+ public static int THREE= 3;
+
+ @Test
+ public void bothPasses() {
+ assertThat(3, both(is(Integer.class)).and(is(3)));
+ }
+
+ @Theory
+ public void bothFails(int value, Matcher<Integer> first,
+ Matcher<Integer> second) {
+ assumeTrue(!(first.matches(value) && second.matches(value)));
+ assertThat(value, not(both(first).and(second)));
+ }
+
+ @Theory
+ public <T> void descriptionIsSensible(Matcher<T> first, Matcher<T> second) {
+ Matcher<?> both= both(first).and(second);
+ assertThat(both.toString(), containsString(first.toString()));
+ assertThat(both.toString(), containsString(second.toString()));
+ }
+
+ @Test
+ public void eitherPasses() {
+ assertThat(3, either(is(3)).or(is(4)));
+ }
+
+ @Theory
+ public <T> void threeAndsWork(Matcher<Integer> first,
+ Matcher<Integer> second, Matcher<Integer> third, int value) {
+ assumeTrue(first.matches(value) && second.matches(value)
+ && third.matches(value));
+ assertThat(value, both(first).and(second).and(third));
+ }
+
+ @Theory
+ public <T> void threeOrsWork(Matcher<Integer> first,
+ Matcher<Integer> second, Matcher<Integer> third, int value) {
+ assumeTrue(first.matches(value) || second.matches(value)
+ || third.matches(value));
+ assertThat(value, either(first).or(second).or(third));
+ }
+
+ @Test public void subclassesAreOkInSecondPositionOnly() {
+ assertThat(3, both(is(Integer.class)).and(is(3)));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/assertion/EachTest.java b/junit4/src/test/java/org/junit/tests/assertion/EachTest.java
new file mode 100644
index 0000000..16327e2
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/assertion/EachTest.java
@@ -0,0 +1,13 @@
+package org.junit.tests.assertion;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import org.junit.Test;
+import org.junit.internal.matchers.Each;
+
+public class EachTest {
+ @Test
+ public void eachDescription() {
+ assertThat(Each.each(is("a")).toString(), is("each is \"a\""));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java b/junit4/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java
new file mode 100644
index 0000000..1ddbcea
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java
@@ -0,0 +1,60 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package org.junit.tests.assertion;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runners.model.MultipleFailureException;
+
+/**
+ * Tests for {@link org.junit.runners.model.MultipleFailureException}
+ *
+ * @author kcooney@google.com (Kevin Cooney)
+ */
+public class MultipleFailureExceptionTest {
+
+ @Test
+ public void assertEmptyDoesNotThrowForEmptyList() throws Throwable {
+ MultipleFailureException.assertEmpty(Collections.<Throwable>emptyList());
+ }
+
+ @Test(expected=ExpectedException.class)
+ public void assertEmptyRethrowsSingleThrowable() throws Throwable {
+ MultipleFailureException.assertEmpty(
+ Collections.<Throwable>singletonList(new ExpectedException("pesto")));
+ }
+
+ @Test
+ public void assertEmptyThrowsMutipleFailureExceptionForManyThrowables() throws Throwable {
+ List<Throwable> errors = new ArrayList<Throwable>();
+ errors.add(new ExpectedException("basil"));
+ errors.add(new RuntimeException("garlic"));
+
+ try {
+ MultipleFailureException.assertEmpty(errors);
+ fail();
+ } catch (MultipleFailureException expected) {
+ assertThat(expected.getFailures(), equalTo(errors));
+ assertTrue(expected.getMessage().startsWith("There were 2 errors:\n"));
+ assertTrue(expected.getMessage().contains("ExpectedException(basil)\n"));
+ assertTrue(expected.getMessage().contains("RuntimeException(garlic)"));
+ }
+ }
+
+
+ private static class ExpectedException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public ExpectedException(String message) {
+ super(message);
+ }
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java b/junit4/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java
new file mode 100644
index 0000000..7cdfbb7
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java
@@ -0,0 +1,54 @@
+package org.junit.tests.deprecated;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import org.junit.Test;
+import org.junit.internal.runners.JUnit4ClassRunner;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+
+/*
+ * @deprecated This is a simple smoke test to make sure the old JUnit4ClassRunner basically works.
+ * Delete this test when JUnit4ClassRunner goes to the Great Heap In The Sky.
+ */
+@Deprecated
+public class JUnit4ClassRunnerTest {
+
+ @SuppressWarnings("deprecation")
+ @RunWith(JUnit4ClassRunner.class)
+ public static class Example {
+ @Test public void success() {}
+ @Test public void failure() {
+ fail();
+ }
+ }
+
+ @Test
+ public void runWithOldJUnit4ClassRunner() {
+ Result result= JUnitCore.runClasses(Example.class);
+ assertThat(result.getRunCount(), is(2));
+ assertThat(result.getFailureCount(), is(1));
+ }
+
+ @SuppressWarnings("deprecation")
+ @RunWith(JUnit4ClassRunner.class)
+ public static class UnconstructableExample {
+ public UnconstructableExample() {
+ throw new UnsupportedOperationException();
+ }
+ @Test public void success() {}
+ @Test public void failure() {
+ fail();
+ }
+ }
+
+
+ @Test
+ public void runWithOldJUnit4ClassRunnerAndBadConstructor() {
+ Result result= JUnitCore.runClasses(UnconstructableExample.class);
+ assertThat(result.getRunCount(), is(2));
+ assertThat(result.getFailureCount(), is(2));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/description/AnnotatedDescriptionTest.java b/junit4/src/test/java/org/junit/tests/description/AnnotatedDescriptionTest.java
new file mode 100644
index 0000000..370293b
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/description/AnnotatedDescriptionTest.java
@@ -0,0 +1,96 @@
+package org.junit.tests.description;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+
+public class AnnotatedDescriptionTest {
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface MyOwnAnnotation {
+
+ }
+
+ @MyOwnAnnotation
+ public static class AnnotatedClass {
+ @Test
+ public void a() {
+ }
+ }
+
+ @Test
+ public void annotationsExistOnDescriptionsOfClasses() {
+ assertTrue((describe(AnnotatedClass.class).getAnnotation(
+ MyOwnAnnotation.class) != null));
+ }
+
+ @Test
+ public void getAnnotationsReturnsAllAnnotations() {
+ assertEquals(1, describe(ValueAnnotatedClass.class).getAnnotations()
+ .size());
+ }
+
+ @Ignore
+ public static class IgnoredClass {
+ @Test
+ public void a() {
+ }
+ }
+
+ @Test
+ public void annotationsExistOnDescriptionsOfIgnoredClass() {
+ assertTrue((describe(IgnoredClass.class).getAnnotation(Ignore.class) != null));
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface ValuedAnnotation {
+ String value();
+ }
+
+ @ValuedAnnotation("hello")
+ public static class ValueAnnotatedClass {
+ @Test
+ public void a() {
+ }
+ }
+
+ @Test
+ public void descriptionOfTestClassHasValuedAnnotation() {
+ Description description= describe(ValueAnnotatedClass.class);
+ assertEquals("hello", description.getAnnotation(ValuedAnnotation.class)
+ .value());
+ }
+
+ @Test
+ public void childlessCopyOfDescriptionStillHasAnnotations() {
+ Description description= describe(ValueAnnotatedClass.class);
+ assertEquals("hello", description.childlessCopy().getAnnotation(ValuedAnnotation.class)
+ .value());
+ }
+
+ @Test
+ public void characterizeCreatingMyOwnAnnotation() {
+ Annotation annotation= new Ignore() {
+ public String value() {
+ return "message";
+ }
+
+ public Class<? extends Annotation> annotationType() {
+ return Ignore.class;
+ }
+ };
+
+ assertEquals(Ignore.class, annotation.annotationType());
+ }
+
+ private Description describe(Class<?> testClass) {
+ return Request.aClass(testClass).getRunner().getDescription();
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/description/SuiteDescriptionTest.java b/junit4/src/test/java/org/junit/tests/description/SuiteDescriptionTest.java
new file mode 100644
index 0000000..8124b01
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/description/SuiteDescriptionTest.java
@@ -0,0 +1,35 @@
+package org.junit.tests.description;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import org.junit.Test;
+import org.junit.runner.Description;
+
+public class SuiteDescriptionTest {
+ Description childless = Description.createSuiteDescription("a");
+ Description anotherChildless = Description.createSuiteDescription("a");
+ Description namedB = Description.createSuiteDescription("b");
+
+ Description twoKids = descriptionWithTwoKids("foo", "bar");
+ Description anotherTwoKids = descriptionWithTwoKids("foo", "baz");
+
+ @Test public void equalsIsCorrect() {
+ assertEquals(childless, anotherChildless);
+ assertFalse(childless.equals(namedB));
+ assertEquals(childless, twoKids);
+ assertEquals(twoKids, anotherTwoKids);
+ assertFalse(twoKids.equals(new Integer(5)));
+ }
+
+ @Test public void hashCodeIsReasonable() {
+ assertEquals(childless.hashCode(), anotherChildless.hashCode());
+ assertFalse(childless.hashCode() == namedB.hashCode());
+ }
+
+ private Description descriptionWithTwoKids(String first, String second) {
+ Description twoKids = Description.createSuiteDescription("a");
+ twoKids.addChild(Description.createTestDescription(getClass(), first));
+ twoKids.addChild(Description.createTestDescription(getClass(), second));
+ return twoKids;
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/description/TestDescriptionTest.java b/junit4/src/test/java/org/junit/tests/description/TestDescriptionTest.java
new file mode 100644
index 0000000..7d6c8a5
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/description/TestDescriptionTest.java
@@ -0,0 +1,11 @@
+package org.junit.tests.description;
+
+import static org.junit.Assert.assertFalse;
+import org.junit.Test;
+import org.junit.runner.Description;
+
+public class TestDescriptionTest {
+ @Test public void equalsIsFalseForNonTestDescription() {
+ assertFalse(Description.createTestDescription(getClass(), "a").equals(new Integer(5)));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/AssumptionTest.java b/junit4/src/test/java/org/junit/tests/experimental/AssumptionTest.java
new file mode 100644
index 0000000..3c0fd9c
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/AssumptionTest.java
@@ -0,0 +1,177 @@
+package org.junit.tests.experimental;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeThat;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.internal.matchers.StringContains.containsString;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+public class AssumptionTest {
+ public static class HasFailingAssumption {
+ @Test
+ public void assumptionsFail() {
+ assumeThat(3, is(4));
+ fail();
+ }
+ }
+
+ @Test
+ public void failedAssumptionsMeanPassing() {
+ Result result= JUnitCore.runClasses(HasFailingAssumption.class);
+ assertThat(result.getRunCount(), is(1));
+ assertThat(result.getIgnoreCount(), is(0));
+ assertThat(result.getFailureCount(), is(0));
+ }
+
+ private static int assumptionFailures= 0;
+ @Test
+ public void failedAssumptionsCanBeDetectedByListeners() {
+ assumptionFailures= 0;
+ JUnitCore core= new JUnitCore();
+ core.addListener(new RunListener() {
+ @Override
+ public void testAssumptionFailure(Failure failure) {
+ assumptionFailures++;
+ }
+ });
+ core.run(HasFailingAssumption.class);
+
+ assertThat(assumptionFailures, is(1));
+ }
+
+ public static class HasPassingAssumption {
+ @Test
+ public void assumptionsFail() {
+ assumeThat(3, is(3));
+ fail();
+ }
+ }
+
+ @Test
+ public void passingAssumptionsScootThrough() {
+ Result result= JUnitCore.runClasses(HasPassingAssumption.class);
+ assertThat(result.getRunCount(), is(1));
+ assertThat(result.getIgnoreCount(), is(0));
+ assertThat(result.getFailureCount(), is(1));
+ }
+
+ @Test(expected= AssumptionViolatedException.class)
+ public void assumeThatWorks() {
+ assumeThat(1, is(2));
+ }
+
+ @Test
+ public void assumeThatPasses() {
+ assumeThat(1, is(1));
+ assertCompletesNormally();
+ }
+
+ @Test
+ public void assumeThatPassesOnStrings() {
+ assumeThat("x", is("x"));
+ assertCompletesNormally();
+ }
+
+ @Test(expected= AssumptionViolatedException.class)
+ public void assumeNotNullThrowsException() {
+ Object[] objects= { 1, 2, null };
+ assumeNotNull(objects);
+ }
+
+ @Test
+ public void assumeNotNullPasses() {
+ Object[] objects= { 1, 2 };
+ assumeNotNull(objects);
+ assertCompletesNormally();
+ }
+
+ @Test
+ public void assumeNotNullIncludesParameterList() {
+ try {
+ Object[] objects= { 1, 2, null };
+ assumeNotNull(objects);
+ } catch (AssumptionViolatedException e) {
+ assertThat(e.getMessage(), containsString("1, 2, null"));
+ } catch (Exception e) {
+ fail("Should have thrown AssumptionViolatedException");
+ }
+ }
+ @Test
+ public void assumeNoExceptionThrows() {
+ final Throwable exception= new NullPointerException();
+ try {
+ assumeNoException(exception);
+ fail("Should have thrown exception");
+ } catch (AssumptionViolatedException e) {
+ assertThat(e.getCause(), is(exception));
+ }
+ }
+
+ private void assertCompletesNormally() {
+ }
+
+ @Test(expected=AssumptionViolatedException.class) public void assumeTrueWorks() {
+ Assume.assumeTrue(false);
+ }
+
+ public static class HasFailingAssumeInBefore {
+ @Before public void checkForSomethingThatIsntThere() {
+ assumeTrue(false);
+ }
+
+ @Test public void failing() {
+ fail();
+ }
+ }
+
+ @Test public void failingAssumptionInBeforePreventsTestRun() {
+ assertThat(testResult(HasFailingAssumeInBefore.class), isSuccessful());
+ }
+
+ public static class HasFailingAssumeInBeforeClass {
+ @BeforeClass public static void checkForSomethingThatIsntThere() {
+ assumeTrue(false);
+ }
+
+ @Test public void failing() {
+ fail();
+ }
+ }
+
+ @Test public void failingAssumptionInBeforeClassIgnoresClass() {
+ assertThat(testResult(HasFailingAssumeInBeforeClass.class), isSuccessful());
+ }
+
+ public static class AssumptionFailureInConstructor {
+ public AssumptionFailureInConstructor() {
+ assumeTrue(false);
+ }
+
+ @Test public void shouldFail() {
+ fail();
+ }
+ }
+
+ @Test public void failingAssumptionInConstructorIgnoresClass() {
+ assertThat(testResult(AssumptionFailureInConstructor.class), isSuccessful());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void assumeWithExpectedException() {
+ assumeTrue(false);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/AssumptionViolatedExceptionTest.java b/junit4/src/test/java/org/junit/tests/experimental/AssumptionViolatedExceptionTest.java
new file mode 100644
index 0000000..f1cb955
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/AssumptionViolatedExceptionTest.java
@@ -0,0 +1,52 @@
+package org.junit.tests.experimental;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.junit.internal.matchers.StringContains.containsString;
+import org.hamcrest.Matcher;
+import org.hamcrest.StringDescription;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class AssumptionViolatedExceptionTest {
+ @DataPoint
+ public static Object TWO= 2;
+
+ @DataPoint
+ public static Matcher<?> IS_THREE= is(3);
+
+ @DataPoint
+ public static Matcher<?> NULL= null;
+
+ @Theory
+ public void toStringReportsMatcher(Object actual, Matcher<?> matcher) {
+ assumeThat(matcher, notNullValue());
+ assertThat(new AssumptionViolatedException(actual, matcher).toString(),
+ containsString(matcher.toString()));
+ }
+
+ @Theory
+ public void toStringReportsValue(Object actual, Matcher<?> matcher) {
+ assertThat(new AssumptionViolatedException(actual, matcher).toString(),
+ containsString(String.valueOf(actual)));
+ }
+
+ @Test
+ public void AssumptionViolatedExceptionDescribesItself() {
+ AssumptionViolatedException e= new AssumptionViolatedException(3, is(2));
+ assertThat(StringDescription.asString(e), is("got: <3>, expected: is <2>"));
+ }
+
+ @Test
+ public void simpleAssumptionViolatedExceptionDescribesItself() {
+ AssumptionViolatedException e= new AssumptionViolatedException("not enough money");
+ assertThat(StringDescription.asString(e), is("failed assumption: not enough money"));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/ExperimentalTests.java b/junit4/src/test/java/org/junit/tests/experimental/ExperimentalTests.java
new file mode 100644
index 0000000..7ac7714
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/ExperimentalTests.java
@@ -0,0 +1,28 @@
+package org.junit.tests.experimental;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+import org.junit.tests.experimental.results.PrintableResultTest;
+import org.junit.tests.experimental.results.ResultMatchersTest;
+import org.junit.tests.experimental.theories.ParameterSignatureTest;
+import org.junit.tests.experimental.theories.ParameterizedAssertionErrorTest;
+import org.junit.tests.experimental.theories.extendingwithstubs.StubbedTheoriesTest;
+import org.junit.tests.experimental.theories.runner.SuccessfulWithDataPointFields;
+import org.junit.tests.experimental.theories.runner.UnsuccessfulWithDataPointFields;
+import org.junit.tests.experimental.theories.runner.WhenNoParametersMatch;
+import org.junit.tests.experimental.theories.runner.WithDataPointMethod;
+import org.junit.tests.experimental.theories.runner.WithExtendedParameterSources;
+import org.junit.tests.experimental.theories.runner.WithOnlyTestAnnotations;
+
+@RunWith(Suite.class)
+@SuiteClasses( { ParameterizedAssertionErrorTest.class,
+ UnsuccessfulWithDataPointFields.class,
+ SuccessfulWithDataPointFields.class, PrintableResultTest.class,
+ ResultMatchersTest.class, WithDataPointMethod.class,
+ ParameterSignatureTest.class, WhenNoParametersMatch.class,
+ WithExtendedParameterSources.class, StubbedTheoriesTest.class,
+ WithOnlyTestAnnotations.class })
+public class ExperimentalTests {
+
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/MatcherTest.java b/junit4/src/test/java/org/junit/tests/experimental/MatcherTest.java
new file mode 100644
index 0000000..6b01179
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/MatcherTest.java
@@ -0,0 +1,43 @@
+package org.junit.tests.experimental;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.junit.experimental.results.ResultMatchers.hasFailureContaining;
+import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
+
+import java.util.Arrays;
+
+import org.hamcrest.Matcher;
+import org.junit.experimental.results.PrintableResult;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.Failure;
+
+@RunWith(Theories.class)
+public class MatcherTest {
+ @DataPoint
+ public static Matcher<?> SINGLE_FAILURE= hasSingleFailureContaining("cheese");
+
+ @DataPoint
+ public static Matcher<?> ANY_FAILURE= hasFailureContaining("cheese");
+
+ @DataPoint
+ public static PrintableResult TWO_FAILURES_ONE_CHEESE= new PrintableResult(
+ Arrays.asList(failure("cheese"), failure("mustard")));
+
+ @Theory
+ public <T> void differentMatchersHaveDifferentDescriptions(
+ Matcher<T> matcher1, Matcher<T> matcher2, T value) {
+ assumeThat(value, matcher1);
+ assumeThat(value, not(matcher2));
+ assertThat(matcher1.toString(), not(matcher2.toString()));
+ }
+
+ private static Failure failure(String string) {
+ return new Failure(Description.EMPTY, new Error(string));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java b/junit4/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java
new file mode 100644
index 0000000..f589aea
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java
@@ -0,0 +1,123 @@
+package org.junit.tests.experimental.categories;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.hasFailureContaining;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Categories;
+import org.junit.experimental.categories.Categories.IncludeCategory;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Suite.SuiteClasses;
+
+public class CategoriesAndParameterizedTest {
+ public static class Token {
+
+ }
+
+ @RunWith(Parameterized.class)
+ public static class WellBehavedParameterizedTest {
+ public WellBehavedParameterizedTest(String a) {
+ }
+
+ @Parameters
+ public static Collection<Object[]> getParameters() {
+ return Collections.singletonList(new Object[] { "a" });
+ }
+
+ @Test
+ public void testSomething() {
+ Assert.assertTrue(true);
+ }
+ }
+
+ @RunWith(Parameterized.class)
+ public static class ParameterizedTestWithAttemptedMethodCategory {
+ public ParameterizedTestWithAttemptedMethodCategory(String a) {
+ }
+
+ @Parameters
+ public static Collection<Object[]> getParameters() {
+ return Collections.singletonList(new Object[] { "a" });
+ }
+
+ @Test
+ @Category(Token.class)
+ public void testSomething() {
+ Assert.assertTrue(true);
+ }
+ }
+
+ @RunWith(Parameterized.class)
+ @Category(Token.class)
+ public static class ParameterizedTestWithClassCategory {
+ public ParameterizedTestWithClassCategory(String a) {
+ }
+
+ @Parameters
+ public static Collection<Object[]> getParameters() {
+ return Collections.singletonList(new Object[] { "a" });
+ }
+
+ @Test
+ public void testSomething() {
+ Assert.assertTrue(true);
+ }
+ }
+
+ @Category(Token.class)
+ public static class VanillaCategorizedJUnitTest {
+ @Test
+ public void testSomething() {
+ Assert.assertTrue(true);
+ }
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(Token.class)
+ @SuiteClasses({ VanillaCategorizedJUnitTest.class,
+ WellBehavedParameterizedTest.class,
+ ParameterizedTestWithClassCategory.class })
+ public static class ParameterTokenSuiteWellFormed {
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(Token.class)
+ @SuiteClasses({ ParameterizedTestWithAttemptedMethodCategory.class, VanillaCategorizedJUnitTest.class })
+ public static class ParameterTokenSuiteMalformed {
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(Token.class)
+ @SuiteClasses({ VanillaCategorizedJUnitTest.class, ParameterizedTestWithAttemptedMethodCategory.class })
+ public static class ParameterTokenSuiteMalformedAndSwapped {
+ }
+
+ @Test
+ public void shouldSucceedWithAParameterizedClassSomewhere() {
+ assertThat(testResult(ParameterTokenSuiteWellFormed.class),
+ isSuccessful());
+ }
+
+ @Test
+ public void shouldFailWithMethodLevelCategoryAnnotation() {
+ assertThat(
+ testResult(ParameterTokenSuiteMalformed.class),
+ hasFailureContaining("Category annotations on Parameterized classes are not supported on individual methods."));
+ }
+
+ @Test
+ public void shouldFailWithMethodLevelCategoryAnnotationSwapped() {
+ assertThat(
+ testResult(ParameterTokenSuiteMalformedAndSwapped.class),
+ hasFailureContaining("Category annotations on Parameterized classes are not supported on individual methods."));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/categories/CategoryTest.java b/junit4/src/test/java/org/junit/tests/experimental/categories/CategoryTest.java
new file mode 100644
index 0000000..b316731
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/categories/CategoryTest.java
@@ -0,0 +1,254 @@
+package org.junit.tests.experimental.categories;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import org.junit.Test;
+import org.junit.experimental.categories.Categories;
+import org.junit.experimental.categories.Category;
+import org.junit.experimental.categories.Categories.CategoryFilter;
+import org.junit.experimental.categories.Categories.ExcludeCategory;
+import org.junit.experimental.categories.Categories.IncludeCategory;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+import org.junit.runners.model.InitializationError;
+
+public class CategoryTest {
+ public interface FastTests {
+ // category marker
+ }
+
+ public interface SlowTests {
+ // category marker
+ }
+
+ public static class A {
+ @Test
+ public void a() {
+ fail();
+ }
+
+ @Category(SlowTests.class)
+ @Test
+ public void b() {
+ }
+ }
+
+ @Category(SlowTests.class)
+ public static class B {
+ @Test
+ public void c() {
+
+ }
+ }
+
+ public static class C {
+ @Test
+ public void d() {
+ fail();
+ }
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(SlowTests.class)
+ @SuiteClasses( { A.class, B.class, C.class })
+ public static class SlowTestSuite {
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(SlowTests.class)
+ @SuiteClasses( { A.class })
+ public static class JustA {
+ }
+
+ @Test
+ public void testCountOnJustA() {
+ assertThat(testResult(JustA.class), isSuccessful());
+ }
+
+ @Test
+ public void testCount() {
+ assertThat(testResult(SlowTestSuite.class), isSuccessful());
+ }
+
+ public static class Category1 {}
+ public static class Category2 {}
+
+ public static class SomeAreSlow {
+ @Test public void noCategory() {}
+ @Category(Category1.class) @Test public void justCategory1() {}
+ @Category(Category2.class) @Test public void justCategory2() {}
+ @Category({Category1.class, Category2.class}) @Test public void both() {}
+ @Category({Category2.class, Category1.class}) @Test public void bothReversed() {}
+ }
+
+ @RunWith(Categories.class)
+ @ExcludeCategory(Category1.class)
+ @SuiteClasses( { SomeAreSlow.class })
+ public static class SomeAreSlowSuite {
+ }
+
+ @Test
+ public void testCountOnAWithoutSlowTests() {
+ Result result= JUnitCore.runClasses(SomeAreSlowSuite.class);
+ assertThat(testResult(SomeAreSlowSuite.class), isSuccessful());
+ assertEquals(2, result.getRunCount());
+ assertTrue(result.wasSuccessful());
+ }
+
+ @RunWith(Categories.class)
+ @ExcludeCategory(Category1.class)
+ @IncludeCategory(Category2.class)
+ @SuiteClasses( { SomeAreSlow.class })
+ public static class IncludeAndExcludeSuite {
+ }
+
+ @Test
+ public void testsThatAreBothIncludedAndExcludedAreExcluded() {
+ Result result= JUnitCore.runClasses(IncludeAndExcludeSuite.class);
+ assertThat(testResult(SomeAreSlowSuite.class), isSuccessful());
+ assertEquals(1, result.getRunCount());
+ assertTrue(result.wasSuccessful());
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses( { A.class, B.class, C.class })
+ public static class TestSuiteWithNoCategories {
+ }
+
+ @Test
+ public void testCountWithExplicitFilter() throws Throwable {
+ CategoryFilter include= CategoryFilter.include(SlowTests.class);
+ Request baseRequest= Request.aClass(TestSuiteWithNoCategories.class);
+ Result result= new JUnitCore().run(baseRequest.filterWith(include));
+ assertTrue(result.wasSuccessful());
+ assertEquals(2, result.getRunCount());
+ }
+
+ @Test
+ public void categoryFilterLeavesOnlyMatchingMethods()
+ throws InitializationError, NoTestsRemainException {
+ CategoryFilter filter= CategoryFilter.include(SlowTests.class);
+ BlockJUnit4ClassRunner runner= new BlockJUnit4ClassRunner(A.class);
+ filter.apply(runner);
+ assertEquals(1, runner.testCount());
+ }
+
+ public static class OneFastOneSlow {
+ @Category(FastTests.class)
+ @Test
+ public void a() {
+
+ }
+
+ @Category(SlowTests.class)
+ @Test
+ public void b() {
+
+ }
+ }
+
+ @Test
+ public void categoryFilterRejectsIncompatibleCategory()
+ throws InitializationError, NoTestsRemainException {
+ CategoryFilter filter= CategoryFilter.include(SlowTests.class);
+ BlockJUnit4ClassRunner runner= new BlockJUnit4ClassRunner(
+ OneFastOneSlow.class);
+ filter.apply(runner);
+ assertEquals(1, runner.testCount());
+ }
+
+ public static class OneFast {
+ @Category(FastTests.class)
+ @Test
+ public void a() {
+
+ }
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(SlowTests.class)
+ @SuiteClasses( { OneFast.class })
+ public static class OneFastSuite {
+ }
+
+ @Test
+ public void ifNoTestsToRunUseErrorRunner() {
+ Result result= JUnitCore.runClasses(OneFastSuite.class);
+ assertEquals(1, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ }
+
+ @Test
+ public void describeACategoryFilter() {
+ CategoryFilter filter= CategoryFilter.include(SlowTests.class);
+ assertEquals("category " + SlowTests.class, filter.describe());
+ }
+
+ public static class OneThatIsBothFastAndSlow {
+ @Category({FastTests.class, SlowTests.class})
+ @Test
+ public void a() {
+
+ }
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(SlowTests.class)
+ @SuiteClasses( { OneThatIsBothFastAndSlow.class })
+ public static class ChooseSlowFromBoth {
+ }
+
+ @Test public void runMethodWithTwoCategories() {
+ assertThat(testResult(ChooseSlowFromBoth.class), isSuccessful());
+ }
+
+ public interface VerySlowTests extends SlowTests {
+
+ }
+
+ public static class OneVerySlowTest {
+ @Category(VerySlowTests.class)
+ @Test
+ public void a() {
+
+ }
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(SlowTests.class)
+ @SuiteClasses( { OneVerySlowTest.class })
+ public static class RunSlowFromVerySlow {
+ }
+
+ @Test public void subclassesOfIncludedCategoriesAreRun() {
+ assertThat(testResult(RunSlowFromVerySlow.class), isSuccessful());
+ }
+
+ public static class ClassAsCategory {
+
+ }
+
+ public static class OneMoreTest {
+ @Category(ClassAsCategory.class) @Test public void a() {}
+ }
+
+ @RunWith(Categories.class)
+ @IncludeCategory(ClassAsCategory.class)
+ @SuiteClasses( { OneMoreTest.class })
+ public static class RunClassAsCategory {
+ }
+
+ @Test public void classesCanBeCategories() {
+ assertThat(testResult(RunClassAsCategory.class), isSuccessful());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/max/DescriptionTest.java b/junit4/src/test/java/org/junit/tests/experimental/max/DescriptionTest.java
new file mode 100644
index 0000000..c020320
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/max/DescriptionTest.java
@@ -0,0 +1,24 @@
+package org.junit.tests.experimental.max;
+
+import static org.junit.Assert.assertNull;
+import org.junit.Test;
+import org.junit.runner.Description;
+
+public class DescriptionTest {
+
+ @Test
+ public void parseClass_whenCantParse() {
+ assertNull(Description.TEST_MECHANISM.getTestClass());
+ }
+
+ @Test
+ public void parseMethod_whenCantParse() {
+ assertNull(Description.TEST_MECHANISM.getMethodName());
+ }
+
+ @Test(expected= IllegalArgumentException.class)
+ public void createSuiteDescription_whenZeroLength() {
+ Description.createSuiteDescription("");
+ }
+
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/max/JUnit38SortingTest.java b/junit4/src/test/java/org/junit/tests/experimental/max/JUnit38SortingTest.java
new file mode 100644
index 0000000..68a25d6
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/max/JUnit38SortingTest.java
@@ -0,0 +1,53 @@
+package org.junit.tests.experimental.max;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.util.List;
+
+import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.max.MaxCore;
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+
+public class JUnit38SortingTest {
+ private MaxCore fMax;
+ private File fMaxFile;
+
+ @Before
+ public void createMax() {
+ fMaxFile= new File("MaxCore.ser");
+ if (fMaxFile.exists())
+ fMaxFile.delete();
+ fMax= MaxCore.storedLocally(fMaxFile);
+ }
+
+ @After
+ public void forgetMax() {
+ fMaxFile.delete();
+ }
+
+ public static class JUnit4Test {
+ @Test public void pass() {}
+ }
+
+ public static class JUnit38Test extends TestCase {
+ public void testFails() { fail(); }
+ public void testSucceeds() {}
+ public void testSucceedsToo() {}
+ }
+
+ @Test
+ public void preferRecentlyFailed38Test() {
+ Request request= Request.classes(JUnit4Test.class, JUnit38Test.class);
+ fMax.run(request);
+ List<Description> tests= fMax.sortedLeavesForTest(request);
+ Description dontSucceed= Description.createTestDescription(
+ JUnit38Test.class, "testFails");
+ assertEquals(dontSucceed, tests.get(0));
+ }
+
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/max/MaxStarterTest.java b/junit4/src/test/java/org/junit/tests/experimental/max/MaxStarterTest.java
new file mode 100644
index 0000000..372af8f
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/max/MaxStarterTest.java
@@ -0,0 +1,293 @@
+package org.junit.tests.experimental.max;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.max.MaxCore;
+import org.junit.internal.runners.JUnit38ClassRunner;
+import org.junit.runner.Computer;
+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.runner.manipulation.Filter;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.tests.AllTests;
+
+public class MaxStarterTest {
+ private MaxCore fMax;
+
+ private File fMaxFile;
+
+ @Before
+ public void createMax() {
+ fMaxFile= new File("MaxCore.ser");
+ if (fMaxFile.exists())
+ fMaxFile.delete();
+ fMax= MaxCore.storedLocally(fMaxFile);
+ }
+
+ @After
+ public void forgetMax() {
+ fMaxFile.delete();
+ }
+
+ public static class TwoTests {
+ @Test
+ public void succeed() {
+ }
+
+ @Test
+ public void dontSucceed() {
+ fail();
+ }
+ }
+
+ @Test
+ public void twoTestsNotRunComeBackInRandomOrder() {
+ Request request= Request.aClass(TwoTests.class);
+ List<Description> things= fMax.sortedLeavesForTest(request);
+ Description succeed= Description.createTestDescription(TwoTests.class,
+ "succeed");
+ Description dontSucceed= Description.createTestDescription(
+ TwoTests.class, "dontSucceed");
+ assertTrue(things.contains(succeed));
+ assertTrue(things.contains(dontSucceed));
+ assertEquals(2, things.size());
+ }
+
+ @Test
+ public void preferNewTests() {
+ Request one= Request.method(TwoTests.class, "succeed");
+ fMax.run(one);
+ Request two= Request.aClass(TwoTests.class);
+ List<Description> things= fMax.sortedLeavesForTest(two);
+ Description dontSucceed= Description.createTestDescription(
+ TwoTests.class, "dontSucceed");
+ assertEquals(dontSucceed, things.get(0));
+ assertEquals(2, things.size());
+ }
+
+ // This covers a seemingly-unlikely case, where you had a test that failed
+ // on the
+ // last run and you also introduced new tests. In such a case it pretty much
+ // doesn't matter
+ // which order they run, you just want them both to be early in the sequence
+ @Test
+ public void preferNewTestsOverTestsThatFailed() {
+ Request one= Request.method(TwoTests.class, "dontSucceed");
+ fMax.run(one);
+ Request two= Request.aClass(TwoTests.class);
+ List<Description> things= fMax.sortedLeavesForTest(two);
+ Description succeed= Description.createTestDescription(TwoTests.class,
+ "succeed");
+ assertEquals(succeed, things.get(0));
+ assertEquals(2, things.size());
+ }
+
+ @Test
+ public void preferRecentlyFailed() {
+ Request request= Request.aClass(TwoTests.class);
+ fMax.run(request);
+ List<Description> tests= fMax.sortedLeavesForTest(request);
+ Description dontSucceed= Description.createTestDescription(
+ TwoTests.class, "dontSucceed");
+ assertEquals(dontSucceed, tests.get(0));
+ }
+
+ @Test
+ public void sortTestsInMultipleClasses() {
+ Request request= Request.classes(Computer.serial(), TwoTests.class,
+ TwoTests.class);
+ fMax.run(request);
+ List<Description> tests= fMax.sortedLeavesForTest(request);
+ Description dontSucceed= Description.createTestDescription(
+ TwoTests.class, "dontSucceed");
+ assertEquals(dontSucceed, tests.get(0));
+ assertEquals(dontSucceed, tests.get(1));
+ }
+
+ public static class TwoUnEqualTests {
+ @Test
+ public void slow() throws InterruptedException {
+ Thread.sleep(100);
+ fail();
+ }
+
+ @Test
+ public void fast() {
+ fail();
+ }
+
+ }
+
+ @Test
+ public void rememberOldRuns() {
+ fMax.run(TwoUnEqualTests.class);
+
+ MaxCore reincarnation= MaxCore.storedLocally(fMaxFile);
+ List<Failure> failures= reincarnation.run(TwoUnEqualTests.class)
+ .getFailures();
+ assertEquals("fast", failures.get(0).getDescription().getMethodName());
+ assertEquals("slow", failures.get(1).getDescription().getMethodName());
+ }
+
+ @Test
+ public void preferFast() {
+ Request request= Request.aClass(TwoUnEqualTests.class);
+ fMax.run(request);
+ Description thing= fMax.sortedLeavesForTest(request).get(1);
+ assertEquals(Description.createTestDescription(TwoUnEqualTests.class,
+ "slow"), thing);
+ }
+
+ @Test
+ public void listenersAreCalledCorrectlyInTheFaceOfFailures()
+ throws Exception {
+ JUnitCore core= new JUnitCore();
+ final List<Failure> failures= new ArrayList<Failure>();
+ core.addListener(new RunListener() {
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ failures.addAll(result.getFailures());
+ }
+ });
+ fMax.run(Request.aClass(TwoTests.class), core);
+ assertEquals(1, failures.size());
+ }
+
+ @Test
+ public void testsAreOnlyIncludedOnceWhenExpandingForSorting()
+ throws Exception {
+ Result result= fMax.run(Request.aClass(TwoTests.class));
+ assertEquals(2, result.getRunCount());
+ }
+
+ public static class TwoOldTests extends TestCase {
+ public void testOne() {
+ }
+
+ public void testTwo() {
+ }
+ }
+
+ @Test
+ public void junit3TestsAreRunOnce() throws Exception {
+ Result result= fMax.run(Request.aClass(TwoOldTests.class),
+ new JUnitCore());
+ assertEquals(2, result.getRunCount());
+ }
+
+ @Test
+ public void filterSingleMethodFromOldTestClass() throws Exception {
+ final Description method= Description.createTestDescription(
+ TwoOldTests.class, "testOne");
+ Filter filter= Filter.matchMethodDescription(method);
+ JUnit38ClassRunner child= new JUnit38ClassRunner(TwoOldTests.class);
+ child.filter(filter);
+ assertEquals(1, child.testCount());
+ }
+
+ @Test
+ public void testCountsStandUpToFiltration() {
+ assertFilterLeavesTestUnscathed(AllTests.class);
+ }
+
+ private void assertFilterLeavesTestUnscathed(Class<?> testClass) {
+ Request oneClass= Request.aClass(testClass);
+ Request filtered= oneClass.filterWith(new Filter() {
+ @Override
+ public boolean shouldRun(Description description) {
+ return true;
+ }
+
+ @Override
+ public String describe() {
+ return "Everything";
+ }
+ });
+
+ int filterCount= filtered.getRunner().testCount();
+ int coreCount= oneClass.getRunner().testCount();
+ assertEquals("Counts match up in " + testClass, coreCount, filterCount);
+ }
+
+ private static class MalformedJUnit38Test {
+ private MalformedJUnit38Test() {
+ }
+
+ @SuppressWarnings("unused")
+ public void testSucceeds() {
+ }
+ }
+
+ @Test
+ public void maxShouldSkipMalformedJUnit38Classes() {
+ Request request= Request.aClass(MalformedJUnit38Test.class);
+ fMax.run(request);
+ }
+
+ public static class MalformedJUnit38TestMethod extends TestCase {
+ @SuppressWarnings("unused")
+ private void testNothing() {
+ }
+ }
+
+ String fMessage= null;
+
+ @Test
+ public void correctErrorFromMalformedTest() {
+ Request request= Request.aClass(MalformedJUnit38TestMethod.class);
+ JUnitCore core= new JUnitCore();
+ Request sorted= fMax.sortRequest(request);
+ Runner runner= sorted.getRunner();
+ Result result= core.run(runner);
+ Failure failure= result.getFailures().get(0);
+ assertThat(failure.toString(), containsString("MalformedJUnit38TestMethod"));
+ assertThat(failure.toString(), containsString("testNothing"));
+ assertThat(failure.toString(), containsString("isn't public"));
+ }
+
+ public static class HalfMalformedJUnit38TestMethod extends TestCase {
+ public void testSomething() {
+ }
+
+ @SuppressWarnings("unused")
+ private void testNothing() {
+ }
+ }
+
+ @Test
+ public void halfMalformed() {
+ assertThat(JUnitCore.runClasses(HalfMalformedJUnit38TestMethod.class)
+ .getFailureCount(), is(1));
+ }
+
+
+ @Test
+ public void correctErrorFromHalfMalformedTest() {
+ Request request= Request.aClass(HalfMalformedJUnit38TestMethod.class);
+ JUnitCore core= new JUnitCore();
+ Request sorted= fMax.sortRequest(request);
+ Runner runner= sorted.getRunner();
+ Result result= core.run(runner);
+ Failure failure= result.getFailures().get(0);
+ assertThat(failure.toString(), containsString("MalformedJUnit38TestMethod"));
+ assertThat(failure.toString(), containsString("testNothing"));
+ assertThat(failure.toString(), containsString("isn't public"));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/parallel/ParallelClassTest.java b/junit4/src/test/java/org/junit/tests/experimental/parallel/ParallelClassTest.java
new file mode 100644
index 0000000..3f9b2f1
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/parallel/ParallelClassTest.java
@@ -0,0 +1,54 @@
+package org.junit.tests.experimental.parallel;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.experimental.ParallelComputer;
+import org.junit.internal.matchers.TypeSafeMatcher;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+
+public class ParallelClassTest {
+
+ public static class Example1 {
+ @Test public void one() throws InterruptedException {
+ Thread.sleep(1000);
+ }
+ }
+ public static class Example2 {
+ @Test public void one() throws InterruptedException {
+ Thread.sleep(1000);
+ }
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses({Example1.class, Example2.class})
+ public static class ExampleSuite {}
+
+ @Test(timeout=1500) public void testsRunInParallel() {
+ long start= System.currentTimeMillis();
+ Result result= JUnitCore.runClasses(ParallelComputer.classes(), Example1.class, Example2.class);
+ assertTrue(result.wasSuccessful());
+ long end= System.currentTimeMillis();
+ assertThat(end - start, greaterThan(999)); // Overhead could be less than half a millisecond
+ }
+
+ private Matcher<Long> greaterThan(final long l) {
+ return new TypeSafeMatcher<Long>() {
+ @Override
+ public boolean matchesSafely(Long item) {
+ return item > l;
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("greater than " + l);
+ }
+ };
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/parallel/ParallelMethodTest.java b/junit4/src/test/java/org/junit/tests/experimental/parallel/ParallelMethodTest.java
new file mode 100644
index 0000000..be5a792
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/parallel/ParallelMethodTest.java
@@ -0,0 +1,44 @@
+package org.junit.tests.experimental.parallel;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.experimental.ParallelComputer;
+import org.junit.internal.matchers.TypeSafeMatcher;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+
+public class ParallelMethodTest {
+ 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, 1900));
+ }
+
+ private Matcher<Long> betweenInclusive(final long min, final long max) {
+ return new TypeSafeMatcher<Long>() {
+ @Override
+ public boolean matchesSafely(Long item) {
+ return item >= min && item <= max;
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("between " + min + " and " + max);
+ }
+ };
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/results/PrintableResultTest.java b/junit4/src/test/java/org/junit/tests/experimental/results/PrintableResultTest.java
new file mode 100644
index 0000000..de715cb
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/results/PrintableResultTest.java
@@ -0,0 +1,51 @@
+package org.junit.tests.experimental.results;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.junit.Assert.assertThat;
+import static org.junit.internal.matchers.StringContains.containsString;
+
+import java.util.Arrays;
+
+import org.junit.experimental.results.PrintableResult;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.Failure;
+
+@RunWith(Theories.class)
+public class PrintableResultTest {
+ @SuppressWarnings("unchecked")
+ @Theory(nullsAccepted= false)
+ public void backTraceHasGoodToString(String descriptionName,
+ final String stackTraceClassName) {
+ Failure failure= new Failure(Description
+ .createSuiteDescription(descriptionName), new Throwable() {
+ private static final long serialVersionUID= 1L;
+
+ @Override
+ public StackTraceElement[] getStackTrace() {
+ return new StackTraceElement[] { new StackTraceElement(
+ stackTraceClassName, "methodName", "fileName", 1) };
+ }
+ });
+
+ assertThat(new PrintableResult(asList(failure)).toString(), allOf(
+ containsString(descriptionName), containsString(stackTraceClassName)));
+ }
+
+ @DataPoint
+ public static String SHELL_POINT= "Shell Point";
+
+ @Theory
+ public void includeMultipleFailures(String secondExceptionName) {
+ PrintableResult backtrace= new PrintableResult(Arrays.asList(
+ new Failure(Description.createSuiteDescription("firstName"),
+ new RuntimeException("firstException")), new Failure(
+ Description.createSuiteDescription("secondName"),
+ new RuntimeException(secondExceptionName))));
+ assertThat(backtrace.toString(), containsString(secondExceptionName));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/results/ResultMatchersTest.java b/junit4/src/test/java/org/junit/tests/experimental/results/ResultMatchersTest.java
new file mode 100644
index 0000000..1263a8c
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/results/ResultMatchersTest.java
@@ -0,0 +1,21 @@
+package org.junit.tests.experimental.results;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.internal.matchers.StringContains.containsString;
+import org.junit.Test;
+import org.junit.experimental.results.ResultMatchers;
+import org.junit.experimental.theories.Theory;
+public class ResultMatchersTest {
+ @Test
+ public void hasFailuresHasGoodDescription() {
+ assertThat(ResultMatchers.failureCountIs(3).toString(),
+ is("has 3 failures"));
+ }
+
+ @Theory
+ public void hasFailuresDescriptionReflectsInput(int i) {
+ assertThat(ResultMatchers.failureCountIs(i).toString(),
+ containsString("" + i));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java
new file mode 100644
index 0000000..1fa3714
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java
@@ -0,0 +1,93 @@
+package org.junit.tests.experimental.rules;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.rules.MethodRule;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+@SuppressWarnings("deprecation")
+public class BlockJUnit4ClassRunnerOverrideTest {
+ public static class FlipBitRule implements MethodRule {
+ public Statement apply(final Statement base, FrameworkMethod method,
+ final Object target) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ target.getClass().getField("flipBit").set(target, true);
+ base.evaluate();
+ }
+ };
+ }
+
+ }
+
+ public static class OverrideRulesRunner extends BlockJUnit4ClassRunner {
+ public OverrideRulesRunner(Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+
+ @Override
+ protected List<MethodRule> rules(Object test) {
+ final LinkedList<MethodRule> methodRules= new LinkedList<MethodRule>(
+ super.rules(test));
+ methodRules.add(new FlipBitRule());
+ return methodRules;
+ }
+ }
+
+ @RunWith(OverrideRulesRunner.class)
+ public static class OverrideRulesTest {
+ public boolean flipBit= false;
+
+ @Test
+ public void testFlipBit() {
+ assertTrue(flipBit);
+ }
+ }
+
+ @Test
+ public void overrideRulesMethod() {
+ assertThat(testResult(OverrideTestRulesTest.class), isSuccessful());
+ }
+
+ public static class OverrideTestRulesRunner extends BlockJUnit4ClassRunner {
+ public OverrideTestRulesRunner(Class<?> klass)
+ throws InitializationError {
+ super(klass);
+ }
+
+ @Override
+ protected List<TestRule> getTestRules(final Object test) {
+ final LinkedList<TestRule> methodRules= new LinkedList<TestRule>(
+ super.getTestRules(test));
+ methodRules.add(new TestRule() {
+ public Statement apply(Statement base, Description description) {
+ return new FlipBitRule().apply(base, null, test);
+ }
+ });
+ return methodRules;
+ }
+ }
+
+ @RunWith(OverrideTestRulesRunner.class)
+ public static class OverrideTestRulesTest extends OverrideRulesTest {
+ }
+
+ @Test
+ public void overrideTestRulesMethod() {
+ assertThat(testResult(OverrideRulesTest.class), isSuccessful());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java
new file mode 100644
index 0000000..70b2d84
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java
@@ -0,0 +1,101 @@
+/**
+ * Created Oct 19, 2009
+ */
+package org.junit.tests.experimental.rules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.rules.ExternalResource;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runners.model.Statement;
+
+/**
+ * Tests to exercise class-level rules.
+ */
+public class ClassRulesTest {
+ public static class Counter extends ExternalResource {
+ public int count = 0;
+
+ @Override
+ protected void before() throws Throwable {
+ count++;
+ }
+ }
+
+ public static class ExampleTestWithClassRule {
+ @ClassRule
+ public static Counter counter= new Counter();
+
+ @Test
+ public void firstTest() {
+ assertEquals(1, counter.count);
+ }
+
+ @Test
+ public void secondTest() {
+ assertEquals(1, counter.count);
+ }
+ }
+
+ @Test
+ public void ruleIsAppliedOnce() {
+ ExampleTestWithClassRule.counter.count= 0;
+ JUnitCore.runClasses(ExampleTestWithClassRule.class);
+ assertEquals(1, ExampleTestWithClassRule.counter.count);
+ }
+
+ public static class SubclassOfTestWithClassRule extends
+ ExampleTestWithClassRule {
+
+ }
+
+ @Test
+ public void ruleIsIntroducedAndEvaluatedOnSubclass() {
+ ExampleTestWithClassRule.counter.count= 0;
+ JUnitCore.runClasses(SubclassOfTestWithClassRule.class);
+ assertEquals(1, ExampleTestWithClassRule.counter.count);
+ }
+
+ public static class CustomCounter implements TestRule {
+ public int count = 0;
+
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ count++;
+ base.evaluate();
+ }
+ };
+ }
+ }
+
+ public static class ExampleTestWithCustomClassRule {
+ @ClassRule
+ public static CustomCounter counter= new CustomCounter();
+
+ @Test
+ public void firstTest() {
+ assertEquals(1, counter.count);
+ }
+
+ @Test
+ public void secondTest() {
+ assertEquals(1, counter.count);
+ }
+ }
+
+
+ @Test
+ public void customRuleIsAppliedOnce() {
+ ExampleTestWithCustomClassRule.counter.count= 0;
+ Result result= JUnitCore.runClasses(ExampleTestWithCustomClassRule.class);
+ assertTrue(result.wasSuccessful());
+ assertEquals(1, ExampleTestWithCustomClassRule.counter.count);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionRuleTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionRuleTest.java
new file mode 100644
index 0000000..b5119cd
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionRuleTest.java
@@ -0,0 +1,232 @@
+package org.junit.tests.experimental.rules;
+
+import static org.hamcrest.CoreMatchers.any;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.matchers.JUnitMatchers.both;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.internal.matchers.TypeSafeMatcher;
+import org.junit.rules.ExpectedException;
+
+public class ExpectedExceptionRuleTest {
+ public static class HasExpectedException {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsNothing() {
+
+ }
+
+ @Test
+ public void throwsNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ throw new NullPointerException();
+ }
+
+ @Test
+ public void throwsNullPointerExceptionWithMessage() {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("happened?");
+ throw new NullPointerException("What happened?");
+ }
+ }
+
+ @Test
+ public void expectedExceptionPasses() {
+ assertThat(testResult(HasExpectedException.class), isSuccessful());
+ }
+
+ public static class HasWrongExpectedException {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Test
+ public void unExpectedExceptionFails() {
+ assertThat(
+ testResult(HasWrongExpectedException.class),
+ hasSingleFailureContaining("Expected: an instance of java.lang.NullPointerException"));
+ }
+
+ public static class HasWrongMessage {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsNullPointerException() {
+ thrown.expectMessage("expectedMessage");
+ throw new IllegalArgumentException("actualMessage");
+ }
+ }
+
+ @Test
+ public void wrongMessageFails() {
+ assertThat(
+ testResult(HasWrongMessage.class), both(
+ hasSingleFailureContaining("expectedMessage")).and(
+ hasSingleFailureContaining("actualMessage")));
+ }
+
+ public static class WronglyExpectsException {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void doesntThrowNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ }
+ }
+
+ @Test
+ public void failsIfExceptionNeverComes() {
+ assertThat(
+ testResult(WronglyExpectsException.class),
+ hasSingleFailureContaining("Expected test to throw an instance of java.lang.NullPointerException"));
+ }
+
+ public static class WronglyExpectsExceptionMessage {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void doesntThrowAnything() {
+ thrown.expectMessage("anything!");
+ }
+ }
+
+ @Test
+ public void failsIfExceptionMessageNeverComes() {
+ assertThat(
+ testResult(WronglyExpectsExceptionMessage.class),
+ hasSingleFailureContaining("Expected test to throw exception with message a string containing \"anything!\""));
+ }
+
+ public static class ExpectsSubstring {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsMore() {
+ thrown.expectMessage("anything!");
+ throw new NullPointerException(
+ "This could throw anything! (as long as it has the right substring)");
+ }
+ }
+
+ @Test
+ public void passesWithSubstringMethod() {
+ assertThat(testResult(ExpectsSubstring.class), isSuccessful());
+ }
+
+ public static class ExpectsSubstringNullMessage {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsMore() {
+ thrown.expectMessage("anything!");
+ throw new NullPointerException();
+ }
+ }
+
+ @Test
+ public void failsWithNullExceptionMessage() {
+ assertThat(testResult(ExpectsSubstringNullMessage.class),
+ hasSingleFailureContaining("NullPointerException"));
+ }
+
+ public static class ExpectsMessageMatcher {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsMore() {
+ thrown.expectMessage(startsWith("Ack"));
+ throw new NullPointerException("Ack!");
+ }
+ }
+
+ @Test
+ public void succeedsWithMessageMatcher() {
+ assertThat(testResult(ExpectsMessageMatcher.class), isSuccessful());
+ }
+
+ public static class ExpectedMessageMatcherFails {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsMore() {
+ thrown.expectMessage(startsWith("Wrong start"));
+ throw new NullPointerException("Back!");
+ }
+ }
+
+
+
+ private static Matcher<String> startsWith(final String prefix) {
+ return new TypeSafeMatcher<String>() {
+ public void describeTo(Description description) {
+ description.appendText("starts with ");
+ description.appendText(prefix);
+ }
+
+ @Override
+ public boolean matchesSafely(String item) {
+ return item.startsWith(prefix);
+ }
+ };
+ }
+
+ @Test
+ public void failsWithMatcher() {
+ assertThat(testResult(ExpectedMessageMatcherFails.class),
+ hasSingleFailureContaining("Wrong start"));
+ }
+
+ public static class ExpectsMatcher {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsMore() {
+ thrown.expect(any(Throwable.class));
+ throw new NullPointerException("Ack!");
+ }
+ }
+
+ @Test
+ public void succeedsWithMatcher() {
+ assertThat(testResult(ExpectsMatcher.class), isSuccessful());
+ }
+
+ public static class ExpectsMultipleMatchers {
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+ @Test
+ public void throwsMore() {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Ack!");
+ throw new NullPointerException("Ack!");
+ }
+ }
+
+ @Test
+ public void failsWithMultipleMatchers() {
+ assertThat(testResult(ExpectsMultipleMatchers.class),
+ hasSingleFailureContaining("IllegalArgumentException"));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/ExternalResourceRuleTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/ExternalResourceRuleTest.java
new file mode 100644
index 0000000..48cbeb9
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/ExternalResourceRuleTest.java
@@ -0,0 +1,37 @@
+package org.junit.tests.experimental.rules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExternalResource;
+
+public class ExternalResourceRuleTest {
+ private static String callSequence;
+
+ public static class UsesExternalResource {
+ @Rule public ExternalResource resource = new ExternalResource() {
+ @Override
+ protected void before() throws Throwable {
+ callSequence += "before ";
+ };
+
+ @Override
+ protected void after() {
+ callSequence += "after ";
+ };
+ };
+
+ @Test public void testFoo() {
+ callSequence += "test ";
+ }
+ }
+
+ @Test public void externalResourceGeneratesCorrectSequence() {
+ callSequence= "";
+ assertThat(testResult(UsesExternalResource.class), isSuccessful());
+ assertEquals("before test after ", callSequence);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java b/junit4/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java
new file mode 100644
index 0000000..98251b9
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java
@@ -0,0 +1,32 @@
+package org.junit.tests.experimental.rules;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+class LoggingTestWatcher extends TestWatcher {
+ private final StringBuilder log;
+
+ LoggingTestWatcher(StringBuilder log) {
+ this.log= log;
+ }
+
+ @Override
+ protected void succeeded(Description description) {
+ log.append("succeeded ");
+ }
+
+ @Override
+ protected void failed(Throwable e, Description description) {
+ log.append("failed ");
+ }
+
+ @Override
+ protected void starting(Description description) {
+ log.append("starting ");
+ }
+
+ @Override
+ protected void finished(Description description) {
+ log.append("finished ");
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java
new file mode 100644
index 0000000..116953e
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java
@@ -0,0 +1,275 @@
+package org.junit.tests.experimental.rules;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.rules.MethodRule;
+import org.junit.rules.TestName;
+import org.junit.rules.TestWatchman;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+@SuppressWarnings("deprecation")
+public class MethodRulesTest {
+ private static boolean wasRun;
+
+ public static class ExampleTest {
+ @Rule
+ public MethodRule example= new MethodRule() {
+ public Statement apply(final Statement base,
+ FrameworkMethod method, Object target) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ wasRun= true;
+ base.evaluate();
+ };
+ };
+ }
+ };
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void ruleIsIntroducedAndEvaluated() {
+ wasRun= false;
+ JUnitCore.runClasses(ExampleTest.class);
+ assertTrue(wasRun);
+ }
+
+ public static class SonOfExampleTest extends ExampleTest {
+
+ }
+
+ @Test
+ public void ruleIsIntroducedAndEvaluatedOnSubclass() {
+ wasRun= false;
+ JUnitCore.runClasses(SonOfExampleTest.class);
+ assertTrue(wasRun);
+ }
+
+ private static int runCount;
+
+ public static class MultipleRuleTest {
+ private static class Increment implements MethodRule {
+ public Statement apply(final Statement base,
+ FrameworkMethod method, Object target) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ runCount++;
+ base.evaluate();
+ };
+ };
+ }
+ }
+
+ @Rule
+ public MethodRule incrementor1= new Increment();
+
+ @Rule
+ public MethodRule incrementor2= new Increment();
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void multipleRulesAreRun() {
+ runCount= 0;
+ JUnitCore.runClasses(MultipleRuleTest.class);
+ assertEquals(2, runCount);
+ }
+
+ public static class NoRulesTest {
+ public int x;
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void ignoreNonRules() {
+ Result result= JUnitCore.runClasses(NoRulesTest.class);
+ assertEquals(0, result.getFailureCount());
+ }
+
+ private static String log;
+
+ public static class OnFailureTest {
+ @Rule
+ public MethodRule watchman= new TestWatchman() {
+ @Override
+ public void failed(Throwable e, FrameworkMethod method) {
+ log+= method.getName() + " " + e.getClass().getSimpleName();
+ }
+ };
+
+ @Test
+ public void nothing() {
+ fail();
+ }
+ }
+
+ @Test
+ public void onFailure() {
+ log= "";
+ Result result= JUnitCore.runClasses(OnFailureTest.class);
+ assertEquals("nothing AssertionError", log);
+ assertEquals(1, result.getFailureCount());
+ }
+
+ public static class WatchmanTest {
+ private static String watchedLog;
+
+ @Rule
+ public MethodRule watchman= new TestWatchman() {
+ @Override
+ public void failed(Throwable e, FrameworkMethod method) {
+ watchedLog+= method.getName() + " "
+ + e.getClass().getSimpleName() + "\n";
+ }
+
+ @Override
+ public void succeeded(FrameworkMethod method) {
+ watchedLog+= method.getName() + " " + "success!\n";
+ }
+ };
+
+ @Test
+ public void fails() {
+ fail();
+ }
+
+ @Test
+ public void succeeds() {
+ }
+ }
+
+ @Test
+ public void succeeded() {
+ WatchmanTest.watchedLog= "";
+ JUnitCore.runClasses(WatchmanTest.class);
+ assertThat(WatchmanTest.watchedLog, containsString("fails AssertionError"));
+ assertThat(WatchmanTest.watchedLog, containsString("succeeds success!"));
+ }
+
+ public static class BeforesAndAfters {
+ private static String watchedLog;
+
+ @Before public void before() {
+ watchedLog+= "before ";
+ }
+
+ @Rule
+ public MethodRule watchman= new TestWatchman() {
+ @Override
+ public void starting(FrameworkMethod method) {
+ watchedLog+= "starting ";
+ }
+
+ @Override
+ public void finished(FrameworkMethod method) {
+ watchedLog+= "finished ";
+ }
+
+ @Override
+ public void succeeded(FrameworkMethod method) {
+ watchedLog+= "succeeded ";
+ }
+ };
+
+ @After public void after() {
+ watchedLog+= "after ";
+ }
+
+ @Test
+ public void succeeds() {
+ watchedLog+= "test ";
+ }
+ }
+
+ @Test
+ public void beforesAndAfters() {
+ BeforesAndAfters.watchedLog= "";
+ JUnitCore.runClasses(BeforesAndAfters.class);
+ assertThat(BeforesAndAfters.watchedLog, is("starting before test after succeeded finished "));
+ }
+
+ public static class WrongTypedField {
+ @Rule public int x = 5;
+ @Test public void foo() {}
+ }
+
+ @Test public void validateWrongTypedField() {
+ assertThat(testResult(WrongTypedField.class),
+ hasSingleFailureContaining("must implement MethodRule"));
+ }
+
+ public static class SonOfWrongTypedField extends WrongTypedField {
+
+ }
+
+ @Test public void validateWrongTypedFieldInSuperclass() {
+ assertThat(testResult(SonOfWrongTypedField.class),
+ hasSingleFailureContaining("must implement MethodRule"));
+ }
+
+ public static class PrivateRule {
+ @SuppressWarnings("unused")
+ @Rule private TestRule rule = new TestName();
+ @Test public void foo() {}
+ }
+
+ @Test public void validatePrivateRule() {
+ assertThat(testResult(PrivateRule.class),
+ hasSingleFailureContaining("must be public"));
+ }
+
+ public static class CustomTestName implements TestRule {
+ public String name = null;
+
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ name = description.getMethodName();
+ base.evaluate();
+ }
+ };
+ }
+ }
+
+ public static class UsesCustomMethodRule {
+ @Rule public CustomTestName counter = new CustomTestName();
+ @Test public void foo() {
+ assertEquals("foo", counter.name);
+ }
+ }
+
+ @Test public void useCustomMethodRule() {
+ assertThat(testResult(UsesCustomMethodRule.class), isSuccessful());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/NameRulesTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/NameRulesTest.java
new file mode 100644
index 0000000..4f15bde
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/NameRulesTest.java
@@ -0,0 +1,50 @@
+package org.junit.tests.experimental.rules;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+@RunWith(Enclosed.class)
+public class NameRulesTest {
+ public static class TestNames {
+ @Rule
+ public TestName name= new TestName();
+
+ @Test
+ public void testA() {
+ assertEquals("testA", name.getMethodName());
+ }
+
+ @Test
+ public void testB() {
+ assertEquals("testB", name.getMethodName());
+ }
+ }
+
+ public static class BeforeAndAfterTest {
+ @Rule
+ public TestName name= new TestName();
+
+ private final String expectedName= "x";
+
+ @Before
+ public void setUp() {
+ assertEquals(expectedName, name.getMethodName());
+ }
+
+ @Test
+ public void x() {
+ assertEquals(expectedName, name.getMethodName());
+ }
+
+ @After
+ public void tearDown() {
+ assertEquals(expectedName, name.getMethodName());
+ }
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/RuleChainTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/RuleChainTest.java
new file mode 100644
index 0000000..e1ea4c5
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/RuleChainTest.java
@@ -0,0 +1,60 @@
+package org.junit.tests.experimental.rules;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.rules.RuleChain.outerRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+public class RuleChainTest {
+ private static final List<String> LOG= new ArrayList<String>();
+
+ private static class LoggingRule extends TestWatcher {
+ private final String label;
+
+ public LoggingRule(String label) {
+ this.label= label;
+ }
+
+ @Override
+ protected void starting(Description description) {
+ LOG.add("starting " + label);
+ }
+
+ @Override
+ protected void finished(Description description) {
+ LOG.add("finished " + label);
+ }
+ }
+
+ public static class UseRuleChain {
+ @Rule
+ public final RuleChain chain= outerRule(new LoggingRule("outer rule"))
+ .around(new LoggingRule("middle rule")).around(
+ new LoggingRule("inner rule"));
+
+ @Test
+ public void example() {
+ assertTrue(true);
+ }
+ }
+
+ @Test
+ public void executeRulesInCorrectOrder() throws Exception {
+ testResult(UseRuleChain.class);
+ List<String> expectedLog= asList("starting outer rule",
+ "starting middle rule", "starting inner rule",
+ "finished inner rule", "finished middle rule",
+ "finished outer rule");
+ assertEquals(expectedLog, LOG);
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java
new file mode 100644
index 0000000..fa6dcbf
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/RuleFieldValidatorTest.java
@@ -0,0 +1,96 @@
+package org.junit.tests.experimental.rules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_VALIDATOR;
+import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_VALIDATOR;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.MethodRule;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+@SuppressWarnings("deprecation")
+public class RuleFieldValidatorTest {
+ private final List<Throwable> errors = new ArrayList<Throwable>();
+
+ @Test
+ public void rejectProtectedClassRule() {
+ TestClass target= new TestClass(TestWithProtectedClassRule.class);
+ CLASS_RULE_VALIDATOR.validate(target, errors);
+ assertOneErrorWithMessage("The @ClassRule 'temporaryFolder' must be public.");
+ }
+
+ public static class TestWithProtectedClassRule {
+ @ClassRule
+ protected static TestRule temporaryFolder = new TemporaryFolder();
+ }
+
+ @Test
+ public void rejectNonStaticClassRule() {
+ TestClass target= new TestClass(TestWithNonStaticClassRule.class);
+ CLASS_RULE_VALIDATOR.validate(target, errors);
+ assertOneErrorWithMessage("The @ClassRule 'temporaryFolder' must be static.");
+ }
+
+ public static class TestWithNonStaticClassRule {
+ @ClassRule
+ public TestRule temporaryFolder = new TemporaryFolder();
+ }
+
+ @Test
+ public void acceptNonStaticTestRule() {
+ TestClass target= new TestClass(TestWithNonStaticTestRule.class);
+ RULE_VALIDATOR.validate(target, errors);
+ assertNumberOfErrors(0);
+ }
+
+ public static class TestWithNonStaticTestRule {
+ @Rule
+ public TestRule temporaryFolder = new TemporaryFolder();
+ }
+
+ @Test
+ public void acceptMethodRule() throws Exception {
+ TestClass target= new TestClass(TestWithMethodRule.class);
+ RULE_VALIDATOR.validate(target, errors);
+ assertNumberOfErrors(0);
+ }
+
+ public static class TestWithMethodRule {
+ @Rule
+ public MethodRule temporaryFolder = new MethodRule(){
+ public Statement apply(Statement base, FrameworkMethod method,
+ Object target) {
+ return null;
+ }};
+ }
+
+ @Test
+ public void rejectArbitraryObjectWithRuleAnnotation() throws Exception {
+ TestClass target= new TestClass(TestWithArbitraryObjectWithRuleAnnotation.class);
+ RULE_VALIDATOR.validate(target, errors);
+ assertOneErrorWithMessage("The @Rule 'arbitraryObject' must implement MethodRule or TestRule.");
+ }
+
+ public static class TestWithArbitraryObjectWithRuleAnnotation {
+ @Rule
+ public Object arbitraryObject = 1;
+ }
+
+ private void assertOneErrorWithMessage(String message) {
+ assertNumberOfErrors(1);
+ assertEquals("Wrong error message:", message, errors.get(0).getMessage());
+ }
+
+ private void assertNumberOfErrors(int numberOfErrors) {
+ assertEquals("Wrong number of errors:", numberOfErrors, errors.size());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java
new file mode 100644
index 0000000..200d51e
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java
@@ -0,0 +1,200 @@
+package org.junit.tests.experimental.rules;
+
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.failureCountIs;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class TempFolderRuleTest {
+ private static File[] createdFiles= new File[20];
+
+ public static class HasTempFolder {
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testUsingTempFolder() throws IOException {
+ createdFiles[0]= folder.newFile("myfile.txt");
+ assertTrue(createdFiles[0].exists());
+ }
+ }
+
+ @Test
+ public void tempFolderIsDeleted() {
+ assertThat(testResult(HasTempFolder.class), isSuccessful());
+ assertFalse(createdFiles[0].exists());
+ }
+
+ public static class CreatesSubFolder {
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testUsingTempFolder() throws IOException {
+ String subfolder = "subfolder";
+ String filename = "a.txt";
+ createdFiles[0]= folder.newFolder(subfolder);
+ new File(createdFiles[0], filename).createNewFile();
+
+ File expectedFile = new File(folder.getRoot(), join(subfolder, filename));
+
+ assertTrue(expectedFile.exists());
+ }
+
+ @Test
+ public void testUsingTempTreeFolders() throws IOException {
+ String subfolder = "subfolder";
+ String anotherfolder = "anotherfolder";
+ String filename = "a.txt";
+
+ createdFiles[0] = folder.newFolder(subfolder, anotherfolder);
+ new File(createdFiles[0], filename).createNewFile();
+
+ File expectedFile = new File(folder.getRoot(), join(subfolder, anotherfolder, filename));
+
+ assertTrue(expectedFile.exists());
+ }
+
+ private String join(String... folderNames) {
+ StringBuilder path = new StringBuilder();
+ for (String folderName : folderNames) {
+ path.append(File.separator).append(folderName);
+ }
+ return path.toString();
+ }
+ }
+
+ @Test
+ public void subFolderIsDeleted() {
+ assertThat(testResult(CreatesSubFolder.class), isSuccessful());
+ assertFalse(createdFiles[0].exists());
+ }
+
+ public static class CreatesRandomSubFolders {
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testUsingRandomTempFolders() throws IOException {
+ for (int i= 0; i < 20; i++) {
+ File newFolder= folder.newFolder();
+ assertThat(Arrays.asList(createdFiles), not(hasItem(newFolder)));
+ createdFiles[i]= newFolder;
+ new File(newFolder, "a.txt").createNewFile();
+ assertTrue(newFolder.exists());
+ }
+ }
+ }
+
+ @Test
+ public void randomSubFoldersAreDeleted() {
+ assertThat(testResult(CreatesRandomSubFolders.class), isSuccessful());
+ for (File f : createdFiles) {
+ assertFalse(f.exists());
+ }
+ }
+
+ public static class CreatesRandomFiles {
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testUsingRandomTempFiles() throws IOException {
+ for (int i= 0; i < 20; i++) {
+ File newFile= folder.newFile();
+ assertThat(Arrays.asList(createdFiles), not(hasItem(newFile)));
+ createdFiles[i]= newFile;
+ assertTrue(newFile.exists());
+ }
+ }
+ }
+
+ @Test
+ public void randomFilesAreDeleted() {
+ assertThat(testResult(CreatesRandomFiles.class), isSuccessful());
+ for (File f : createdFiles) {
+ assertFalse(f.exists());
+ }
+ }
+
+ @Test
+ public void recursiveDeleteFolderWithOneElement() throws IOException {
+ TemporaryFolder folder= new TemporaryFolder();
+ folder.create();
+ File file= folder.newFile("a");
+ folder.delete();
+ assertFalse(file.exists());
+ assertFalse(folder.getRoot().exists());
+ }
+
+ @Test
+ public void recursiveDeleteFolderWithOneRandomElement() throws IOException {
+ TemporaryFolder folder= new TemporaryFolder();
+ folder.create();
+ File file= folder.newFile();
+ folder.delete();
+ assertFalse(file.exists());
+ assertFalse(folder.getRoot().exists());
+ }
+
+ @Test
+ public void recursiveDeleteFolderWithZeroElements() throws IOException {
+ TemporaryFolder folder= new TemporaryFolder();
+ folder.create();
+ folder.delete();
+ assertFalse(folder.getRoot().exists());
+ }
+
+ private static final String GET_ROOT_DUMMY= "dummy-getRoot";
+
+ private static final String NEW_FILE_DUMMY= "dummy-newFile";
+
+ private static final String NEW_FOLDER_DUMMY= "dummy-newFolder";
+
+ public static class IncorrectUsage {
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testGetRoot() throws IOException {
+ new File(folder.getRoot(), GET_ROOT_DUMMY).createNewFile();
+ }
+
+ @Test
+ public void testNewFile() throws IOException {
+ folder.newFile(NEW_FILE_DUMMY);
+ }
+
+ @Test
+ public void testNewFolder() {
+ folder.newFolder(NEW_FOLDER_DUMMY);
+ }
+ }
+
+ @Test
+ public void incorrectUsageWithoutApplyingTheRuleShouldNotPolluteTheCurrentWorkingDirectory() {
+ assertThat(testResult(IncorrectUsage.class), failureCountIs(3));
+ assertFalse("getRoot should have failed early", new File(GET_ROOT_DUMMY).exists());
+ assertFalse("newFile should have failed early", new File(NEW_FILE_DUMMY).exists());
+ assertFalse("newFolder should have failed early", new File(NEW_FOLDER_DUMMY).exists());
+ }
+
+ @After
+ public void cleanCurrentWorkingDirectory() {
+ new File(GET_ROOT_DUMMY).delete();
+ new File(NEW_FILE_DUMMY).delete();
+ new File(NEW_FOLDER_DUMMY).delete();
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
new file mode 100644
index 0000000..167eb20
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java
@@ -0,0 +1,289 @@
+package org.junit.tests.experimental.rules;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.rules.TestRule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+public class TestRuleTest {
+ private static boolean wasRun;
+
+ public static class ExampleTest {
+ @Rule
+ public TestRule example= new TestRule() {
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ wasRun= true;
+ base.evaluate();
+ };
+ };
+ }
+ };
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void ruleIsIntroducedAndEvaluated() {
+ wasRun= false;
+ JUnitCore.runClasses(ExampleTest.class);
+ assertTrue(wasRun);
+ }
+
+ @SuppressWarnings("deprecation")
+ public static class BothKindsOfRule implements TestRule, org.junit.rules.MethodRule {
+ public int applications = 0;
+
+ public Statement apply(Statement base, FrameworkMethod method,
+ Object target) {
+ applications++;
+ return base;
+ }
+
+ public Statement apply(Statement base, Description description) {
+ applications++;
+ return base;
+ }
+ }
+
+ public static class OneFieldTwoKindsOfRule {
+ @Rule public BothKindsOfRule both = new BothKindsOfRule();
+
+ @Test public void onlyOnce() {
+ assertEquals(1, both.applications);
+ }
+ }
+
+
+ @Test
+ public void onlyApplyOnceEvenIfImplementsBothInterfaces() {
+ assertTrue(JUnitCore.runClasses(OneFieldTwoKindsOfRule.class).wasSuccessful());
+ }
+
+ public static class SonOfExampleTest extends ExampleTest {
+
+ }
+
+ @Test
+ public void ruleIsIntroducedAndEvaluatedOnSubclass() {
+ wasRun= false;
+ JUnitCore.runClasses(SonOfExampleTest.class);
+ assertTrue(wasRun);
+ }
+
+ private static int runCount;
+
+ public static class MultipleRuleTest {
+ private static class Increment implements TestRule {
+ public Statement apply(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ runCount++;
+ base.evaluate();
+ };
+ };
+ }
+ }
+
+ @Rule
+ public TestRule incrementor1= new Increment();
+
+ @Rule
+ public TestRule incrementor2= new Increment();
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void multipleRulesAreRun() {
+ runCount= 0;
+ JUnitCore.runClasses(MultipleRuleTest.class);
+ assertEquals(2, runCount);
+ }
+
+ public static class NoRulesTest {
+ public int x;
+
+ @Test
+ public void nothing() {
+
+ }
+ }
+
+ @Test
+ public void ignoreNonRules() {
+ Result result= JUnitCore.runClasses(NoRulesTest.class);
+ assertEquals(0, result.getFailureCount());
+ }
+
+ private static String log;
+
+ public static class OnFailureTest {
+ @Rule
+ public TestRule watcher= new TestWatcher() {
+ @Override
+ protected void failed(Throwable e, Description description) {
+ log+= description + " " + e.getClass().getSimpleName();
+ }
+ };
+
+ @Test
+ public void nothing() {
+ fail();
+ }
+ }
+
+ @Test
+ public void onFailure() {
+ log= "";
+ Result result= JUnitCore.runClasses(OnFailureTest.class);
+ assertEquals(String.format("nothing(%s) AssertionError", OnFailureTest.class.getName()), log);
+ assertEquals(1, result.getFailureCount());
+ }
+
+ public static class WatchmanTest {
+ private static String watchedLog;
+
+ @Rule
+ public TestRule watcher= new TestWatcher() {
+ @Override
+ protected void failed(Throwable e, Description description) {
+ watchedLog+= description + " "
+ + e.getClass().getSimpleName() + "\n";
+ }
+
+ @Override
+ protected void succeeded(Description description) {
+ watchedLog+= description + " " + "success!\n";
+ }
+ };
+
+ @Test
+ public void fails() {
+ fail();
+ }
+
+ @Test
+ public void succeeds() {
+ }
+ }
+
+ @Test
+ public void succeeded() {
+ WatchmanTest.watchedLog= "";
+ JUnitCore.runClasses(WatchmanTest.class);
+ assertThat(WatchmanTest.watchedLog, containsString(String.format("fails(%s) AssertionError", WatchmanTest.class.getName())));
+ assertThat(WatchmanTest.watchedLog, containsString(String.format("succeeds(%s) success!", WatchmanTest.class.getName())));
+ }
+
+ public static class BeforesAndAfters {
+ private static StringBuilder watchedLog= new StringBuilder();
+
+ @Before
+ public void before() {
+ watchedLog.append("before ");
+ }
+
+ @Rule
+ public TestRule watcher= new LoggingTestWatcher(watchedLog);
+
+ @After
+ public void after() {
+ watchedLog.append("after ");
+ }
+
+ @Test
+ public void succeeds() {
+ watchedLog.append("test ");
+ }
+ }
+
+ @Test
+ public void beforesAndAfters() {
+ BeforesAndAfters.watchedLog= new StringBuilder();
+ JUnitCore.runClasses(BeforesAndAfters.class);
+ assertThat(BeforesAndAfters.watchedLog.toString(),
+ is("starting before test after succeeded finished "));
+ }
+
+ public static class WrongTypedField {
+ @Rule public int x = 5;
+ @Test public void foo() {}
+ }
+
+ @Test public void validateWrongTypedField() {
+ assertThat(testResult(WrongTypedField.class),
+ hasSingleFailureContaining("must implement MethodRule"));
+ }
+
+ public static class SonOfWrongTypedField extends WrongTypedField {
+
+ }
+
+ @Test public void validateWrongTypedFieldInSuperclass() {
+ assertThat(testResult(SonOfWrongTypedField.class),
+ hasSingleFailureContaining("must implement MethodRule"));
+ }
+
+ public static class PrivateRule {
+ @SuppressWarnings("unused")
+ @Rule private TestRule rule = new TestName();
+ @Test public void foo() {}
+ }
+
+ @Test public void validatePrivateRule() {
+ assertThat(testResult(PrivateRule.class),
+ hasSingleFailureContaining("must be public"));
+ }
+
+ public static class CustomTestName implements TestRule {
+ public String name = null;
+
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ name = description.getMethodName();
+ base.evaluate();
+ }
+ };
+ }
+ }
+
+ public static class UsesCustomMethodRule {
+ @Rule public CustomTestName counter = new CustomTestName();
+ @Test public void foo() {
+ assertEquals("foo", counter.name);
+ }
+ }
+
+ @Test public void useCustomMethodRule() {
+ assertThat(testResult(UsesCustomMethodRule.class), isSuccessful());
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java
new file mode 100644
index 0000000..19ac3e6
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java
@@ -0,0 +1,52 @@
+package org.junit.tests.experimental.rules;
+
+import static junit.framework.Assert.fail;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.runner.JUnitCore.runClasses;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+
+public class TestWatcherTest {
+ public static class ViolatedAssumptionTest {
+ private static StringBuilder watchedLog= new StringBuilder();
+
+ @Rule
+ public TestRule watcher= new LoggingTestWatcher(watchedLog);
+
+ @Test
+ public void succeeds() {
+ assumeTrue(false);
+ }
+ }
+
+ @Test
+ public void neitherLogSuccessNorFailedForViolatedAssumption() {
+ ViolatedAssumptionTest.watchedLog= new StringBuilder();
+ runClasses(ViolatedAssumptionTest.class);
+ assertThat(ViolatedAssumptionTest.watchedLog.toString(),
+ is("starting finished "));
+ }
+
+ public static class FailingTest {
+ private static StringBuilder watchedLog= new StringBuilder();
+
+ @Rule
+ public TestRule watcher= new LoggingTestWatcher(watchedLog);
+
+ @Test
+ public void succeeds() {
+ fail();
+ }
+ }
+
+ @Test
+ public void logFailingTest() {
+ FailingTest.watchedLog= new StringBuilder();
+ runClasses(FailingTest.class);
+ assertThat(FailingTest.watchedLog.toString(),
+ is("starting failed finished "));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java
new file mode 100644
index 0000000..9ef22cb
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java
@@ -0,0 +1,72 @@
+package org.junit.tests.experimental.rules;
+
+import static junit.framework.Assert.fail;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.runner.JUnitCore.runClasses;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestWatchman;
+import org.junit.runners.model.FrameworkMethod;
+
+@SuppressWarnings("deprecation")
+public class TestWatchmanTest {
+ public static class ViolatedAssumptionTest {
+ @Rule
+ public static LoggingTestWatchman watchman= new LoggingTestWatchman();
+
+ @Test
+ public void succeeds() {
+ assumeTrue(false);
+ }
+ }
+
+ @Test
+ public void neitherLogSuccessNorFailedForViolatedAssumption() {
+ runClasses(ViolatedAssumptionTest.class);
+ assertThat(ViolatedAssumptionTest.watchman.log.toString(),
+ is("starting finished "));
+ }
+
+ public static class FailingTest {
+ @Rule
+ public static LoggingTestWatchman watchman= new LoggingTestWatchman();
+
+ @Test
+ public void succeeds() {
+ fail();
+ }
+ }
+
+ @Test
+ public void logFailingTest() {
+ runClasses(FailingTest.class);
+ assertThat(FailingTest.watchman.log.toString(),
+ is("starting failed finished "));
+ }
+
+ private static class LoggingTestWatchman extends TestWatchman {
+ private final StringBuilder log= new StringBuilder();
+
+ @Override
+ public void succeeded(FrameworkMethod method) {
+ log.append("succeeded ");
+ }
+
+ @Override
+ public void failed(Throwable e, FrameworkMethod method) {
+ log.append("failed ");
+ }
+
+ @Override
+ public void starting(FrameworkMethod method) {
+ log.append("starting ");
+ }
+
+ @Override
+ public void finished(FrameworkMethod method) {
+ log.append("finished ");
+ }
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java
new file mode 100644
index 0000000..28d3553
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java
@@ -0,0 +1,39 @@
+package org.junit.tests.experimental.rules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+
+public class TimeoutRuleTest {
+ public static class HasGlobalTimeout {
+ public static String log;
+
+ @Rule public TestRule globalTimeout = new Timeout(20);
+
+ @Test public void testInfiniteLoop1() {
+ log+= "ran1";
+ for(;;) {}
+ }
+
+ @Test public void testInfiniteLoop2() {
+ log+= "ran2";
+ for(;;) {}
+ }
+ }
+
+ @Ignore("For gump, for now")
+ @Test(timeout=100) public void globalTimeoutAvoidsInfiniteLoop() {
+ HasGlobalTimeout.log = "";
+ Result result= JUnitCore.runClasses(HasGlobalTimeout.class);
+ assertEquals(2, result.getFailureCount());
+ assertThat(HasGlobalTimeout.log, containsString("ran1"));
+ assertThat(HasGlobalTimeout.log, containsString("ran2"));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java b/junit4/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
new file mode 100644
index 0000000..ef75174
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java
@@ -0,0 +1,133 @@
+package org.junit.tests.experimental.rules;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.hasFailureContaining;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+
+import java.util.concurrent.Callable;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.results.PrintableResult;
+import org.junit.rules.ErrorCollector;
+import org.junit.rules.Verifier;
+
+public class VerifierRuleTest {
+ public static class UsesErrorCollector {
+ @Rule
+ public ErrorCollector collector= new ErrorCollector();
+
+ @Test public void example() {
+ collector.addError(new Throwable("message"));
+ }
+ }
+
+ @Test public void usedErrorCollectorShouldFail() {
+ assertThat(testResult(UsesErrorCollector.class), hasFailureContaining("message"));
+ }
+
+ public static class UsesErrorCollectorTwice {
+ @Rule
+ public ErrorCollector collector= new ErrorCollector();
+
+ @Test public void example() {
+ collector.addError(new Throwable("first thing went wrong"));
+ collector.addError(new Throwable("second thing went wrong"));
+ }
+ }
+
+ @Test public void usedErrorCollectorTwiceShouldFail() {
+ PrintableResult testResult= testResult(UsesErrorCollectorTwice.class);
+ assertThat(testResult, hasFailureContaining("first thing went wrong"));
+ assertThat(testResult, hasFailureContaining("second thing went wrong"));
+ }
+
+ public static class UsesErrorCollectorCheckThat {
+ @Rule
+ public ErrorCollector collector= new ErrorCollector();
+
+ @Test public void example() {
+ collector.checkThat(3, is(4));
+ collector.checkThat(5, is(6));
+ collector.checkThat("reason 1", 7, is(8));
+ collector.checkThat("reason 2", 9, is(16));
+ }
+ }
+
+ @Test public void usedErrorCollectorCheckThatShouldFail() {
+ PrintableResult testResult= testResult(UsesErrorCollectorCheckThat.class);
+ assertThat(testResult, hasFailureContaining("got: <3>"));
+ assertThat(testResult, hasFailureContaining("got: <5>"));
+ assertThat(testResult, hasFailureContaining("reason 1"));
+ assertThat(testResult, hasFailureContaining("got: <7>"));
+ assertThat(testResult, hasFailureContaining("reason 2"));
+ assertThat(testResult, hasFailureContaining("got: <9>"));
+ }
+
+ public static class UsesErrorCollectorCheckSucceeds {
+ @Rule
+ public ErrorCollector collector= new ErrorCollector();
+
+ @Test public void example() {
+ collector.checkSucceeds(new Callable<Object>() {
+ public Object call() throws Exception {
+ throw new RuntimeException("first!");
+ }
+ });
+ collector.checkSucceeds(new Callable<Object>() {
+ public Object call() throws Exception {
+ throw new RuntimeException("second!");
+ }
+ });
+ }
+ }
+
+ @Test public void usedErrorCollectorCheckSucceedsShouldFail() {
+ PrintableResult testResult= testResult(UsesErrorCollectorCheckSucceeds.class);
+ assertThat(testResult, hasFailureContaining("first!"));
+ assertThat(testResult, hasFailureContaining("second!"));
+ }
+
+ public static class UsesErrorCollectorCheckSucceedsPasses {
+ @Rule
+ public ErrorCollector collector= new ErrorCollector();
+
+ @Test public void example() {
+ assertEquals(3, collector.checkSucceeds(new Callable<Object>() {
+ public Object call() throws Exception {
+ return 3;
+ }
+ }));
+ }
+ }
+
+ @Test public void usedErrorCollectorCheckSucceedsShouldPass() {
+ PrintableResult testResult= testResult(UsesErrorCollectorCheckSucceedsPasses.class);
+ assertThat(testResult, isSuccessful());
+ }
+
+ private static String sequence;
+
+ public static class UsesVerifier {
+ @Rule
+ public Verifier collector= new Verifier() {
+ @Override
+ protected void verify() {
+ sequence+= "verify ";
+ }
+ };
+
+ @Test public void example() {
+ sequence+= "test ";
+ }
+ }
+
+ @Test public void verifierRunsAfterTest() {
+ sequence = "";
+ assertThat(testResult(UsesVerifier.class), isSuccessful());
+ assertEquals("test verify ", sequence);
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/AllMembersSupplierTest.java b/junit4/src/test/java/org/junit/tests/experimental/theories/AllMembersSupplierTest.java
new file mode 100644
index 0000000..e3fa0f0
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/AllMembersSupplierTest.java
@@ -0,0 +1,34 @@
+package org.junit.tests.experimental.theories;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.experimental.theories.internal.AllMembersSupplier;
+import org.junit.runners.model.TestClass;
+
+public class AllMembersSupplierTest {
+ public static class HasDataPoints {
+ @DataPoints
+ public static Object[] objects= { 1, 2 };
+
+ public HasDataPoints(Object obj) {
+ }
+ }
+
+ @Test
+ public void dataPointsAnnotationMeansTreatAsArrayOnly()
+ throws SecurityException, NoSuchMethodException {
+ List<PotentialAssignment> valueSources= new AllMembersSupplier(
+ new TestClass(HasDataPoints.class))
+ .getValueSources(ParameterSignature.signatures(
+ HasDataPoints.class.getConstructor(Object.class))
+ .get(0));
+ assertThat(valueSources.size(), is(2));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java b/junit4/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java
new file mode 100644
index 0000000..c0191c4
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java
@@ -0,0 +1,57 @@
+package org.junit.tests.experimental.theories;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.matchers.JUnitMatchers.hasItem;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.experimental.theories.suppliers.TestedOn;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class ParameterSignatureTest {
+ @DataPoint
+ public static Method getType() throws SecurityException,
+ NoSuchMethodException {
+ return ParameterSignatureTest.class.getMethod("getType", Method.class,
+ int.class);
+ }
+
+ @DataPoint
+ public static int ZERO= 0;
+
+ @DataPoint
+ public static int ONE= 1;
+
+ @Theory
+ public void getType(Method method, int index) {
+ assumeTrue(index < method.getParameterTypes().length);
+ assertEquals(method.getParameterTypes()[index], ParameterSignature
+ .signatures(method).get(index).getType());
+ }
+
+ public void foo(@TestedOn(ints= { 1, 2, 3 })
+ int x) {
+ }
+
+ @Test
+ public void getAnnotations() throws SecurityException,
+ NoSuchMethodException {
+ Method method= ParameterSignatureTest.class.getMethod("foo", int.class);
+ List<Annotation> annotations= ParameterSignature.signatures(method)
+ .get(0).getAnnotations();
+ assertThat(new ArrayList<Object>(annotations),
+ hasItem(is(TestedOn.class)));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/ParameterizedAssertionErrorTest.java b/junit4/src/test/java/org/junit/tests/experimental/theories/ParameterizedAssertionErrorTest.java
new file mode 100644
index 0000000..91c0e04
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/ParameterizedAssertionErrorTest.java
@@ -0,0 +1,75 @@
+package org.junit.tests.experimental.theories;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.junit.internal.matchers.StringContains.containsString;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.experimental.theories.internal.ParameterizedAssertionError;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class ParameterizedAssertionErrorTest {
+ @DataPoint
+ public static final String METHOD_NAME= "methodName";
+
+ @DataPoint
+ public static final NullPointerException NULL_POINTER_EXCEPTION= new NullPointerException();
+
+ @DataPoint
+ public static Object[] NO_OBJECTS= new Object[0];
+
+ @DataPoint
+ public static ParameterizedAssertionError A= new ParameterizedAssertionError(
+ NULL_POINTER_EXCEPTION, METHOD_NAME);
+
+ @DataPoint
+ public static ParameterizedAssertionError B= new ParameterizedAssertionError(
+ NULL_POINTER_EXCEPTION, METHOD_NAME);
+
+ @DataPoint
+ public static ParameterizedAssertionError B2= new ParameterizedAssertionError(
+ NULL_POINTER_EXCEPTION, "methodName2");
+
+ @Theory
+ public void equalParameterizedAssertionErrorsHaveSameToString(
+ ParameterizedAssertionError a, ParameterizedAssertionError b) {
+ assumeThat(a, is(b));
+ assertThat(a.toString(), is(b.toString()));
+ }
+
+ @Theory
+ public void differentParameterizedAssertionErrorsHaveDifferentToStrings(
+ ParameterizedAssertionError a, ParameterizedAssertionError b) {
+ assumeThat(a, not(b));
+ assertThat(a.toString(), not(b.toString()));
+ }
+
+ @Theory
+ public void equalsReturnsTrue(Throwable targetException, String methodName,
+ Object[] params) {
+ assertThat(new ParameterizedAssertionError(targetException, methodName,
+ params), is(new ParameterizedAssertionError(targetException,
+ methodName, params)));
+ }
+
+ @Theory(nullsAccepted= false)
+ public void buildParameterizedAssertionError(String methodName, String param) {
+ assertThat(new ParameterizedAssertionError(new RuntimeException(),
+ methodName, param).toString(), containsString(methodName));
+ }
+
+ @Test
+ public void canJoinWhenToStringFails() {
+ assertThat(ParameterizedAssertionError.join(" ", new Object() {
+ @Override
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+ }), is("[toString failed]"));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Correspondent.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Correspondent.java
new file mode 100644
index 0000000..60d7836
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Correspondent.java
@@ -0,0 +1,7 @@
+package org.junit.tests.experimental.theories.extendingwithstubs;
+
+public interface Correspondent {
+
+ String getAnswer(String question, String... bucket);
+
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Guesser.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Guesser.java
new file mode 100644
index 0000000..dcc5627
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Guesser.java
@@ -0,0 +1,122 @@
+package org.junit.tests.experimental.theories.extendingwithstubs;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Random;
+import java.util.Map.Entry;
+
+import org.hamcrest.BaseDescription;
+import org.hamcrest.Description;
+import org.junit.internal.AssumptionViolatedException;
+
+public class Guesser<T> extends ReguessableValue {
+ static class GuessMap extends HashMap<MethodCall, Object> implements
+ InvocationHandler {
+ private static final long serialVersionUID= 1L;
+
+ public GuessMap(GuessMap guesses) {
+ super(guesses);
+ }
+
+ public GuessMap() {
+ }
+
+ GuessMap replaceGuess(Object oldValue, Object newValue) {
+ GuessMap newGuesses= new GuessMap(this);
+ for (Entry<MethodCall, Object> entry : newGuesses.entrySet()) {
+ if (entry.getValue().equals(oldValue))
+ entry.setValue(newValue);
+ }
+ return newGuesses;
+ }
+
+ protected Object generateGuess(Class<?> returnType) {
+ if (returnType.equals(String.class))
+ return "GUESS" + new Random().nextInt();
+ if (returnType.equals(Integer.class)
+ || returnType.equals(int.class))
+ return new Random().nextInt();
+ return null;
+ }
+
+ Object getGuess(MethodCall call) {
+ if (!containsKey(call))
+ put(call, generateGuess(call.getReturnType()));
+ return get(call);
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ return getGuess(new MethodCall(method, args));
+ }
+ }
+
+ private final GuessMap guesses;
+
+ private final Class<? extends T> type;
+
+ public Guesser(Class<? extends T> type) {
+ this(type, new GuessMap());
+ }
+
+ public Guesser(Class<? extends T> type2, GuessMap guesses) {
+ this.type= type2;
+ this.guesses= guesses;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getProxy() {
+ return (T) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class[] { getType() }, guesses);
+ }
+
+ @Override
+ public List<ReguessableValue> reguesses(AssumptionViolatedException e) {
+ final ArrayList<ReguessableValue> returnThis= new ArrayList<ReguessableValue>();
+ e.describeTo(new BaseDescription() {
+ @Override
+ protected void append(char arg0) {
+ }
+
+ boolean expectedSeen= false;
+ Object expected= null;
+
+ @Override
+ public Description appendValue(Object value) {
+ noteValue(value);
+ return super.appendValue(value);
+ }
+
+ private void noteValue(Object value) {
+ if (!expectedSeen) {
+ expected= value;
+ expectedSeen= true;
+ return;
+ }
+
+ GuessMap newGuesses= guesses.replaceGuess(expected, value);
+ returnThis.add(new Guesser<T>(getType(), newGuesses));
+ }
+ });
+ return returnThis;
+ }
+
+ @Override
+ public Object getValue() throws CouldNotGenerateValueException {
+ return getProxy();
+ }
+
+ public Class<? extends T> getType() {
+ return type;
+ }
+
+ @Override
+ public String getDescription() throws CouldNotGenerateValueException {
+ return "guesser[" + type + "]";
+ }
+
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/GuesserQueue.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/GuesserQueue.java
new file mode 100644
index 0000000..f3eb550
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/GuesserQueue.java
@@ -0,0 +1,57 @@
+package org.junit.tests.experimental.theories.extendingwithstubs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.internal.AssumptionViolatedException;
+
+public class GuesserQueue extends ArrayList<ReguessableValue> {
+ static class ReguessableDecorator extends ReguessableValue {
+ private final PotentialAssignment delegate;
+
+ public ReguessableDecorator(PotentialAssignment delegate) {
+ this.delegate= delegate;
+ }
+
+ @Override
+ public List<ReguessableValue> reguesses(AssumptionViolatedException e) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Object getValue() throws CouldNotGenerateValueException {
+ return delegate.getValue();
+ }
+
+ @Override
+ public String getDescription() throws CouldNotGenerateValueException {
+ return delegate.getDescription();
+ }
+ }
+
+ static GuesserQueue forSingleValues(
+ List<PotentialAssignment> potentials) {
+ GuesserQueue returnThis= new GuesserQueue();
+ for (PotentialAssignment potentialParameterValue : potentials) {
+ returnThis
+ .add(new GuesserQueue.ReguessableDecorator(potentialParameterValue));
+ }
+ return returnThis;
+ }
+
+ private static final long serialVersionUID = 1L;
+ private ReguessableValue lastRemoved;
+
+ public void update(AssumptionViolatedException e) {
+ if (lastRemoved != null)
+ addAll(lastRemoved.reguesses(e));
+ }
+
+ @Override
+ public ReguessableValue remove(int index) {
+ lastRemoved = super.remove(index);
+ return lastRemoved;
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/MethodCall.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/MethodCall.java
new file mode 100644
index 0000000..85c44c5
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/MethodCall.java
@@ -0,0 +1,54 @@
+package org.junit.tests.experimental.theories.extendingwithstubs;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MethodCall {
+ private final Method method;
+ private final Object[] args;
+
+ public MethodCall(Method method, Object... args) {
+ this.method = method;
+ this.args = args;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ MethodCall call = (MethodCall) obj;
+ return call.method.equals(method) && Arrays.deepEquals(call.args, args);
+ }
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+
+ public Class<?> getReturnType() {
+ return method.getReturnType();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s(%s)", method.getName(), argListString());
+ }
+
+ private String argListString() {
+ if (args == null)
+ return null;
+ return argList().toString().substring(1, argList().toString().length() - 1);
+ }
+
+ private List<Object> argList() {
+ ArrayList<Object> list = new ArrayList<Object>();
+ for (Object arg : args) {
+ list.add(new StringableObject(arg));
+ }
+ return list;
+ }
+
+ public Object stringableObject(Object arg) {
+ return new StringableObject(arg).stringableObject();
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/ReguessableValue.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/ReguessableValue.java
new file mode 100644
index 0000000..6c96ed6
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/ReguessableValue.java
@@ -0,0 +1,16 @@
+package org.junit.tests.experimental.theories.extendingwithstubs;
+
+import java.util.List;
+
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.internal.AssumptionViolatedException;
+
+public abstract class ReguessableValue extends PotentialAssignment {
+
+ public ReguessableValue() {
+ super();
+ }
+
+ public abstract List<ReguessableValue> reguesses(
+ AssumptionViolatedException e);
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StringableObject.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StringableObject.java
new file mode 100644
index 0000000..94d5b31
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StringableObject.java
@@ -0,0 +1,27 @@
+package org.junit.tests.experimental.theories.extendingwithstubs;
+
+import java.util.Arrays;
+
+public class StringableObject {
+ public Object obj;
+
+ public StringableObject(Object obj) {
+ this.obj = obj;
+ }
+
+ public Object stringableObject() {
+ if (isListableArray())
+ return Arrays.asList((Object[]) obj);
+ else
+ return obj;
+ }
+
+ private boolean isListableArray() {
+ Class<?> type = obj.getClass();
+ return type.isArray() && !type.getComponentType().isPrimitive();
+ }
+
+ @Override public String toString() {
+ return stringableObject().toString();
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Stub.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Stub.java
new file mode 100644
index 0000000..aa320d5
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/Stub.java
@@ -0,0 +1,8 @@
+package org.junit.tests.experimental.theories.extendingwithstubs;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Stub {
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheories.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheories.java
new file mode 100644
index 0000000..91c0b42
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheories.java
@@ -0,0 +1,65 @@
+package org.junit.tests.experimental.theories.extendingwithstubs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.internal.Assignments;
+import org.junit.internal.AssumptionViolatedException;
+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 StubbedTheories extends Theories {
+ public StubbedTheories(Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+
+ @Override
+ public Statement methodBlock(FrameworkMethod method) {
+ return new StubbedTheoryAnchor(method, getTestClass());
+ }
+
+ public static class StubbedTheoryAnchor extends TheoryAnchor {
+ public StubbedTheoryAnchor(FrameworkMethod method, TestClass testClass) {
+ super(method, testClass);
+ }
+
+ private List<GuesserQueue> queues= new ArrayList<GuesserQueue>();
+
+ @Override
+ protected void handleAssumptionViolation(AssumptionViolatedException e) {
+ super.handleAssumptionViolation(e);
+ for (GuesserQueue queue : queues)
+ queue.update(e);
+ }
+
+ @Override
+ protected void runWithIncompleteAssignment(Assignments incomplete)
+ throws InstantiationException, IllegalAccessException,
+ Throwable {
+ GuesserQueue guessers= createGuesserQueue(incomplete);
+ queues.add(guessers);
+ while (!guessers.isEmpty())
+ runWithAssignment(incomplete.assignNext(guessers.remove(0)));
+ queues.remove(guessers);
+ }
+
+ private GuesserQueue createGuesserQueue(Assignments incomplete)
+ throws InstantiationException, IllegalAccessException {
+ ParameterSignature nextUnassigned= incomplete.nextUnassigned();
+
+ if (nextUnassigned.hasAnnotation(Stub.class)) {
+ GuesserQueue queue= new GuesserQueue();
+ queue.add(new Guesser<Object>(nextUnassigned.getType()));
+ return queue;
+ }
+
+ return GuesserQueue.forSingleValues(incomplete.potentialsForNextUnassigned());
+ }
+ }
+
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java
new file mode 100644
index 0000000..24abd7a
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java
@@ -0,0 +1 @@
+package org.junit.tests.experimental.theories.extendingwithstubs; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assume.assumeThat; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; @RunWith(StubbedTheories.class) public class StubbedTheoriesTest { @Theory public void ask(@Stub Correspondent correspondent) { assumeThat(correspondent.getAnswer("What is five?", "four", "five"), is("five")); } } \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/runner/SuccessfulWithDataPointFields.java b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/SuccessfulWithDataPointFields.java
new file mode 100644
index 0000000..ba3f149
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/SuccessfulWithDataPointFields.java
@@ -0,0 +1,204 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Enclosed.class)
+public class SuccessfulWithDataPointFields {
+ @RunWith(Theories.class)
+ public static class HasATwoParameterTheory {
+ @DataPoint
+ public static int ONE= 1;
+
+ @Theory
+ public void allIntsAreEqual(int x, int y) {
+ assertThat(x, is(y));
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class BeforeAndAfterOnSameInstance {
+ @DataPoint
+ public static String A= "A";
+
+ private int befores= 0;
+
+ @Before
+ public void incrementBefore() {
+ befores++;
+ }
+
+ @Theory
+ public void stringsAreOK(String string) {
+ assertTrue(befores == 1);
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class NewObjectEachTime {
+ @DataPoint
+ public static String A= "A";
+
+ @DataPoint
+ public static String B= "B";
+
+ private List<String> list= new ArrayList<String>();
+
+ @Theory
+ public void addToEmptyList(String string) {
+ list.add(string);
+ assertThat(list.size(), is(1));
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class PositiveInts {
+ @DataPoint
+ public static final int ONE= 1;
+
+ private int x;
+
+ public PositiveInts(int x) {
+ assumeTrue(x > 0);
+ this.x= x;
+ }
+
+ @Theory
+ public void haveAPostiveSquare() {
+ assertTrue(x * x > 0);
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class PositiveIntsWithNegativeField {
+ @DataPoint
+ public static final int ONE= 1;
+ @DataPoint
+ public static final int NEGONE= -1;
+
+ private int x;
+
+ public PositiveIntsWithNegativeField(int x) {
+ assumeTrue(x > 0);
+ this.x= x;
+ }
+
+ @Theory
+ public void haveAPostiveSquare() {
+ assertTrue(x > 0);
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class PositiveIntsWithMethodParams {
+ @DataPoint
+ public static final int ONE= 1;
+
+ private int x;
+
+ public PositiveIntsWithMethodParams(int x) {
+ assumeTrue(x > 0);
+ this.x= x;
+ }
+
+ @Theory
+ public void haveAPostiveSquare(int y) {
+ assumeTrue(y > 0);
+ assertTrue(x * y > 0);
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class DifferentTypesInConstructor {
+ @DataPoint
+ public static final int ONE= 1;
+
+ @DataPoint public static final String A = "A";
+
+ public DifferentTypesInConstructor(int x) {
+ }
+
+ @Theory
+ public void yesIndeed(String a) {
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class BeforeAndAfterEachTime {
+ public static int befores= 0;
+
+ @DataPoint
+ public static String A= "A";
+
+ @DataPoint
+ public static String B= "B";
+
+ @Before
+ public void incrementBefore() {
+ befores++;
+ }
+
+ @BeforeClass public static void resetCalls() {
+ befores = 0;
+ }
+
+ @Theory
+ public void stringsAreOK(String string) {
+ }
+
+ @AfterClass public static void calledTwice() {
+ assertEquals(2, befores);
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class OneTestTwoAnnotations {
+ public static int tests= 0;
+
+ @DataPoint
+ public static String A= "A";
+
+ @BeforeClass public static void resetCalls() {
+ tests = 0;
+ }
+
+ @Theory @Test
+ public void stringsAreOK(String string) {
+ tests++;
+ }
+
+ @AfterClass public static void calledTwice() {
+ assertEquals(1, tests);
+ }
+ }
+
+ @RunWith(Theories.class)
+ static public class StaticPublicNonDataPoints {
+ // DataPoint which passes the test
+ @DataPoint public static int ZERO = 0;
+
+ // Not annotated as a DataPoint and therefore should be ignored:
+ public static int ONE = 1;
+
+ @Theory
+ public void onlyAnnotatedFields(int i) {
+ assertTrue(i == 0);
+ }
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/runner/TheoriesPerformanceTest.java b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/TheoriesPerformanceTest.java
new file mode 100644
index 0000000..52dc528
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/TheoriesPerformanceTest.java
@@ -0,0 +1,37 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+public class TheoriesPerformanceTest {
+ @RunWith(Theories.class)
+ public static class UpToTen {
+ @DataPoints
+ public static int[] ints= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ @Theory
+ public void threeInts(int x, int y, int z) {
+ // pass always
+ }
+ }
+
+ private static final boolean TESTING_PERFORMANCE= false;
+
+ // If we do not share the same instance of TestClass, repeatedly parsing the
+ // class's annotations looking for @Befores and @Afters gets really costly.
+ //
+ // Likewise, the TestClass must be passed into AllMembersSupplier, or the
+ // annotation parsing is again costly.
+ @Test
+ public void tryCombinationsQuickly() {
+ assumeTrue(TESTING_PERFORMANCE);
+ assertThat(testResult(UpToTen.class), isSuccessful());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java
new file mode 100644
index 0000000..790d798
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java
@@ -0,0 +1,126 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.failureCountIs;
+import static org.junit.experimental.results.ResultMatchers.hasFailureContaining;
+import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
+import static org.junit.matchers.JUnitMatchers.both;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.TestClass;
+
+public class UnsuccessfulWithDataPointFields {
+ @RunWith(Theories.class)
+ public static class HasATheory {
+ @DataPoint
+ public static int ONE= 1;
+
+ @Theory
+ public void everythingIsZero(int x) {
+ assertThat(x, is(0));
+ }
+ }
+
+ @Test
+ public void theoryClassMethodsShowUp() throws Exception {
+ assertThat(new Theories(HasATheory.class).getDescription()
+ .getChildren().size(), is(1));
+ }
+
+ @Test
+ public void theoryAnnotationsAreRetained() throws Exception {
+ assertThat(new TestClass(HasATheory.class).getAnnotatedMethods(
+ Theory.class).size(), is(1));
+ }
+
+ @Test
+ public void canRunTheories() throws Exception {
+ assertThat(testResult(HasATheory.class),
+ hasSingleFailureContaining("Expected"));
+ }
+
+ @RunWith(Theories.class)
+ public static class DoesntUseParams {
+ @DataPoint
+ public static int ONE= 1;
+
+ @Theory
+ public void everythingIsZero(int x, int y) {
+ assertThat(2, is(3));
+ }
+ }
+
+ @Test
+ public void reportBadParams() throws Exception {
+ assertThat(testResult(DoesntUseParams.class),
+ hasSingleFailureContaining("everythingIsZero(ONE, ONE)"));
+ }
+
+ @RunWith(Theories.class)
+ public static class NullsOK {
+ @DataPoint
+ public static String NULL= null;
+
+ @DataPoint
+ public static String A= "A";
+
+ @Theory
+ public void everythingIsA(String a) {
+ assertThat(a, is("A"));
+ }
+ }
+
+ @Test
+ public void nullsUsedUnlessProhibited() throws Exception {
+ assertThat(testResult(NullsOK.class),
+ hasSingleFailureContaining("null"));
+ }
+
+ @RunWith(Theories.class)
+ public static class DataPointsMustBeStatic {
+ @DataPoint
+ int THREE= 3;
+
+ @DataPoint
+ int FOUR= 3;
+
+ @Theory
+ public void numbers(int x) {
+
+ }
+ }
+
+ @Test
+ public void dataPointsMustBeStatic() {
+ assertThat(
+ testResult(DataPointsMustBeStatic.class),
+ both(failureCountIs(2))
+ .and(
+ hasFailureContaining("DataPoint field THREE must be static"))
+ .and(
+ hasFailureContaining("DataPoint field FOUR must be static")));
+ }
+
+ @RunWith(Theories.class)
+ public static class TheoriesMustBePublic {
+ @DataPoint
+ public static int THREE= 3;
+
+ @Theory
+ void numbers(int x) {
+
+ }
+ }
+
+ @Test
+ public void theoriesMustBePublic() {
+ assertThat(
+ testResult(TheoriesMustBePublic.class),
+ hasSingleFailureContaining("public"));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WhenNoParametersMatch.java b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WhenNoParametersMatch.java
new file mode 100644
index 0000000..3c83d82
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WhenNoParametersMatch.java
@@ -0,0 +1,50 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.internal.matchers.StringContains.containsString;
+import org.hamcrest.Matcher;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class WhenNoParametersMatch {
+ @DataPoints
+ public static int[] ints= { 0, 1, 3, 5, 1776 };
+
+ @DataPoints
+ public static Matcher<?>[] matchers= { not(0), is(1) };
+
+ @RunWith(Theories.class)
+ public static class AssumptionsFail {
+ @DataPoint
+ public static int DATA= 0;
+
+ @DataPoint
+ public static Matcher<Integer> MATCHER= null;
+
+ @Theory
+ public void nonZeroIntsAreFun(int x) {
+ assumeThat(x, MATCHER);
+ }
+ }
+
+ @Theory
+ public void showFailedAssumptionsWhenNoParametersFound(int data,
+ Matcher<Integer> matcher) throws Exception {
+ assumeThat(data, not(matcher));
+ AssumptionsFail.DATA= data;
+ AssumptionsFail.MATCHER= matcher;
+
+ String result= testResult(AssumptionsFail.class).toString();
+
+ assertThat(result, containsString(matcher.toString()));
+ assertThat(result, containsString("" + data));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java
new file mode 100644
index 0000000..659f430
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java
@@ -0,0 +1,152 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.internal.matchers.Each.each;
+import static org.junit.internal.matchers.StringContains.containsString;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.PotentialAssignment;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.experimental.theories.internal.Assignments;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.Failure;
+import org.junit.runners.model.TestClass;
+
+public class WithDataPointMethod {
+ @RunWith(Theories.class)
+ public static class HasDataPointMethod {
+ @DataPoint
+ public static int oneHundred() {
+ return 100;
+ }
+
+ @Theory
+ public void allIntsOk(int x) {
+
+ }
+ }
+
+ @RunWith(Theories.class)
+ public static class HasUglyDataPointMethod {
+ @DataPoint
+ public static int oneHundred() {
+ return 100;
+ }
+
+ @DataPoint
+ public static int oneUglyHundred() {
+ throw new RuntimeException();
+ }
+
+ @Theory
+ public void allIntsOk(int x) {
+
+ }
+ }
+
+ @Test
+ public void pickUpDataPointMethods() {
+ assertThat(testResult(HasDataPointMethod.class), isSuccessful());
+ }
+
+ @Test
+ public void ignoreExceptionsFromDataPointMethods() {
+ assertThat(testResult(HasUglyDataPointMethod.class), isSuccessful());
+ }
+
+ @RunWith(Theories.class)
+ public static class DataPointMethodReturnsMutableObject {
+ @DataPoint
+ public static List<Object> empty() {
+ return new ArrayList<Object>();
+ }
+
+ @DataPoint
+ public static int ONE= 1;
+
+ @DataPoint
+ public static int TWO= 2;
+
+ @Theory
+ public void everythingsEmpty(List<Object> first, int number) {
+ assertThat(first.size(), is(0));
+ first.add("a");
+ }
+ }
+
+ @Test
+ public void mutableObjectsAreCreatedAfresh() {
+ assertThat(failures(DataPointMethodReturnsMutableObject.class), empty());
+ }
+
+ @RunWith(Theories.class)
+ public static class HasDateMethod {
+ @DataPoint
+ public int oneHundred() {
+ return 100;
+ }
+
+ public Date notADataPoint() {
+ return new Date();
+ }
+
+ @Theory
+ public void allIntsOk(int x) {
+
+ }
+
+ @Theory
+ public void onlyStringsOk(String s) {
+
+ }
+
+ @Theory
+ public void onlyDatesOk(Date d) {
+
+ }
+ }
+
+ @Test
+ public void ignoreDataPointMethodsWithWrongTypes() throws Exception {
+ assertThat(potentialValues(
+ HasDateMethod.class.getMethod("onlyStringsOk", String.class))
+ .toString(), not(containsString("100")));
+ }
+
+ @Test
+ public void ignoreDataPointMethodsWithoutAnnotation() throws Throwable {
+ assertThat(potentialValues(
+ HasDateMethod.class.getMethod("onlyDatesOk", Date.class))
+ .size(), is(0));
+ }
+
+ private List<PotentialAssignment> potentialValues(Method method)
+ throws Exception {
+ return Assignments.allUnassigned(method,
+ new TestClass(HasDateMethod.class))
+ .potentialsForNextUnassigned();
+ }
+
+ private List<Failure> failures(Class<?> type) {
+ return JUnitCore.runClasses(type).getFailures();
+ }
+
+ private Matcher<Iterable<Failure>> empty() {
+ Matcher<Failure> nullValue= nullValue();
+ return each(nullValue);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java
new file mode 100644
index 0000000..9b5f0ae
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java
@@ -0,0 +1,146 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import org.junit.Test;
+import org.junit.experimental.results.ResultMatchers;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.experimental.theories.suppliers.TestedOn;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.RunWith;
+
+public class WithExtendedParameterSources {
+ @RunWith(Theories.class)
+ public static class ParameterAnnotations {
+ @Theory
+ public void everythingIsOne(@TestedOn(ints= { 1 })
+ int number) {
+ assertThat(number, is(1));
+ }
+ }
+
+ @Test
+ public void testedOnLimitsParameters() throws Exception {
+ assertThat(testResult(ParameterAnnotations.class), ResultMatchers
+ .isSuccessful());
+ }
+
+ @RunWith(Theories.class)
+ public static class ShouldFilterNull {
+ @DataPoint
+ public static String NULL= null;
+
+ @DataPoint
+ public static String A= "a";
+
+ @Theory(nullsAccepted= false)
+ public void allStringsAreNonNull(String s) {
+ assertThat(s, notNullValue());
+ }
+ }
+
+ @Test
+ public void shouldFilterNull() {
+ assertThat(testResult(ShouldFilterNull.class), isSuccessful());
+ }
+
+ @RunWith(Theories.class)
+ public static class DataPointArrays {
+ public static String log= "";
+
+ @DataPoints
+ public static String[] STRINGS= new String[] { "A", "B" };
+
+ @Theory
+ public void addToLog(String string) {
+ log+= string;
+ }
+ }
+
+ @Test
+ public void getDataPointsFromArray() {
+ DataPointArrays.log= "";
+ JUnitCore.runClasses(DataPointArrays.class);
+ assertThat(DataPointArrays.log, is("AB"));
+ }
+
+ @RunWith(Theories.class)
+ public static class DataPointArrayMethod {
+ public static String log= "";
+
+ @DataPoints
+ public static String[] STRINGS() {
+ return new String[] { "A", "B" };
+ };
+
+ @Theory
+ public void addToLog(String string) {
+ log+= string;
+ }
+ }
+
+ @Test
+ public void getDataPointsFromArrayMethod() {
+ DataPointArrayMethod.log= "";
+ JUnitCore.runClasses(DataPointArrayMethod.class);
+ assertThat(DataPointArrayMethod.log, is("AB"));
+ }
+
+ @RunWith(Theories.class)
+ public static class DataPointMalformedArrayMethods {
+ public static String log= "";
+
+ @DataPoints
+ public static String[] STRINGS() {
+ return new String[] { "A", "B" };
+ };
+
+ @DataPoints
+ public static String STRING() {
+ return "C";
+ }
+
+ @DataPoints
+ public static int[] INTS() {
+ return new int[] { 1, 2, 3 };
+ }
+
+ @Theory
+ public void addToLog(String string) {
+ log+= string;
+ }
+ }
+
+ @Test
+ public void getDataPointsFromArrayMethodInSpiteOfMalformedness() {
+ DataPointArrayMethod.log= "";
+ JUnitCore.runClasses(DataPointArrayMethod.class);
+ assertThat(DataPointArrayMethod.log, is("AB"));
+ }
+
+ @RunWith(Theories.class)
+ public static class DataPointArrayToBeUsedForWholeParameter {
+ public static String log= "";
+
+ @DataPoint
+ public static String[] STRINGS= new String[] { "A", "B" };
+
+ @Theory
+ public void addToLog(String[] strings) {
+ log+= strings[0];
+ }
+ }
+
+ @Test
+ public void dataPointCanBeArray() {
+ DataPointArrayToBeUsedForWholeParameter.log= "";
+ JUnitCore.runClasses(DataPointArrayToBeUsedForWholeParameter.class);
+ assertThat(DataPointArrayToBeUsedForWholeParameter.log, is("A"));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithOnlyTestAnnotations.java b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithOnlyTestAnnotations.java
new file mode 100644
index 0000000..2204fb6
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithOnlyTestAnnotations.java
@@ -0,0 +1,80 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.failureCountIs;
+import static org.junit.experimental.results.ResultMatchers.isSuccessful;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+
+public class WithOnlyTestAnnotations {
+ @RunWith(Theories.class)
+ public static class HonorExpectedException {
+ @Test(expected= NullPointerException.class)
+ public void shouldThrow() {
+
+ }
+ }
+
+ @Test
+ public void honorExpected() throws Exception {
+ assertThat(testResult(HonorExpectedException.class).failureCount(), is(1));
+ }
+
+ @RunWith(Theories.class)
+ public static class HonorExpectedExceptionPasses {
+ @Test(expected= NullPointerException.class)
+ public void shouldThrow() {
+ throw new NullPointerException();
+ }
+ }
+
+ @Test
+ public void honorExpectedPassing() throws Exception {
+ assertThat(testResult(HonorExpectedExceptionPasses.class), isSuccessful());
+ }
+
+ @RunWith(Theories.class)
+ public static class HonorTimeout {
+ @Test(timeout= 5)
+ public void shouldStop() {
+ while (true) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+
+ }
+ }
+ }
+ }
+
+ @Test
+ public void honorTimeout() throws Exception {
+ assertThat(testResult(HonorTimeout.class), failureCountIs(1));
+ }
+
+ @RunWith(Theories.class)
+ static public class ErrorWhenTestHasParametersDespiteTheories {
+ @DataPoint
+ public static int ZERO = 0;
+
+ @Test
+ public void testMethod(int i) {
+ }
+ }
+
+ @Test public void testErrorWhenTestHasParametersDespiteTheories() {
+ JUnitCore core = new JUnitCore();
+ Result result = core.run(ErrorWhenTestHasParametersDespiteTheories.class);
+ assertEquals(1, result.getFailureCount());
+ String message = result.getFailures().get(0).getMessage();
+ assertThat(message, containsString("should have no parameters"));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java
new file mode 100644
index 0000000..579fc7e
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java
@@ -0,0 +1,177 @@
+package org.junit.tests.experimental.theories.runner;
+
+import static org.junit.Assert.*;
+import static org.junit.experimental.results.PrintableResult.*;
+import static org.junit.experimental.results.ResultMatchers.*;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.experimental.results.PrintableResult;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+public class WithUnresolvedGenericTypeVariablesOnTheoryParms {
+ @Test
+ public void whereTypeVariableIsOnTheTheory() {
+ PrintableResult result= testResult(TypeVariableOnTheoryOnly.class);
+ assertThat(result, isSuccessful());
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnTheoryOnly {
+ @DataPoint
+ public static List<String> strings = Arrays.asList("foo", "bar");
+
+ @Theory
+ public <T> void forItems(Collection<?> items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable T"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnTheoryParm {
+ @DataPoint
+ public static String string = "foo";
+
+ @Theory
+ public <T> void forItem(T item) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnParameterizedTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnParameterizedTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable T"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnParameterizedTheoryParm {
+ @DataPoint
+ public static List<String> strings = Arrays.asList("foo", "bar");
+
+ @Theory
+ public <T> void forItems(Collection<T> items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnWildcardUpperBoundOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnWildcardUpperBoundOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable U"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnWildcardUpperBoundOnTheoryParm {
+ @DataPoint
+ public static List<String> strings = Arrays.asList("foo", "bar");
+
+ @Theory
+ public <U> void forItems(Collection<? extends U> items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnWildcardLowerBoundOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnWildcardLowerBoundOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable V"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnWildcardLowerBoundOnTheoryParm {
+ @DataPoint
+ public static List<String> strings = Arrays.asList("foo", "bar");
+
+ @Theory
+ public <V> void forItems(Collection<? super V> items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnArrayTypeOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnArrayTypeOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable T"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnArrayTypeOnTheoryParm {
+ @DataPoints
+ public static String[][] items() {
+ return new String[][] { new String[] { "foo" }, new String[] { "bar" } };
+ }
+
+ @Theory
+ public <T> void forItems(T[] items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnComponentOfArrayTypeOnTheoryParm() {
+ PrintableResult result= testResult(TypeVariableOnComponentOfArrayTypeOnTheoryParm.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable U"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnComponentOfArrayTypeOnTheoryParm {
+ @DataPoints
+ public static List<?>[][] items() {
+ return new List<?>[][] {
+ new List<?>[] { Arrays.asList("foo") },
+ new List<?>[] { Arrays.asList("bar") }
+ };
+ }
+
+ @Theory
+ public <U> void forItems(Collection<U>[] items) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariableIsOnTheoryClass() {
+ PrintableResult result= testResult(TypeVariableOnTheoryClass.class);
+ assertThat(result, hasSingleFailureContaining("unresolved type variable T"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariableOnTheoryClass<T> {
+ @DataPoint
+ public static String item = "bar";
+
+ @Theory
+ public void forItem(T item) {
+ }
+ }
+
+ @Test
+ public void whereTypeVariablesAbound() {
+ PrintableResult result= testResult(TypeVariablesAbound.class);
+ assertThat(result, failureCountIs(7));
+ assertThat(result, hasFailureContaining("unresolved type variable A"));
+ assertThat(result, hasFailureContaining("unresolved type variable B"));
+ assertThat(result, hasFailureContaining("unresolved type variable C"));
+ assertThat(result, hasFailureContaining("unresolved type variable D"));
+ assertThat(result, hasFailureContaining("unresolved type variable E"));
+ assertThat(result, hasFailureContaining("unresolved type variable F"));
+ assertThat(result, hasFailureContaining("unresolved type variable G"));
+ }
+
+ @RunWith(Theories.class)
+ public static class TypeVariablesAbound<A, B extends A, C extends Collection<B>> {
+ @Theory
+ public <D, E extends D, F, G> void forItem(A first, Collection<B> second,
+ Map<C, ? extends D> third, List<? super E> fourth, F[] fifth,
+ Collection<G>[] sixth) {
+ }
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java b/junit4/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java
new file mode 100644
index 0000000..152d641
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java
@@ -0,0 +1,110 @@
+package org.junit.tests.internal.runners.statements;
+
+import static java.lang.Thread.sleep;
+import static org.junit.Assert.assertTrue;
+import static org.hamcrest.core.Is.is;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.internal.runners.statements.FailOnTimeout;
+import org.junit.rules.ExpectedException;
+import org.junit.runners.model.Statement;
+
+/**
+ * @author Asaf Ary, Stefan Birkner
+ */
+public class FailOnTimeoutTest {
+ private static final int TIMEOUT= 100;
+
+ @Rule
+ public final ExpectedException thrown= ExpectedException.none();
+
+ private final TestStatement statement= new TestStatement();
+
+ private final FailOnTimeout failOnTimeout= new FailOnTimeout(statement,
+ TIMEOUT);
+
+ @Test
+ public void throwExceptionWithNiceMessageOnTimeout() throws Throwable {
+ thrown.expectMessage("test timed out after 100 milliseconds");
+ evaluateWithWaitDuration(TIMEOUT + 50);
+ }
+
+ @Test
+ public void sendUpExceptionThrownByStatement() throws Throwable {
+ RuntimeException exception= new RuntimeException();
+ thrown.expect(is(exception));
+ evaluateWithException(exception);
+ }
+
+ @Test
+ public void throwExceptionIfTheSecondCallToEvaluateNeedsTooMuchTime()
+ throws Throwable {
+ thrown.expect(Exception.class);
+ evaluateWithWaitDuration(0);
+ evaluateWithWaitDuration(TIMEOUT + 50);
+ }
+
+ @Test
+ public void throwTimeoutExceptionOnSecondCallAlthoughFirstCallThrowsException()
+ throws Throwable {
+ thrown.expectMessage("test timed out after 100 milliseconds");
+ try {
+ evaluateWithException(new RuntimeException());
+ } catch (Throwable expected) {
+ }
+ evaluateWithWaitDuration(TIMEOUT + 50);
+ }
+
+ private void evaluateWithException(Exception exception) throws Throwable {
+ statement.nextException= exception;
+ statement.waitDuration= 0;
+ failOnTimeout.evaluate();
+ }
+
+ private void evaluateWithWaitDuration(int waitDuration) throws Throwable {
+ statement.nextException= null;
+ statement.waitDuration= waitDuration;
+ failOnTimeout.evaluate();
+ }
+
+ private static final class TestStatement extends Statement {
+ int waitDuration;
+
+ Exception nextException;
+
+ @Override
+ public void evaluate() throws Throwable {
+ sleep(waitDuration);
+ if (nextException != null)
+ throw nextException;
+ }
+ }
+
+ @Test
+ public void stopEndlessStatement() throws Throwable {
+ InfiniteLoopStatement infiniteLoop= new InfiniteLoopStatement();
+ FailOnTimeout infiniteLoopTimeout= new FailOnTimeout(infiniteLoop,
+ TIMEOUT);
+ try {
+ infiniteLoopTimeout.evaluate();
+ } catch (Exception timeoutException) {
+ sleep(20); // time to interrupt the thread
+ int firstCount= InfiniteLoopStatement.COUNT;
+ sleep(20); // time to increment the count
+ assertTrue("Thread has not been stopped.",
+ firstCount == InfiniteLoopStatement.COUNT);
+ }
+ }
+
+ private static final class InfiniteLoopStatement extends Statement {
+ private static int COUNT= 0;
+
+ @Override
+ public void evaluate() throws Throwable {
+ while (true) {
+ sleep(10); //sleep in order to enable interrupting thread
+ ++COUNT;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/AllTestsTest.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/AllTestsTest.java
new file mode 100644
index 0000000..d9076e3
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/AllTestsTest.java
@@ -0,0 +1,81 @@
+package org.junit.tests.junit3compatibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+
+public class AllTestsTest {
+
+ private static boolean run;
+
+ public static class OneTest extends TestCase {
+ public void testSomething() {
+ run= true;
+ }
+ }
+
+ @RunWith(AllTests.class)
+ public static class All {
+ static public junit.framework.Test suite() {
+ TestSuite suite= new TestSuite();
+ suite.addTestSuite(OneTest.class);
+ return suite;
+ }
+ }
+
+ @org.junit.Test public void ensureTestIsRun() {
+ JUnitCore runner= new JUnitCore();
+ run= false; // Have to explicitly set run here because the runner might independently run OneTest above
+ runner.run(All.class);
+ assertTrue(run);
+ }
+
+ @org.junit.Test public void correctTestCount() throws Throwable {
+ AllTests tests= new AllTests(All.class);
+ assertEquals(1, tests.testCount());
+ }
+
+ @org.junit.Test public void someUsefulDescription() throws Throwable {
+ AllTests tests= new AllTests(All.class);
+ assertThat(tests.getDescription().toString(), containsString("OneTest"));
+ }
+
+ public static class JUnit4Test {
+ @org.junit.Test public void testSomething() {
+ run= true;
+ }
+ }
+
+ @RunWith(AllTests.class)
+ public static class AllJUnit4 {
+ static public junit.framework.Test suite() {
+ TestSuite suite= new TestSuite();
+ suite.addTest(new JUnit4TestAdapter(JUnit4Test.class));
+ return suite;
+ }
+ }
+
+ @org.junit.Test public void correctTestCountAdapted() throws Throwable {
+ AllTests tests= new AllTests(AllJUnit4.class);
+ assertEquals(1, tests.testCount());
+ }
+
+ @RunWith(AllTests.class)
+ public static class BadSuiteMethod {
+ public static junit.framework.Test suite() {
+ throw new RuntimeException("can't construct");
+ }
+ }
+
+ @org.junit.Test(expected= RuntimeException.class)
+ public void exceptionThrownWhenSuiteIsBad() throws Throwable {
+ new AllTests(BadSuiteMethod.class);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/ClassRequestTest.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/ClassRequestTest.java
new file mode 100644
index 0000000..91bc037
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/ClassRequestTest.java
@@ -0,0 +1,19 @@
+package org.junit.tests.junit3compatibility;
+
+import static org.junit.Assert.assertNull;
+import org.junit.Test;
+import org.junit.internal.builders.SuiteMethodBuilder;
+
+public class ClassRequestTest {
+ public static class PrivateSuiteMethod {
+ static junit.framework.Test suite() {
+ return null;
+ }
+ }
+
+ @Test
+ public void noSuiteMethodIfMethodPrivate() throws Throwable {
+ assertNull(new SuiteMethodBuilder()
+ .runnerForClass(PrivateSuiteMethod.class));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityPrintingTest.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityPrintingTest.java
new file mode 100644
index 0000000..34a08a6
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityPrintingTest.java
@@ -0,0 +1,89 @@
+package org.junit.tests.junit3compatibility;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.textui.ResultPrinter;
+import junit.textui.TestRunner;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ForwardCompatibilityPrintingTest extends TestCase {
+ static class TestResultPrinter extends ResultPrinter {
+ TestResultPrinter(PrintStream writer) {
+ super(writer);
+ }
+
+ /*
+ * Spoof printing time so the tests are deterministic
+ */
+ @Override
+ protected String elapsedTimeAsString(long runTime) {
+ return "0";
+ }
+ }
+
+ public void testError() {
+ ByteArrayOutputStream output= new ByteArrayOutputStream();
+ TestRunner runner= new TestRunner(new TestResultPrinter(
+ new PrintStream(output)));
+
+ String expected= expected(new String[] { ".E", "Time: 0",
+ "Errors here", "", "FAILURES!!!",
+ "Tests run: 1, Failures: 0, Errors: 1", "" });
+ ResultPrinter printer= new TestResultPrinter(new PrintStream(output)) {
+ @Override
+ public void printErrors(TestResult result) {
+ getWriter().println("Errors here");
+ }
+ };
+ runner.setPrinter(printer);
+ TestSuite suite= new TestSuite();
+ suite.addTest(new TestCase() {
+ @Override
+ public void runTest() throws Exception {
+ throw new Exception();
+ }
+ });
+ runner.doRun(suite);
+ assertEquals(expected, output.toString());
+ }
+
+ public static class ATest {
+ @Test public void error() {
+ Assert.fail();
+ }
+ }
+
+ public void testErrorAdapted() {
+ ByteArrayOutputStream output= new ByteArrayOutputStream();
+ TestRunner runner= new TestRunner(new TestResultPrinter(
+ new PrintStream(output)));
+
+ String expected= expected(new String[] { ".E", "Time: 0",
+ "Errors here", "", "FAILURES!!!",
+ "Tests run: 1, Failures: 0, Errors: 1", "" });
+ ResultPrinter printer= new TestResultPrinter(new PrintStream(output)) {
+ @Override
+ public void printErrors(TestResult result) {
+ getWriter().println("Errors here");
+ }
+ };
+ runner.setPrinter(printer);
+ runner.doRun(new JUnit4TestAdapter(ATest.class));
+ assertEquals(expected, output.toString());
+ }
+
+ private String expected(String[] lines) {
+ OutputStream expected= new ByteArrayOutputStream();
+ PrintStream expectedWriter= new PrintStream(expected);
+ for (int i= 0; i < lines.length; i++)
+ expectedWriter.println(lines[i]);
+ return expected.toString();
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityTest.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityTest.java
new file mode 100644
index 0000000..2c73089
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/ForwardCompatibilityTest.java
@@ -0,0 +1,222 @@
+package org.junit.tests.junit3compatibility;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+
+public class ForwardCompatibilityTest extends TestCase {
+ static String fLog;
+
+ static public class NewTest {
+ @Before public void before() {
+ fLog+= "before ";
+ }
+ @After public void after() {
+ fLog+= "after ";
+ }
+ @Test public void test() {
+ fLog+= "test ";
+ }
+ }
+
+ public void testCompatibility() {
+ fLog= "";
+ TestResult result= new TestResult();
+ junit.framework.Test adapter= new JUnit4TestAdapter(NewTest.class);
+ adapter.run(result);
+ assertEquals("before test after ", fLog);
+ }
+
+ public void testToString() {
+ JUnit4TestAdapter adapter= new JUnit4TestAdapter(NewTest.class);
+ junit.framework.Test test= adapter.getTests().get(0);
+ assertEquals(String.format("test(%s)", NewTest.class.getName()), test.toString());
+ }
+
+ public void testUseGlobalCache() {
+ JUnit4TestAdapter adapter1= new JUnit4TestAdapter(NewTest.class);
+ JUnit4TestAdapter adapter2= new JUnit4TestAdapter(NewTest.class);
+ assertSame(adapter1.getTests().get(0), adapter2.getTests().get(0));
+ }
+
+ static Exception exception= new Exception();
+
+ public static class ErrorTest {
+ @Test public void error() throws Exception {
+ throw exception;
+ }
+ }
+ public void testException() {
+ TestResult result= new TestResult();
+ junit.framework.Test adapter= new JUnit4TestAdapter(ErrorTest.class);
+ adapter.run(result);
+ assertEquals(exception, result.errors().nextElement().thrownException());
+ }
+
+ public void testNotifyResult() {
+ JUnit4TestAdapter adapter= new JUnit4TestAdapter(ErrorTest.class);
+ TestResult result= new TestResult();
+ final StringBuffer log= new StringBuffer();
+ result.addListener(new TestListener() {
+
+ public void startTest(junit.framework.Test test) {
+ log.append(" start " + test);
+ }
+
+ public void endTest(junit.framework.Test test) {
+ log.append(" end " + test);
+ }
+
+ public void addFailure(junit.framework.Test test, AssertionFailedError t) {
+ log.append(" failure " + test);
+ }
+
+ public void addError(junit.framework.Test test, Throwable t) {
+ log.append(" error " + test);
+ }
+ });
+ adapter.run(result);
+ String testName= String.format("error(%s)", ErrorTest.class.getName());
+ assertEquals(String.format(" start %s error %s end %s", testName, testName, testName), log.toString());
+ }
+
+
+ public static class NoExceptionTest {
+ @Test(expected=Exception.class) public void succeed() throws Exception {
+ }
+ }
+ public void testNoException() {
+ TestResult result= new TestResult();
+ junit.framework.Test adapter= new JUnit4TestAdapter(NoExceptionTest.class);
+ adapter.run(result);
+ assertFalse(result.wasSuccessful());
+ }
+
+ public static class ExpectedTest {
+ @Test(expected= Exception.class) public void expected() throws Exception {
+ throw new Exception();
+ }
+ }
+ public void testExpected() {
+ TestResult result= new TestResult();
+ junit.framework.Test adapter= new JUnit4TestAdapter(ExpectedTest.class);
+ adapter.run(result);
+ assertTrue(result.wasSuccessful());
+ }
+
+ public static class UnExpectedExceptionTest {
+ @Test(expected= Exception.class) public void expected() throws Exception {
+ throw new Error();
+ }
+ }
+
+ static String log;
+ public static class BeforeClassTest {
+ @BeforeClass public static void beforeClass() {
+ log+= "before class ";
+ }
+ @Before public void before() {
+ log+= "before ";
+ }
+ @Test public void one() {
+ log+= "test ";
+ }
+ @Test public void two() {
+ log+= "test ";
+ }
+ @After public void after() {
+ log+= "after ";
+ }
+ @AfterClass public static void afterClass() {
+ log+= "after class ";
+ }
+ }
+
+ public void testBeforeAndAfterClass() {
+ log= "";
+ TestResult result= new TestResult();
+ junit.framework.Test adapter= new JUnit4TestAdapter(BeforeClassTest.class);
+ adapter.run(result);
+ assertEquals("before class before test after before test after after class ", log);
+ }
+
+ public static class ExceptionInBeforeTest {
+ @Before public void error() {
+ throw new Error();
+ }
+ @Test public void nothing() {
+ }
+ }
+
+ public void testExceptionInBefore() {
+ TestResult result= new TestResult();
+ junit.framework.Test adapter= new JUnit4TestAdapter(ExceptionInBeforeTest.class);
+ adapter.run(result);
+ assertEquals(1, result.errorCount());
+ }
+
+ public static class InvalidMethodTest {
+ @BeforeClass public void shouldBeStatic() {}
+ @Test public void aTest() {}
+ }
+
+ public void testInvalidMethod() {
+ TestResult result= new TestResult();
+ junit.framework.Test adapter= new JUnit4TestAdapter(InvalidMethodTest.class);
+ adapter.run(result);
+ assertEquals(1, result.errorCount());
+ TestFailure failure= result.errors().nextElement();
+ assertTrue(failure.exceptionMessage().contains("Method shouldBeStatic() should be static"));
+ }
+
+ private static boolean wasRun= false;
+
+ public static class MarkerRunner extends Runner {
+ public MarkerRunner(Class<?> klass) {
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ wasRun= true;
+ }
+
+ @Override
+ public int testCount() {
+ return 0;
+ }
+
+ @Override
+ public Description getDescription() {
+ return Description.EMPTY;
+ }
+ }
+
+ @RunWith(MarkerRunner.class)
+ public static class NoTests {
+ }
+
+ public void testRunWithClass() {
+ wasRun= false;
+ TestResult result= new TestResult();
+ junit.framework.Test adapter= new JUnit4TestAdapter(NoTests.class);
+ adapter.run(result);
+ assertTrue(wasRun);
+ }
+
+ public void testToStringSuite() {
+ junit.framework.Test adapter= new JUnit4TestAdapter(NoTests.class);
+ assertEquals(NoTests.class.getName(), adapter.toString());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/InitializationErrorForwardCompatibilityTest.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/InitializationErrorForwardCompatibilityTest.java
new file mode 100644
index 0000000..6c87a8b
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/InitializationErrorForwardCompatibilityTest.java
@@ -0,0 +1,100 @@
+package org.junit.tests.junit3compatibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import junit.framework.AssertionFailedError;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+public class InitializationErrorForwardCompatibilityTest {
+ public static class CantInitialize extends Runner {
+ private static final String UNIQUE_ERROR_MESSAGE= "Unique error message";
+
+ public CantInitialize(Class<?> klass) throws Exception {
+ throw new Exception(UNIQUE_ERROR_MESSAGE);
+ }
+
+ @Override
+ public Description getDescription() {
+ return Description.EMPTY;
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ }
+ }
+
+ @RunWith(CantInitialize.class)
+ public static class CantInitializeTests {
+ }
+
+ private JUnit4TestAdapter fAdapter;
+
+ @Before public void createAdapter() {
+ fAdapter= new JUnit4TestAdapter(
+ CantInitializeTests.class);
+ }
+
+ @Test
+ public void initializationErrorsShowUpAsWarnings() {
+ assertEquals(1, fAdapter.getTests().size());
+ }
+
+ @Test
+ public void initializationErrorsAreThrownAtRuntime() {
+ TestResult result= new TestResult();
+ fAdapter.run(result);
+ assertEquals(1, result.errorCount());
+ assertEquals(CantInitialize.UNIQUE_ERROR_MESSAGE, result.errors()
+ .nextElement().exceptionMessage());
+ }
+
+ private final class ErrorRememberingListener implements TestListener {
+ private junit.framework.Test fError;
+
+ public void addError(junit.framework.Test test, Throwable t) {
+ fError= test;
+ }
+
+ public void addFailure(junit.framework.Test test,
+ AssertionFailedError t) {
+ }
+
+ public void endTest(junit.framework.Test test) {
+ }
+
+ public void startTest(junit.framework.Test test) {
+ }
+
+ public junit.framework.Test getError() {
+ return fError;
+ }
+ }
+
+ @Test
+ public void generatedErrorTestsMatchUp() {
+ junit.framework.Test shouldFail= fAdapter.getTests().get(0);
+ TestResult result= new TestResult();
+ ErrorRememberingListener listener= new ErrorRememberingListener();
+ result.addListener(listener);
+ fAdapter.run(result);
+ assertNotNull(listener.getError());
+ assertTrue(shouldFail == listener.getError());
+ }
+
+ public static class InitializesWithError extends BlockJUnit4ClassRunner {
+ public InitializesWithError(Class<?> klass) throws Exception {
+ super(klass);
+ throw new Exception();
+ }
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/JUnit38ClassRunnerTest.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/JUnit38ClassRunnerTest.java
new file mode 100644
index 0000000..52fbd2c
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/JUnit38ClassRunnerTest.java
@@ -0,0 +1,79 @@
+package org.junit.tests.junit3compatibility;
+
+import static org.junit.Assert.assertEquals;
+import junit.extensions.TestDecorator;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.internal.runners.JUnit38ClassRunner;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+public class JUnit38ClassRunnerTest {
+ public static class MyTest extends TestCase {
+ public void testA() {
+
+ }
+ }
+
+ @Test public void plansDecoratorCorrectly() {
+ JUnit38ClassRunner runner= new JUnit38ClassRunner(new TestDecorator(new TestSuite(MyTest.class)));
+ assertEquals(1, runner.testCount());
+ }
+
+ public static class AnnotatedTest {
+ @Test public void foo() {
+ Assert.fail();
+ }
+ }
+
+ @Test public void canUnadaptAnAdapter() {
+ JUnit38ClassRunner runner= new JUnit38ClassRunner(new JUnit4TestAdapter(AnnotatedTest.class));
+ Result result= new JUnitCore().run(runner);
+ Failure failure= result.getFailures().get(0);
+ assertEquals(Description.createTestDescription(AnnotatedTest.class, "foo"), failure.getDescription());
+ }
+
+ static int count;
+
+ static public class OneTest extends TestCase {
+ public void testOne() {
+ }
+ }
+
+ @Test public void testListener() throws Exception {
+ JUnitCore runner= new JUnitCore();
+ RunListener listener= new RunListener() {
+ @Override
+ public void testStarted(Description description) {
+ assertEquals(Description.createTestDescription(OneTest.class, "testOne"),
+ description);
+ count++;
+ }
+ };
+
+ runner.addListener(listener);
+ count= 0;
+ Result result= runner.run(OneTest.class);
+ assertEquals(1, count);
+ assertEquals(1, result.getRunCount());
+ }
+
+ public static class ClassWithInvalidMethod extends TestCase {
+ @SuppressWarnings("unused")
+ private void testInvalid() {}
+ }
+
+ @Test public void invalidTestMethodReportedCorrectly() {
+ Result result= JUnitCore.runClasses(ClassWithInvalidMethod.class);
+ Failure failure= result.getFailures().get(0);
+ assertEquals("warning", failure.getDescription().getMethodName());
+ assertEquals("junit.framework.TestSuite$1", failure.getDescription().getClassName());
+ }
+
+}
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/OldTestClassAdaptingListenerTest.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/OldTestClassAdaptingListenerTest.java
new file mode 100644
index 0000000..8c68a1a
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/OldTestClassAdaptingListenerTest.java
@@ -0,0 +1,27 @@
+package org.junit.tests.junit3compatibility;
+
+import static org.junit.Assert.assertEquals;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import org.junit.Test;
+import org.junit.internal.runners.JUnit38ClassRunner;
+import org.junit.runner.Result;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
+
+public class OldTestClassAdaptingListenerTest {
+ @Test
+ public void addFailureDelegatesToNotifier() {
+ Result result= new Result();
+ RunListener listener= result.createListener();
+ RunNotifier notifier= new RunNotifier();
+ notifier.addFirstListener(listener);
+ TestCase testCase= new TestCase() {
+ };
+ TestListener adaptingListener= new JUnit38ClassRunner(testCase)
+ .createAdaptingListener(notifier);
+ adaptingListener.addFailure(testCase, new AssertionFailedError());
+ assertEquals(1, result.getFailureCount());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/OldTests.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/OldTests.java
new file mode 100644
index 0000000..ab154a6
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/OldTests.java
@@ -0,0 +1,11 @@
+package org.junit.tests.junit3compatibility;
+import junit.framework.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+
+@RunWith(AllTests.class)
+public class OldTests {
+ static public Test suite() {
+ return junit.tests.AllTests.suite();
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/junit3compatibility/SuiteMethodTest.java b/junit4/src/test/java/org/junit/tests/junit3compatibility/SuiteMethodTest.java
new file mode 100644
index 0000000..c4890d0
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/junit3compatibility/SuiteMethodTest.java
@@ -0,0 +1,123 @@
+package org.junit.tests.junit3compatibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+
+public class SuiteMethodTest {
+ public static boolean wasRun;
+
+ static public class OldTest extends TestCase {
+ public OldTest(String name) {
+ super(name);
+ }
+
+ public static junit.framework.Test suite() {
+ TestSuite result= new TestSuite();
+ result.addTest(new OldTest("notObviouslyATest"));
+ return result;
+ }
+
+ public void notObviouslyATest() {
+ wasRun= true;
+ }
+ }
+
+ @Test public void makeSureSuiteIsCalled() {
+ wasRun= false;
+ JUnitCore.runClasses(OldTest.class);
+ assertTrue(wasRun);
+ }
+
+ static public class NewTest {
+ @Test public void sample() {
+ wasRun= true;
+ }
+
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(NewTest.class);
+ }
+ }
+
+ @Test public void makeSureSuiteWorksWithJUnit4Classes() {
+ wasRun= false;
+ JUnitCore.runClasses(NewTest.class);
+ assertTrue(wasRun);
+ }
+
+
+ public static class CompatibilityTest {
+ @Ignore @Test
+ public void ignored() {
+ }
+
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(CompatibilityTest.class);
+ }
+ }
+
+ // when executing as JUnit 3, ignored tests are stripped out before execution
+ @Test
+ public void descriptionAndRunNotificationsAreConsistent() {
+ Result result= JUnitCore.runClasses(CompatibilityTest.class);
+ assertEquals(0, result.getIgnoreCount());
+
+ Description description= Request.aClass(CompatibilityTest.class).getRunner().getDescription();
+ assertEquals(0, description.getChildren().size());
+ }
+
+ static public class NewTestSuiteFails {
+ @Test public void sample() {
+ wasRun= true;
+ }
+
+ public static junit.framework.Test suite() {
+ fail("called with JUnit 4 runner");
+ return null;
+ }
+ }
+
+ @Test public void suiteIsUsedWithJUnit4Classes() {
+ wasRun= false;
+ Result result= JUnitCore.runClasses(NewTestSuiteFails.class);
+ assertEquals(1, result.getFailureCount());
+ assertFalse(wasRun);
+ }
+
+ static public class NewTestSuiteNotUsed {
+ private static boolean wasIgnoredRun;
+
+ @Test public void sample() {
+ wasRun= true;
+ }
+
+ @Ignore @Test public void ignore() {
+ wasIgnoredRun= true;
+ }
+
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(NewTestSuiteNotUsed.class);
+ }
+ }
+
+ @Test public void makeSureSuiteNotUsedWithJUnit4Classes2() {
+ wasRun= false;
+ NewTestSuiteNotUsed.wasIgnoredRun= false;
+ Result res= JUnitCore.runClasses(NewTestSuiteNotUsed.class);
+ assertTrue(wasRun);
+ assertFalse(NewTestSuiteNotUsed.wasIgnoredRun);
+ assertEquals(0, res.getFailureCount());
+ assertEquals(1, res.getRunCount());
+ assertEquals(0, res.getIgnoreCount());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/listening/ListenerTest.java b/junit4/src/test/java/org/junit/tests/listening/ListenerTest.java
new file mode 100644
index 0000000..964c4d4
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/listening/ListenerTest.java
@@ -0,0 +1,33 @@
+package org.junit.tests.listening;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.notification.RunListener;
+
+public class ListenerTest {
+ static private String log;
+ public static class OneTest {
+ @Test public void nothing() {
+ }
+ }
+ @Test public void notifyListenersInTheOrderInWhichTheyAreAdded() {
+ JUnitCore core= new JUnitCore();
+ log= "";
+ core.addListener(new RunListener() {
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ log+="first ";
+ }
+ });
+ core.addListener(new RunListener() {
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ log+="second ";
+ }
+ });
+ core.run(OneTest.class);
+ assertEquals("first second ", log);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/listening/RunnerTest.java b/junit4/src/test/java/org/junit/tests/listening/RunnerTest.java
new file mode 100644
index 0000000..a07848d
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/listening/RunnerTest.java
@@ -0,0 +1,69 @@
+package org.junit.tests.listening;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.notification.RunListener;
+
+public class RunnerTest {
+
+ private boolean wasRun;
+
+ public class MyListener extends RunListener {
+
+ int testCount;
+
+ @Override
+ public void testRunStarted(Description description) {
+ this.testCount= description.testCount();
+ }
+ }
+
+ public static class Example {
+ @Test public void empty() {
+ }
+ }
+
+ @Test public void newTestCount() {
+ JUnitCore runner= new JUnitCore();
+ MyListener listener= new MyListener();
+ runner.addListener(listener);
+ runner.run(Example.class);
+ assertEquals(1, listener.testCount);
+ }
+
+ public static class ExampleTest extends TestCase {
+ public void testEmpty() {
+ }
+ }
+
+ @Test public void oldTestCount() {
+ JUnitCore runner= new JUnitCore();
+ MyListener listener= new MyListener();
+ runner.addListener(listener);
+ runner.run(ExampleTest.class);
+ assertEquals(1, listener.testCount);
+ }
+
+ public static class NewExample {
+ @Test public void empty() {
+ }
+ }
+
+ @Test public void testFinished() {
+ JUnitCore runner= new JUnitCore();
+ wasRun= false;
+ RunListener listener= new MyListener() {
+ @Override
+ public void testFinished(Description description) {
+ wasRun= true;
+ }
+ };
+ runner.addListener(listener);
+ runner.run(NewExample.class);
+ assertTrue(wasRun);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/listening/TestListenerTest.java b/junit4/src/test/java/org/junit/tests/listening/TestListenerTest.java
new file mode 100644
index 0000000..35c0c75
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/listening/TestListenerTest.java
@@ -0,0 +1,63 @@
+package org.junit.tests.listening;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+public class TestListenerTest {
+
+ int count;
+
+ class ErrorListener extends RunListener {
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ throw new Error();
+ }
+ }
+
+ public static class OneTest {
+ @Test public void nothing() {}
+ }
+
+ @Test(expected=Error.class) public void failingListener() {
+ JUnitCore runner= new JUnitCore();
+ runner.addListener(new ErrorListener());
+ runner.run(OneTest.class);
+ }
+
+ class ExceptionListener extends ErrorListener {
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ count++;
+ throw new Exception();
+ }
+ }
+
+ @Test public void removeFailingListeners() {
+ JUnitCore core= new JUnitCore();
+ core.addListener(new ExceptionListener());
+
+ count= 0;
+ Result result= core.run(OneTest.class);
+ assertEquals(1, count);
+ assertEquals(1, result.getFailureCount());
+ Failure testFailure= result.getFailures().get(0);
+ assertEquals(Description.TEST_MECHANISM, testFailure.getDescription());
+
+ count= 0;
+ core.run(OneTest.class);
+ assertEquals(0, count); // Doesn't change because listener was removed
+ }
+
+ @Test public void freshResultEachTime() {
+ JUnitCore core= new JUnitCore();
+ Result first= core.run(OneTest.class);
+ Result second= core.run(OneTest.class);
+ assertNotSame(first, second);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/listening/TextListenerTest.java b/junit4/src/test/java/org/junit/tests/listening/TextListenerTest.java
new file mode 100644
index 0000000..b9684a6
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/listening/TextListenerTest.java
@@ -0,0 +1,65 @@
+package org.junit.tests.listening;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.internal.TextListener;
+import org.junit.runner.JUnitCore;
+import org.junit.tests.TestSystem;
+
+public class TextListenerTest extends TestCase {
+
+ private JUnitCore runner;
+ private OutputStream results;
+ private TextListener listener;
+
+ @Override
+ public void setUp() {
+ runner= new JUnitCore();
+ TestSystem system= new TestSystem();
+ results= system.outContents();
+ listener= new TextListener(system);
+ runner.addListener(listener);
+ }
+
+ public static class OneTest {
+ @Test public void one() {}
+ }
+
+ public void testSuccess() throws Exception {
+ runner.run(OneTest.class);
+ assertTrue(results.toString().startsWith(convert(".\nTime: ")));
+ assertTrue(results.toString().endsWith(convert("\n\nOK (1 test)\n\n")));
+ }
+
+ public static class ErrorTest {
+ @Test public void error() throws Exception {throw new Exception();}
+ }
+
+ public void testError() throws Exception {
+ runner.run(ErrorTest.class);
+ assertTrue(results.toString().startsWith(convert(".E\nTime: ")));
+ assertTrue(results.toString().indexOf(convert("\nThere was 1 failure:\n1) error(org.junit.tests.listening.TextListenerTest$ErrorTest)\njava.lang.Exception")) != -1);
+ }
+
+ public static class Slow {
+ @Test public void pause() throws InterruptedException {
+ Thread.sleep(1000);
+ }
+ }
+
+ public void testTime() {
+ runner.run(Slow.class);
+ assertFalse(results.toString().contains("Time: 0"));
+ }
+
+ private String convert(String string) {
+ OutputStream resultsStream= new ByteArrayOutputStream();
+ PrintStream writer= new PrintStream(resultsStream);
+ writer.println();
+ return string.replace("\n", resultsStream.toString());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/listening/UserStopTest.java b/junit4/src/test/java/org/junit/tests/listening/UserStopTest.java
new file mode 100644
index 0000000..822e203
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/listening/UserStopTest.java
@@ -0,0 +1,28 @@
+package org.junit.tests.listening;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Request;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runner.notification.StoppedByUserException;
+
+public class UserStopTest {
+ private RunNotifier fNotifier;
+
+ @Before public void createNotifier() {
+ fNotifier= new RunNotifier();
+ fNotifier.pleaseStop();
+ }
+
+ @Test(expected=StoppedByUserException.class) public void userStop() {
+ fNotifier.fireTestStarted(null);
+ }
+
+ public static class OneTest {
+ @Test public void foo() {}
+ }
+
+ @Test(expected=StoppedByUserException.class) public void stopClassRunner() throws Exception {
+ Request.aClass(OneTest.class).getRunner().run(fNotifier);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/manipulation/FilterTest.java b/junit4/src/test/java/org/junit/tests/manipulation/FilterTest.java
new file mode 100644
index 0000000..242e990
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/manipulation/FilterTest.java
@@ -0,0 +1,49 @@
+package org.junit.tests.manipulation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+
+public class FilterTest {
+ public static class NamedFilter extends Filter {
+ private final String fName;
+
+ public NamedFilter(String name) {
+ fName= name;
+ }
+
+ @Override
+ public boolean shouldRun(Description description) {
+ return false;
+ }
+
+ @Override
+ public String describe() {
+ return fName;
+ }
+ }
+
+ @Test
+ public void intersectionText() {
+ NamedFilter a= new NamedFilter("a");
+ NamedFilter b= new NamedFilter("b");
+ assertEquals("a and b", a.intersect(b).describe());
+ assertEquals("b and a", b.intersect(a).describe());
+ }
+
+ @Test
+ public void intersectSelf() {
+ NamedFilter a= new NamedFilter("a");
+ assertSame(a, a.intersect(a));
+ }
+
+ @Test
+ public void intersectAll() {
+ NamedFilter a= new NamedFilter("a");
+ assertSame(a, a.intersect(Filter.ALL));
+ assertSame(a, Filter.ALL.intersect(a));
+ assertSame(Filter.ALL, Filter.ALL.intersect(Filter.ALL));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/manipulation/FilterableTest.java b/junit4/src/test/java/org/junit/tests/manipulation/FilterableTest.java
new file mode 100644
index 0000000..3d35169
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/manipulation/FilterableTest.java
@@ -0,0 +1,62 @@
+package org.junit.tests.manipulation;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+public class FilterableTest {
+ public static class FilteredRunner extends Parameterized {
+ public FilteredRunner(Class<?> klass) throws Throwable {
+ super(klass);
+ filter(new Filter() {
+
+ @Override
+ public boolean shouldRun(Description description) {
+ return !description.getDisplayName().contains("skip");
+ }
+
+ @Override
+ public String describe() {
+ return "skip methods containing the word 'skip'";
+ }
+ });
+ }
+ }
+
+ @RunWith(FilteredRunner.class)
+ public static class FilteredTest {
+ @Parameters
+ public static List<Object[]> parameters() {
+ return Arrays.asList(new Object[] { 3 }, new Object[] { 4 });
+ }
+
+ public FilteredTest(int x) {
+ }
+
+ @Test
+ public void skipThis() {
+ Assert.fail();
+ }
+
+ @Test
+ public void runThis() {
+ }
+ }
+
+ @Test
+ public void testFilterInRunnerConstructor() {
+ Result result= JUnitCore.runClasses(FilteredTest.class);
+ assertTrue(result.wasSuccessful());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/manipulation/SingleMethodTest.java b/junit4/src/test/java/org/junit/tests/manipulation/SingleMethodTest.java
new file mode 100644
index 0000000..393a844
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/manipulation/SingleMethodTest.java
@@ -0,0 +1,168 @@
+package org.junit.tests.manipulation;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.JUnit4TestAdapter;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.Filterable;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Suite;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Suite.SuiteClasses;
+
+public class SingleMethodTest {
+ public static int count;
+
+ static public class OneTimeSetup {
+ @BeforeClass public static void once() {
+ count++;
+ }
+
+ @Test public void one() {
+ }
+
+ @Test public void two() {
+ }
+ }
+
+ @Test public void oneTimeSetup() throws Exception {
+ count = 0;
+ Runner runner = Request.method(OneTimeSetup.class, "one").getRunner();
+ Result result = new JUnitCore().run(runner);
+
+ assertEquals(1, count);
+ assertEquals(1, result.getRunCount());
+ }
+
+ @RunWith(Parameterized.class)
+ static public class ParameterizedOneTimeSetup {
+ @Parameters
+ public static List<Object[]> params() {
+ return Arrays.asList(new Object[] {1}, new Object[] {2});
+ }
+
+ public ParameterizedOneTimeSetup(int x) {
+ }
+
+ @Test public void one() {
+ }
+ }
+
+ @Test public void parameterizedFilterToSingleMethod() throws Exception {
+ count = 0;
+ Runner runner = Request.method(ParameterizedOneTimeSetup.class,
+ "one[0]").getRunner();
+ Result result = new JUnitCore().run(runner);
+
+ assertEquals(1, result.getRunCount());
+ }
+
+ @RunWith(Parameterized.class)
+ static public class ParameterizedOneTimeBeforeClass {
+ @Parameters
+ public static List<Object[]> params() {
+ return Arrays.asList(new Object[] {1}, new Object[] {2});
+ }
+
+ public ParameterizedOneTimeBeforeClass(int x) {
+ }
+
+ @BeforeClass public static void once() {
+ count++;
+ }
+
+ @Test public void one() {
+ }
+ }
+
+
+ @Test public void parameterizedBeforeClass() throws Exception {
+ count = 0;
+ JUnitCore.runClasses(ParameterizedOneTimeBeforeClass.class);
+ assertEquals(1, count);
+ }
+
+ @Test public void filteringAffectsPlan() throws Exception {
+ Runner runner = Request.method(OneTimeSetup.class, "one").getRunner();
+ assertEquals(1, runner.testCount());
+ }
+
+ @Test public void nonexistentMethodCreatesFailure() throws Exception {
+ assertEquals(1, new JUnitCore().run(
+ Request.method(OneTimeSetup.class, "thisMethodDontExist"))
+ .getFailureCount());
+ }
+
+ @Test(expected = NoTestsRemainException.class)
+ public void filteringAwayEverythingThrowsException() throws NoTestsRemainException {
+ Filterable runner = (Filterable) Request.aClass(OneTimeSetup.class).getRunner();
+ runner.filter(new Filter() {
+ @Override
+ public boolean shouldRun(Description description) {
+ return false;
+ }
+
+ @Override
+ public String describe() {
+ return null;
+ }
+ });
+ }
+
+ public static class TestOne {
+ @Test public void a() {
+ }
+
+ @Test public void b() {
+ }
+ }
+
+ public static class TestTwo {
+ @Test public void a() {
+ }
+
+ @Test public void b() {
+ }
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses( { TestOne.class, TestTwo.class })
+ public static class OneTwoSuite {
+ }
+
+ @Test public void eliminateUnnecessaryTreeBranches() throws Exception {
+ Runner runner = Request.aClass(OneTwoSuite.class).filterWith(
+ Description.createTestDescription(TestOne.class, "a"))
+ .getRunner();
+ Description description = runner.getDescription();
+ assertEquals(1, description.getChildren().size());
+ }
+
+ public static class HasSuiteMethod {
+ @Test public void a() {}
+ @Test public void b() {}
+
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(HasSuiteMethod.class);
+ }
+ }
+
+ @Test public void classesWithSuiteMethodsAreFiltered() {
+ int testCount= Request.method(HasSuiteMethod.class, "a").getRunner().getDescription().testCount();
+ assertThat(testCount, is(1));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/manipulation/SortableTest.java b/junit4/src/test/java/org/junit/tests/manipulation/SortableTest.java
new file mode 100644
index 0000000..eac7aa8
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/manipulation/SortableTest.java
@@ -0,0 +1,149 @@
+package org.junit.tests.manipulation;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Comparator;
+
+import junit.framework.JUnit4TestAdapter;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+
+@RunWith(Enclosed.class)
+public class SortableTest {
+ private static Comparator<Description> forward() {
+ return new Comparator<Description>() {
+ public int compare(Description o1, Description o2) {
+ return o1.getDisplayName().compareTo(o2.getDisplayName());
+ }
+ };
+ }
+
+ private static Comparator<Description> backward() {
+ return new Comparator<Description>() {
+ public int compare(Description o1, Description o2) {
+ return o2.getDisplayName().compareTo(o1.getDisplayName());
+ }
+ };
+ }
+
+ public static class TestClassRunnerIsSortable {
+ private static String log= "";
+
+ public static class SortMe {
+ @Test public void a() { log+= "a"; }
+ @Test public void b() { log+= "b"; }
+ @Test public void c() { log+= "c"; }
+ }
+
+ @Before public void resetLog() {
+ log= "";
+ }
+
+ @Test public void sortingForwardWorksOnTestClassRunner() {
+ Request forward= Request.aClass(SortMe.class).sortWith(forward());
+
+ new JUnitCore().run(forward);
+ assertEquals("abc", log);
+ }
+
+ @Test public void sortingBackwardWorksOnTestClassRunner() {
+ Request backward= Request.aClass(SortMe.class).sortWith(backward());
+
+ new JUnitCore().run(backward);
+ assertEquals("cba", log);
+ }
+
+ @RunWith(Enclosed.class)
+ public static class Enclosing {
+ public static class A {
+ @Test public void a() { log+= "Aa"; }
+ @Test public void b() { log+= "Ab"; }
+ @Test public void c() { log+= "Ac"; }
+ }
+ public static class B {
+ @Test public void a() { log+= "Ba"; }
+ @Test public void b() { log+= "Bb"; }
+ @Test public void c() { log+= "Bc"; }
+ }
+ }
+
+ @Test public void sortingForwardWorksOnSuite() {
+ Request forward= Request.aClass(Enclosing.class).sortWith(forward());
+
+ new JUnitCore().run(forward);
+ assertEquals("AaAbAcBaBbBc", log);
+ }
+
+ @Test public void sortingBackwardWorksOnSuite() {
+ Request backward= Request.aClass(Enclosing.class).sortWith(backward());
+
+ new JUnitCore().run(backward);
+ assertEquals("BcBbBaAcAbAa", log);
+ }
+ }
+
+ public static class TestClassRunnerIsSortableWithSuiteMethod {
+ private static String log= "";
+
+ public static class SortMe {
+ @Test public void a() { log+= "a"; }
+ @Test public void b() { log+= "b"; }
+ @Test public void c() { log+= "c"; }
+
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(SortMe.class);
+ }
+ }
+
+ @Before public void resetLog() {
+ log= "";
+ }
+
+ @Test public void sortingForwardWorksOnTestClassRunner() {
+ Request forward= Request.aClass(SortMe.class).sortWith(forward());
+
+ new JUnitCore().run(forward);
+ assertEquals("abc", log);
+ }
+
+ @Test public void sortingBackwardWorksOnTestClassRunner() {
+ Request backward= Request.aClass(SortMe.class).sortWith(backward());
+
+ new JUnitCore().run(backward);
+ assertEquals("cba", log);
+ }
+ }
+
+ public static class UnsortableRunnersAreHandledWithoutCrashing {
+ public static class UnsortableRunner extends Runner {
+ public UnsortableRunner(Class<?> klass) {
+ }
+
+ @Override
+ public Description getDescription() {
+ return Description.EMPTY;
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ }
+ }
+
+ @RunWith(UnsortableRunner.class)
+ public static class Unsortable {
+ @Test public void a() {}
+ }
+
+ @Test public void unsortablesAreHandledWithoutCrashing() {
+ Request unsorted= Request.aClass(Unsortable.class).sortWith(forward());
+ new JUnitCore().run(unsorted);
+ }
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/package-info.java b/junit4/src/test/java/org/junit/tests/package-info.java
new file mode 100644
index 0000000..21d611c
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * Tests the JUnit functionality.
+ *
+ * Corresponds to {@link junit.tests.AllTests} in Junit 3.x.
+ *
+ * @since 4.0
+ */
+package org.junit.tests; \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java b/junit4/src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java
new file mode 100644
index 0000000..a19cd94
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java
@@ -0,0 +1,33 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+
+public class BlockJUnit4ClassRunnerTest {
+ public static class OuterClass {
+ public class Enclosed {
+ @Test
+ public void test() {
+ }
+ }
+ }
+
+ @Test
+ public void detectNonStaticEnclosedClass() throws Exception {
+ try {
+ new BlockJUnit4ClassRunner(OuterClass.Enclosed.class);
+ } catch (InitializationError e) {
+ List<Throwable> causes= e.getCauses();
+ assertEquals("Wrong number of causes.", 1, causes.size());
+ assertEquals(
+ "Wrong exception.",
+ "The inner class org.junit.tests.running.classes.BlockJUnit4ClassRunnerTest$OuterClass$Enclosed is not static.",
+ causes.get(0).getMessage());
+ }
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/EnclosedTest.java b/junit4/src/test/java/org/junit/tests/running/classes/EnclosedTest.java
new file mode 100644
index 0000000..8a6973a
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/EnclosedTest.java
@@ -0,0 +1,40 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+
+public class EnclosedTest {
+ @RunWith(Enclosed.class)
+ public static class Enclosing {
+ public static class A {
+ @Test public void a() {}
+ @Test public void b() {}
+ }
+ public static class B {
+ @Test public void a() {}
+ @Test public void b() {}
+ @Test public void c() {}
+ }
+ }
+
+ @Test public void enclosedRunnerPlansEnclosedClasses() throws Exception {
+ Runner runner= Request.aClass(Enclosing.class).getRunner();
+ assertEquals(5, runner.testCount());
+ }
+
+ @Test public void enclosedRunnerRunsEnclosedClasses() throws Exception {
+ Result result= JUnitCore.runClasses(Enclosing.class);
+ assertEquals(5, result.getRunCount());
+ }
+
+ @Test public void enclosedRunnerIsNamedForEnclosingClass() throws Exception {
+ assertEquals(Enclosing.class.getName(), Request.aClass(Enclosing.class)
+ .getRunner().getDescription().getDisplayName());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/IgnoreClassTest.java b/junit4/src/test/java/org/junit/tests/running/classes/IgnoreClassTest.java
new file mode 100644
index 0000000..e193712
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/IgnoreClassTest.java
@@ -0,0 +1,26 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+
+public class IgnoreClassTest {
+ @Ignore("For a good reason") public static class IgnoreMe {
+ @Test public void iFail() {
+ fail();
+ }
+
+ @Test public void iFailToo() {
+ fail();
+ }
+ }
+
+ @Test public void ignoreClass() {
+ Result result= JUnitCore.runClasses(IgnoreMe.class);
+ assertEquals(0, result.getFailureCount());
+ assertEquals(1, result.getIgnoreCount());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java b/junit4/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
new file mode 100644
index 0000000..d48433f
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
@@ -0,0 +1,216 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.model.InitializationError;
+
+public class ParameterizedTestTest {
+ @RunWith(Parameterized.class)
+ static public class FibonacciTest {
+ @Parameters
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
+ { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
+ }
+
+ private int fInput;
+
+ private int fExpected;
+
+ public FibonacciTest(int input, int expected) {
+ fInput= input;
+ fExpected= expected;
+ }
+
+ @Test
+ public void test() {
+ assertEquals(fExpected, fib(fInput));
+ }
+
+ private int fib(int x) {
+ return 0;
+ }
+ }
+
+ @Test
+ public void count() {
+ Result result= JUnitCore.runClasses(FibonacciTest.class);
+ assertEquals(7, result.getRunCount());
+ assertEquals(6, result.getFailureCount());
+ }
+
+ @Test
+ public void failuresNamedCorrectly() {
+ Result result= JUnitCore.runClasses(FibonacciTest.class);
+ assertEquals(String
+ .format("test[1](%s)", FibonacciTest.class.getName()), result
+ .getFailures().get(0).getTestHeader());
+ }
+
+ @Test
+ public void countBeforeRun() throws Exception {
+ Runner runner= Request.aClass(FibonacciTest.class).getRunner();
+ assertEquals(7, runner.testCount());
+ }
+
+ @Test
+ public void plansNamedCorrectly() throws Exception {
+ Runner runner= Request.aClass(FibonacciTest.class).getRunner();
+ Description description= runner.getDescription();
+ assertEquals("[0]", description.getChildren().get(0).getDisplayName());
+ }
+
+ private static String fLog;
+
+ @RunWith(Parameterized.class)
+ static public class BeforeAndAfter {
+ @BeforeClass
+ public static void before() {
+ fLog+= "before ";
+ }
+
+ @AfterClass
+ public static void after() {
+ fLog+= "after ";
+ }
+
+ public BeforeAndAfter(int x) {
+
+ }
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { { 3 } });
+ }
+
+ @Test
+ public void aTest() {
+ }
+ }
+
+ @Test
+ public void beforeAndAfterClassAreRun() {
+ fLog= "";
+ JUnitCore.runClasses(BeforeAndAfter.class);
+ assertEquals("before after ", fLog);
+ }
+
+ @RunWith(Parameterized.class)
+ static public class EmptyTest {
+ @BeforeClass
+ public static void before() {
+ fLog+= "before ";
+ }
+
+ @AfterClass
+ public static void after() {
+ fLog+= "after ";
+ }
+ }
+
+ @Test
+ public void validateClassCatchesNoParameters() {
+ Result result= JUnitCore.runClasses(EmptyTest.class);
+ assertEquals(1, result.getFailureCount());
+ }
+
+ @RunWith(Parameterized.class)
+ static public class IncorrectTest {
+ @Test
+ public int test() {
+ return 0;
+ }
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ return Collections.singletonList(new Object[] {1});
+ }
+ }
+
+ @Test
+ public void failuresAddedForBadTestMethod() throws Exception {
+ Result result= JUnitCore.runClasses(IncorrectTest.class);
+ assertEquals(1, result.getFailureCount());
+ }
+
+ @RunWith(Parameterized.class)
+ static public class ProtectedParametersTest {
+ @Parameters
+ protected static Collection<Object[]> data() {
+ return Collections.emptyList();
+ }
+
+ @Test
+ public void aTest() {
+ }
+ }
+
+ @Test
+ public void meaningfulFailureWhenParametersNotPublic() throws Exception {
+ Result result= JUnitCore.runClasses(ProtectedParametersTest.class);
+ String expected= String.format(
+ "No public static parameters method on class %s",
+ ProtectedParametersTest.class.getName());
+ assertEquals(expected, result.getFailures().get(0).getMessage());
+ }
+
+ @RunWith(Parameterized.class)
+ static public class WrongElementType {
+ @Parameters
+ public static Collection<String> data() {
+ return Arrays.asList("a", "b", "c");
+ }
+
+ @Test
+ public void aTest() {
+ }
+ }
+
+ @Test
+ public void meaningfulFailureWhenParameterListsAreNotArrays() {
+ String expected= String.format(
+ "%s.data() must return a Collection of arrays.",
+ WrongElementType.class.getName());
+ assertThat(testResult(WrongElementType.class).toString(),
+ containsString(expected));
+ }
+
+ @RunWith(Parameterized.class)
+ static public class PrivateConstructor {
+ private PrivateConstructor(int x) {
+
+ }
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { { 3 } });
+ }
+
+ @Test
+ public void aTest() {
+ }
+ }
+
+ @Test(expected=InitializationError.class)
+ public void exceptionWhenPrivateConstructor() throws Throwable {
+ new Parameterized(PrivateConstructor.class);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/ParentRunnerFilteringTest.java b/junit4/src/test/java/org/junit/tests/running/classes/ParentRunnerFilteringTest.java
new file mode 100644
index 0000000..9bf542f
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/ParentRunnerFilteringTest.java
@@ -0,0 +1,171 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
+import static org.junit.runner.Description.createSuiteDescription;
+import static org.junit.runner.Description.createTestDescription;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+public class ParentRunnerFilteringTest {
+ private static Filter notThisMethodName(final String methodName) {
+ return new Filter() {
+ @Override
+ public boolean shouldRun(Description description) {
+ return description.getMethodName() == null
+ || !description.getMethodName().equals(methodName);
+ }
+
+ @Override
+ public String describe() {
+ return "don't run method name: " + methodName;
+ }
+ };
+ }
+
+ private static class CountingFilter extends Filter {
+ private final Map<Description, Integer> countMap= new HashMap<Description, Integer>();
+
+ @Override
+ public boolean shouldRun(Description description) {
+ Integer count= countMap.get(description);
+ if (count == null) {
+ countMap.put(description, 1);
+ } else {
+ countMap.put(description, count + 1);
+ }
+ return true;
+ }
+
+ @Override
+ public String describe() {
+ return "filter counter";
+ }
+
+ public int getCount(final Description desc) {
+ if (!countMap.containsKey(desc)) {
+ throw new IllegalArgumentException("Looking for " + desc
+ + ", but only contains: " + countMap.keySet());
+ }
+ return countMap.get(desc);
+ }
+ }
+
+ public static class ExampleTest {
+ @Test
+ public void test1() throws Exception {
+ // passes
+ }
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses({ ExampleTest.class })
+ public static class ExampleSuite {
+ }
+
+ @Test
+ public void testSuiteFiltering() throws Exception {
+ Runner runner= Request.aClass(ExampleSuite.class).getRunner();
+ Filter filter= notThisMethodName("test1");
+ try {
+ filter.apply(runner);
+ } catch (NoTestsRemainException e) {
+ return;
+ }
+ fail("Expected 'NoTestsRemainException' due to complete filtering");
+ }
+
+ public static class SuiteWithUnmodifyableChildList extends Suite {
+
+ public SuiteWithUnmodifyableChildList(
+ Class<?> klass, RunnerBuilder builder)
+ throws InitializationError {
+ super(klass, builder);
+ }
+
+ @Override
+ protected List<Runner> getChildren() {
+ return Collections.unmodifiableList(super.getChildren());
+ }
+ }
+
+ @RunWith(SuiteWithUnmodifyableChildList.class)
+ @SuiteClasses({ ExampleTest.class })
+ public static class ExampleSuiteWithUnmodifyableChildList {
+ }
+
+ @Test
+ public void testSuiteFilteringWithUnmodifyableChildList() throws Exception {
+ Runner runner= Request.aClass(ExampleSuiteWithUnmodifyableChildList.class)
+ .getRunner();
+ Filter filter= notThisMethodName("test1");
+ try {
+ filter.apply(runner);
+ } catch (NoTestsRemainException e) {
+ return;
+ }
+ fail("Expected 'NoTestsRemainException' due to complete filtering");
+ }
+
+ @Test
+ public void testRunSuiteFiltering() throws Exception {
+ Request request= Request.aClass(ExampleSuite.class);
+ Request requestFiltered= request.filterWith(notThisMethodName("test1"));
+ assertThat(testResult(requestFiltered),
+ hasSingleFailureContaining("don't run method name: test1"));
+ }
+
+ @Test
+ public void testCountClassFiltering() throws Exception {
+ JUnitCore junitCore= new JUnitCore();
+ Request request= Request.aClass(ExampleTest.class);
+ CountingFilter countingFilter= new CountingFilter();
+ Request requestFiltered= request.filterWith(countingFilter);
+ Result result= junitCore.run(requestFiltered);
+ assertEquals(1, result.getRunCount());
+ assertEquals(0, result.getFailureCount());
+
+ Description desc= createTestDescription(ExampleTest.class, "test1");
+ assertEquals(1, countingFilter.getCount(desc));
+ }
+
+ @Test
+ public void testCountSuiteFiltering() throws Exception {
+ Class<ExampleSuite> suiteClazz= ExampleSuite.class;
+ Class<ExampleTest> clazz= ExampleTest.class;
+
+ JUnitCore junitCore= new JUnitCore();
+ Request request= Request.aClass(suiteClazz);
+ CountingFilter countingFilter= new CountingFilter();
+ Request requestFiltered= request.filterWith(countingFilter);
+ Result result= junitCore.run(requestFiltered);
+ assertEquals(1, result.getRunCount());
+ assertEquals(0, result.getFailureCount());
+
+ Description suiteDesc= createSuiteDescription(clazz);
+ assertEquals(1, countingFilter.getCount(suiteDesc));
+
+ Description desc= createTestDescription(ExampleTest.class, "test1");
+ assertEquals(1, countingFilter.getCount(desc));
+ }
+} \ No newline at end of file
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java b/junit4/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java
new file mode 100644
index 0000000..21c22b8
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java
@@ -0,0 +1,139 @@
+package org.junit.tests.running.classes;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.internal.matchers.TypeSafeMatcher;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.ParentRunner;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerScheduler;
+import org.junit.tests.experimental.rules.RuleFieldValidatorTest.TestWithNonStaticClassRule;
+import org.junit.tests.experimental.rules.RuleFieldValidatorTest.TestWithProtectedClassRule;
+
+public class ParentRunnerTest {
+ public static String log= "";
+
+ public static class FruitTest {
+ @Test
+ public void apple() {
+ log+= "apple ";
+ }
+
+ @Test
+ public void banana() {
+ log+= "banana ";
+ }
+ }
+
+ @Test
+ public void useChildHarvester() throws InitializationError {
+ log= "";
+ ParentRunner<?> runner= new BlockJUnit4ClassRunner(FruitTest.class);
+ runner.setScheduler(new RunnerScheduler() {
+ public void schedule(Runnable childStatement) {
+ log+= "before ";
+ childStatement.run();
+ log+= "after ";
+ }
+
+ public void finished() {
+ log+= "afterAll ";
+ }
+ });
+
+ runner.run(new RunNotifier());
+ assertEquals("before apple after before banana after afterAll ", log);
+ }
+
+ @Test
+ public void testMultipleFilters() throws Exception {
+ JUnitCore junitCore= new JUnitCore();
+ Request request= Request.aClass(ExampleTest.class);
+ Request requestFiltered= request.filterWith(new Exclude("test1"));
+ Request requestFilteredFiltered= requestFiltered
+ .filterWith(new Exclude("test2"));
+ Result result= junitCore.run(requestFilteredFiltered);
+ assertThat(result.getFailures(), isEmpty());
+ assertEquals(1, result.getRunCount());
+ }
+
+ private Matcher<List<?>> isEmpty() {
+ return new TypeSafeMatcher<List<?>>() {
+ public void describeTo(org.hamcrest.Description description) {
+ description.appendText("is empty");
+ }
+
+ @Override
+ public boolean matchesSafely(List<?> item) {
+ return item.size() == 0;
+ }
+ };
+ }
+
+ private static class Exclude extends Filter {
+ private String methodName;
+
+ public Exclude(String methodName) {
+ this.methodName= methodName;
+ }
+
+ @Override
+ public boolean shouldRun(Description description) {
+ return !description.getMethodName().equals(methodName);
+ }
+
+ @Override
+ public String describe() {
+ return "filter method name: " + methodName;
+ }
+ }
+
+ public static class ExampleTest {
+ @Test
+ public void test1() throws Exception {
+ }
+
+ @Test
+ public void test2() throws Exception {
+ }
+
+ @Test
+ public void test3() throws Exception {
+ }
+ }
+
+ @Test
+ public void failWithHelpfulMessageForProtectedClassRule() {
+ assertClassHasFailureMessage(TestWithProtectedClassRule.class,
+ "The @ClassRule 'temporaryFolder' must be public.");
+ }
+
+ @Test
+ public void failWithHelpfulMessageForNonStaticClassRule() {
+ assertClassHasFailureMessage(TestWithNonStaticClassRule.class,
+ "The @ClassRule 'temporaryFolder' must be static.");
+ }
+
+ private void assertClassHasFailureMessage(Class<?> klass, String message) {
+ JUnitCore junitCore= new JUnitCore();
+ Request request= Request.aClass(klass);
+ Result result= junitCore.run(request);
+ assertThat(result.getFailureCount(), is(2)); //the second failure is no runnable methods
+ assertThat(result.getFailures().get(0).getMessage(),
+ is(equalTo(message)));
+
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/RunWithTest.java b/junit4/src/test/java/org/junit/tests/running/classes/RunWithTest.java
new file mode 100644
index 0000000..1df0167
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/RunWithTest.java
@@ -0,0 +1,85 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+
+public class RunWithTest {
+
+ private static String log;
+
+ public static class ExampleRunner extends Runner {
+ public ExampleRunner(Class<?> klass) {
+ log+= "initialize";
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ log+= "run";
+ }
+
+ @Override
+ public int testCount() {
+ log+= "count";
+ return 0;
+ }
+
+ @Override
+ public Description getDescription() {
+ log+= "plan";
+ return Description.createSuiteDescription("example");
+ }
+ }
+
+ @RunWith(ExampleRunner.class)
+ public static class ExampleTest {
+ }
+
+ @Test public void run() {
+ log= "";
+
+ JUnitCore.runClasses(ExampleTest.class);
+ assertTrue(log.contains("plan"));
+ assertTrue(log.contains("initialize"));
+ assertTrue(log.contains("run"));
+ }
+
+ public static class SubExampleTest extends ExampleTest {
+ }
+
+ @Test public void runWithExtendsToSubclasses() {
+ log= "";
+
+ JUnitCore.runClasses(SubExampleTest.class);
+ assertTrue(log.contains("run"));
+ }
+
+ public static class BadRunner extends Runner {
+ @Override
+ public Description getDescription() {
+ return null;
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ // do nothing
+ }
+ }
+
+ @RunWith(BadRunner.class)
+ public static class Empty {
+ }
+
+ @Test
+ public void characterizeErrorMessageFromBadRunner() {
+ assertEquals(
+ "Custom runner class BadRunner should have a public constructor with signature BadRunner(Class testClass)",
+ JUnitCore.runClasses(Empty.class).getFailures().get(0)
+ .getMessage());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/SuiteTest.java b/junit4/src/test/java/org/junit/tests/running/classes/SuiteTest.java
new file mode 100644
index 0000000..bda24fd
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/SuiteTest.java
@@ -0,0 +1,167 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.experimental.results.PrintableResult.testResult;
+import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining;
+
+import java.util.List;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestResult;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+public class SuiteTest {
+ public static class TestA {
+ @Test public void pass() {
+ }
+ }
+
+ public static class TestB {
+ @Test public void fail() {
+ Assert.fail();
+ }
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses({TestA.class, TestB.class})
+ public static class All {
+ }
+
+ public static class InheritsAll extends All {
+ }
+
+ @Test public void ensureTestIsRun() {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(All.class);
+ assertEquals(2, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ }
+
+ @Test public void ensureInheritedTestIsRun() {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(InheritsAll.class);
+ assertEquals(2, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ }
+
+ @Test public void suiteTestCountIsCorrect() throws Exception {
+ Runner runner= Request.aClass(All.class).getRunner();
+ assertEquals(2, runner.testCount());
+ }
+
+ @Test public void ensureSuitesWorkWithForwardCompatibility() {
+ junit.framework.Test test= new JUnit4TestAdapter(All.class);
+ TestResult result= new TestResult();
+ test.run(result);
+ assertEquals(2, result.runCount());
+ }
+
+ @Test public void forwardCompatibilityWorksWithGetTests() {
+ JUnit4TestAdapter adapter= new JUnit4TestAdapter(All.class);
+ List<? extends junit.framework.Test> tests= adapter.getTests();
+ assertEquals(2, tests.size());
+ }
+
+ @Test public void forwardCompatibilityWorksWithTestCount() {
+ JUnit4TestAdapter adapter= new JUnit4TestAdapter(All.class);
+ assertEquals(2, adapter.countTestCases());
+ }
+
+
+ private static String log= "";
+ @RunWith(Suite.class)
+ @SuiteClasses({TestA.class, TestB.class})
+ public static class AllWithBeforeAndAfterClass {
+ @BeforeClass public static void before() { log+= "before "; }
+ @AfterClass public static void after() { log+= "after "; }
+ }
+
+ @Test public void beforeAndAfterClassRunOnSuite() {
+ log= "";
+ JUnitCore.runClasses(AllWithBeforeAndAfterClass.class);
+ assertEquals("before after ", log);
+ }
+
+ @RunWith(Suite.class)
+ public static class AllWithOutAnnotation {
+ }
+
+ @Test public void withoutSuiteClassAnnotationProducesFailure() {
+ Result result= JUnitCore.runClasses(AllWithOutAnnotation.class);
+ assertEquals(1, result.getFailureCount());
+ String expected= String.format(
+ "class '%s' must have a SuiteClasses annotation",
+ AllWithOutAnnotation.class.getName());
+ assertEquals(expected, result.getFailures().get(0).getMessage());
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses(InfiniteLoop.class)
+ static public class InfiniteLoop { }
+
+ @Test public void whatHappensWhenASuiteHasACycle() {
+ Result result= JUnitCore.runClasses(InfiniteLoop.class);
+ assertEquals(1, result.getFailureCount());
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses({BiInfiniteLoop.class, BiInfiniteLoop.class})
+ static public class BiInfiniteLoop { }
+
+ @Test public void whatHappensWhenASuiteHasAForkingCycle() {
+ Result result= JUnitCore.runClasses(BiInfiniteLoop.class);
+ assertEquals(2, result.getFailureCount());
+ }
+
+ // The interesting case here is that Hydra indirectly contains two copies of
+ // itself (if it only contains one, Java's StackOverflowError eventually
+ // bails us out)
+
+ @RunWith(Suite.class)
+ @SuiteClasses({Hercules.class})
+ static public class Hydra { }
+
+ @RunWith(Suite.class)
+ @SuiteClasses({Hydra.class, Hydra.class})
+ static public class Hercules { }
+
+ @Test public void whatHappensWhenASuiteContainsItselfIndirectly() {
+ Result result= JUnitCore.runClasses(Hydra.class);
+ assertEquals(2, result.getFailureCount());
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses( {})
+ public class WithoutDefaultConstructor {
+ public WithoutDefaultConstructor(int i) {
+
+ }
+ }
+
+ @Test
+ public void suiteShouldBeOKwithNonDefaultConstructor() throws Exception {
+ Result result= JUnitCore.runClasses(WithoutDefaultConstructor.class);
+ assertTrue(result.wasSuccessful());
+ }
+
+ @RunWith(Suite.class)
+ public class NoSuiteClassesAnnotation {
+ }
+
+ @Test
+ public void suiteShouldComplainAboutNoSuiteClassesAnnotation() {
+ assertThat(testResult(NoSuiteClassesAnnotation.class), hasSingleFailureContaining("SuiteClasses"));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/TestClassTest.java b/junit4/src/test/java/org/junit/tests/running/classes/TestClassTest.java
new file mode 100644
index 0000000..7b738d9
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/TestClassTest.java
@@ -0,0 +1,121 @@
+package org.junit.tests.running.classes;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.TestClass;
+
+public class TestClassTest {
+ public static class TwoConstructors {
+ public TwoConstructors() {
+ }
+
+ public TwoConstructors(int x) {
+ }
+ }
+
+ @Test(expected= IllegalArgumentException.class)
+ public void complainIfMultipleConstructors() {
+ new TestClass(TwoConstructors.class);
+ }
+
+ public static class ManyMethods {
+ @Test
+ public void a() {
+ }
+
+ @Before
+ public void b() {
+ }
+
+ @Ignore
+ @Test
+ public void c() {
+ }
+
+ @Ignore
+ @After
+ public void d() {
+ }
+
+ public void e() {
+ }
+
+ @BeforeClass
+ public void f() {
+ }
+
+ public void g() {
+ }
+
+ @AfterClass
+ public void h() {
+ }
+
+ @Test
+ public void i() {
+ }
+
+ @Test
+ public void j() {
+ }
+ }
+
+ public static class SuperclassWithField {
+ @Rule
+ public TestRule x;
+ }
+
+ public static class SubclassWithField extends SuperclassWithField {
+ @Rule
+ public TestRule x;
+ }
+
+ @Test
+ public void fieldsOnSubclassesShadowSuperclasses() {
+ assertThat(new TestClass(SubclassWithField.class).getAnnotatedFields(
+ Rule.class).size(), is(1));
+ }
+
+ public static class OuterClass {
+ public class NonStaticInnerClass {
+ }
+ }
+
+ @Test
+ public void identifyNonStaticInnerClass() {
+ assertThat(
+ new TestClass(OuterClass.NonStaticInnerClass.class)
+ .isANonStaticInnerClass(),
+ is(true));
+ }
+
+ public static class OuterClass2 {
+ public static class StaticInnerClass {
+ }
+ }
+
+ @Test
+ public void dontMarkStaticInnerClassAsNonStatic() {
+ assertThat(
+ new TestClass(OuterClass2.StaticInnerClass.class)
+ .isANonStaticInnerClass(),
+ is(false));
+ }
+
+ public static class SimpleClass {
+ }
+
+ @Test
+ public void dontMarkNonInnerClassAsInnerClass() {
+ assertThat(new TestClass(SimpleClass.class).isANonStaticInnerClass(),
+ is(false));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/classes/UseSuiteAsASuperclassTest.java b/junit4/src/test/java/org/junit/tests/running/classes/UseSuiteAsASuperclassTest.java
new file mode 100644
index 0000000..2917181
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/classes/UseSuiteAsASuperclassTest.java
@@ -0,0 +1,44 @@
+package org.junit.tests.running.classes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+
+public class UseSuiteAsASuperclassTest {
+
+ public static class TestA {
+ @Test
+ public void pass() {
+ }
+ }
+
+ public static class TestB {
+ @Test
+ public void dontPass() {
+ fail();
+ }
+ }
+
+ public static class MySuite extends Suite {
+ public MySuite(Class<?> klass) throws InitializationError {
+ super(klass, new Class[] { TestA.class, TestB.class });
+ }
+ }
+
+ @RunWith(MySuite.class)
+ public static class AllWithMySuite {
+ }
+
+ @Test
+ public void ensureTestsAreRun() {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(AllWithMySuite.class);
+ assertEquals(2, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/core/CommandLineTest.java b/junit4/src/test/java/org/junit/tests/running/core/CommandLineTest.java
new file mode 100644
index 0000000..cdf8b55
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/core/CommandLineTest.java
@@ -0,0 +1,67 @@
+package org.junit.tests.running.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.internal.RealSystem;
+import org.junit.runner.JUnitCore;
+
+public class CommandLineTest {
+ private ByteArrayOutputStream results;
+ private PrintStream oldOut;
+ private static boolean testWasRun;
+
+ @Before public void before() {
+ oldOut= System.out;
+ results= new ByteArrayOutputStream();
+ System.setOut(new PrintStream(results));
+ }
+
+ @After public void after() {
+ System.setOut(oldOut);
+ }
+
+ static public class Example {
+ @Test public void test() {
+ testWasRun= true;
+ }
+ }
+
+ @Test public void runATest() {
+ testWasRun= false; // todo create a TestSystem instead
+ new JUnitCore().runMain(new RealSystem(), new String[]{"org.junit.tests.running.core.CommandLineTest$Example"});
+ assertTrue(testWasRun);
+ }
+
+ @Test public void runAClass() {
+ testWasRun= false;
+ JUnitCore.runClasses(Example.class);
+ assertTrue(testWasRun);
+ }
+
+ private static int fCount;
+
+ static public class Count {
+ @Test public void increment() {
+ fCount++;
+ }
+ }
+
+ @Test public void runTwoClassesAsArray() {
+ fCount= 0;
+ JUnitCore.runClasses(new Class[] {Count.class, Count.class});
+ assertEquals(2, fCount);
+ }
+
+ @Test public void runTwoClasses() {
+ fCount= 0;
+ JUnitCore.runClasses(Count.class, Count.class);
+ assertEquals(2, fCount);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java b/junit4/src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java
new file mode 100644
index 0000000..0d8bb37
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/core/JUnitCoreReturnsCorrectExitCodeTest.java
@@ -0,0 +1,39 @@
+package org.junit.tests.running.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.tests.TestSystem;
+
+public class JUnitCoreReturnsCorrectExitCodeTest {
+
+ static public class Fail {
+ @Test public void kaboom() {
+ fail();
+ }
+ }
+
+ @Test public void failureCausesExitCodeOf1() throws Exception {
+ runClass(getClass().getName() + "$Fail", 1);
+ }
+
+ @Test public void missingClassCausesExitCodeOf1() throws Exception {
+ runClass("Foo", 1);
+ }
+
+ static public class Succeed {
+ @Test public void peacefulSilence() {
+ }
+ }
+
+ @Test public void successCausesExitCodeOf0() throws Exception {
+ runClass(getClass().getName() + "$Succeed", 0);
+ }
+
+ private void runClass(String className, int returnCode) {
+ TestSystem system= new TestSystem();
+ JUnitCore.runMainAndExit(system, className);
+ assertEquals(returnCode, system.fCode);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/core/SystemExitTest.java b/junit4/src/test/java/org/junit/tests/running/core/SystemExitTest.java
new file mode 100644
index 0000000..1460119
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/core/SystemExitTest.java
@@ -0,0 +1,30 @@
+package org.junit.tests.running.core;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.InputStream;
+
+import org.junit.Test;
+
+// Make sure System.exit works as expected. We've had problems with this on some platforms.
+public class SystemExitTest {
+
+ private static final int EXIT_CODE= 5;
+
+ static public class Exit {
+ public static void main(String[] args) {
+ System.exit(EXIT_CODE);
+ }
+ }
+
+ @Test public void failureCausesExitCodeOf1() throws Exception {
+ String java= System.getProperty("java.home")+File.separator+"bin"+File.separator+"java";
+ String classPath= getClass().getClassLoader().getResource(".").getFile() + File.pathSeparator + System.getProperty("java.class.path");
+ String [] cmd= { java, "-cp", classPath, getClass().getName() + "$Exit"};
+ Process process= Runtime.getRuntime().exec(cmd);
+ InputStream input= process.getInputStream();
+ while((input.read()) != -1);
+ assertEquals(EXIT_CODE, process.waitFor());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/methods/AnnotationTest.java b/junit4/src/test/java/org/junit/tests/running/methods/AnnotationTest.java
new file mode 100644
index 0000000..2eb496a
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/methods/AnnotationTest.java
@@ -0,0 +1,520 @@
+package org.junit.tests.running.methods;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.both;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+public class AnnotationTest extends TestCase {
+ static boolean run;
+
+ @Override
+ public void setUp() {
+ run= false;
+ }
+
+ static public class SimpleTest {
+ @Test public void success() {
+ run= true;
+ }
+ }
+
+ public void testAnnotatedMethod() throws Exception {
+ JUnitCore runner= new JUnitCore();
+ runner.run(SimpleTest.class);
+ assertTrue(run);
+ }
+
+ @RunWith(JUnit4.class)
+ static public class SimpleTestWithFutureProofExplicitRunner {
+ @Test public void success() {
+ run= true;
+ }
+ }
+
+ public void testAnnotatedMethodWithFutureProofExplicitRunner() throws Exception {
+ JUnitCore runner= new JUnitCore();
+ runner.run(SimpleTestWithFutureProofExplicitRunner.class);
+ assertTrue(run);
+ }
+
+ static public class SetupTest {
+ @Before public void before() {
+ run= true;
+ }
+ @Test public void success() {
+ }
+ }
+
+ public void testSetup() throws Exception {
+ JUnitCore runner= new JUnitCore();
+ runner.run(SetupTest.class);
+ assertTrue(run);
+ }
+
+ static public class TeardownTest {
+ @After public void after() {
+ run= true;
+ }
+ @Test public void success() {
+ }
+ }
+
+ public void testTeardown() throws Exception {
+ JUnitCore runner= new JUnitCore();
+ runner.run(TeardownTest.class);
+ assertTrue(run);
+ }
+
+ static public class FailureTest {
+ @Test public void error() throws Exception {
+ org.junit.Assert.fail();
+ }
+ }
+
+ public void testRunFailure() throws Exception {
+ JUnitCore runner= new JUnitCore();
+ Result result= runner.run(FailureTest.class);
+ assertEquals(1, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ assertEquals(AssertionError.class, result.getFailures().get(0).getException().getClass());
+ }
+
+ static public class SetupFailureTest {
+ @Before public void before() {
+ throw new Error();
+ }
+ @Test public void test() {
+ run= true;
+ }
+ }
+
+ public void testSetupFailure() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result runner= core.run(SetupFailureTest.class);
+ assertEquals(1, runner.getRunCount());
+ assertEquals(1, runner.getFailureCount());
+ assertEquals(Error.class, runner.getFailures().get(0).getException().getClass());
+ assertFalse(run);
+ }
+
+ static public class TeardownFailureTest {
+ @After public void after() {
+ throw new Error();
+ }
+ @Test public void test() {
+ }
+ }
+
+ public void testTeardownFailure() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result runner= core.run(TeardownFailureTest.class);
+ assertEquals(1, runner.getRunCount());
+ assertEquals(1, runner.getFailureCount());
+ assertEquals(Error.class, runner.getFailures().get(0).getException().getClass());
+ }
+
+ static public class TestAndTeardownFailureTest {
+ @After public void after() {
+ throw new Error("hereAfter");
+ }
+ @Test public void test() throws Exception {
+ throw new Exception("inTest");
+ }
+ }
+
+ public void testTestAndTeardownFailure() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result runner= core.run(TestAndTeardownFailureTest.class);
+ assertEquals(1, runner.getRunCount());
+ assertEquals(2, runner.getFailureCount());
+ assertThat(runner.getFailures().toString(), both(containsString("hereAfter")).and(containsString("inTest")));
+ }
+
+ static public class TeardownAfterFailureTest {
+ @After public void after() {
+ run= true;
+ }
+ @Test public void test() throws Exception {
+ throw new Exception();
+ }
+ }
+
+ public void testTeardownAfterFailure() throws Exception {
+ JUnitCore runner= new JUnitCore();
+ runner.run(TeardownAfterFailureTest.class);
+ assertTrue(run);
+ }
+
+ static int count;
+ static Collection<Object> tests;
+ static public class TwoTests {
+ @Test public void one() {
+ count++;
+ tests.add(this);
+ }
+ @Test public void two() {
+ count++;
+ tests.add(this);
+ }
+ }
+
+ public void testTwoTests() throws Exception {
+ count= 0;
+ tests= new HashSet<Object>();
+ JUnitCore runner= new JUnitCore();
+ runner.run(TwoTests.class);
+ assertEquals(2, count);
+ assertEquals(2, tests.size());
+ }
+
+ static public class OldTest extends TestCase {
+ public void test() {
+ run= true;
+ }
+ }
+ public void testOldTest() throws Exception {
+ JUnitCore runner= new JUnitCore();
+ runner.run(OldTest.class);
+ assertTrue(run);
+ }
+
+ static public class OldSuiteTest extends TestCase {
+ public void testOne() {
+ run= true;
+ }
+ }
+
+ public void testOldSuiteTest() throws Exception {
+ TestSuite suite= new TestSuite(OldSuiteTest.class);
+ JUnitCore runner= new JUnitCore();
+ runner.run(suite);
+ assertTrue(run);
+ }
+
+ static public class ExceptionTest {
+ @Test(expected= Error.class) public void expectedException() {
+ throw new Error();
+ }
+ }
+
+ public void testException() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(ExceptionTest.class);
+ assertEquals(0, result.getFailureCount());
+ }
+
+ static public class NoExceptionTest {
+ @Test(expected= Error.class)
+ public void expectedException() {
+ }
+ }
+
+ public void testExceptionNotThrown() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(NoExceptionTest.class);
+ assertEquals(1, result.getFailureCount());
+ assertEquals("Expected exception: java.lang.Error", result.getFailures().get(0).getMessage());
+ }
+
+ static public class OneTimeSetup {
+ @BeforeClass public static void once() {
+ count++;
+ }
+ @Test public void one() {}
+ @Test public void two() {}
+ }
+
+ public void testOneTimeSetup() throws Exception {
+ count= 0;
+ JUnitCore core= new JUnitCore();
+ core.run(OneTimeSetup.class);
+ assertEquals(1, count);
+ }
+
+ static public class OneTimeTeardown {
+ @AfterClass public static void once() {
+ count++;
+ }
+ @Test public void one() {}
+ @Test public void two() {}
+ }
+
+ public void testOneTimeTeardown() throws Exception {
+ count= 0;
+ JUnitCore core= new JUnitCore();
+ core.run(OneTimeTeardown.class);
+ assertEquals(1, count);
+ }
+
+ static String log;
+
+ public static class OrderTest {
+ @BeforeClass public static void onceBefore() { log+= "beforeClass "; }
+ @Before public void before() { log+= "before "; }
+ @Test public void test() { log+= "test "; }
+ @After public void after() { log+= "after "; }
+ @AfterClass public static void onceAfter() { log+= "afterClass "; }
+ }
+
+ public void testOrder() throws Exception {
+ log= "";
+ JUnitCore core= new JUnitCore();
+ core.run(OrderTest.class);
+ assertEquals("beforeClass before test after afterClass ", log);
+ }
+
+ static public class NonStaticOneTimeSetup {
+ @BeforeClass public void once() {
+ }
+
+ @Test public void aTest() {
+ }
+ }
+
+ public void testNonStaticOneTimeSetup() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(NonStaticOneTimeSetup.class);
+ assertEquals(1, result.getFailureCount());
+ }
+
+ static public class ErrorInBeforeClass {
+ @BeforeClass public static void before() throws Exception {
+ throw new Exception();
+ }
+ @Test public void test() {
+ run= true;
+ }
+ }
+
+ public void testErrorInBeforeClass() throws Exception {
+ run= false;
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(ErrorInBeforeClass.class);
+ assertFalse(run);
+ assertEquals(1, result.getFailureCount());
+ Description description= result.getFailures().get(0).getDescription();
+ assertEquals(ErrorInBeforeClass.class.getName(), description.getDisplayName());
+ }
+
+ static public class ErrorInAfterClass {
+ @Test public void test() {
+ run= true;
+ }
+ @AfterClass public static void after() throws Exception {
+ throw new Exception();
+ }
+ }
+
+ public void testErrorInAfterClass() throws Exception {
+ run= false;
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(ErrorInAfterClass.class);
+ assertTrue(run);
+ assertEquals(1, result.getFailureCount());
+ }
+
+ static public class SuperInheritance {
+ @BeforeClass static public void beforeClassSuper() {
+ log+= "Before class super ";
+ }
+ @AfterClass static public void afterClassSuper() {
+ log+= "After class super ";
+ }
+ @Before public void beforeSuper() {
+ log+= "Before super ";
+ }
+ @After public void afterSuper() {
+ log+= "After super ";
+ }
+ }
+
+ static public class SubInheritance extends SuperInheritance {
+ @BeforeClass static public void beforeClassSub() {
+ log+= "Before class sub ";
+ }
+ @AfterClass static public void afterClassSub() {
+ log+= "After class sub ";
+ }
+ @Before public void beforeSub() {
+ log+= "Before sub ";
+ }
+ @After public void afterSub() {
+ log+= "After sub ";
+ }
+ @Test public void test() {
+ log+= "Test ";
+ }
+ }
+
+ public void testOrderingOfInheritance() throws Exception {
+ log= "";
+ JUnitCore core= new JUnitCore();
+ core.run(SubInheritance.class);
+ assertEquals("Before class super Before class sub Before super Before sub Test After sub After super After class sub After class super ", log);
+ }
+
+ static public class SuperShadowing {
+ @Before public void before() {
+ log+= "Before super ";
+ }
+ @After public void after() {
+ log+= "After super ";
+ }
+ }
+
+ static public class SubShadowing extends SuperShadowing {
+ @Override
+ @Before public void before() {
+ log+= "Before sub ";
+ }
+ @Override
+ @After public void after() {
+ log+= "After sub ";
+ }
+ @Test public void test() {
+ log+= "Test ";
+ }
+ }
+
+ public void testShadowing() throws Exception {
+ log= "";
+ JUnitCore core= new JUnitCore();
+ core.run(SubShadowing.class);
+ assertEquals("Before sub Test After sub ", log);
+ }
+
+ static public class SuperTest {
+ @Test public void one() {
+ log+= "Super";
+ }
+
+ @Test public void two() {
+ log+= "Two";
+ }
+ }
+
+ static public class SubTest extends SuperTest {
+ @Override
+ @Test public void one() {
+ log+= "Sub";
+ }
+ }
+
+ public void testTestInheritance() throws Exception {
+ log= "";
+ JUnitCore core= new JUnitCore();
+ core.run(SubTest.class);
+ // The order in which the test methods are called is unspecified
+ assertTrue(log.contains("Sub"));
+ assertTrue(log.contains("Two"));
+ assertFalse(log.contains("Super"));
+ }
+
+ static public class RunAllAfters {
+ @Before public void good() {
+ }
+ @Before public void bad() {
+ throw new Error();
+ }
+ @Test public void empty() {
+ }
+ @After public void one() {
+ log+= "one";
+ }
+ @After public void two() {
+ log+= "two";
+ }
+ }
+
+ public void testRunAllAfters() {
+ log= "";
+ JUnitCore core= new JUnitCore();
+ core.run(RunAllAfters.class);
+ assertTrue(log.contains("one"));
+ assertTrue(log.contains("two"));
+ }
+
+ static public class RunAllAftersRegardless {
+ @Test public void empty() {
+ }
+ @After public void one() {
+ log+= "one";
+ throw new Error();
+ }
+ @After public void two() {
+ log+= "two";
+ throw new Error();
+ }
+ }
+
+ public void testRunAllAftersRegardless() {
+ log= "";
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(RunAllAftersRegardless.class);
+ assertTrue(log.contains("one"));
+ assertTrue(log.contains("two"));
+ assertEquals(2, result.getFailureCount());
+ }
+
+ static public class RunAllAfterClasses {
+ @Before public void good() {
+ }
+ @BeforeClass public static void bad() {
+ throw new Error();
+ }
+ @Test public void empty() {
+ }
+ @AfterClass public static void one() {
+ log+= "one";
+ }
+ @AfterClass public static void two() {
+ log+= "two";
+ }
+ }
+
+ public void testRunAllAfterClasses() {
+ log= "";
+ JUnitCore core= new JUnitCore();
+ core.run(RunAllAfterClasses.class);
+ assertTrue(log.contains("one"));
+ assertTrue(log.contains("two"));
+ }
+
+ static public class RunAllAfterClassesRegardless {
+ @Test public void empty() {
+ }
+ @AfterClass static public void one() {
+ log+= "one";
+ throw new Error();
+ }
+ @AfterClass static public void two() {
+ log+= "two";
+ throw new Error();
+ }
+ }
+
+ public void testRunAllAfterClassesRegardless() {
+ log= "";
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(RunAllAfterClassesRegardless.class);
+ assertTrue(log.contains("one"));
+ assertTrue(log.contains("two"));
+ assertEquals(2, result.getFailureCount());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/methods/ExpectedTest.java b/junit4/src/test/java/org/junit/tests/running/methods/ExpectedTest.java
new file mode 100644
index 0000000..d16e689
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/methods/ExpectedTest.java
@@ -0,0 +1,58 @@
+package org.junit.tests.running.methods;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+public class ExpectedTest {
+
+ public static class Expected {
+ @Test(expected= Exception.class) public void expected() throws Exception {
+ throw new Exception();
+ }
+ }
+
+ @Test public void expected() {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(Expected.class);
+ assertTrue(result.wasSuccessful());
+ }
+
+ public static class Unexpected {
+ @Test(expected= Exception.class) public void expected() throws Exception {
+ throw new Error();
+ }
+ }
+ @Test public void unexpected() {
+ Result result= JUnitCore.runClasses(Unexpected.class);
+ Failure failure= result.getFailures().get(0);
+ String message= failure.getMessage();
+ assertTrue(message.contains("expected<java.lang.Exception> but was<java.lang.Error>"));
+ assertEquals(Error.class, failure.getException().getCause().getClass());
+ }
+
+ public static class NoneThrown {
+ @Test(expected= Exception.class) public void nothing() {
+ }
+ }
+ @Test public void noneThrown() {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(NoneThrown.class);
+ assertFalse(result.wasSuccessful());
+ String message= result.getFailures().get(0).getMessage();
+ assertTrue(message.contains("Expected exception: java.lang.Exception"));
+ }
+
+ public static class ExpectSuperclass {
+ @Test(expected= RuntimeException.class) public void throwsSubclass() {
+ throw new ClassCastException();
+ }
+ }
+ @Test public void expectsSuperclass() {
+ assertTrue(new JUnitCore().run(ExpectSuperclass.class).wasSuccessful());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/methods/InheritedTestTest.java b/junit4/src/test/java/org/junit/tests/running/methods/InheritedTestTest.java
new file mode 100644
index 0000000..15f55a6
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/methods/InheritedTestTest.java
@@ -0,0 +1,31 @@
+package org.junit.tests.running.methods;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+
+public class InheritedTestTest {
+ public abstract static class Super {
+ @Test public void nothing() {}
+ }
+ public static class Sub extends Super {}
+
+ @Test public void subclassWithOnlyInheritedTestsRuns() {
+ Result result= JUnitCore.runClasses(Sub.class);
+ assertTrue(result.wasSuccessful());
+ }
+
+ public static class SubWithBefore extends Super {
+ @Before public void gack() {
+ fail();
+ }
+ }
+
+ @Test public void subclassWithInheritedTestAndOwnBeforeRunsBefore() {
+ assertFalse(JUnitCore.runClasses(SubWithBefore.class).wasSuccessful());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/methods/ParameterizedTestMethodTest.java b/junit4/src/test/java/org/junit/tests/running/methods/ParameterizedTestMethodTest.java
new file mode 100644
index 0000000..4d4dcbd
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/methods/ParameterizedTestMethodTest.java
@@ -0,0 +1,102 @@
+package org.junit.tests.running.methods;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.JUnit4TestAdapter;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.model.InitializationError;
+
+@RunWith(Parameterized.class)
+public class ParameterizedTestMethodTest {
+
+ @SuppressWarnings("all")
+ public static class EverythingWrong {
+ private EverythingWrong() {}
+ @BeforeClass public void notStaticBC() {}
+ @BeforeClass static void notPublicBC() {}
+ @BeforeClass public static int nonVoidBC() { return 0; }
+ @BeforeClass public static void argumentsBC(int i) {}
+ @BeforeClass public static void fineBC() {}
+ @AfterClass public void notStaticAC() {}
+ @AfterClass static void notPublicAC() {}
+ @AfterClass public static int nonVoidAC() { return 0; }
+ @AfterClass public static void argumentsAC(int i) {}
+ @AfterClass public static void fineAC() {}
+ @After public static void staticA() {}
+ @After void notPublicA() {}
+ @After public int nonVoidA() { return 0; }
+ @After public void argumentsA(int i) {}
+ @After public void fineA() {}
+ @Before public static void staticB() {}
+ @Before void notPublicB() {}
+ @Before public int nonVoidB() { return 0; }
+ @Before public void argumentsB(int i) {}
+ @Before public void fineB() {}
+ @Test public static void staticT() {}
+ @Test void notPublicT() {}
+ @Test public int nonVoidT() { return 0; }
+ @Test public void argumentsT(int i) {}
+ @Test public void fineT() {}
+ }
+
+ private Class<?> fClass;
+ private int fErrorCount;
+
+ static public class SuperWrong {
+ @Test void notPublic() {
+ }
+ }
+
+ static public class SubWrong extends SuperWrong {
+ @Test public void justFine() {
+ }
+ }
+
+ static public class SubShadows extends SuperWrong {
+ @Override
+ @Test public void notPublic() {
+ }
+ }
+
+ public ParameterizedTestMethodTest(Class<?> class1, int errorCount) {
+ fClass= class1;
+ fErrorCount= errorCount;
+ }
+
+ @Parameters
+ public static Collection<Object[]> params() {
+ return Arrays.asList(new Object[][] {
+ { EverythingWrong.class, 1 + 4 * 5 }, { SubWrong.class, 1 },
+ { SubShadows.class, 0 } });
+ }
+
+ private List<Throwable> validateAllMethods(Class<?> clazz) {
+ try {
+ new BlockJUnit4ClassRunner(clazz);
+ } catch (InitializationError e) {
+ return e.getCauses();
+ }
+ return Collections.emptyList();
+ }
+
+ @Test public void testFailures() throws Exception {
+ List<Throwable> problems= validateAllMethods(fClass);
+ assertEquals(fErrorCount, problems.size());
+ }
+ public static junit.framework.Test suite() {
+ return new JUnit4TestAdapter(ParameterizedTestMethodTest.class);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/methods/TestMethodTest.java b/junit4/src/test/java/org/junit/tests/running/methods/TestMethodTest.java
new file mode 100644
index 0000000..cbabab2
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/methods/TestMethodTest.java
@@ -0,0 +1,147 @@
+package org.junit.tests.running.methods;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestResult;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+
+public class TestMethodTest {
+
+ @SuppressWarnings("all")
+ public static class EverythingWrong {
+ private EverythingWrong() {}
+ @BeforeClass public void notStaticBC() {}
+ @BeforeClass static void notPublicBC() {}
+ @BeforeClass public static int nonVoidBC() { return 0; }
+ @BeforeClass public static void argumentsBC(int i) {}
+ @BeforeClass public static void fineBC() {}
+ @AfterClass public void notStaticAC() {}
+ @AfterClass static void notPublicAC() {}
+ @AfterClass public static int nonVoidAC() { return 0; }
+ @AfterClass public static void argumentsAC(int i) {}
+ @AfterClass public static void fineAC() {}
+ @After public static void staticA() {}
+ @After void notPublicA() {}
+ @After public int nonVoidA() { return 0; }
+ @After public void argumentsA(int i) {}
+ @After public void fineA() {}
+ @Before public static void staticB() {}
+ @Before void notPublicB() {}
+ @Before public int nonVoidB() { return 0; }
+ @Before public void argumentsB(int i) {}
+ @Before public void fineB() {}
+ @Test public static void staticT() {}
+ @Test void notPublicT() {}
+ @Test public int nonVoidT() { return 0; }
+ @Test public void argumentsT(int i) {}
+ @Test public void fineT() {}
+ }
+
+ @Test public void testFailures() throws Exception {
+ List<Throwable> problems= validateAllMethods(EverythingWrong.class);
+ int errorCount= 1 + 4 * 5; // missing constructor plus four invalid methods for each annotation */
+ assertEquals(errorCount, problems.size());
+ }
+
+ static public class SuperWrong {
+ @Test void notPublic() {
+ }
+ }
+
+ static public class SubWrong extends SuperWrong {
+ @Test public void justFine() {
+ }
+ }
+
+ @Test public void validateInheritedMethods() throws Exception {
+ List<Throwable> problems= validateAllMethods(SubWrong.class);
+ assertEquals(1, problems.size());
+ }
+
+ static public class SubShadows extends SuperWrong {
+ @Override
+ @Test public void notPublic() {
+ }
+ }
+
+ @Test public void dontValidateShadowedMethods() throws Exception {
+ List<Throwable> problems= validateAllMethods(SubShadows.class);
+ assertTrue(problems.isEmpty());
+ }
+
+ private List<Throwable> validateAllMethods(Class<?> clazz) {
+ try {
+ new BlockJUnit4ClassRunner(clazz);
+ } catch (InitializationError e) {
+ return e.getCauses();
+ }
+ return Collections.emptyList();
+ }
+
+ static public class IgnoredTest {
+ @Test public void valid() {}
+ @Ignore @Test public void ignored() {}
+ @Ignore("For testing purposes") @Test public void withReason() {}
+ }
+
+ @Test public void ignoreRunner() {
+ JUnitCore runner= new JUnitCore();
+ Result result= runner.run(IgnoredTest.class);
+ assertEquals(2, result.getIgnoreCount());
+ assertEquals(1, result.getRunCount());
+ }
+
+ @Test public void compatibility() {
+ TestResult result= new TestResult();
+ new JUnit4TestAdapter(IgnoredTest.class).run(result);
+ assertEquals(1, result.runCount());
+ }
+
+ public static class Confused {
+ @Test public void a(Object b) {
+ }
+
+ @Test public void a() {
+ }
+ }
+
+ @Test(expected=InitializationError.class) public void overloaded() throws InitializationError {
+ new BlockJUnit4ClassRunner(Confused.class);
+ }
+
+ public static class ConstructorParameter {
+ public ConstructorParameter(Object something) {
+ }
+
+ @Test public void a() {
+ }
+ }
+
+ @Test(expected=InitializationError.class) public void constructorParameter() throws InitializationError {
+ new BlockJUnit4ClassRunner(ConstructorParameter.class);
+ }
+
+ public static class OnlyTestIsIgnored {
+ @Ignore @Test public void ignored() {}
+ }
+
+ @Test public void onlyIgnoredMethodsIsStillFineTestClass() {
+ Result result= JUnitCore.runClasses(OnlyTestIsIgnored.class);
+ assertEquals(0, result.getFailureCount());
+ assertEquals(1, result.getIgnoreCount());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/running/methods/TimeoutTest.java b/junit4/src/test/java/org/junit/tests/running/methods/TimeoutTest.java
new file mode 100644
index 0000000..777b0bd
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/running/methods/TimeoutTest.java
@@ -0,0 +1,170 @@
+package org.junit.tests.running.methods;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestResult;
+import org.junit.After;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+
+public class TimeoutTest {
+
+ static public class FailureWithTimeoutTest {
+ @Test(timeout= 1000) public void failure() {
+ fail();
+ }
+ }
+
+ @Test public void failureWithTimeout() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(FailureWithTimeoutTest.class);
+ assertEquals(1, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ assertEquals(AssertionError.class, result.getFailures().get(0).getException().getClass());
+ }
+
+ static public class FailureWithTimeoutRunTimeExceptionTest {
+ @Test(timeout= 1000) public void failure() {
+ throw new NullPointerException();
+ }
+ }
+
+ @Test public void failureWithTimeoutRunTimeException() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(FailureWithTimeoutRunTimeExceptionTest.class);
+ assertEquals(1, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ assertEquals(NullPointerException.class, result.getFailures().get(0).getException().getClass());
+ }
+
+ static public class SuccessWithTimeoutTest {
+ @Test(timeout= 1000) public void success() {
+ }
+ }
+
+ @Test public void successWithTimeout() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(SuccessWithTimeoutTest.class);
+ assertEquals(1, result.getRunCount());
+ assertEquals(0, result.getFailureCount());
+ }
+
+ static public class TimeoutFailureTest {
+ @Test(timeout= 100) public void success() throws InterruptedException {
+ Thread.sleep(40000);
+ }
+ }
+
+ @Ignore("was breaking gump")
+ @Test public void timeoutFailure() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(TimeoutFailureTest.class);
+ assertEquals(1, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ assertEquals(InterruptedException.class, result.getFailures().get(0).getException().getClass());
+ }
+
+ static public class InfiniteLoopTest {
+ @Test(timeout= 100) public void failure() {
+ infiniteLoop();
+ }
+
+ private void infiniteLoop() {
+ for(;;)
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ @Test public void infiniteLoop() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(InfiniteLoopTest.class);
+ assertEquals(1, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ Throwable exception= result.getFailures().get(0).getException();
+ assertTrue(exception.getMessage().contains("test timed out after 100 milliseconds"));
+ }
+
+ static public class ImpatientLoopTest {
+ @Test(timeout= 1) public void failure() {
+ infiniteLoop();
+ }
+
+ private void infiniteLoop() {
+ for(;;);
+ }
+ }
+
+ @Ignore("This breaks sporadically with time differences just slightly more than 200ms")
+ @Test public void infiniteLoopRunsForApproximatelyLengthOfTimeout() throws Exception {
+ // "prime the pump": running these beforehand makes the runtimes more predictable
+ // (because of class loading?)
+ JUnitCore.runClasses(InfiniteLoopTest.class, ImpatientLoopTest.class);
+ long longTime= runAndTime(InfiniteLoopTest.class);
+ long shortTime= runAndTime(ImpatientLoopTest.class);
+ long difference= longTime - shortTime;
+ assertTrue(String.format("Difference was %sms", difference), difference < 200);
+ }
+
+ private long runAndTime(Class<?> clazz) {
+ JUnitCore core= new JUnitCore();
+ long startTime= System.currentTimeMillis();
+ core.run(clazz);
+ long totalTime = System.currentTimeMillis() - startTime;
+ return totalTime;
+ }
+
+ @Test public void stalledThreadAppearsInStackTrace() throws Exception {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(InfiniteLoopTest.class);
+ assertEquals(1, result.getRunCount());
+ assertEquals(1, result.getFailureCount());
+ Throwable exception= result.getFailures().get(0).getException();
+ Writer buffer= new StringWriter();
+ PrintWriter writer= new PrintWriter(buffer);
+ exception.printStackTrace(writer);
+ assertThat(buffer.toString(), containsString("infiniteLoop")); // Make sure we have the stalled frame on the stack somewhere
+ }
+
+ @Test public void compatibility() {
+ TestResult result= new TestResult();
+ new JUnit4TestAdapter(InfiniteLoopTest.class).run(result);
+ assertEquals(1, result.errorCount());
+ }
+
+ public static class WillTimeOut {
+ static boolean afterWasCalled= false;
+
+ @Test(timeout=1) public void test() {
+ for(;;)
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ // ok, tests are over
+ }
+ }
+
+ @After public void after() {
+ afterWasCalled= true;
+ }
+ }
+
+ @Test public void makeSureAfterIsCalledAfterATimeout() {
+ JUnitCore.runClasses(WillTimeOut.class);
+ assertThat(WillTimeOut.afterWasCalled, is(true));
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java b/junit4/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java
new file mode 100644
index 0000000..ff61822
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java
@@ -0,0 +1,68 @@
+package org.junit.tests.validation;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.internal.runners.JUnit4ClassRunner;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.Failure;
+
+@SuppressWarnings("deprecation")
+public class BadlyFormedClassesTest {
+ public static class FaultyConstructor {
+ public FaultyConstructor() throws Exception {
+ throw new Exception("Thrown during construction");
+ }
+
+ @Test
+ public void someTest() {
+ /*
+ * Empty test just to fool JUnit and IDEs into running this class as
+ * a JUnit test
+ */
+ }
+ };
+
+ @RunWith(JUnit4ClassRunner.class)
+ public static class BadBeforeMethodWithLegacyRunner {
+ @Before
+ void before() {
+
+ }
+
+ @Test
+ public void someTest() {
+ }
+ };
+
+ public static class NoTests {
+ // class without tests
+ }
+
+ @Test
+ public void constructorException() {
+ String message= exceptionMessageFrom(FaultyConstructor.class);
+ assertEquals("Thrown during construction", message);
+ }
+
+ @Test
+ public void noRunnableMethods() {
+ assertEquals("No runnable methods", exceptionMessageFrom(NoTests.class));
+ }
+
+ @Test
+ public void badBeforeMethodWithLegacyRunner() {
+ assertEquals("Method before should be public",
+ exceptionMessageFrom(BadBeforeMethodWithLegacyRunner.class));
+ }
+
+ private String exceptionMessageFrom(Class<?> testClass) {
+ JUnitCore core= new JUnitCore();
+ Result result= core.run(testClass);
+ Failure failure= result.getFailures().get(0);
+ String message= failure.getException().getMessage();
+ return message;
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/validation/FailedConstructionTest.java b/junit4/src/test/java/org/junit/tests/validation/FailedConstructionTest.java
new file mode 100644
index 0000000..7d2ab1e
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/validation/FailedConstructionTest.java
@@ -0,0 +1,28 @@
+package org.junit.tests.validation;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+public class FailedConstructionTest {
+ public static class CantConstruct {
+ public CantConstruct() {
+ throw new RuntimeException();
+ }
+
+ @Test
+ public void foo() {
+ }
+ }
+
+ @Test
+ public void failedConstructionIsTestFailure() {
+ Result result= JUnitCore.runClasses(CantConstruct.class);
+ Failure failure= result.getFailures().get(0);
+ Description expected= Description.createTestDescription(CantConstruct.class, "foo");
+ Assert.assertEquals(expected, failure.getDescription());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/validation/InaccessibleBaseClassTest.java b/junit4/src/test/java/org/junit/tests/validation/InaccessibleBaseClassTest.java
new file mode 100644
index 0000000..0677dd8
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/validation/InaccessibleBaseClassTest.java
@@ -0,0 +1,13 @@
+package org.junit.tests.validation;
+
+import org.junit.Test;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+import org.junit.tests.validation.anotherpackage.Sub;
+
+public class InaccessibleBaseClassTest {
+ @Test(expected= InitializationError.class)
+ public void inaccessibleBaseClassIsCaughtAtValidation() throws InitializationError {
+ new BlockJUnit4ClassRunner(Sub.class);
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/validation/ValidationTest.java b/junit4/src/test/java/org/junit/tests/validation/ValidationTest.java
new file mode 100644
index 0000000..3251705
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/validation/ValidationTest.java
@@ -0,0 +1,34 @@
+package org.junit.tests.validation;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+
+public class ValidationTest {
+ public static class WrongBeforeClass {
+ @BeforeClass
+ protected int a() {
+ return 0;
+ }
+ }
+
+ @Test
+ public void initializationErrorIsOnCorrectClass() {
+ assertEquals(WrongBeforeClass.class.getName(),
+ Request.aClass(WrongBeforeClass.class).getRunner().getDescription().getDisplayName());
+ }
+
+ public static class NonStaticBeforeClass {
+ @BeforeClass public void before() {}
+ @Test public void hereBecauseEveryTestClassNeedsATest() {}
+ }
+
+ @Test
+ public void nonStaticBeforeClass() {
+ Result result= JUnitCore.runClasses(NonStaticBeforeClass.class);
+ assertEquals("Method before() should be static", result.getFailures().get(0).getMessage());
+ }
+}
diff --git a/junit4/src/test/java/org/junit/tests/validation/anotherpackage/Sub.java b/junit4/src/test/java/org/junit/tests/validation/anotherpackage/Sub.java
new file mode 100644
index 0000000..44d6c76
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/validation/anotherpackage/Sub.java
@@ -0,0 +1,5 @@
+package org.junit.tests.validation.anotherpackage;
+
+public class Sub extends Super {
+
+}
diff --git a/junit4/src/test/java/org/junit/tests/validation/anotherpackage/Super.java b/junit4/src/test/java/org/junit/tests/validation/anotherpackage/Super.java
new file mode 100644
index 0000000..ba1cfe4
--- /dev/null
+++ b/junit4/src/test/java/org/junit/tests/validation/anotherpackage/Super.java
@@ -0,0 +1,7 @@
+package org.junit.tests.validation.anotherpackage;
+
+import org.junit.Test;
+
+class Super {
+ @Test public void a() {}
+}
diff --git a/junit4/stylesheet.css b/junit4/stylesheet.css
new file mode 100644
index 0000000..032b85c
--- /dev/null
+++ b/junit4/stylesheet.css
@@ -0,0 +1 @@
+/* Javadoc style sheet */ /* makes unvisted linkes red (red bad) */ A {color:red;} /* makes visted linkes the same green as the toolbar (green good) */ A:visited {color:#03A35D;} /* Define colors, fonts and other style attributes here to override the defaults */ /* Page background color */ body { background-color: #FFFFFF } /* Table colors */ .TableHeadingColor { background: #03A35D} /* Green */ .TableSubHeadingColor { background: #03A35D } /* Green */ .TableRowColor { background: #FFFFFF } /* White */ /* Font used in left-hand frame lists */ .FrameTitleFont { font-size: normal; font-family: normal } .FrameHeadingFont { font-size: normal; font-family: normal } .FrameItemFont { font-size: normal; font-family: normal } /* Example of smaller, sans-serif font in frames */ /* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ /* Navigation bar fonts and colors */ .NavBarCell1 { background-color:#03A35D;}/* Green */ .NavBarCell1Rev { background-color:#006400;}/* Dark green */ .NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} .NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} .NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;} .NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;} \ No newline at end of file
diff --git a/junit4/to-do.txt b/junit4/to-do.txt
new file mode 100644
index 0000000..2e30000
--- /dev/null
+++ b/junit4/to-do.txt
@@ -0,0 +1,31 @@
+* assertArrayEquals(double[], double[], double) and assertArrayEquals(float[], float[], float)
+
+* update documentation
+ * new cook's tour
+ * update Test Infected
+* Should there be a "prefix" annotation for Suites?
+ * This would allow two Suites with different BeforeClass/AfterClass behaviors,
+ but the same component tests, to co-exist
+
+* update the build process
+ * automatically upload a new JAR
+ * update site for plug-in version?
+* Ant
+ * Basic task
+* support testing run once initialization code e.g. class Foo {{...}}
+* Automatically add failing tests to the Known Defects section of the README.html
+
+* Create test target in ant
+* Create assume(that()) and assert(that())
+ (what is a better name for the second one?)
+
+* Simplify implementation of equality, and organize AssertionTest
+
+* Theories class validation should be much better
+
+* Find a way to make Parameterized a single-class extension
+
+* If a suite() returns a JUnit4TestAdapter, allow Filters and Sorters to operate on
+ the adapted Runner.
+
+* Every time I add a Filter feature, I have to add an equivalent Sorter feature. Suspicious. \ No newline at end of file