summaryrefslogtreecommitdiffstats
path: root/junit4/src
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/src
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/src')
-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
322 files changed, 23852 insertions, 0 deletions
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() {}
+}