diff --git a/.classpath b/.classpath index c98259118ee0..f648ca63c5ff 100644 --- a/.classpath +++ b/.classpath @@ -2,6 +2,8 @@ + + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000000..43cf4920bd13 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,21 @@ +* text eol=lf +*.gif binary +*.GIF binary +*.jar binary +*.png binary +*.jpg binary +*.svg text eol=lf + +# These files do not have unix line endings. Do not normalize them for now. +# Will fix these right before we cut JUnit 4.13. +/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java -text +/src/main/java/org/junit/experimental/categories/ExcludeCategories.java -text +/src/main/java/org/junit/experimental/categories/IncludeCategories.java -text +/src/main/java/org/junit/internal/Classes.java -text +/src/main/java/org/junit/runner/FilterFactories.java -text +/src/main/java/org/junit/runner/FilterFactory.java -text +/src/main/java/org/junit/runner/FilterFactoryParams.java -text +/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java -text +/src/test/java/org/junit/experimental/categories/CategoryFilterFactoryTest.java -text +/src/test/java/org/junit/runner/FilterFactoriesTest.java -text +/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java -text diff --git a/.gitignore b/.gitignore index b3df647a6236..54f5aa75e33f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ MaxCore.max *.iws out java.hprof.txt -.gitattributes \ No newline at end of file +.DS_Store diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100755 index 000000000000..41c70a7e0b7d Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100755 index 000000000000..37cb61582de0 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.1.1/apache-maven-3.1.1-bin.zip \ No newline at end of file diff --git a/.travis.settings.xml b/.travis.settings.xml new file mode 100644 index 000000000000..332f39daa17b --- /dev/null +++ b/.travis.settings.xml @@ -0,0 +1,22 @@ + + + + central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + google-maven-central + + + + + junit-snapshot-repo + ${env.OSSRH_USERNAME} + ${env.OSSRH_PASSWORD} + + + junit-releases-repo + ${env.OSSRH_USERNAME} + ${env.OSSRH_PASSWORD} + + + diff --git a/.travis.yml b/.travis.yml index 378d46143fe0..5b1744397f29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,69 @@ +dist: trusty + language: java -script: mvn verify javadoc:javadoc site:site -jdk: - - oraclejdk7 - - oraclejdk8 - - openjdk7 - - openjdk6 + +script: ./mvnw verify javadoc:javadoc site:site + +install: +- ./mvnw --version + +stages: + - test + - name: deploy + if: (branch = main) AND (NOT type IN (pull_request)) + +jobs: + include: + - name: Java 6 + env: JDK=openjdk6 + addons: + apt: + packages: + - openjdk-6-jdk + install: + # Download dependencies with JDK 8 because Mave Central supports + # TLS 1.2 only but OpenJDK 6 does not. + - export ORIGINAL_JAVA_HOME=$JAVA_HOME + - jdk_switcher use oraclejdk8 + - ./mvnw test -DskipTests + # Delete all files created with JDK 8 + - ./mvnw clean + # Restore desired JDK + - export JAVA_HOME=$ORIGINAL_JAVA_HOME + - jdk_switcher use openjdk6 + - ./mvnw --version + - name: Java 7 + jdk: openjdk7 + - name: Java 8 + jdk: oraclejdk8 + - name: Java 9 + jdk: oraclejdk9 + - name: Java 10 + jdk: openjdk10 + - name: Java 11 + jdk: openjdk11 + - stage: deploy + name: "Publish snapshot artifacts" + addons: + apt: + packages: + - openjdk-6-jdk + install: + # Download dependencies with JDK 8 because Mave Central supports + # TLS 1.2 only but OpenJDK 6 does not. + - export ORIGINAL_JAVA_HOME=$JAVA_HOME + - jdk_switcher use oraclejdk8 + - ./mvnw test -DskipTests + # Delete all files created with JDK 8 + - ./mvnw clean + # Restore desired JDK + - export JAVA_HOME=$ORIGINAL_JAVA_HOME + - jdk_switcher use openjdk6 + - ./mvnw --version + env: + - JDK=openjdk6 + # OSSRH_USERNAME + - secure: griGZYDtqDMRUaYex/uAnpkWIQ/yodM6IOn4G8izWKpyGLeCxyXBG0FDcVo81xRq/9mMevj2idyW/xNP/HAQ45G4pyJUk/vTSMkNslzVjr7OBEtQQCN8XahSaOO0l0CJ5lzA6LdwWg7uDaf9znqZ0slt81u0S1NJmUZyYeUEim0= + # OSSRH_PASSWORD + - secure: EM7Z2M09HvLJXYJaeD/YmeF5A6tqavG2tBBeDcFZ7C6k0AI/wApe882pEMMoUG06xufKfSlt7WFJxoyU3M+fPOpeK5qZpJQxsHWnNJwbcbKzqMpM9mDsgIL9rtAvm9MuIIbIY2spiT0Cx3sHdh5qofaJHPL/u8Or5L9tE8FV1ew= + script: ./mvnw deploy --batch-mode --activate-profiles generate-docs --settings .travis.settings.xml diff --git a/BUILDING b/BUILDING index 5d1ec90fc5f1..496eeb03b820 100644 --- a/BUILDING +++ b/BUILDING @@ -1,8 +1,8 @@ BUILDING FROM GITHUB: ===================== -git clone https://github.com/junit-team/junit.git -cd junit +git clone https://github.com/junit-team/junit4.git +cd junit4 mvn install BUILDING FROM JARS OR ZIPS: @@ -11,4 +11,4 @@ BUILDING FROM JARS OR ZIPS: The contents of the zip and jar files are largely maintained for historical reasons. We do not at this time have an official way to build from the src jar or zip. If this is an important missing feature, please let us know -at http://github.com/junit-team/junit/issues +at http://github.com/junit-team/junit4/issues diff --git a/CODING_STYLE.txt b/CODING_STYLE.txt index d9600afdf5a6..fefecdd26f83 100644 --- a/CODING_STYLE.txt +++ b/CODING_STYLE.txt @@ -1,3 +1,9 @@ -JUnit project uses the Google Java Style (http://google-styleguide.googlecode.com/svn/trunk/javaguide.html) for all new -code (under org.junit.*). Legacy code (under junit.*) used the legacy guide specified in LEGACY_CODING_STYLE.txt in the +JUnit project uses the Google Java Style (https://github.com/google/styleguide) for all new +code (under org.junit.*). Deviating from this, indentation is 4 spaces instead of 2. + +Be sure to set text file encoding to UTF-8 and line delimiters to UNIX style. + +Since not all code has been formatted yet, please format only code lines you changed to avoid extraneous changes. + +Legacy code (under junit.*) used the legacy guide specified in LEGACY_CODING_STYLE.txt in the project root. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 629ea4cb6bbb..1943d567915c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,45 @@ +## Project License: Eclipse Public License v1.0 + +- You will only Submit Contributions where You have authored 100% of the content. +- You will only Submit Contributions to which You have the necessary rights. This means that if You are employed You have received the necessary permissions from Your employer to make the Contributions. +- Whatever content You Contribute will be provided under the Project License(s). + +## Coding Conventions + +### Formatting + +See [CODING_STYLE.txt](CODING_STYLE.txt) for how we format our code. + +## How to submit a pull request + We love pull requests. Here is a quick guide: 1. You need to have Maven and a JDK (at least version 1.5) installed. -2. Fork the repo (see https://help.github.com/articles/fork-a-repo) -3. Create a new branch from master. -4. Ensure that you have a clean state by running `mvn verify` +2. [Fork the repo](https://help.github.com/articles/fork-a-repo). +3. [Create a new branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/) from `main`. +4. Ensure that you have a clean state by running `./mvnw verify`. 5. Add your change together with a test (tests are not needed for refactorings and documentation changes). 6. Format your code: Import the JUnit project in Eclipse and use its formatter or apply the rules in the `CODING_STYLE` file manually. Only format the code you've changed; reformatting unrelated code makes it harder for us to review your changes. -6. Run `mvn verify` again and ensure all tests are passing. -8. Push to your fork and submit a pull request. +7. Run `./mvnw verify` again and ensure all tests are passing. +8. Push to your fork and [submit a pull request](https://help.github.com/articles/creating-a-pull-request/). Now you are waiting on us. We review your pull request and at least leave some comments. Note that if you are thinking of providing a fix for one of the bugs or feature requests, it's usually a good idea to add a comment to the bug to make sure that there's agreement on how we should proceed. + +## Limitations + +The JUnit team is not accepting changes to the code under the following paths: + +* `src/main/java/junit` +* `test/java/junit/tests/framework` +* `test/java/junit/tests/extensions` + +The reasoning is that the JUnit team feels that our users should focus on using either the JUnit4 or JUnit5 APIs. + +The team is also reluctant to accept changes that only update code from one code style to another. +Generally the code in JUnit was approved by at least one person, so two people agreed that the style was reasonable. + +To find other places where you can have an impact, please see the [Issues tagged "up-for-grabs"](https://github.com/junit-team/junit4/issues?q=is%3Aissue+is%3Aopen+label%3Aup-for-grabs). diff --git a/KEYS b/KEYS new file mode 100644 index 000000000000..0433e72f3343 --- /dev/null +++ b/KEYS @@ -0,0 +1,70 @@ +This file contains the PGP key that is used to sign releases. + +Importing: `pgp < KEYS` or `gpg --import KEYS` + +Adding a key: +`pgp -kxa >> KEYS`, +or `(pgpk -ll && pgpk -xa ) >> KEYS`, +or `(gpg --list-sigs && gpg --armor --export ) >> KEYS` + +================================ + +pub rsa4096 2018-04-08 [SC] + FF6E2C001948C5F2F38B0CC385911F425EC61B51 +uid [ unknown] Open Source Development +sig 3 85911F425EC61B51 2018-04-08 Open Source Development +sub rsa4096 2018-04-08 [E] +sig 85911F425EC61B51 2018-04-08 Open Source Development + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFrKW9IBEACkqUvM7hU1WqOOeb1gZ7pUsRliHuoUvYIrd+hdp+qhPmJ0NG0W +YhZK5UtJBmqvtHKRkbwYxUuya9zlBmCfQFf0GpFKJ65JSrPSkZADI3aZ4aUkxIUw +nIRoUHucmr10Xftpebr/zaJk5oR8RdaL5FapapmcZmAaHR9CDWB8XtI318u314jq +M5rKatnAZMERoPugOvvuAOz4bfZKwdfCmZKfYUM/TMSrSinXrGExSW6z4RhtqmpC +E5M/7OoVfvDynVJKqNazqgigpmMNhOyzAhQsiKh1K0akyxTZbjeZKsdYfhCXvq0q +k9+KM/cTllQ54MPnFWiObLkHeK0Waw8bI/vAJ4h4x/XM9iGYpkXv7F2/FVsHQdPe +YJcwD/CkD8KHyiPaRKMeApiUtZsdAHU0L4X/lNmcooea/7ipskruUgwcm+RdLhRZ +P949t1e7nqDZfpEHy90NiFxmlRAPSNqBLwefxY/hwBgog2jabDALJVcLCMosFWPj +MQhFlGSIODiVcW8folGIjzkyNZbNMWkwnl2QnWp/h2TAwYQJOMqcv2MG9o5pyzpx +97Iz1ngq1FlM/gJnGnNUydP2tAjT2L2U3MP1uX/EdRChdgPqdolqYhdFfwCr0Fpf +W527bUZpReHCEiQ29ABSnQ711mO+d9+qM6edRyHUoBWz89IHt8sCunuvNwARAQAB +tC1PcGVuIFNvdXJjZSBEZXZlbG9wbWVudCA8bWFpbEBtYXJjcGhpbGlwcC5kZT6J +Ak4EEwEIADgWIQT/biwAGUjF8vOLDMOFkR9CXsYbUQUCWspb0gIbAwULCQgHAgYV +CAkKCwIEFgIDAQIeAQIXgAAKCRCFkR9CXsYbUQyRD/9xm3BqdpWcRCE5UyB6nbwV +8TgzMmbOhpFhhcjzobly/pKAbcofKsjhreENJkfBVUo+zAFx21ToC5tbH20wRtIE +vQVCP6sAIzhYWU1ohafqVFP4+PztNBuYTnS6vGvSwzp0IXLIIoxSxo0IOED9uUS9 +DTxh1n9NnDLDe2pfjrXBblQtLSW3W5ISDoUvcoyO7Hk1OByW6MNsSoLvXIUNeVhB +ju9TfYxFACJSWBhUxJfgip9Y2GrNBJaYGLZrTAoW1Lh1H1DfLV3wHDClQ1+H+oyx +IOZULEGYY3MgZTd6Ner2yNAUCB7gVa50NiCZXCS74m+XzMrTEsdWjSMUaOe+dL0I +9MCrgi4ycUHWIfTKx9gGlIOo3hSDMN+8Nj33XPjLT8kcfoFeUX8jTOvC1HFfTuQJ +x2t/dKHizdrS3F6A/JQa7v8GNTrZFnEXkwgRTf3ccLoo3gPwzNJeCm2xNjvne1VH +fvxzwNmq8M05oicEigvEed2VMStMhvT7dSiMAf66rEJHjjaHAoNqbLDEATYrWUP2 +I52txHSSxSJohxVP6Ec6dERnqqYi0mVyzBPo7mmFFBisq74w8RvZXyzvXE3BTiDL +we1E/Z/AXbtJye9DickQ/G6RFtVLbUHQfzyRS/65JPtlH8rqJr58YWlylGImVLwE +OsKNQrwLZ0UkfaWV7wqr3rkCDQRaylvSARAAnQG636wliEOLkXN662OZS6Qz2+cF +ltCWboq9oX9FnA1PHnTY2cAtwS214RfWZxkjg6Stau+d1Wb8TsF/SUN3eKRSyrkA +xlX0v552vj3xmmfNsslQX47e6aEWZ0du0M8jw7/f7Qxp0InkBfpQwjSg4ECoH4cA +6dOFJIdxBv8dgS4K90HNuIHa+QYfVSVMjGwOjD9St6Pwkbg1sLedITRo59Bbv0J1 +4nE9LdWbCiwNrkDr24jTewdgrDaCpN6msUwcH1E0nYxuKAetHEi2OpgBhaY3RQ6Q +PQB6NywvmD0xRllMqu4hSp70pHFtm8LvJdWOsJ5we3KijHuZzEbBVTTl+2DhNMI0 +KMoh+P/OmyNOfWD8DL4NO3pVv+mPDZn82/eZ3XY1/oSQrpyJaCBjRKasVTtfiA/F +gYqTml6qZMjy6iywg84rLezELgcxHHvjhAKd4CfxyuCCgnGT0iRLFZKw44ZmOUqP +DkyvGRddIyHag1K7UaM/2UMn6iPMy7XWcaFiH5Huhz43SiOdsWGuwNk4dDxHdxmz +Sjps0H5dkfCciOFhEc54AFcGEXCWHXuxVqIq/hwqTmVl1RY+PTcQUIOfx36WW1ix +JQf8TpVxUbooK8vr1jOFF6khorDXoZDJNhI2VKomWp8Y38EPGyiUPZNcnmSiezx+ +MoQwAbeqjFMKG7UAEQEAAYkCNgQYAQgAIBYhBP9uLAAZSMXy84sMw4WRH0JexhtR +BQJaylvSAhsMAAoJEIWRH0JexhtR0LEP/RvYGlaokoosAYI5vNORAiYEc1Ow2McP +I1ZafHhcVxZhlwF48dAC2bYcasDX/PbEdcD6pwo8ZU8eI8Ht0VpRQxeV/sP01m2Y +EpAuyZ6jI7IQQCGcwQdN4qzQJxMAASl9JlplH2NniXV1/994FOtesT59ePMyexm5 +7lzhYXP1PGcdt8dH37r6z3XQu0lHRG/KBn7YhyA3zwJcno324KdBRJiynlc7uqQq ++ZptU9fR1+Nx0uoWZoFMsrQUmY34aAOPJu7jGMTG+VseMH6vDdNhhZs9JOlD/e/V +aF7NyadjOUD4j/ud7c0z2EwqjDKMFTHGbIdawT/7jartT+9yGUO+EmScBMiMuJUT +dCP4YDh3ExRdqefEBff3uE/rAP73ndNYdIVq9U0gY0uSNCD9JPfj4aCN52y9a2pS +7Dg7KB/Z8SH1R9IWP+t0HvVtAILdsLExNFTedJGHRh7uaC7pwRz01iivmtAKYICz +ruqlJie/IdEFFK/sus6fZek29odTrQxx42HGHO5GCNyEdK9jKVAeuZ10vcaNbuBp +iP7sf8/BsiEU4wHE8gjFeUPRiSjnERgXQwfJosLgf/K/SShQn2dCkYZRNF+SWJ6Z +2tQxcW5rpUjtclV/bRVkUX21EYfwA6SMB811mI7AVy8WPXCe8La72ukmaxEGbpJ8 +mdzS2PJko7mm +=l0XA +-----END PGP PUBLIC KEY BLOCK----- diff --git a/README.md b/README.md index 660111c796e8..f73f89ca5ed0 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,8 @@ JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. For more information, please visit: -* [Wiki](https://github.com/junit-team/junit/wiki) -* [Download and Install guide](https://github.com/junit-team/junit/wiki/Download-and-Install) -* [Getting Started](https://github.com/junit-team/junit/wiki/Getting-started) - -[![Latest Build Status](https://junit.ci.cloudbees.com/job/JUnit/badge/icon)](https://junit.ci.cloudbees.com/) - -[![Built on DEV@cloud](http://www.cloudbees.com/sites/default/files/Button-Built-on-CB-1.png)](http://www.cloudbees.com/foss/foss-dev.cb) +* [Wiki](https://github.com/junit-team/junit4/wiki) +* [Download and Install guide](https://github.com/junit-team/junit4/wiki/Download-and-Install) +* [Getting Started](https://github.com/junit-team/junit4/wiki/Getting-started) +[![Build Status](https://travis-ci.org/junit-team/junit4.svg?branch=main)](https://travis-ci.org/junit-team/junit4) diff --git a/acknowledgements.txt b/acknowledgements.txt index fa1aa8596737..bbc24dfe041f 100644 --- a/acknowledgements.txt +++ b/acknowledgements.txt @@ -82,7 +82,7 @@ reinholdfuereder@github For initial test for GH-39 2011 Apr 15 - ububenheimer@github for bug report https://github.com/junit-team/junit/issues/208 + ububenheimer@github for bug report https://github.com/junit-team/junit4/issues/208 2011 Apr 29 reinholdfuereder@github: bug report, test, and fix for GH-38: @@ -160,4 +160,4 @@ == NOTE: as of September 2011, we have stopped recording contributions here. For a full list of everyone who has contributed great bug reports and code, please see - http://github.com/junit-team/junit + http://github.com/junit-team/junit4 diff --git a/doc/ReleaseNotes4.10.html b/doc/ReleaseNotes4.10.html index 84bc3d47cec2..b6b9483b8a74 100644 --- a/doc/ReleaseNotes4.10.html +++ b/doc/ReleaseNotes4.10.html @@ -1,6 +1,6 @@ -

Summary of Changes in version 4.10 [unreleased!]

+

Summary of Changes in version 4.10

-

A full summary of commits between 4.9 and 4.10 is on github

+

A full summary of commits between 4.9 and 4.10 is on github

junit-dep has correct contents

diff --git a/doc/ReleaseNotes4.10.md b/doc/ReleaseNotes4.10.md index 0b0a9d36a83a..5f19bf744889 100644 --- a/doc/ReleaseNotes4.10.md +++ b/doc/ReleaseNotes4.10.md @@ -2,7 +2,7 @@ Thanks to a full cast of contributors of bug fixes and new features. -A full summary of commits between 4.9 and 4.10 is on [github](https://github.com/junit-team/junit/compare/r4.9...4.10) +A full summary of commits between 4.9 and 4.10 is on [github](https://github.com/junit-team/junit4/compare/r4.9...r4.10) ### junit-dep has correct contents ### diff --git a/doc/ReleaseNotes4.12.md b/doc/ReleaseNotes4.12.md index db5197f02f80..744ecf369062 100644 --- a/doc/ReleaseNotes4.12.md +++ b/doc/ReleaseNotes4.12.md @@ -2,23 +2,23 @@ # Assertions -### [Pull request #611:](https://github.com/junit-team/junit/pull/611) Assert.assertNotEquals() for `float` parameters +### [Pull request #611:](https://github.com/junit-team/junit4/pull/611) Assert.assertNotEquals() for `float` parameters Version 4.11 added `Assert.assertEquals()` for `float` parameters with a delta, and `Assert.assertNotEquals()`. This is the combination of those two features. -### [Pull request #632:](https://github.com/junit-team/junit/pull/632) Assert.assertArrayEquals() for `boolean[]` parameters. +### [Pull request #632:](https://github.com/junit-team/junit4/pull/632) Assert.assertArrayEquals() for `boolean[]` parameters. `Assert.assertArrayEquals()` previously existed for all primitive array types, except `boolean[]`. This has now been added for `boolean[]`. -### [Pull request #918:](https://github.com/junit-team/junit/pull/918) Avoid potentially expensive reflection-based loop in Assert.assertArrayEquals() +### [Pull request #918:](https://github.com/junit-team/junit4/pull/918) Avoid potentially expensive reflection-based loop in Assert.assertArrayEquals() In the usual case, where the array elements are in fact exactly equal, the potentially expensive reflection-based loop to compare them is avoided by using `Arrays.deepEquals()` first. The exact comparison is only executed when `deepEquals()` returns `false`. # Command-line options -### [Pull request #647:](https://github.com/junit-team/junit/pull/647) Support command-line `--filter` param. +### [Pull request #647:](https://github.com/junit-team/junit4/pull/647) Support command-line `--filter` param. When running JUnit from the command line, a command-line parameter can be supplied using `--filter`, which supplies a filter that will restrict which tests and subtests from the rest of the command will be run. For example, this will run only the tests in ExampleTestSuite that are in categories Cat1 or Cat2: @@ -33,12 +33,12 @@ In general, the argument to `--filter` should be `ClassName=param`, where `Class # Test Runners -### [Pull request #763:](https://github.com/junit-team/junit/pull/763) Allow custom test runners to create their own TestClasses and customize the scanning of annotations. +### [Pull request #763:](https://github.com/junit-team/junit4/pull/763) Allow custom test runners to create their own TestClasses and customize the scanning of annotations. This introduces some extension points to `ParentRunner` to allow subclasses to control creation of the `TestClass` instance and to scan for annotations. -### [Pull request #817:](https://github.com/junit-team/junit/pull/817) Support for context hierarchies +### [Pull request #817:](https://github.com/junit-team/junit4/pull/817) Support for context hierarchies The `AnnotatedBuilder` is a strategy for constructing runners for test classes that have been annotated with the `@RunWith` annotation. All tests within such a class will be executed using the runner that was specified within the annotation. @@ -95,17 +95,17 @@ The key points to note here are: One example of a runner that makes use of this extension is the Hierarchical Context Runner (see https://github.com/bechte/junit-hierarchicalcontextrunner/wiki). -### [Pull request #716:](https://github.com/junit-team/junit/pull/716) Fix annotation collection from superclasses of JUnit3 tests. +### [Pull request #716:](https://github.com/junit-team/junit4/pull/716) Fix annotation collection from superclasses of JUnit3 tests. Previously `Description.getAnnotations()` would always return an empty list for _test*_ methods derived from superclasses. -### [Pull request #625 (commit 72af03c49f):](https://github.com/junit-team/junit/commit/72af03c49fdad5f10e36c7eb4e7045feb971d253) Make `RunNotifier` code concurrent. +### [Pull request #625 (commit 72af03c49f):](https://github.com/junit-team/junit4/commit/72af03c49fdad5f10e36c7eb4e7045feb971d253) Make `RunNotifier` code concurrent. When running tests from multiple threads, JUnit will now call `RunListener` methods from multiple threads if the listener class is annotated with `@RunListener.ThreadSafe`. In addition, the code in `RunNotifier` has been modified to not use locks. -### [Pull request #684:](https://github.com/junit-team/junit/pull/684) Adding `AnnotationValidator` framework and validation checks for `@Category`. +### [Pull request #684:](https://github.com/junit-team/junit4/pull/684) Adding `AnnotationValidator` framework and validation checks for `@Category`. This allows for validation to be added to annotations. Validators should extend `AnnotationValidator` and be attached to annotations with the `@ValidateWith` annotation. `CategoryValidator` extends `AnnotationValidator` and ensures that incompatible annotations (`@BeforeClass`, `@AfterClass`, `@Before`, `@After`) are not used in conjunction with `@Category`. @@ -113,12 +113,12 @@ This allows for validation to be added to annotations. Validators should extend # Exception Testing -### [Pull request #583:](https://github.com/junit-team/junit/pull/583) [Pull request #720:](https://github.com/junit-team/junit/pull/720) Fix handling of `AssertionError` and `AssumptionViolatedException` in `ExpectedException` rule. +### [Pull request #583:](https://github.com/junit-team/junit4/pull/583) [Pull request #720:](https://github.com/junit-team/junit4/pull/720) Fix handling of `AssertionError` and `AssumptionViolatedException` in `ExpectedException` rule. `ExpectedException` didn't handle `AssertionError`s and `AssumptionViolatedException` well. This has been fixed. The new documentation explains the usage of `ExpectedException` for testing these exceptions. The two methods `handleAssertionErrors()` and `handleAssumptionViolatedExceptions()` are not needed anymore. If you have used them, just remove it and read `ExpectedException`'s documentation. -### [Pull request #818:](https://github.com/junit-team/junit/pull/818) [Pull request #993:](https://github.com/junit-team/junit/pull/993) External version of AssumptionViolatedException +### [Pull request #818:](https://github.com/junit-team/junit4/pull/818) [Pull request #993:](https://github.com/junit-team/junit4/pull/993) External version of AssumptionViolatedException In JUnit 4.11 and earlier, if you wanted to write a custom runner that handled `AssumptionViolatedException` or you needed to create an instance of `AssumptionViolatedException` @@ -133,7 +133,7 @@ simpler than the ones in the internal version. That being said, it's recommended that you create `AssumptionViolatedException` via the methods in `Assume`. -### [Pull request #985:](https://github.com/junit-team/junit/pull/985) Change AssumptionViolatedException to not set the cause to null; fixes issue #494 +### [Pull request #985:](https://github.com/junit-team/junit4/pull/985) Change AssumptionViolatedException to not set the cause to null; fixes issue #494 Previously, the `AssumptionViolatedException` constructors would explicitly set the cause to `null` (unless you use a constructor where you provide a `Throwable`, in which case it would set that as @@ -144,7 +144,7 @@ With this change, the cause is only set if you pass in a `Throwable`. It's recommended that you create `AssumptionViolatedException` via the methods in `Assume`. -### [Pull request #542:](https://github.com/junit-team/junit/pull/542) Customized failure message for `ExpectedException` +### [Pull request #542:](https://github.com/junit-team/junit4/pull/542) Customized failure message for `ExpectedException` `ExpectedException` now allows customization of the failure message when the test does not throw the expected exception. For example: @@ -155,15 +155,22 @@ thrown.reportMissingExceptionWithMessage("FAIL: Expected exception to be thrown" If a custom failure message is not provided, a default message is used. +### [Pull request #1013:](https://github.com/junit-team/junit4/pull/1013) Make ErrorCollector#checkSucceeds generic + +The method `ErrorCollector.checkSucceeds()` is now generic. Previously, you could only pass +in a `Callable` and it returned `Object`. You can now pass any `Callable` and the +return type will match the type of the callable. + + # Timeout for Tests -*See also [Timeout for tests](https://github.com/junit-team/junit/wiki/Timeout-for-tests)* +*See also [Timeout for tests](https://github.com/junit-team/junit4/wiki/Timeout-for-tests)* -### [Pull request #823:](https://github.com/junit-team/junit/pull/823) Throw `TestFailedOnTimeoutException` instead of plain `Exception` on timeout +### [Pull request #823:](https://github.com/junit-team/junit4/pull/823) Throw `TestFailedOnTimeoutException` instead of plain `Exception` on timeout When a test times out, a `org.junit.runners.model.TestTimedOutException` is now thrown instead of a plain `java.lang.Exception`. -### [Pull request #742:](https://github.com/junit-team/junit/pull/742) [Pull request #986:](https://github.com/junit-team/junit/pull/986) `Timeout` exceptions now include stack trace from stuck thread (experimental) +### [Pull request #742:](https://github.com/junit-team/junit4/pull/742) [Pull request #986:](https://github.com/junit-team/junit4/pull/986) `Timeout` exceptions now include stack trace from stuck thread (experimental) `Timeout` exceptions try to determine if there is a child thread causing the problem, and if so its stack trace is included in the exception in addition to the one of the main thread. This feature must be enabled with the timeout rule by creating it through the new `Timeout.builder()` method: @@ -183,7 +190,7 @@ public class HasGlobalTimeout { ``` -### [Pull request #544:](https://github.com/junit-team/junit/pull/544) New constructor and factories in `Timeout` +### [Pull request #544:](https://github.com/junit-team/junit4/pull/544) New constructor and factories in `Timeout` `Timeout` deprecated the old constructor `Timeout(int millis)`. A new constructor is available: `Timeout(long timeout, TimeUnit unit)`. It enables you to use different granularities of time units like `NANOSECONDS`, `MICROSECONDS`, `MILLISECONDS`, and `SECONDS`. Examples: @@ -209,7 +216,7 @@ and factory methods in `Timeout`: This usage avoids the truncation, which was the problem in the deprecated constructor `Timeout(int millis)` when casting `long` to `int`. -### [Pull request #549:](https://github.com/junit-team/junit/pull/549) fixes for #544 and #545 +### [Pull request #549:](https://github.com/junit-team/junit4/pull/549) fixes for #544 and #545 The `Timeout` rule applies the same timeout to all test methods in a class: @@ -243,18 +250,20 @@ public class HasGlobalTimeout { ``` Each test is run in a new _daemon_ thread. If the specified timeout elapses before the test completes, its execution is interrupted via `Thread#interrupt()`. This happens in interruptable I/O (operations throwing `java.io.InterruptedIOException` and `java.nio.channels.ClosedByInterruptException`), locks (package `java.util.concurrent`) and methods in `java.lang.Object` and `java.lang.Thread` throwing `java.lang.InterruptedException`. -### [Pull request #876:](https://github.com/junit-team/junit/pull/876) The timeout rule never times out if you pass in a timeout of zero. +### [Pull request #876:](https://github.com/junit-team/junit4/pull/876) The timeout rule never times out if you pass in a timeout of zero. + +A specified timeout of 0 will be interpreted as not set, however tests still launch from separate threads. This can be useful for disabling timeouts in environments where they are dynamically set based on some property. # Parameterized Tests -### [Pull request #702:](https://github.com/junit-team/junit/pull/702) Support more return types for the `@Parameters` method of the `Parameterized` runner +### [Pull request #702:](https://github.com/junit-team/junit4/pull/702) Support more return types for the `@Parameters` method of the `Parameterized` runner The return types `Iterator`, `Object[]` and `Object[][]` are now supported on methods annotated with `@Parameters`. You don't have to wrap arrays with `Iterable`s and single parameters with `Object` arrays. -### [Pull request #773:](https://github.com/junit-team/junit/pull/773) Allow configurable creation of child runners of parameterized suites +### [Pull request #773:](https://github.com/junit-team/junit4/pull/773) Allow configurable creation of child runners of parameterized suites The factory for creating the `Runner` instance of a single set of parameters is now configurable. It can be specified by the `@UseParametersRunnerFactory` annotation. @@ -262,7 +271,7 @@ The factory for creating the `Runner` instance of a single set of parameters is # Rules -### [Pull request #552:](https://github.com/junit-team/junit/pull/552) [Pull request #937:](https://github.com/junit-team/junit/pull/937) `Stopwatch` rule +### [Pull request #552:](https://github.com/junit-team/junit4/pull/552) [Pull request #937:](https://github.com/junit-team/junit4/pull/937) `Stopwatch` rule The `Stopwatch` Rule notifies one of its own protected methods of the time spent by a test. Override them to get the time in nanoseconds. For example, this class will keep logging the time spent by each passed, failed, skipped, and finished test: @@ -327,9 +336,9 @@ public void performanceTest() throws InterruptedException { } ``` -### [Pull request #932:](https://github.com/junit-team/junit/pull/932) Allow static `@Rule`s also annotated with `@ClassRule` +### [Pull request #932:](https://github.com/junit-team/junit4/pull/932) Allow static `@Rule`s also annotated with `@ClassRule` -JUnit 4.11 introduced restrictions requiring `@Rule` members to be non-static and `@ClassRule` members to be static. These restrictions have been relaxed slightly, in that a static member annotated with both `@Rule` and `@ClassRule` is now considered valid. This means a single rule may be used to perform actions both before/after a class (e.g. setup/tear down an external resource) and between tests (e.g. reset the external resource), without the need for any workarounds mentioned in issue [#793](https://github.com/junit-team/junit/issues/793). +JUnit 4.11 introduced restrictions requiring `@Rule` members to be non-static and `@ClassRule` members to be static. These restrictions have been relaxed slightly, in that a static member annotated with both `@Rule` and `@ClassRule` is now considered valid. This means a single rule may be used to perform actions both before/after a class (e.g. setup/tear down an external resource) and between tests (e.g. reset the external resource), without the need for any workarounds mentioned in issue [#793](https://github.com/junit-team/junit4/issues/793). Note that a non-static `@ClassRule` annotated member is still considered invalid, even if annotated with `@Rule`. @@ -343,7 +352,7 @@ public class CommonRuleTest { Be warned that if you have static methods or fields annotated with `@Rule` you will not be able to run your test methods in parallel. -### [Pull request #956:](https://github.com/junit-team/junit/pull/956) `DisableOnDebug` rule +### [Pull request #956:](https://github.com/junit-team/junit4/pull/956) `DisableOnDebug` rule The `DisableOnDebug` rule allows users to disable other rules when the JVM is launched in debug mode. Prior to this feature the common approach to disable rules that make debugging difficult was to comment them out and remember to revert the change. When using this feature users no longer have to modify their test code nor do they need to remember to revert changes. @@ -354,15 +363,15 @@ This rule is particularly useful in combination with the `Timeout` rule. public DisableOnDebug timeout = new DisableOnDebug(Timeout.seconds(1)); ``` -See the Javadoc for more detail and limitations. Related to https://github.com/junit-team/junit/issues/738 +See the Javadoc for more detail and limitations. Related to https://github.com/junit-team/junit4/issues/738 -### [Pull request #974:](https://github.com/junit-team/junit/pull/974) Updated `TemporaryFolder.newFolder()` to give an error message if a path contains a slash. +### [Pull request #974:](https://github.com/junit-team/junit4/pull/974) Updated `TemporaryFolder.newFolder()` to give an error message if a path contains a slash. If you call `TemporaryFolder.newFolder("foo/bar")` in JUnit 4.10 the method returns a `File` object for the new folder but actually fails to create it. That is contrary to the expected behaviour of the method which is to actually create the folder. In JUnit 4.11 the same call throws an exception. Nowhere in the documentation does it explain that the String(s) passed to that method can only be single path components. With this fix, folder names are validated to contain single path name. If the folder name consists of multiple path names, an exception is thrown stating that usage of multiple path components in a string containing folder name is disallowed. -### [Pull request #1015:](https://github.com/junit-team/junit/pull/1015) Methods annotated with `Rule` can return a `MethodRule`. +### [Pull request #1015:](https://github.com/junit-team/junit4/pull/1015) Methods annotated with `Rule` can return a `MethodRule`. Methods annotated with `@Rule` can now return either a `TestRule` (or subclass) or a `MethodRule` (or subclass). @@ -373,7 +382,7 @@ the method is only called if the return type could be assigned to `TestRule` or `MethodRule`. For methods annotated with `@Rule` that return other values, see the notes for pull request #1020. -### [Pull request #1020:](https://github.com/junit-team/junit/pull/1020) Added validation that @ClassRule should only be implementation of TestRule. +### [Pull request #1020:](https://github.com/junit-team/junit4/pull/1020) Added validation that @ClassRule should only be implementation of TestRule. Prior to this change, fields annotated with `@ClassRule` that did not have a type of `TestRule` (or a class that implements `TestRule`) were ignored. With this change, the test will fail @@ -383,7 +392,7 @@ Prior to this change, methods annotated with `@ClassRule` that did specify a ret of `TestRule`(or a class that implements `TestRule`) were ignored. With this change, the test will fail with a validation error. -### [Pull request #1021:](https://github.com/junit-team/junit/pull/1021) JavaDoc of TemporaryFolder: folder not guaranteed to be deleted. +### [Pull request #1021:](https://github.com/junit-team/junit4/pull/1021) JavaDoc of TemporaryFolder: folder not guaranteed to be deleted. Adjusted JavaDoc of TemporaryFolder to reflect that temporary folders are not guaranteed to be deleted. @@ -391,12 +400,12 @@ deleted. # Theories -### [Pull request #529:](https://github.com/junit-team/junit/pull/529) `@DataPoints`-annotated methods can now yield `null` values +### [Pull request #529:](https://github.com/junit-team/junit4/pull/529) `@DataPoints`-annotated methods can now yield `null` values Up until JUnit 4.11 a `@DataPoints`-annotated array field could contain `null` values, but the array returned by a `@DataPoints`-annotated method could not. This asymmetry has been resolved: _both_ can now provide a `null` data point. -### [Pull request #572:](https://github.com/junit-team/junit/pull/572) Ensuring no-generic-type-parms validator called/tested for theories +### [Pull request #572:](https://github.com/junit-team/junit4/pull/572) Ensuring no-generic-type-parms validator called/tested for theories The `Theories` runner now disallows `Theory` methods with parameters that have "unresolved" generic type parameters (e.g. `List` where `T` is a type variable). It is exceedingly difficult for the `DataPoint(s)` scraper or other `ParameterSupplier`s to correctly decide values that can legitimately be assigned to such parameters in a type-safe way, so JUnit now disallows them altogether. Theory parameters such as `List` and `Iterable` are still allowed. @@ -405,7 +414,7 @@ The machinery to perform this validation was in the code base for some time, but [junit.contrib](https://github.com/junit-team/junit.contrib)'s rendition of theories performs the same validation. -### [Pull request #607:](https://github.com/junit-team/junit/pull/607) Improving theory failure messages +### [Pull request #607:](https://github.com/junit-team/junit4/pull/607) Improving theory failure messages Theory failure messages previously were of the form: `ParameterizedAssertionError: theoryTest(badDatapoint, allValues[1], otherVar)`, where allValues, badDatapoint and otherVar were the variables the datapoints was sourced from. These messages are now of the form: @@ -415,7 +424,7 @@ ParameterizedAssertionError: theoryTest(null , "good value" < ``` -### [Pull request #601:](https://github.com/junit-team/junit/pull/601) Allow use of `Assume` in tests run by `Theories` runner +### [Pull request #601:](https://github.com/junit-team/junit4/pull/601) Allow use of `Assume` in tests run by `Theories` runner If, in a theory, all parameters were "assumed" away, the `Theories` runner would properly fail, informing you that no parameters were found to actually test something. However, if you had another method in that same class, that was not a theory (annotated with `@Test` only,) you could not use Assume in that test. Now, the `Theories` runner will verify the method is annotated with `@Theory` before failing due to no parameters being found. @@ -440,12 +449,12 @@ public class TheoriesAndTestsTogether { ``` -### [Pull request #623:](https://github.com/junit-team/junit/pull/623) Ensure data points array fields and methods are `public` and `static` in Theory classes. +### [Pull request #623:](https://github.com/junit-team/junit4/pull/623) Ensure data points array fields and methods are `public` and `static` in Theory classes. Previously if a data points array field or method was non-`static` or non-`public` it would be silently ignored and the data points not used. Now the `Theories` runner verifies that all `@DataPoint` or `@DataPoints` annotated fields or methods in classes are both `public` and `static`, and such classes will fail to run with `InitializationError`s if they are not. -### [Pull request #621:](https://github.com/junit-team/junit/pull/621) Added mechanism for matching specific data points in theories to specific parameters, by naming data points. +### [Pull request #621:](https://github.com/junit-team/junit4/pull/621) Added mechanism for matching specific data points in theories to specific parameters, by naming data points. `@DataPoints` fields or methods can now be given (one or more) names in the annotation, and `@Theory` method parameters can be annotated with `@FromDataPoints(name)`, to limit the data points considered for that parameter to only the data points with that name: @@ -475,26 +484,26 @@ public void regexTheory(@FromDataPoints("regexes") String regex, ``` -### [Pull request #654:](https://github.com/junit-team/junit/pull/654) Auto-generation of `enum` and `boolean` data points +### [Pull request #654:](https://github.com/junit-team/junit4/pull/654) Auto-generation of `enum` and `boolean` data points Any theory method parameters with `boolean` or `enum` types that cannot be supplied with values by any other sources will be automatically supplied with default values: `true` and `false`, or every value of the given `enum`. If other explicitly defined values are available (e.g. from a specified `ParameterSupplier` or some `DataPoints` method in the theory class), only those explicitly defined values will be used. -### [Pull request #651:](https://github.com/junit-team/junit/pull/651) Improvements to Theory parameter and DataPoint type matching +### [Pull request #651:](https://github.com/junit-team/junit4/pull/651) Improvements to Theory parameter and DataPoint type matching * Validity of `DataPoints` for theory parameters for all field data points and multi-valued method data points (i.e. not single-valued method data points) is now done on runtime type, not field/method return type (previously this was the case for multi-valued array methods only). * Validity of `DataPoints` for theory parameters for all data points now correctly handles boxing and unboxing for primitive and wrapper types; e.g. `int` values will be considered for theory parameters that are `Integer` assignable, and vice versa. -### [Pull request #639:](https://github.com/junit-team/junit/pull/639) Failing theory datapoint methods now cause theory test failures +### [Pull request #639:](https://github.com/junit-team/junit4/pull/639) Failing theory datapoint methods now cause theory test failures Previously `@DataPoint(s)` methods that threw exceptions were quietly ignored and if another `DataPoint` source was available then those values alone were used, leaving the theory passing using only a subset of the (presumably) intended input values. Now, any data point method failures during invocation of a theory will cause the theory being tested to fail immediately. *This is a non-backward-compatible change*, and could potentially break theory tests that depended on failing methods. If that was desired behavior, then the expected exceptions can instead be specifically ignored using the new `ignoredExceptions` array attribute on `@DataPoint` and `@DataPoints` methods. Adding an exception to this `ignoredExceptions` array will stop theory methods from failing if the given exception, or subclasses of it, are thrown in the annotated method. This attribute has no effect on data point fields. -### [Pull request #658:](https://github.com/junit-team/junit/pull/658) `Iterable`s can now be used as data points +### [Pull request #658:](https://github.com/junit-team/junit4/pull/658) `Iterable`s can now be used as data points Previously, when building sets of data points for theory parameters, the only valid multi-valued `@DataPoints` types were arrays. This has now been extended to also take parameters from `Iterable` `@DataPoints` methods and fields. @@ -502,12 +511,12 @@ Previously, when building sets of data points for theory parameters, the only va # Categories -### [Pull request #566:](https://github.com/junit-team/junit/pull/566) Enables inheritance on `Category` by adding `@Inherited` +### [Pull request #566:](https://github.com/junit-team/junit4/pull/566) Enables inheritance on `Category` by adding `@Inherited` `@interface Category` now is annotated with `@Inherited` itself. This enables inheritance of categories from ancestors (e.g. abstract test-classes). Note that you are able to "overwrite" `@Category` on inheritors and that this has no effect on method-level categories (see [@Inherited](http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/Inherited.html)). -### [Pull request #503:](https://github.com/junit-team/junit/pull/503) Configurable Categories +### [Pull request #503:](https://github.com/junit-team/junit4/pull/503) Configurable Categories From a given set of test classes, the `Categories` runner runs only the classes and methods that are annotated with either the category given with the `@IncludeCategory` annotation, or a subtype of that category. Either classes or interfaces can be used as categories. Subtyping works, so if you say `@IncludeCategory(SuperClass.class)`, a test marked `@Category({SubClass.class})` will be run. @@ -582,7 +591,7 @@ public class SlowTestSuiteWithoutFast { # Use with Maven -### [Pull request #879:] (https://github.com/junit-team/junit/pull/879) Add the default 'Implementation-*' headers to the manifest +### [Pull request #879:] (https://github.com/junit-team/junit4/pull/879) Add the default 'Implementation-*' headers to the manifest The default Maven-style 'Implementation-*' headers are now present in the manifest of `junit.jar`. Example: ``` @@ -593,7 +602,7 @@ Implementation-Vendor-Id: junit ``` -### [Pull request #511:](https://github.com/junit-team/junit/pull/511) Maven project junit:junit:jar +### [Pull request #511:](https://github.com/junit-team/junit4/pull/511) Maven project junit:junit:jar #### How to install Maven @@ -609,7 +618,7 @@ Create directory _.m2_ in your _user home_. Then the artifacts and plugins are s #### How to launch the build from the command line -Clone the project (git clone https://github.com/junit-team/junit.git) and navigate to the project root on your local system (cd junit). +Clone the project (git clone https://github.com/junit-team/junit4.git) and navigate to the project root on your local system (cd junit). Clean the previous build in _target_ directory, build the project, and install new artifacts in your local repository: `apache-maven-3.0.4/bin/mvn clean install` @@ -659,15 +668,15 @@ Follow this link for _IntelliJ IDEA_: [http://www.jetbrains.com/idea/webhelp/act # Miscellaneous -### [Pull request #776:](https://github.com/junit-team/junit/pull/776) Add support for [Travis CI](http://travis-ci.org) +### [Pull request #776:](https://github.com/junit-team/junit4/pull/776) Add support for [Travis CI](http://travis-ci.org) Travis CI is a free CI server for public Github repositories. Every pull request is run by Travis CI and Github's web interface shows the CI result for each pull request. Every user can use Travis CI for testing her branches, too. -### [Pull request #921:](https://github.com/junit-team/junit/pull/921) Apply Google Code Style +### [Pull request #921:](https://github.com/junit-team/junit4/pull/921) Apply Google Code Style JUnit is now using the well documented [Google Code Style](http://google-styleguide.googlecode.com/svn/trunk/javaguide.html) -### [Pull request #939](https://github.com/junit-team/junit/pull/939) Renamed license file +### [Pull request #939](https://github.com/junit-team/junit4/pull/939) Renamed license file While using JUnit in Android apps, if any other referenced library has a file named `LICENSE.txt`, the APK generation failed with the following error - @@ -676,7 +685,7 @@ While using JUnit in Android apps, if any other referenced library has a file na To avoid this, the license file has been renamed to `LICENSE-junit.txt` -### [Pull request #962:](https://github.com/junit-team/junit/pull/962) Do not include thread start time in test timeout measurements. +### [Pull request #962:](https://github.com/junit-team/junit4/pull/962) Do not include thread start time in test timeout measurements. The time it takes to start a thread can be surprisingly large. Especially in virtualized cloud environments where noisy neighbours. @@ -693,31 +702,31 @@ The following section lists fixes to problems introduced in the first release candidates for JUnit 4.12. You can ignore this section if you are trying to understand the changes between 4.11 and 4.12. -### [Pull request #961:](https://github.com/junit-team/junit/pull/961) Restore field names with f prefix. +### [Pull request #961:](https://github.com/junit-team/junit4/pull/961) Restore field names with f prefix. In order to make the JUnit code more consistent with current coding practices, we changed a number of field names to not start with the prefix "f". Unfortunately, at least one IDE referenced a private field via reflection. This change reverts the field names for fields known to be read via reflection. -### [Pull request #988:](https://github.com/junit-team/junit/pull/988) Revert "Delete classes that are deprecated for six years." +### [Pull request #988:](https://github.com/junit-team/junit4/pull/988) Revert "Delete classes that are deprecated for six years." -In [745ca05](https://github.com/junit-team/junit/commit/745ca05dccf5cc907e43a58142bb8be97da2b78f) +In [745ca05](https://github.com/junit-team/junit4/commit/745ca05dccf5cc907e43a58142bb8be97da2b78f) we removed classes that were deprecated for many releases. There was some concern that people might not expect classes to be removed in a 4.x release. Even though we are not aware of any problems from the deletion, we decided to add them back. These classes may be removed in JUnit 5.0 or later. -### [Pull request #989:](https://github.com/junit-team/junit/pull/989) Add JUnitSystem.exit() back. +### [Pull request #989:](https://github.com/junit-team/junit4/pull/989) Add JUnitSystem.exit() back. -In [917a88f](https://github.com/junit-team/junit/commit/917a88fad06ce108a596a8fdb4607b1a2fbb3f3e) +In [917a88f](https://github.com/junit-team/junit4/commit/917a88fad06ce108a596a8fdb4607b1a2fbb3f3e) the exit() method in JUnit was removed. This caused problems for at least one user. Even though this class is in an internal package, we decided to add it back, and deprecated it. This method may be removed in JUnit 5.0 or later. -### [Pull request #994:](https://github.com/junit-team/junit/pull/994) [Pull request #1000:](https://github.com/junit-team/junit/pull/1000) Ensure serialization compatibility where possible. +### [Pull request #994:](https://github.com/junit-team/junit4/pull/994) [Pull request #1000:](https://github.com/junit-team/junit4/pull/1000) Ensure serialization compatibility where possible. JUnit 4.12 RC1 introduced serilization incompatibilities with some of the classes. For example, these pre-release versions of JUnit could not read instances of `Result` that were serialized diff --git a/doc/ReleaseNotes4.13.1.md b/doc/ReleaseNotes4.13.1.md new file mode 100644 index 000000000000..ab44490622c6 --- /dev/null +++ b/doc/ReleaseNotes4.13.1.md @@ -0,0 +1,7 @@ +## Summary of changes in version 4.13.1 + +# Test Runners + +### [Pull request #1669:](https://github.com/junit-team/junit/pull/1669) Make `FrameworkField` constructor public + +Prior to this change, custom runners could make `FrameworkMethod` instances, but not `FrameworkField` instances. This small change allows for both now, because `FrameworkField`'s constructor has been promoted from package-private to public. diff --git a/doc/ReleaseNotes4.13.md b/doc/ReleaseNotes4.13.md index a8391ce173ba..a3ec73e178cf 100644 --- a/doc/ReleaseNotes4.13.md +++ b/doc/ReleaseNotes4.13.md @@ -1,6 +1,327 @@ -## Summary of changes in version 4.13 [unreleased!] +## Summary of changes in version 4.13 -We collect release notes in the wiki: -https://github.com/junit-team/junit/wiki/4.13-release-notes +# Assertions -This file will be updated right before release. +### [Pull request #1054:](https://github.com/junit-team/junit/pull/1054) Improved error message for `assertArrayEquals` when multi-dimensional arrays have different lengths + +Previously, JUnit's assertion error message would indicate only that some array lengths _x_ and _y_ were unequal, without indicating whether this pertained to the outer array or some nested array. Now, in case of a length mismatch between two nested arrays, JUnit will tell at which indices they reside. + +### [Pull request #1154](https://github.com/junit-team/junit/pull/1154) and [#1504](https://github.com/junit-team/junit/pull/1504) Add `assertThrows` + +The `Assert` class now includes methods that can assert that a given function call (specified, for instance, as a lambda expression or method reference) results in a particular type of exception being thrown. In addition it returns the exception that was thrown, so that further assertions can be made (e.g. to verify that the message and cause are correct). + +### [Pull request #1300:](https://github.com/junit-team/junit/pull/1300) Show contents of actual array when array lengths differ + +Previously, when comparing two arrays which differ in length, `assertArrayEquals()` would only report that they differ in length. Now, it does the usual array comparison even when arrays differ in length, producing a failure message which combines the difference in length and the first difference in content. Where the content is another array, it is described by its type and length. + +### [Pull request #1315:](https://github.com/junit-team/junit4/pull/1315) `assertArrayEquals` shouldn't throw an NPE when test suites are compiled/run across versions of junit + +A redundant field, `fCause`, was removed on v4.12, and was seemingly harmless because `Throwable#initCause()` could directly initialize `cause` in the constructor. Unfortunately, this backwards incompatible change got aggravated when a test class, compiled with the latest (4.12+), ran with an older version that depended on fCause when building the assertion message[1](#1315-f1). + +This change adds back `fCause`, and overrides `getCause()` to handle forward compatibility[2](#1315-f2). + +To ensure serializability of further changes in `ArrayAssertionFailure` (until excising these fields by a major rev), a unit test now runs against v4.11, v4.12 failures, asserting around `#toString/getCause()`. + +[1] [Issue #1178](https://github.com/junit-team/junit4/issues/1178) details a particular case where gradle v2.2 is packaged with junit v4.11 and is used on running a test, generating test reports, despite specifying a particular version of junit (users would specify v4.12, or v4.+) in the test compile dependencies). + +[2] [Case](https://github.com/junit-team/junit4/pull/1315#issuecomment-222905229) if the test class is compiled with <= v4.11, where only `fCause` is initialized and not `Throwable#cause`, it can now fallback to the field, `fCause`, when building the message. + +### [Pull request #1150:](https://github.com/junit-team/junit4/pull/1150) Deprecate `Assert#assertThat` + +The method `assertThat` is used for writing assertions with Hamcrest. Hamcrest is an independent assertion library and contains an own `assertThat` method in the class `org.hamcrest.MatcherAssert`. It is available both in the old Hamcrest 1.3 release and in the current Hamcrest 2.1. Therefore the JUnit team recommends to use Hamcrest's own `assertThat` directly. + +# Test Runners + +### [Pull request #1037:](https://github.com/junit-team/junit/pull/1037) `BlockJUnit4ClassRunner#createTest` now accepts `FrameworkMethod` + +Subclasses of `BlockJUnit4ClassRunner` can now produce a custom test object based on the `FrameworkMethod` test being executed by implementing the new `createTest(FrameworkMethod)` method. The default implementation calls the existing `createTest()` method. + +### [Pull request #1082](https://github.com/junit-team/junit/pull/1082): Ensure exceptions from `BlockJUnit4ClassRunner.methodBlock()` don't result in unrooted tests + +The introduction of the `runLeaf()` method in `BlockJUnit4ClassRunner` in JUnit 4.9 introduced a regression with regard to exception handling. Specifically, in JUnit 4.9 through 4.12 the invocation of `methodBlock()` is no longer executed within a try-catch block as was the case in previous versions of JUnit. Custom modifications to `methodBlock()` or the methods it invokes may in fact throw exceptions, and such exceptions cause the current test execution to abort immediately. As a result, the failing test method is unrooted in test reports, and subsequent test methods are never invoked. Furthermore, any `RunListener` registered with JUnit is not notified. + +As of JUnit 4.13, the invocation of `methodBlock()` is once again wrapped within a try-catch block. If an exception is _not_ thrown, the resulting `Statement` is passed to `runLeaf()`. If an exception _is_ thrown, it is wrapped in a `Fail` statement which is passed to `runLeaf()`. + +### [Pull request #1286](https://github.com/junit-team/junit/pull/1286): Provide better feedback to the user in case of invalid test classes + +Only one exception per invalid test class is now thrown, rather than one per validation error. +The message of the exception includes all of the validation errors. + +Example: + + org.junit.runners.InvalidTestClassError: Invalid test class 'com.example.MyTest': + 1. Method staticAfterMethod() should not be static + 2. Method staticBeforeMethod() should not be static + +is the exception thrown when running the following test class with any kind of `ParentRunner`: + + public class MyTest { + + @Before + public static void staticBeforeMethod() { .. } + + @After + public static void staticAfterMethod() { .. } + + @Test + public void myTest() { .. } + } + +Validation errors for the same test class now count only once in the failure count. Therefore, in the example above, `Result#getFailureCount` will return 1. + +### [Pull request #1252](https://github.com/junit-team/junit4/pull/1252): Restore ability use ParentRunner lost in separate class loader + +`ParentRunner.getDescription()` now uses the class instance of the test class to create the description +(previously the class instance was loaded using the current classloader). + +### [Pull request #1377](https://github.com/junit-team/junit4/pull/1377): Description produced by Request.classes() shouldn't be null + +When obtaining a `Runner` via [Request.classes(Class... classes)](http://junit.org/junit4/javadoc/4.12/org/junit/runner/Request.html#classes(java.lang.Class...)), that Runner's `Description` will now print "classes" for the root item. This replaces the misleading output of String "null". + +### [Issue #1290](https://github.com/junit-team/junit4/issues/1290): Tests expecting AssumptionViolatedException are now correctly marked as passed + + @Test(expected = AssumptionViolatedException.class) + public void shouldThrowAssumptionViolatedException() { + throw new AssumptionViolatedException("expected"); + } + +This test would previously be marked as skipped; now will be marked as passed. + + +### [Pull request #1465](https://github.com/junit-team/junit/pull/1465): Provide helpful message if parameter cannot be set. + +JUnit throws an exception with a message like + + Cannot set parameter 'name'. Ensure that the the field 'name' is public. + +if a field of a parameterized test is annotated `@Parameter`, but its visibility is not public. Before an IllegalAccessException was thrown with a message like "Class ... can not access a member of class X with modifiers private". + + +### [Issue #1329](https://github.com/junit-team/junit4/issus/1329): Support assumptions in `@Parameters` method + +No test is run when an assumption in the `@Parameters` method fails. The test result for this test class contains one assumption failure and run count is zero. + + +### [Pull request #1449](https://github.com/junit-team/junit/pull/1449): Parameterized runner reuses TestClass instance + +Reduce memory consumption of parameterized tests by not creating a new instance of `TestClass` for every test. + +### [Pull request #1130](https://github.com/junit-team/junit/pull/1130): Add Ordering, Orderable and @OrderWith + +Test classes can now be annotated with `@OrderWith` to specify that the tests should execute in a particular +order. All runners extending `ParentRunner` support `@OrderWith`. Runners can also be ordered using +`Request.orderWith(Ordering)` + +Classes annotated with `@RunWith(Suite.class)` can also be ordered with `@OrderWith`. Note that if this is done, nested classes annotated with `@FixMethodOrder` will not be reordered (i.e. the `@FixMethodOrder` annotation is +always respected). Having a test class annotated with both `@OrderWith` and `@FixMethodOrder` will result in a +validation error (see +[pull request #1638](https://github.com/junit-team/junit4/pull/1638)). + +### [Pull request #1408](https://github.com/junit-team/junit/pull/1408): Suites don't have to be public + +Classes annotated with `@RunWith(Suite.class)` do not need to be public. This fixes a regression bug in JUnit 4.12. Suites didn't had to be public before 4.12. + +### [Pull request #1638](https://github.com/junit-team/junit4/pull/1638): Never reorder classes annotated with @FixMethodOrder + +Changing the order of a test run using `Request.sortWith()` no longer changes the order of test classes annotated +with `@FixMethodOrder`. The same holds true when you reorder tests with `Request.orderWith()` (`orderWith()` +was introduced in [Pull request #1130](https://github.com/junit-team/junit/pull/1130)). + +This was done because usually `@FixMethodOrder` is added to a class because the tests in the class they only pass +if run in a specific order. + +Test suites annotated with `@OrderWith` will also respect the `@FixMethodOrder` annotation. + +Having a test class annotated with both `@OrderWith` and `@FixMethodOrder` will result in a validation error. + +# Rules + +### [Pull request #1044:](https://github.com/junit-team/junit/pull/1044) Strict verification of resource deletion in `TemporaryFolder` rule + +Previously `TemporaryFolder` rule did not fail the test if some temporary resources could not be deleted. With this change a new `assuredDeletion` parameter is introduced which will fail the test with an `AssertionError`, if resource deletion fails. The default behavior of `TemporaryFolder` is unchanged. + +This feature must be enabled by creating a `TemporaryFolder` using the `TemporaryFolder.builder()` method: +```java +@Rule public TemporaryFolder folder = TemporaryFolder.builder().assureDeletion().build(); +``` + +### [Issue #1100:](https://github.com/junit-team/junit/issues/1110) StopWatch does not need to be abstract. + +Previously `StopWatch` was an abstract class, which means it cannot be used without extending it or using an anonymous class. The abstract modifier has been removed and StopWatch can be used easily now. + +### [Issue #1157:](https://github.com/junit-team/junit/issues/1157) TestName: Make 'name' field volatile + +The `name` field in the `TestName` rule was updated to be volatile. This should ensure that the name +is published even when tests are running in parallel. + +### [Issue #1223:](https://github.com/junit-team/junit/issues/1223) TemporaryFolder doesn't work for parallel test execution in several JVMs + +Previously `TemporaryFolder` rule silently succeeded if it failed to create a fresh temporary directory. With this change it will notice the failure, retry with a new name, and ultimately throw an `IOException` if all such attempts fail. + +### [Pull request #1305:](https://github.com/junit-team/junit/pull/1305) Add `ErrorCollector.checkThrows` + +The `ErrorCollector` class now has a `checkThrows` method that can assert that a given function call (specified, for instance, as a lambda expression or method reference) results in a particular type of exception being thrown. + +### [Issue #1303:](https://github.com/junit-team/junit/issues/1303) Prevent following symbolic links when deleting temporary directories + +Previously, `TemporaryFolder` would follow symbolic links; now it just deletes them. + +Following symbolic links when removing files can lead to the removal of files outside the directory structure rooted in the temporary folder, and it can lead to unbounded recursion if a symbolic link points to a directory where the link is directly reachable from. + +### [Issue #1295:](https://github.com/junit-team/junit/issues/1295) Javadoc for RuleChain contains errors + +Removed error from RuleChain Javadoc and clarified how it works with existing rules. Removed `static` modifier, added missing closing parenthesis of method calls and added clarification. + +### [Pull request #1313](https://github.com/junit-team/junit4/pull/1313): `RuleChain.around()` rejects null arguments +`RuleChain.around()` now implements a fail-fast strategy which also allows for better feedback to the final user, as the stacktrace will point to the exact line where the null rule is declared. + +### [Pull request #1397](https://github.com/junit-team/junit4/pull/1397): Change generics on `ExpectedException.expectCause()` +The signature of `ExpectedException.expectCause()` would not allow the caller to pass in a `Matcher` (which is returned by `CoreMatchers.notNullValue()`). This was fixed by changing the method to take in a +`Matcher` (ideally, the method should take in `Matcher` but there was concern that +changing the parameter type to `Matcher` would break some callers). + +### [Pull request #1443](https://github.com/junit-team/junit4/pull/1443): `ExpectedException.isAnyExceptionExpected()` is now public +The method `ExpectedException.isAnyExceptionExpected()` returns `true` if there is at least one expectation present for the `ExpectedException` rule. + +### [Pull request #1395](https://github.com/junit-team/junit4/pull/1395): Wrap assumption violations in ErrorCollector +Both `ErrorCollector.addError()` and `ErrorCollector.checkSucceeds()` now wrap `AssumptionViolatedException`. +In addition, `ErrorCollector.addError()` will throw a `NullPointerException` if you pass in a `null` value. + +### [Pull request #1402](https://github.com/junit-team/junit4/pull/1402): TemporaryFolder.newFolder(String) supports paths with slashes +There was a regression in JUnit 4.12 where `TemporaryFolder.newFolder(String)` no longer supported passing +in strings with separator characters. This has been fixed. he overload of newFolder() that +supports passing in multiple strings still does not allow path separators. + +### [Pull requests #1406 (part 1)](https://github.com/junit-team/junit4/pull/1406) and [#1568](https://github.com/junit-team/junit4/pull/1568): Improve error message when TemporaryFolder.newFolder(String) fails +When `newFolder(String path)` was not able to create the folder then it always failed with the error message "a folder with the name '``' already exists" although the reason for the failure could be something else. This message is now only used if the folder really exists. The message is "a file with the path '``' exists" if the whole path or a part of the path points to a file. In all other cases it fails now with the message "could not create a folder with the path '``'" + +### [Pull request #1406 (part 2)](https://github.com/junit-team/junit4/pull/1406): TemporaryFolder.newFolder(String...) supports path separator +You can now pass paths with path separators to `TemporaryFolder.newFolder(String...)`. E.g. + + tempFolder.newFolder("temp1", "temp2", "temp3/temp4") + +It creates a folder `temp1/temp2/temp3/temp4`. + + +### [Pull request #1406 (part 3)](https://github.com/junit-team/junit4/pull/1406): TemporaryFolder.newFolder(String...) fails for empty array + +When you call + + tempFolder.newFolder(new String[]) + +then it throws an `IllegalArgumentException` instead of returning an already existing folder. + + +### [Pull request #1335](https://github.com/junit-team/junit4/pull/1335): Fix ExternalResource: the test failure could be lost +When both the test failed and closing the resource failed, only the exception coming from the `after()` method was propagated, as per semantics of the try-finally (see also http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.2). + +The new behavior is compatible with @After method semantics, as implemented in [RunAfters](https://github.com/junit-team/junit4/blob/HEAD/src/main/java/org/junit/internal/runners/statements/RunAfters.java). + +### [Pull request #1435](https://github.com/junit-team/junit4/pull/1435): @BeforeParam/@AfterParam method annotations for Parameterized tests. +This allows having preparation and/or cleanup in tests for specific parameter values. + +### [Pull request #1460](https://github.com/junit-team/junit4/pull/1460): Handle assumption violations in the @Parameters method for Parameterized tests. +This allows skipping the whole test class when its assumptions are not met. + +### [Pull request #1445](https://github.com/junit-team/junit4/pull/1445) and [Pull request #1335](https://github.com/junit-team/junit4/pull/1501): Declarative ordering of rules. +The order in which rules are executed is specified by the annotation attribute: `@Rule(order = N)`, deprecating `RuleChain`. This may be used for avoiding some common pitfalls with `TestWatcher, `ErrorCollector` and `ExpectedException` for example. The Javadoc of `TestWatcher` was retrofitted accordingly. + +### [Pull request #1517](https://github.com/junit-team/junit4/pull/1517): Timeout rule destroys its ThreadGroups at the end +The `ThreadGroup` created for handling the timeout of tests is now destroyed, so the main thread group no longer keeps a reference to all timeout groups created during the tests. This caused the `threadGroup` to remain in memory, and all of its context along with it. + +### [Pull request #1633](https://github.com/junit-team/junit4/pull/1633): Deprecate ExpectedException.none() +The method Assert.assertThrows provides a nicer way for verifying exceptions. In addition the use of ExpectedException is error-prone when used with other rules like TestWatcher because the order of rules is important in that case. + +### [Pull request #1413](https://github.com/junit-team/junit4/pull/1413): Ignore bridge methods when scanning for annotated methods + +In a setup with a class hierarchy for test classes the order of rules (from methods), before methods, after methods and others depends on the class that contains these methods. Compilers can add bridge methods to child classes and therefore the order of the aforementioned methods can change in older JUnit releases. This is now fixed because bridge methods are ignored when scanning for annotated methods. + +### [Pull request #1612](https://github.com/junit-team/junit4/pull/1612): Make @ValidateWith only applicable to annotation types + +`@Target(ANNOTATION_TYPE)` has been added to `@ValidateWith` since it's only designed to be applied to another annotation. + +# Run Listener + +### [Pull request #1118:](https://github.com/junit-team/junit4/pull/1118) Add suite start/finish events to listener + +The `RunListener` class now has `fireTestSuiteStarted` and `fireTestSuiteFinished` methods that notify when test suites are about to be started/finished. + + +# Exception Testing + +### [Pull request #1359:](https://github.com/junit-team/junit4/pull/1359) Fixes how `MultipleFailureException` stack traces are printed + +Previously, calling `MultipleFailureException.printStackTrace()` only printed the stack trace for the `MultipleFailureException` itself. After this change, the stack trace for each exception caught in the `MultipleFailureException` is printed. + +### [Pull request #1376:](https://github.com/junit-team/junit4/pull/1376) Initializing MultipleFailureException with an empty list will now fail the test + +Previously, initializing `MultipleFailureException` with an empty list of contained Exceptions and throwing it in a test case wouldn't actually fail the test. Now an `IllegalArgumentException` will be raised in this situation and thus also fail the test. + +### [Pull request #1371:](https://github.com/junit-team/junit4/pull/1371) Update MultipleFailureException.assertEmpty() to wrap assumption failure + +`MultipleFailureException` will now wrap `MultipleFailureException` with `TestCouldNotBeSkippedException`. Previously, if you passed `MultipleFailureException` one `MultipleFailureException`--and no other exceptions-- +then the test would be skipped, otherwise it would fail. With the new behavior, it will always fail. + +### [Issue #1290:](https://github.com/junit-team/junit4/issues/1290) `@Test(expected = AssumptionViolatedException.class)` passes for AssumptionViolatedException + +Tests annotated with `@test(expected = AssumptionViolatedException.class)` +which throw AssumptionViolatedException had been marked as skipped. Now the are marked as successful tests. + + +# JUnit 3 Changes + +### [Pull request #1227:](https://github.com/junit-team/junit/pull/1227) Behave better if the `SecurityManager` denies access to `junit.properties` + +Previously, running tests with a `SecurityManager` would cause the test runner itself to throw an `AccessControlException` if the security policy didn't want it reading from `~/junit.properties`. This will now be treated the same as if the file does not exist. + +# Misc + +### [Pull request #1571:](https://github.com/junit-team/junit4/pull/1571) Set "junit" as "Automatic-Module-Name" + +For existing releases of JUnit the `Automatic-Module-Name` was derived from the name of the jar. In most cases it is already the name "junit". JUnit 4.13 explicitly sets the module name to "junit" so that it is independent from the jar's name. + + +### [Pull request #1028:](https://github.com/junit-team/junit4/pull/1028) Trim stack trace + +JUnit's command-line runner (`JUnitCore`) prints smaller stack traces. It skips all stack trace elements that come before the test method so that it starts at the test method. E.g. the output for the example from [Getting started](https://github.com/junit-team/junit4/wiki/Getting-started) page is now + + .E + Time: 0,006 + There was 1 failure: + 1) evaluatesExpression(CalculatorTest) + java.lang.AssertionError: expected:<6> but was:<-6> + at org.junit.Assert.fail(Assert.java:89) + at org.junit.Assert.failNotEquals(Assert.java:835) + at org.junit.Assert.assertEquals(Assert.java:647) + at org.junit.Assert.assertEquals(Assert.java:633) + at CalculatorTest.evaluatesExpression(CalculatorTest.java:9) + + FAILURES!!! + Tests run: 1, Failures: 1 + + +### [Pull request #1403:](https://github.com/junit-team/junit4/pull/1403) Restore CategoryFilter constructor + +The constructor `CategoryFilter(Class includedCategory, Class excludedCategory)` has been removed in JUnit 4.12. It is now available again. + + +### [Pull request #1530:](https://github.com/junit-team/junit4/pull/1530) Add Result#getAssumptionFailureCount + +Add method `getAssumptionFailureCount()` to `Result` which returns the number of assumption failures. + +### [Pull request #1292:](https://github.com/junit-team/junit4/pull/1292) Fix ResultMatchers#hasFailureContaining + +`ResultMatchers.hasFailureContaining()` should return `false` when the given `PrintableResult` has no failures. + +### [Pull request #1380:](https://github.com/junit-team/junit4/pull/1380) Fix Assume#assumeNotNull + +`Assume.assumeNotNull` should throw AssumptionViolatedException when called with a `null` array. + +### [Pull request #1557:](https://github.com/junit-team/junit4/pull/1380) MaxCore always closes stream of history file + +MaxCore didn't close the output stream of the history file when write failed. Now it does. + +### Signing + +The 4.13 release is signed with a new key (id 5EC61B51): +https://github.com/junit-team/junit4/blob/8c0df64ff17fead54c304a8b189da839084925c2/KEYS diff --git a/doc/ReleaseNotes4.4.html b/doc/ReleaseNotes4.4.html index 3736b468b820..383d7b504038 100644 --- a/doc/ReleaseNotes4.4.html +++ b/doc/ReleaseNotes4.4.html @@ -48,7 +48,7 @@

Summary of Changes in version 4.4

assertThat

-

Two years ago, Joe Walnes built a new assertion mechanism on top of what was +

Two years ago, Joe Walnes built a new assertion mechanism on top of what was then JMock 1. The method name was assertThat, and the syntax looked like this:

assertThat(x, is(3));
@@ -84,7 +84,7 @@ 

assertThat

  • Custom Matchers. By implementing the Matcher interface yourself, you can get all of the above benefits for your own custom assertions.

  • -
  • For a more thorough description of these points, see Joe Walnes's +

  • For a more thorough description of these points, see Joe Walnes's original post.

  • diff --git a/doc/ReleaseNotes4.4.md b/doc/ReleaseNotes4.4.md index bc1d54b9b3b0..2be5e49bd01f 100644 --- a/doc/ReleaseNotes4.4.md +++ b/doc/ReleaseNotes4.4.md @@ -65,7 +65,7 @@ past, and how we can make them easier. Two years ago, Joe Walnes built a [new assertion mechanism][walnes] on top of what was then [JMock 1][]. The method name was `assertThat`, and the syntax looked like this: -[walnes]: http://joe.truemesh.com/blog/000511.html +[walnes]: http://joewalnes.com/2005/05/13/flexible-junit-assertions-with-assertthat/ [JMock 1]: http://www.jmock.org/download.html ```java diff --git a/doc/ReleaseNotes4.5.html b/doc/ReleaseNotes4.5.html index 643a2e04c8a0..d6549aa5badc 100644 --- a/doc/ReleaseNotes4.5.html +++ b/doc/ReleaseNotes4.5.html @@ -97,7 +97,7 @@

    Summary of Changes in version 4.4

    assertThat

    -

    Two years ago, Joe Walnes built a new assertion mechanism on top of what was +

    Two years ago, Joe Walnes built a new assertion mechanism on top of what was then JMock 1. The method name was assertThat, and the syntax looked like this:

    assertThat(x, is(3));
    @@ -133,7 +133,7 @@ 

    assertThat

  • Custom Matchers. By implementing the Matcher interface yourself, you can get all of the above benefits for your own custom assertions.

  • -
  • For a more thorough description of these points, see Joe Walnes's +

  • For a more thorough description of these points, see Joe Walnes's original post.:

  • diff --git a/doc/ReleaseNotes4.7.md b/doc/ReleaseNotes4.7.md index d33a501e2e5e..1f9607074106 100644 --- a/doc/ReleaseNotes4.7.md +++ b/doc/ReleaseNotes4.7.md @@ -38,12 +38,12 @@ public static class UsesExternalResource { @Override protected void before() throws Throwable { myServer.connect(); - }; + } @Override protected void after() { myServer.disconnect(); - }; + } }; @Test public void testFoo() { diff --git a/doc/ReleaseNotes4.9.md b/doc/ReleaseNotes4.9.md index 5e62cea11d0a..7d8d75880c48 100644 --- a/doc/ReleaseNotes4.9.md +++ b/doc/ReleaseNotes4.9.md @@ -23,12 +23,12 @@ public class UsesExternalResource { @Override protected void before() throws Throwable { myServer.connect(); - }; + } @Override protected void after() { myServer.disconnect(); - }; + } }; } ``` diff --git a/doc/building-junit.txt b/doc/building-junit.txt index 325a27ed8c2b..91169e3427b3 100644 --- a/doc/building-junit.txt +++ b/doc/building-junit.txt @@ -4,8 +4,8 @@ Steps to build junit: - Write release notes - Not too tedious: - Push to github (junit-team) - - Run the mvn clean install - - If not done, update src/main/config/settings.xml in /private/.../settings.xml on CloudBees' webdav share. + - Run the ./mvnw clean install + - If not done, update $M2_HOME/settings.xml - If not done, copy GnuPG keys in to ${gpg.homedir}. See settings.xml. - Perform Maven deployment of a snapshot or release version in Jenkins Remember that the version specified in the pom.xml indicates the version @@ -14,11 +14,11 @@ Steps to build junit: - (to deploy gpg signed snapshot version) - $ mvn -Pjunit-release clean deploy + $ ./mvnw -Pjunit-release clean deploy - (to cut a release of the current targetted version) - $ mvn -B release:prepare release:perform + $ ./mvnw -B release:prepare release:perform This will result in the current pom.xml version having -SNAPSHOT removed and the release cut from that version. The version will then be incremented @@ -26,7 +26,7 @@ Steps to build junit: - (to cut a release of while changing the version from the current target) - $ mvn -B -DreleaseVersion=5.0 release:prepare release:perform + $ ./mvnw -B -DreleaseVersion=5.0 release:prepare release:perform This will ignore the current version in the pom.xml, set it to 5.0 and the release cut from that 5.0 version. Then 5.0 will be incremented (to 5.1) @@ -35,12 +35,12 @@ Steps to build junit: - (to deploy specified release version and next target release in non-interactive mode -B) An example with the next development version and deploying release version: - $ mvn -B -DreleaseVersion=4.12 -DdevelopmentVersion=4.13-SNAPSHOT release:prepare release:perform + $ ./mvnw -B -DreleaseVersion=4.12 -DdevelopmentVersion=4.13-SNAPSHOT release:prepare release:perform - If you are not an official release manager, and you want to cut a release of JUnit for use within your organization, use the following command - $ mvn -DpushChanges=false -DlocalCheckout '-Darguments=-Dgpg.skip=true -DaltDeploymentRepository=my-company-repo-id::default::my-company-repo-url' -B -DreleaseVersion=4.12-mycompany-1 release:prepare release:perform + $ ./mvnw -DpushChanges=false -DlocalCheckout '-Darguments=-Dgpg.skip=true -DaltDeploymentRepository=my-company-repo-id::default::my-company-repo-url' -B -DreleaseVersion=4.12-mycompany-1 release:prepare release:perform where - my-company-repo-id is the of your company's entry in your diff --git a/doc/homepage.html b/doc/homepage.html deleted file mode 100644 index 69c6248102e4..000000000000 --- a/doc/homepage.html +++ /dev/null @@ -1,115 +0,0 @@ - - -JUnit - - - - -

    JUnit

    -

    JUnit is a simple framework to write repeatable tests. It is an instance of -the xUnit architecture for unit testing frameworks. -

    - -

    -Getting Started

    - -To get started with unit testing and JUnit read the article: -JUnit Cookbook. -
    This article describes basic test writing using JUnit 4. -

    You find additional samples in the org.junit.samples package: -

      -
    • -SimpleTest.java - some simple test cases
    • - -
    • -VectorTest.java - test cases for java.util.Vector
    • -
    -

    JUnit 4.x only comes with a textual TestRunner. For graphical feedback, -most major IDE's support -JUnit 4. If necessary, you can run JUnit 4 tests in a JUnit 3 -environment by adding the following method to each test class: -

    -public static Test suite() {
    -   return new JUnit4TestAdapter(ThisClass.class);
    -} 
    -
    -
    - -

    -Documentation

    - -
    JUnit Cookbook -
        A cookbook for implementing tests with JUnit. -
    Javadoc -
        API documentation generated with javadoc. -
    Frequently asked questions -
        Some frequently asked questions about using JUnit. - -
    Release notes -
        Latest JUnit release notes -
    License -
        The terms of the common public license used for JUnit.
    -
    -The following documents still describe JUnit 3.8. -
    -
    The JUnit 3.8 version of this homepage -
    Test Infected - Programmers -Love Writing Tests -
        An article demonstrating the development process -with JUnit. - -
    JUnit - A cooks tour -
    - -

    JUnit Related Projects/Sites

    -
      -
    • junit.org - a site for software - developers using JUnit. It provides instructions for how to integrate JUnit - with development tools like JBuilder and VisualAge/Java. As well as articles - about and extensions to JUnit.
    • -
    • XProgramming.com - - various implementations of the xUnit testing framework architecture. 
    • - -
    -

    Mailing Lists

    -There are three junit mailing lists: - - -

    Get Involved

    - JUnit celebrates programmers testing their own software. As a result - bugs, patches, and feature requests which include JUnit TestCases have a - better - chance of being addressed than those without. - -
    - JUnit is forged on - Sourceforge please use the tools provided for your submissions. - -
    - JUnit source code is now hosted on GitHub. - -
    - -hosted by SourceForge Logo - - - diff --git a/doc/index.htm b/doc/index.htm deleted file mode 100644 index dd19ff3383be..000000000000 --- a/doc/index.htm +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - JUnit Documentation - - - -

    -JUnit Documentation

    - -

    -Kent Beck, Erich Gamma, David Saff

    - -
    -We have just begun documenting the new JUnit 4 architecture. The cookbook has already been updated. You can find the javadoc here. -The JUnit home page is here. -
    - - diff --git a/doc/testinfected/testing.htm b/doc/testinfected/testing.htm index d11c11cd98d5..c5721e752b8d 100644 --- a/doc/testinfected/testing.htm +++ b/doc/testinfected/testing.htm @@ -181,14 +181,14 @@

    result report. The value a string representation created by the toString converter method. There are -other asertXXXX variants not discussed here. +other assertXXXX variants not discussed here.

    Now that we have implemented two test cases we notice some code duplication for setting-up the tests. It would be nice to reuse some of this test set-up code. In other words, we would like to have a common fixture for running the tests. With JUnit you can do so by storing the fixture's objects in instance variables of your TestCase -subclass and initialize them by overridding +subclass and initialize them by overriding the setUp method. The symmetric operation to setUp is tearDown which you can override to clean up the test fixture at the end of a test. Each test runs in its own fixture and JUnit calls setUp and tearDown for each test @@ -435,7 +435,7 @@

    public IMoney addMoneyBag(MoneyBag s) {     return s.addMoney(this); } -Here is the implemenation in MoneyBag which assumes additional constructors +Here is the implementation in MoneyBag which assumes additional constructors to create a MoneyBag from a Money and a MoneyBag and from two MoneyBags.
    public IMoney addMoney(Money m) {
         return new MoneyBag(m, this);
    diff --git a/mvnw b/mvnw
    new file mode 100755
    index 000000000000..e96ccd5fbbb6
    --- /dev/null
    +++ b/mvnw
    @@ -0,0 +1,227 @@
    +#!/bin/sh
    +# ----------------------------------------------------------------------------
    +# Licensed to the Apache Software Foundation (ASF) under one
    +# or more contributor license agreements.  See the NOTICE file
    +# distributed with this work for additional information
    +# regarding copyright ownership.  The ASF licenses this file
    +# to you under the Apache License, Version 2.0 (the
    +# "License"); you may not use this file except in compliance
    +# with the License.  You may obtain a copy of the License at
    +#
    +#    http://www.apache.org/licenses/LICENSE-2.0
    +#
    +# Unless required by applicable law or agreed to in writing,
    +# software distributed under the License is distributed on an
    +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    +# KIND, either express or implied.  See the License for the
    +# specific language governing permissions and limitations
    +# under the License.
    +# ----------------------------------------------------------------------------
    +
    +# ----------------------------------------------------------------------------
    +# Maven2 Start Up Batch script
    +#
    +# Required ENV vars:
    +# ------------------
    +#   JAVA_HOME - location of a JDK home dir
    +#
    +# Optional ENV vars
    +# -----------------
    +#   M2_HOME - location of maven2's installed home dir
    +#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
    +#     e.g. to debug Maven itself, use
    +#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
    +#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
    +# ----------------------------------------------------------------------------
    +
    +if [ -z "$MAVEN_SKIP_RC" ] ; then
    +
    +  if [ -f /etc/mavenrc ] ; then
    +    . /etc/mavenrc
    +  fi
    +
    +  if [ -f "$HOME/.mavenrc" ] ; then
    +    . "$HOME/.mavenrc"
    +  fi
    +
    +fi
    +
    +# OS specific support.  $var _must_ be set to either true or false.
    +cygwin=false;
    +darwin=false;
    +mingw=false
    +case "`uname`" in
    +  CYGWIN*) cygwin=true ;;
    +  MINGW*) mingw=true;;
    +  Darwin*) darwin=true
    +    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
    +    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
    +    if [ -z "$JAVA_HOME" ]; then
    +      if [ -x "/usr/libexec/java_home" ]; then
    +        export JAVA_HOME="`/usr/libexec/java_home`"
    +      else
    +        export JAVA_HOME="/Library/Java/Home"
    +      fi
    +    fi
    +    ;;
    +esac
    +
    +if [ -z "$JAVA_HOME" ] ; then
    +  if [ -r /etc/gentoo-release ] ; then
    +    JAVA_HOME=`java-config --jre-home`
    +  fi
    +fi
    +
    +if [ -z "$M2_HOME" ] ; then
    +  ## resolve links - $0 may be a link to maven's home
    +  PRG="$0"
    +
    +  # need this for relative symlinks
    +  while [ -h "$PRG" ] ; do
    +    ls=`ls -ld "$PRG"`
    +    link=`expr "$ls" : '.*-> \(.*\)$'`
    +    if expr "$link" : '/.*' > /dev/null; then
    +      PRG="$link"
    +    else
    +      PRG="`dirname "$PRG"`/$link"
    +    fi
    +  done
    +
    +  saveddir=`pwd`
    +
    +  M2_HOME=`dirname "$PRG"`/..
    +
    +  # make it fully qualified
    +  M2_HOME=`cd "$M2_HOME" && pwd`
    +
    +  cd "$saveddir"
    +  # echo Using m2 at $M2_HOME
    +fi
    +
    +# For Cygwin, ensure paths are in UNIX format before anything is touched
    +if $cygwin ; then
    +  [ -n "$M2_HOME" ] &&
    +    M2_HOME=`cygpath --unix "$M2_HOME"`
    +  [ -n "$JAVA_HOME" ] &&
    +    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
    +  [ -n "$CLASSPATH" ] &&
    +    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
    +fi
    +
    +# For Mingw, ensure paths are in UNIX format before anything is touched
    +if $mingw ; then
    +  [ -n "$M2_HOME" ] &&
    +    M2_HOME="`(cd "$M2_HOME"; pwd)`"
    +  [ -n "$JAVA_HOME" ] &&
    +    JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
    +  # TODO classpath?
    +fi
    +
    +if [ -z "$JAVA_HOME" ]; then
    +  javaExecutable="`which javac`"
    +  if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
    +    # readlink(1) is not available as standard on Solaris 10.
    +    readLink=`which readlink`
    +    if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
    +      if $darwin ; then
    +        javaHome="`dirname \"$javaExecutable\"`"
    +        javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
    +      else
    +        javaExecutable="`readlink -f \"$javaExecutable\"`"
    +      fi
    +      javaHome="`dirname \"$javaExecutable\"`"
    +      javaHome=`expr "$javaHome" : '\(.*\)/bin'`
    +      JAVA_HOME="$javaHome"
    +      export JAVA_HOME
    +    fi
    +  fi
    +fi
    +
    +if [ -z "$JAVACMD" ] ; then
    +  if [ -n "$JAVA_HOME"  ] ; then
    +    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
    +      # IBM's JDK on AIX uses strange locations for the executables
    +      JAVACMD="$JAVA_HOME/jre/sh/java"
    +    else
    +      JAVACMD="$JAVA_HOME/bin/java"
    +    fi
    +  else
    +    JAVACMD="`which java`"
    +  fi
    +fi
    +
    +if [ ! -x "$JAVACMD" ] ; then
    +  echo "Error: JAVA_HOME is not defined correctly." >&2
    +  echo "  We cannot execute $JAVACMD" >&2
    +  exit 1
    +fi
    +
    +if [ -z "$JAVA_HOME" ] ; then
    +  echo "Warning: JAVA_HOME environment variable is not set."
    +fi
    +
    +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
    +
    +# traverses directory structure from process work directory to filesystem root
    +# first directory with .mvn subdirectory is considered project base directory
    +find_maven_basedir() {
    +
    +  if [ -z "$1" ]
    +  then
    +    echo "Path not specified to find_maven_basedir"
    +    return 1
    +  fi
    +
    +  basedir="$1"
    +  wdir="$1"
    +  while [ "$wdir" != '/' ] ; do
    +    if [ -d "$wdir"/.mvn ] ; then
    +      basedir=$wdir
    +      break
    +    fi
    +    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
    +    if [ -d "${wdir}" ]; then
    +      wdir=`cd "$wdir/.."; pwd`
    +    fi
    +    # end of workaround
    +  done
    +  echo "${basedir}"
    +}
    +
    +# concatenates all lines of a file
    +concat_lines() {
    +  if [ -f "$1" ]; then
    +    echo "$(tr -s '\n' ' ' < "$1")"
    +  fi
    +}
    +
    +BASE_DIR=`find_maven_basedir "$(pwd)"`
    +if [ -z "$BASE_DIR" ]; then
    +  exit 1;
    +fi
    +
    +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
    +if [ "$MVNW_VERBOSE" = true ]; then
    +  echo $MAVEN_PROJECTBASEDIR
    +fi
    +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
    +
    +# For Cygwin, switch paths to Windows format before running java
    +if $cygwin; then
    +  [ -n "$M2_HOME" ] &&
    +    M2_HOME=`cygpath --path --windows "$M2_HOME"`
    +  [ -n "$JAVA_HOME" ] &&
    +    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
    +  [ -n "$CLASSPATH" ] &&
    +    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
    +  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
    +    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
    +fi
    +
    +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
    +
    +exec "$JAVACMD" \
    +  $MAVEN_OPTS \
    +  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
    +  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
    +  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
    diff --git a/mvnw.cmd b/mvnw.cmd
    new file mode 100755
    index 000000000000..019bd74d766e
    --- /dev/null
    +++ b/mvnw.cmd
    @@ -0,0 +1,143 @@
    +@REM ----------------------------------------------------------------------------
    +@REM Licensed to the Apache Software Foundation (ASF) under one
    +@REM or more contributor license agreements.  See the NOTICE file
    +@REM distributed with this work for additional information
    +@REM regarding copyright ownership.  The ASF licenses this file
    +@REM to you under the Apache License, Version 2.0 (the
    +@REM "License"); you may not use this file except in compliance
    +@REM with the License.  You may obtain a copy of the License at
    +@REM
    +@REM    http://www.apache.org/licenses/LICENSE-2.0
    +@REM
    +@REM Unless required by applicable law or agreed to in writing,
    +@REM software distributed under the License is distributed on an
    +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    +@REM KIND, either express or implied.  See the License for the
    +@REM specific language governing permissions and limitations
    +@REM under the License.
    +@REM ----------------------------------------------------------------------------
    +
    +@REM ----------------------------------------------------------------------------
    +@REM Maven2 Start Up Batch script
    +@REM
    +@REM Required ENV vars:
    +@REM JAVA_HOME - location of a JDK home dir
    +@REM
    +@REM Optional ENV vars
    +@REM M2_HOME - location of maven2's installed home dir
    +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
    +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
    +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
    +@REM     e.g. to debug Maven itself, use
    +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
    +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
    +@REM ----------------------------------------------------------------------------
    +
    +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
    +@echo off
    +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
    +@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
    +
    +@REM set %HOME% to equivalent of $HOME
    +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
    +
    +@REM Execute a user defined script before this one
    +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
    +@REM check for pre script, once with legacy .bat ending and once with .cmd ending
    +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
    +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
    +:skipRcPre
    +
    +@setlocal
    +
    +set ERROR_CODE=0
    +
    +@REM To isolate internal variables from possible post scripts, we use another setlocal
    +@setlocal
    +
    +@REM ==== START VALIDATION ====
    +if not "%JAVA_HOME%" == "" goto OkJHome
    +
    +echo.
    +echo Error: JAVA_HOME not found in your environment. >&2
    +echo Please set the JAVA_HOME variable in your environment to match the >&2
    +echo location of your Java installation. >&2
    +echo.
    +goto error
    +
    +:OkJHome
    +if exist "%JAVA_HOME%\bin\java.exe" goto init
    +
    +echo.
    +echo Error: JAVA_HOME is set to an invalid directory. >&2
    +echo JAVA_HOME = "%JAVA_HOME%" >&2
    +echo Please set the JAVA_HOME variable in your environment to match the >&2
    +echo location of your Java installation. >&2
    +echo.
    +goto error
    +
    +@REM ==== END VALIDATION ====
    +
    +:init
    +
    +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
    +@REM Fallback to current working directory if not found.
    +
    +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
    +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
    +
    +set EXEC_DIR=%CD%
    +set WDIR=%EXEC_DIR%
    +:findBaseDir
    +IF EXIST "%WDIR%"\.mvn goto baseDirFound
    +cd ..
    +IF "%WDIR%"=="%CD%" goto baseDirNotFound
    +set WDIR=%CD%
    +goto findBaseDir
    +
    +:baseDirFound
    +set MAVEN_PROJECTBASEDIR=%WDIR%
    +cd "%EXEC_DIR%"
    +goto endDetectBaseDir
    +
    +:baseDirNotFound
    +set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
    +cd "%EXEC_DIR%"
    +
    +:endDetectBaseDir
    +
    +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
    +
    +@setlocal EnableExtensions EnableDelayedExpansion
    +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
    +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
    +
    +:endReadAdditionalConfig
    +
    +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
    +
    +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
    +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
    +
    +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
    +if ERRORLEVEL 1 goto error
    +goto end
    +
    +:error
    +set ERROR_CODE=1
    +
    +:end
    +@endlocal & set ERROR_CODE=%ERROR_CODE%
    +
    +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
    +@REM check for post script, once with legacy .bat ending and once with .cmd ending
    +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
    +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
    +:skipRcPost
    +
    +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
    +if "%MAVEN_BATCH_PAUSE%" == "on" pause
    +
    +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
    +
    +exit /B %ERROR_CODE%
    diff --git a/pom.xml b/pom.xml
    index 799cb9bed88c..428715884b4e 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -4,7 +4,7 @@
     
         junit
         junit
    -    4.12
    +    4.13.1
     
         JUnit
         JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.
    @@ -48,42 +48,34 @@
             
                 JUnit contributors
                 JUnit
    -            junit@yahoogroups.com
    -            https://github.com/junit-team/junit/graphs/contributors
    +            team@junit.org
    +            https://github.com/junit-team/junit4/graphs/contributors
                 
                     developers
                 
             
         
     
    -    
    -        
    -            JUnit Mailing List
    -            junit@yahoogroups.com
    -            https://groups.yahoo.com/neo/groups/junit/info
    -        
    -    
    -
         
             3.0.4
         
     
         
    -        scm:git:git://github.com/junit-team/junit.git
    -        scm:git:git@github.com:junit-team/junit.git
    -        http://github.com/junit-team/junit/tree/master
    -      r4.12
    +        scm:git:git://github.com/junit-team/junit4.git
    +        scm:git:git@github.com:junit-team/junit4.git
    +        https://github.com/junit-team/junit4
    +      r4.13.1
       
         
             github
    -        https://github.com/junit-team/junit/issues
    +        https://github.com/junit-team/junit4/issues
         
         
    -        jenkins
    -        https://junit.ci.cloudbees.com/
    +        travis
    +        https://travis-ci.org/junit-team/junit4
         
         
    -        https://github.com/junit-team/junit/wiki/Download-and-Install
    +        https://github.com/junit-team/junit4/wiki/Download-and-Install
             
                 junit-snapshot-repo
                 Nexus Snapshot Repository
    @@ -96,12 +88,14 @@
             
             
                 junit.github.io
    -            gitsite:git@github.com/junit-team/junit.git
    +            gitsite:git@github.com/junit-team/junit4.git
             
         
     
         
             1.5
    +        2.19.1
    +        1.3
             ISO-8859-1
             
             67893CC4
    @@ -111,7 +105,14 @@
             
                 org.hamcrest
                 hamcrest-core
    -            1.3
    +            ${hamcrestVersion}
    +        
    +
    +        
    +            org.hamcrest
    +            hamcrest-library
    +            ${hamcrestVersion}
    +            test
             
         
     
    @@ -146,7 +147,7 @@
                     the project, requires only release versions of dependencies of other artifacts.
                     -->
                     maven-enforcer-plugin
    -                1.3.1
    +                1.4
                     
                         
                             enforce-versions
    @@ -199,8 +200,8 @@
                     
                     
                         false
    -                    src/main/java/junit/runner/Version.java.template
    -                    src/main/java/junit/runner/Version.java
    +                    ${project.build.sourceDirectory}/junit/runner/Version.java.template
    +                    ${project.build.sourceDirectory}/junit/runner/Version.java
                         false
                         @version@
                         ${project.version}
    @@ -211,7 +212,7 @@
                     java compiler plugin forked in extra process
                     -->
                     maven-compiler-plugin
    -                3.1
    +                3.3
                     
                         ${project.build.sourceEncoding}
                         ${jdkVersion}
    @@ -232,7 +233,7 @@
                 
                     org.codehaus.mojo
                     animal-sniffer-maven-plugin
    -                1.11
    +                1.14
                     
                         
                             signature-check
    @@ -256,12 +257,19 @@
                     our junit suite "AllTests" after the sources are compiled.
                     -->
                     maven-surefire-plugin
    -                2.17
    +                ${surefireVersion}
                     
                         org/junit/tests/AllTests.java
                         true
                         false
                     
    +                
    +                    
    +                        org.apache.maven.surefire
    +                        surefire-junit47
    +                        ${surefireVersion}
    +                    
    +                
                 
                 
                     
                     maven-source-plugin
    -                2.2.1
    +                2.4
                 
                 
                     
                     maven-javadoc-plugin
    -                2.9.1
    +                2.10.3
                     
                         ${basedir}/src/main/javadoc/stylesheet.css
                         protected
    @@ -287,7 +295,7 @@
                         false
                         true
                         true
    -                    false
    +                    true
                         JUnit API
                         UTF-8
                         en
    @@ -298,7 +306,7 @@
                                 http://docs.oracle.com/javase/${jdkVersion}.0/docs/api/
                             
                         
    -                    junit.*,*.internal.*
    +                    *.internal.*
                         true
                         32m
                         128m
    @@ -311,7 +319,7 @@
                 
                 
                     maven-release-plugin
    -                2.5
    +                2.5.2
                     
                         forked-path
                         false
    @@ -321,7 +329,7 @@
                 
                 
                     maven-site-plugin
    -                3.3
    +                3.4
                     
                         
                             com.github.stephenc.wagon
    @@ -337,16 +345,35 @@
                 
                 
                     maven-jar-plugin
    -                2.4
    +                2.6
                     
                         
                             false
                             
                                 true
                             
    +                        
    +                            junit
    +                                                
                         
                     
                 
    +            
    +                maven-clean-plugin
    +                2.6.1
    +            
    +            
    +                maven-deploy-plugin
    +                2.8.2
    +            
    +            
    +                maven-install-plugin
    +                2.5.2
    +            
    +            
    +                maven-resources-plugin
    +                2.7
    +            
             
         
     
    @@ -354,7 +381,7 @@
             
                 
                     maven-project-info-reports-plugin
    -                2.7
    +                2.8
                     
                         false
                         
    @@ -381,7 +408,7 @@
                 
                 
                     maven-javadoc-plugin
    -                2.9.1
    +                2.10.3
                     
                         javadoc/latest
                         ${basedir}/src/main/javadoc/stylesheet.css
    @@ -391,7 +418,7 @@
                         false
                         true
                         true
    -                    false
    +                    true
                         JUnit API
                         UTF-8
                         en
    @@ -440,7 +467,7 @@
                             (–– stands for double dash)
                             -->
                             maven-gpg-plugin
    -                        1.5
    +                        1.6
                             
                                 
                                     gpg-sign
    @@ -527,25 +554,34 @@
                 
             
             
    -            fast-tests
    +            java9
    +            
    +                [1.9,)
    +            
    +            
    +                
    +                1.6
    +            
                 
                     
                         
    -                        maven-surefire-plugin
    +                        maven-javadoc-plugin
                             
    -                            classes
    -                            2
    +                            1.6
                             
    -                        
    -                            
    -                                org.apache.maven.surefire
    -                                surefire-junit47
    -                                2.17
    -                            
    -                        
                         
                     
                 
    +            
    +                
    +                    
    +                        maven-javadoc-plugin
    +                        
    +                            1.6
    +                        
    +                    
    +                
    +            
             
         
     
    diff --git a/src/changes/changes.xml b/src/changes/changes.xml
    deleted file mode 100644
    index e2631b19f28b..000000000000
    --- a/src/changes/changes.xml
    +++ /dev/null
    @@ -1,38 +0,0 @@
    -
    -  
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -
    -    
    -    
    -  
    -
    \ No newline at end of file
    diff --git a/src/main/java/junit/extensions/TestDecorator.java b/src/main/java/junit/extensions/TestDecorator.java
    index 2b74f3075dc7..a3c5e08c548e 100644
    --- a/src/main/java/junit/extensions/TestDecorator.java
    +++ b/src/main/java/junit/extensions/TestDecorator.java
    @@ -9,6 +9,7 @@
      * test decorators. Test decorator subclasses can be introduced to add behaviour
      * before or after a test is run.
      */
    +@SuppressWarnings("deprecation")
     public class TestDecorator extends Assert implements Test {
         protected Test fTest;
     
    diff --git a/src/main/java/junit/framework/Assert.java b/src/main/java/junit/framework/Assert.java
    index 663461c7ab79..d10cdb4247b6 100644
    --- a/src/main/java/junit/framework/Assert.java
    +++ b/src/main/java/junit/framework/Assert.java
    @@ -117,7 +117,7 @@ static public void assertEquals(String message, double expected, double actual,
                 return;
             }
             if (!(Math.abs(expected - actual) <= delta)) {
    -            failNotEquals(message, new Double(expected), new Double(actual));
    +            failNotEquals(message, Double.valueOf(expected), Double.valueOf(actual));
             }
         }
     
    @@ -139,7 +139,7 @@ static public void assertEquals(String message, float expected, float actual, fl
                 return;
             }
             if (!(Math.abs(expected - actual) <= delta)) {
    -            failNotEquals(message, new Float(expected), new Float(actual));
    +            failNotEquals(message, Float.valueOf(expected), Float.valueOf(actual));
             }
         }
     
    diff --git a/src/main/java/junit/framework/ComparisonCompactor.java b/src/main/java/junit/framework/ComparisonCompactor.java
    index fa20a8e3a075..81ddd5bda514 100644
    --- a/src/main/java/junit/framework/ComparisonCompactor.java
    +++ b/src/main/java/junit/framework/ComparisonCompactor.java
    @@ -18,6 +18,7 @@ public ComparisonCompactor(int contextLength, String expected, String actual) {
             fActual = actual;
         }
     
    +    @SuppressWarnings("deprecation")
         public String compact(String message) {
             if (fExpected == null || fActual == null || areStringsEqual()) {
                 return Assert.format(message, fExpected, fActual);
    diff --git a/src/main/java/junit/framework/JUnit4TestAdapter.java b/src/main/java/junit/framework/JUnit4TestAdapter.java
    index cbb66dbb064c..9d32031e4eba 100644
    --- a/src/main/java/junit/framework/JUnit4TestAdapter.java
    +++ b/src/main/java/junit/framework/JUnit4TestAdapter.java
    @@ -9,11 +9,23 @@
     import org.junit.runner.Runner;
     import org.junit.runner.manipulation.Filter;
     import org.junit.runner.manipulation.Filterable;
    +import org.junit.runner.manipulation.Orderer;
    +import org.junit.runner.manipulation.InvalidOrderingException;
     import org.junit.runner.manipulation.NoTestsRemainException;
    -import org.junit.runner.manipulation.Sortable;
    +import org.junit.runner.manipulation.Orderable;
     import org.junit.runner.manipulation.Sorter;
     
    -public class JUnit4TestAdapter implements Test, Filterable, Sortable, Describable {
    +/**
    + * The JUnit4TestAdapter enables running JUnit-4-style tests using a JUnit-3-style test runner.
    + *
    + * 

    To use it, add the following to a test class: + *

    +      public static Test suite() {
    +        return new JUnit4TestAdapter(YourJUnit4TestClass.class);
    +      }
    +
    + */ +public class JUnit4TestAdapter implements Test, Filterable, Orderable, Describable { private final Class fNewTestClass; private final Runner fRunner; @@ -83,4 +95,13 @@ public void filter(Filter filter) throws NoTestsRemainException { public void sort(Sorter sorter) { sorter.apply(fRunner); } + + /** + * {@inheritDoc} + * + * @since 4.13 + */ + public void order(Orderer orderer) throws InvalidOrderingException { + orderer.apply(fRunner); + } } \ No newline at end of file diff --git a/src/main/java/junit/framework/Protectable.java b/src/main/java/junit/framework/Protectable.java index 9f30b102da33..c5ceb16ae038 100644 --- a/src/main/java/junit/framework/Protectable.java +++ b/src/main/java/junit/framework/Protectable.java @@ -8,7 +8,7 @@ public interface Protectable { /** - * Run the the following method protected. + * Run the following method protected. */ public abstract void protect() throws Throwable; -} \ No newline at end of file +} diff --git a/src/main/java/junit/framework/TestCase.java b/src/main/java/junit/framework/TestCase.java index b89ce71a1009..e474a6493664 100644 --- a/src/main/java/junit/framework/TestCase.java +++ b/src/main/java/junit/framework/TestCase.java @@ -73,6 +73,7 @@ * @see TestResult * @see TestSuite */ +@SuppressWarnings("deprecation") public abstract class TestCase extends Assert implements Test { /** * the name of the test case @@ -102,7 +103,7 @@ public int countTestCases() { } /** - * Creates a default TestResult object + * Creates a default TestResult object. * * @see TestResult */ @@ -187,7 +188,6 @@ protected void runTest() throws Throwable { * Asserts that a condition is true. If it isn't it throws * an AssertionFailedError with the given message. */ - @SuppressWarnings("deprecation") public static void assertTrue(String message, boolean condition) { Assert.assertTrue(message, condition); } @@ -196,7 +196,6 @@ public static void assertTrue(String message, boolean condition) { * Asserts that a condition is true. If it isn't it throws * an AssertionFailedError. */ - @SuppressWarnings("deprecation") public static void assertTrue(boolean condition) { Assert.assertTrue(condition); } @@ -205,7 +204,6 @@ public static void assertTrue(boolean condition) { * Asserts that a condition is false. If it isn't it throws * an AssertionFailedError with the given message. */ - @SuppressWarnings("deprecation") public static void assertFalse(String message, boolean condition) { Assert.assertFalse(message, condition); } @@ -214,7 +212,6 @@ public static void assertFalse(String message, boolean condition) { * Asserts that a condition is false. If it isn't it throws * an AssertionFailedError. */ - @SuppressWarnings("deprecation") public static void assertFalse(boolean condition) { Assert.assertFalse(condition); } @@ -222,7 +219,6 @@ public static void assertFalse(boolean condition) { /** * Fails a test with the given message. */ - @SuppressWarnings("deprecation") public static void fail(String message) { Assert.fail(message); } @@ -230,7 +226,6 @@ public static void fail(String message) { /** * Fails a test with no message. */ - @SuppressWarnings("deprecation") public static void fail() { Assert.fail(); } @@ -239,7 +234,6 @@ public static void fail() { * Asserts that two objects are equal. If they are not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, Object expected, Object actual) { Assert.assertEquals(message, expected, actual); } @@ -248,7 +242,6 @@ public static void assertEquals(String message, Object expected, Object actual) * Asserts that two objects are equal. If they are not * an AssertionFailedError is thrown. */ - @SuppressWarnings("deprecation") public static void assertEquals(Object expected, Object actual) { Assert.assertEquals(expected, actual); } @@ -256,7 +249,6 @@ public static void assertEquals(Object expected, Object actual) { /** * Asserts that two Strings are equal. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, String expected, String actual) { Assert.assertEquals(message, expected, actual); } @@ -264,7 +256,6 @@ public static void assertEquals(String message, String expected, String actual) /** * Asserts that two Strings are equal. */ - @SuppressWarnings("deprecation") public static void assertEquals(String expected, String actual) { Assert.assertEquals(expected, actual); } @@ -274,7 +265,6 @@ public static void assertEquals(String expected, String actual) { * an AssertionFailedError is thrown with the given message. If the expected * value is infinity then the delta value is ignored. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, double expected, double actual, double delta) { Assert.assertEquals(message, expected, actual, delta); } @@ -283,7 +273,6 @@ public static void assertEquals(String message, double expected, double actual, * Asserts that two doubles are equal concerning a delta. If the expected * value is infinity then the delta value is ignored. */ - @SuppressWarnings("deprecation") public static void assertEquals(double expected, double actual, double delta) { Assert.assertEquals(expected, actual, delta); } @@ -293,7 +282,6 @@ public static void assertEquals(double expected, double actual, double delta) { * are not an AssertionFailedError is thrown with the given message. If the * expected value is infinity then the delta value is ignored. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, float expected, float actual, float delta) { Assert.assertEquals(message, expected, actual, delta); } @@ -302,7 +290,6 @@ public static void assertEquals(String message, float expected, float actual, fl * Asserts that two floats are equal concerning a delta. If the expected * value is infinity then the delta value is ignored. */ - @SuppressWarnings("deprecation") public static void assertEquals(float expected, float actual, float delta) { Assert.assertEquals(expected, actual, delta); } @@ -311,7 +298,6 @@ public static void assertEquals(float expected, float actual, float delta) { * Asserts that two longs are equal. If they are not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, long expected, long actual) { Assert.assertEquals(message, expected, actual); } @@ -319,7 +305,6 @@ public static void assertEquals(String message, long expected, long actual) { /** * Asserts that two longs are equal. */ - @SuppressWarnings("deprecation") public static void assertEquals(long expected, long actual) { Assert.assertEquals(expected, actual); } @@ -328,7 +313,6 @@ public static void assertEquals(long expected, long actual) { * Asserts that two booleans are equal. If they are not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, boolean expected, boolean actual) { Assert.assertEquals(message, expected, actual); } @@ -336,7 +320,6 @@ public static void assertEquals(String message, boolean expected, boolean actual /** * Asserts that two booleans are equal. */ - @SuppressWarnings("deprecation") public static void assertEquals(boolean expected, boolean actual) { Assert.assertEquals(expected, actual); } @@ -345,7 +328,6 @@ public static void assertEquals(boolean expected, boolean actual) { * Asserts that two bytes are equal. If they are not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, byte expected, byte actual) { Assert.assertEquals(message, expected, actual); } @@ -353,7 +335,6 @@ public static void assertEquals(String message, byte expected, byte actual) { /** * Asserts that two bytes are equal. */ - @SuppressWarnings("deprecation") public static void assertEquals(byte expected, byte actual) { Assert.assertEquals(expected, actual); } @@ -362,7 +343,6 @@ public static void assertEquals(byte expected, byte actual) { * Asserts that two chars are equal. If they are not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, char expected, char actual) { Assert.assertEquals(message, expected, actual); } @@ -370,7 +350,6 @@ public static void assertEquals(String message, char expected, char actual) { /** * Asserts that two chars are equal. */ - @SuppressWarnings("deprecation") public static void assertEquals(char expected, char actual) { Assert.assertEquals(expected, actual); } @@ -379,7 +358,6 @@ public static void assertEquals(char expected, char actual) { * Asserts that two shorts are equal. If they are not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, short expected, short actual) { Assert.assertEquals(message, expected, actual); } @@ -387,7 +365,6 @@ public static void assertEquals(String message, short expected, short actual) { /** * Asserts that two shorts are equal. */ - @SuppressWarnings("deprecation") public static void assertEquals(short expected, short actual) { Assert.assertEquals(expected, actual); } @@ -396,7 +373,6 @@ public static void assertEquals(short expected, short actual) { * Asserts that two ints are equal. If they are not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertEquals(String message, int expected, int actual) { Assert.assertEquals(message, expected, actual); } @@ -404,7 +380,6 @@ public static void assertEquals(String message, int expected, int actual) { /** * Asserts that two ints are equal. */ - @SuppressWarnings("deprecation") public static void assertEquals(int expected, int actual) { Assert.assertEquals(expected, actual); } @@ -412,7 +387,6 @@ public static void assertEquals(int expected, int actual) { /** * Asserts that an object isn't null. */ - @SuppressWarnings("deprecation") public static void assertNotNull(Object object) { Assert.assertNotNull(object); } @@ -421,7 +395,6 @@ public static void assertNotNull(Object object) { * Asserts that an object isn't null. If it is * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertNotNull(String message, Object object) { Assert.assertNotNull(message, object); } @@ -433,7 +406,6 @@ public static void assertNotNull(String message, Object object) { * * @param object Object to check or null */ - @SuppressWarnings("deprecation") public static void assertNull(Object object) { Assert.assertNull(object); } @@ -442,7 +414,6 @@ public static void assertNull(Object object) { * Asserts that an object is null. If it is not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertNull(String message, Object object) { Assert.assertNull(message, object); } @@ -451,7 +422,6 @@ public static void assertNull(String message, Object object) { * Asserts that two objects refer to the same object. If they are not * an AssertionFailedError is thrown with the given message. */ - @SuppressWarnings("deprecation") public static void assertSame(String message, Object expected, Object actual) { Assert.assertSame(message, expected, actual); } @@ -460,7 +430,6 @@ public static void assertSame(String message, Object expected, Object actual) { * Asserts that two objects refer to the same object. If they are not * the same an AssertionFailedError is thrown. */ - @SuppressWarnings("deprecation") public static void assertSame(Object expected, Object actual) { Assert.assertSame(expected, actual); } @@ -470,7 +439,6 @@ public static void assertSame(Object expected, Object actual) { * refer to the same object an AssertionFailedError is thrown with the * given message. */ - @SuppressWarnings("deprecation") public static void assertNotSame(String message, Object expected, Object actual) { Assert.assertNotSame(message, expected, actual); } @@ -479,27 +447,22 @@ public static void assertNotSame(String message, Object expected, Object actual) * Asserts that two objects do not refer to the same object. If they do * refer to the same object an AssertionFailedError is thrown. */ - @SuppressWarnings("deprecation") public static void assertNotSame(Object expected, Object actual) { Assert.assertNotSame(expected, actual); } - @SuppressWarnings("deprecation") public static void failSame(String message) { Assert.failSame(message); } - @SuppressWarnings("deprecation") public static void failNotSame(String message, Object expected, Object actual) { Assert.failNotSame(message, expected, actual); } - @SuppressWarnings("deprecation") public static void failNotEquals(String message, Object expected, Object actual) { Assert.failNotEquals(message, expected, actual); } - @SuppressWarnings("deprecation") public static String format(String message, Object expected, Object actual) { return Assert.format(message, expected, actual); } @@ -519,7 +482,7 @@ protected void tearDown() throws Exception { } /** - * Returns a string representation of the test case + * Returns a string representation of the test case. */ @Override public String toString() { @@ -527,7 +490,7 @@ public String toString() { } /** - * Gets the name of a TestCase + * Gets the name of a TestCase. * * @return the name of the TestCase */ @@ -536,7 +499,7 @@ public String getName() { } /** - * Sets the name of a TestCase + * Sets the name of a TestCase. * * @param name the name to set */ diff --git a/src/main/java/junit/framework/TestFailure.java b/src/main/java/junit/framework/TestFailure.java index 6168b5809718..d1ddfbc29357 100644 --- a/src/main/java/junit/framework/TestFailure.java +++ b/src/main/java/junit/framework/TestFailure.java @@ -1,7 +1,6 @@ package junit.framework; -import java.io.PrintWriter; -import java.io.StringWriter; +import org.junit.internal.Throwables; /** @@ -49,10 +48,7 @@ public String toString() { * thrown by TestFailure. */ public String trace() { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - thrownException().printStackTrace(writer); - return stringWriter.toString(); + return Throwables.getStacktrace(thrownException()); } /** diff --git a/src/main/java/junit/framework/TestResult.java b/src/main/java/junit/framework/TestResult.java index 83325424b5fe..e01a2b0a72aa 100644 --- a/src/main/java/junit/framework/TestResult.java +++ b/src/main/java/junit/framework/TestResult.java @@ -52,14 +52,14 @@ public synchronized void addFailure(Test test, AssertionFailedError e) { } /** - * Registers a TestListener + * Registers a TestListener. */ public synchronized void addListener(TestListener listener) { fListeners.add(listener); } /** - * Unregisters a TestListener + * Unregisters a TestListener. */ public synchronized void removeListener(TestListener listener) { fListeners.remove(listener); @@ -91,7 +91,7 @@ public synchronized int errorCount() { } /** - * Returns an Enumeration for the errors + * Returns an Enumeration for the errors. */ public synchronized Enumeration errors() { return Collections.enumeration(fErrors); @@ -106,7 +106,7 @@ public synchronized int failureCount() { } /** - * Returns an Enumeration for the failures + * Returns an Enumeration for the failures. */ public synchronized Enumeration failures() { return Collections.enumeration(fFailures); @@ -150,7 +150,7 @@ public void runProtected(final Test test, Protectable p) { } /** - * Checks whether the test run should stop + * Checks whether the test run should stop. */ public synchronized boolean shouldStop() { return fStop; diff --git a/src/main/java/junit/framework/TestSuite.java b/src/main/java/junit/framework/TestSuite.java index 366f1cf379d6..50cd5f8d120b 100644 --- a/src/main/java/junit/framework/TestSuite.java +++ b/src/main/java/junit/framework/TestSuite.java @@ -1,7 +1,5 @@ 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; @@ -12,6 +10,7 @@ import java.util.Vector; import org.junit.internal.MethodSorter; +import org.junit.internal.Throwables; /** * A TestSuite is a Composite of Tests. @@ -35,7 +34,7 @@ *

    * A final option is to do the same for a large array of test classes. *

    - * Class[] testClasses = { MathTest.class, AnotherTest.class }
    + * Class[] testClasses = { MathTest.class, AnotherTest.class };
      * TestSuite suite= new TestSuite(testClasses);
      * 
    * @@ -65,11 +64,11 @@ static public Test createTest(Class theClass, String name) { test = constructor.newInstance(new Object[]{name}); } } catch (InstantiationException e) { - return (warning("Cannot instantiate test case: " + name + " (" + exceptionToString(e) + ")")); + return (warning("Cannot instantiate test case: " + name + " (" + Throwables.getStacktrace(e) + ")")); } catch (InvocationTargetException e) { - return (warning("Exception in constructor: " + name + " (" + exceptionToString(e.getTargetException()) + ")")); + return (warning("Exception in constructor: " + name + " (" + Throwables.getStacktrace(e.getTargetException()) + ")")); } catch (IllegalAccessException e) { - return (warning("Cannot access test case: " + name + " (" + exceptionToString(e) + ")")); + return (warning("Cannot access test case: " + name + " (" + Throwables.getStacktrace(e) + ")")); } return (Test) test; } @@ -99,16 +98,6 @@ protected void runTest() { }; } - /** - * Converts the stack trace into a string - */ - private static String exceptionToString(Throwable e) { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - e.printStackTrace(writer); - return stringWriter.toString(); - } - private String fName; private Vector fTests = new Vector(10); // Cannot convert this to List because it is used directly by some test runners @@ -210,7 +199,7 @@ public void addTest(Test test) { } /** - * Adds the tests from the given class to the suite + * Adds the tests from the given class to the suite. */ public void addTestSuite(Class testClass) { addTest(new TestSuite(testClass)); @@ -262,21 +251,21 @@ public void setName(String name) { } /** - * Returns the test at the given index + * Returns the test at the given index. */ public Test testAt(int index) { return fTests.get(index); } /** - * Returns the number of tests in this suite + * Returns the number of tests in this suite. */ public int testCount() { return fTests.size(); } /** - * Returns the tests as an enumeration + * Returns the tests as an enumeration. */ public Enumeration tests() { return fTests.elements(); diff --git a/src/main/java/junit/runner/BaseTestRunner.java b/src/main/java/junit/runner/BaseTestRunner.java index 8268323103a7..d63fae7ac2cb 100644 --- a/src/main/java/junit/runner/BaseTestRunner.java +++ b/src/main/java/junit/runner/BaseTestRunner.java @@ -20,6 +20,8 @@ import junit.framework.TestListener; import junit.framework.TestSuite; +import org.junit.internal.Throwables; + /** * Base class for all test runners. * This class was born live on stage in Sardinia during XP2000. @@ -233,6 +235,7 @@ private static void readPreferences() { setPreferences(new Properties(getPreferences())); getPreferences().load(is); } catch (IOException ignored) { + } catch (SecurityException ignored) { } finally { try { if (is != null) { @@ -264,11 +267,7 @@ public static int getPreference(String key, int dflt) { * Returns a filtered stack trace */ public static String getFilteredTrace(Throwable e) { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - e.printStackTrace(writer); - String trace = stringWriter.toString(); - return BaseTestRunner.getFilteredTrace(trace); + return BaseTestRunner.getFilteredTrace(Throwables.getStacktrace(e)); } /** diff --git a/src/main/java/junit/runner/TestRunListener.java b/src/main/java/junit/runner/TestRunListener.java index b5e22f57844f..ce5b3d5920a2 100644 --- a/src/main/java/junit/runner/TestRunListener.java +++ b/src/main/java/junit/runner/TestRunListener.java @@ -8,18 +8,18 @@ */ public interface TestRunListener { /* test status constants*/ - public static final int STATUS_ERROR = 1; - public static final int STATUS_FAILURE = 2; + int STATUS_ERROR = 1; + int STATUS_FAILURE = 2; - public void testRunStarted(String testSuiteName, int testCount); + void testRunStarted(String testSuiteName, int testCount); - public void testRunEnded(long elapsedTime); + void testRunEnded(long elapsedTime); - public void testRunStopped(long elapsedTime); + void testRunStopped(long elapsedTime); - public void testStarted(String testName); + void testStarted(String testName); - public void testEnded(String testName); + void testEnded(String testName); - public void testFailed(int status, String testName, String trace); + void testFailed(int status, String testName, String trace); } diff --git a/src/main/java/junit/runner/Version.java b/src/main/java/junit/runner/Version.java index eaf3db72d0ab..9f263840e40f 100644 --- a/src/main/java/junit/runner/Version.java +++ b/src/main/java/junit/runner/Version.java @@ -9,7 +9,7 @@ private Version() { } public static String id() { - return "4.12-SNAPSHOT"; + return "4.13.1-SNAPSHOT"; } public static void main(String[] args) { diff --git a/src/main/java/junit/textui/TestRunner.java b/src/main/java/junit/textui/TestRunner.java index 4d78f77da51d..913020af6b77 100644 --- a/src/main/java/junit/textui/TestRunner.java +++ b/src/main/java/junit/textui/TestRunner.java @@ -131,7 +131,7 @@ protected void pause(boolean wait) { } } - public static void main(String args[]) { + public static void main(String[] args) { TestRunner aTestRunner = new TestRunner(); try { TestResult r = aTestRunner.start(args); @@ -149,7 +149,7 @@ public static void main(String args[]) { * Starts a test run. Analyzes the command line arguments and runs the given * test suite. */ - public TestResult start(String args[]) throws Exception { + public TestResult start(String[] args) throws Exception { String testCase = ""; String method = ""; boolean wait = false; diff --git a/src/main/java/org/junit/Assert.java b/src/main/java/org/junit/Assert.java old mode 100755 new mode 100644 index d7deb06bb33e..65bbc9d3f7ff --- a/src/main/java/org/junit/Assert.java +++ b/src/main/java/org/junit/Assert.java @@ -2,6 +2,7 @@ import org.hamcrest.Matcher; import org.hamcrest.MatcherAssert; +import org.junit.function.ThrowingRunnable; import org.junit.internal.ArrayComparisonFailure; import org.junit.internal.ExactComparisonCriteria; import org.junit.internal.InexactComparisonCriteria; @@ -36,7 +37,7 @@ protected Assert() { * okay) * @param condition condition to be checked */ - static public void assertTrue(String message, boolean condition) { + public static void assertTrue(String message, boolean condition) { if (!condition) { fail(message); } @@ -48,7 +49,7 @@ static public void assertTrue(String message, boolean condition) { * * @param condition condition to be checked */ - static public void assertTrue(boolean condition) { + public static void assertTrue(boolean condition) { assertTrue(null, condition); } @@ -60,7 +61,7 @@ static public void assertTrue(boolean condition) { * okay) * @param condition condition to be checked */ - static public void assertFalse(String message, boolean condition) { + public static void assertFalse(String message, boolean condition) { assertTrue(message, !condition); } @@ -70,7 +71,7 @@ static public void assertFalse(String message, boolean condition) { * * @param condition condition to be checked */ - static public void assertFalse(boolean condition) { + public static void assertFalse(boolean condition) { assertFalse(null, condition); } @@ -81,7 +82,7 @@ static public void assertFalse(boolean condition) { * okay) * @see AssertionError */ - static public void fail(String message) { + public static void fail(String message) { if (message == null) { throw new AssertionError(); } @@ -91,7 +92,7 @@ static public void fail(String message) { /** * Fails a test with no message. */ - static public void fail() { + public static void fail() { fail(null); } @@ -106,11 +107,12 @@ static public void fail() { * @param expected expected value * @param actual actual value */ - static public void assertEquals(String message, Object expected, + public static void assertEquals(String message, Object expected, Object actual) { if (equalsRegardingNull(expected, actual)) { return; - } else if (expected instanceof String && actual instanceof String) { + } + if (expected instanceof String && actual instanceof String) { String cleanMessage = message == null ? "" : message; throw new ComparisonFailure(cleanMessage, (String) expected, (String) actual); @@ -140,7 +142,7 @@ private static boolean isEquals(Object expected, Object actual) { * @param expected expected value * @param actual the value to check against expected */ - static public void assertEquals(Object expected, Object actual) { + public static void assertEquals(Object expected, Object actual) { assertEquals(null, expected, actual); } @@ -155,7 +157,7 @@ static public void assertEquals(Object expected, Object actual) { * @param unexpected unexpected value to check * @param actual the value to check against unexpected */ - static public void assertNotEquals(String message, Object unexpected, + public static void assertNotEquals(String message, Object unexpected, Object actual) { if (equalsRegardingNull(unexpected, actual)) { failEquals(message, actual); @@ -171,7 +173,7 @@ static public void assertNotEquals(String message, Object unexpected, * @param unexpected unexpected value to check * @param actual the value to check against unexpected */ - static public void assertNotEquals(Object unexpected, Object actual) { + public static void assertNotEquals(Object unexpected, Object actual) { assertNotEquals(null, unexpected, actual); } @@ -194,7 +196,7 @@ private static void failEquals(String message, Object actual) { * @param unexpected unexpected value to check * @param actual the value to check against unexpected */ - static public void assertNotEquals(String message, long unexpected, long actual) { + public static void assertNotEquals(String message, long unexpected, long actual) { if (unexpected == actual) { failEquals(message, Long.valueOf(actual)); } @@ -207,7 +209,7 @@ static public void assertNotEquals(String message, long unexpected, long actual) * @param unexpected unexpected value to check * @param actual the value to check against unexpected */ - static public void assertNotEquals(long unexpected, long actual) { + public static void assertNotEquals(long unexpected, long actual) { assertNotEquals(null, unexpected, actual); } @@ -226,7 +228,7 @@ static public void assertNotEquals(long unexpected, long actual) { * actual for which both numbers are still * considered equal. */ - static public void assertNotEquals(String message, double unexpected, + public static void assertNotEquals(String message, double unexpected, double actual, double delta) { if (!doubleIsDifferent(unexpected, actual, delta)) { failEquals(message, Double.valueOf(actual)); @@ -245,7 +247,7 @@ static public void assertNotEquals(String message, double unexpected, * actual for which both numbers are still * considered equal. */ - static public void assertNotEquals(double unexpected, double actual, double delta) { + public static void assertNotEquals(double unexpected, double actual, double delta) { assertNotEquals(null, unexpected, actual, delta); } @@ -261,7 +263,7 @@ static public void assertNotEquals(double unexpected, double actual, double delt * actual for which both numbers are still * considered equal. */ - static public void assertNotEquals(float unexpected, float actual, float delta) { + public static void assertNotEquals(float unexpected, float actual, float delta) { assertNotEquals(null, unexpected, actual, delta); } @@ -297,7 +299,7 @@ public static void assertArrayEquals(String message, Object[] expecteds, public static void assertArrayEquals(Object[] expecteds, Object[] actuals) { assertArrayEquals(null, expecteds, actuals); } - + /** * Asserts that two boolean arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. If @@ -312,8 +314,8 @@ public static void assertArrayEquals(Object[] expecteds, Object[] actuals) { public static void assertArrayEquals(String message, boolean[] expecteds, boolean[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); - } - + } + /** * Asserts that two boolean arrays are equal. If they are not, an * {@link AssertionError} is thrown. If expected and @@ -547,7 +549,7 @@ private static void internalArrayEquals(String message, Object expecteds, * actual for which both numbers are still * considered equal. */ - static public void assertEquals(String message, double expected, + public static void assertEquals(String message, double expected, double actual, double delta) { if (doubleIsDifferent(expected, actual, delta)) { failNotEquals(message, Double.valueOf(expected), Double.valueOf(actual)); @@ -569,7 +571,7 @@ static public void assertEquals(String message, double expected, * actual for which both numbers are still * considered equal. */ - static public void assertEquals(String message, float expected, + public static void assertEquals(String message, float expected, float actual, float delta) { if (floatIsDifferent(expected, actual, delta)) { failNotEquals(message, Float.valueOf(expected), Float.valueOf(actual)); @@ -591,14 +593,14 @@ static public void assertEquals(String message, float expected, * actual for which both numbers are still * considered equal. */ - static public void assertNotEquals(String message, float unexpected, + public static void assertNotEquals(String message, float unexpected, float actual, float delta) { if (!floatIsDifferent(unexpected, actual, delta)) { failEquals(message, Float.valueOf(actual)); } } - static private boolean doubleIsDifferent(double d1, double d2, double delta) { + private static boolean doubleIsDifferent(double d1, double d2, double delta) { if (Double.compare(d1, d2) == 0) { return false; } @@ -609,7 +611,7 @@ static private boolean doubleIsDifferent(double d1, double d2, double delta) { return true; } - static private boolean floatIsDifferent(float f1, float f2, float delta) { + private static boolean floatIsDifferent(float f1, float f2, float delta) { if (Float.compare(f1, f2) == 0) { return false; } @@ -627,7 +629,7 @@ static private boolean floatIsDifferent(float f1, float f2, float delta) { * @param expected expected long value. * @param actual actual long value */ - static public void assertEquals(long expected, long actual) { + public static void assertEquals(long expected, long actual) { assertEquals(null, expected, actual); } @@ -640,7 +642,7 @@ static public void assertEquals(long expected, long actual) { * @param expected long expected value. * @param actual long actual value */ - static public void assertEquals(String message, long expected, long actual) { + public static void assertEquals(String message, long expected, long actual) { if (expected != actual) { failNotEquals(message, Long.valueOf(expected), Long.valueOf(actual)); } @@ -652,7 +654,7 @@ static public void assertEquals(String message, long expected, long actual) { * instead */ @Deprecated - static public void assertEquals(double expected, double actual) { + public static void assertEquals(double expected, double actual) { assertEquals(null, expected, actual); } @@ -662,7 +664,7 @@ static public void assertEquals(double expected, double actual) { * instead */ @Deprecated - static public void assertEquals(String message, double expected, + public static void assertEquals(String message, double expected, double actual) { fail("Use assertEquals(expected, actual, delta) to compare floating-point numbers"); } @@ -679,7 +681,7 @@ static public void assertEquals(String message, double expected, * actual for which both numbers are still * considered equal. */ - static public void assertEquals(double expected, double actual, double delta) { + public static void assertEquals(double expected, double actual, double delta) { assertEquals(null, expected, actual, delta); } @@ -695,8 +697,7 @@ static public void assertEquals(double expected, double actual, double delta) { * actual for which both numbers are still * considered equal. */ - - static public void assertEquals(float expected, float actual, float delta) { + public static void assertEquals(float expected, float actual, float delta) { assertEquals(null, expected, actual, delta); } @@ -708,7 +709,7 @@ static public void assertEquals(float expected, float actual, float delta) { * okay) * @param object Object to check or null */ - static public void assertNotNull(String message, Object object) { + public static void assertNotNull(String message, Object object) { assertTrue(message, object != null); } @@ -718,7 +719,7 @@ static public void assertNotNull(String message, Object object) { * * @param object Object to check or null */ - static public void assertNotNull(Object object) { + public static void assertNotNull(Object object) { assertNotNull(null, object); } @@ -730,7 +731,7 @@ static public void assertNotNull(Object object) { * okay) * @param object Object to check or null */ - static public void assertNull(String message, Object object) { + public static void assertNull(String message, Object object) { if (object == null) { return; } @@ -743,11 +744,11 @@ static public void assertNull(String message, Object object) { * * @param object Object to check or null */ - static public void assertNull(Object object) { + public static void assertNull(Object object) { assertNull(null, object); } - static private void failNotNull(String message, Object actual) { + private static void failNotNull(String message, Object actual) { String formatted = ""; if (message != null) { formatted = message + " "; @@ -764,7 +765,7 @@ static private void failNotNull(String message, Object actual) { * @param expected the expected object * @param actual the object to compare to expected */ - static public void assertSame(String message, Object expected, Object actual) { + public static void assertSame(String message, Object expected, Object actual) { if (expected == actual) { return; } @@ -778,7 +779,7 @@ static public void assertSame(String message, Object expected, Object actual) { * @param expected the expected object * @param actual the object to compare to expected */ - static public void assertSame(Object expected, Object actual) { + public static void assertSame(Object expected, Object actual) { assertSame(null, expected, actual); } @@ -792,7 +793,7 @@ static public void assertSame(Object expected, Object actual) { * @param unexpected the object you don't expect * @param actual the object to compare to unexpected */ - static public void assertNotSame(String message, Object unexpected, + public static void assertNotSame(String message, Object unexpected, Object actual) { if (unexpected == actual) { failSame(message); @@ -807,11 +808,11 @@ static public void assertNotSame(String message, Object unexpected, * @param unexpected the object you don't expect * @param actual the object to compare to unexpected */ - static public void assertNotSame(Object unexpected, Object actual) { + public static void assertNotSame(Object unexpected, Object actual) { assertNotSame(null, unexpected, actual); } - static private void failSame(String message) { + private static void failSame(String message) { String formatted = ""; if (message != null) { formatted = message + " "; @@ -819,7 +820,7 @@ static private void failSame(String message) { fail(formatted + "expected not same"); } - static private void failNotSame(String message, Object expected, + private static void failNotSame(String message, Object expected, Object actual) { String formatted = ""; if (message != null) { @@ -829,19 +830,19 @@ static private void failNotSame(String message, Object expected, + ">"); } - static private void failNotEquals(String message, Object expected, + private static void failNotEquals(String message, Object expected, Object actual) { fail(format(message, expected, actual)); } static String format(String message, Object expected, Object actual) { String formatted = ""; - if (message != null && !message.equals("")) { + if (message != null && !"".equals(message)) { formatted = message + " "; } String expectedString = String.valueOf(expected); String actualString = String.valueOf(actual); - if (expectedString.equals(actualString)) { + if (equalsRegardingNull(expectedString, actualString)) { return formatted + "expected: " + formatClassAndValue(expected, expectedString) + " but was: " + formatClassAndValue(actual, actualString); @@ -851,6 +852,11 @@ static String format(String message, Object expected, Object actual) { } } + private static String formatClass(Class value) { + String className = value.getCanonicalName(); + return className == null ? value.getName() : className; + } + private static String formatClassAndValue(Object value, String valueString) { String className = value == null ? "null" : value.getClass().getName(); return className + "<" + valueString + ">"; @@ -917,8 +923,9 @@ public static void assertEquals(Object[] expecteds, Object[] actuals) { * @param matcher an expression, built of {@link Matcher}s, specifying allowed * values * @see org.hamcrest.CoreMatchers - * @see org.hamcrest.MatcherAssert + * @deprecated use {@code org.hamcrest.MatcherAssert.assertThat()} */ + @Deprecated public static void assertThat(T actual, Matcher matcher) { assertThat("", actual, matcher); } @@ -949,10 +956,79 @@ public static void assertThat(T actual, Matcher matcher) { * @param matcher an expression, built of {@link Matcher}s, specifying allowed * values * @see org.hamcrest.CoreMatchers - * @see org.hamcrest.MatcherAssert + * @deprecated use {@code org.hamcrest.MatcherAssert.assertThat()} */ + @Deprecated public static void assertThat(String reason, T actual, Matcher matcher) { MatcherAssert.assertThat(reason, actual, matcher); } + + /** + * Asserts that {@code runnable} throws an exception of type {@code expectedThrowable} when + * executed. If it does, the exception object is returned. If it does not throw an exception, an + * {@link AssertionError} is thrown. If it throws the wrong type of exception, an {@code + * AssertionError} is thrown describing the mismatch; the exception that was actually thrown can + * be obtained by calling {@link AssertionError#getCause}. + * + * @param expectedThrowable the expected type of the exception + * @param runnable a function that is expected to throw an exception when executed + * @return the exception thrown by {@code runnable} + * @since 4.13 + */ + public static T assertThrows(Class expectedThrowable, + ThrowingRunnable runnable) { + return assertThrows(null, expectedThrowable, runnable); + } + + /** + * Asserts that {@code runnable} throws an exception of type {@code expectedThrowable} when + * executed. If it does, the exception object is returned. If it does not throw an exception, an + * {@link AssertionError} is thrown. If it throws the wrong type of exception, an {@code + * AssertionError} is thrown describing the mismatch; the exception that was actually thrown can + * be obtained by calling {@link AssertionError#getCause}. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expectedThrowable the expected type of the exception + * @param runnable a function that is expected to throw an exception when executed + * @return the exception thrown by {@code runnable} + * @since 4.13 + */ + public static T assertThrows(String message, Class expectedThrowable, + ThrowingRunnable runnable) { + try { + runnable.run(); + } catch (Throwable actualThrown) { + if (expectedThrowable.isInstance(actualThrown)) { + @SuppressWarnings("unchecked") T retVal = (T) actualThrown; + return retVal; + } else { + String expected = formatClass(expectedThrowable); + Class actualThrowable = actualThrown.getClass(); + String actual = formatClass(actualThrowable); + if (expected.equals(actual)) { + // There must be multiple class loaders. Add the identity hash code so the message + // doesn't say "expected: java.lang.String ..." + expected += "@" + Integer.toHexString(System.identityHashCode(expectedThrowable)); + actual += "@" + Integer.toHexString(System.identityHashCode(actualThrowable)); + } + String mismatchMessage = buildPrefix(message) + + format("unexpected exception type thrown;", expected, actual); + + // The AssertionError(String, Throwable) ctor is only available on JDK7. + AssertionError assertionError = new AssertionError(mismatchMessage); + assertionError.initCause(actualThrown); + throw assertionError; + } + } + String notThrownMessage = buildPrefix(message) + String + .format("expected %s to be thrown, but nothing was thrown", + formatClass(expectedThrowable)); + throw new AssertionError(notThrownMessage); + } + + private static String buildPrefix(String message) { + return message != null && message.length() != 0 ? message + ": " : ""; + } } diff --git a/src/main/java/org/junit/Assume.java b/src/main/java/org/junit/Assume.java index b7687f7c1ffa..29b705be6988 100644 --- a/src/main/java/org/junit/Assume.java +++ b/src/main/java/org/junit/Assume.java @@ -14,7 +14,7 @@ * basically means "don't run this test if these conditions don't apply". The default JUnit runner skips tests with * failing assumptions. Custom runners may behave differently. *

    - * A good example of using assumptions is in Theories where they are needed to exclude certain datapoints that aren't suitable or allowed for a certain test case. + * A good example of using assumptions is in Theories where they are needed to exclude certain datapoints that aren't suitable or allowed for a certain test case. *

    * Failed assumptions are usually not logged, because there may be many tests that don't apply to certain * configurations. @@ -29,11 +29,20 @@ *
    *

    * - * @see Theories + * @see Theories * * @since 4.4 */ public class Assume { + + /** + * Do not instantiate. + * @deprecated since 4.13. + */ + @Deprecated + public Assume() { + } + /** * If called with an expression evaluating to {@code false}, the test will halt and be ignored. */ @@ -45,7 +54,7 @@ public static void assumeTrue(boolean b) { * The inverse of {@link #assumeTrue(boolean)}. */ public static void assumeFalse(boolean b) { - assumeTrue(!b); + assumeThat(b, is(false)); } /** @@ -67,9 +76,11 @@ public static void assumeFalse(String message, boolean b) { } /** - * If called with one or more null elements in objects, the test will halt and be ignored. + * If called with a {@code null} array or one or more {@code null} elements in {@code objects}, + * the test will halt and be ignored. */ public static void assumeNotNull(Object... objects) { + assumeThat(objects, notNullValue()); assumeThat(asList(objects), everyItem(notNullValue())); } diff --git a/src/main/java/org/junit/AssumptionViolatedException.java b/src/main/java/org/junit/AssumptionViolatedException.java index e48ddf000a78..1d62190a2315 100644 --- a/src/main/java/org/junit/AssumptionViolatedException.java +++ b/src/main/java/org/junit/AssumptionViolatedException.java @@ -40,7 +40,7 @@ public AssumptionViolatedException(String message) { /** * An assumption exception with the given message and a cause. */ - public AssumptionViolatedException(String assumption, Throwable t) { - super(assumption, t); + public AssumptionViolatedException(String message, Throwable t) { + super(message, t); } } diff --git a/src/main/java/org/junit/ClassRule.java b/src/main/java/org/junit/ClassRule.java index 02c40a713fce..94ee29f9f51d 100644 --- a/src/main/java/org/junit/ClassRule.java +++ b/src/main/java/org/junit/ClassRule.java @@ -28,7 +28,10 @@ * annotated {@link ClassRule}s on a class, they will be applied in an order * that depends on your JVM's implementation of the reflection API, which is * undefined, in general. However, Rules defined by fields will always be applied - * before Rules defined by methods. + * after Rules defined by methods, i.e. the Statements returned by the former will + * be executed around those returned by the latter. + * + *

    Usage

    *

    * 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: @@ -79,9 +82,37 @@ *

    * For more information and more examples, see {@link org.junit.rules.TestRule}. * + *

    Ordering

    + *

    + * You can use {@link #order()} if you want to have control over the order in + * which the Rules are applied. + * + *

    + * public class ThreeClassRules {
    + *     @ClassRule(order = 0)
    + *     public static LoggingRule outer = new LoggingRule("outer rule");
    + *
    + *     @ClassRule(order = 1)
    + *     public static LoggingRule middle = new LoggingRule("middle rule");
    + *
    + *     @ClassRule(order = 2)
    + *     public static LoggingRule inner = new LoggingRule("inner rule");
    + *
    + *     // ...
    + * }
    + * 
    + * * @since 4.9 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD}) public @interface ClassRule { + + /** + * Specifies the order in which rules are applied. The rules with a higher value are inner. + * + * @since 4.13 + */ + int order() default Rule.DEFAULT_ORDER; + } diff --git a/src/main/java/org/junit/ComparisonFailure.java b/src/main/java/org/junit/ComparisonFailure.java index 9563e61c5c7a..d1daa863c3f3 100644 --- a/src/main/java/org/junit/ComparisonFailure.java +++ b/src/main/java/org/junit/ComparisonFailure.java @@ -21,7 +21,7 @@ public class ComparisonFailure extends AssertionError { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * See https://github.com/junit-team/junit4/issues/976 */ private String fExpected; private String fActual; diff --git a/src/main/java/org/junit/Rule.java b/src/main/java/org/junit/Rule.java index 711235c5a7f3..9370e94f51fc 100644 --- a/src/main/java/org/junit/Rule.java +++ b/src/main/java/org/junit/Rule.java @@ -16,12 +16,14 @@ * to the {@link org.junit.rules.TestRule} will run any {@link Before} methods, * then the {@link Test} method, and finally any {@link After} methods, * throwing an exception if any of these fail. If there are multiple - * annotated {@link Rule}s on a class, they will be applied in order of fields first, then methods. + * annotated {@link Rule}s on a class, they will be applied in order of methods first, then fields. * However, if there are multiple fields (or methods) they will be applied in an order * that depends on your JVM's implementation of the reflection API, which is * undefined, in general. Rules defined by fields will always be applied - * before Rules defined by methods. You can use a {@link org.junit.rules.RuleChain} if you want - * to have control over the order in which the Rules are applied. + * after Rules defined by methods, i.e. the Statements returned by the former will + * be executed around those returned by the latter. + * + *

    Usage

    *

    * For example, here is a test class that creates a temporary folder before * each test method, and deletes it after each: @@ -61,10 +63,39 @@ * For more information and more examples, see * {@link org.junit.rules.TestRule}. * + *

    Ordering

    + *

    + * You can use {@link #order()} if you want to have control over the order in + * which the Rules are applied. + * + *

    + * public class ThreeRules {
    + *     @Rule(order = 0)
    + *     public LoggingRule outer = new LoggingRule("outer rule");
    + *
    + *     @Rule(order = 1)
    + *     public LoggingRule middle = new LoggingRule("middle rule");
    + *
    + *     @Rule(order = 2)
    + *     public LoggingRule inner = new LoggingRule("inner rule");
    + *
    + *     // ...
    + * }
    + * 
    + * * @since 4.7 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD}) public @interface Rule { -} \ No newline at end of file + int DEFAULT_ORDER = -1; + + /** + * Specifies the order in which rules are applied. The rules with a higher value are inner. + * + * @since 4.13 + */ + int order() default DEFAULT_ORDER; + +} diff --git a/src/main/java/org/junit/Test.java b/src/main/java/org/junit/Test.java index 71ac4287dbef..1db6fc7ab073 100644 --- a/src/main/java/org/junit/Test.java +++ b/src/main/java/org/junit/Test.java @@ -1,5 +1,7 @@ package org.junit; +import org.junit.function.ThrowingRunnable; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -23,24 +25,40 @@ * } * *

    - * The Test annotation supports two optional parameters. - * The first, expected, declares that a test method should throw + * The Test annotation supports two optional parameters for + * exception testing and for limiting test execution time. + * + *

    Exception Testing

    + *

    + * The parameter expected 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: *

    - *    @Test(expected=IndexOutOfBoundsException.class) public void outOfBounds() {
    + *    @Test(expected=IndexOutOfBoundsException.class)
    + *    public void outOfBounds() {
      *       new ArrayList<Object>().get(1);
      *    }
      * 
    - * If the exception's message or one of its properties should be verified, the - * {@link org.junit.rules.ExpectedException ExpectedException} rule can be used. Further + * + * Using the parameter expected for exception testing comes with + * some limitations: only the exception's type can be checked and it is not + * possible to precisely specify the code that throws the exception. Therefore + * JUnit 4 has improved its support for exception testing with + * {@link Assert#assertThrows(Class, ThrowingRunnable)} and the + * {@link org.junit.rules.ExpectedException ExpectedException} rule. + * With assertThrows the code that throws the exception can be + * precisely specified. If the exception's message or one of its properties + * should be verified, the ExpectedException rule can be used. Further * information about exception testing can be found at the - * JUnit Wiki. + * JUnit Wiki. + * + *

    Timeout

    *

    - * The second optional parameter, timeout, causes a test to fail if it takes + * The parameter timeout causes a test to fail if it takes * longer than a specified amount of clock time (measured in milliseconds). The following test fails: *

    - *    @Test(timeout=100) public void infinity() {
    + *    @Test(timeout=100)
    + *    public void infinity() {
      *       while(true);
      *    }
      * 
    @@ -49,7 +67,8 @@ * following test may or may not fail depending on how the operating system * schedules threads: *
    - *    @Test(timeout=100) public void sleep100() {
    + *    @Test(timeout=100)
    + *    public void sleep100() {
      *       Thread.sleep(100);
      *    }
      * 
    @@ -66,7 +85,7 @@ public @interface Test { /** - * Default empty exception + * Default empty exception. */ static class None extends Throwable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/junit/TestCouldNotBeSkippedException.java b/src/main/java/org/junit/TestCouldNotBeSkippedException.java new file mode 100644 index 000000000000..4804493290ef --- /dev/null +++ b/src/main/java/org/junit/TestCouldNotBeSkippedException.java @@ -0,0 +1,19 @@ +package org.junit; + +/** + * Indicates that a test that indicated that it should be skipped could not be skipped. + * This can be thrown if a test uses the methods in {@link Assume} to indicate that + * it should be skipped, but before processing of the test was completed, other failures + * occured. + * + * @see org.junit.Assume + * @since 4.13 + */ +public class TestCouldNotBeSkippedException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** Creates an instance using the given assumption failure. */ + public TestCouldNotBeSkippedException(org.junit.internal.AssumptionViolatedException cause) { + super("Test could not be skipped due to other failures", cause); + } +} diff --git a/src/main/java/org/junit/experimental/categories/Categories.java b/src/main/java/org/junit/experimental/categories/Categories.java index 290c1800cbc6..0c73ed82afff 100644 --- a/src/main/java/org/junit/experimental/categories/Categories.java +++ b/src/main/java/org/junit/experimental/categories/Categories.java @@ -2,8 +2,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import org.junit.runner.Description; @@ -76,7 +78,7 @@ * * * @version 4.12 - * @see Categories at JUnit wiki + * @see Categories at JUnit wiki */ public class Categories extends Suite { @@ -86,13 +88,13 @@ public class Categories extends Suite { * Determines the tests to run that are annotated with categories specified in * the value of this annotation or their subtypes unless excluded with {@link ExcludeCategory}. */ - public Class[] value() default {}; + Class[] value() default {}; /** * If true, runs tests annotated with any of the categories in * {@link IncludeCategory#value()}. Otherwise, runs tests only if annotated with all of the categories. */ - public boolean matchAny() default true; + boolean matchAny() default true; } @Retention(RetentionPolicy.RUNTIME) @@ -101,13 +103,13 @@ public class Categories extends Suite { * Determines the tests which do not run if they are annotated with categories specified in the * value of this annotation or their subtypes regardless of being included in {@link IncludeCategory#value()}. */ - public Class[] value() default {}; + Class[] value() default {}; /** * If true, the tests annotated with any of the categories in {@link ExcludeCategory#value()} * do not run. Otherwise, the tests do not run if and only if annotated with all categories. */ - public boolean matchAny() default true; + boolean matchAny() default true; } public static class CategoryFilter extends Filter { @@ -117,10 +119,7 @@ public static class CategoryFilter extends Filter { private final boolean excludedAny; public static CategoryFilter include(boolean matchAny, Class... categories) { - if (hasNull(categories)) { - throw new NullPointerException("has null category"); - } - return categoryFilter(matchAny, createSet(categories), true, null); + return new CategoryFilter(matchAny, categories, true, null); } public static CategoryFilter include(Class category) { @@ -132,10 +131,7 @@ public static CategoryFilter include(Class... categories) { } public static CategoryFilter exclude(boolean matchAny, Class... categories) { - if (hasNull(categories)) { - throw new NullPointerException("has null category"); - } - return categoryFilter(true, null, matchAny, createSet(categories)); + return new CategoryFilter(true, null, matchAny, categories); } public static CategoryFilter exclude(Class category) { @@ -151,14 +147,30 @@ public static CategoryFilter categoryFilter(boolean matchAnyInclusions, Set includedCategory, Class excludedCategory) { + includedAny = true; + excludedAny = true; + included = nullableClassToSet(includedCategory); + excluded = nullableClassToSet(excludedCategory); + } + protected CategoryFilter(boolean matchAnyIncludes, Set> includes, - boolean matchAnyExcludes, Set> excludes) { + boolean matchAnyExcludes, Set> excludes) { includedAny = matchAnyIncludes; excludedAny = matchAnyExcludes; included = copyAndRefine(includes); excluded = copyAndRefine(excludes); } + private CategoryFilter(boolean matchAnyIncludes, Class[] inclusions, + boolean matchAnyExcludes, Class[] exclusions) { + includedAny = matchAnyIncludes; + excludedAny = matchAnyExcludes; + included = createSet(inclusions); + excluded = createSet(exclusions); + } + /** * @see #toString() */ @@ -284,23 +296,13 @@ private static Class[] directCategories(Description description) { } private static Set> copyAndRefine(Set> classes) { - HashSet> c= new HashSet>(); + Set> c= new LinkedHashSet>(); if (classes != null) { c.addAll(classes); } c.remove(null); return c; } - - private static boolean hasNull(Class... classes) { - if (classes == null) return false; - for (Class clazz : classes) { - if (clazz == null) { - return true; - } - } - return false; - } } public Categories(Class klass, RunnerBuilder builder) throws InitializationError { @@ -315,7 +317,6 @@ public Categories(Class klass, RunnerBuilder builder) throws InitializationEr } catch (NoTestsRemainException e) { throw new InitializationError(e); } - assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription()); } private static Set> getIncludedCategory(Class klass) { @@ -338,34 +339,6 @@ private static boolean isAnyExcluded(Class klass) { return annotation == null || annotation.matchAny(); } - private static void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError { - if (!canHaveCategorizedChildren(description)) { - assertNoDescendantsHaveCategoryAnnotations(description); - } - for (Description each : description.getChildren()) { - assertNoCategorizedDescendentsOfUncategorizeableParents(each); - } - } - - private static void assertNoDescendantsHaveCategoryAnnotations(Description description) throws InitializationError { - for (Description each : description.getChildren()) { - if (each.getAnnotation(Category.class) != null) { - throw new InitializationError("Category annotations on Parameterized classes are not supported on individual methods."); - } - assertNoDescendantsHaveCategoryAnnotations(each); - } - } - - // If children have names like [0], our current magical category code can't determine their parentage. - private static boolean canHaveCategorizedChildren(Description description) { - for (Description each : description.getChildren()) { - if (each.getTestClass() == null) { - return false; - } - } - return true; - } - private static boolean hasAssignableTo(Set> assigns, Class to) { for (final Class from : assigns) { if (to.isAssignableFrom(from)) { @@ -375,11 +348,28 @@ private static boolean hasAssignableTo(Set> assigns, Class to) { return false; } - private static Set> createSet(Class... t) { - final Set> set= new HashSet>(); - if (t != null) { - Collections.addAll(set, t); + private static Set> createSet(Class[] classes) { + // Not throwing a NPE if t is null is a bad idea, but it's the behavior from JUnit 4.12 + // for include(boolean, Class...) and exclude(boolean, Class...) + if (classes == null || classes.length == 0) { + return Collections.emptySet(); + } + for (Class category : classes) { + if (category == null) { + throw new NullPointerException("has null category"); + } } - return set; + + return classes.length == 1 + ? Collections.>singleton(classes[0]) + : new LinkedHashSet>(Arrays.asList(classes)); + } + + private static Set> nullableClassToSet(Class nullableClass) { + // Not throwing a NPE if t is null is a bad idea, but it's the behavior from JUnit 4.11 + // for CategoryFilter(Class includedCategory, Class excludedCategory) + return nullableClass == null + ? Collections.>emptySet() + : Collections.>singleton(nullableClass); } } diff --git a/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java b/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java index cee1ae724595..e9bdab77e502 100644 --- a/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java +++ b/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java @@ -37,7 +37,11 @@ private List> parseCategories(String categories) throws ClassNotFoundEx List> categoryClasses = new ArrayList>(); for (String category : categories.split(",")) { - Class categoryClass = Classes.getClass(category); + /* + * Load the category class using the context class loader. + * If there is no context class loader, use the class loader for this class. + */ + Class categoryClass = Classes.getClass(category, getClass()); categoryClasses.add(categoryClass); } diff --git a/src/main/java/org/junit/experimental/max/MaxHistory.java b/src/main/java/org/junit/experimental/max/MaxHistory.java index 45a40336b3f6..ab7443f38535 100644 --- a/src/main/java/org/junit/experimental/max/MaxHistory.java +++ b/src/main/java/org/junit/experimental/max/MaxHistory.java @@ -64,7 +64,7 @@ private static MaxHistory readHistory(File storedResults) /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * See https://github.com/junit-team/junit4/issues/976 */ private final Map fDurations = new HashMap(); private final Map fFailureTimestamps = new HashMap(); @@ -75,10 +75,15 @@ private MaxHistory(File storedResults) { } private void save() throws IOException { - ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream( - fHistoryStore)); - stream.writeObject(this); - stream.close(); + ObjectOutputStream stream = null; + try { + stream = new ObjectOutputStream(new FileOutputStream(fHistoryStore)); + stream.writeObject(this); + } finally { + if (stream != null) { + stream.close(); + } + } } Long getFailureTimestamp(Description key) { diff --git a/src/main/java/org/junit/experimental/results/PrintableResult.java b/src/main/java/org/junit/experimental/results/PrintableResult.java index ffe22f0e957c..0f67766f9141 100644 --- a/src/main/java/org/junit/experimental/results/PrintableResult.java +++ b/src/main/java/org/junit/experimental/results/PrintableResult.java @@ -54,6 +54,15 @@ public int failureCount() { return result.getFailures().size(); } + /** + * Returns the failures in this result. + * + * @since 4.13 + */ + public List failures() { + return result.getFailures(); + } + @Override public String toString() { ByteArrayOutputStream stream = new ByteArrayOutputStream(); diff --git a/src/main/java/org/junit/experimental/results/ResultMatchers.java b/src/main/java/org/junit/experimental/results/ResultMatchers.java index cf58f1bc499a..e111093150c1 100644 --- a/src/main/java/org/junit/experimental/results/ResultMatchers.java +++ b/src/main/java/org/junit/experimental/results/ResultMatchers.java @@ -4,6 +4,7 @@ import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; +import org.junit.runner.notification.Failure; /** * Matchers on a PrintableResult, to enable JUnit self-tests. @@ -14,6 +15,15 @@ * */ public class ResultMatchers { + + /** + * Do not instantiate. + * @deprecated will be private soon. + */ + @Deprecated + public ResultMatchers() { + } + /** * Matches if the tests are all successful */ @@ -52,14 +62,34 @@ public void describeTo(Description description) { }; } + /** + * Matches if the result has exactly one failure matching the given matcher. + * + * @since 4.13 + */ + public static Matcher hasSingleFailureMatching(final Matcher matcher) { + return new TypeSafeMatcher() { + @Override + public boolean matchesSafely(PrintableResult item) { + return item.failureCount() == 1 && matcher.matches(item.failures().get(0).getException()); + } + + public void describeTo(Description description) { + description.appendText("has failure with exception matching "); + matcher.describeTo(description); + } + }; + } + /** * Matches if the result has one or more failures, and at least one of them * contains {@code string} */ public static Matcher hasFailureContaining(final String string) { - return new BaseMatcher() { - public boolean matches(Object item) { - return item.toString().contains(string); + return new TypeSafeMatcher() { + @Override + public boolean matchesSafely(PrintableResult item) { + return item.failureCount() > 0 && item.toString().contains(string); } public void describeTo(Description description) { diff --git a/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java b/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java index 15b5d9518d8a..846a39e46339 100644 --- a/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java +++ b/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java @@ -17,7 +17,7 @@ * * In addition, annotations themselves can be annotated with * @ParametersSuppliedBy, and then used similarly. ParameterSuppliedBy - * annotations on parameters are detected by searching up this heirarchy such + * annotations on parameters are detected by searching up this hierarchy such * that these act as syntactic sugar, making: * *
    diff --git a/src/main/java/org/junit/experimental/theories/Theories.java b/src/main/java/org/junit/experimental/theories/Theories.java
    index 817f553a51bc..ac88a364a670 100644
    --- a/src/main/java/org/junit/experimental/theories/Theories.java
    +++ b/src/main/java/org/junit/experimental/theories/Theories.java
    @@ -51,11 +51,11 @@
      *      }
      * }
      * 
    - * This makes it clear that the user's filename should be included in the config file name, + * This makes it clear that the username should be included in the config file name, * only if it doesn't contain a slash. Another test or theory might define what happens when a username does contain * a slash. UserTest will attempt to run filenameIncludesUsername on every compatible data * point defined in the class. If any of the assumptions fail, the data point is silently ignored. If all of the - * assumptions pass, but an assertion fails, the test fails. + * assumptions pass, but an assertion fails, the test fails. If no parameters can be found that satisfy all assumptions, the test fails. *

    * Defining general statements as theories allows data point reuse across a bunch of functionality tests and also * allows automated tools to search for new, unexpected data points that expose bugs. @@ -73,6 +73,11 @@ public Theories(Class klass) throws InitializationError { super(klass); } + /** @since 4.13 */ + protected Theories(TestClass testClass) throws InitializationError { + super(testClass); + } + @Override protected void collectInitializationErrors(List errors) { super.collectInitializationErrors(errors); @@ -215,7 +220,7 @@ protected void runWithIncompleteAssignment(Assignments incomplete) protected void runWithCompleteAssignment(final Assignments complete) throws Throwable { - new BlockJUnit4ClassRunner(getTestClass().getJavaClass()) { + new BlockJUnit4ClassRunner(getTestClass()) { @Override protected void collectInitializationErrors( List errors) { diff --git a/src/main/java/org/junit/experimental/theories/internal/Assignments.java b/src/main/java/org/junit/experimental/theories/internal/Assignments.java index a94c8a5e00b1..6626797ef089 100644 --- a/src/main/java/org/junit/experimental/theories/internal/Assignments.java +++ b/src/main/java/org/junit/experimental/theories/internal/Assignments.java @@ -47,7 +47,7 @@ public static Assignments allUnassigned(Method testMethod, } public boolean isComplete() { - return unassigned.size() == 0; + return unassigned.isEmpty(); } public ParameterSignature nextUnassigned() { @@ -55,11 +55,10 @@ public ParameterSignature nextUnassigned() { } public Assignments assignNext(PotentialAssignment source) { - List assigned = new ArrayList( - this.assigned); - assigned.add(source); + List potentialAssignments = new ArrayList(assigned); + potentialAssignments.add(source); - return new Assignments(assigned, unassigned.subList(1, + return new Assignments(potentialAssignments, unassigned.subList(1, unassigned.size()), clazz); } @@ -77,7 +76,7 @@ public List potentialsForNextUnassigned() ParameterSignature unassigned = nextUnassigned(); List assignments = getSupplier(unassigned).getValueSources(unassigned); - if (assignments.size() == 0) { + if (assignments.isEmpty()) { assignments = generateAssignmentsFromTypeAlone(unassigned); } diff --git a/src/main/java/org/junit/function/ThrowingRunnable.java b/src/main/java/org/junit/function/ThrowingRunnable.java new file mode 100644 index 000000000000..d0eb782ccd30 --- /dev/null +++ b/src/main/java/org/junit/function/ThrowingRunnable.java @@ -0,0 +1,14 @@ +package org.junit.function; + +/** + * This interface facilitates the use of + * {@link org.junit.Assert#assertThrows(Class, ThrowingRunnable)} from Java 8. It allows method + * references to void methods (that declare checked exceptions) to be passed directly into + * {@code assertThrows} + * without wrapping. It is not meant to be implemented directly. + * + * @since 4.13 + */ +public interface ThrowingRunnable { + void run() throws Throwable; +} diff --git a/src/main/java/org/junit/internal/ArrayComparisonFailure.java b/src/main/java/org/junit/internal/ArrayComparisonFailure.java index 8627d6ec3308..d300e7e5866b 100644 --- a/src/main/java/org/junit/internal/ArrayComparisonFailure.java +++ b/src/main/java/org/junit/internal/ArrayComparisonFailure.java @@ -16,11 +16,12 @@ public class ArrayComparisonFailure extends AssertionError { /* * We have to use the f prefix until the next major release to ensure - * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * serialization compatibility. + * See https://github.com/junit-team/junit4/issues/976 */ private final List fIndices = new ArrayList(); private final String fMessage; + private final AssertionError fCause; /** * Construct a new ArrayComparisonFailure with an error text and the array's @@ -32,7 +33,8 @@ public class ArrayComparisonFailure extends AssertionError { */ public ArrayComparisonFailure(String message, AssertionError cause, int index) { this.fMessage = message; - initCause(cause); + this.fCause = cause; + initCause(fCause); addDimension(index); } @@ -40,6 +42,11 @@ public void addDimension(int index) { fIndices.add(0, index); } + @Override + public synchronized Throwable getCause() { + return super.getCause() == null ? fCause : super.getCause(); + } + @Override public String getMessage() { StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/org/junit/internal/AssumptionViolatedException.java b/src/main/java/org/junit/internal/AssumptionViolatedException.java index 880d73f9af60..15c27af1b279 100644 --- a/src/main/java/org/junit/internal/AssumptionViolatedException.java +++ b/src/main/java/org/junit/internal/AssumptionViolatedException.java @@ -18,7 +18,7 @@ public class AssumptionViolatedException extends RuntimeException implements Sel /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * See https://github.com/junit-team/junit4/issues/976 */ private final String fAssumption; private final boolean fValueMatcher; diff --git a/src/main/java/org/junit/internal/Checks.java b/src/main/java/org/junit/internal/Checks.java new file mode 100644 index 000000000000..9724947f9977 --- /dev/null +++ b/src/main/java/org/junit/internal/Checks.java @@ -0,0 +1,37 @@ +package org.junit.internal; + +/** @since 4.13 */ +public final class Checks { + + private Checks() {} + + /** + * Checks that the given value is not {@code null}. + * + * @param value object reference to check + * @return the passed-in value, if not {@code null} + * @throws NullPointerException if {@code value} is {@code null} + */ + public static T notNull(T value) { + if (value == null) { + throw new NullPointerException(); + } + return value; + } + + /** + * Checks that the given value is not {@code null}, using the given message + * as the exception message if an exception is thrown. + * + * @param value object reference to check + * @param message message to use if {@code value} is {@code null} + * @return the passed-in value, if not {@code null} + * @throws NullPointerException if {@code value} is {@code null} + */ + public static T notNull(T value, String message) { + if (value == null) { + throw new NullPointerException(message); + } + return value; + } +} diff --git a/src/main/java/org/junit/internal/Classes.java b/src/main/java/org/junit/internal/Classes.java index 154603d2e4f6..e8404f685504 100644 --- a/src/main/java/org/junit/internal/Classes.java +++ b/src/main/java/org/junit/internal/Classes.java @@ -6,13 +6,39 @@ * Miscellaneous functions dealing with classes. */ public class Classes { + + /** + * Do not instantiate. + * @deprecated will be private soon. + */ + @Deprecated + public Classes() { + } + /** * Returns Class.forName for {@code className} using the current thread's class loader. + * If the current thread does not have a class loader, falls back to the class loader for + * {@link Classes}. * * @param className Name of the class. * @throws ClassNotFoundException */ public static Class getClass(String className) throws ClassNotFoundException { - return Class.forName(className, true, currentThread().getContextClassLoader()); + return getClass(className, Classes.class); + } + + /** + * Returns Class.forName for {@code className} using the current thread's class loader. + * If the current thread does not have a class loader, falls back to the class loader for the + * passed-in class. + * + * @param className Name of the class. + * @param callingClass Class that is requesting a the class + * @throws ClassNotFoundException + * @since 4.13 + */ + public static Class getClass(String className, Class callingClass) throws ClassNotFoundException { + ClassLoader classLoader = currentThread().getContextClassLoader(); + return Class.forName(className, true, classLoader == null ? callingClass.getClassLoader() : classLoader); } } diff --git a/src/main/java/org/junit/internal/ComparisonCriteria.java b/src/main/java/org/junit/internal/ComparisonCriteria.java index e6d49a4dc230..ed1c674907cb 100644 --- a/src/main/java/org/junit/internal/ComparisonCriteria.java +++ b/src/main/java/org/junit/internal/ComparisonCriteria.java @@ -25,6 +25,11 @@ public abstract class ComparisonCriteria { */ public void arrayEquals(String message, Object expecteds, Object actuals) throws ArrayComparisonFailure { + arrayEquals(message, expecteds, actuals, true); + } + + private void arrayEquals(String message, Object expecteds, Object actuals, boolean outer) + throws ArrayComparisonFailure { if (expecteds == actuals || Arrays.deepEquals(new Object[] {expecteds}, new Object[] {actuals})) { // The reflection-based loop below is potentially very slow, especially for primitive @@ -34,19 +39,37 @@ public void arrayEquals(String message, Object expecteds, Object actuals) } String header = message == null ? "" : message + ": "; - int expectedsLength = assertArraysAreSameLength(expecteds, - actuals, header); + // Only include the user-provided message in the outer exception. + String exceptionMessage = outer ? header : ""; + + if (expecteds == null) { + Assert.fail(exceptionMessage + "expected array was null"); + } + if (actuals == null) { + Assert.fail(exceptionMessage + "actual array was null"); + } + + int actualsLength = Array.getLength(actuals); + int expectedsLength = Array.getLength(expecteds); + if (actualsLength != expectedsLength) { + header += "array lengths differed, expected.length=" + + expectedsLength + " actual.length=" + actualsLength + "; "; + } + int prefixLength = Math.min(actualsLength, expectedsLength); - for (int i = 0; i < expectedsLength; i++) { + for (int i = 0; i < prefixLength; i++) { Object expected = Array.get(expecteds, i); Object actual = Array.get(actuals, i); if (isArray(expected) && isArray(actual)) { try { - arrayEquals(message, expected, actual); + arrayEquals(message, expected, actual, false); } catch (ArrayComparisonFailure e) { e.addDimension(i); throw e; + } catch (AssertionError e) { + // Array lengths differed. + throw new ArrayComparisonFailure(header, e, i); } } else { try { @@ -56,27 +79,53 @@ public void arrayEquals(String message, Object expecteds, Object actuals) } } } - } - private boolean isArray(Object expected) { - return expected != null && expected.getClass().isArray(); + if (actualsLength != expectedsLength) { + Object expected = getToStringableArrayElement(expecteds, expectedsLength, prefixLength); + Object actual = getToStringableArrayElement(actuals, actualsLength, prefixLength); + try { + Assert.assertEquals(expected, actual); + } catch (AssertionError e) { + throw new ArrayComparisonFailure(header, e, prefixLength); + } + } } - 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"); + private static final Object END_OF_ARRAY_SENTINEL = objectWithToString("end of array"); + + private Object getToStringableArrayElement(Object array, int length, int index) { + if (index < length) { + Object element = Array.get(array, index); + if (isArray(element)) { + return objectWithToString(componentTypeName(element.getClass()) + "[" + Array.getLength(element) + "]"); + } else { + return element; + } + } else { + return END_OF_ARRAY_SENTINEL; } - 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); + } + + private static Object objectWithToString(final String string) { + return new Object() { + @Override + public String toString() { + return string; + } + }; + } + + private String componentTypeName(Class arrayClass) { + Class componentType = arrayClass.getComponentType(); + if (componentType.isArray()) { + return componentTypeName(componentType) + "[]"; + } else { + return componentType.getName(); } - return expectedsLength; + } + + private boolean isArray(Object expected) { + return expected != null && expected.getClass().isArray(); } protected abstract void assertElementsEqual(Object expected, Object actual); diff --git a/src/main/java/org/junit/internal/TextListener.java b/src/main/java/org/junit/internal/TextListener.java index 9aa56c75f5ec..d548aeb26e99 100644 --- a/src/main/java/org/junit/internal/TextListener.java +++ b/src/main/java/org/junit/internal/TextListener.java @@ -58,7 +58,7 @@ protected void printHeader(long runTime) { protected void printFailures(Result result) { List failures = result.getFailures(); - if (failures.size() == 0) { + if (failures.isEmpty()) { return; } if (failures.size() == 1) { @@ -74,7 +74,7 @@ protected void printFailures(Result result) { protected void printFailure(Failure each, String prefix) { getWriter().println(prefix + ") " + each.getTestHeader()); - getWriter().print(each.getTrace()); + getWriter().print(each.getTrimmedTrace()); } protected void printFooter(Result result) { diff --git a/src/main/java/org/junit/internal/Throwables.java b/src/main/java/org/junit/internal/Throwables.java index 86dceeff2559..67d6b2bc06ec 100644 --- a/src/main/java/org/junit/internal/Throwables.java +++ b/src/main/java/org/junit/internal/Throwables.java @@ -1,5 +1,17 @@ package org.junit.internal; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + /** * Miscellaneous functions dealing with {@code Throwable}. * @@ -39,4 +51,220 @@ public static Exception rethrowAsException(Throwable e) throws Exception { private static void rethrow(Throwable e) throws T { throw (T) e; } + + /** + * Returns the stacktrace of the given Throwable as a String. + * + * @since 4.13 + */ + public static String getStacktrace(Throwable exception) { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + exception.printStackTrace(writer); + return stringWriter.toString(); + } + + /** + * Gets a trimmed version of the stack trace of the given exception. Stack trace + * elements that are below the test method are filtered out. + * + * @return a trimmed stack trace, or the original trace if trimming wasn't possible + */ + public static String getTrimmedStackTrace(Throwable exception) { + List trimmedStackTraceLines = getTrimmedStackTraceLines(exception); + if (trimmedStackTraceLines.isEmpty()) { + return getFullStackTrace(exception); + } + + StringBuilder result = new StringBuilder(exception.toString()); + appendStackTraceLines(trimmedStackTraceLines, result); + appendStackTraceLines(getCauseStackTraceLines(exception), result); + return result.toString(); + } + + private static List getTrimmedStackTraceLines(Throwable exception) { + List stackTraceElements = Arrays.asList(exception.getStackTrace()); + int linesToInclude = stackTraceElements.size(); + + State state = State.PROCESSING_OTHER_CODE; + for (StackTraceElement stackTraceElement : asReversedList(stackTraceElements)) { + state = state.processStackTraceElement(stackTraceElement); + if (state == State.DONE) { + List trimmedLines = new ArrayList(linesToInclude + 2); + trimmedLines.add(""); + for (StackTraceElement each : stackTraceElements.subList(0, linesToInclude)) { + trimmedLines.add("\tat " + each); + } + if (exception.getCause() != null) { + trimmedLines.add("\t... " + (stackTraceElements.size() - trimmedLines.size()) + " trimmed"); + } + return trimmedLines; + } + linesToInclude--; + } + return Collections.emptyList(); + } + + private static final Method getSuppressed = initGetSuppressed(); + + private static Method initGetSuppressed() { + try { + return Throwable.class.getMethod("getSuppressed"); + } catch (Throwable e) { + return null; + } + } + + private static boolean hasSuppressed(Throwable exception) { + if (getSuppressed == null) { + return false; + } + try { + Throwable[] suppressed = (Throwable[]) getSuppressed.invoke(exception); + return suppressed.length != 0; + } catch (Throwable e) { + return false; + } + } + + private static List getCauseStackTraceLines(Throwable exception) { + if (exception.getCause() != null || hasSuppressed(exception)) { + String fullTrace = getFullStackTrace(exception); + BufferedReader reader = new BufferedReader( + new StringReader(fullTrace.substring(exception.toString().length()))); + List causedByLines = new ArrayList(); + + try { + String line; + while ((line = reader.readLine()) != null) { + if (line.startsWith("Caused by: ") || line.trim().startsWith("Suppressed: ")) { + causedByLines.add(line); + while ((line = reader.readLine()) != null) { + causedByLines.add(line); + } + return causedByLines; + } + } + } catch (IOException e) { + // We should never get here, because we are reading from a StringReader + } + } + + return Collections.emptyList(); + } + + private static String getFullStackTrace(Throwable exception) { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + exception.printStackTrace(writer); + return stringWriter.toString(); + } + + private static void appendStackTraceLines( + List stackTraceLines, StringBuilder destBuilder) { + for (String stackTraceLine : stackTraceLines) { + destBuilder.append(String.format("%s%n", stackTraceLine)); + } + } + + private static List asReversedList(final List list) { + return new AbstractList() { + + @Override + public T get(int index) { + return list.get(list.size() - index - 1); + } + + @Override + public int size() { + return list.size(); + } + }; + } + + private enum State { + PROCESSING_OTHER_CODE { + @Override public State processLine(String methodName) { + if (isTestFrameworkMethod(methodName)) { + return PROCESSING_TEST_FRAMEWORK_CODE; + } + return this; + } + }, + PROCESSING_TEST_FRAMEWORK_CODE { + @Override public State processLine(String methodName) { + if (isReflectionMethod(methodName)) { + return PROCESSING_REFLECTION_CODE; + } else if (isTestFrameworkMethod(methodName)) { + return this; + } + return PROCESSING_OTHER_CODE; + } + }, + PROCESSING_REFLECTION_CODE { + @Override public State processLine(String methodName) { + if (isReflectionMethod(methodName)) { + return this; + } else if (isTestFrameworkMethod(methodName)) { + // This is here to handle TestCase.runBare() calling TestCase.runTest(). + return PROCESSING_TEST_FRAMEWORK_CODE; + } + return DONE; + } + }, + DONE { + @Override public State processLine(String methodName) { + return this; + } + }; + + /** Processes a stack trace element method name, possibly moving to a new state. */ + protected abstract State processLine(String methodName); + + /** Processes a stack trace element, possibly moving to a new state. */ + public final State processStackTraceElement(StackTraceElement element) { + return processLine(element.getClassName() + "." + element.getMethodName() + "()"); + } + } + + private static final String[] TEST_FRAMEWORK_METHOD_NAME_PREFIXES = { + "org.junit.runner.", + "org.junit.runners.", + "org.junit.experimental.runners.", + "org.junit.internal.", + "junit.", + }; + + private static final String[] TEST_FRAMEWORK_TEST_METHOD_NAME_PREFIXES = { + "org.junit.internal.StackTracesTest", + }; + + private static boolean isTestFrameworkMethod(String methodName) { + return isMatchingMethod(methodName, TEST_FRAMEWORK_METHOD_NAME_PREFIXES) && + !isMatchingMethod(methodName, TEST_FRAMEWORK_TEST_METHOD_NAME_PREFIXES); + } + + private static final String[] REFLECTION_METHOD_NAME_PREFIXES = { + "sun.reflect.", + "java.lang.reflect.", + "jdk.internal.reflect.", + "org.junit.rules.RunRules.(", + "org.junit.rules.RunRules.applyAll(", // calls TestRules + "org.junit.runners.RuleContainer.apply(", // calls MethodRules & TestRules + "junit.framework.TestCase.runBare(", // runBare() directly calls setUp() and tearDown() + }; + + private static boolean isReflectionMethod(String methodName) { + return isMatchingMethod(methodName, REFLECTION_METHOD_NAME_PREFIXES); + } + + private static boolean isMatchingMethod(String methodName, String[] methodNamePrefixes) { + for (String methodNamePrefix : methodNamePrefixes) { + if (methodName.startsWith(methodNamePrefix)) { + return true; + } + } + + return false; + } } diff --git a/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java b/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java index d86ec950f655..8704a546b5f2 100644 --- a/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java +++ b/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java @@ -9,6 +9,17 @@ public class AllDefaultPossibilitiesBuilder extends RunnerBuilder { private final boolean canUseSuiteMethod; + /** + * @since 4.13 + */ + public AllDefaultPossibilitiesBuilder() { + canUseSuiteMethod = true; + } + + /** + * @deprecated used {@link #AllDefaultPossibilitiesBuilder()}. + */ + @Deprecated public AllDefaultPossibilitiesBuilder(boolean canUseSuiteMethod) { this.canUseSuiteMethod = canUseSuiteMethod; } diff --git a/src/main/java/org/junit/internal/builders/JUnit4Builder.java b/src/main/java/org/junit/internal/builders/JUnit4Builder.java index 6a0067852cc6..7959e75239db 100644 --- a/src/main/java/org/junit/internal/builders/JUnit4Builder.java +++ b/src/main/java/org/junit/internal/builders/JUnit4Builder.java @@ -1,12 +1,12 @@ package org.junit.internal.builders; import org.junit.runner.Runner; -import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.JUnit4; import org.junit.runners.model.RunnerBuilder; public class JUnit4Builder extends RunnerBuilder { @Override public Runner runnerForClass(Class testClass) throws Throwable { - return new BlockJUnit4ClassRunner(testClass); + return new JUnit4(testClass); } -} \ No newline at end of file +} diff --git a/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java b/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java new file mode 100644 index 000000000000..477b1509ce45 --- /dev/null +++ b/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java @@ -0,0 +1,21 @@ +package org.junit.internal.management; + +import java.util.Collections; +import java.util.List; + +/** + * No-op implementation of RuntimeMXBean when the platform doesn't provide it. + */ +class FakeRuntimeMXBean implements RuntimeMXBean { + + /** + * {@inheritDoc} + * + *

    Always returns an empty list. + */ + public List getInputArguments() { + return Collections.emptyList(); + } + +} + diff --git a/src/main/java/org/junit/internal/management/FakeThreadMXBean.java b/src/main/java/org/junit/internal/management/FakeThreadMXBean.java new file mode 100644 index 000000000000..893f2e3ea583 --- /dev/null +++ b/src/main/java/org/junit/internal/management/FakeThreadMXBean.java @@ -0,0 +1,27 @@ +package org.junit.internal.management; + +/** + * No-op implementation of ThreadMXBean when the platform doesn't provide it. + */ +final class FakeThreadMXBean implements ThreadMXBean { + + /** + * {@inheritDoc} + * + *

    Always throws an {@link UnsupportedOperationException} + */ + public long getThreadCpuTime(long id) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + * + *

    Always returns false. + */ + public boolean isThreadCpuTimeSupported() { + return false; + } + +} + diff --git a/src/main/java/org/junit/internal/management/ManagementFactory.java b/src/main/java/org/junit/internal/management/ManagementFactory.java new file mode 100644 index 000000000000..5be1447532e9 --- /dev/null +++ b/src/main/java/org/junit/internal/management/ManagementFactory.java @@ -0,0 +1,77 @@ +package org.junit.internal.management; + +import org.junit.internal.Classes; + +import java.lang.reflect.InvocationTargetException; + +/** + * Reflective wrapper around {@link java.lang.management.ManagementFactory} + */ +public class ManagementFactory { + private static final class FactoryHolder { + private static final Class MANAGEMENT_FACTORY_CLASS; + + static { + Class managementFactoryClass = null; + try { + managementFactoryClass = Classes.getClass("java.lang.management.ManagementFactory"); + } catch (ClassNotFoundException e) { + // do nothing, managementFactoryClass will be none on failure + } + MANAGEMENT_FACTORY_CLASS = managementFactoryClass; + } + + static Object getBeanObject(String methodName) { + if (MANAGEMENT_FACTORY_CLASS != null) { + try { + return MANAGEMENT_FACTORY_CLASS.getMethod(methodName).invoke(null); + } catch (IllegalAccessException e) { + // fallthrough + } catch (IllegalArgumentException e) { + // fallthrough + } catch (InvocationTargetException e) { + // fallthrough + } catch (NoSuchMethodException e) { + // fallthrough + } catch (SecurityException e) { + // fallthrough + } + } + return null; + } + } + + private static final class RuntimeHolder { + private static final RuntimeMXBean RUNTIME_MX_BEAN = + getBean(FactoryHolder.getBeanObject("getRuntimeMXBean")); + + private static final RuntimeMXBean getBean(Object runtimeMxBean) { + return runtimeMxBean != null + ? new ReflectiveRuntimeMXBean(runtimeMxBean) : new FakeRuntimeMXBean(); + } + } + + private static final class ThreadHolder { + private static final ThreadMXBean THREAD_MX_BEAN = + getBean(FactoryHolder.getBeanObject("getThreadMXBean")); + + private static final ThreadMXBean getBean(Object threadMxBean) { + return threadMxBean != null + ? new ReflectiveThreadMXBean(threadMxBean) : new FakeThreadMXBean(); + } + } + + /** + * @see java.lang.management.ManagementFactory#getRuntimeMXBean() + */ + public static RuntimeMXBean getRuntimeMXBean() { + return RuntimeHolder.RUNTIME_MX_BEAN; + } + + /** + * @see java.lang.management.ManagementFactory#getThreadMXBean() + */ + public static ThreadMXBean getThreadMXBean() { + return ThreadHolder.THREAD_MX_BEAN; + } +} diff --git a/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java b/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java new file mode 100644 index 000000000000..289587a44776 --- /dev/null +++ b/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java @@ -0,0 +1,61 @@ +package org.junit.internal.management; + +import org.junit.internal.Classes; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; + +/** + * Implementation of {@link RuntimeMXBean} using the JVM reflectively. + */ +final class ReflectiveRuntimeMXBean implements RuntimeMXBean { + private final Object runtimeMxBean; + + private static final class Holder { + private static final Method getInputArgumentsMethod; + static { + Method inputArguments = null; + try { + Class threadMXBeanClass = Classes.getClass("java.lang.management.RuntimeMXBean"); + inputArguments = threadMXBeanClass.getMethod("getInputArguments"); + } catch (ClassNotFoundException e) { + // do nothing, input arguments will be null on failure + } catch (NoSuchMethodException e) { + // do nothing, input arguments will be null on failure + } catch (SecurityException e) { + // do nothing, input arguments will be null on failure + } + getInputArgumentsMethod = inputArguments; + } + } + + ReflectiveRuntimeMXBean(Object runtimeMxBean) { + super(); + this.runtimeMxBean = runtimeMxBean; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + public List getInputArguments() { + if (Holder.getInputArgumentsMethod != null) { + try { + return (List) Holder.getInputArgumentsMethod.invoke(runtimeMxBean); + } catch (ClassCastException e) { // no multi-catch with source level 6 + // fallthrough + } catch (IllegalAccessException e) { + // fallthrough + } catch (IllegalArgumentException e) { + // fallthrough + } catch (InvocationTargetException e) { + // fallthrough + } + } + return Collections.emptyList(); + } + +} + diff --git a/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java b/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java new file mode 100644 index 000000000000..bc741bec8e61 --- /dev/null +++ b/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java @@ -0,0 +1,92 @@ +package org.junit.internal.management; + +import org.junit.internal.Classes; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Implementation of {@link ThreadMXBean} using the JVM reflectively. + */ +final class ReflectiveThreadMXBean implements ThreadMXBean { + private final Object threadMxBean; + + + private static final class Holder { + static final Method getThreadCpuTimeMethod; + static final Method isThreadCpuTimeSupportedMethod; + + private static final String FAILURE_MESSAGE = "Unable to access ThreadMXBean"; + + static { + Method threadCpuTime = null; + Method threadCpuTimeSupported = null; + try { + Class threadMXBeanClass = Classes.getClass("java.lang.management.ThreadMXBean"); + threadCpuTime = threadMXBeanClass.getMethod("getThreadCpuTime", long.class); + threadCpuTimeSupported = threadMXBeanClass.getMethod("isThreadCpuTimeSupported"); + } catch (ClassNotFoundException e) { + // do nothing, the methods will be null on failure + } catch (NoSuchMethodException e) { + // do nothing, the methods will be null on failure + } catch (SecurityException e) { + // do nothing, the methods will be null on failure + } + getThreadCpuTimeMethod = threadCpuTime; + isThreadCpuTimeSupportedMethod = threadCpuTimeSupported; + } + } + + ReflectiveThreadMXBean(Object threadMxBean) { + super(); + this.threadMxBean = threadMxBean; + } + + /** + * {@inheritDoc} + */ + public long getThreadCpuTime(long id) { + if (Holder.getThreadCpuTimeMethod != null) { + Exception error = null; + try { + return (Long) Holder.getThreadCpuTimeMethod.invoke(threadMxBean, id); + } catch (ClassCastException e) { + error = e; + // fallthrough + } catch (IllegalAccessException e) { + error = e; + // fallthrough + } catch (IllegalArgumentException e) { + error = e; + // fallthrough + } catch (InvocationTargetException e) { + error = e; + // fallthrough + } + throw new UnsupportedOperationException(Holder.FAILURE_MESSAGE, error); + } + throw new UnsupportedOperationException(Holder.FAILURE_MESSAGE); + } + + /** + * {@inheritDoc} + */ + public boolean isThreadCpuTimeSupported() { + if (Holder.isThreadCpuTimeSupportedMethod != null) { + try { + return (Boolean) Holder.isThreadCpuTimeSupportedMethod.invoke(threadMxBean); + } catch (ClassCastException e) { + // fallthrough + } catch (IllegalAccessException e) { + // fallthrough + } catch (IllegalArgumentException e) { + // fallthrough + } catch (InvocationTargetException e) { + // fallthrough + } + } + return false; + } + +} + diff --git a/src/main/java/org/junit/internal/management/RuntimeMXBean.java b/src/main/java/org/junit/internal/management/RuntimeMXBean.java new file mode 100644 index 000000000000..84f8861f2fed --- /dev/null +++ b/src/main/java/org/junit/internal/management/RuntimeMXBean.java @@ -0,0 +1,14 @@ +package org.junit.internal.management; + +import java.util.List; + +/** + * Wrapper for {@link java.lang.management.RuntimeMXBean}. + */ +public interface RuntimeMXBean { + + /** + * @see java.lang.management.RuntimeMXBean#getInputArguments() + */ + List getInputArguments(); +} diff --git a/src/main/java/org/junit/internal/management/ThreadMXBean.java b/src/main/java/org/junit/internal/management/ThreadMXBean.java new file mode 100644 index 000000000000..f9225c9fb888 --- /dev/null +++ b/src/main/java/org/junit/internal/management/ThreadMXBean.java @@ -0,0 +1,17 @@ +package org.junit.internal.management; + +/** + * Wrapper for {@link java.lang.management.ThreadMXBean}. + */ +public interface ThreadMXBean { + /** + * @see java.lang.management.ThreadMXBean#getThreadCpuTime(long) + */ + long getThreadCpuTime(long id); + + /** + * @see java.lang.management.ThreadMXBean#isThreadCpuTimeSupported() + */ + boolean isThreadCpuTimeSupported(); +} + diff --git a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java index 5d45ba3d03af..93a6827678d0 100644 --- a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java +++ b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java @@ -1,12 +1,11 @@ package org.junit.internal.matchers; -import java.io.PrintWriter; -import java.io.StringWriter; - import org.hamcrest.Description; import org.hamcrest.Factory; import org.hamcrest.Matcher; +import org.junit.internal.Throwables; + /** * A matcher that delegates to throwableMatcher and in addition appends the * stacktrace of the actual Throwable in case of a mismatch. @@ -37,9 +36,7 @@ protected void describeMismatchSafely(T item, Description description) { } private String readStacktrace(Throwable throwable) { - StringWriter stringWriter = new StringWriter(); - throwable.printStackTrace(new PrintWriter(stringWriter)); - return stringWriter.toString(); + return Throwables.getStacktrace(throwable); } @Factory diff --git a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java index 22ce8bd59341..6e2ff5e3d565 100644 --- a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java +++ b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java @@ -14,9 +14,9 @@ public class ThrowableCauseMatcher extends TypeSafeMatcher { - private final Matcher causeMatcher; + private final Matcher causeMatcher; - public ThrowableCauseMatcher(Matcher causeMatcher) { + public ThrowableCauseMatcher(Matcher causeMatcher) { this.causeMatcher = causeMatcher; } @@ -44,7 +44,7 @@ protected void describeMismatchSafely(T item, Description description) { * @param type of the outer exception */ @Factory - public static Matcher hasCause(final Matcher matcher) { + public static Matcher hasCause(final Matcher matcher) { return new ThrowableCauseMatcher(matcher); } } \ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java index 4e2cc1264d09..fb25982bbd4d 100644 --- a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java +++ b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java @@ -40,7 +40,7 @@ private static Class findExpectedType(Class fromClass) { } private static boolean isMatchesSafelyMethod(Method method) { - return method.getName().equals("matchesSafely") + return "matchesSafely".equals(method.getName()) && method.getParameterTypes().length == 1 && !method.isSynthetic(); } diff --git a/src/main/java/org/junit/internal/requests/ClassRequest.java b/src/main/java/org/junit/internal/requests/ClassRequest.java index 3d6b10066099..d60e36062d81 100644 --- a/src/main/java/org/junit/internal/requests/ClassRequest.java +++ b/src/main/java/org/junit/internal/requests/ClassRequest.java @@ -1,20 +1,18 @@ package org.junit.internal.requests; import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; -import org.junit.runner.Request; +import org.junit.internal.builders.SuiteMethodBuilder; import org.junit.runner.Runner; +import org.junit.runners.model.RunnerBuilder; -public class ClassRequest extends Request { - private final Object runnerLock = new Object(); - +public class ClassRequest extends MemoizingRequest { /* * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses * reflection to access this field. See - * https://github.com/junit-team/junit/issues/960 + * https://github.com/junit-team/junit4/issues/960 */ private final Class fTestClass; private final boolean canUseSuiteMethod; - private volatile Runner runner; public ClassRequest(Class testClass, boolean canUseSuiteMethod) { this.fTestClass = testClass; @@ -26,14 +24,31 @@ public ClassRequest(Class testClass) { } @Override - public Runner getRunner() { - if (runner == null) { - synchronized (runnerLock) { - if (runner == null) { - runner = new AllDefaultPossibilitiesBuilder(canUseSuiteMethod).safeRunnerForClass(fTestClass); - } + protected Runner createRunner() { + return new CustomAllDefaultPossibilitiesBuilder().safeRunnerForClass(fTestClass); + } + + private class CustomAllDefaultPossibilitiesBuilder extends AllDefaultPossibilitiesBuilder { + + @Override + protected RunnerBuilder suiteMethodBuilder() { + return new CustomSuiteMethodBuilder(); + } + } + + /* + * Customization of {@link SuiteMethodBuilder} that prevents use of the + * suite method when creating a runner for fTestClass when canUseSuiteMethod + * is false. + */ + private class CustomSuiteMethodBuilder extends SuiteMethodBuilder { + + @Override + public Runner runnerForClass(Class testClass) throws Throwable { + if (testClass == fTestClass && !canUseSuiteMethod) { + return null; } + return super.runnerForClass(testClass); } - return runner; } } \ No newline at end of file diff --git a/src/main/java/org/junit/internal/requests/FilterRequest.java b/src/main/java/org/junit/internal/requests/FilterRequest.java index 066cba322205..5f00399557c2 100644 --- a/src/main/java/org/junit/internal/requests/FilterRequest.java +++ b/src/main/java/org/junit/internal/requests/FilterRequest.java @@ -14,7 +14,7 @@ public final class FilterRequest extends Request { /* * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses * reflection to access this field. See - * https://github.com/junit-team/junit/issues/960 + * https://github.com/junit-team/junit4/issues/960 */ private final Filter fFilter; diff --git a/src/main/java/org/junit/internal/requests/MemoizingRequest.java b/src/main/java/org/junit/internal/requests/MemoizingRequest.java new file mode 100644 index 000000000000..191c23022536 --- /dev/null +++ b/src/main/java/org/junit/internal/requests/MemoizingRequest.java @@ -0,0 +1,30 @@ +package org.junit.internal.requests; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.junit.runner.Request; +import org.junit.runner.Runner; + +abstract class MemoizingRequest extends Request { + private final Lock runnerLock = new ReentrantLock(); + private volatile Runner runner; + + @Override + public final Runner getRunner() { + if (runner == null) { + runnerLock.lock(); + try { + if (runner == null) { + runner = createRunner(); + } + } finally { + runnerLock.unlock(); + } + } + return runner; + } + + /** Creates the {@link Runner} to return from {@link #getRunner()}. Called at most once. */ + protected abstract Runner createRunner(); +} diff --git a/src/main/java/org/junit/internal/requests/OrderingRequest.java b/src/main/java/org/junit/internal/requests/OrderingRequest.java new file mode 100644 index 000000000000..441e595a3680 --- /dev/null +++ b/src/main/java/org/junit/internal/requests/OrderingRequest.java @@ -0,0 +1,29 @@ +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.InvalidOrderingException; +import org.junit.runner.manipulation.Ordering; + +/** @since 4.13 */ +public class OrderingRequest extends MemoizingRequest { + private final Request request; + private final Ordering ordering; + + public OrderingRequest(Request request, Ordering ordering) { + this.request = request; + this.ordering = ordering; + } + + @Override + protected Runner createRunner() { + Runner runner = request.getRunner(); + try { + ordering.apply(runner); + } catch (InvalidOrderingException e) { + return new ErrorReportingRunner(ordering.getClass(), e); + } + return runner; + } +} diff --git a/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java b/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java index 1d32bebe1f09..f52abab69439 100644 --- a/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java +++ b/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java @@ -1,33 +1,44 @@ 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.InvalidTestClassError; import org.junit.runners.model.InitializationError; +import static java.util.Collections.singletonList; + public class ErrorReportingRunner extends Runner { private final List causes; - private final Class testClass; + private final String classNames; public ErrorReportingRunner(Class testClass, Throwable cause) { - if (testClass == null) { - throw new NullPointerException("Test class cannot be null"); + this(cause, testClass); + } + + public ErrorReportingRunner(Throwable cause, Class... testClasses) { + if (testClasses == null || testClasses.length == 0) { + throw new NullPointerException("Test classes cannot be null or empty"); } - this.testClass = testClass; + for (Class testClass : testClasses) { + if (testClass == null) { + throw new NullPointerException("Test class cannot be null"); + } + } + classNames = getClassNames(testClasses); causes = getCauses(cause); } - + @Override public Description getDescription() { - Description description = Description.createSuiteDescription(testClass); + Description description = Description.createSuiteDescription(classNames); for (Throwable each : causes) { - description.addChild(describeCause(each)); + description.addChild(describeCause()); } return description; } @@ -39,11 +50,25 @@ public void run(RunNotifier notifier) { } } + private String getClassNames(Class... testClasses) { + final StringBuilder builder = new StringBuilder(); + for (Class testClass : testClasses) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(testClass.getName()); + } + return builder.toString(); + } + @SuppressWarnings("deprecation") private List getCauses(Throwable cause) { if (cause instanceof InvocationTargetException) { return getCauses(cause.getCause()); } + if (cause instanceof InvalidTestClassError) { + return singletonList(cause); + } if (cause instanceof InitializationError) { return ((InitializationError) cause).getCauses(); } @@ -51,16 +76,15 @@ private List getCauses(Throwable cause) { return ((org.junit.internal.runners.InitializationError) cause) .getCauses(); } - return Arrays.asList(cause); + return singletonList(cause); } - private Description describeCause(Throwable child) { - return Description.createTestDescription(testClass, - "initializationError"); + private Description describeCause() { + return Description.createTestDescription(classNames, "initializationError"); } private void runCause(Throwable child, RunNotifier notifier) { - Description description = describeCause(child); + Description description = describeCause(); notifier.fireTestStarted(description); notifier.fireTestFailure(new Failure(description, child)); notifier.fireTestFinished(description); diff --git a/src/main/java/org/junit/internal/runners/InitializationError.java b/src/main/java/org/junit/internal/runners/InitializationError.java index 52065ecc6068..484f58d26d69 100644 --- a/src/main/java/org/junit/internal/runners/InitializationError.java +++ b/src/main/java/org/junit/internal/runners/InitializationError.java @@ -15,7 +15,7 @@ public class InitializationError extends Exception { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * See https://github.com/junit-team/junit4/issues/976 */ private final List fErrors; diff --git a/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java b/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java index 631fcf2e5904..0d51541adcf8 100644 --- a/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java +++ b/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java @@ -1,5 +1,8 @@ package org.junit.internal.runners; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + import junit.extensions.TestDecorator; import junit.framework.AssertionFailedError; import junit.framework.Test; @@ -12,15 +15,16 @@ import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.Filterable; +import org.junit.runner.manipulation.Orderer; +import org.junit.runner.manipulation.InvalidOrderingException; import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runner.manipulation.Orderable; 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 java.lang.annotation.Annotation; -import java.lang.reflect.Method; -public class JUnit38ClassRunner extends Runner implements Filterable, Sortable { +public class JUnit38ClassRunner extends Runner implements Filterable, Orderable { private static final class OldTestClassAdaptingListener implements TestListener { private final RunNotifier notifier; @@ -170,6 +174,18 @@ public void sort(Sorter sorter) { } } + /** + * {@inheritDoc} + * + * @since 4.13 + */ + public void order(Orderer orderer) throws InvalidOrderingException { + if (getTest() instanceof Orderable) { + Orderable adapter = (Orderable) getTest(); + adapter.order(orderer); + } + } + private void setTest(Test test) { this.test = test; } diff --git a/src/main/java/org/junit/internal/runners/MethodValidator.java b/src/main/java/org/junit/internal/runners/MethodValidator.java index ba9c9d1546ba..e656ee50efea 100644 --- a/src/main/java/org/junit/internal/runners/MethodValidator.java +++ b/src/main/java/org/junit/internal/runners/MethodValidator.java @@ -86,7 +86,7 @@ private void validateTestMethods(Class annotation, } if (each.getReturnType() != Void.TYPE) { errors.add(new Exception("Method " + each.getName() - + " should be void")); + + "should have a return type of void")); } if (each.getParameterTypes().length != 0) { errors.add(new Exception("Method " + each.getName() diff --git a/src/main/java/org/junit/internal/runners/TestClass.java b/src/main/java/org/junit/internal/runners/TestClass.java index 1abaeeab688a..6d24f4fb05af 100644 --- a/src/main/java/org/junit/internal/runners/TestClass.java +++ b/src/main/java/org/junit/internal/runners/TestClass.java @@ -85,7 +85,7 @@ private boolean isShadowed(Method current, Method previous) { } private List> getSuperClasses(Class testClass) { - ArrayList> results = new ArrayList>(); + List> results = new ArrayList>(); Class current = testClass; while (current != null) { results.add(current); diff --git a/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java b/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java index e094809fdf91..c5a0764e6a47 100644 --- a/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java +++ b/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java @@ -45,4 +45,27 @@ public void fireTestStarted() { public void fireTestIgnored() { notifier.fireTestIgnored(description); } + + /** + * Calls {@link RunNotifier#fireTestSuiteStarted(Description)}, passing the + * {@link Description} that was passed to the {@code EachTestNotifier} constructor. + * This should be called when a test suite is about to be started. + * @see RunNotifier#fireTestSuiteStarted(Description) + * @since 4.13 + */ + public void fireTestSuiteStarted() { + notifier.fireTestSuiteStarted(description); + } + + /** + * Calls {@link RunNotifier#fireTestSuiteFinished(Description)}, passing the + * {@link Description} that was passed to the {@code EachTestNotifier} constructor. + * This should be called when a test suite has finished, whether the test suite succeeds + * or fails. + * @see RunNotifier#fireTestSuiteFinished(Description) + * @since 4.13 + */ + public void fireTestSuiteFinished() { + notifier.fireTestSuiteFinished(description); + } } \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/rules/ValidationError.java b/src/main/java/org/junit/internal/runners/rules/ValidationError.java index d1af8ae7b744..31bd66019e09 100644 --- a/src/main/java/org/junit/internal/runners/rules/ValidationError.java +++ b/src/main/java/org/junit/internal/runners/rules/ValidationError.java @@ -5,6 +5,9 @@ import java.lang.annotation.Annotation; class ValidationError extends Exception { + + private static final long serialVersionUID = 3176511008672645574L; + public ValidationError(FrameworkMember member, Class annotation, String suffix) { super(String.format("The @%s '%s' %s", annotation.getSimpleName(), member.getName(), suffix)); } diff --git a/src/main/java/org/junit/internal/runners/statements/ExpectException.java b/src/main/java/org/junit/internal/runners/statements/ExpectException.java index d0636bd78bbb..9a2a952858a3 100644 --- a/src/main/java/org/junit/internal/runners/statements/ExpectException.java +++ b/src/main/java/org/junit/internal/runners/statements/ExpectException.java @@ -19,7 +19,9 @@ public void evaluate() throws Exception { next.evaluate(); complete = true; } catch (AssumptionViolatedException e) { - throw e; + if (!expected.isAssignableFrom(e.getClass())) { + throw e; + } } catch (Throwable e) { if (!expected.isAssignableFrom(e.getClass())) { String message = "Unexpected exception, expected<" diff --git a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java index 7f4f0d521b16..94c12e6e9770 100644 --- a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java +++ b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java @@ -1,8 +1,8 @@ package org.junit.internal.runners.statements; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -10,6 +10,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.internal.management.ManagementFactory; +import org.junit.internal.management.ThreadMXBean; import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; import org.junit.runners.model.TestTimedOutException; @@ -19,7 +21,6 @@ public class FailOnTimeout extends Statement { private final TimeUnit timeUnit; private final long timeout; private final boolean lookForStuckThread; - private volatile ThreadGroup threadGroup = null; /** * Returns a new builder for building an instance. @@ -119,14 +120,28 @@ public FailOnTimeout build(Statement statement) { public void evaluate() throws Throwable { CallableStatement callable = new CallableStatement(); FutureTask task = new FutureTask(callable); - threadGroup = new ThreadGroup("FailOnTimeoutGroup"); + ThreadGroup threadGroup = new ThreadGroup("FailOnTimeoutGroup"); Thread thread = new Thread(threadGroup, task, "Time-limited test"); - thread.setDaemon(true); - thread.start(); - callable.awaitStarted(); - Throwable throwable = getResult(task, thread); - if (throwable != null) { - throw throwable; + try { + thread.setDaemon(true); + thread.start(); + callable.awaitStarted(); + Throwable throwable = getResult(task, thread); + if (throwable != null) { + throw throwable; + } + } finally { + try { + thread.join(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + try { + threadGroup.destroy(); + } catch (IllegalThreadStateException e) { + // If a thread from the group is still alive, the ThreadGroup cannot be destroyed. + // Swallow the exception to keep the same behavior prior to this change. + } } } @@ -162,7 +177,7 @@ private Exception createTimeoutException(Thread thread) { } if (stuckThread != null) { Exception stuckThreadException = - new Exception ("Appears to be stuck in thread " + + new Exception("Appears to be stuck in thread " + stuckThread.getName()); stuckThreadException.setStackTrace(getStackTrace(stuckThread)); return new MultipleFailureException( @@ -197,11 +212,8 @@ private StackTraceElement[] getStackTrace(Thread thread) { * to {@code mainThread}. */ private Thread getStuckThread(Thread mainThread) { - if (threadGroup == null) { - return null; - } - Thread[] threadsInGroup = getThreadArray(threadGroup); - if (threadsInGroup == null) { + List threadsInGroup = getThreadsInGroup(mainThread.getThreadGroup()); + if (threadsInGroup.isEmpty()) { return null; } @@ -228,49 +240,27 @@ private Thread getStuckThread(Thread mainThread) { * Returns all active threads belonging to a thread group. * @param group The thread group. * @return The active threads in the thread group. The result should be a - * complete list of the active threads at some point in time. Returns {@code null} + * complete list of the active threads at some point in time. Returns an empty list * if this cannot be determined, e.g. because new threads are being created at an * extremely fast rate. */ - private Thread[] getThreadArray(ThreadGroup group) { - final int count = group.activeCount(); // this is just an estimate - int enumSize = Math.max(count * 2, 100); - int enumCount; - Thread[] threads; - int loopCount = 0; - while (true) { - threads = new Thread[enumSize]; - enumCount = group.enumerate(threads); - if (enumCount < enumSize) { - break; + private List getThreadsInGroup(ThreadGroup group) { + final int activeThreadCount = group.activeCount(); // this is just an estimate + int threadArraySize = Math.max(activeThreadCount * 2, 100); + for (int loopCount = 0; loopCount < 5; loopCount++) { + Thread[] threads = new Thread[threadArraySize]; + int enumCount = group.enumerate(threads); + if (enumCount < threadArraySize) { + return Arrays.asList(threads).subList(0, enumCount); } // if there are too many threads to fit into the array, enumerate's result // is >= the array's length; therefore we can't trust that it returned all // the threads. Try again. - enumSize += 100; - if (++loopCount >= 5) { - return null; - } - // threads are proliferating too fast for us. Bail before we get into - // trouble. - } - return copyThreads(threads, enumCount); - } - - /** - * Returns an array of the first {@code count} Threads in {@code threads}. - * (Use instead of Arrays.copyOf to maintain compatibility with Java 1.5.) - * @param threads The source array. - * @param count The maximum length of the result array. - * @return The first {@count} (at most) elements of {@code threads}. - */ - private Thread[] copyThreads(Thread[] threads, int count) { - int length = Math.min(count, threads.length); - Thread[] result = new Thread[length]; - for (int i = 0; i < length; i++) { - result[i] = threads[i]; + threadArraySize += 100; } - return result; + // threads are proliferating too fast for us. Bail before we get into + // trouble. + return Collections.emptyList(); } /** @@ -278,7 +268,7 @@ private Thread[] copyThreads(Thread[] threads, int count) { * @param thr The thread to query. * @return The CPU time used by {@code thr}, or 0 if it cannot be determined. */ - private long cpuTime (Thread thr) { + private long cpuTime(Thread thr) { ThreadMXBean mxBean = ManagementFactory.getThreadMXBean(); if (mxBean.isThreadCpuTimeSupported()) { try { diff --git a/src/main/java/org/junit/internal/runners/statements/RunAfters.java b/src/main/java/org/junit/internal/runners/statements/RunAfters.java index 7512a7d61f40..5e56c3350ac1 100644 --- a/src/main/java/org/junit/internal/runners/statements/RunAfters.java +++ b/src/main/java/org/junit/internal/runners/statements/RunAfters.java @@ -30,7 +30,7 @@ public void evaluate() throws Throwable { } finally { for (FrameworkMethod each : afters) { try { - each.invokeExplosively(target); + invokeMethod(each); } catch (Throwable e) { errors.add(e); } @@ -38,4 +38,11 @@ public void evaluate() throws Throwable { } MultipleFailureException.assertEmpty(errors); } + + /** + * @since 4.13 + */ + protected void invokeMethod(FrameworkMethod method) throws Throwable { + method.invokeExplosively(target); + } } \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/statements/RunBefores.java b/src/main/java/org/junit/internal/runners/statements/RunBefores.java index 238fbe7d07a5..bd835c772530 100644 --- a/src/main/java/org/junit/internal/runners/statements/RunBefores.java +++ b/src/main/java/org/junit/internal/runners/statements/RunBefores.java @@ -21,8 +21,15 @@ public RunBefores(Statement next, List befores, Object target) @Override public void evaluate() throws Throwable { for (FrameworkMethod before : befores) { - before.invokeExplosively(target); + invokeMethod(before); } next.evaluate(); } + + /** + * @since 4.13 + */ + protected void invokeMethod(FrameworkMethod method) throws Throwable { + method.invokeExplosively(target); + } } \ No newline at end of file diff --git a/src/main/java/org/junit/rules/DisableOnDebug.java b/src/main/java/org/junit/rules/DisableOnDebug.java index afa6dee7d735..3bca103ed5a4 100644 --- a/src/main/java/org/junit/rules/DisableOnDebug.java +++ b/src/main/java/org/junit/rules/DisableOnDebug.java @@ -1,9 +1,9 @@ package org.junit.rules; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; import java.util.List; +import org.junit.internal.management.ManagementFactory; +import org.junit.internal.management.RuntimeMXBean; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -103,9 +103,7 @@ public Statement apply(Statement base, Description description) { */ private static boolean isDebugging(List arguments) { for (final String argument : arguments) { - if ("-Xdebug".equals(argument)) { - return true; - } else if (argument.startsWith("-agentlib:jdwp")) { + if ("-Xdebug".equals(argument) || argument.startsWith("-agentlib:jdwp")) { return true; } } diff --git a/src/main/java/org/junit/rules/ErrorCollector.java b/src/main/java/org/junit/rules/ErrorCollector.java index 8c6600e882e4..9711e50358f7 100644 --- a/src/main/java/org/junit/rules/ErrorCollector.java +++ b/src/main/java/org/junit/rules/ErrorCollector.java @@ -1,11 +1,14 @@ package org.junit.rules; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertThrows; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; +import org.junit.function.ThrowingRunnable; +import org.junit.internal.AssumptionViolatedException; import org.hamcrest.Matcher; import org.junit.runners.model.MultipleFailureException; @@ -43,7 +46,16 @@ protected void verify() throws Throwable { * Adds a Throwable to the table. Execution continues, but the test will fail at the end. */ public void addError(Throwable error) { - errors.add(error); + if (error == null) { + throw new NullPointerException("Error cannot be null"); + } + if (error instanceof AssumptionViolatedException) { + AssertionError e = new AssertionError(error.getMessage()); + e.initCause(error); + errors.add(e); + } else { + errors.add(error); + } } /** @@ -76,9 +88,33 @@ public Object call() throws Exception { public T checkSucceeds(Callable callable) { try { return callable.call(); + } catch (AssumptionViolatedException e) { + AssertionError error = new AssertionError("Callable threw AssumptionViolatedException"); + error.initCause(e); + addError(error); + return null; } catch (Throwable e) { addError(e); return null; } } + + /** + * Adds a failure to the table if {@code runnable} does not throw an + * exception of type {@code expectedThrowable} when executed. + * Execution continues, but the test will fail at the end if the runnable + * does not throw an exception, or if it throws a different exception. + * + * @param expectedThrowable the expected type of the exception + * @param runnable a function that is expected to throw an exception when executed + * @since 4.13 + */ + public void checkThrows(Class expectedThrowable, ThrowingRunnable runnable) { + try { + assertThrows(expectedThrowable, runnable); + } catch (AssertionError e) { + addError(e); + } + } + } diff --git a/src/main/java/org/junit/rules/ExpectedException.java b/src/main/java/org/junit/rules/ExpectedException.java index 4d61712803a0..431ad495b12f 100644 --- a/src/main/java/org/junit/rules/ExpectedException.java +++ b/src/main/java/org/junit/rules/ExpectedException.java @@ -7,7 +7,6 @@ import static org.junit.Assert.fail; import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause; import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; - import org.hamcrest.Matcher; import org.hamcrest.StringDescription; import org.junit.AssumptionViolatedException; @@ -21,7 +20,7 @@ * *

     public class SimpleExpectedExceptionTest {
      *     @Rule
    - *     public ExpectedException thrown= ExpectedException.none();
    + *     public ExpectedException thrown = ExpectedException.none();
      *
      *     @Test
      *     public void throwsNothing() {
    @@ -35,16 +34,19 @@
      *     }
      * }
    * - *

    - * You have to add the {@code ExpectedException} rule to your test. + *

    You have to add the {@code ExpectedException} rule to your test. * This doesn't affect your existing tests (see {@code throwsNothing()}). - * After specifiying the type of the expected exception your test is + * After specifying the type of the expected exception your test is * successful when such an exception is thrown and it fails if a * different or no exception is thrown. * - *

    - * Instead of specifying the exception's type you can characterize the - * expected exception based on other criterias, too: + *

    This rule does not perform any special magic to make execution continue + * as if the exception had not been thrown. So it is nearly always a mistake + * for a test method to have statements after the one that is expected to + * throw the exception. + * + *

    Instead of specifying the exception's type you can characterize the + * expected exception based on other criteria, too: * *

      *
    • The exception's message contains a specific text: {@link #expectMessage(String)}
    • @@ -53,8 +55,7 @@ *
    • The exception itself complies with a Hamcrest matcher: {@link #expect(Matcher)}
    • *
    * - *

    - * You can combine any of the presented expect-methods. The test is + *

    You can combine any of the presented expect-methods. The test is * successful if all specifications are met. *

     @Test
      * public void throwsException() {
    @@ -63,9 +64,15 @@
      *     throw new NullPointerException("What happened?");
      * }
    * + *

    It is recommended to set the {@link org.junit.Rule#order() order} of the + * {@code ExpectedException} to {@code Integer.MAX_VALUE} if it is used together + * with another rule that handles exceptions, e.g. {@link ErrorCollector}. + * Otherwise failing tests may be successful. + *

     @Rule(order = Integer.MAX_VALUE)
    + * public ExpectedException thrown = ExpectedException.none();
    + * *

    AssumptionViolatedExceptions

    - *

    - * JUnit uses {@link AssumptionViolatedException}s for indicating that a test + *

    JUnit uses {@link AssumptionViolatedException}s for indicating that a test * provides no useful information. (See {@link org.junit.Assume} for more * information.) You have to call {@code assume} methods before you set * expectations of the {@code ExpectedException} rule. In this case the rule @@ -80,8 +87,7 @@ * *

    AssertionErrors

    * - *

    - * JUnit uses {@link AssertionError}s for indicating that a test is failing. You + *

    JUnit uses {@link AssertionError}s for indicating that a test is failing. You * have to call {@code assert} methods before you set expectations of the * {@code ExpectedException} rule, if they should be handled by the framework. * E.g. the following test fails because of the {@code assertTrue} statement. @@ -93,8 +99,7 @@ * } * *

    Missing Exceptions

    - *

    - * By default missing exceptions are reported with an error message + *

    By default missing exceptions are reported with an error message * like "Expected test to throw an instance of foo". You can configure a different * message by means of {@link #reportMissingExceptionWithMessage(String)}. You * can use a {@code %s} placeholder for the description of the expected @@ -107,7 +112,13 @@ public class ExpectedException implements TestRule { /** * Returns a {@linkplain TestRule rule} that expects no exception to * be thrown (identical to behavior without this rule). + * + * @deprecated Since 4.13 + * {@link org.junit.Assert#assertThrows(Class, org.junit.function.ThrowingRunnable) + * Assert.assertThrows} can be used to verify that your code throws a specific + * exception. */ + @Deprecated public static ExpectedException none() { return new ExpectedException(); } @@ -222,10 +233,18 @@ public void expectMessage(Matcher matcher) { * throw new IllegalArgumentException("What happened?", cause); * } */ - public void expectCause(Matcher expectedCause) { + public void expectCause(Matcher expectedCause) { expect(hasCause(expectedCause)); } + /** + * Check if any Exception is expected. + * @since 4.13 + */ + public final boolean isAnyExceptionExpected() { + return matcherBuilder.expectsThrowable(); + } + private class ExpectedExceptionStatement extends Statement { private final Statement next; @@ -255,10 +274,6 @@ private void handleException(Throwable e) throws Throwable { } } - private boolean isAnyExceptionExpected() { - return matcherBuilder.expectsThrowable(); - } - private void failDueToMissingException() throws AssertionError { fail(missingExceptionMessage()); } diff --git a/src/main/java/org/junit/rules/ExternalResource.java b/src/main/java/org/junit/rules/ExternalResource.java index 71ca287cce49..71fc84294308 100644 --- a/src/main/java/org/junit/rules/ExternalResource.java +++ b/src/main/java/org/junit/rules/ExternalResource.java @@ -1,6 +1,10 @@ package org.junit.rules; +import java.util.ArrayList; +import java.util.List; + import org.junit.runner.Description; +import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; /** @@ -44,11 +48,20 @@ private Statement statement(final Statement base) { @Override public void evaluate() throws Throwable { before(); + + List errors = new ArrayList(); try { base.evaluate(); + } catch (Throwable t) { + errors.add(t); } finally { - after(); + try { + after(); + } catch (Throwable t) { + errors.add(t); + } } + MultipleFailureException.assertEmpty(errors); } }; } diff --git a/src/main/java/org/junit/rules/MethodRule.java b/src/main/java/org/junit/rules/MethodRule.java index 823ee7812d00..94608f5a88f9 100644 --- a/src/main/java/org/junit/rules/MethodRule.java +++ b/src/main/java/org/junit/rules/MethodRule.java @@ -10,21 +10,9 @@ * {@link Statement} that executes the method is passed to each annotated * {@link Rule} in turn, and each may return a substitute or modified * {@link Statement}, which is passed to the next {@link Rule}, if any. For - * examples of how this can be useful, see these provided MethodRules, - * or write your own: + * an example of how this can be useful, see {@link TestWatchman}. * - *

      - *
    • {@link ErrorCollector}: collect multiple errors in one test method
    • - *
    • {@link ExpectedException}: make flexible assertions about thrown exceptions
    • - *
    • {@link ExternalResource}: start and stop a server, for example
    • - *
    • {@link TemporaryFolder}: create fresh files, and delete after test
    • - *
    • {@link TestName}: remember the test name for use during the method
    • - *
    • {@link TestWatchman}: add logic at events during method execution
    • - *
    • {@link Timeout}: cause test to fail after a set time
    • - *
    • {@link Verifier}: fail test if object state ends up incorrect
    • - *
    - * - * Note that {@link MethodRule} has been replaced by {@link TestRule}, + *

    Note that {@link MethodRule} has been replaced by {@link TestRule}, * which has the added benefit of supporting class rules. * * @since 4.7 diff --git a/src/main/java/org/junit/rules/RuleChain.java b/src/main/java/org/junit/rules/RuleChain.java index f43d8f5562d9..bf93aae1f318 100644 --- a/src/main/java/org/junit/rules/RuleChain.java +++ b/src/main/java/org/junit/rules/RuleChain.java @@ -4,26 +4,34 @@ import java.util.Collections; import java.util.List; +import org.junit.Rule; import org.junit.runner.Description; import org.junit.runners.model.Statement; /** - * The RuleChain rule allows ordering of TestRules. You create a + * The {@code RuleChain} can be used for creating composite rules. You create a * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of * {@link #around(TestRule)}: * *

    - * public static class UseRuleChain {
    - * 	@Rule
    - * 	public RuleChain chain= RuleChain
    - * 	                       .outerRule(new LoggingRule("outer rule")
    - * 	                       .around(new LoggingRule("middle rule")
    - * 	                       .around(new LoggingRule("inner rule");
    + * public abstract class CompositeRules {
    + *   public static TestRule extendedLogging() {
    + *     return RuleChain.outerRule(new LoggingRule("outer rule"))
    + *                     .around(new LoggingRule("middle rule"))
    + *                     .around(new LoggingRule("inner rule"));
    + *   }
    + * }
    + * 
    + * + *
    + * public class UseRuleChain {
    + *   @Rule
    + *   public final TestRule extendedLogging = CompositeRules.extendedLogging();
      *
    - * 	@Test
    - * 	public void example() {
    - * 		assertTrue(true);
    - *     }
    + *   @Test
    + *   public void example() {
    + *     assertTrue(true);
    + *   }
      * }
      * 
    * @@ -38,6 +46,13 @@ * finished outer rule * * + * In older versions of JUnit (before 4.13) {@code RuleChain} was used for + * ordering rules. We recommend to not use it for this purpose anymore. You can + * use the attribute {@code order} of the annotation {@link Rule#order() Rule} + * or {@link org.junit.ClassRule#order() ClassRule} for ordering rules. + * + * @see org.junit.Rule#order() + * @see org.junit.ClassRule#order() * @since 4.10 */ public class RuleChain implements TestRule { @@ -72,13 +87,17 @@ private RuleChain(List rules) { } /** - * Create a new {@code RuleChain}, which encloses the {@code nextRule} with + * Create a new {@code RuleChain}, which encloses the given {@link TestRule} with * the rules of the current {@code RuleChain}. * - * @param enclosedRule the rule to enclose. + * @param enclosedRule the rule to enclose; must not be {@code null}. * @return a new {@code RuleChain}. + * @throws NullPointerException if the argument {@code enclosedRule} is {@code null} */ public RuleChain around(TestRule enclosedRule) { + if (enclosedRule == null) { + throw new NullPointerException("The enclosed rule must not be null"); + } List rulesOfNewChain = new ArrayList(); rulesOfNewChain.add(enclosedRule); rulesOfNewChain.addAll(rulesStartingWithInnerMost); @@ -89,9 +108,6 @@ public RuleChain around(TestRule enclosedRule) { * {@inheritDoc} */ public Statement apply(Statement base, Description description) { - for (TestRule each : rulesStartingWithInnerMost) { - base = each.apply(base, description); - } - return base; + return new RunRules(base, rulesStartingWithInnerMost, description); } } \ No newline at end of file diff --git a/src/main/java/org/junit/rules/Stopwatch.java b/src/main/java/org/junit/rules/Stopwatch.java index 5d34e7f11a85..6900a481cf11 100644 --- a/src/main/java/org/junit/rules/Stopwatch.java +++ b/src/main/java/org/junit/rules/Stopwatch.java @@ -76,7 +76,7 @@ * @author tibor17 * @since 4.12 */ -public abstract class Stopwatch implements TestRule { +public class Stopwatch implements TestRule { private final Clock clock; private volatile long startNanos; private volatile long endNanos; diff --git a/src/main/java/org/junit/rules/TemporaryFolder.java b/src/main/java/org/junit/rules/TemporaryFolder.java index dc75c93bb115..a726c66e36aa 100644 --- a/src/main/java/org/junit/rules/TemporaryFolder.java +++ b/src/main/java/org/junit/rules/TemporaryFolder.java @@ -1,15 +1,20 @@ package org.junit.rules; +import static org.junit.Assert.fail; + import java.io.File; import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import org.junit.Rule; /** * The TemporaryFolder Rule allows creation of files and folders that should * be deleted when the test method finishes (whether it passes or - * fails). Whether the deletion is successful or not is not checked by this rule. - * No exception will be thrown in case the deletion fails. + * fails). + * By default no exception will be thrown in case the deletion fails. * *

    Example of usage: *

    @@ -26,18 +31,104 @@
      * }
      * 
    * + *

    TemporaryFolder rule supports assured deletion mode, which + * will fail the test in case deletion fails with {@link AssertionError}. + * + *

    Creating TemporaryFolder with assured deletion: + *

    + *  @Rule
    + *  public TemporaryFolder folder= TemporaryFolder.builder().assureDeletion().build();
    + * 
    + * * @since 4.7 */ public class TemporaryFolder extends ExternalResource { private final File parentFolder; + private final boolean assureDeletion; private File folder; + private static final int TEMP_DIR_ATTEMPTS = 10000; + private static final String TMP_PREFIX = "junit"; + + /** + * Create a temporary folder which uses system default temporary-file + * directory to create temporary resources. + */ public TemporaryFolder() { - this(null); + this((File) null); } + /** + * Create a temporary folder which uses the specified directory to create + * temporary resources. + * + * @param parentFolder folder where temporary resources will be created. + * If {@code null} then system default temporary-file directory is used. + */ public TemporaryFolder(File parentFolder) { this.parentFolder = parentFolder; + this.assureDeletion = false; + } + + /** + * Create a {@link TemporaryFolder} initialized with + * values from a builder. + */ + protected TemporaryFolder(Builder builder) { + this.parentFolder = builder.parentFolder; + this.assureDeletion = builder.assureDeletion; + } + + /** + * Returns a new builder for building an instance of {@link TemporaryFolder}. + * + * @since 4.13 + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builds an instance of {@link TemporaryFolder}. + * + * @since 4.13 + */ + public static class Builder { + private File parentFolder; + private boolean assureDeletion; + + protected Builder() {} + + /** + * Specifies which folder to use for creating temporary resources. + * If {@code null} then system default temporary-file directory is + * used. + * + * @return this + */ + public Builder parentFolder(File parentFolder) { + this.parentFolder = parentFolder; + return this; + } + + /** + * Setting this flag assures that no resources are left undeleted. Failure + * to fulfill the assurance results in failure of tests with an + * {@link AssertionError}. + * + * @return this + */ + public Builder assureDeletion() { + this.assureDeletion = true; + return this; + } + + /** + * Builds a {@link TemporaryFolder} instance using the values in this builder. + */ + public TemporaryFolder build() { + return new TemporaryFolder(this); + } } @Override @@ -75,52 +166,63 @@ public File newFile(String fileName) throws IOException { * Returns a new fresh file with a random name under the temporary folder. */ public File newFile() throws IOException { - return File.createTempFile("junit", null, getRoot()); + return File.createTempFile(TMP_PREFIX, null, getRoot()); } /** - * Returns a new fresh folder with the given name under the temporary + * Returns a new fresh folder with the given path under the temporary * folder. */ - public File newFolder(String folder) throws IOException { - return newFolder(new String[]{folder}); + public File newFolder(String path) throws IOException { + return newFolder(new String[]{path}); } /** - * Returns a new fresh folder with the given name(s) under the temporary - * folder. + * Returns a new fresh folder with the given paths under the temporary + * folder. For example, if you pass in the strings {@code "parent"} and {@code "child"} + * then a directory named {@code "parent"} will be created under the temporary folder + * and a directory named {@code "child"} will be created under the newly-created + * {@code "parent"} directory. */ - public File newFolder(String... folderNames) throws IOException { - File file = getRoot(); - for (int i = 0; i < folderNames.length; i++) { - String folderName = folderNames[i]; - validateFolderName(folderName); - file = new File(file, folderName); - if (!file.mkdir() && isLastElementInArray(i, folderNames)) { - throw new IOException( - "a folder with the name \'" + folderName + "\' already exists"); - } + public File newFolder(String... paths) throws IOException { + if (paths.length == 0) { + throw new IllegalArgumentException("must pass at least one path"); } - return file; - } - - /** - * Validates if multiple path components were used while creating a folder. - * - * @param folderName - * Name of the folder being created - */ - private void validateFolderName(String folderName) throws IOException { - File tempFile = new File(folderName); - if (tempFile.getParent() != null) { - String errorMsg = "Folder name cannot consist of multiple path components separated by a file separator." - + " Please use newFolder('MyParentFolder','MyFolder') to create hierarchies of folders"; - throw new IOException(errorMsg); + + /* + * Before checking if the paths are absolute paths, check if create() was ever called, + * and if it wasn't, throw IllegalStateException. + */ + File root = getRoot(); + for (String path : paths) { + if (new File(path).isAbsolute()) { + throw new IOException("folder path \'" + path + "\' is not a relative path"); + } } - } - private boolean isLastElementInArray(int index, String[] array) { - return index == array.length - 1; + File relativePath = null; + File file = root; + boolean lastMkdirsCallSuccessful = true; + for (String path : paths) { + relativePath = new File(relativePath, path); + file = new File(root, relativePath.getPath()); + + lastMkdirsCallSuccessful = file.mkdirs(); + if (!lastMkdirsCallSuccessful && !file.isDirectory()) { + if (file.exists()) { + throw new IOException( + "a file with the path \'" + relativePath.getPath() + "\' exists"); + } else { + throw new IOException( + "could not create a folder with the path \'" + relativePath.getPath() + "\'"); + } + } + } + if (!lastMkdirsCallSuccessful) { + throw new IOException( + "a folder with the path \'" + relativePath.getPath() + "\' already exists"); + } + return file; } /** @@ -130,11 +232,63 @@ public File newFolder() throws IOException { return createTemporaryFolderIn(getRoot()); } - private File createTemporaryFolderIn(File parentFolder) throws IOException { - File createdFolder = File.createTempFile("junit", "", parentFolder); - createdFolder.delete(); - createdFolder.mkdir(); - return createdFolder; + private static File createTemporaryFolderIn(File parentFolder) throws IOException { + try { + return createTemporaryFolderWithNioApi(parentFolder); + } catch (ClassNotFoundException ignore) { + // Fallback for Java 5 and 6 + return createTemporaryFolderWithFileApi(parentFolder); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof IOException) { + throw (IOException) cause; + } + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } + IOException exception = new IOException("Failed to create temporary folder in " + parentFolder); + exception.initCause(cause); + throw exception; + } catch (Exception e) { + throw new RuntimeException("Failed to create temporary folder in " + parentFolder, e); + } + } + + private static File createTemporaryFolderWithNioApi(File parentFolder) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class filesClass = Class.forName("java.nio.file.Files"); + Object fileAttributeArray = Array.newInstance(Class.forName("java.nio.file.attribute.FileAttribute"), 0); + Class pathClass = Class.forName("java.nio.file.Path"); + Object tempDir; + if (parentFolder != null) { + Method createTempDirectoryMethod = filesClass.getDeclaredMethod("createTempDirectory", pathClass, String.class, fileAttributeArray.getClass()); + Object parentPath = File.class.getDeclaredMethod("toPath").invoke(parentFolder); + tempDir = createTempDirectoryMethod.invoke(null, parentPath, TMP_PREFIX, fileAttributeArray); + } else { + Method createTempDirectoryMethod = filesClass.getDeclaredMethod("createTempDirectory", String.class, fileAttributeArray.getClass()); + tempDir = createTempDirectoryMethod.invoke(null, TMP_PREFIX, fileAttributeArray); + } + return (File) pathClass.getDeclaredMethod("toFile").invoke(tempDir); + } + + private static File createTemporaryFolderWithFileApi(File parentFolder) throws IOException { + File createdFolder = null; + for (int i = 0; i < TEMP_DIR_ATTEMPTS; ++i) { + // Use createTempFile to get a suitable folder name. + String suffix = ".tmp"; + File tmpFile = File.createTempFile(TMP_PREFIX, suffix, parentFolder); + String tmpName = tmpFile.toString(); + // Discard .tmp suffix of tmpName. + String folderName = tmpName.substring(0, tmpName.length() - suffix.length()); + createdFolder = new File(folderName); + if (createdFolder.mkdir()) { + tmpFile.delete(); + return createdFolder; + } + tmpFile.delete(); + } + throw new IOException("Unable to create temporary directory in: " + + parentFolder.toString() + ". Tried " + TEMP_DIR_ATTEMPTS + " times. " + + "Last attempted to create: " + createdFolder.toString()); } /** @@ -150,21 +304,48 @@ public File getRoot() { /** * Delete all files and folders under the temporary folder. Usually not - * called directly, since it is automatically applied by the {@link Rule} + * called directly, since it is automatically applied by the {@link Rule}. + * + * @throws AssertionError if unable to clean up resources + * and deletion of resources is assured. */ public void delete() { - if (folder != null) { - recursiveDelete(folder); + if (!tryDelete()) { + if (assureDeletion) { + fail("Unable to clean up temporary folder " + folder); + } + } + } + + /** + * Tries to delete all files and folders under the temporary folder and + * returns whether deletion was successful or not. + * + * @return {@code true} if all resources are deleted successfully, + * {@code false} otherwise. + */ + private boolean tryDelete() { + if (folder == null) { + return true; } + + return recursiveDelete(folder); } - private void recursiveDelete(File file) { + private boolean recursiveDelete(File file) { + // Try deleting file before assuming file is a directory + // to prevent following symbolic links. + if (file.delete()) { + return true; + } File[] files = file.listFiles(); if (files != null) { for (File each : files) { - recursiveDelete(each); + if (!recursiveDelete(each)) { + return false; + } } } - file.delete(); + return file.delete(); } } diff --git a/src/main/java/org/junit/rules/TestName.java b/src/main/java/org/junit/rules/TestName.java index bf726023bf68..e2ebc2ec97d1 100644 --- a/src/main/java/org/junit/rules/TestName.java +++ b/src/main/java/org/junit/rules/TestName.java @@ -25,7 +25,7 @@ * @since 4.7 */ public class TestName extends TestWatcher { - private String name; + private volatile String name; @Override protected void starting(Description d) { diff --git a/src/main/java/org/junit/rules/TestWatcher.java b/src/main/java/org/junit/rules/TestWatcher.java index 5492b6bc571b..a28514dd2b2f 100644 --- a/src/main/java/org/junit/rules/TestWatcher.java +++ b/src/main/java/org/junit/rules/TestWatcher.java @@ -4,6 +4,7 @@ import java.util.List; import org.junit.AssumptionViolatedException; +import org.junit.Rule; import org.junit.runner.Description; import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; @@ -17,7 +18,7 @@ * public static class WatchmanTest { * private static String watchedLog; * - * @Rule + * @Rule(order = Integer.MIN_VALUE) * public TestWatcher watchman= new TestWatcher() { * @Override * protected void failed(Throwable e, Description description) { @@ -40,6 +41,11 @@ * } * } * + *

    It is recommended to always set the {@link Rule#order() order} of the + * {@code TestWatcher} to {@code Integer.MIN_VALUE} so that it encloses all + * other rules. Otherwise it may see failed tests as successful and vice versa + * if some rule changes the result of a test (e.g. {@link ErrorCollector} or + * {@link ExpectedException}). * * @since 4.9 */ @@ -54,7 +60,7 @@ public void evaluate() throws Throwable { try { base.evaluate(); succeededQuietly(description, errors); - } catch (@SuppressWarnings("deprecation") org.junit.internal.AssumptionViolatedException e) { + } catch (org.junit.internal.AssumptionViolatedException e) { errors.add(e); skippedQuietly(e, description, errors); } catch (Throwable e) { @@ -87,7 +93,6 @@ private void failedQuietly(Throwable e, Description description, } } - @SuppressWarnings("deprecation") private void skippedQuietly( org.junit.internal.AssumptionViolatedException e, Description description, List errors) { @@ -135,7 +140,6 @@ protected void failed(Throwable e, Description description) { /** * Invoked when a test is skipped due to a failed assumption. */ - @SuppressWarnings("deprecation") protected void skipped(AssumptionViolatedException e, Description description) { // For backwards compatibility with JUnit 4.11 and earlier, call the legacy version org.junit.internal.AssumptionViolatedException asInternalException = e; diff --git a/src/main/java/org/junit/rules/Timeout.java b/src/main/java/org/junit/rules/Timeout.java index 45a5bc532050..334a9235cd26 100644 --- a/src/main/java/org/junit/rules/Timeout.java +++ b/src/main/java/org/junit/rules/Timeout.java @@ -12,7 +12,7 @@ * public static class HasGlobalLongTimeout { * * @Rule - * public Timeout globalTimeout= new Timeout(20); + * public Timeout globalTimeout = Timeout.millis(20); * * @Test * public void run1() throws InterruptedException { @@ -84,7 +84,7 @@ public Timeout(long timeout, TimeUnit timeUnit) { } /** - * Create a {@code Timeout} instance initialized with values form + * Create a {@code Timeout} instance initialized with values from * a builder. * * @since 4.12 diff --git a/src/main/java/org/junit/runner/Computer.java b/src/main/java/org/junit/runner/Computer.java index 8bb4b20c1565..18d0d31ce11f 100644 --- a/src/main/java/org/junit/runner/Computer.java +++ b/src/main/java/org/junit/runner/Computer.java @@ -30,7 +30,17 @@ public Runner getSuite(final RunnerBuilder builder, public Runner runnerForClass(Class testClass) throws Throwable { return getRunner(builder, testClass); } - }, classes); + }, classes) { + @Override + protected String getName() { + /* + * #1320 The generated suite is not based on a real class so + * only a 'null' description can be generated from it. This name + * will be overridden here. + */ + return "classes"; + } + }; } /** diff --git a/src/main/java/org/junit/runner/Describable.java b/src/main/java/org/junit/runner/Describable.java index 151414181b35..293fdb32a5c6 100644 --- a/src/main/java/org/junit/runner/Describable.java +++ b/src/main/java/org/junit/runner/Describable.java @@ -10,5 +10,5 @@ public interface Describable { /** * @return a {@link Description} showing the tests to be run by the receiver */ - public abstract Description getDescription(); + Description getDescription(); } \ No newline at end of file diff --git a/src/main/java/org/junit/runner/Description.java b/src/main/java/org/junit/runner/Description.java index fe47eacb537b..0846a1e9d31b 100644 --- a/src/main/java/org/junit/runner/Description.java +++ b/src/main/java/org/junit/runner/Description.java @@ -124,6 +124,17 @@ public static Description createSuiteDescription(Class testClass) { return new Description(testClass, testClass.getName(), testClass.getAnnotations()); } + /** + * Create a Description named after testClass + * + * @param testClass A not null {@link Class} containing tests + * @param annotations meta-data about the test, for downstream interpreters + * @return a Description of testClass + */ + public static Description createSuiteDescription(Class testClass, Annotation... annotations) { + return new Description(testClass, testClass.getName(), annotations); + } + /** * Describes a Runner which runs no tests */ @@ -139,7 +150,7 @@ public static Description createSuiteDescription(Class testClass) { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * See https://github.com/junit-team/junit4/issues/976 */ private final Collection fChildren = new ConcurrentLinkedQueue(); private final String fDisplayName; diff --git a/src/main/java/org/junit/runner/FilterFactory.java b/src/main/java/org/junit/runner/FilterFactory.java index 57b4eaa64795..e2bfb7358044 100644 --- a/src/main/java/org/junit/runner/FilterFactory.java +++ b/src/main/java/org/junit/runner/FilterFactory.java @@ -16,7 +16,8 @@ public interface FilterFactory { /** * Exception thrown if the {@link Filter} cannot be created. */ - public static class FilterNotCreatedException extends Exception { + @SuppressWarnings("serial") + class FilterNotCreatedException extends Exception { public FilterNotCreatedException(Exception exception) { super(exception.getMessage(), exception); } diff --git a/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java b/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java index 434157cebbff..338340789ee8 100644 --- a/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java +++ b/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java @@ -85,13 +85,11 @@ String[] parseOptions(String... args) { } private String[] copyArray(String[] args, int from, int to) { - ArrayList result = new ArrayList(); - + String[] result = new String[to - from]; for (int j = from; j != to; ++j) { - result.add(args[j]); + result[j - from] = args[j]; } - - return result.toArray(new String[result.size()]); + return result; } void parseParameters(String[] args) { diff --git a/src/main/java/org/junit/runner/OrderWith.java b/src/main/java/org/junit/runner/OrderWith.java new file mode 100644 index 000000000000..e8470c9dd1c8 --- /dev/null +++ b/src/main/java/org/junit/runner/OrderWith.java @@ -0,0 +1,28 @@ +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; + +import org.junit.runner.manipulation.Ordering; +import org.junit.validator.ValidateWith; + +/** + * When a test class is annotated with @OrderWith or extends a class annotated + * with @OrderWith, JUnit will order the tests in the test class (and child + * test classes, if any) using the ordering defined by the {@link Ordering} class. + * + * @since 4.13 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +@ValidateWith(OrderWithValidator.class) +public @interface OrderWith { + /** + * Gets a class that extends {@link Ordering}. The class must have a public no-arg constructor. + */ + Class value(); +} diff --git a/src/main/java/org/junit/runner/OrderWithValidator.java b/src/main/java/org/junit/runner/OrderWithValidator.java new file mode 100644 index 000000000000..f8eab2523c16 --- /dev/null +++ b/src/main/java/org/junit/runner/OrderWithValidator.java @@ -0,0 +1,38 @@ +package org.junit.runner; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +import java.util.List; + +import org.junit.FixMethodOrder; +import org.junit.runners.model.TestClass; +import org.junit.validator.AnnotationValidator; + +/** + * Validates that there are no errors in the use of the {@code OrderWith} + * annotation. If there is, a {@code Throwable} object will be added to the list + * of errors. + * + * @since 4.13 + */ +public final class OrderWithValidator extends AnnotationValidator { + + /** + * Adds to {@code errors} a throwable for each problem detected. Looks for + * {@code FixMethodOrder} annotations. + * + * @param testClass that is being validated + * @return A list of exceptions detected + * + * @since 4.13 + */ + @Override + public List validateAnnotatedClass(TestClass testClass) { + if (testClass.getAnnotation(FixMethodOrder.class) != null) { + return singletonList( + new Exception("@FixMethodOrder cannot be combined with @OrderWith")); + } + return emptyList(); + } +} diff --git a/src/main/java/org/junit/runner/Request.java b/src/main/java/org/junit/runner/Request.java index 79c0f1ee15db..7b9a99003b47 100644 --- a/src/main/java/org/junit/runner/Request.java +++ b/src/main/java/org/junit/runner/Request.java @@ -5,9 +5,11 @@ import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; import org.junit.internal.requests.ClassRequest; import org.junit.internal.requests.FilterRequest; +import org.junit.internal.requests.OrderingRequest; import org.junit.internal.requests.SortingRequest; import org.junit.internal.runners.ErrorReportingRunner; import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.Ordering; import org.junit.runners.model.InitializationError; /** @@ -71,12 +73,11 @@ public static Request classWithoutSuiteMethod(Class clazz) { */ public static Request classes(Computer computer, Class... classes) { try { - AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(true); + AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(); Runner suite = computer.getSuite(builder, classes); return runner(suite); } catch (InitializationError e) { - throw new RuntimeException( - "Bug in saff's brain: Suite constructor, called as above, should always complete"); + return runner(new ErrorReportingRunner(e, classes)); } } @@ -132,13 +133,16 @@ public Request filterWith(Filter filter) { } /** - * Returns a Request that only runs contains tests whose {@link Description} - * equals desiredDescription + * Returns a Request that only runs tests whose {@link Description} + * matches the given description. * - * @param desiredDescription {@link Description} of those tests that should be run + *

    Returns an empty {@code Request} if {@code desiredDescription} is not a single test and filters all but the single + * test if {@code desiredDescription} is a single test.

    + * + * @param desiredDescription {@code Description} of those tests that should be run * @return the filtered Request */ - public Request filterWith(final Description desiredDescription) { + public Request filterWith(Description desiredDescription) { return filterWith(Filter.matchMethodDescription(desiredDescription)); } @@ -149,15 +153,15 @@ public Request filterWith(final Description desiredDescription) { * For example, here is code to run a test suite in alphabetical order: *
          * private static Comparator<Description> forward() {
    -     * return new Comparator<Description>() {
    -     * public int compare(Description o1, Description o2) {
    -     * return o1.getDisplayName().compareTo(o2.getDisplayName());
    -     * }
    -     * };
    +     *   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()));
    +     *   new JUnitCore().run(Request.aClass(AllTests.class).sortWith(forward()));
          * }
          * 
    * @@ -167,4 +171,32 @@ public Request filterWith(final Description desiredDescription) { public Request sortWith(Comparator comparator) { return new SortingRequest(this, comparator); } + + /** + * Returns a Request whose Tests can be run in a certain order, defined by + * ordering + *

    + * For example, here is code to run a test suite in reverse order: + *

    +     * private static Ordering reverse() {
    +     *   return new Ordering() {
    +     *     public List<Description> orderItems(Collection<Description> descriptions) {
    +     *       List<Description> ordered = new ArrayList<>(descriptions);
    +     *       Collections.reverse(ordered);
    +     *       return ordered;
    +     *     }
    +     *   }
    +     * }
    +     *     
    +     * public static main() {
    +     *   new JUnitCore().run(Request.aClass(AllTests.class).orderWith(reverse()));
    +     * }
    +     * 
    + * + * @return a Request with ordered Tests + * @since 4.13 + */ + public Request orderWith(Ordering ordering) { + return new OrderingRequest(this, ordering); + } } diff --git a/src/main/java/org/junit/runner/Result.java b/src/main/java/org/junit/runner/Result.java index 73ad059caefb..4b5f4a406238 100644 --- a/src/main/java/org/junit/runner/Result.java +++ b/src/main/java/org/junit/runner/Result.java @@ -28,6 +28,7 @@ public class Result implements Serializable { ObjectStreamClass.lookup(SerializedForm.class).getFields(); private final AtomicInteger count; private final AtomicInteger ignoreCount; + private final AtomicInteger assumptionFailureCount; private final CopyOnWriteArrayList failures; private final AtomicLong runTime; private final AtomicLong startTime; @@ -38,6 +39,7 @@ public class Result implements Serializable { public Result() { count = new AtomicInteger(); ignoreCount = new AtomicInteger(); + assumptionFailureCount = new AtomicInteger(); failures = new CopyOnWriteArrayList(); runTime = new AtomicLong(); startTime = new AtomicLong(); @@ -46,34 +48,35 @@ public Result() { private Result(SerializedForm serializedForm) { count = serializedForm.fCount; ignoreCount = serializedForm.fIgnoreCount; + assumptionFailureCount = serializedForm.assumptionFailureCount; failures = new CopyOnWriteArrayList(serializedForm.fFailures); runTime = new AtomicLong(serializedForm.fRunTime); startTime = new AtomicLong(serializedForm.fStartTime); } /** - * @return the number of tests run + * Returns the number of tests run */ public int getRunCount() { return count.get(); } /** - * @return the number of tests that failed during the run + * Returns the number of tests that failed during the run */ public int getFailureCount() { return failures.size(); } /** - * @return the number of milliseconds it took to run the entire suite to run + * Returns the number of milliseconds it took to run the entire suite to run */ public long getRunTime() { return runTime.get(); } /** - * @return the {@link Failure}s describing tests that failed and the problems they encountered + * Returns the {@link Failure}s describing tests that failed and the problems they encountered */ public List getFailures() { return failures; @@ -86,6 +89,20 @@ public int getIgnoreCount() { return ignoreCount.get(); } + /** + * Returns the number of tests skipped because of an assumption failure + * + * @throws UnsupportedOperationException if the result was serialized in a version before JUnit 4.13 + * @since 4.13 + */ + public int getAssumptionFailureCount() { + if (assumptionFailureCount == null) { + throw new UnsupportedOperationException( + "Result was serialized from a version of JUnit that doesn't support this method"); + } + return assumptionFailureCount.get(); + } + /** * @return true if all tests succeeded */ @@ -137,7 +154,7 @@ public void testIgnored(Description description) throws Exception { @Override public void testAssumptionFailure(Failure failure) { - // do nothing: same as passing (for 4.5; may change in 4.6) + assumptionFailureCount.getAndIncrement(); } } @@ -156,6 +173,7 @@ private static class SerializedForm implements Serializable { private static final long serialVersionUID = 1L; private final AtomicInteger fCount; private final AtomicInteger fIgnoreCount; + private final AtomicInteger assumptionFailureCount; private final List fFailures; private final long fRunTime; private final long fStartTime; @@ -163,6 +181,7 @@ private static class SerializedForm implements Serializable { public SerializedForm(Result result) { fCount = result.count; fIgnoreCount = result.ignoreCount; + assumptionFailureCount = result.assumptionFailureCount; fFailures = Collections.synchronizedList(new ArrayList(result.failures)); fRunTime = result.runTime.longValue(); fStartTime = result.startTime.longValue(); @@ -172,6 +191,7 @@ public SerializedForm(Result result) { private SerializedForm(ObjectInputStream.GetField fields) throws IOException { fCount = (AtomicInteger) fields.get("fCount", null); fIgnoreCount = (AtomicInteger) fields.get("fIgnoreCount", null); + assumptionFailureCount = (AtomicInteger) fields.get("assumptionFailureCount", null); fFailures = (List) fields.get("fFailures", null); fRunTime = fields.get("fRunTime", 0L); fStartTime = fields.get("fStartTime", 0L); @@ -184,6 +204,7 @@ public void serialize(ObjectOutputStream s) throws IOException { fields.put("fFailures", fFailures); fields.put("fRunTime", fRunTime); fields.put("fStartTime", fStartTime); + fields.put("assumptionFailureCount", assumptionFailureCount); s.writeFields(); } diff --git a/src/main/java/org/junit/runner/manipulation/Alphanumeric.java b/src/main/java/org/junit/runner/manipulation/Alphanumeric.java new file mode 100644 index 000000000000..8388d21eb804 --- /dev/null +++ b/src/main/java/org/junit/runner/manipulation/Alphanumeric.java @@ -0,0 +1,27 @@ +package org.junit.runner.manipulation; + +import java.util.Comparator; + +import org.junit.runner.Description; + +/** + * A sorter that orders tests alphanumerically by test name. + * + * @since 4.13 + */ +public final class Alphanumeric extends Sorter implements Ordering.Factory { + + public Alphanumeric() { + super(COMPARATOR); + } + + public Ordering create(Context context) { + return this; + } + + private static final Comparator COMPARATOR = new Comparator() { + public int compare(Description o1, Description o2) { + return o1.getDisplayName().compareTo(o2.getDisplayName()); + } + }; +} diff --git a/src/main/java/org/junit/runner/manipulation/InvalidOrderingException.java b/src/main/java/org/junit/runner/manipulation/InvalidOrderingException.java new file mode 100644 index 000000000000..d9d60f778b62 --- /dev/null +++ b/src/main/java/org/junit/runner/manipulation/InvalidOrderingException.java @@ -0,0 +1,21 @@ +package org.junit.runner.manipulation; + +/** + * Thrown when an ordering does something invalid (like remove or add children) + * + * @since 4.13 + */ +public class InvalidOrderingException extends Exception { + private static final long serialVersionUID = 1L; + + public InvalidOrderingException() { + } + + public InvalidOrderingException(String message) { + super(message); + } + + public InvalidOrderingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/junit/runner/manipulation/Orderable.java b/src/main/java/org/junit/runner/manipulation/Orderable.java new file mode 100644 index 000000000000..9a12a3bc1ef2 --- /dev/null +++ b/src/main/java/org/junit/runner/manipulation/Orderable.java @@ -0,0 +1,21 @@ +package org.junit.runner.manipulation; + +/** + * Interface for runners that allow ordering of tests. + * + *

    Beware of using this interface to cope with order dependencies between tests. + * Tests that are isolated from each other are less expensive to maintain and + * can be run individually. + * + * @since 4.13 + */ +public interface Orderable extends Sortable { + + /** + * Orders the tests using orderer + * + * @throws InvalidOrderingException if orderer does something invalid (like remove or add + * children) + */ + void order(Orderer orderer) throws InvalidOrderingException; +} diff --git a/src/main/java/org/junit/runner/manipulation/Orderer.java b/src/main/java/org/junit/runner/manipulation/Orderer.java new file mode 100644 index 000000000000..eb1305437076 --- /dev/null +++ b/src/main/java/org/junit/runner/manipulation/Orderer.java @@ -0,0 +1,62 @@ +package org.junit.runner.manipulation; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.runner.Description; + +/** + * Orders tests. + * + * @since 4.13 + */ +public final class Orderer { + private final Ordering ordering; + + Orderer(Ordering delegate) { + this.ordering = delegate; + } + + /** + * Orders the descriptions. + * + * @return descriptions in order + */ + public List order(Collection descriptions) + throws InvalidOrderingException { + List inOrder = ordering.orderItems( + Collections.unmodifiableCollection(descriptions)); + if (!ordering.validateOrderingIsCorrect()) { + return inOrder; + } + + Set uniqueDescriptions = new HashSet(descriptions); + if (!uniqueDescriptions.containsAll(inOrder)) { + throw new InvalidOrderingException("Ordering added items"); + } + Set resultAsSet = new HashSet(inOrder); + if (resultAsSet.size() != inOrder.size()) { + throw new InvalidOrderingException("Ordering duplicated items"); + } else if (!resultAsSet.containsAll(uniqueDescriptions)) { + throw new InvalidOrderingException("Ordering removed items"); + } + + return inOrder; + } + + /** + * Order the tests in target. + * + * @throws InvalidOrderingException if ordering does something invalid (like remove or add + * children) + */ + public void apply(Object target) throws InvalidOrderingException { + if (target instanceof Orderable) { + Orderable orderable = (Orderable) target; + orderable.order(this); + } + } +} diff --git a/src/main/java/org/junit/runner/manipulation/Ordering.java b/src/main/java/org/junit/runner/manipulation/Ordering.java new file mode 100644 index 000000000000..0d0ce93780e6 --- /dev/null +++ b/src/main/java/org/junit/runner/manipulation/Ordering.java @@ -0,0 +1,172 @@ +package org.junit.runner.manipulation; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +import org.junit.runner.Description; +import org.junit.runner.OrderWith; + +/** + * Reorders tests. An {@code Ordering} can reverse the order of tests, sort the + * order or even shuffle the order. + * + *

    In general you will not need to use a Ordering directly. + * Instead, use {@link org.junit.runner.Request#orderWith(Ordering)}. + * + * @since 4.13 + */ +public abstract class Ordering { + private static final String CONSTRUCTOR_ERROR_FORMAT + = "Ordering class %s should have a public constructor with signature " + + "%s(Ordering.Context context)"; + + /** + * Creates an {@link Ordering} that shuffles the items using the given + * {@link Random} instance. + */ + public static Ordering shuffledBy(final Random random) { + return new Ordering() { + @Override + boolean validateOrderingIsCorrect() { + return false; + } + + @Override + protected List orderItems(Collection descriptions) { + List shuffled = new ArrayList(descriptions); + Collections.shuffle(shuffled, random); + return shuffled; + } + }; + } + + /** + * Creates an {@link Ordering} from the given factory class. The class must have a public no-arg + * constructor. + * + * @param factoryClass class to use to create the ordering + * @param annotatedTestClass test class that is annotated with {@link OrderWith}. + * @throws InvalidOrderingException if the instance could not be created + */ + public static Ordering definedBy( + Class factoryClass, Description annotatedTestClass) + throws InvalidOrderingException { + if (factoryClass == null) { + throw new NullPointerException("factoryClass cannot be null"); + } + if (annotatedTestClass == null) { + throw new NullPointerException("annotatedTestClass cannot be null"); + } + + Ordering.Factory factory; + try { + Constructor constructor = factoryClass.getConstructor(); + factory = constructor.newInstance(); + } catch (NoSuchMethodException e) { + throw new InvalidOrderingException(String.format( + CONSTRUCTOR_ERROR_FORMAT, + getClassName(factoryClass), + factoryClass.getSimpleName())); + } catch (Exception e) { + throw new InvalidOrderingException( + "Could not create ordering for " + annotatedTestClass, e); + } + return definedBy(factory, annotatedTestClass); + } + + /** + * Creates an {@link Ordering} from the given factory. + * + * @param factory factory to use to create the ordering + * @param annotatedTestClass test class that is annotated with {@link OrderWith}. + * @throws InvalidOrderingException if the instance could not be created + */ + public static Ordering definedBy( + Ordering.Factory factory, Description annotatedTestClass) + throws InvalidOrderingException { + if (factory == null) { + throw new NullPointerException("factory cannot be null"); + } + if (annotatedTestClass == null) { + throw new NullPointerException("annotatedTestClass cannot be null"); + } + + return factory.create(new Ordering.Context(annotatedTestClass)); + } + + private static String getClassName(Class clazz) { + String name = clazz.getCanonicalName(); + if (name == null) { + return clazz.getName(); + } + return name; + } + + /** + * Order the tests in target using this ordering. + * + * @throws InvalidOrderingException if ordering does something invalid (like remove or add + * children) + */ + public void apply(Object target) throws InvalidOrderingException { + /* + * Note that some subclasses of Ordering override apply(). The Sorter + * subclass of Ordering overrides apply() to apply the sort (this is + * done because sorting is more efficient than ordering). + */ + if (target instanceof Orderable) { + Orderable orderable = (Orderable) target; + orderable.order(new Orderer(this)); + } + } + + /** + * Returns {@code true} if this ordering could produce invalid results (i.e. + * if it could add or remove values). + */ + boolean validateOrderingIsCorrect() { + return true; + } + + /** + * Implemented by sub-classes to order the descriptions. + * + * @return descriptions in order + */ + protected abstract List orderItems(Collection descriptions); + + /** Context about the ordering being applied. */ + public static class Context { + private final Description description; + + /** + * Gets the description for the top-level target being ordered. + */ + public Description getTarget() { + return description; + } + + private Context(Description description) { + this.description = description; + } + } + + /** + * Factory for creating {@link Ordering} instances. + * + *

    For a factory to be used with {@code @OrderWith} it needs to have a public no-arg + * constructor. + */ + public interface Factory { + /** + * Creates an Ordering instance using the given context. Implementations + * of this method that do not need to use the context can return the + * same instance every time. + */ + Ordering create(Context context); + } +} diff --git a/src/main/java/org/junit/runner/manipulation/Sortable.java b/src/main/java/org/junit/runner/manipulation/Sortable.java index 9ac864c60a2d..0c59f330a371 100644 --- a/src/main/java/org/junit/runner/manipulation/Sortable.java +++ b/src/main/java/org/junit/runner/manipulation/Sortable.java @@ -15,6 +15,6 @@ public interface Sortable { * * @param sorter the {@link Sorter} to use for sorting the tests */ - public void sort(Sorter sorter); + void sort(Sorter sorter); } diff --git a/src/main/java/org/junit/runner/manipulation/Sorter.java b/src/main/java/org/junit/runner/manipulation/Sorter.java index 20192d0c96e8..4b5274c31012 100644 --- a/src/main/java/org/junit/runner/manipulation/Sorter.java +++ b/src/main/java/org/junit/runner/manipulation/Sorter.java @@ -1,16 +1,21 @@ package org.junit.runner.manipulation; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Comparator; +import java.util.List; import org.junit.runner.Description; /** * A Sorter orders tests. In general you will not need - * to use a Sorter directly. Instead, use {@link org.junit.runner.Request#sortWith(Comparator)}. + * to use a Sorter directly. Instead, use + * {@link org.junit.runner.Request#sortWith(Comparator)}. * * @since 4.0 */ -public class Sorter implements Comparator { +public class Sorter extends Ordering implements Comparator { /** * NULL is a Sorter that leaves elements in an undefined order */ @@ -27,17 +32,26 @@ public int compare(Description o1, Description o2) { * to sort tests * * @param comparator the {@link Comparator} to use when sorting tests + * @since 4.0 */ public Sorter(Comparator comparator) { this.comparator = comparator; } /** - * Sorts the test in runner using comparator + * Sorts the tests in target using comparator. + * + * @since 4.0 */ - public void apply(Object object) { - if (object instanceof Sortable) { - Sortable sortable = (Sortable) object; + @Override + public void apply(Object target) { + /* + * Note that all runners that are Orderable are also Sortable (because + * Orderable extends Sortable). Sorting is more efficient than ordering, + * so we override the parent behavior so we sort instead. + */ + if (target instanceof Sortable) { + Sortable sortable = (Sortable) target; sortable.sort(this); } } @@ -45,4 +59,32 @@ public void apply(Object object) { public int compare(Description o1, Description o2) { return comparator.compare(o1, o2); } + + /** + * {@inheritDoc} + * + * @since 4.13 + */ + @Override + protected final List orderItems(Collection descriptions) { + /* + * In practice, we will never get here--Sorters do their work in the + * compare() method--but the Liskov substitution principle demands that + * we obey the general contract of Orderable. Luckily, it's trivial to + * implement. + */ + List sorted = new ArrayList(descriptions); + Collections.sort(sorted, this); // Note: it would be incorrect to pass in "comparator" + return sorted; + } + + /** + * {@inheritDoc} + * + * @since 4.13 + */ + @Override + boolean validateOrderingIsCorrect() { + return false; + } } diff --git a/src/main/java/org/junit/runner/notification/Failure.java b/src/main/java/org/junit/runner/notification/Failure.java index c03b4c181407..4551302807b3 100644 --- a/src/main/java/org/junit/runner/notification/Failure.java +++ b/src/main/java/org/junit/runner/notification/Failure.java @@ -1,9 +1,8 @@ package org.junit.runner.notification; -import java.io.PrintWriter; import java.io.Serializable; -import java.io.StringWriter; +import org.junit.internal.Throwables; import org.junit.runner.Description; /** @@ -21,7 +20,7 @@ public class Failure implements Serializable { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * See https://github.com/junit-team/junit4/issues/976 */ private final Description fDescription; private final Throwable fThrownException; @@ -65,15 +64,19 @@ public String toString() { } /** - * Convenience method - * - * @return the printed form of the exception + * Gets the printed form of the exception and its stack trace. */ public String getTrace() { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - getException().printStackTrace(writer); - return stringWriter.toString(); + return Throwables.getStacktrace(getException()); + } + + /** + * Gets a the printed form of the exception, with a trimmed version of the stack trace. + * This method will attempt to filter out frames of the stack trace that are below + * the test method call. + */ + public String getTrimmedTrace() { + return Throwables.getTrimmedStackTrace(getException()); } /** diff --git a/src/main/java/org/junit/runner/notification/RunListener.java b/src/main/java/org/junit/runner/notification/RunListener.java index db9d8c1697ea..d7cac003f1c6 100644 --- a/src/main/java/org/junit/runner/notification/RunListener.java +++ b/src/main/java/org/junit/runner/notification/RunListener.java @@ -69,6 +69,34 @@ public void testRunStarted(Description description) throws Exception { public void testRunFinished(Result result) throws Exception { } + /** + * Called when a test suite is about to be started. If this method is + * called for a given {@link Description}, then {@link #testSuiteFinished(Description)} + * will also be called for the same {@code Description}. + * + *

    Note that not all runners will call this method, so runners should + * be prepared to handle {@link #testStarted(Description)} calls for tests + * where there was no corresponding {@code testSuiteStarted()} call for + * the parent {@code Description}. + * + * @param description the description of the test suite that is about to be run + * (generally a class name) + * @since 4.13 + */ + public void testSuiteStarted(Description description) throws Exception { + } + + /** + * Called when a test suite has finished, whether the test suite succeeds or fails. + * This method will not be called for a given {@link Description} unless + * {@link #testSuiteStarted(Description)} was called for the same @code Description}. + * + * @param description the description of the test suite that just ran + * @since 4.13 + */ + public void testSuiteFinished(Description description) throws Exception { + } + /** * Called when an atomic test is about to be started. * diff --git a/src/main/java/org/junit/runner/notification/RunNotifier.java b/src/main/java/org/junit/runner/notification/RunNotifier.java index 6875f76939ea..8b686cdf287a 100644 --- a/src/main/java/org/junit/runner/notification/RunNotifier.java +++ b/src/main/java/org/junit/runner/notification/RunNotifier.java @@ -65,8 +65,8 @@ private abstract class SafeNotifier { void run() { int capacity = currentListeners.size(); - ArrayList safeListeners = new ArrayList(capacity); - ArrayList failures = new ArrayList(capacity); + List safeListeners = new ArrayList(capacity); + List failures = new ArrayList(capacity); for (RunListener listener : currentListeners) { try { notifyListener(listener); @@ -105,6 +105,41 @@ protected void notifyListener(RunListener each) throws Exception { }.run(); } + /** + * Invoke to tell listeners that a test suite is about to start. Runners are strongly + * encouraged--but not required--to call this method. If this method is called for + * a given {@link Description} then {@link #fireTestSuiteFinished(Description)} MUST + * be called for the same {@code Description}. + * + * @param description the description of the suite test (generally a class name) + * @since 4.13 + */ + public void fireTestSuiteStarted(final Description description) { + new SafeNotifier() { + @Override + protected void notifyListener(RunListener each) throws Exception { + each.testSuiteStarted(description); + } + }.run(); + } + + /** + * Invoke to tell listeners that a test suite is about to finish. Always invoke + * this method if you invoke {@link #fireTestSuiteStarted(Description)} + * as listeners are likely to expect them to come in pairs. + * + * @param description the description of the suite test (generally a class name) + * @since 4.13 + */ + public void fireTestSuiteFinished(final Description description) { + new SafeNotifier() { + @Override + protected void notifyListener(RunListener each) throws Exception { + each.testSuiteFinished(description); + } + }.run(); + } + /** * Invoke to tell listeners that an atomic test is about to start. * diff --git a/src/main/java/org/junit/runner/notification/SynchronizedRunListener.java b/src/main/java/org/junit/runner/notification/SynchronizedRunListener.java index c53c1ee642c7..400fed8fcebf 100644 --- a/src/main/java/org/junit/runner/notification/SynchronizedRunListener.java +++ b/src/main/java/org/junit/runner/notification/SynchronizedRunListener.java @@ -10,7 +10,7 @@ *

    This class synchronizes all listener calls on a RunNotifier instance. This is done because * prior to JUnit 4.12, all listeners were called in a synchronized block in RunNotifier, * so no two listeners were ever called concurrently. If we instead made the methods here - * sychronized, clients that added multiple listeners that called common code might see + * synchronized, clients that added multiple listeners that called common code might see * issues due to the reduced synchronization. * * @author Tibor Digana (tibor17) @@ -43,6 +43,37 @@ public void testRunFinished(Result result) throws Exception { } } + /** + * {@inheritDoc} + *

    + * Synchronized decorator for {@link RunListener#testSuiteStarted(Description)}. + * @param description the description of the test suite that is about to be run + * (generally a class name). + * @throws Exception if any occurs. + * @since 4.13 + */ + @Override + public void testSuiteStarted(Description description) throws Exception { + synchronized (monitor) { + listener.testSuiteStarted(description); + } + } + + /** + * {@inheritDoc} + *

    + * Synchronized decorator for {@link RunListener#testSuiteFinished(Description)}. + * @param description the description of the test suite that just ran. + * @throws Exception + * @since 4.13 + */ + @Override + public void testSuiteFinished(Description description) throws Exception { + synchronized (monitor) { + listener.testSuiteFinished(description); + } + } + @Override public void testStarted(Description description) throws Exception { synchronized (monitor) { diff --git a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java index 4d06199164e8..455341aa0cb9 100644 --- a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java +++ b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java @@ -3,8 +3,10 @@ import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_METHOD_VALIDATOR; import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_VALIDATOR; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import org.junit.After; @@ -21,14 +23,18 @@ import org.junit.internal.runners.statements.RunAfters; import org.junit.internal.runners.statements.RunBefores; import org.junit.rules.MethodRule; -import org.junit.rules.RunRules; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.FrameworkMember; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; +import org.junit.runners.model.MemberValueConsumer; import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; +import org.junit.runners.model.TestClass; +import org.junit.validator.PublicClassValidator; +import org.junit.validator.TestClassValidator; /** * Implements the JUnit 4 standard test case class model, as defined by the @@ -55,14 +61,27 @@ * @since 4.5 */ public class BlockJUnit4ClassRunner extends ParentRunner { - private final ConcurrentHashMap methodDescriptions = new ConcurrentHashMap(); + private static TestClassValidator PUBLIC_CLASS_VALIDATOR = new PublicClassValidator(); + + private final ConcurrentMap methodDescriptions = new ConcurrentHashMap(); + + /** + * Creates a BlockJUnit4ClassRunner to run {@code testClass} + * + * @throws InitializationError if the test class is malformed. + */ + public BlockJUnit4ClassRunner(Class testClass) throws InitializationError { + super(testClass); + } + /** - * Creates a BlockJUnit4ClassRunner to run {@code klass} + * Creates a BlockJUnit4ClassRunner to run {@code testClass}. * * @throws InitializationError if the test class is malformed. + * @since 4.13 */ - public BlockJUnit4ClassRunner(Class klass) throws InitializationError { - super(klass); + protected BlockJUnit4ClassRunner(TestClass testClass) throws InitializationError { + super(testClass); } // @@ -75,10 +94,16 @@ protected void runChild(final FrameworkMethod method, RunNotifier notifier) { if (isIgnored(method)) { notifier.fireTestIgnored(description); } else { - runLeaf(methodBlock(method), description, notifier); + Statement statement = new Statement() { + @Override + public void evaluate() throws Throwable { + methodBlock(method).evaluate(); + } + }; + runLeaf(statement, description, notifier); } } - + /** * Evaluates whether {@link FrameworkMethod}s are ignored based on the * {@link Ignore} annotation. @@ -123,6 +148,7 @@ protected List computeTestMethods() { protected void collectInitializationErrors(List errors) { super.collectInitializationErrors(errors); + validatePublicConstructor(errors); validateNoNonStaticInnerClass(errors); validateConstructor(errors); validateInstanceMethods(errors); @@ -130,6 +156,12 @@ protected void collectInitializationErrors(List errors) { validateMethods(errors); } + private void validatePublicConstructor(List errors) { + if (getTestClass().getJavaClass() != null) { + errors.addAll(PUBLIC_CLASS_VALIDATOR.validateTestClass(getTestClass())); + } + } + protected void validateNoNonStaticInnerClass(List errors) { if (getTestClass().isANonStaticInnerClass()) { String gripe = "The inner class " + getTestClass().getName() @@ -180,6 +212,7 @@ private boolean hasOneConstructor() { * 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 */ @Deprecated protected void validateInstanceMethods(List errors) { @@ -187,7 +220,7 @@ protected void validateInstanceMethods(List errors) { validatePublicVoidNoArgMethods(Before.class, false, errors); validateTestMethods(errors); - if (computeTestMethods().size() == 0) { + if (computeTestMethods().isEmpty()) { errors.add(new Exception("No runnable methods")); } } @@ -217,6 +250,16 @@ protected Object createTest() throws Exception { return getTestClass().getOnlyConstructor().newInstance(); } + /** + * Returns a new fixture to run a particular test {@code method} against. + * Default implementation executes the no-argument {@link #createTest()} method. + * + * @since 4.13 + */ + protected Object createTest(FrameworkMethod method) throws Exception { + return createTest(); + } + /** * Returns the name that describes {@code method} for {@link Description}s. * Default implementation is the method's name @@ -232,10 +275,10 @@ protected String testName(FrameworkMethod method) { * Here is an outline of the default implementation: * *

      - *
    • Invoke {@code method} on the result of {@code createTest()}, and + *
    • Invoke {@code method} on the result of {@link #createTest(org.junit.runners.model.FrameworkMethod)}, and * throw any exceptions thrown by either operation. - *
    • HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code - * expecting} attribute, return normally only if the previous step threw an + *
    • HOWEVER, if {@code method}'s {@code @Test} annotation has the {@link Test#expected()} + * attribute, return normally only if the previous step threw an * exception of the correct type, and throw an exception otherwise. *
    • HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code * timeout} attribute, throw an exception if the previous step takes more @@ -257,13 +300,13 @@ protected String testName(FrameworkMethod method) { * This can be overridden in subclasses, either by overriding this method, * or the implementations creating each sub-statement. */ - protected Statement methodBlock(FrameworkMethod method) { + protected Statement methodBlock(final FrameworkMethod method) { Object test; try { test = new ReflectiveCallable() { @Override protected Object runReflectiveCall() throws Throwable { - return createTest(); + return createTest(method); } }.run(); } catch (Throwable e) { @@ -276,6 +319,7 @@ protected Object runReflectiveCall() throws Throwable { statement = withBefores(method, test, statement); statement = withAfters(method, test, statement); statement = withRules(method, test, statement); + statement = withInterruptIsolation(statement); return statement; } @@ -292,21 +336,22 @@ protected Statement methodInvoker(FrameworkMethod method, Object test) { /** * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation - * has the {@code expecting} attribute, return normally only if {@code next} + * has the {@link Test#expected()} attribute, return normally only if {@code next} * throws an exception of the correct type, and throw an exception * otherwise. */ protected Statement possiblyExpectingExceptions(FrameworkMethod method, Object test, Statement next) { Test annotation = method.getAnnotation(Test.class); - return expectsException(annotation) ? new ExpectException(next, - getExpectedException(annotation)) : next; + Class expectedExceptionClass = getExpectedException(annotation); + return expectedExceptionClass != null ? new ExpectException(next, expectedExceptionClass) : 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 */ @Deprecated protected Statement withPotentialTimeout(FrameworkMethod method, @@ -348,28 +393,23 @@ protected Statement withAfters(FrameworkMethod method, Object target, target); } - private Statement withRules(FrameworkMethod method, Object target, - Statement statement) { - List testRules = getTestRules(target); - Statement result = statement; - result = withMethodRules(method, testRules, target, result); - result = withTestRules(method, testRules, result); - - return result; - } - - private Statement withMethodRules(FrameworkMethod method, List testRules, - Object target, Statement result) { - for (org.junit.rules.MethodRule each : getMethodRules(target)) { - if (!testRules.contains(each)) { - result = each.apply(result, method, target); + private Statement withRules(FrameworkMethod method, Object target, Statement statement) { + RuleContainer ruleContainer = new RuleContainer(); + CURRENT_RULE_CONTAINER.set(ruleContainer); + try { + List testRules = getTestRules(target); + for (MethodRule each : rules(target)) { + if (!(each instanceof TestRule && testRules.contains(each))) { + ruleContainer.add(each); + } } + for (TestRule rule : testRules) { + ruleContainer.add(rule); + } + } finally { + CURRENT_RULE_CONTAINER.remove(); } - return result; - } - - private List getMethodRules(Object target) { - return rules(target); + return ruleContainer.apply(method, describeChild(method), target, statement); } /** @@ -378,27 +418,12 @@ private List getMethodRules(Object target) { * test */ protected List rules(Object target) { - List rules = getTestClass().getAnnotatedMethodValues(target, - Rule.class, MethodRule.class); - - rules.addAll(getTestClass().getAnnotatedFieldValues(target, - Rule.class, MethodRule.class)); - - return rules; - } - - /** - * Returns a {@link Statement}: apply all non-static 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, List testRules, - Statement statement) { - return testRules.isEmpty() ? statement : - new RunRules(statement, testRules, describeChild(method)); + RuleCollector collector = new RuleCollector(); + getTestClass().collectAnnotatedMethodValues(target, Rule.class, MethodRule.class, + collector); + getTestClass().collectAnnotatedFieldValues(target, Rule.class, MethodRule.class, + collector); + return collector.result; } /** @@ -407,13 +432,10 @@ private Statement withTestRules(FrameworkMethod method, List testRules * test */ protected List getTestRules(Object target) { - List result = getTestClass().getAnnotatedMethodValues(target, - Rule.class, TestRule.class); - - result.addAll(getTestClass().getAnnotatedFieldValues(target, - Rule.class, TestRule.class)); - - return result; + RuleCollector collector = new RuleCollector(); + getTestClass().collectAnnotatedMethodValues(target, Rule.class, TestRule.class, collector); + getTestClass().collectAnnotatedFieldValues(target, Rule.class, TestRule.class, collector); + return collector.result; } private Class getExpectedException(Test annotation) { @@ -424,14 +446,28 @@ private Class getExpectedException(Test annotation) { } } - private boolean expectsException(Test annotation) { - return getExpectedException(annotation) != null; - } - private long getTimeout(Test annotation) { if (annotation == null) { return 0; } return annotation.timeout(); } + + private static final ThreadLocal CURRENT_RULE_CONTAINER = + new ThreadLocal(); + + private static class RuleCollector implements MemberValueConsumer { + final List result = new ArrayList(); + + public void accept(FrameworkMember member, T value) { + Rule rule = member.getAnnotation(Rule.class); + if (rule != null) { + RuleContainer container = CURRENT_RULE_CONTAINER.get(); + if (container != null) { + container.setOrder(value, rule.order()); + } + } + result.add(value); + } + } } diff --git a/src/main/java/org/junit/runners/JUnit4.java b/src/main/java/org/junit/runners/JUnit4.java index 6ba28c2fd431..28eafb3a1050 100644 --- a/src/main/java/org/junit/runners/JUnit4.java +++ b/src/main/java/org/junit/runners/JUnit4.java @@ -1,6 +1,7 @@ package org.junit.runners; import org.junit.runners.model.InitializationError; +import org.junit.runners.model.TestClass; /** * Aliases the current default JUnit 4 class runner, for future-proofing. If @@ -19,6 +20,6 @@ public final class JUnit4 extends BlockJUnit4ClassRunner { * Constructs a new instance of the default runner */ public JUnit4(Class klass) throws InitializationError { - super(klass); + super(new TestClass(klass)); } } diff --git a/src/main/java/org/junit/runners/Parameterized.java b/src/main/java/org/junit/runners/Parameterized.java index 829c8f0f15af..d11b66a2d0c3 100644 --- a/src/main/java/org/junit/runners/Parameterized.java +++ b/src/main/java/org/junit/runners/Parameterized.java @@ -1,5 +1,6 @@ package org.junit.runners; +import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; @@ -8,12 +9,18 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.Result; import org.junit.runner.Runner; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.InitializationError; +import org.junit.runners.model.InvalidTestClassError; import org.junit.runners.model.TestClass; import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParametersFactory; import org.junit.runners.parameterized.ParametersRunnerFactory; @@ -24,34 +31,37 @@ * When running a parameterized test class, instances are created for the * cross-product of the test methods and the test data elements. *

      - * For example, to test a Fibonacci function, write: + * For example, to test the + operator, write: *

        * @RunWith(Parameterized.class)
      - * public class FibonacciTest {
      - *     @Parameters(name= "{index}: fib[{0}]={1}")
      + * public class AdditionTest {
      + *     @Parameters(name = "{index}: {0} + {1} = {2}")
        *     public static Iterable<Object[]> data() {
      - *         return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
      - *                 { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
      + *         return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 },
      + *                 { 3, 2, 5 }, { 4, 3, 7 } });
        *     }
        *
      - *     private int fInput;
      + *     private int firstSummand;
        *
      - *     private int fExpected;
      + *     private int secondSummand;
        *
      - *     public FibonacciTest(int input, int expected) {
      - *         fInput= input;
      - *         fExpected= expected;
      + *     private int sum;
      + *
      + *     public AdditionTest(int firstSummand, int secondSummand, int sum) {
      + *         this.firstSummand = firstSummand;
      + *         this.secondSummand = secondSummand;
      + *         this.sum = sum;
        *     }
        *
        *     @Test
        *     public void test() {
      - *         assertEquals(fExpected, Fibonacci.compute(fInput));
      + *         assertEquals(sum, firstSummand + secondSummand);
        *     }
        * }
        * 
      *

      - * Each instance of FibonacciTest will be constructed using the - * two-argument constructor and the data values in the + * Each instance of AdditionTest will be constructed using the + * three-argument constructor and the data values in the * @Parameters method. *

      * In order that you can easily identify the individual tests, you may provide a @@ -69,33 +79,36 @@ * *

      * In the example given above, the Parameterized runner creates - * names like [1: fib(3)=2]. If you don't use the name parameter, + * names like [2: 3 + 2 = 5]. If you don't use the name parameter, * then the current parameter index is used as name. *

      * You can also write: *

        * @RunWith(Parameterized.class)
      - * public class FibonacciTest {
      - *  @Parameters
      - *  public static Iterable<Object[]> data() {
      - *      return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
      - *                 { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
      - *  }
      - *  
      - *  @Parameter(0)
      - *  public int fInput;
      + * public class AdditionTest {
      + *     @Parameters(name = "{index}: {0} + {1} = {2}")
      + *     public static Iterable<Object[]> data() {
      + *         return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 },
      + *                 { 3, 2, 5 }, { 4, 3, 7 } });
      + *     }
      + *
      + *     @Parameter(0)
      + *     public int firstSummand;
        *
      - *  @Parameter(1)
      - *  public int fExpected;
      + *     @Parameter(1)
      + *     public int secondSummand;
        *
      - *  @Test
      - *  public void test() {
      - *      assertEquals(fExpected, Fibonacci.compute(fInput));
      - *  }
      + *     @Parameter(2)
      + *     public int sum;
      + *
      + *     @Test
      + *     public void test() {
      + *         assertEquals(sum, firstSummand + secondSummand);
      + *     }
        * }
        * 
      *

      - * Each instance of FibonacciTest will be constructed with the default constructor + * Each instance of AdditionTest will be constructed with the default constructor * and fields annotated by @Parameter will be initialized * with the data values in the @Parameters method. * @@ -105,8 +118,7 @@ *

        * @Parameters
        * public static Object[][] data() {
      - * 	return new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 },
      - * 			{ 5, 5 }, { 6, 8 } };
      + * 	return new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, { 3, 2, 5 }, { 4, 3, 7 } } };
        * }
        * 
      * @@ -130,6 +142,19 @@ * } * * + *

      Executing code before/after executing tests for specific parameters

      + *

      + * If your test needs to perform some preparation or cleanup based on the + * parameters, this can be done by adding public static methods annotated with + * {@code @BeforeParam}/{@code @AfterParam}. Such methods should either have no + * parameters or the same parameters as the test. + *

      + * @BeforeParam
      + * public static void beforeTestsForParameter(String onlyParameter) {
      + *     System.out.println("Testing " + onlyParameter);
      + * }
      + * 
      + * *

      Create different runners

      *

      * By default the {@code Parameterized} runner creates a slightly modified @@ -141,7 +166,7 @@ * The factory must have a public zero-arg constructor. * *

      - * public class YourRunnerFactory implements ParameterizedRunnerFactory {
      + * public class YourRunnerFactory implements ParametersRunnerFactory {
        *     public Runner createRunnerForTestWithParameters(TestWithParameters test)
        *             throws InitializationError {
        *         return YourRunner(test);
      @@ -160,6 +185,21 @@
        * }
        * 
      * + *

      Avoid creating parameters

      + *

      With {@link org.junit.Assume assumptions} you can dynamically skip tests. + * Assumptions are also supported by the @Parameters method. + * Creating parameters is stopped when the assumption fails and none of the + * tests in the test class is executed. JUnit reports a + * {@link Result#getAssumptionFailureCount() single assumption failure} for the + * whole test class in this case. + *

      + * @Parameters
      + * public static Iterable<? extends Object> data() {
      + * 	String os = System.getProperty("os.name").toLowerCase()
      + * 	Assume.assumeTrue(os.contains("win"));
      + * 	return Arrays.asList("first test", "second test");
      + * }
      + * 
      * @since 4.0 */ public class Parameterized extends Suite { @@ -170,7 +210,7 @@ public class Parameterized extends Suite { */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) - public static @interface Parameters { + public @interface Parameters { /** * Optional pattern to derive the test's name from the parameters. Use * numbers in braces to refer to the parameters or the additional data @@ -201,7 +241,7 @@ public class Parameterized extends Suite { */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) - public static @interface Parameter { + public @interface Parameter { /** * Method that returns the index of the parameter in the array * returned by the method annotated by Parameters. @@ -230,122 +270,235 @@ public class Parameterized extends Suite { Class value() default BlockJUnit4ClassRunnerWithParametersFactory.class; } - private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory(); - - private static final List NO_RUNNERS = Collections.emptyList(); + /** + * Annotation for {@code public static void} methods which should be executed before + * evaluating tests with particular parameters. + * + * @see org.junit.BeforeClass + * @see org.junit.Before + * @since 4.13 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface BeforeParam { + } - private final List runners; + /** + * Annotation for {@code public static void} methods which should be executed after + * evaluating tests with particular parameters. + * + * @see org.junit.AfterClass + * @see org.junit.After + * @since 4.13 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface AfterParam { + } /** * Only called reflectively. Do not use programmatically. */ public Parameterized(Class klass) throws Throwable { - super(klass, NO_RUNNERS); - ParametersRunnerFactory runnerFactory = getParametersRunnerFactory( - klass); - Parameters parameters = getParametersMethod().getAnnotation( - Parameters.class); - runners = Collections.unmodifiableList(createRunnersForParameters( - allParameters(), parameters.name(), runnerFactory)); + this(klass, new RunnersFactory(klass)); } - private ParametersRunnerFactory getParametersRunnerFactory(Class klass) - throws InstantiationException, IllegalAccessException { - UseParametersRunnerFactory annotation = klass - .getAnnotation(UseParametersRunnerFactory.class); - if (annotation == null) { - return DEFAULT_FACTORY; - } else { - Class factoryClass = annotation - .value(); - return factoryClass.newInstance(); - } + private Parameterized(Class klass, RunnersFactory runnersFactory) throws Exception { + super(klass, runnersFactory.createRunners()); + validateBeforeParamAndAfterParamMethods(runnersFactory.parameterCount); } - @Override - protected List getChildren() { - return runners; + private void validateBeforeParamAndAfterParamMethods(Integer parameterCount) + throws InvalidTestClassError { + List errors = new ArrayList(); + validatePublicStaticVoidMethods(Parameterized.BeforeParam.class, parameterCount, errors); + validatePublicStaticVoidMethods(Parameterized.AfterParam.class, parameterCount, errors); + if (!errors.isEmpty()) { + throw new InvalidTestClassError(getTestClass().getJavaClass(), errors); + } } - private TestWithParameters createTestWithNotNormalizedParameters( - String pattern, int index, Object parametersOrSingleParameter) { - Object[] parameters= (parametersOrSingleParameter instanceof Object[]) ? (Object[]) parametersOrSingleParameter - : new Object[] { parametersOrSingleParameter }; - return createTestWithParameters(getTestClass(), pattern, index, - parameters); + private void validatePublicStaticVoidMethods( + Class annotation, Integer parameterCount, + List errors) { + List methods = getTestClass().getAnnotatedMethods(annotation); + for (FrameworkMethod fm : methods) { + fm.validatePublicVoid(true, errors); + if (parameterCount != null) { + int methodParameterCount = fm.getMethod().getParameterTypes().length; + if (methodParameterCount != 0 && methodParameterCount != parameterCount) { + errors.add(new Exception("Method " + fm.getName() + + "() should have 0 or " + parameterCount + " parameter(s)")); + } + } + } } - @SuppressWarnings("unchecked") - private Iterable allParameters() throws Throwable { - Object parameters = getParametersMethod().invokeExplosively(null); - if (parameters instanceof Iterable) { - return (Iterable) parameters; - } else if (parameters instanceof Object[]) { - return Arrays.asList((Object[]) parameters); - } else { - throw parametersMethodReturnedWrongType(); + private static class AssumptionViolationRunner extends Runner { + private final Description description; + private final AssumptionViolatedException exception; + + AssumptionViolationRunner(TestClass testClass, String methodName, + AssumptionViolatedException exception) { + this.description = Description + .createTestDescription(testClass.getJavaClass(), + methodName + "() assumption violation"); + this.exception = exception; + } + + @Override + public Description getDescription() { + return description; + } + + @Override + public void run(RunNotifier notifier) { + notifier.fireTestAssumptionFailed(new Failure(description, exception)); } } - private FrameworkMethod getParametersMethod() throws Exception { - List methods = getTestClass().getAnnotatedMethods( - Parameters.class); - for (FrameworkMethod each : methods) { - if (each.isStatic() && each.isPublic()) { - return each; + private static class RunnersFactory { + private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory(); + + private final TestClass testClass; + private final FrameworkMethod parametersMethod; + private final List allParameters; + private final int parameterCount; + private final Runner runnerOverride; + + private RunnersFactory(Class klass) throws Throwable { + testClass = new TestClass(klass); + parametersMethod = getParametersMethod(testClass); + List allParametersResult; + AssumptionViolationRunner assumptionViolationRunner = null; + try { + allParametersResult = allParameters(testClass, parametersMethod); + } catch (AssumptionViolatedException e) { + allParametersResult = Collections.emptyList(); + assumptionViolationRunner = new AssumptionViolationRunner(testClass, + parametersMethod.getName(), e); } + allParameters = allParametersResult; + runnerOverride = assumptionViolationRunner; + parameterCount = + allParameters.isEmpty() ? 0 : normalizeParameters(allParameters.get(0)).length; } - throw new Exception("No public static parameters method on class " - + getTestClass().getName()); - } + private List createRunners() throws Exception { + if (runnerOverride != null) { + return Collections.singletonList(runnerOverride); + } + Parameters parameters = parametersMethod.getAnnotation(Parameters.class); + return Collections.unmodifiableList(createRunnersForParameters( + allParameters, parameters.name(), + getParametersRunnerFactory())); + } - private List createRunnersForParameters( - Iterable allParameters, String namePattern, - ParametersRunnerFactory runnerFactory) - throws InitializationError, - Exception { - try { - List tests = createTestsForParameters( - allParameters, namePattern); - List runners = new ArrayList(); - for (TestWithParameters test : tests) { - runners.add(runnerFactory - .createRunnerForTestWithParameters(test)); + private ParametersRunnerFactory getParametersRunnerFactory() + throws InstantiationException, IllegalAccessException { + UseParametersRunnerFactory annotation = testClass + .getAnnotation(UseParametersRunnerFactory.class); + if (annotation == null) { + return DEFAULT_FACTORY; + } else { + Class factoryClass = annotation + .value(); + return factoryClass.newInstance(); } - return runners; - } catch (ClassCastException e) { - throw parametersMethodReturnedWrongType(); } - } - private List createTestsForParameters( - Iterable allParameters, String namePattern) - throws Exception { - int i = 0; - List children = new ArrayList(); - for (Object parametersOfSingleTest : allParameters) { - children.add(createTestWithNotNormalizedParameters(namePattern, - i++, parametersOfSingleTest)); + private TestWithParameters createTestWithNotNormalizedParameters( + String pattern, int index, Object parametersOrSingleParameter) { + Object[] parameters = normalizeParameters(parametersOrSingleParameter); + return createTestWithParameters(testClass, pattern, index, parameters); } - return children; - } - private Exception parametersMethodReturnedWrongType() throws Exception { - String className = getTestClass().getName(); - String methodName = getParametersMethod().getName(); - String message = MessageFormat.format( - "{0}.{1}() must return an Iterable of arrays.", - className, methodName); - return new Exception(message); - } + private static Object[] normalizeParameters(Object parametersOrSingleParameter) { + return (parametersOrSingleParameter instanceof Object[]) ? (Object[]) parametersOrSingleParameter + : new Object[] { parametersOrSingleParameter }; + } - private static TestWithParameters createTestWithParameters( - TestClass testClass, String pattern, int index, Object[] parameters) { - String finalPattern = pattern.replaceAll("\\{index\\}", - Integer.toString(index)); - String name = MessageFormat.format(finalPattern, parameters); - return new TestWithParameters("[" + name + "]", testClass, - Arrays.asList(parameters)); + @SuppressWarnings("unchecked") + private static List allParameters( + TestClass testClass, FrameworkMethod parametersMethod) throws Throwable { + Object parameters = parametersMethod.invokeExplosively(null); + if (parameters instanceof List) { + return (List) parameters; + } else if (parameters instanceof Collection) { + return new ArrayList((Collection) parameters); + } else if (parameters instanceof Iterable) { + List result = new ArrayList(); + for (Object entry : ((Iterable) parameters)) { + result.add(entry); + } + return result; + } else if (parameters instanceof Object[]) { + return Arrays.asList((Object[]) parameters); + } else { + throw parametersMethodReturnedWrongType(testClass, parametersMethod); + } + } + + private static FrameworkMethod getParametersMethod(TestClass testClass) throws Exception { + List methods = testClass + .getAnnotatedMethods(Parameters.class); + for (FrameworkMethod each : methods) { + if (each.isStatic() && each.isPublic()) { + return each; + } + } + + throw new Exception("No public static parameters method on class " + + testClass.getName()); + } + + private List createRunnersForParameters( + Iterable allParameters, String namePattern, + ParametersRunnerFactory runnerFactory) throws Exception { + try { + List tests = createTestsForParameters( + allParameters, namePattern); + List runners = new ArrayList(); + for (TestWithParameters test : tests) { + runners.add(runnerFactory + .createRunnerForTestWithParameters(test)); + } + return runners; + } catch (ClassCastException e) { + throw parametersMethodReturnedWrongType(testClass, parametersMethod); + } + } + + private List createTestsForParameters( + Iterable allParameters, String namePattern) + throws Exception { + int i = 0; + List children = new ArrayList(); + for (Object parametersOfSingleTest : allParameters) { + children.add(createTestWithNotNormalizedParameters(namePattern, + i++, parametersOfSingleTest)); + } + return children; + } + + private static Exception parametersMethodReturnedWrongType( + TestClass testClass, FrameworkMethod parametersMethod) throws Exception { + String className = testClass.getName(); + String methodName = parametersMethod.getName(); + String message = MessageFormat.format( + "{0}.{1}() must return an Iterable of arrays.", className, + methodName); + return new Exception(message); + } + + private TestWithParameters createTestWithParameters( + TestClass testClass, String pattern, int index, + Object[] parameters) { + String finalPattern = pattern.replaceAll("\\{index\\}", + Integer.toString(index)); + String name = MessageFormat.format(finalPattern, parameters); + return new TestWithParameters("[" + name + "]", testClass, + Arrays.asList(parameters)); + } } } diff --git a/src/main/java/org/junit/runners/ParentRunner.java b/src/main/java/org/junit/runners/ParentRunner.java old mode 100755 new mode 100644 index 92641bf64cf7..0a0e7cb6a583 --- a/src/main/java/org/junit/runners/ParentRunner.java +++ b/src/main/java/org/junit/runners/ParentRunner.java @@ -1,21 +1,25 @@ package org.junit.runners; +import static org.junit.internal.Checks.notNull; import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR; import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.FixMethodOrder; import org.junit.Ignore; import org.junit.Rule; import org.junit.internal.AssumptionViolatedException; @@ -28,18 +32,22 @@ import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.Filterable; +import org.junit.runner.manipulation.Orderer; +import org.junit.runner.manipulation.InvalidOrderingException; import org.junit.runner.manipulation.NoTestsRemainException; -import org.junit.runner.manipulation.Sortable; +import org.junit.runner.manipulation.Orderable; import org.junit.runner.manipulation.Sorter; import org.junit.runner.notification.RunNotifier; import org.junit.runner.notification.StoppedByUserException; +import org.junit.runners.model.FrameworkMember; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; +import org.junit.runners.model.InvalidTestClassError; +import org.junit.runners.model.MemberValueConsumer; import org.junit.runners.model.RunnerScheduler; import org.junit.runners.model.Statement; import org.junit.runners.model.TestClass; import org.junit.validator.AnnotationsValidator; -import org.junit.validator.PublicClassValidator; import org.junit.validator.TestClassValidator; /** @@ -56,15 +64,15 @@ * @since 4.5 */ public abstract class ParentRunner extends Runner implements Filterable, - Sortable { - private static final List VALIDATORS = Arrays.asList( - new AnnotationsValidator(), new PublicClassValidator()); + Orderable { + private static final List VALIDATORS = Collections.singletonList( + new AnnotationsValidator()); - private final Object childrenLock = new Object(); + private final Lock childrenLock = new ReentrantLock(); private final TestClass testClass; // Guarded by childrenLock - private volatile Collection filteredChildren = null; + private volatile List filteredChildren = null; private volatile RunnerScheduler scheduler = new RunnerScheduler() { public void schedule(Runnable childStatement) { @@ -84,6 +92,21 @@ protected ParentRunner(Class testClass) throws InitializationError { validate(); } + /** + * Constructs a new {@code ParentRunner} that will run the {@code TestClass}. + * + * @since 4.13 + */ + protected ParentRunner(TestClass testClass) throws InitializationError { + this.testClass = notNull(testClass); + validate(); + } + + /** + * @deprecated Please use {@link #ParentRunner(org.junit.runners.model.TestClass)}. + * @since 4.12 + */ + @Deprecated protected TestClass createTestClass(Class testClass) { return new TestClass(testClass); } @@ -192,6 +215,7 @@ protected Statement classBlock(final RunNotifier notifier) { statement = withBeforeClasses(statement); statement = withAfterClasses(statement); statement = withClassRules(statement); + statement = withInterruptIsolation(statement); } return statement; } @@ -219,7 +243,7 @@ protected Statement withBeforeClasses(Statement statement) { /** * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class - * and superclasses before executing {@code statement}; all AfterClass methods are + * and superclasses after 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 org.junit.runners.model.MultipleFailureException}. @@ -251,9 +275,10 @@ private Statement withClassRules(Statement statement) { * each method in the tested class. */ protected List classRules() { - List result = testClass.getAnnotatedMethodValues(null, ClassRule.class, TestRule.class); - result.addAll(testClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class)); - return result; + ClassRuleCollector collector = new ClassRuleCollector(); + testClass.collectAnnotatedMethodValues(null, ClassRule.class, TestRule.class, collector); + testClass.collectAnnotatedFieldValues(null, ClassRule.class, TestRule.class, collector); + return collector.getOrderedRules(); } /** @@ -270,6 +295,22 @@ public void evaluate() { }; } + /** + * @return a {@link Statement}: clears interrupt status of current thread after execution of statement + */ + protected final Statement withInterruptIsolation(final Statement statement) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try { + statement.evaluate(); + } finally { + Thread.interrupted(); // clearing thread interrupted status for isolation + } + } + }; + } + /** * Evaluates whether a child is ignored. The default implementation always * returns false. @@ -346,8 +387,16 @@ protected Annotation[] getRunnerAnnotations() { @Override public Description getDescription() { - Description description = Description.createSuiteDescription(getName(), - getRunnerAnnotations()); + Class clazz = getTestClass().getJavaClass(); + Description description; + // if subclass overrides `getName()` then we should use it + // to maintain backwards compatibility with JUnit 4.12 + if (clazz == null || !clazz.getName().equals(getName())) { + description = Description.createSuiteDescription(getName(), getRunnerAnnotations()); + } else { + description = Description.createSuiteDescription(clazz, getRunnerAnnotations()); + } + for (T child : getFilteredChildren()) { description.addChild(describeChild(child)); } @@ -358,6 +407,7 @@ public Description getDescription() { public void run(final RunNotifier notifier) { EachTestNotifier testNotifier = new EachTestNotifier(notifier, getDescription()); + testNotifier.fireTestSuiteStarted(); try { Statement statement = classBlock(notifier); statement.evaluate(); @@ -367,6 +417,8 @@ public void run(final RunNotifier notifier) { throw e; } catch (Throwable e) { testNotifier.addFailure(e); + } finally { + testNotifier.fireTestSuiteFinished(); } } @@ -375,7 +427,8 @@ public void run(final RunNotifier notifier) { // public void filter(Filter filter) throws NoTestsRemainException { - synchronized (childrenLock) { + childrenLock.lock(); + try { List children = new ArrayList(getFilteredChildren()); for (Iterator iter = children.iterator(); iter.hasNext(); ) { T each = iter.next(); @@ -389,21 +442,70 @@ public void filter(Filter filter) throws NoTestsRemainException { iter.remove(); } } - filteredChildren = Collections.unmodifiableCollection(children); + filteredChildren = Collections.unmodifiableList(children); if (filteredChildren.isEmpty()) { throw new NoTestsRemainException(); } + } finally { + childrenLock.unlock(); } } public void sort(Sorter sorter) { - synchronized (childrenLock) { + if (shouldNotReorder()) { + return; + } + + childrenLock.lock(); + try { for (T each : getFilteredChildren()) { sorter.apply(each); } List sortedChildren = new ArrayList(getFilteredChildren()); Collections.sort(sortedChildren, comparator(sorter)); - filteredChildren = Collections.unmodifiableCollection(sortedChildren); + filteredChildren = Collections.unmodifiableList(sortedChildren); + } finally { + childrenLock.unlock(); + } + } + + /** + * Implementation of {@link Orderable#order(Orderer)}. + * + * @since 4.13 + */ + public void order(Orderer orderer) throws InvalidOrderingException { + if (shouldNotReorder()) { + return; + } + + childrenLock.lock(); + try { + List children = getFilteredChildren(); + // In theory, we could have duplicate Descriptions. De-dup them before ordering, + // and add them back at the end. + Map> childMap = new LinkedHashMap>( + children.size()); + for (T child : children) { + Description description = describeChild(child); + List childrenWithDescription = childMap.get(description); + if (childrenWithDescription == null) { + childrenWithDescription = new ArrayList(1); + childMap.put(description, childrenWithDescription); + } + childrenWithDescription.add(child); + orderer.apply(child); + } + + List inOrder = orderer.order(childMap.keySet()); + + children = new ArrayList(children.size()); + for (Description description : inOrder) { + children.addAll(childMap.get(description)); + } + filteredChildren = Collections.unmodifiableList(children); + } finally { + childrenLock.unlock(); } } @@ -411,20 +513,29 @@ public void sort(Sorter sorter) { // Private implementation // + private boolean shouldNotReorder() { + // If the test specifies a specific order, do not reorder. + return getDescription().getAnnotation(FixMethodOrder.class) != null; + } + private void validate() throws InitializationError { List errors = new ArrayList(); collectInitializationErrors(errors); if (!errors.isEmpty()) { - throw new InitializationError(errors); + throw new InvalidTestClassError(testClass.getJavaClass(), errors); } } - private Collection getFilteredChildren() { + private List getFilteredChildren() { if (filteredChildren == null) { - synchronized (childrenLock) { + childrenLock.lock(); + try { if (filteredChildren == null) { - filteredChildren = Collections.unmodifiableCollection(getChildren()); + filteredChildren = Collections.unmodifiableList( + new ArrayList(getChildren())); } + } finally { + childrenLock.unlock(); } } return filteredChildren; @@ -449,4 +560,23 @@ public int compare(T o1, T o2) { public void setScheduler(RunnerScheduler scheduler) { this.scheduler = scheduler; } + + private static class ClassRuleCollector implements MemberValueConsumer { + final List entries = new ArrayList(); + + public void accept(FrameworkMember member, TestRule value) { + ClassRule rule = member.getAnnotation(ClassRule.class); + entries.add(new RuleContainer.RuleEntry(value, RuleContainer.RuleEntry.TYPE_TEST_RULE, + rule != null ? rule.order() : null)); + } + + public List getOrderedRules() { + Collections.sort(entries, RuleContainer.ENTRY_COMPARATOR); + List result = new ArrayList(entries.size()); + for (RuleContainer.RuleEntry entry : entries) { + result.add((TestRule) entry.rule); + } + return result; + } + } } diff --git a/src/main/java/org/junit/runners/RuleContainer.java b/src/main/java/org/junit/runners/RuleContainer.java new file mode 100644 index 000000000000..30ddd8d38a03 --- /dev/null +++ b/src/main/java/org/junit/runners/RuleContainer.java @@ -0,0 +1,113 @@ +package org.junit.runners; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.IdentityHashMap; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.MethodRule; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +/** + * Data structure for ordering of {@link TestRule}/{@link MethodRule} instances. + * + * @since 4.13 + */ +class RuleContainer { + private final IdentityHashMap orderValues = new IdentityHashMap(); + private final List testRules = new ArrayList(); + private final List methodRules = new ArrayList(); + + /** + * Sets order value for the specified rule. + */ + public void setOrder(Object rule, int order) { + orderValues.put(rule, order); + } + + public void add(MethodRule methodRule) { + methodRules.add(methodRule); + } + + public void add(TestRule testRule) { + testRules.add(testRule); + } + + static final Comparator ENTRY_COMPARATOR = new Comparator() { + public int compare(RuleEntry o1, RuleEntry o2) { + int result = compareInt(o1.order, o2.order); + return result != 0 ? result : o1.type - o2.type; + } + + private int compareInt(int a, int b) { + return (a < b) ? 1 : (a == b ? 0 : -1); + } + }; + + /** + * Returns entries in the order how they should be applied, i.e. inner-to-outer. + */ + private List getSortedEntries() { + List ruleEntries = new ArrayList( + methodRules.size() + testRules.size()); + for (MethodRule rule : methodRules) { + ruleEntries.add(new RuleEntry(rule, RuleEntry.TYPE_METHOD_RULE, orderValues.get(rule))); + } + for (TestRule rule : testRules) { + ruleEntries.add(new RuleEntry(rule, RuleEntry.TYPE_TEST_RULE, orderValues.get(rule))); + } + Collections.sort(ruleEntries, ENTRY_COMPARATOR); + return ruleEntries; + } + + /** + * Applies all the rules ordered accordingly to the specified {@code statement}. + */ + public Statement apply(FrameworkMethod method, Description description, Object target, + Statement statement) { + if (methodRules.isEmpty() && testRules.isEmpty()) { + return statement; + } + Statement result = statement; + for (RuleEntry ruleEntry : getSortedEntries()) { + if (ruleEntry.type == RuleEntry.TYPE_TEST_RULE) { + result = ((TestRule) ruleEntry.rule).apply(result, description); + } else { + result = ((MethodRule) ruleEntry.rule).apply(result, method, target); + } + } + return result; + } + + /** + * Returns rule instances in the order how they should be applied, i.e. inner-to-outer. + * VisibleForTesting + */ + List getSortedRules() { + List result = new ArrayList(); + for (RuleEntry entry : getSortedEntries()) { + result.add(entry.rule); + } + return result; + } + + static class RuleEntry { + static final int TYPE_TEST_RULE = 1; + static final int TYPE_METHOD_RULE = 0; + + final Object rule; + final int type; + final int order; + + RuleEntry(Object rule, int type, Integer order) { + this.rule = rule; + this.type = type; + this.order = order != null ? order.intValue() : Rule.DEFAULT_ORDER; + } + } +} diff --git a/src/main/java/org/junit/runners/Suite.java b/src/main/java/org/junit/runners/Suite.java index b37179f4fa0b..c2c8e583ea66 100644 --- a/src/main/java/org/junit/runners/Suite.java +++ b/src/main/java/org/junit/runners/Suite.java @@ -47,7 +47,7 @@ public static Runner emptySuite() { /** * @return the classes to be run */ - public Class[] value(); + Class[] value(); } private static Class[] getAnnotatedClasses(Class klass) throws InitializationError { @@ -88,7 +88,7 @@ public Suite(RunnerBuilder builder, Class[] classes) throws InitializationErr * @param suiteClasses the classes in the suite */ protected Suite(Class klass, Class[] suiteClasses) throws InitializationError { - this(new AllDefaultPossibilitiesBuilder(true), klass, suiteClasses); + this(new AllDefaultPossibilitiesBuilder(), klass, suiteClasses); } /** diff --git a/src/main/java/org/junit/runners/model/FrameworkField.java b/src/main/java/org/junit/runners/model/FrameworkField.java index 945e3899eb30..1f8a101418fb 100644 --- a/src/main/java/org/junit/runners/model/FrameworkField.java +++ b/src/main/java/org/junit/runners/model/FrameworkField.java @@ -2,6 +2,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.util.List; import org.junit.runners.BlockJUnit4ClassRunner; @@ -14,12 +15,26 @@ public class FrameworkField extends FrameworkMember { private final Field field; - FrameworkField(Field field) { + /** + * Returns a new {@code FrameworkField} for {@code field}. + * + *

      Access relaxed to {@code public} since version 4.13.1. + */ + public FrameworkField(Field field) { if (field == null) { throw new NullPointerException( "FrameworkField cannot be created without an underlying field."); } this.field = field; + + if (isPublic()) { + // This field could be a public field in a package-scope base class + try { + field.setAccessible(true); + } catch (SecurityException e) { + // We may get an IllegalAccessException when we try to access the field + } + } } @Override @@ -40,6 +55,11 @@ public boolean isShadowedBy(FrameworkField otherMember) { return otherMember.getName().equals(getName()); } + @Override + boolean isBridgeMethod() { + return false; + } + @Override protected int getModifiers() { return field.getModifiers(); diff --git a/src/main/java/org/junit/runners/model/FrameworkMember.java b/src/main/java/org/junit/runners/model/FrameworkMember.java index 724f096ebacc..5634b3f0ca98 100644 --- a/src/main/java/org/junit/runners/model/FrameworkMember.java +++ b/src/main/java/org/junit/runners/model/FrameworkMember.java @@ -12,15 +12,29 @@ public abstract class FrameworkMember> implements Annotatable { abstract boolean isShadowedBy(T otherMember); - boolean isShadowedBy(List members) { - for (T each : members) { - if (isShadowedBy(each)) { - return true; + T handlePossibleBridgeMethod(List members) { + for (int i = members.size() - 1; i >=0; i--) { + T otherMember = members.get(i); + if (isShadowedBy(otherMember)) { + if (otherMember.isBridgeMethod()) { + /* + * We need to return the previously-encountered bridge method + * because JUnit won't be able to call the parent method, + * because the parent class isn't public. + */ + members.remove(i); + return otherMember; + } + // We found a shadowed member that isn't a bridge method. Ignore it. + return null; } } - return false; + // No shadow or bridge method found. The caller should add *this* member. + return (T) this; } + abstract boolean isBridgeMethod(); + protected abstract int getModifiers(); /** diff --git a/src/main/java/org/junit/runners/model/FrameworkMethod.java b/src/main/java/org/junit/runners/model/FrameworkMethod.java index 3580052ed957..4471407bab2f 100644 --- a/src/main/java/org/junit/runners/model/FrameworkMethod.java +++ b/src/main/java/org/junit/runners/model/FrameworkMethod.java @@ -28,6 +28,15 @@ public FrameworkMethod(Method method) { "FrameworkMethod cannot be created without an underlying method."); } this.method = method; + + if (isPublic()) { + // This method could be a public method in a package-scope base class + try { + method.setAccessible(true); + } catch (SecurityException e) { + // We may get an IllegalAccessException when we try to call the method + } + } } /** @@ -148,6 +157,11 @@ public boolean isShadowedBy(FrameworkMethod other) { return true; } + @Override + boolean isBridgeMethod() { + return method.isBridge(); + } + @Override public boolean equals(Object obj) { if (!FrameworkMethod.class.isInstance(obj)) { diff --git a/src/main/java/org/junit/runners/model/InitializationError.java b/src/main/java/org/junit/runners/model/InitializationError.java index 841b565330be..dd9c8b33c696 100644 --- a/src/main/java/org/junit/runners/model/InitializationError.java +++ b/src/main/java/org/junit/runners/model/InitializationError.java @@ -14,7 +14,7 @@ public class InitializationError extends Exception { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * See https://github.com/junit-team/junit4/issues/976 */ private final List fErrors; diff --git a/src/main/java/org/junit/runners/model/InvalidTestClassError.java b/src/main/java/org/junit/runners/model/InvalidTestClassError.java new file mode 100644 index 000000000000..57be61093a61 --- /dev/null +++ b/src/main/java/org/junit/runners/model/InvalidTestClassError.java @@ -0,0 +1,39 @@ +package org.junit.runners.model; + +import java.util.List; + +/** + * Thrown by {@link org.junit.runner.Runner}s in case the class under test is not valid. + *

      + * Its message conveniently lists all of the validation errors. + * + * @since 4.13 + */ +public class InvalidTestClassError extends InitializationError { + private static final long serialVersionUID = 1L; + + private final String message; + + public InvalidTestClassError(Class offendingTestClass, List validationErrors) { + super(validationErrors); + this.message = createMessage(offendingTestClass, validationErrors); + } + + private static String createMessage(Class testClass, List validationErrors) { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("Invalid test class '%s':", testClass.getName())); + int i = 1; + for (Throwable error : validationErrors) { + sb.append("\n " + (i++) + ". " + error.getMessage()); + } + return sb.toString(); + } + + /** + * @return a message with a list of all of the validation errors + */ + @Override + public String getMessage() { + return message; + } +} diff --git a/src/main/java/org/junit/runners/model/MemberValueConsumer.java b/src/main/java/org/junit/runners/model/MemberValueConsumer.java new file mode 100644 index 000000000000..a6157bf3be72 --- /dev/null +++ b/src/main/java/org/junit/runners/model/MemberValueConsumer.java @@ -0,0 +1,18 @@ +package org.junit.runners.model; + +/** + * Represents a receiver for values of annotated fields/methods together with the declaring member. + * + * @see TestClass#collectAnnotatedFieldValues(Object, Class, Class, MemberValueConsumer) + * @see TestClass#collectAnnotatedMethodValues(Object, Class, Class, MemberValueConsumer) + * @since 4.13 + */ +public interface MemberValueConsumer { + /** + * Receives the next value and its declaring member. + * + * @param member declaring member ({@link FrameworkMethod} or {@link FrameworkField}) + * @param value the value of the next member + */ + void accept(FrameworkMember member, T value); +} diff --git a/src/main/java/org/junit/runners/model/MultipleFailureException.java b/src/main/java/org/junit/runners/model/MultipleFailureException.java index 325c645f937a..8e355a70afa4 100644 --- a/src/main/java/org/junit/runners/model/MultipleFailureException.java +++ b/src/main/java/org/junit/runners/model/MultipleFailureException.java @@ -1,9 +1,13 @@ package org.junit.runners.model; +import java.io.PrintStream; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.junit.TestCouldNotBeSkippedException; +import org.junit.internal.AssumptionViolatedException; import org.junit.internal.Throwables; /** @@ -17,12 +21,22 @@ public class MultipleFailureException extends Exception { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit/issues/976 + * See https://github.com/junit-team/junit4/issues/976 */ private final List fErrors; public MultipleFailureException(List errors) { - this.fErrors = new ArrayList(errors); + if (errors.isEmpty()) { + throw new IllegalArgumentException( + "List of Throwables must not be empty"); + } + this.fErrors = new ArrayList(errors.size()); + for (Throwable error : errors) { + if (error instanceof AssumptionViolatedException) { + error = new TestCouldNotBeSkippedException((AssumptionViolatedException) error); + } + fErrors.add(error); + } } public List getFailures() { @@ -34,11 +48,32 @@ 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())); + sb.append(String.format("%n %s(%s)", e.getClass().getName(), e.getMessage())); } return sb.toString(); } + @Override + public void printStackTrace() { + for (Throwable e: fErrors) { + e.printStackTrace(); + } + } + + @Override + public void printStackTrace(PrintStream s) { + for (Throwable e: fErrors) { + e.printStackTrace(s); + } + } + + @Override + public void printStackTrace(PrintWriter s) { + for (Throwable e: fErrors) { + e.printStackTrace(s); + } + } + /** * Asserts that a list of throwables is empty. If it isn't empty, * will throw {@link MultipleFailureException} (if there are diff --git a/src/main/java/org/junit/runners/model/RunnerBuilder.java b/src/main/java/org/junit/runners/model/RunnerBuilder.java index 7d3eee301f1e..ba7c9e24d6ba 100644 --- a/src/main/java/org/junit/runners/model/RunnerBuilder.java +++ b/src/main/java/org/junit/runners/model/RunnerBuilder.java @@ -6,7 +6,11 @@ import java.util.Set; import org.junit.internal.runners.ErrorReportingRunner; +import org.junit.runner.Description; +import org.junit.runner.OrderWith; import org.junit.runner.Runner; +import org.junit.runner.manipulation.InvalidOrderingException; +import org.junit.runner.manipulation.Ordering; /** * A RunnerBuilder is a strategy for constructing runners for classes. @@ -49,19 +53,39 @@ public abstract class RunnerBuilder { 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. + * Always returns a runner for the given test class. + * + *

      In case of an exception a runner will be returned that prints an error instead of running + * tests. + * + *

      Note that some of the internal JUnit implementations of RunnerBuilder will return + * {@code null} from this method, but no RunnerBuilder passed to a Runner constructor will + * return {@code null} from this method. * * @param testClass class to be run * @return a Runner */ public Runner safeRunnerForClass(Class testClass) { try { - return runnerForClass(testClass); + Runner runner = runnerForClass(testClass); + if (runner != null) { + configureRunner(runner); + } + return runner; } catch (Throwable e) { return new ErrorReportingRunner(testClass, e); } } + private void configureRunner(Runner runner) throws InvalidOrderingException { + Description description = runner.getDescription(); + OrderWith orderWith = description.getAnnotation(OrderWith.class); + if (orderWith != null) { + Ordering ordering = Ordering.definedBy(orderWith.value(), description); + ordering.apply(runner); + } + } + 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())); @@ -96,7 +120,7 @@ public List runners(Class parent, List> children) } private List runners(Class[] children) { - ArrayList runners = new ArrayList(); + List runners = new ArrayList(); for (Class each : children) { Runner childRunner = safeRunnerForClass(each); if (childRunner != null) { diff --git a/src/main/java/org/junit/runners/model/TestClass.java b/src/main/java/org/junit/runners/model/TestClass.java old mode 100755 new mode 100644 index c8a544d6cb9b..5962c2b478dc --- a/src/main/java/org/junit/runners/model/TestClass.java +++ b/src/main/java/org/junit/runners/model/TestClass.java @@ -84,20 +84,21 @@ protected static > void addToAnnotationLists(T memb for (Annotation each : member.getAnnotations()) { Class type = each.annotationType(); List members = getAnnotatedMembers(map, type, true); - if (member.isShadowedBy(members)) { + T memberToAdd = member.handlePossibleBridgeMethod(members); + if (memberToAdd == null) { return; } if (runsTopToBottom(type)) { - members.add(0, member); + members.add(0, memberToAdd); } else { - members.add(member); + members.add(memberToAdd); } } } private static > Map, List> makeDeeplyUnmodifiable(Map, List> source) { - LinkedHashMap, List> copy = + Map, List> copy = new LinkedHashMap, List>(); for (Map.Entry, List> entry : source.entrySet()) { copy.put(entry.getKey(), Collections.unmodifiableList(entry.getValue())); @@ -168,7 +169,7 @@ private static boolean runsTopToBottom(Class annotation) { } private static List> getSuperClasses(Class testClass) { - ArrayList> results = new ArrayList>(); + List> results = new ArrayList>(); Class current = testClass; while (current != null) { results.add(current); @@ -224,24 +225,59 @@ public T getAnnotation(Class annotationType) { public List getAnnotatedFieldValues(Object test, Class annotationClass, Class valueClass) { - List results = new ArrayList(); + final List results = new ArrayList(); + collectAnnotatedFieldValues(test, annotationClass, valueClass, + new MemberValueConsumer() { + public void accept(FrameworkMember member, T value) { + results.add(value); + } + }); + return results; + } + + /** + * Finds the fields annotated with the specified annotation and having the specified type, + * retrieves the values and passes those to the specified consumer. + * + * @since 4.13 + */ + public void collectAnnotatedFieldValues(Object test, + Class annotationClass, Class valueClass, + MemberValueConsumer consumer) { for (FrameworkField each : getAnnotatedFields(annotationClass)) { try { Object fieldValue = each.get(test); if (valueClass.isInstance(fieldValue)) { - results.add(valueClass.cast(fieldValue)); + consumer.accept(each, valueClass.cast(fieldValue)); } } catch (IllegalAccessException e) { throw new RuntimeException( "How did getFields return a field we couldn't access?", e); } } - return results; } public List getAnnotatedMethodValues(Object test, Class annotationClass, Class valueClass) { - List results = new ArrayList(); + final List results = new ArrayList(); + collectAnnotatedMethodValues(test, annotationClass, valueClass, + new MemberValueConsumer() { + public void accept(FrameworkMember member, T value) { + results.add(value); + } + }); + return results; + } + + /** + * Finds the methods annotated with the specified annotation and returning the specified type, + * invokes it and pass the return value to the specified consumer. + * + * @since 4.13 + */ + public void collectAnnotatedMethodValues(Object test, + Class annotationClass, Class valueClass, + MemberValueConsumer consumer) { for (FrameworkMethod each : getAnnotatedMethods(annotationClass)) { try { /* @@ -254,14 +290,13 @@ public List getAnnotatedMethodValues(Object test, */ if (valueClass.isAssignableFrom(each.getReturnType())) { Object fieldValue = each.invokeExplosively(test); - results.add(valueClass.cast(fieldValue)); + consumer.accept(each, valueClass.cast(fieldValue)); } } catch (Throwable e) { throw new RuntimeException( "Exception in " + each.getName(), e); } } - return results; } public boolean isPublic() { diff --git a/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java b/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java index 1c49f84f0178..5c70a75d0caf 100644 --- a/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java +++ b/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java @@ -4,8 +4,12 @@ import java.lang.reflect.Field; import java.util.List; +import org.junit.internal.runners.statements.RunAfters; +import org.junit.internal.runners.statements.RunBefores; +import org.junit.runner.RunWith; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.model.FrameworkField; import org.junit.runners.model.FrameworkMethod; @@ -18,13 +22,17 @@ */ public class BlockJUnit4ClassRunnerWithParameters extends BlockJUnit4ClassRunner { + private enum InjectionType { + CONSTRUCTOR, FIELD + } + private final Object[] parameters; private final String name; public BlockJUnit4ClassRunnerWithParameters(TestWithParameters test) throws InitializationError { - super(test.getTestClass().getJavaClass()); + super(test.getTestClass()); parameters = test.getParameters().toArray( new Object[test.getParameters().size()]); name = test.getName(); @@ -32,10 +40,15 @@ public BlockJUnit4ClassRunnerWithParameters(TestWithParameters test) @Override public Object createTest() throws Exception { - if (fieldsAreAnnotated()) { - return createTestUsingFieldInjection(); - } else { - return createTestUsingConstructorInjection(); + InjectionType injectionType = getInjectionType(); + switch (injectionType) { + case CONSTRUCTOR: + return createTestUsingConstructorInjection(); + case FIELD: + return createTestUsingFieldInjection(); + default: + throw new IllegalStateException("The injection type " + + injectionType + " is not supported."); } } @@ -60,6 +73,13 @@ private Object createTestUsingFieldInjection() throws Exception { int index = annotation.value(); try { field.set(testClassInstance, parameters[index]); + } catch (IllegalAccessException e) { + IllegalAccessException wrappedException = new IllegalAccessException( + "Cannot set parameter '" + field.getName() + + "'. Ensure that the field '" + field.getName() + + "' is public."); + wrappedException.initCause(e); + throw wrappedException; } catch (IllegalArgumentException iare) { throw new Exception(getTestClass().getName() + ": Trying to set " + field.getName() @@ -86,7 +106,7 @@ protected String testName(FrameworkMethod method) { @Override protected void validateConstructor(List errors) { validateOnlyOneConstructor(errors); - if (fieldsAreAnnotated()) { + if (getInjectionType() != InjectionType.CONSTRUCTOR) { validateZeroArgConstructor(errors); } } @@ -94,7 +114,7 @@ protected void validateConstructor(List errors) { @Override protected void validateFields(List errors) { super.validateFields(errors); - if (fieldsAreAnnotated()) { + if (getInjectionType() == InjectionType.FIELD) { List annotatedFieldsByParameter = getAnnotatedFieldsByParameter(); int[] usedIndices = new int[annotatedFieldsByParameter.size()]; for (FrameworkField each : annotatedFieldsByParameter) { @@ -125,18 +145,74 @@ protected void validateFields(List errors) { @Override protected Statement classBlock(RunNotifier notifier) { - return childrenInvoker(notifier); + Statement statement = childrenInvoker(notifier); + statement = withBeforeParams(statement); + statement = withAfterParams(statement); + return statement; + } + + private Statement withBeforeParams(Statement statement) { + List befores = getTestClass() + .getAnnotatedMethods(Parameterized.BeforeParam.class); + return befores.isEmpty() ? statement : new RunBeforeParams(statement, befores); + } + + private class RunBeforeParams extends RunBefores { + RunBeforeParams(Statement next, List befores) { + super(next, befores, null); + } + + @Override + protected void invokeMethod(FrameworkMethod method) throws Throwable { + int paramCount = method.getMethod().getParameterTypes().length; + method.invokeExplosively(null, paramCount == 0 ? (Object[]) null : parameters); + } + } + + private Statement withAfterParams(Statement statement) { + List afters = getTestClass() + .getAnnotatedMethods(Parameterized.AfterParam.class); + return afters.isEmpty() ? statement : new RunAfterParams(statement, afters); + } + + private class RunAfterParams extends RunAfters { + RunAfterParams(Statement next, List afters) { + super(next, afters, null); + } + + @Override + protected void invokeMethod(FrameworkMethod method) throws Throwable { + int paramCount = method.getMethod().getParameterTypes().length; + method.invokeExplosively(null, paramCount == 0 ? (Object[]) null : parameters); + } } @Override protected Annotation[] getRunnerAnnotations() { - return new Annotation[0]; + Annotation[] allAnnotations = super.getRunnerAnnotations(); + Annotation[] annotationsWithoutRunWith = new Annotation[allAnnotations.length - 1]; + int i = 0; + for (Annotation annotation: allAnnotations) { + if (!annotation.annotationType().equals(RunWith.class)) { + annotationsWithoutRunWith[i] = annotation; + ++i; + } + } + return annotationsWithoutRunWith; } private List getAnnotatedFieldsByParameter() { return getTestClass().getAnnotatedFields(Parameter.class); } + private InjectionType getInjectionType() { + if (fieldsAreAnnotated()) { + return InjectionType.FIELD; + } else { + return InjectionType.CONSTRUCTOR; + } + } + private boolean fieldsAreAnnotated() { return !getAnnotatedFieldsByParameter().isEmpty(); } diff --git a/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java b/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java index 16ea1f30e029..8123e83b1a15 100644 --- a/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java +++ b/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java @@ -4,7 +4,7 @@ import org.junit.runners.model.InitializationError; /** - * A {@code ParameterizedRunnerFactory} creates a runner for a single + * A {@code ParametersRunnerFactory} creates a runner for a single * {@link TestWithParameters}. * * @since 4.12 diff --git a/src/main/java/org/junit/runners/parameterized/TestWithParameters.java b/src/main/java/org/junit/runners/parameterized/TestWithParameters.java index 1b86644a2940..1c5abd9b81b0 100644 --- a/src/main/java/org/junit/runners/parameterized/TestWithParameters.java +++ b/src/main/java/org/junit/runners/parameterized/TestWithParameters.java @@ -1,6 +1,7 @@ package org.junit.runners.parameterized; import static java.util.Collections.unmodifiableList; +import static org.junit.internal.Checks.notNull; import java.util.ArrayList; import java.util.List; @@ -73,10 +74,4 @@ public String toString() { return testClass.getName() + " '" + name + "' with parameters " + parameters; } - - private static void notNull(Object value, String message) { - if (value == null) { - throw new NullPointerException(message); - } - } } diff --git a/src/main/java/org/junit/validator/AnnotationValidatorFactory.java b/src/main/java/org/junit/validator/AnnotationValidatorFactory.java index 7309fdde6574..fb2460d08fbe 100644 --- a/src/main/java/org/junit/validator/AnnotationValidatorFactory.java +++ b/src/main/java/org/junit/validator/AnnotationValidatorFactory.java @@ -27,9 +27,6 @@ public AnnotationValidator createAnnotationValidator(ValidateWith validateWithAn } Class clazz = validateWithAnnotation.value(); - if (clazz == null) { - throw new IllegalArgumentException("Can't create validator, value is null in annotation " + validateWithAnnotation.getClass().getName()); - } try { AnnotationValidator annotationValidator = clazz.newInstance(); VALIDATORS_FOR_ANNOTATION_TYPES.putIfAbsent(validateWithAnnotation, annotationValidator); diff --git a/src/main/java/org/junit/validator/AnnotationsValidator.java b/src/main/java/org/junit/validator/AnnotationsValidator.java index 30f54a651303..44d99d2a2f8d 100644 --- a/src/main/java/org/junit/validator/AnnotationsValidator.java +++ b/src/main/java/org/junit/validator/AnnotationsValidator.java @@ -116,5 +116,5 @@ List validateAnnotatable( AnnotationValidator validator, FrameworkField field) { return validator.validateAnnotatedField(field); } - }; + } } diff --git a/src/main/java/org/junit/validator/TestClassValidator.java b/src/main/java/org/junit/validator/TestClassValidator.java index 43cb787e01c7..ba5e892a156f 100644 --- a/src/main/java/org/junit/validator/TestClassValidator.java +++ b/src/main/java/org/junit/validator/TestClassValidator.java @@ -17,5 +17,5 @@ public interface TestClassValidator { * the {@link TestClass} that is validated. * @return the validation errors found by the validator. */ - public List validateTestClass(TestClass testClass); + List validateTestClass(TestClass testClass); } diff --git a/src/main/java/org/junit/validator/ValidateWith.java b/src/main/java/org/junit/validator/ValidateWith.java index 03d790670f75..3725db81f954 100644 --- a/src/main/java/org/junit/validator/ValidateWith.java +++ b/src/main/java/org/junit/validator/ValidateWith.java @@ -1,8 +1,10 @@ package org.junit.validator; +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; /** * Allows for an {@link AnnotationValidator} to be attached to an annotation. @@ -13,6 +15,7 @@ * @since 4.12 */ @Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) @Inherited public @interface ValidateWith { Class value(); diff --git a/src/site/fml/faq.fml b/src/site/fml/faq.fml index dcf28ee7cba8..26d2e2bf41a4 100644 --- a/src/site/fml/faq.fml +++ b/src/site/fml/faq.fml @@ -35,11 +35,11 @@ Where do I get the latest version of this FAQ? -

      The master copy of this FAQ is available +

      The latest copy of this FAQ is available at - - http://junit.sourceforge.net/doc/faq/faq.htm.

      + + https://junit.org/junit4/faq.html.

      The JUnit distribution also includes this FAQ in the @@ -128,24 +128,6 @@ - -Where can I find articles on - JUnit? -

      - The JUnit home page maintains a list - of JUnit - articles. -

      - - - What's the latest news on JUnit? - -

      - The JUnit home page publishes - the latest JUnit - news. -

      -
      How is JUnit licensed? @@ -324,7 +306,7 @@

      Please stick to technical issues on the discussion forum and mailing lists. Keep in mind that these are public, so - do not include any confidental information in your + do not include any confidential information in your questions!

      @@ -355,7 +337,7 @@

      JUnit is hosted on GitHub. + href="https://github.com/junit-team/junit4">GitHub. Please use the tools provided by GitHub for your submissions.

      @@ -721,6 +703,12 @@ public void testIndexOutOfBoundsExceptionNotRaised() read this article. +

      +

      + If you are using JDK 1.6 or higher and you annotate your tests with @Test, + you can use Dp4j to inject reflection in your + test methods. For details on how to use it, see + this test script.

      Why does JUnit only report the first failure in a single test?

      @@ -1063,7 +1051,7 @@ oneTimeTearDown() (Submitted by: Eric Armstrong)

      - To run your JUnit tests, you'll need the following elemements in + To run your JUnit tests, you'll need the following elements in your CLASSPATH:

        @@ -1255,7 +1243,7 @@ oneTimeTearDown()

        -DparameterName=parameterValue

        - If the number of parameters on the command line gets unweildy, + If the number of parameters on the command line gets unwieldy, pass in the location of a property file that defines a set of parameters. Alternatively, the JUnit-addons package @@ -1378,7 +1366,7 @@ excluded.8=net.jini.* now you can have the reverse problem where the JUnit loader will load a host of org.w3c.dom/org.xml.sax classes, and then the system loader violates the loader - contraints at some point when it tries to do exactly what I + constraints at some point when it tries to do exactly what I described above with JAXP because it doesn't ever delegate to its logical child (the JUnit loader). Inevitably, if your test cases use many JAXP and related XML classes, one or the other @@ -1464,7 +1452,7 @@ a test failure, rather than the source file's line number? Idiomatic naming patterns for unit tests are Test*.java and *Test.java. Documentation and examples are at http://ant.apache.org/manual/OptionalTasks/junit.html. + href="https://ant.apache.org/manual/Tasks/junit.html">https://ant.apache.org/manual/Tasks/junit.html.

      • @@ -1475,7 +1463,7 @@ a test failure, rather than the source file's line number?

        DirectorySuiteBuilder builder = new DirectorySuiteBuilder();
         builder.setSuffix("Test");
        -Test suite = builer.suite("/home/project/myproject/tests");
        +Test suite = builder.suite("/home/project/myproject/tests");

        Documentation and examples are at http://junit-addons.sourceforge.net. @@ -1711,14 +1699,6 @@ end Miscellaneous - - How do I integrate JUnit with my IDE? -

        - The JUnit home page maintains a list of IDE integration - instructions. -

        - How do I launch a debugger when a test fails?

        @@ -1740,10 +1720,10 @@ end Where can I find unit testing frameworks similar to JUnit for other languages?

        - XProgramming.com maintains a complete list of available xUnit testing + Wikipedia maintains a list of available xUnit testing frameworks.

        - \ No newline at end of file + diff --git a/src/site/resources/css/carousel.css b/src/site/resources/css/carousel.css new file mode 100644 index 000000000000..bc63d46add7c --- /dev/null +++ b/src/site/resources/css/carousel.css @@ -0,0 +1,13 @@ +.carousel-content { + height: 20em; +} +.carousel-caption a { + color: #ffffff; +} +#junit-lambda-teaser { + background: url(../images/junit-lambda/background.png); + text-align: center; +} +#junit-lambda-teaser p { + padding-top: 25px; +} \ No newline at end of file diff --git a/src/site/resources/css/junit-lambda.css b/src/site/resources/css/junit-lambda.css new file mode 100644 index 000000000000..fbcb1feb0242 --- /dev/null +++ b/src/site/resources/css/junit-lambda.css @@ -0,0 +1,69 @@ +ul.inline { + margin-left: 0; + list-style: none; +} +.inline li { + display: inline-block; + margin-right: 10px; + margin-bottom: 10px; +} + +.sponsors li { + border: 1px solid #e3e3e3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.sponsors li:hover { + border-color: #c5c5c5; +} +.sponsors li { + text-align: center; + padding: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.sponsors li a { + display: block; + padding: 0 10px !important; +} + +.sponsors-small li a img { + max-height: 100px; + max-width: 200px; +} + +.sponsors-small li a { + width: 200px; + height: 120px; + line-height: 120px; +} +.sponsors-medium li a { + width: 278px; + height: 141px; + line-height: 141px; +} +.sponsors-large li a { + width: 435px; + height: 237px; + line-height: 237px; +} + +ul.people { + margin-left: 7px; + margin-right: 7px; +} +.people li { + display: block; + width: 170px; + margin: 0; + padding: 0 15px 0 0; + float: left; + text-align: center; +} +.people img.avatar { + display: block; + width: 100%; + margin: 0 0 10px 0; +} diff --git a/src/site/resources/images/junit-lambda/background.png b/src/site/resources/images/junit-lambda/background.png new file mode 100644 index 000000000000..ff8b1be8654c Binary files /dev/null and b/src/site/resources/images/junit-lambda/background.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/42talents.png b/src/site/resources/images/junit-lambda/contributors/42talents.png new file mode 100644 index 000000000000..cddcae9b5bfd Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/42talents.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/adnovum.png b/src/site/resources/images/junit-lambda/contributors/adnovum.png new file mode 100644 index 000000000000..0743bed58bc2 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/adnovum.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/arcbees.png b/src/site/resources/images/junit-lambda/contributors/arcbees.png new file mode 100755 index 000000000000..943325e0bf1a Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/arcbees.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/autotrader.jpg b/src/site/resources/images/junit-lambda/contributors/autotrader.jpg new file mode 100644 index 000000000000..a20a8d69c11f Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/autotrader.jpg differ diff --git a/src/site/resources/images/junit-lambda/contributors/bol.jpg b/src/site/resources/images/junit-lambda/contributors/bol.jpg new file mode 100644 index 000000000000..ba0a4f73202e Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/bol.jpg differ diff --git a/src/site/resources/images/junit-lambda/contributors/bouvet.png b/src/site/resources/images/junit-lambda/contributors/bouvet.png new file mode 100644 index 000000000000..9f239ca57c93 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/bouvet.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/devnexus.png b/src/site/resources/images/junit-lambda/contributors/devnexus.png new file mode 100644 index 000000000000..fa6d6ea25885 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/devnexus.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/diffplug.png b/src/site/resources/images/junit-lambda/contributors/diffplug.png new file mode 100644 index 000000000000..e663310f72f4 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/diffplug.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/disy.jpg b/src/site/resources/images/junit-lambda/contributors/disy.jpg new file mode 100644 index 000000000000..99210e522eab Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/disy.jpg differ diff --git a/src/site/resources/images/junit-lambda/contributors/eclipse.png b/src/site/resources/images/junit-lambda/contributors/eclipse.png new file mode 100755 index 000000000000..47db56d82ac3 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/eclipse.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/ergon.png b/src/site/resources/images/junit-lambda/contributors/ergon.png new file mode 100644 index 000000000000..70c2014ba387 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/ergon.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/gradle.png b/src/site/resources/images/junit-lambda/contributors/gradle.png new file mode 100644 index 000000000000..ed603e574563 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/gradle.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/intellijidea.png b/src/site/resources/images/junit-lambda/contributors/intellijidea.png new file mode 100644 index 000000000000..5d9edbf29a2d Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/intellijidea.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/klarna.png b/src/site/resources/images/junit-lambda/contributors/klarna.png new file mode 100644 index 000000000000..9122da6b4c76 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/klarna.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/klosebrothers.png b/src/site/resources/images/junit-lambda/contributors/klosebrothers.png new file mode 100644 index 000000000000..6ff579789d33 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/klosebrothers.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/msgsystems.png b/src/site/resources/images/junit-lambda/contributors/msgsystems.png new file mode 100644 index 000000000000..68850ccc202e Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/msgsystems.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/murex.jpg b/src/site/resources/images/junit-lambda/contributors/murex.jpg new file mode 100644 index 000000000000..a86019ff4b1c Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/murex.jpg differ diff --git a/src/site/resources/images/junit-lambda/contributors/netcetera.png b/src/site/resources/images/junit-lambda/contributors/netcetera.png new file mode 100644 index 000000000000..8520f90efe1b Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/netcetera.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/novatec.png b/src/site/resources/images/junit-lambda/contributors/novatec.png new file mode 100644 index 000000000000..b5a6ee3b1c18 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/novatec.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/ociweb.png b/src/site/resources/images/junit-lambda/contributors/ociweb.png new file mode 100644 index 000000000000..36cb8d92106f Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/ociweb.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/oio.png b/src/site/resources/images/junit-lambda/contributors/oio.png new file mode 100644 index 000000000000..66ce7e397287 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/oio.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/red6-es.jpg b/src/site/resources/images/junit-lambda/contributors/red6-es.jpg new file mode 100644 index 000000000000..f4bdb869e696 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/red6-es.jpg differ diff --git a/src/site/resources/images/junit-lambda/contributors/samuraism.png b/src/site/resources/images/junit-lambda/contributors/samuraism.png new file mode 100644 index 000000000000..fa804899097b Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/samuraism.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/siili.png b/src/site/resources/images/junit-lambda/contributors/siili.png new file mode 100644 index 000000000000..a757885fb660 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/siili.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/sipgate.png b/src/site/resources/images/junit-lambda/contributors/sipgate.png new file mode 100644 index 000000000000..31cc742527fb Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/sipgate.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/six.gif b/src/site/resources/images/junit-lambda/contributors/six.gif new file mode 100644 index 000000000000..19f111831ba1 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/six.gif differ diff --git a/src/site/resources/images/junit-lambda/contributors/sonrisa.png b/src/site/resources/images/junit-lambda/contributors/sonrisa.png new file mode 100644 index 000000000000..350e0df1042d Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/sonrisa.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/squeed.png b/src/site/resources/images/junit-lambda/contributors/squeed.png new file mode 100644 index 000000000000..275f663c8795 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/squeed.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/structure101.png b/src/site/resources/images/junit-lambda/contributors/structure101.png new file mode 100644 index 000000000000..f57ece9ae304 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/structure101.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/synyx.jpg b/src/site/resources/images/junit-lambda/contributors/synyx.jpg new file mode 100755 index 000000000000..5143a738fec8 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/synyx.jpg differ diff --git a/src/site/resources/images/junit-lambda/contributors/tng.png b/src/site/resources/images/junit-lambda/contributors/tng.png new file mode 100644 index 000000000000..94db5512ebd2 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/tng.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/topdesk.png b/src/site/resources/images/junit-lambda/contributors/topdesk.png new file mode 100644 index 000000000000..2a1d50c5767f Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/topdesk.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/vaddy.png b/src/site/resources/images/junit-lambda/contributors/vaddy.png new file mode 100644 index 000000000000..b595aef46558 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/vaddy.png differ diff --git a/src/site/resources/images/junit-lambda/contributors/zenika.png b/src/site/resources/images/junit-lambda/contributors/zenika.png new file mode 100644 index 000000000000..a83250c36573 Binary files /dev/null and b/src/site/resources/images/junit-lambda/contributors/zenika.png differ diff --git a/src/site/resources/images/junit-lambda/junit-lambda-logo.png b/src/site/resources/images/junit-lambda/junit-lambda-logo.png new file mode 100644 index 000000000000..d14a985e9f64 Binary files /dev/null and b/src/site/resources/images/junit-lambda/junit-lambda-logo.png differ diff --git a/src/site/resources/images/junit-lambda/sponsors/amex.png b/src/site/resources/images/junit-lambda/sponsors/amex.png new file mode 100644 index 000000000000..8f9d2f3c5a0c Binary files /dev/null and b/src/site/resources/images/junit-lambda/sponsors/amex.png differ diff --git a/src/site/resources/images/junit-lambda/sponsors/andrena.png b/src/site/resources/images/junit-lambda/sponsors/andrena.png new file mode 100644 index 000000000000..bd3663c5cc47 Binary files /dev/null and b/src/site/resources/images/junit-lambda/sponsors/andrena.png differ diff --git a/src/site/resources/images/junit-lambda/sponsors/heidelberg-mobil.png b/src/site/resources/images/junit-lambda/sponsors/heidelberg-mobil.png new file mode 100644 index 000000000000..2e3046a8f8eb Binary files /dev/null and b/src/site/resources/images/junit-lambda/sponsors/heidelberg-mobil.png differ diff --git a/src/site/resources/images/junit-lambda/sponsors/namics.png b/src/site/resources/images/junit-lambda/sponsors/namics.png new file mode 100644 index 000000000000..3a30b5205a30 Binary files /dev/null and b/src/site/resources/images/junit-lambda/sponsors/namics.png differ diff --git a/src/site/resources/images/junit-lambda/sponsors/pivotal.png b/src/site/resources/images/junit-lambda/sponsors/pivotal.png new file mode 100644 index 000000000000..1ee4d0c8eeee Binary files /dev/null and b/src/site/resources/images/junit-lambda/sponsors/pivotal.png differ diff --git a/src/site/resources/images/junit5-banner.png b/src/site/resources/images/junit5-banner.png new file mode 100644 index 000000000000..76a1243ddc28 Binary files /dev/null and b/src/site/resources/images/junit5-banner.png differ diff --git a/src/site/resources/scripts/index.js b/src/site/resources/scripts/index.js index 9e1486ec601c..043f1df72734 100644 --- a/src/site/resources/scripts/index.js +++ b/src/site/resources/scripts/index.js @@ -1,6 +1,6 @@ $(document).ready(function(){ $('#main-carousel').carousel({ - interval:5000 + interval:10000 }); $('#main-carousel-prev').on("click", function () { diff --git a/src/site/site.xml b/src/site/site.xml index 323f6eb065f6..89d1463a000f 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd"> ${project.name} - http://junit.org/images/junit-logo.png + ./images/junit-logo.png http://junit.org/ @@ -12,7 +12,6 @@ - @@ -24,18 +23,20 @@ + + - + - + - + @@ -45,7 +46,7 @@ false true - junit-team/junit + junit-team/junit4 right diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml index b33e8ca26a81..6cd91b2d1f45 100644 --- a/src/site/xdoc/index.xml +++ b/src/site/xdoc/index.xml @@ -14,17 +14,26 @@

      Third-party extensions

      +junit-quickcheck - QuickCheck-style parameter suppliers for JUnit theories. Uses junit.contrib's version of the theories machinery, which respects generics on theory parameters.
      @@ -149,7 +161,7 @@ content: "Don't forget that the documentation generated by Maven is hiding up here" }, { - target: $('body a[href="http://github.com/junit-team/junit"] img')[0], + target: $('body a[href="http://github.com/junit-team/junit4"] img')[0], placement: "left", title: "Source code", content: "The source code for JUnit is hosted on GitHub" diff --git a/src/site/xhtml/junit-lambda-campaign.xhtml b/src/site/xhtml/junit-lambda-campaign.xhtml new file mode 100644 index 000000000000..fa932c808c79 --- /dev/null +++ b/src/site/xhtml/junit-lambda-campaign.xhtml @@ -0,0 +1,67 @@ + + + JUnit Lambda Crowdfunding Campaign + + +

      Crowdfunding JUnit Lambda #fundJUnit

      +
      + +
      +
      +

      The crowdfunding campaign has successfully ended.
      Thank you all!

      +

      + Campaign page on Indiegogo + Campaign Contributors + Follow @junitteam on Twitter +

      +
      +

      Main Sponsors

      +

      Each of these companies will fund a developer for 6 weeks. They will not receive any money collected through the campaign.

      +
        +
      • +
      • +
      • +
      • +
      +

      Main Campaign Sponsor

      +

      This company will fund JUnit Lambda through the Main Sponsor campaign perk.

      +
        +
      • +
      +

      Campaign Contributors

      +

      Thank you to all other people, companies, and organizations that have contributed already! Please check out our contributors page.

      +
      +

      Why JUnit needs your support

      +

      With 43 million downloads from Maven Central in 2014 JUnit still is the default testing library for Java. Millions of projects rely on it being both stable and allowing to test the latest features of the latest JDK. Moreover, many other testing libraries hook into JUnit as a way to enable IDE and build tool integration. Keeping JUnit in shape is a major task for those maintaining and evolving the library.

      +

      As of today, none of the active JUnit maintainers are payed by their employer to do this work. Not surprisingly many unresolved issues have piled up and, what’s worse, there is no hope to get JUnit to support and make use of all the features in Java 8 any time soon. Since Lambdas are the most prominent of those features, we borrowed their name for the campaign.

      +

      This campaign will allow a team of long-time JUnit committers, backed by a few experienced Java developers, to focus on getting JUnit ready for the years—and JDKs—to come.

      +

      Obstacles for evolving JUnit

      +

      A major design goal of JUnit has always been simplicity. JUnit 4 was released 10 years ago and has served its purpose very well. Since then many things have changed: Java got a couple of new versions and many new testing frameworks and ideas about testing have popped up.

      +

      The basic design of JUnit, however, has remained the same since 2005. Some constructs like Rules were added, but at the same time backwards compatibility has always been and will continue to be the major goal of evolving JUnit. A number of issues have increasingly slowed down its evolution:

      +
        +
      • +

        Runners have found a widespread use and become a crucial concept to extend JUnit. Writing a custom runner is a very powerful way to customize how a test class is instantiated, how its children are collected, how they are run, reported, and so on. However, you can only have a single runner for each test class. For example, combining SpringJUnit4ClassRunner and Parameterized is not possible at the moment. We want to separate the different concerns, for which the runner is currently responsible, into separated interfaces.

        +
      • +
      • +

        The current execution model requires all test cases to be known a-priori. This prevents the dynamic creation of test cases as response to observed behaviour during test execution. This also means that you cannot use Streams (Java 8), e.g. in combination with @Parameters, to create your test data.

        +
      • +
      • +

        All IDEs and build tools include support for JUnit. While that makes it really easy to execute JUnit tests, on the flip side the IDEs and build tools are tightly coupled to JUnit internals. Some IDEs and build tools use internal JUnit classes or even reflection to circumvent the absence of a JUnit API that does what they want. For example, there is no extensible way to link to a test location in case it is not a Java method. Those “tricks” complicate the evolution of JUnit tremendously, and even render some changes virtually impossible. Therefore, we want to closely work with IDE and build tool developers to add features their users need in an extensible way.

        +
      • +
      +

      The Vision

      +

      We’ve identified two main areas to focus on during the upcoming JUnit overhaul:

      +
        +
      • +

        Decouple test execution and reporting from test definition and provisioning: This will greatly simplify further evolution of JUnit and allow users to mix test specifications from different test libraries—like JUnit, Spock, ScalaTest and so on—more easily. Other testing libraries should only depend on the test execution/reporting API of JUnit, not on the test definition API (e.g. Runner).

        +
      • +
      • +

        Rethinking the JUnit’s extensibility story: Runners, Rules, subclassing and other techniques will be revamped into a cohesive set of constructs to enhance JUnit and to allow—if possible—the seamless combination of individual extensions.

        +
      • +
      • +

        Making use of Java 8 features (Lambdas, Streams, Interface default methods) for better assertions, generating test cases, formulating test hierarchies, testing asynchronous code and other stuff: We will provide those extensions in additional libraries to keep the JUnit core compatible with older JDKs.

        +
      • +
      +

      All development will happen openly on GitHub in order to foster early feedback and detect problems as soon as possible.

      + + diff --git a/src/site/xhtml/junit-lambda-contributors.xhtml b/src/site/xhtml/junit-lambda-contributors.xhtml new file mode 100644 index 000000000000..fad6d5355dd9 --- /dev/null +++ b/src/site/xhtml/junit-lambda-contributors.xhtml @@ -0,0 +1,326 @@ + + + JUnit Lambda + + +

      Crowdfunding Campaign Contributors #fundJUnit

      +

      The following individuals, companies, and organizations have made substantial contributions to the JUnit Lambda crowdfunding campaign on Indiegogo. Thank you from the JUnit team!

      +

      Depending on the perk they have chosen, they are listed with a large logo, a small one, or by their name.

      +
        +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      +
        +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      • +
      +
        +
      • Hans Sowa
      • +
      • Jens Schauder
      • +
      • Tobias Ahlers
      • +
      • Daniel Zappold
      • +
      • Kai-Marian Pukall
      • +
      • Julien Jakubowski
      • +
      • Dmitry Karlinsky
      • +
      • Mark Munson
      • +
      • Andrew Janke
      • +
      • Eric Lefevre-Ardant
      • +
      • Brett Tucker
      • +
      • Andi Scharfstein
      • +
      • Oyvind Horneland
      • +
      • Görge Albrecht
      • +
      • Justin Ryan
      • +
      • Maria Savela
      • +
      • Eugen Parasachiv
      • +
      • Stefan Domnanovits
      • +
      • Nils Wloka
      • +
      • Eduardo Ucha Tortuero
      • +
      • Mark Crossfield
      • +
      • Benjamin Murray
      • +
      • MinGyoo Jung
      • +
      • Hadrien Zalek
      • +
      • Khaled Sinno
      • +
      • Chadi El Masri
      • +
      • Davide Fucci
      • +
      • Frederik Hahne
      • +
      • Benjamin Murray
      • +
      • Erik Severinsen
      • +
      • Anna-Pitschna Kunz
      • +
      • Daniel Baldes
      • +
      • Stefan Ferstl
      • +
      • Jonathan Gray
      • +
      • Seb Heglmeier
      • +
      • Bruno Girin
      • +
      • Steve Ash
      • +
      • Yves Geissbuehler
      • +
      • Jacques Stadler
      • +
      • Bernard D'Havé
      • +
      • Monica Granbois
      • +
      • Florian Hopf
      • +
      • Erich Oswald
      • +
      • Joe Schmetzer
      • +
      • Sebastian Hempel
      • +
      • Christoph Pater
      • +
      • Klaus Unger
      • +
      • Martijn Dashorst
      • +
      • Alexey Kornev
      • +
      • Timo Kockert
      • +
      • Michael Prieß
      • +
      • Joseph Moore
      • +
      • Richard Capraro
      • +
      • J. B. Rainsberger
      • +
      • Marcel Körtgen
      • +
      • Tim Yates
      • +
      • Evan Porter
      • +
      • Jeroen Ingelbrecht
      • +
      • Mustafa Ulu
      • +
      • Daniel Wellman
      • +
      • Juan Llado
      • +
      • Michał Bendowski
      • +
      • Samir Talwar
      • +
      • David Tanzer
      • +
      • Siv Midtun Hollup
      • +
      • Alexander Schwartz
      • +
      • Oliver Paulus
      • +
      • Micael Gallego
      • +
      • Johannes Seitz
      • +
      • Tristan Mills
      • +
      • Henk van Voorthuijsen
      • +
      • Dennis Hunziker
      • +
      • Stefan Odendahl
      • +
      • Gregor Trefs
      • +
      • Steve Moyer
      • +
      • Björn Kimminich
      • +
      • Fabrice Sznajderman
      • +
      • Nikita Makarov
      • +
      • Carsten Otto
      • +
      • Markus Decke
      • +
      • Henrik Steudel
      • +
      • Matt Newell
      • +
      • Thomas Michael
      • +
      • Robert Klaus
      • +
      • Martin Dürrmeier
      • +
      • Petri Kainulainen
      • +
      • Jean-Christophe Sirot
      • +
      • Max Schwaab
      • +
      • Brian Clozel
      • +
      • Per-Ingemar Andersson
      • +
      • Henry Voyer
      • +
      • Greg Roodt
      • +
      • Java User Group Frankfurt
      • +
      • Adrian McMichael
      • +
      • Björn Darri Sigurðsson
      • +
      • Chris Williams
      • +
      • Agile Pain Relief Consulting
      • +
      • Andrew Beussink
      • +
      • Per Arnold Blaasmo
      • +
      • Ian Mayo
      • +
      • Doyle Young
      • +
      • Wolfgang Werner
      • +
      • Daniel Kunz
      • +
      • Benjamin Herbert
      • +
      • Axel Schüssler
      • +
      • Matthias Lünemann
      • +
      • Christophe Taret
      • +
      • Stephen Starkey
      • +
      • Michael Dörsam
      • +
      • Matt Bertolini
      • +
      • Jun Yong Chong
      • +
      • Svante Kumlien
      • +
      • Matt Garner
      • +
      • Patrick Podbregar
      • +
      • Alessandro Proscia
      • +
      • David Burkhart
      • +
      • Matthias Grund
      • +
      • Tomas Michalec
      • +
      • Tadaya Tsuyukubo
      • +
      • Frank Appel
      • +
      • Paul Holser
      • +
      • Patrick Baumgartner
      • +
      • Emmanuel Chavane
      • +
      • Kini
      • +
      • Robert-Jan Regout
      • +
      • Bastian Spanneberg
      • +
      • Jérémie Bresson
      • +
      • Harald Brabenetz
      • +
      • Nacho Cougil
      • +
      • Martin Schröder
      • +
      • Thorsten Brunzendorf
      • +
      • Paolo Escobar
      • +
      • Brad Milne
      • +
      • Bill Chen
      • +
      • Craig Doremus
      • +
      • Jean-Michel Bea
      • +
      • Thorsten Göckeler
      • +
      • Ben Romberg
      • +
      • Sixto Cantolla Sánchez
      • +
      • Altiria
      • +
      • Andres Rodriguez
      • +
      • Romain Rocès
      • +
      • Ivan Caspeta
      • +
      • Oliver Gierke
      • +
      • Pierre Marguerite
      • +
      • Dmitry Spikhalskiy
      • +
      • Francisco Javier Jiménez Sáez
      • +
      • Ivo Smid
      • +
      • Sargon
      • +
      • Balázs Sándor Mracskó
      • +
      • Marco Fritschi
      • +
      • Matthias 'Yolgie' Holzinger
      • +
      • Christian Schubert
      • +
      • Rémy Francillette
      • +
      • Martin Klose
      • +
      • tennisoff.net
      • +
      • Yoshio Terada
      • +
      • Oleg Lavorskyi
      • +
      • Marvin Lillehaug
      • +
      • y.ono
      • +
      • Kouji Nomura
      • +
      • Takuto Wada
      • +
      • Teruaki Kanamori
      • +
      • Keita Kita
      • +
      • Manabu Matsuzaki
      • +
      • Sato Taichi
      • +
      • Koji Hasegawa
      • +
      • Lukas Hinsch
      • +
      • Hirofumi Nakagawa
      • +
      • Chanwook
      • +
      • Masashi Yoshida
      • +
      • Yusuke Ikeda
      • +
      • Takafumi Yoshida
      • +
      • Iwao Harada
      • +
      • Daisuke Nakagome
      • +
      • Yasushi Hagai
      • +
      • Takuya Kawabe
      • +
      • Oohara Kazutaka
      • +
      • Itsuo Okamoto
      • +
      • Shigeyuki Azuchi
      • +
      • Shinya Kamijo
      • +
      • Noritaka Ishizumi
      • +
      • Cagatay Kavukcuoglu
      • +
      • Lars Vogel
      • +
      • Koji LIn
      • +
      • Elmar Fasel
      • +
      • Behrang Saeedzadeh
      • +
      • Paul Naranja
      • +
      • Naoko Yamazaki
      • +
      • Kouta Imanaka
      • +
      • Takahiro Yano
      • +
      • Minoru Yokomichi
      • +
      • Yuki Matsumura
      • +
      • Kazutoshi Tanaka
      • +
      • Itsuki Kuroda
      • +
      • Alexander Golonzovsky
      • +
      • Ryo Uchino
      • +
      • Shingo Ishimura
      • +
      • Yamamoto Masaki
      • +
      • 幸田英隆
      • +
      • Hiroyuki Ohnaka
      • +
      • Ito Sho
      • +
      • Yu Asano
      • +
      • Takeshi Hagikura
      • +
      • Shigeki Yamato
      • +
      • Shinya Yoshida
      • +
      • Dimitrios Liapis
      • +
      • Kohei Yamamoto
      • +
      • Hiroto Kusuda
      • +
      • Jonas Lindholm
      • +
      • Takumi Endo
      • +
      • Gabi Merten
      • +
      • Ben Hale
      • +
      • Eiji Hachiya
      • +
      • Hideyuki Kikuma
      • +
      • Park Sungchul
      • +
      • Eiji Yamane
      • +
      • Akinori Ikeda
      • +
      • Jun Nakamura
      • +
      • Takuya Shimabukuro
      • +
      • Setsu Fujita
      • +
      • Jochen Winzen
      • +
      • Yousuke Tezuka
      • +
      • Shimizu Yasuhiro
      • +
      • Satoshi Okano
      • +
      • Yasuyuki Fukai
      • +
      • Charles Goddard
      • +
      • Tiarê Balbi Bonamini
      • +
      • Kazumune Katagiri
      • +
      • Masahiro Wakame
      • +
      • Kazutaka Ogaki
      • +
      • Taizo Nakatani
      • +
      • Yoshitaka Kawaji
      • +
      • Akihiro Kitada
      • +
      • Kozaki Tsuneaki
      • +
      • Takehiro Inoue
      • +
      • Shigeki Shoji
      • +
      • Junya Suzuki
      • +
      • Tomoharu Nagasawa
      • +
      • Toby Lee
      • +
      • Yuichiro Mukai
      • +
      • Hiroyuki Yamaoka
      • +
      • Jun Sagawa
      • +
      • Soma Kuwabara
      • +
      • Yui Iwamatsu
      • +
      • Michael Schlechter
      • +
      • Hiroshi Ito
      • +
      • Tae-jun Jin
      • +
      • Dennis Rippinger
      • +
      • Dejan Janosevic
      • +
      • Dbj Shrestha
      • +
      • Hideaki Takahashi
      • +
      • Daigo Ikeda
      • +
      • Teppei Yamaguchi
      • +
      • Pierre Templier
      • +
      • TDD Base Camp
      • +
      • Hirofumi Nozaki
      • +
      • Takayuki Hayashi
      • +
      • Steven Christou
      • +
      • Kostadin Golev
      • +
      • Ricardo Gladwell
      • +
      • Thorsten Hoeger
      • +
      • Markus Gärtner
      • +
      • Hiroyuki Aoki
      • +
      • Gary Fleming
      • +
      • Samuel Eickelberg
      • +
      • Marcel Berschneider
      • +
      • Frank Jakop
      • +
      • Dominik Lange
      • +
      • Stefan Matzdorf
      • +
      • Suzanne Hamilton
      • +
      • Satoru Kimura
      • +
      • 今井一幾
      • +
      • Yasuharu Nakano
      • +
      • Takatoshi Kawamura
      • +
      + + diff --git a/src/site/xhtml/junit-lambda-spending.xhtml b/src/site/xhtml/junit-lambda-spending.xhtml new file mode 100644 index 000000000000..8125c1ce74a7 --- /dev/null +++ b/src/site/xhtml/junit-lambda-spending.xhtml @@ -0,0 +1,29 @@ + + + JUnit Lambda - Campaign Spending + + +

      JUnit Lambda - Spending

      +

      + Since all the money is going through the books of a company (andrena objects ag), + the exact amount for taxes cannot be calculated. We will fill in details and + exact amounts for other positions as soon as we have them. +

      + + + + + + + + + + + + + + + +
      WhatCredit/EURDebit/EURBalance/EUR
      Indiegogo Sum€53,937.00€53,937.00
      Indiegogo Fees (5%)€2,696.85€51,240.15
      Paypal Fees€2,270.06€48,970.09
      German VAT (estimated)€7,666.49€41,303.60
      Kick-off Expenses, Travel and Food€3,011.32€38,292.28
      Development October 2015€14,000.00€24,292.28
      Development November 2015€7,600.00€16,692.28
      Development December 2015€5,400.00€11,292.28
      Travel Expenses December 2015€749.69€10,542.59
      Development January 2016€6,000.00€4,542.59
      Travel Expenses January 2016€1,001.13€3,541.46
      Development April 2016€1,200.00€2,341.46
      Development August 2016€2,341.46€0.00
      + + diff --git a/src/site/xhtml/junit-lambda.xhtml b/src/site/xhtml/junit-lambda.xhtml new file mode 100644 index 000000000000..ce0752fb55d1 --- /dev/null +++ b/src/site/xhtml/junit-lambda.xhtml @@ -0,0 +1,30 @@ + + + JUnit Lambda + + +

      JUnit Lambda

      +

      + JUnit Lambda was the working title for + what has now become JUnit 5. +

      +

      + The initial phases of this work were enabled by a crowdfunding campaign on Indiegogo. +

      +
      +

      Campaign Spending

      +

      + As part of our accountability we agreed to make all campaign spending transparent. +

      +
      +

      Main Sponsors and Campaign Sponsor

      +

      Without sponsoring JUnit Lambda would not exist. We're especially grateful to the companies below:

      +
        +
      • +
      • +
      • +
      • +
      • +
      + + diff --git a/src/site/xhtml/junit5.xhtml b/src/site/xhtml/junit5.xhtml new file mode 100644 index 000000000000..d0f7b6f98d84 --- /dev/null +++ b/src/site/xhtml/junit5.xhtml @@ -0,0 +1,11 @@ + + + JUnit 5 + + +

      JUnit 5

      +

      + This page has moved to http://junit.org/junit5/. +

      + + diff --git a/src/test/java/junit/samples/ListTest.java b/src/test/java/junit/samples/ListTest.java index 182027f56244..324f12bd0e23 100644 --- a/src/test/java/junit/samples/ListTest.java +++ b/src/test/java/junit/samples/ListTest.java @@ -11,20 +11,17 @@ * A sample test case, testing {@link java.util.ArrayList}. */ public class ListTest extends TestCase { - protected List fEmpty; - protected List fFull; + private List emptyList; + private List fullList; - public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); - } @Override protected void setUp() { - fEmpty = new ArrayList(); - fFull = new ArrayList(); - fFull.add(1); - fFull.add(2); - fFull.add(3); + emptyList = new ArrayList(); + fullList = new ArrayList(); + fullList.add(1); + fullList.add(2); + fullList.add(3); } public static Test suite() { @@ -32,24 +29,24 @@ public static Test suite() { } public void testCapacity() { - int size = fFull.size(); + int size = fullList.size(); for (int i = 0; i < 100; i++) { - fFull.add(new Integer(i)); + fullList.add(i); } - assertTrue(fFull.size() == 100 + size); + assertTrue(fullList.size() == 100 + size); } public void testContains() { - assertTrue(fFull.contains(1)); - assertTrue(!fEmpty.contains(1)); + assertTrue(fullList.contains(1)); + assertFalse(emptyList.contains(1)); } public void testElementAt() { - int i = fFull.get(0); - assertTrue(i == 1); + int i = fullList.get(0); + assertEquals(1,i); try { - fFull.get(fFull.size()); + fullList.get(fullList.size()); } catch (IndexOutOfBoundsException e) { return; } @@ -57,14 +54,14 @@ public void testElementAt() { } public void testRemoveAll() { - fFull.removeAll(fFull); - fEmpty.removeAll(fEmpty); - assertTrue(fFull.isEmpty()); - assertTrue(fEmpty.isEmpty()); + fullList.removeAll(fullList); + emptyList.removeAll(emptyList); + assertTrue(fullList.isEmpty()); + assertTrue(emptyList.isEmpty()); } public void testRemoveElement() { - fFull.remove(new Integer(3)); - assertTrue(!fFull.contains(3)); + fullList.remove(Integer.valueOf(3)); + assertFalse(fullList.contains(3)); } } \ No newline at end of file diff --git a/src/test/java/junit/tests/extensions/ExtensionTest.java b/src/test/java/junit/tests/extensions/ExtensionTest.java index bfe1eccdd8e9..155a478a4f2c 100644 --- a/src/test/java/junit/tests/extensions/ExtensionTest.java +++ b/src/test/java/junit/tests/extensions/ExtensionTest.java @@ -71,6 +71,7 @@ public void testSetupErrorDontTearDown() { WasRun test = new WasRun(); TornDown wrapper = new TornDown(test) { + @SuppressWarnings("deprecation") @Override public void setUp() { fail(); @@ -87,6 +88,7 @@ public void testSetupErrorInTestSetup() { WasRun test = new WasRun(); TestSetup wrapper = new TestSetup(test) { + @SuppressWarnings("deprecation") @Override public void setUp() { fail(); diff --git a/src/test/java/junit/tests/runner/ResultTest.java b/src/test/java/junit/tests/runner/ResultTest.java index 17204068da40..7a6042996268 100644 --- a/src/test/java/junit/tests/runner/ResultTest.java +++ b/src/test/java/junit/tests/runner/ResultTest.java @@ -2,6 +2,8 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; @@ -10,6 +12,7 @@ import junit.framework.TestCase; import junit.tests.framework.Success; +import org.junit.Test; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; @@ -17,32 +20,89 @@ public class ResultTest extends TestCase { + private Result fromStream; + public void testRunFailureResultCanBeSerialised() throws Exception { JUnitCore runner = new JUnitCore(); Result result = runner.run(AnnotationTest.FailureTest.class); assertResultSerializable(result); } + public void testRunFailureResultCanBeReserialised_v4_12() throws Exception { + JUnitCore runner = new JUnitCore(); + Result result = runner.run(AnnotationTest.FailureTest.class); + assertResultReserializable(result, SerializationFormat.V4_12); + } + + public void testRunAssumptionFailedResultCanBeSerialised() throws Exception { + JUnitCore runner = new JUnitCore(); + Result result = runner.run(AssumptionFailedTest.class); + assertResultSerializable(result); + } + + public void testRunAssumptionFailedResultCanBeReserialised_v4_12() throws Exception { + JUnitCore runner = new JUnitCore(); + Result result = runner.run(AssumptionFailedTest.class); + assertResultReserializable(result, SerializationFormat.V4_12); + } + + public void testRunAssumptionFailedResultCanBeReserialised_v4_13() throws Exception { + JUnitCore runner = new JUnitCore(); + Result result = runner.run(AssumptionFailedTest.class); + assertResultReserializable(result, SerializationFormat.V4_13); + } + public void testRunSuccessResultCanBeSerialised() throws Exception { JUnitCore runner = new JUnitCore(); Result result = runner.run(Success.class); assertResultSerializable(result); } + public void testRunSuccessResultCanBeReserialised_v4_12() throws Exception { + JUnitCore runner = new JUnitCore(); + Result result = runner.run(Success.class); + assertResultReserializable(result, SerializationFormat.V4_12); + } + + public void testRunSuccessResultCanBeReserialised_v4_13() throws Exception { + JUnitCore runner = new JUnitCore(); + Result result = runner.run(Success.class); + assertResultReserializable(result, SerializationFormat.V4_13); + } + + private enum SerializationFormat { + V4_12, + V4_13 + } + private void assertResultSerializable(Result result) throws IOException, ClassNotFoundException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - new ObjectOutputStream(byteArrayOutputStream).writeObject(result); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); + objectOutputStream.writeObject(result); + objectOutputStream.flush(); byte[] bytes = byteArrayOutputStream.toByteArray(); ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes)); Result fromStream = (Result) objectInputStream.readObject(); - assertSerializedCorrectly(result, fromStream); - - InputStream resource = getClass().getResourceAsStream(getName()); - assertNotNull("Could not read resource " + getName(), resource); - objectInputStream = new ObjectInputStream(resource); + assertSerializedCorrectly(result, fromStream, SerializationFormat.V4_13); + } + + private void assertResultReserializable(Result result, SerializationFormat resourceSerializationFormat) + throws IOException, ClassNotFoundException { + String resourceName = getName(); + InputStream resource = getClass().getResourceAsStream(resourceName); + assertNotNull("Could not read resource " + resourceName, resource); + ObjectInputStream objectInputStream = new ObjectInputStream(resource); fromStream = (Result) objectInputStream.readObject(); - - assertSerializedCorrectly(new ResultWithFixedRunTime(result), fromStream); + + assertSerializedCorrectly(new ResultWithFixedRunTime(result), + fromStream, resourceSerializationFormat); + } + + static public class AssumptionFailedTest { + @Test + public void assumptionFailed() throws Exception { + org.junit.Assume.assumeTrue(false); + } } /** @@ -50,6 +110,9 @@ private void assertResultSerializable(Result result) throws IOException, ClassNo * This makes values returned by the methods deterministic. */ private static class ResultWithFixedRunTime extends Result { + + private static final long serialVersionUID = 1L; + private final Result delegate; public ResultWithFixedRunTime(Result delegate) { @@ -80,14 +143,35 @@ public List getFailures() { public int getIgnoreCount() { return delegate.getIgnoreCount(); } + + @Override + public int getAssumptionFailureCount() { + return delegate.getAssumptionFailureCount(); + } } - private void assertSerializedCorrectly(Result result, Result fromStream) { + private void assertSerializedCorrectly( + Result result, Result fromStream, SerializationFormat serializationFormat) { assertNotNull(fromStream); // Exceptions don't implement equals() so we need to compare field by field assertEquals("failureCount", result.getFailureCount(), fromStream.getFailureCount()); assertEquals("ignoreCount", result.getIgnoreCount(), fromStream.getIgnoreCount()); + + if (serializationFormat == SerializationFormat.V4_13) { + // assumption failures are serialized + assertEquals("assumptionFailureCount", + result.getAssumptionFailureCount(), + fromStream.getAssumptionFailureCount()); + } else { + // assumption failures were not serialized + try { + fromStream.getAssumptionFailureCount(); + fail("UnsupportedOperationException expected"); + } catch (UnsupportedOperationException expected) { + } + } + assertEquals("runTime", result.getRunTime(), fromStream.getRunTime()); assertEquals("failures", result.getFailures().size(), fromStream.getFailures().size()); int index = 0; diff --git a/src/test/java/junit/tests/runner/StackFilterTest.java b/src/test/java/junit/tests/runner/StackFilterTest.java index 741fc3484612..6aca9ebf1053 100644 --- a/src/test/java/junit/tests/runner/StackFilterTest.java +++ b/src/test/java/junit/tests/runner/StackFilterTest.java @@ -15,28 +15,28 @@ 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)"); + pwin.println("\tat junit.framework.Assert.fail(Assert.java:144)"); + pwin.println("\tat junit.framework.Assert.assert(Assert.java:19)"); + pwin.println("\tat junit.framework.Assert.assert(Assert.java:26)"); + pwin.println("\tat MyTest.f(MyTest.java:13)"); + pwin.println("\tat MyTest.testStackTrace(MyTest.java:8)"); + pwin.println("\tat java.lang.reflect.Method.invoke(Native Method)"); + pwin.println("\tat junit.framework.TestCase.runTest(TestCase.java:156)"); + pwin.println("\tat junit.framework.TestCase.runBare(TestCase.java:130)"); + pwin.println("\tat junit.framework.TestResult$1.protect(TestResult.java:100)"); + pwin.println("\tat junit.framework.TestResult.runProtected(TestResult.java:118)"); + pwin.println("\tat junit.framework.TestResult.run(TestResult.java:103)"); + pwin.println("\tat junit.framework.TestCase.run(TestCase.java:121)"); + pwin.println("\tat junit.framework.TestSuite.runTest(TestSuite.java:157)"); + pwin.println("\tat junit.framework.TestSuite.run(TestSuite.java, Compiled Code)"); + pwin.println("\tat 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)"); + pwout.println("\tat MyTest.f(MyTest.java:13)"); + pwout.println("\tat MyTest.testStackTrace(MyTest.java:8)"); fFiltered = swout.toString(); } diff --git a/src/test/java/org/junit/AssumptionViolatedExceptionTest.java b/src/test/java/org/junit/AssumptionViolatedExceptionTest.java index 18deb9e18367..574cdb13059d 100644 --- a/src/test/java/org/junit/AssumptionViolatedExceptionTest.java +++ b/src/test/java/org/junit/AssumptionViolatedExceptionTest.java @@ -3,8 +3,7 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assume.assumeThat; import org.hamcrest.Matcher; import org.hamcrest.StringDescription; diff --git a/src/test/java/org/junit/experimental/categories/AllCategoriesTests.java b/src/test/java/org/junit/experimental/categories/AllCategoriesTests.java new file mode 100644 index 000000000000..6609bb8dcb4e --- /dev/null +++ b/src/test/java/org/junit/experimental/categories/AllCategoriesTests.java @@ -0,0 +1,17 @@ +package org.junit.experimental.categories; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + CategoriesAndParameterizedTest.class, + CategoryFilterFactoryTest.class, + CategoryTest.class, + CategoryValidatorTest.class, + JavadocTest.class, + MultiCategoryTest.class +}) +public class AllCategoriesTests { +} diff --git a/src/test/java/org/junit/experimental/categories/CategoriesAndParameterizedTest.java b/src/test/java/org/junit/experimental/categories/CategoriesAndParameterizedTest.java new file mode 100644 index 000000000000..68e842bb53e9 --- /dev/null +++ b/src/test/java/org/junit/experimental/categories/CategoriesAndParameterizedTest.java @@ -0,0 +1,129 @@ +package org.junit.experimental.categories; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Categories; +import org.junit.experimental.categories.Categories.IncludeCategory; +import org.junit.experimental.categories.Category; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Suite.SuiteClasses; + +public class CategoriesAndParameterizedTest { + public static class Token { + + } + + @RunWith(Parameterized.class) + public static class ParameterizedTestWithoutCategory { + @Parameters + public static Iterable getParameters() { + return Arrays.asList("first", "second"); + } + + @Parameterized.Parameter + public String value; + + @Test + public void testSomething() { + Assert.assertTrue(true); + } + } + + @Category(Token.class) + public static class TestThatAvoidsNoTestRemainsException { + @Test + public void testSomething() { + Assert.assertTrue(true); + } + } + + @RunWith(Categories.class) + @IncludeCategory(Token.class) + @SuiteClasses({ TestThatAvoidsNoTestRemainsException.class, + ParameterizedTestWithoutCategory.class }) + public static class SuiteWithParameterizedTestWithoutCategory { + } + + @Test + public void doesNotRunTestsWithoutCategory() { + Result result = new JUnitCore() + .run(SuiteWithParameterizedTestWithoutCategory.class); + assertEquals(1, result.getRunCount()); + assertEquals(0, result.getFailureCount()); + } + + @RunWith(Parameterized.class) + @Category(Token.class) + public static class ParameterizedTestWithCategory { + @Parameters + public static Iterable getParameters() { + return Arrays.asList("first", "second"); + } + + @Parameterized.Parameter + public String value; + + @Test + public void testSomething() { + Assert.assertTrue(true); + } + } + + @RunWith(Categories.class) + @IncludeCategory(Token.class) + @SuiteClasses({ ParameterizedTestWithCategory.class }) + public static class SuiteWithParameterizedTestWithCategory { + } + + @Test + public void runsTestsWithoutCategory() { + Result result = new JUnitCore() + .run(SuiteWithParameterizedTestWithCategory.class); + assertEquals(2, result.getRunCount()); + assertEquals(0, result.getFailureCount()); + } + + @RunWith(Parameterized.class) + public static class ParameterizedTestWithMethodWithCategory { + @Parameters + public static Iterable getParameters() { + return Arrays.asList("first", "second"); + } + + @Parameterized.Parameter + public String value; + + @Test + @Category(Token.class) + public void testSomething() { + Assert.assertTrue(true); + } + + @Test + public void testThatIsNotExecuted() { + Assert.assertTrue(true); + } + } + + @RunWith(Categories.class) + @IncludeCategory(Token.class) + @SuiteClasses({ ParameterizedTestWithMethodWithCategory.class }) + public static class SuiteWithParameterizedTestWithMethodWithCategory { + } + + @Test + public void runsTestMethodWithCategory() { + Result result = new JUnitCore() + .run(SuiteWithParameterizedTestWithMethodWithCategory.class); + assertEquals(2, result.getRunCount()); + assertEquals(0, result.getFailureCount()); + } +} \ No newline at end of file diff --git a/src/test/java/org/junit/tests/experimental/categories/CategoryTest.java b/src/test/java/org/junit/experimental/categories/CategoryTest.java similarity index 91% rename from src/test/java/org/junit/tests/experimental/categories/CategoryTest.java rename to src/test/java/org/junit/experimental/categories/CategoryTest.java index e1a6af37235b..59242b447cfa 100644 --- a/src/test/java/org/junit/tests/experimental/categories/CategoryTest.java +++ b/src/test/java/org/junit/experimental/categories/CategoryTest.java @@ -1,8 +1,8 @@ -package org.junit.tests.experimental.categories; +package org.junit.experimental.categories; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.experimental.results.PrintableResult.testResult; @@ -179,7 +179,7 @@ public static class TestSuiteWithNoCategories { } @Test - public void testCountWithExplicitFilter() throws Throwable { + public void testCountWithExplicitIncludeFilter() throws Throwable { CategoryFilter include = CategoryFilter.include(SlowTests.class); Request baseRequest = Request.aClass(TestSuiteWithNoCategories.class); Result result = new JUnitCore().run(baseRequest.filterWith(include)); @@ -187,6 +187,24 @@ public void testCountWithExplicitFilter() throws Throwable { assertEquals(2, result.getRunCount()); } + @Test + public void testCountWithExplicitExcludeFilter() throws Throwable { + CategoryFilter include = CategoryFilter.exclude(SlowTests.class); + Request baseRequest = Request.aClass(TestSuiteWithNoCategories.class); + Result result = new JUnitCore().run(baseRequest.filterWith(include)); + assertEquals(2, result.getFailureCount()); + assertEquals(2, result.getRunCount()); + } + + @Test + public void testCountWithExplicitExcludeFilter_usingConstructor() throws Throwable { + CategoryFilter include = new CategoryFilter(null, SlowTests.class); + Request baseRequest = Request.aClass(TestSuiteWithNoCategories.class); + Result result = new JUnitCore().run(baseRequest.filterWith(include)); + assertEquals(2, result.getFailureCount()); + assertEquals(2, result.getRunCount()); + } + @Test public void categoryFilterLeavesOnlyMatchingMethods() throws InitializationError, NoTestsRemainException { @@ -196,6 +214,15 @@ public void categoryFilterLeavesOnlyMatchingMethods() assertEquals(1, runner.testCount()); } + @Test + public void categoryFilterLeavesOnlyMatchingMethods_usingConstructor() + throws InitializationError, NoTestsRemainException { + CategoryFilter filter = new CategoryFilter(SlowTests.class, null); + BlockJUnit4ClassRunner runner = new BlockJUnit4ClassRunner(A.class); + filter.apply(runner); + assertEquals(1, runner.testCount()); + } + public static class OneFastOneSlow { @Category(FastTests.class) @Test diff --git a/src/test/java/org/junit/tests/experimental/categories/CategoryValidatorTest.java b/src/test/java/org/junit/experimental/categories/CategoryValidatorTest.java similarity index 96% rename from src/test/java/org/junit/tests/experimental/categories/CategoryValidatorTest.java rename to src/test/java/org/junit/experimental/categories/CategoryValidatorTest.java index 8f7397ee9d91..654622f594bf 100644 --- a/src/test/java/org/junit/tests/experimental/categories/CategoryValidatorTest.java +++ b/src/test/java/org/junit/experimental/categories/CategoryValidatorTest.java @@ -1,7 +1,7 @@ -package org.junit.tests.experimental.categories; +package org.junit.experimental.categories; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import java.util.List; diff --git a/src/test/java/org/junit/tests/experimental/categories/JavadocTest.java b/src/test/java/org/junit/experimental/categories/JavadocTest.java similarity index 97% rename from src/test/java/org/junit/tests/experimental/categories/JavadocTest.java rename to src/test/java/org/junit/experimental/categories/JavadocTest.java index 0f9af8e7cb26..65fa430f9dbb 100644 --- a/src/test/java/org/junit/tests/experimental/categories/JavadocTest.java +++ b/src/test/java/org/junit/experimental/categories/JavadocTest.java @@ -1,4 +1,4 @@ -package org.junit.tests.experimental.categories; +package org.junit.experimental.categories; import org.junit.Test; import org.junit.experimental.categories.Categories; diff --git a/src/test/java/org/junit/tests/experimental/categories/MultiCategoryTest.java b/src/test/java/org/junit/experimental/categories/MultiCategoryTest.java similarity index 99% rename from src/test/java/org/junit/tests/experimental/categories/MultiCategoryTest.java rename to src/test/java/org/junit/experimental/categories/MultiCategoryTest.java index 986c5a895173..c7169aca120a 100644 --- a/src/test/java/org/junit/tests/experimental/categories/MultiCategoryTest.java +++ b/src/test/java/org/junit/experimental/categories/MultiCategoryTest.java @@ -1,4 +1,4 @@ -package org.junit.tests.experimental.categories; +package org.junit.experimental.categories; import org.junit.Test; import org.junit.experimental.categories.Categories; diff --git a/src/test/java/org/junit/internal/AllInternalTests.java b/src/test/java/org/junit/internal/AllInternalTests.java new file mode 100644 index 000000000000..270d80086149 --- /dev/null +++ b/src/test/java/org/junit/internal/AllInternalTests.java @@ -0,0 +1,27 @@ +package org.junit.internal; + +import org.junit.internal.builders.AnnotatedBuilderTest; +import org.junit.internal.matchers.StacktracePrintingMatcherTest; +import org.junit.internal.matchers.ThrowableCauseMatcherTest; +import org.junit.internal.runners.ErrorReportingRunnerTest; +import org.junit.internal.runners.statements.ExpectExceptionTest; +import org.junit.internal.runners.statements.FailOnTimeoutTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + AnnotatedBuilderTest.class, + ChecksTest.class, + ErrorReportingRunnerTest.class, + ExpectExceptionTest.class, + FailOnTimeoutTest.class, + MethodSorterTest.class, + StacktracePrintingMatcherTest.class, + StackTracesTest.class, + ThrowableCauseMatcherTest.class, + ArrayComparisonFailureTest.class +}) +public class AllInternalTests { +} diff --git a/src/test/java/org/junit/internal/ArrayComparisonFailureTest.java b/src/test/java/org/junit/internal/ArrayComparisonFailureTest.java new file mode 100644 index 000000000000..93db64992fa3 --- /dev/null +++ b/src/test/java/org/junit/internal/ArrayComparisonFailureTest.java @@ -0,0 +1,68 @@ +package org.junit.internal; + +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +public class ArrayComparisonFailureTest { + + private static final String ARRAY_COMPARISON_FAILURE_411 = "arrayComparisonFailure_411"; + private static final String ARRAY_COMPARISON_FAILURE_412 = "arrayComparisonFailure_412"; + + /* + Test compatibility of older versions of ArrayComparisonFailure + Setup: + - checkout prior versions of the codebase (r4.11, r4.12 in this case) + - catch the exception resulting from: + assertArrayEquals(new int[]{0, 1}, new int[]{0, 5}); + - serialize the resulting exception to a file, moving into the test/resources path + Ex., for v4.11's resulting exception {@link org/junit/internal/arrayComparisonFailure_411} + Current unit test: + - deserialize the above files casting it to the current version of the class + (catches any forward incompatibility with missing fields) + - assert the results from existing methods: getCause(), toString() -> getMessage() + (catches incompatible usages of fields) + + This does not test if an instance of the current version of the class is able to deserialize to a previous ver. + */ + + @Test + public void classShouldAccept411Version() throws Exception { + assertFailureSerializableFromOthers(ARRAY_COMPARISON_FAILURE_411); + } + + @Test + public void classShouldAccept412Version() throws Exception { + assertFailureSerializableFromOthers(ARRAY_COMPARISON_FAILURE_412); + } + + private void assertFailureSerializableFromOthers(String failureFileName) throws IOException, + ClassNotFoundException { + try { + assertArrayEquals(new int[]{0, 1}, new int[]{0, 5}); + fail(); + } catch (ArrayComparisonFailure e) { + ArrayComparisonFailure arrayComparisonFailureFromFile = deserializeFailureFromFile(failureFileName); + assertNotNull("ArrayComparisonFailure.getCause() should fallback to the deprecated fCause field" + + " for compatibility with older versions of junit4 that didn't use Throwable.initCause().", + arrayComparisonFailureFromFile.getCause()); + assertEquals(e.getCause().toString(), arrayComparisonFailureFromFile.getCause().toString()); + assertEquals(e.toString(), arrayComparisonFailureFromFile.toString()); + } + } + + private ArrayComparisonFailure deserializeFailureFromFile(String fileName) throws IOException, + ClassNotFoundException { + InputStream resource = getClass().getResourceAsStream(fileName); + ObjectInputStream objectInputStream = new ObjectInputStream(resource); + return (ArrayComparisonFailure) objectInputStream.readObject(); + } + +} \ No newline at end of file diff --git a/src/test/java/org/junit/internal/ChecksTest.java b/src/test/java/org/junit/internal/ChecksTest.java new file mode 100644 index 000000000000..29cfbd14391a --- /dev/null +++ b/src/test/java/org/junit/internal/ChecksTest.java @@ -0,0 +1,60 @@ +package org.junit.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; +import static org.junit.internal.Checks.notNull; +import org.junit.Test; + +/** Tests for {@link Checks}. */ +public class ChecksTest { + + @Test + public void notNullShouldReturnNonNullValues() { + Double value = Double.valueOf(3.14); + + Double result = notNull(value); + + assertSame(value, result); + } + + @Test + public void notNullShouldThrowOnNullValues() { + try { + notNull(null); + fail("NullPointerException expected"); + } catch (NullPointerException e) { + assertNull("message should be null", e.getMessage()); + } + } + + @Test + public void notNullWithMessageShouldReturnNonNullValues() { + Float value = Float.valueOf(3.14f); + + Float result = notNull(value, "woops"); + + assertSame(value, result); + } + + @Test + public void notNullWithMessageShouldThrowOnNullValues() { + try { + notNull(null, "woops"); + fail("NullPointerException expected"); + } catch (NullPointerException e) { + assertEquals("message does not match", "woops", e.getMessage()); + } + } + + @Test + public void notNullWithNullMessageShouldThrowOnNullValues() { + try { + notNull(null, null); + fail("NullPointerException expected"); + } catch (NullPointerException e) { + assertNull("message should be null", e.getMessage()); + } + } +} diff --git a/src/test/java/org/junit/internal/StackTracesTest.java b/src/test/java/org/junit/internal/StackTracesTest.java new file mode 100644 index 000000000000..748d86a5f9e8 --- /dev/null +++ b/src/test/java/org/junit/internal/StackTracesTest.java @@ -0,0 +1,476 @@ +package org.junit.internal; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.regex.Pattern; + +import junit.framework.TestCase; +import org.hamcrest.CoreMatchers; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.StringDescription; +import org.hamcrest.TypeSafeMatcher; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.MethodRule; +import org.junit.rules.TestRule; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +public class StackTracesTest { + private static final String EOL = System.getProperty("line.separator", "\n"); + private static ExecutorService executorService; + + @BeforeClass + public static void startExecutorService() { + executorService = Executors.newFixedThreadPool(1); + } + + @AfterClass + public static void shutDownExecutorService() { + executorService.shutdown(); + executorService = null; + } + + @Test + public void getTrimmedStackForJUnit4TestFailingInTestMethod() { + Result result = runTest(TestWithOneThrowingTestMethod.class); + assertEquals("Should run the test", 1, result.getRunCount()); + assertEquals("One test should fail", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: cause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$TestWithOneThrowingTestMethod.alwaysThrows")); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + @Test + public void getTrimmedStackForJUnit4TestFailingInTestMethodWithCause() { + Result result = runTest(TestWithOneThrowingTestMethodWithCause.class); + assertEquals("Should run the test", 1, result.getRunCount()); + assertEquals("One test should fail", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: outer"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithCause"), + at("org.junit.internal.StackTracesTest$TestWithOneThrowingTestMethodWithCause.alwaysThrows"), + framesTrimmed(), + message("Caused by: java.lang.RuntimeException: cause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithCause"), + framesInCommon()); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + @Test + public void getTrimmedStackForJUnit4TestFailingInBeforeMethod() { + Result result = runTest(TestWithThrowingBeforeMethod.class); + assertEquals("Should run the test", 1, result.getRunCount()); + assertEquals("One test should fail", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: cause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$TestWithThrowingBeforeMethod.alwaysThrows")); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + @Test + public void getTrimmedStackForJUnit3TestFailingInTestMethod() { + Result result = runTest(JUnit3TestWithOneThrowingTestMethod.class); + assertEquals("Should run the test", 1, result.getRunCount()); + assertEquals("One test should fail", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: cause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$JUnit3TestWithOneThrowingTestMethod.testAlwaysThrows")); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + @Test + public void getTrimmedStackForJUnit3TestFailingInSetupMethod() { + Result result = runTest(JUnit3TestWithThrowingSetUpMethod.class); + assertEquals("Should run the test", 1, result.getRunCount()); + assertEquals("One test should fail", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: cause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$JUnit3TestWithThrowingSetUpMethod.setUp")); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + @Test + public void getTrimmedStackForJUnit4TestFailingInTestRule() { + Result result = runTest(TestWithThrowingTestRule.class); + assertEquals("Should run the test", 1, result.getRunCount()); + assertEquals("One test should fail", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: cause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$ThrowingTestRule.apply")); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + @Test + public void getTrimmedStackForJUnit4TestFailingInClassRule() { + Result result = runTest(TestWithThrowingClassRule.class); + assertEquals("No tests were executed", 0, result.getRunCount()); + assertEquals("One failure", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: cause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$ThrowingTestRule.apply")); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + @Test + public void getTrimmedStackForJUnit4TestFailingInMethodRule() { + Result result = runTest(TestWithThrowingMethodRule.class); + assertEquals("Should run the test", 1, result.getRunCount()); + assertEquals("One test should fail", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: cause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.doThrowExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$FakeClassUnderTest.throwsExceptionWithoutCause"), + at("org.junit.internal.StackTracesTest$ThrowingMethodRule.apply")); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + @Test + public void getTrimmedStackWithSuppressedExceptions() { + assumeTrue("Running on 1.7+", TestWithSuppressedException.addSuppressed != null); + Result result = runTest(TestWithSuppressedException.class); + assertEquals("Should run the test", 1, result.getRunCount()); + assertEquals("One test should fail", 1, result.getFailureCount()); + Failure failure = result.getFailures().get(0); + + assertHasTrimmedTrace(failure, + message("java.lang.RuntimeException: error"), + at("org.junit.internal.StackTracesTest$TestWithSuppressedException.alwaysThrows"), + message("\tSuppressed: java.lang.RuntimeException: suppressed"), + at("org.junit.internal.StackTracesTest$TestWithSuppressedException.alwaysThrows"), + framesInCommon()); + assertNotEquals(failure.getTrace(), failure.getTrimmedTrace()); + } + + private abstract static class StringMatcher extends TypeSafeMatcher { + } + + /** + * A matcher that matches the exception message in a stack trace. + */ + private static class ExceptionMessageMatcher extends StringMatcher { + private final Matcher matcher; + + public ExceptionMessageMatcher(String message) { + matcher = CoreMatchers.equalTo(message); + } + + public void describeTo(Description description) { + matcher.describeTo(description); + } + + @Override + protected boolean matchesSafely(String line) { + return matcher.matches(line); + } + } + + /** Returns a matcher that matches the message line in a stack trace. */ + private static StringMatcher message(String message) { + return new ExceptionMessageMatcher(message); + } + + /** + * A matcher that matches the "at ..." line in a stack trace. + */ + private static class StackTraceLineMatcher extends StringMatcher { + private static final Pattern PATTERN + = Pattern.compile("\t*at ([a-zA-Z0-9.$]+)\\([a-zA-Z0-9]+\\.java:[0-9]+\\)"); + + private final String method; + + public StackTraceLineMatcher(String method) { + this.method = method; + } + + public void describeTo(Description description) { + description.appendText("A stack trace line for method " + method); + } + + @Override + protected boolean matchesSafely(String line) { + if (!line.startsWith("\t")) { + return false; + } + + line = line.substring(1); + java.util.regex.Matcher matcher = PATTERN.matcher(line); + if (!matcher.matches()) { + fail("Line does not look like a stack trace line: " + line); + } + String matchedMethod = matcher.group(1); + return method.equals(matchedMethod); + } + } + + /** Returns a matcher that matches the "at ..." line in a stack trace. */ + private static StringMatcher at(String method) { + return new StackTraceLineMatcher(method); + } + + /** + * A matcher that matches the line printed when frames were removed from a stack trace. + */ + private static class FramesRemovedMatcher extends StringMatcher { + private static final Pattern PATTERN + = Pattern.compile("\t*\\.\\.\\. [0-9]+ ([a-z]+)"); + + private final String suffix; + + public FramesRemovedMatcher(String suffix) { + this.suffix = suffix; + } + + public void describeTo(Description description) { + description.appendText("A line matching \"..x " + suffix + "\""); + } + + @Override + protected boolean matchesSafely(String line) { + if (!line.startsWith("\t")) { + return false; + } + line = line.substring(1); + + java.util.regex.Matcher matcher = PATTERN.matcher(line); + if (!matcher.matches()) { + fail("Line does not look like a stack trace line: " + line); + } + return suffix.equals(matcher.group(1)); + } + } + + /** Returns a matcher that matches the "\t...x more" line in a stack trace. */ + private static StringMatcher framesInCommon() { + return new FramesRemovedMatcher("more"); + } + + /** Returns a matcher that matches the "\t...x trimmed" line in a stack trace. */ + private static StringMatcher framesTrimmed() { + return new FramesRemovedMatcher("trimmed"); + } + + private static Result runTest(final Class testClass) { + Future future = executorService.submit(new Callable() { + public Result call() throws Exception { + JUnitCore core = new JUnitCore(); + return core.run(testClass); + } + }); + + try { + return future.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Could not run test " + testClass, e); + } catch (ExecutionException e) { + throw new RuntimeException("Could not run test " + testClass, e); + } + } + + private static void assertHasTrimmedTrace(Failure failure, StringMatcher... matchers) { + String trimmedTrace = failure.getTrimmedTrace(); + String[] lines = trimmedTrace.split(EOL); + + int index = 0; + for (; index < lines.length && index < matchers.length; index++) { + String line = lines[index]; + StringMatcher matcher = matchers[index]; + assertThat(line, matcher); + } + if (index < lines.length) { + String extraLine = lines[index]; + fail("Extra line in trimmed trace: " + extraLine); + } else if (index < matchers.length) { + StringDescription description = new StringDescription(); + matchers[index].describeTo(description); + fail("Missing line in trimmed trace: " + description.toString()); + } + } + + public static class TestWithOneThrowingTestMethod { + + @Test + public void alwaysThrows() { + new FakeClassUnderTest().throwsExceptionWithoutCause(); + } + } + + public static class JUnit3TestWithOneThrowingTestMethod extends TestCase { + + public void testAlwaysThrows() { + new FakeClassUnderTest().throwsExceptionWithoutCause(); + } + } + + public static class TestWithOneThrowingTestMethodWithCause { + + @Test + public void alwaysThrows() { + new FakeClassUnderTest().throwsExceptionWithCause(); + } + } + + public static class TestWithThrowingBeforeMethod { + + @Before + public void alwaysThrows() { + new FakeClassUnderTest().throwsExceptionWithoutCause(); + } + + @Test + public void alwaysPasses() { + } + } + + public static class JUnit3TestWithThrowingSetUpMethod extends TestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + new FakeClassUnderTest().throwsExceptionWithoutCause(); + } + + public void testAlwaysPasses() { + } + } + + public static class ThrowingTestRule implements TestRule { + + public Statement apply( + Statement base, org.junit.runner.Description description) { + new FakeClassUnderTest().throwsExceptionWithoutCause(); + return base; + } + } + + public static class TestWithThrowingTestRule { + + @Rule + public final TestRule rule = new ThrowingTestRule(); + + @Test + public void alwaysPasses() { + } + } + + public static class TestWithThrowingClassRule { + + @ClassRule + public static final TestRule rule = new ThrowingTestRule(); + + @Test + public void alwaysPasses() { + } + } + + public static class ThrowingMethodRule implements MethodRule { + + public Statement apply( + Statement base, FrameworkMethod method, Object target) { + new FakeClassUnderTest().throwsExceptionWithoutCause(); + return base; + } + } + + public static class TestWithThrowingMethodRule { + + @Rule + public final ThrowingMethodRule rule = new ThrowingMethodRule(); + + @Test + public void alwaysPasses() { + } + } + + private static class FakeClassUnderTest { + + public void throwsExceptionWithCause() { + doThrowExceptionWithCause(); + } + + public void throwsExceptionWithoutCause() { + doThrowExceptionWithoutCause(); + } + + private void doThrowExceptionWithCause() { + try { + throwsExceptionWithoutCause(); + } catch (Exception e) { + throw new RuntimeException("outer", e); + } + } + + private void doThrowExceptionWithoutCause() { + throw new RuntimeException("cause"); + } + } + + public static class TestWithSuppressedException { + static final Method addSuppressed = initAddSuppressed(); + + static Method initAddSuppressed() { + try { + return Throwable.class.getMethod("addSuppressed", Throwable.class); + } catch (Throwable e) { + return null; + } + } + + @Test + public void alwaysThrows() throws Exception { + final RuntimeException exception = new RuntimeException("error"); + addSuppressed.invoke(exception, new RuntimeException("suppressed")); + throw exception; + } + } +} diff --git a/src/test/java/org/junit/internal/builders/AnnotatedBuilderTest.java b/src/test/java/org/junit/internal/builders/AnnotatedBuilderTest.java index f937da363379..8c8f095bef46 100644 --- a/src/test/java/org/junit/internal/builders/AnnotatedBuilderTest.java +++ b/src/test/java/org/junit/internal/builders/AnnotatedBuilderTest.java @@ -1,5 +1,9 @@ package org.junit.internal.builders; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.hamcrest.core.IsNull.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.Runner; @@ -7,12 +11,6 @@ import org.junit.runners.model.RunnerBuilder; import org.junit.runners.model.RunnerBuilderStub; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; - public class AnnotatedBuilderTest { private AnnotatedBuilder builder = new AnnotatedBuilder(new RunnerBuilderStub()); @@ -28,7 +26,7 @@ public void topLevelTestClassWithAnnotation_isRunWithAnnotatedRunner() throws Ex assertThat(runner, is(instanceOf(RunnerSpy.class))); RunnerSpy runnerSpy = (RunnerSpy) runner; - assertThat(runnerSpy.getInvokedTestClass(), is(equalTo((Class) OuterClass.class))); + assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.class)); } @Test @@ -37,7 +35,7 @@ public void memberClassInsideAnnotatedTopLevelClass_isRunWithTopLevelRunner() th assertThat(runner, is(instanceOf(RunnerSpy.class))); RunnerSpy runnerSpy = (RunnerSpy) runner; - assertThat(runnerSpy.getInvokedTestClass(), is(equalTo((Class) OuterClass.InnerClassWithoutOwnRunWith.class))); + assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.InnerClassWithoutOwnRunWith.class)); } @Test @@ -46,7 +44,7 @@ public void memberClassDeepInsideAnnotatedTopLevelClass_isRunWithTopLevelRunner( assertThat(runner, is(instanceOf(RunnerSpy.class))); RunnerSpy runnerSpy = (RunnerSpy) runner; - assertThat(runnerSpy.getInvokedTestClass(), is(equalTo((Class) OuterClass.InnerClassWithoutOwnRunWith.MostInnerClass.class))); + assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.InnerClassWithoutOwnRunWith.MostInnerClass.class)); } @Test @@ -55,7 +53,7 @@ public void annotatedMemberClassInsideAnnotatedTopLevelClass_isRunWithOwnRunner( assertThat(runner, is(instanceOf(InnerRunner.class))); RunnerSpy runnerSpy = (RunnerSpy) runner; - assertThat(runnerSpy.getInvokedTestClass(), is(equalTo((Class) OuterClass.InnerClassWithOwnRunWith.class))); + assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.InnerClassWithOwnRunWith.class)); } @Test @@ -64,7 +62,7 @@ public void memberClassDeepInsideAnnotatedMemberClass_isRunWithParentMemberClass assertThat(runner, is(instanceOf(InnerRunner.class))); RunnerSpy runnerSpy = (RunnerSpy) runner; - assertThat(runnerSpy.getInvokedTestClass(), is(equalTo((Class) OuterClass.InnerClassWithOwnRunWith.MostInnerClass.class))); + assertThat(runnerSpy.getInvokedTestClass(), is((Object) OuterClass.InnerClassWithOwnRunWith.MostInnerClass.class)); } @RunWith(RunnerSpy.class) @@ -96,11 +94,11 @@ public void test() { } public static class InnerRunner extends RunnerSpy { - public InnerRunner(Class testClass) { + public InnerRunner(Class testClass) { super(testClass); } - public InnerRunner(Class testClass, RunnerBuilder runnerBuilder) { + public InnerRunner(Class testClass, RunnerBuilder runnerBuilder) { super(testClass, runnerBuilder); } } diff --git a/src/test/java/org/junit/internal/matchers/StacktracePrintingMatcherTest.java b/src/test/java/org/junit/internal/matchers/StacktracePrintingMatcherTest.java index 3bd2c54b4d04..2f22c9620873 100644 --- a/src/test/java/org/junit/internal/matchers/StacktracePrintingMatcherTest.java +++ b/src/test/java/org/junit/internal/matchers/StacktracePrintingMatcherTest.java @@ -4,8 +4,8 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.internal.matchers.StacktracePrintingMatcher.isException; import static org.junit.internal.matchers.StacktracePrintingMatcher.isThrowable; diff --git a/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java b/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java index dba1f7b2ce03..8a169c77dd75 100644 --- a/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java +++ b/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java @@ -3,7 +3,7 @@ import org.junit.Test; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause; public class ThrowableCauseMatcherTest { diff --git a/src/test/java/org/junit/internal/runners/ErrorReportingRunnerTest.java b/src/test/java/org/junit/internal/runners/ErrorReportingRunnerTest.java new file mode 100644 index 000000000000..e8263e544bc5 --- /dev/null +++ b/src/test/java/org/junit/internal/runners/ErrorReportingRunnerTest.java @@ -0,0 +1,88 @@ +package org.junit.internal.runners; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.InvalidTestClassError; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ErrorReportingRunnerTest { + + @Test(expected = NullPointerException.class) + public void cannotCreateWithNullClass() { + new ErrorReportingRunner(null, new RuntimeException()); + } + + @Test(expected = NullPointerException.class) + public void cannotCreateWithNullClass2() { + new ErrorReportingRunner(new RuntimeException(), (Class) null); + } + + @Test(expected = NullPointerException.class) + public void cannotCreateWithNullClasses() { + new ErrorReportingRunner(new RuntimeException(), (Class[]) null); + } + + @Test(expected = NullPointerException.class) + public void cannotCreateWithoutClass() { + new ErrorReportingRunner(new RuntimeException()); + } + + @Test + public void givenInvalidTestClassErrorAsCause() { + final List firedFailures = new ArrayList(); + InvalidTestClassError testClassError = new InvalidTestClassError(TestClassWithErrors.class, + Arrays.asList(new Throwable("validation error 1"), new Throwable("validation error 2"))); + ErrorReportingRunner sut = new ErrorReportingRunner(TestClassWithErrors.class, testClassError); + + sut.run(new RunNotifier() { + @Override + public void fireTestFailure(Failure failure) { + super.fireTestFailure(failure); + firedFailures.add(failure); + } + }); + + assertThat(firedFailures.size(), is(1)); + Throwable exception = firedFailures.get(0).getException(); + assertThat(exception, instanceOf(InvalidTestClassError.class)); + assertThat(((InvalidTestClassError) exception), is(testClassError)); + } + + @Test + public void givenInvalidTestClass_integrationTest() { + Result result = JUnitCore.runClasses(TestClassWithErrors.class); + + assertThat(result.getFailureCount(), is(1)); + Throwable failure = result.getFailures().get(0).getException(); + assertThat(failure, instanceOf(InvalidTestClassError.class)); + assertThat(failure.getMessage(), allOf( + startsWith("Invalid test class '" + TestClassWithErrors.class.getName() + "'"), + containsString("\n 1. "), + containsString("\n 2. ") + )); + } + + private static class TestClassWithErrors { + @Before public static void staticBeforeMethod() {} + @After public static void staticAfterMethod() {} + + @Test public String testMethodReturningString() { + return "this should not be allowed"; + } + } +} diff --git a/src/test/java/org/junit/internal/runners/statements/ExpectExceptionTest.java b/src/test/java/org/junit/internal/runners/statements/ExpectExceptionTest.java new file mode 100644 index 000000000000..466e28917a68 --- /dev/null +++ b/src/test/java/org/junit/internal/runners/statements/ExpectExceptionTest.java @@ -0,0 +1,88 @@ +package org.junit.internal.runners.statements; + +import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; +import org.junit.runners.model.Statement; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + +/** + * Integration tests can be found in {@link org.junit.tests.running.methods.ExpectedTest}. + * See e.g. {@link org.junit.tests.running.methods.ExpectedTest#expectsAssumptionViolatedException()} + */ +public class ExpectExceptionTest { + + @Test + public void whenExpectingAssumptionViolatedExceptionStatementsThrowingItShouldPass() { + Statement delegate = new Fail(new AssumptionViolatedException("expected")); + ExpectException expectException = new ExpectException(delegate, AssumptionViolatedException.class); + + try { + expectException.evaluate(); + // then AssumptionViolatedException should not be thrown + } catch (Throwable e) { // need to explicitly catch and re-throw as an AssertionError or it might be skipped + fail("should not throw anything, but was thrown: " + e); + } + } + + @Test + public void whenExpectingAssumptionViolatedExceptionStatementsThrowingSubclassShouldPass() { + Statement delegate = new Fail(new AssumptionViolatedExceptionSubclass("expected")); + ExpectException expectException = new ExpectException(delegate, AssumptionViolatedException.class); + + try { + expectException.evaluate(); + // then no exception should be thrown + } catch (Throwable e) { + fail("should not throw anything, but was thrown: " + e); + } + } + + @Test + public void whenExpectingAssumptionViolatedExceptionStatementsThrowingDifferentExceptionShouldFail() { + Statement delegate = new Fail(new SomeException("not expected")); + ExpectException expectException = new ExpectException(delegate, AssumptionViolatedException.class); + + try { + expectException.evaluate(); + fail("should throw 'Unexpected exception' when statement throws an exception which is not the one expected"); + } catch (Exception e) { + assertThat(e.getMessage(), equalTo("Unexpected exception, expected " + + "but was")); + } + } + + @Test + public void whenExpectingAssumptionViolatedExceptionStatementsPassingShouldFail() throws Exception { + ExpectException expectException = new ExpectException(new PassingStatement(), AssumptionViolatedException.class); + + try { + expectException.evaluate(); + } catch (AssertionError e) { + assertThat(e.getMessage(), containsString("Expected exception: " + AssumptionViolatedException.class.getName())); + return; + } + fail("ExpectException should throw when the given statement passes"); + } + + private static class PassingStatement extends Statement { + public void evaluate() throws Throwable { + // nop + } + } + + private static class SomeException extends RuntimeException { + public SomeException(String message) { + super(message); + } + } + + private static class AssumptionViolatedExceptionSubclass extends AssumptionViolatedException { + public AssumptionViolatedExceptionSubclass(String assumption) { + super(assumption); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java b/src/test/java/org/junit/internal/runners/statements/FailOnTimeoutTest.java similarity index 53% rename from src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java rename to src/test/java/org/junit/internal/runners/statements/FailOnTimeoutTest.java index 5320a3b1662a..00c3f0b98276 100644 --- a/src/test/java/org/junit/tests/internal/runners/statements/FailOnTimeoutTest.java +++ b/src/test/java/org/junit/internal/runners/statements/FailOnTimeoutTest.java @@ -1,22 +1,27 @@ -package org.junit.tests.internal.runners.statements; +package org.junit.internal.runners.statements; import static java.lang.Long.MAX_VALUE; import static java.lang.Math.atan; import static java.lang.System.currentTimeMillis; +import static java.lang.Thread.currentThread; import static java.lang.Thread.sleep; -import static org.hamcrest.core.Is.is; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.internal.runners.statements.FailOnTimeout.builder; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.TimeUnit; -import org.junit.Ignore; -import org.junit.Rule; import org.junit.Test; -import org.junit.internal.runners.statements.FailOnTimeout; -import org.junit.rules.ExpectedException; +import org.junit.function.ThrowingRunnable; import org.junit.runners.model.Statement; import org.junit.runners.model.TestTimedOutException; @@ -24,81 +29,90 @@ * @author Asaf Ary, Stefan Birkner */ public class FailOnTimeoutTest { - private static final int TIMEOUT = 100; - private static final int DURATION_THAT_EXCEEDS_TIMEOUT = 60 * 60 * 1000; //1 hour - - @Rule - public final ExpectedException thrown = ExpectedException.none(); + private static final long TIMEOUT = 100; + private static final long DURATION_THAT_EXCEEDS_TIMEOUT = 60 * 60 * 1000; //1 hour private final TestStatement statement = new TestStatement(); - private final FailOnTimeout failOnTimeout = new FailOnTimeout(statement, - TIMEOUT); + private final FailOnTimeout failOnTimeout = builder().withTimeout(TIMEOUT, MILLISECONDS).build(statement); @Test - public void throwsTestTimedOutException() throws Throwable { - thrown.expect(TestTimedOutException.class); - evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT); + public void throwsTestTimedOutException() { + assertThrows( + TestTimedOutException.class, + evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT)); } @Test - public void throwExceptionWithNiceMessageOnTimeout() throws Throwable { - thrown.expectMessage("test timed out after 100 milliseconds"); - evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT); + public void throwExceptionWithNiceMessageOnTimeout() { + TestTimedOutException e = assertThrows( + TestTimedOutException.class, + evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT)); + assertEquals("test timed out after 100 milliseconds", e.getMessage()); } @Test - public void sendUpExceptionThrownByStatement() throws Throwable { + public void sendUpExceptionThrownByStatement() { RuntimeException exception = new RuntimeException(); - thrown.expect(is(exception)); - evaluateWithException(exception); + RuntimeException e = assertThrows( + RuntimeException.class, + evaluateWithException(exception)); + assertSame(exception, e); } @Test public void throwExceptionIfTheSecondCallToEvaluateNeedsTooMuchTime() throws Throwable { - thrown.expect(TestTimedOutException.class); - evaluateWithWaitDuration(0); - evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT); + evaluateWithWaitDuration(0).run(); + assertThrows( + TestTimedOutException.class, + evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT)); } @Test - public void throwTimeoutExceptionOnSecondCallAlthoughFirstCallThrowsException() - throws Throwable { - thrown.expectMessage("test timed out after 100 milliseconds"); + public void throwTimeoutExceptionOnSecondCallAlthoughFirstCallThrowsException() { try { - evaluateWithException(new RuntimeException()); + evaluateWithException(new RuntimeException()).run(); } catch (Throwable expected) { } - evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT); + + TestTimedOutException e = assertThrows( + TestTimedOutException.class, + evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT)); + assertEquals("test timed out after 100 milliseconds", e.getMessage()); } @Test - public void throwsExceptionWithTimeoutValueAndTimeUnitSet() - throws Throwable { - try { - evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT); - fail("No exception was thrown when test timed out"); - } catch (TestTimedOutException e) { - assertEquals(TIMEOUT, e.getTimeout()); - assertEquals(TimeUnit.MILLISECONDS, e.getTimeUnit()); - } + public void throwsExceptionWithTimeoutValueAndTimeUnitSet() { + TestTimedOutException e = assertThrows( + TestTimedOutException.class, + evaluateWithWaitDuration(DURATION_THAT_EXCEEDS_TIMEOUT)); + assertEquals(TIMEOUT, e.getTimeout()); + assertEquals(TimeUnit.MILLISECONDS, e.getTimeUnit()); } - private void evaluateWithException(Exception exception) throws Throwable { - statement.nextException = exception; - statement.waitDuration = 0; - failOnTimeout.evaluate(); + private ThrowingRunnable evaluateWithException(final Exception exception) { + return new ThrowingRunnable() { + public void run() 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 ThrowingRunnable evaluateWithWaitDuration(final long waitDuration) { + return new ThrowingRunnable() { + public void run() throws Throwable { + statement.nextException = null; + statement.waitDuration = waitDuration; + failOnTimeout.evaluate(); + } + }; } private static final class TestStatement extends Statement { - int waitDuration; + long waitDuration; Exception nextException; @@ -114,8 +128,7 @@ public void evaluate() throws Throwable { @Test public void stopEndlessStatement() throws Throwable { InfiniteLoopStatement infiniteLoop = new InfiniteLoopStatement(); - FailOnTimeout infiniteLoopTimeout = new FailOnTimeout(infiniteLoop, - TIMEOUT); + FailOnTimeout infiniteLoopTimeout = builder().withTimeout(TIMEOUT, MILLISECONDS).build(infiniteLoop); try { infiniteLoopTimeout.evaluate(); } catch (Exception timeoutException) { @@ -142,7 +155,7 @@ public void evaluate() throws Throwable { @Test public void stackTraceContainsRealCauseOfTimeout() throws Throwable { StuckStatement stuck = new StuckStatement(); - FailOnTimeout stuckTimeout = new FailOnTimeout(stuck, TIMEOUT); + FailOnTimeout stuckTimeout = builder().withTimeout(TIMEOUT, MILLISECONDS).build(stuck); try { stuckTimeout.evaluate(); // We must not get here, we expect a timeout exception @@ -194,4 +207,23 @@ private void notTheRealCauseOfTheTimeout() { } } } + + @Test + public void threadGroupNotLeaked() throws Throwable { + Collection groupsBeforeSet = subGroupsOfCurrentThread(); + + evaluateWithWaitDuration(0); + + for (ThreadGroup group: subGroupsOfCurrentThread()) { + if (!groupsBeforeSet.contains(group) && "FailOnTimeoutGroup".equals(group.getName())) { + fail("A 'FailOnTimeoutGroup' thread group remains referenced after the test execution."); + } + } + } + + private Collection subGroupsOfCurrentThread() { + ThreadGroup[] subGroups = new ThreadGroup[256]; + int numGroups = currentThread().getThreadGroup().enumerate(subGroups); + return Arrays.asList(subGroups).subList(0, numGroups); + } } diff --git a/src/test/java/org/junit/rules/AllRulesTests.java b/src/test/java/org/junit/rules/AllRulesTests.java new file mode 100644 index 000000000000..8b63e1510db3 --- /dev/null +++ b/src/test/java/org/junit/rules/AllRulesTests.java @@ -0,0 +1,31 @@ +package org.junit.rules; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + BlockJUnit4ClassRunnerOverrideTest.class, + ClassRulesTest.class, + DisableOnDebugTest.class, + ErrorCollectorTest.class, + ExpectedExceptionTest.class, + ExternalResourceRuleTest.class, + MethodRulesTest.class, + NameRulesTest.class, + RuleChainTest.class, + RuleMemberValidatorTest.class, + StopwatchTest.class, + TempFolderRuleTest.class, + TemporaryFolderRuleAssuredDeletionTest.class, + TemporaryFolderUsageTest.class, + TestRuleTest.class, + TestWatcherTest.class, + TestWatchmanTest.class, + TestWatchmanTest.class, + TimeoutRuleTest.class, + VerifierRuleTest.class +}) +public class AllRulesTests { +} diff --git a/src/test/java/org/junit/rules/BlockJUnit4ClassRunnerOverrideTest.java b/src/test/java/org/junit/rules/BlockJUnit4ClassRunnerOverrideTest.java new file mode 100644 index 000000000000..4f85be096fda --- /dev/null +++ b/src/test/java/org/junit/rules/BlockJUnit4ClassRunnerOverrideTest.java @@ -0,0 +1,175 @@ +package org.junit.rules; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.experimental.results.PrintableResult.testResult; +import static org.junit.experimental.results.ResultMatchers.isSuccessful; + +import java.util.LinkedList; +import java.util.List; + +import org.junit.Test; +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; + +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 rules(Object test) { + final LinkedList methodRules = new LinkedList( + 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 getTestRules(final Object test) { + final LinkedList methodRules = new LinkedList( + 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()); + } + + + /** + * Runner for testing override of {@link org.junit.runners.BlockJUnit4ClassRunner#createTest(org.junit.runners.model.FrameworkMethod)} + * by setting the {@link org.junit.runners.model.FrameworkMethod} in a field + * of the test class so it can be compared with the test method that is being + * executed. + */ + public static class OverrideCreateTestRunner extends BlockJUnit4ClassRunner { + public OverrideCreateTestRunner(final Class klass) throws InitializationError { + super(klass); + + assert(klass.equals(OverrideCreateTest.class)); + } + + @Override + protected Object createTest(FrameworkMethod method) { + final OverrideCreateTest obj = new OverrideCreateTest(); + + obj.method = method; + + return obj; + } + } + + @RunWith(OverrideCreateTestRunner.class) + public static class OverrideCreateTest { + public FrameworkMethod method; + + @Test + public void testMethodA() { + assertEquals("testMethodA", method.getMethod().getName()); + } + + @Test + public void testMethodB() { + assertEquals("testMethodB", method.getMethod().getName()); + } + } + + @Test + public void overrideCreateTestMethod() { + assertThat(testResult(OverrideCreateTest.class), isSuccessful()); + } + + + /** + * Runner for testing override of {@link org.junit.runners.BlockJUnit4ClassRunner#createTest()} + * is still called by default if no other {@code createTest} method override + * is in place. This is tested by setting a boolean flag in a field of the + * test class so it can be checked to confirm that the createTest method was + * called. + */ + public static class CreateTestDefersToNoArgCreateTestRunner extends BlockJUnit4ClassRunner { + public CreateTestDefersToNoArgCreateTestRunner(final Class klass) throws InitializationError { + super(klass); + + assert(klass.equals(CreateTestDefersToNoArgCreateTestTest.class)); + } + + @Override + protected Object createTest() { + final CreateTestDefersToNoArgCreateTestTest obj = new CreateTestDefersToNoArgCreateTestTest(); + + obj.createTestCalled = true; + + return obj; + } + } + + @RunWith(CreateTestDefersToNoArgCreateTestRunner.class) + public static class CreateTestDefersToNoArgCreateTestTest { + public boolean createTestCalled = false; + + @Test + public void testCreateTestCalled() { + assertEquals(true, createTestCalled); + } + } + + @Test + public void createTestDefersToNoArgCreateTest() { + assertThat(testResult(CreateTestDefersToNoArgCreateTestTest.class), isSuccessful()); + } +} diff --git a/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java b/src/test/java/org/junit/rules/ClassRulesTest.java similarity index 65% rename from src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java rename to src/test/java/org/junit/rules/ClassRulesTest.java index 9e0153d555bb..ddfb74494c97 100644 --- a/src/test/java/org/junit/tests/experimental/rules/ClassRulesTest.java +++ b/src/test/java/org/junit/rules/ClassRulesTest.java @@ -1,10 +1,10 @@ -/** +/* * Created Oct 19, 2009 */ -package org.junit.tests.experimental.rules; +package org.junit.rules; +import static org.hamcrest.MatcherAssert.assertThat; 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.isSuccessful; @@ -13,12 +13,15 @@ import java.util.List; import org.junit.ClassRule; +import org.junit.FixMethodOrder; import org.junit.Test; -import org.junit.rules.ExternalResource; -import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runner.JUnitCore; import org.junit.runner.Result; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.MethodSorters; +import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; /** @@ -126,8 +129,6 @@ public void evaluate() throws Throwable { } } - ; - public static class UsesFieldAndMethodRule { @ClassRule public static OrderTestRule orderMethod() { @@ -227,8 +228,6 @@ public Statement apply(final Statement base, Description description) { public void evaluate() throws Throwable { base.evaluate(); } - - ; }; } } @@ -250,4 +249,118 @@ public void testCallMethodOnlyOnceRule() { CallMethodOnlyOnceRule.countOfMethodCalls = 0; assertTrue(JUnitCore.runClasses(CallMethodOnlyOnceRule.class).wasSuccessful()); } + + private static final StringBuilder log = new StringBuilder(); + + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public static class ClassRuleOrdering { + @ClassRule(order = 1) + public static TestRule a() { + return new LoggingTestRule(log, "outer"); + } + + @ClassRule(order = 2) + public static TestRule z() { + return new LoggingTestRule(log, "inner"); + } + + @Test + public void foo() { + log.append(" foo"); + } + + @Test + public void bar() { + log.append(" bar"); + } + } + + @Test + public void classRuleOrdering() { + log.setLength(0); + Result result = JUnitCore.runClasses(ClassRuleOrdering.class); + assertTrue(result.wasSuccessful()); + assertEquals(" outer.begin inner.begin bar foo inner.end outer.end", log.toString()); + } + + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public static class ClassRuleOrderingDefault { + @ClassRule + public static TestRule a() { + return new LoggingTestRule(log, "outer"); + } + + @ClassRule + public static TestRule b() { + return new LoggingTestRule(log, "inner"); + } + + @Test + public void foo() { + log.append(" foo"); + } + + @Test + public void bar() { + log.append(" bar"); + } + } + + @Test + public void classRuleOrderingDefault() { + log.setLength(0); + Result result = JUnitCore.runClasses(ClassRuleOrderingDefault.class); + assertTrue(result.wasSuccessful()); + assertEquals(" inner.begin outer.begin bar foo outer.end inner.end", log.toString()); + } + + public static class RunnerWithClassRuleAddedProgrammatically extends BlockJUnit4ClassRunner { + public RunnerWithClassRuleAddedProgrammatically(Class testClass) throws InitializationError { + super(testClass); + } + + @Override + protected List classRules() { + final List rules = super.classRules(); + rules.add(new LoggingTestRule(log, "fromCode")); + return rules; + } + } + + @RunWith(RunnerWithClassRuleAddedProgrammatically.class) + public static class ClassRulesModifiableListEmpty { + @Test + public void test() { + log.append(" test"); + } + } + + @Test + public void classRulesModifiableListEmpty() { + log.setLength(0); + Result result = JUnitCore.runClasses(ClassRulesModifiableListEmpty.class); + assertTrue(result.wasSuccessful()); + assertEquals(" fromCode.begin test fromCode.end", log.toString()); + } + + @RunWith(RunnerWithClassRuleAddedProgrammatically.class) + public static class ClassRulesModifiableList { + @ClassRule + public static TestRule classRule() { + return new LoggingTestRule(log, "classRule"); + } + + @Test + public void test() { + log.append(" test"); + } + } + + @Test + public void classRulesModifiableList() { + log.setLength(0); + Result result = JUnitCore.runClasses(ClassRulesModifiableList.class); + assertTrue(result.wasSuccessful()); + assertEquals(" fromCode.begin classRule.begin test classRule.end fromCode.end", log.toString()); + } } diff --git a/src/test/java/org/junit/rules/ErrorCollectorTest.java b/src/test/java/org/junit/rules/ErrorCollectorTest.java new file mode 100644 index 000000000000..385a1462ac70 --- /dev/null +++ b/src/test/java/org/junit/rules/ErrorCollectorTest.java @@ -0,0 +1,327 @@ +package org.junit.rules; + +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; +import org.junit.Rule; +import org.junit.Test; +import org.junit.function.ThrowingRunnable; +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.JUnitCore; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import java.util.concurrent.Callable; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; +import static org.junit.rules.EventCollector.*; + +@RunWith(Parameterized.class) +public class ErrorCollectorTest { + + @Parameters(name= "{0}") + public static Object[][] testsWithEventMatcher() { + return new Object[][]{ + { + AddSingleError.class, + hasSingleFailureWithMessage("message")}, + { + AddTwoErrors.class, + hasNumberOfFailures(2)}, + { + AddInternalAssumptionViolatedException.class, + allOf(hasSingleFailure(), hasNoAssumptionFailure())}, + { + CheckMatcherThatDoesNotFailWithoutProvidedReason.class, + everyTestRunSuccessful()}, + { + CheckMatcherThatDoesNotFailWithProvidedReason.class, + everyTestRunSuccessful()}, + { + CheckMatcherThatFailsWithoutProvidedReason.class, + hasSingleFailureWithMessage(Matchers.allOf( + containsString("Expected: is <4>"), + containsString("but: was <3>")))}, + { + CheckMatcherThatFailsWithProvidedReason.class, + hasSingleFailureWithMessage(Matchers.allOf( + containsString("reason"), + containsString("Expected: is <4>"), + containsString("but: was <3>")))}, + { + CheckTwoMatchersThatFail.class, + hasNumberOfFailures(2)}, + { + CheckCallableThatThrowsAnException.class, + hasSingleFailureWithMessage("first!")}, + { + CheckTwoCallablesThatThrowExceptions.class, + hasNumberOfFailures(2)}, + { + CheckCallableThatThrowsInternalAssumptionViolatedException.class, + allOf(hasSingleFailure(), hasNoAssumptionFailure())}, + { + CheckCallableWithFailingAssumption.class, + allOf(hasSingleFailure(), hasNoAssumptionFailure())}, + { + CheckCallableThatDoesNotThrowAnException.class, + everyTestRunSuccessful()}, + { + CheckRunnableThatThrowsExpectedTypeOfException.class, + everyTestRunSuccessful()}, + { + CheckRunnableThatThrowsUnexpectedTypeOfException.class, + hasSingleFailureWithMessage("unexpected exception type thrown; expected: but was:")}, + { + CheckRunnableThatThrowsNoExceptionAlthoughOneIsExpected.class, + hasSingleFailureWithMessage("expected java.lang.IllegalArgumentException to be thrown, but nothing was thrown")}, + { + ErrorCollectorNotCalledBySuccessfulTest.class, + everyTestRunSuccessful()}, + { + ErrorCollectorNotCalledByFailingTest.class, + hasSingleFailure()}, + }; + } + + @Parameter(0) + public Class classUnderTest; + + @Parameter(1) + public Matcher matcher; + + @Test + public void runTestClassAndVerifyEvents() { + EventCollector collector = new EventCollector(); + JUnitCore core = new JUnitCore(); + core.addListener(collector); + core.run(classUnderTest); + assertThat(collector, matcher); + } + + public static class AddSingleError { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.addError(new Throwable("message")); + } + } + + public static class AddTwoErrors { + @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")); + } + } + + public static class AddInternalAssumptionViolatedException { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.addError(new AssumptionViolatedException("message")); + } + } + + public static class CheckMatcherThatDoesNotFailWithProvidedReason { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkThat("dummy reason", 3, is(3)); + } + } + + public static class CheckMatcherThatDoesNotFailWithoutProvidedReason { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkThat(3, is(3)); + } + } + + public static class CheckMatcherThatFailsWithoutProvidedReason { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkThat(3, is(4)); + } + } + + public static class CheckMatcherThatFailsWithProvidedReason { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkThat("reason", 3, is(4)); + } + } + + public static class CheckTwoMatchersThatFail { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkThat(3, is(4)); + collector.checkThat("reason", 7, is(8)); + } + } + + public static class CheckCallableThatThrowsAnException { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkSucceeds(new Callable() { + public Object call() throws Exception { + throw new RuntimeException("first!"); + } + }); + } + } + + public static class CheckTwoCallablesThatThrowExceptions { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkSucceeds(new Callable() { + public Object call() throws Exception { + throw new RuntimeException("first!"); + } + }); + collector.checkSucceeds(new Callable() { + public Integer call() throws Exception { + throw new RuntimeException("second!"); + } + }); + } + } + + public static class CheckCallableThatThrowsInternalAssumptionViolatedException { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkSucceeds(new Callable() { + public Object call() throws Exception { + throw new AssumptionViolatedException("message"); + } + }); + } + } + + public static class CheckCallableWithFailingAssumption { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkSucceeds(new Callable() { + public Object call() throws Exception { + assumeTrue(false); + return null; + } + }); + } + } + + public static class CheckCallableThatDoesNotThrowAnException { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + Object result = collector.checkSucceeds(new Callable() { + public Object call() throws Exception { + return 3; + } + }); + assertEquals(3, result); + } + } + + public static class CheckRunnableThatThrowsExpectedTypeOfException { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkThrows(IllegalArgumentException.class, new ThrowingRunnable() { + public void run() throws Throwable { + throw new IllegalArgumentException(); + } + }); + } + } + + public static class CheckRunnableThatThrowsUnexpectedTypeOfException { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkThrows(IllegalArgumentException.class, new ThrowingRunnable() { + public void run() throws Throwable { + throw new NullPointerException(); + } + }); + } + } + + public static class CheckRunnableThatThrowsNoExceptionAlthoughOneIsExpected { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + collector.checkThrows(IllegalArgumentException.class, new ThrowingRunnable() { + public void run() throws Throwable { + } + }); + } + } + + public static class ErrorCollectorNotCalledBySuccessfulTest { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + } + } + + public static class ErrorCollectorNotCalledByFailingTest { + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Test + public void example() { + fail(); + } + } +} diff --git a/src/test/java/org/junit/tests/experimental/rules/EventCollector.java b/src/test/java/org/junit/rules/EventCollector.java similarity index 96% rename from src/test/java/org/junit/tests/experimental/rules/EventCollector.java rename to src/test/java/org/junit/rules/EventCollector.java index de6f49a3b28e..32c872ee8109 100644 --- a/src/test/java/org/junit/tests/experimental/rules/EventCollector.java +++ b/src/test/java/org/junit/rules/EventCollector.java @@ -1,4 +1,4 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.core.IsEqual.equalTo; @@ -13,12 +13,12 @@ import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunListener; -class EventCollector extends RunListener { +public class EventCollector extends RunListener { static Matcher everyTestRunSuccessful() { return allOf(hasNoFailure(), hasNoAssumptionFailure()); } - private static Matcher hasNumberOfFailures( + static Matcher hasNumberOfFailures( final int numberOfFailures) { return new TypeSafeMatcher() { @Override @@ -73,7 +73,7 @@ static Matcher hasNoAssumptionFailure() { return hasNumberOfAssumptionFailures(0); } - static Matcher hasSingleFailureWithMessage(String message) { + public static Matcher hasSingleFailureWithMessage(String message) { return hasSingleFailureWithMessage(equalTo(message)); } diff --git a/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java b/src/test/java/org/junit/rules/ExpectedExceptionTest.java similarity index 91% rename from src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java rename to src/test/java/org/junit/rules/ExpectedExceptionTest.java index 94024c62a6df..f9bf3f531ac9 100644 --- a/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java +++ b/src/test/java/org/junit/rules/ExpectedExceptionTest.java @@ -1,4 +1,4 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.any; @@ -6,15 +6,15 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import static org.junit.rules.ExpectedException.none; -import static org.junit.tests.experimental.rules.EventCollector.everyTestRunSuccessful; -import static org.junit.tests.experimental.rules.EventCollector.hasSingleAssumptionFailure; -import static org.junit.tests.experimental.rules.EventCollector.hasSingleFailure; -import static org.junit.tests.experimental.rules.EventCollector.hasSingleFailureWithMessage; +import static org.junit.rules.EventCollector.everyTestRunSuccessful; +import static org.junit.rules.EventCollector.hasSingleAssumptionFailure; +import static org.junit.rules.EventCollector.hasSingleFailure; +import static org.junit.rules.EventCollector.hasSingleFailureWithMessage; import java.util.Collection; @@ -22,7 +22,6 @@ import org.hamcrest.Matcher; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.JUnitCore; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -87,7 +86,10 @@ public static Collection testsWithEventMatcher() { { UseCustomMessageWithPlaceHolder.class, hasSingleFailureWithMessage(ARBITRARY_MESSAGE - + " - an instance of java.lang.IllegalArgumentException") } + + " - an instance of java.lang.IllegalArgumentException") }, + { + ErrorCollectorShouldFailAlthoughExpectedExceptionDoesNot.class, + hasSingleFailureWithMessage(ARBITRARY_MESSAGE) } }); } @@ -252,7 +254,7 @@ public void throwsMore() { } } - //https://github.com/junit-team/junit/pull/583 + //https://github.com/junit-team/junit4/pull/583 public static class ExpectAssertionErrorWhichIsNotThrown { @Rule public ExpectedException thrown = none(); @@ -365,4 +367,20 @@ public void noThrow() { thrown.reportMissingExceptionWithMessage(ARBITRARY_MESSAGE); } } + + public static class ErrorCollectorShouldFailAlthoughExpectedExceptionDoesNot { + + @Rule + public ErrorCollector collector = new ErrorCollector(); + + @Rule(order = Integer.MAX_VALUE) + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void test() { + collector.addError(new AssertionError(ARBITRARY_MESSAGE)); + thrown.expect(Exception.class); + throw new RuntimeException(); + } + } } \ No newline at end of file diff --git a/src/test/java/org/junit/rules/ExternalResourceRuleTest.java b/src/test/java/org/junit/rules/ExternalResourceRuleTest.java new file mode 100644 index 000000000000..ba4302e85780 --- /dev/null +++ b/src/test/java/org/junit/rules/ExternalResourceRuleTest.java @@ -0,0 +1,168 @@ +package org.junit.rules; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.junit.experimental.results.PrintableResult.testResult; +import static org.junit.experimental.results.ResultMatchers.isSuccessful; +import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matcher; +import org.junit.Rule; +import org.junit.Test; +import org.junit.TestCouldNotBeSkippedException; +import org.junit.internal.AssumptionViolatedException; +import org.junit.internal.runners.statements.Fail; +import org.junit.runner.Description; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runners.model.MultipleFailureException; +import org.junit.runners.model.Statement; + +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); + } + + @Test + public void shouldThrowMultipleFailureExceptionWhenTestFailsAndClosingResourceFails() throws Throwable { + // given + ExternalResource resourceRule = new ExternalResource() { + @Override + protected void after() { + throw new RuntimeException("simulating resource tear down failure"); + } + }; + Statement failingTest = new Fail(new RuntimeException("simulated test failure")); + Description dummyDescription = Description.createTestDescription( + "dummy test class name", "dummy test name"); + + try { + resourceRule.apply(failingTest, dummyDescription).evaluate(); + fail("ExternalResource should throw"); + } catch (MultipleFailureException e) { + assertThat(e.getMessage(), allOf( + containsString("simulated test failure"), + containsString("simulating resource tear down failure") + )); + } + } + + public static class TestFailsAndTwoClosingResourcesFail { + @Rule + public ExternalResource resourceRule1 = new ExternalResource() { + @Override + protected void after() { + throw new RuntimeException("simulating resource1 tear down failure"); + } + }; + + @Rule + public ExternalResource resourceRule2 = new ExternalResource() { + @Override + protected void after() { + throw new RuntimeException("simulating resource2 tear down failure"); + } + }; + + @Test + public void failingTest() { + throw new RuntimeException("simulated test failure"); + } + } + + @Test + public void shouldThrowMultipleFailureExceptionWhenTestFailsAndTwoClosingResourcesFail() { + Result result = JUnitCore.runClasses(TestFailsAndTwoClosingResourcesFail.class); + assertEquals(3, result.getFailures().size()); + List messages = new ArrayList(); + for (Failure failure : result.getFailures()) { + messages.add(failure.getMessage()); + } + assertThat(messages, CoreMatchers.hasItems( + "simulated test failure", + "simulating resource1 tear down failure", + "simulating resource2 tear down failure" + )); + } + + @Test + public void shouldWrapAssumptionFailuresWhenClosingResourceFails() throws Throwable { + // given + final AtomicReference externalResourceException = new AtomicReference(); + ExternalResource resourceRule = new ExternalResource() { + @Override + protected void after() { + RuntimeException runtimeException = new RuntimeException("simulating resource tear down failure"); + externalResourceException.set(runtimeException); + throw runtimeException; + } + }; + final AtomicReference assumptionViolatedException = new AtomicReference(); + Statement skippedTest = new Statement() { + @Override + public void evaluate() throws Throwable { + AssumptionViolatedException assumptionFailure = new AssumptionViolatedException("skip it"); + assumptionViolatedException.set(assumptionFailure); + throw assumptionFailure; + } + }; + Description dummyDescription = Description.createTestDescription( + "dummy test class name", "dummy test name"); + + try { + resourceRule.apply(skippedTest, dummyDescription).evaluate(); + fail("ExternalResource should throw"); + } catch (MultipleFailureException e) { + assertThat(e.getFailures(), hasItems( + instanceOf(TestCouldNotBeSkippedException.class), + sameInstance(externalResourceException.get()) + )); + assertThat(e.getFailures(), hasItems( + hasCause(sameInstance(assumptionViolatedException.get())), + sameInstance(externalResourceException.get()) + )); + } + } + + @SuppressWarnings("unchecked") + private Matcher> hasItems( + Matcher one, Matcher two) { + return CoreMatchers.hasItems(one, two); + } +} diff --git a/src/test/java/org/junit/rules/LoggingMethodRule.java b/src/test/java/org/junit/rules/LoggingMethodRule.java new file mode 100644 index 000000000000..9df2d2378612 --- /dev/null +++ b/src/test/java/org/junit/rules/LoggingMethodRule.java @@ -0,0 +1,18 @@ +package org.junit.rules; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +class LoggingMethodRule implements MethodRule { + private final StringBuilder log; + private final String name; + + LoggingMethodRule(StringBuilder log, String name) { + this.name = name; + this.log = log; + } + + public Statement apply(Statement base, FrameworkMethod method, Object target) { + return new LoggingStatement(base, log, name); + } +} diff --git a/src/test/java/org/junit/rules/LoggingStatement.java b/src/test/java/org/junit/rules/LoggingStatement.java new file mode 100644 index 000000000000..af36239b5214 --- /dev/null +++ b/src/test/java/org/junit/rules/LoggingStatement.java @@ -0,0 +1,24 @@ +package org.junit.rules; + +import org.junit.runners.model.Statement; + +class LoggingStatement extends Statement { + private final Statement base; + private final StringBuilder log; + private final String name; + + LoggingStatement(Statement base, StringBuilder log, String name) { + this.base = base; + this.log = log; + this.name = name; + } + + public void evaluate() throws Throwable { + log.append(" ").append(name).append(".begin"); + try { + base.evaluate(); + } finally { + log.append(" ").append(name).append(".end"); + } + } +} diff --git a/src/test/java/org/junit/rules/LoggingTestRule.java b/src/test/java/org/junit/rules/LoggingTestRule.java new file mode 100644 index 000000000000..08792f202978 --- /dev/null +++ b/src/test/java/org/junit/rules/LoggingTestRule.java @@ -0,0 +1,18 @@ +package org.junit.rules; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +class LoggingTestRule implements TestRule { + private final StringBuilder log; + private final String name; + + LoggingTestRule(StringBuilder log, String name) { + this.name = name; + this.log = log; + } + + public Statement apply(Statement base, Description description) { + return new LoggingStatement(base, log, name); + } +} diff --git a/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java b/src/test/java/org/junit/rules/LoggingTestWatcher.java similarity index 81% rename from src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java rename to src/test/java/org/junit/rules/LoggingTestWatcher.java index edb899f137d6..44d32a3e5a2c 100644 --- a/src/test/java/org/junit/tests/experimental/rules/LoggingTestWatcher.java +++ b/src/test/java/org/junit/rules/LoggingTestWatcher.java @@ -1,7 +1,6 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import org.junit.AssumptionViolatedException; -import org.junit.rules.TestWatcher; import org.junit.runner.Description; class LoggingTestWatcher extends TestWatcher { @@ -26,6 +25,11 @@ protected void skipped(AssumptionViolatedException e, Description description) { log.append("skipped "); } + @Override + protected void skipped(org.junit.internal.AssumptionViolatedException e, Description description) { + log.append("deprecated skipped "); + } + @Override protected void starting(Description description) { log.append("starting "); diff --git a/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java b/src/test/java/org/junit/rules/MethodRulesTest.java similarity index 79% rename from src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java rename to src/test/java/org/junit/rules/MethodRulesTest.java index c00385d0f201..93eb68468d28 100644 --- a/src/test/java/org/junit/tests/experimental/rules/MethodRulesTest.java +++ b/src/test/java/org/junit/rules/MethodRulesTest.java @@ -1,60 +1,63 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; 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.failureCountIs; import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining; import static org.junit.experimental.results.ResultMatchers.isSuccessful; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.MethodRule; -import org.junit.rules.TestName; -import org.junit.rules.TestRule; -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; + private static boolean ruleWasEvaluated; + + private static class TestMethodRule implements MethodRule { + + public Statement apply(final Statement base, FrameworkMethod method, Object target) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + ruleWasEvaluated = true; + base.evaluate(); + } + }; + } + } 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(); - } - - ; - }; - } - }; + public MethodRule example = new TestMethodRule(); @Test public void nothing() { + } + } + static abstract class NonPublicExampleTest { + @Rule + public MethodRule example = new TestMethodRule(); + + @Test + public void nothing() { } } @Test public void ruleIsIntroducedAndEvaluated() { - wasRun = false; - JUnitCore.runClasses(ExampleTest.class); - assertTrue(wasRun); + ruleWasEvaluated = false; + assertThat(testResult(ExampleTest.class), isSuccessful()); + assertTrue(ruleWasEvaluated); } public static class SonOfExampleTest extends ExampleTest { @@ -63,9 +66,20 @@ public static class SonOfExampleTest extends ExampleTest { @Test public void ruleIsIntroducedAndEvaluatedOnSubclass() { - wasRun = false; - JUnitCore.runClasses(SonOfExampleTest.class); - assertTrue(wasRun); + ruleWasEvaluated = false; + assertThat(testResult(SonOfExampleTest.class), isSuccessful()); + assertTrue(ruleWasEvaluated); + } + + public static class SonOfNonPublicExampleTest extends NonPublicExampleTest { + + } + + @Test + public void ruleIsIntroducedAndEvaluatedOnSubclassOfNonPublicClass() { + ruleWasEvaluated = false; + assertThat(testResult(SonOfNonPublicExampleTest.class), isSuccessful()); + assertTrue(ruleWasEvaluated); } private static int runCount; @@ -100,7 +114,7 @@ public void nothing() { @Test public void multipleRulesAreRun() { runCount = 0; - JUnitCore.runClasses(MultipleRuleTest.class); + assertThat(testResult(MultipleRuleTest.class), isSuccessful()); assertEquals(2, runCount); } @@ -115,8 +129,7 @@ public void nothing() { @Test public void ignoreNonRules() { - Result result = JUnitCore.runClasses(NoRulesTest.class); - assertEquals(0, result.getFailureCount()); + assertThat(testResult(NoRulesTest.class), isSuccessful()); } private static String log; @@ -139,9 +152,8 @@ public void nothing() { @Test public void onFailure() { log = ""; - Result result = JUnitCore.runClasses(OnFailureTest.class); + assertThat(testResult(OnFailureTest.class), failureCountIs(1)); assertEquals("nothing AssertionError", log); - assertEquals(1, result.getFailureCount()); } public static class WatchmanTest { @@ -174,7 +186,7 @@ public void succeeds() { @Test public void succeeded() { WatchmanTest.watchedLog = ""; - JUnitCore.runClasses(WatchmanTest.class); + assertThat(testResult(WatchmanTest.class), failureCountIs(1)); assertThat(WatchmanTest.watchedLog, containsString("fails AssertionError")); assertThat(WatchmanTest.watchedLog, containsString("succeeds success!")); } @@ -219,7 +231,7 @@ public void succeeds() { @Test public void beforesAndAfters() { BeforesAndAfters.watchedLog = ""; - JUnitCore.runClasses(BeforesAndAfters.class); + assertThat(testResult(BeforesAndAfters.class), isSuccessful()); assertThat(BeforesAndAfters.watchedLog, is("starting before test after succeeded finished ")); } @@ -299,7 +311,7 @@ public Statement apply(final Statement base, FrameworkMethod method, Object targ @Override public void evaluate() throws Throwable { - wasRun = true; + ruleWasEvaluated = true; base.evaluate(); } }; @@ -322,14 +334,14 @@ public void doNothing() { * then it should also be run. * *

      This case has been added with - * Issue #589 - + * Issue #589 - * Support @Rule for methods works only for TestRule but not for MethodRule */ @Test public void runsMethodRuleThatIsReturnedByMethod() { - wasRun = false; - JUnitCore.runClasses(HasMethodReturningMethodRule.class); - assertTrue(wasRun); + ruleWasEvaluated = false; + assertThat(testResult(HasMethodReturningMethodRule.class), isSuccessful()); + assertTrue(ruleWasEvaluated); } public static class HasMultipleMethodsReturningMethodRule { @@ -354,13 +366,13 @@ public void doNothing() { * then all the rules returned should be run. * *

      This case has been added with - * Issue #589 - + * Issue #589 - * Support @Rule for methods works only for TestRule but not for MethodRule */ @Test public void runsAllMethodRulesThatAreReturnedByMethods() { runCount = 0; - JUnitCore.runClasses(HasMultipleMethodsReturningMethodRule.class); + assertThat(testResult(HasMultipleMethodsReturningMethodRule.class), isSuccessful()); assertEquals(2, runCount); } @@ -378,7 +390,7 @@ public void evaluate() throws Throwable { } }; } - }; + } @Rule @@ -398,11 +410,11 @@ public void doNothing() { * then method should be called only once. * *

      This case has been added with - * Issue #589 - + * Issue #589 - * Support @Rule for methods works only for TestRule but not for MethodRule */ @Test public void callsMethodReturningRuleOnlyOnce() { - assertTrue(JUnitCore.runClasses(CallsMethodReturningRuleOnlyOnce.class).wasSuccessful()); + assertThat(testResult(CallsMethodReturningRuleOnlyOnce.class), isSuccessful()); } } diff --git a/src/test/java/org/junit/tests/experimental/rules/NameRulesTest.java b/src/test/java/org/junit/rules/NameRulesTest.java similarity index 93% rename from src/test/java/org/junit/tests/experimental/rules/NameRulesTest.java rename to src/test/java/org/junit/rules/NameRulesTest.java index eec6205edb65..9ae45ff217a8 100644 --- a/src/test/java/org/junit/tests/experimental/rules/NameRulesTest.java +++ b/src/test/java/org/junit/rules/NameRulesTest.java @@ -1,4 +1,4 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static org.junit.Assert.assertEquals; @@ -7,7 +7,6 @@ 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) diff --git a/src/test/java/org/junit/tests/experimental/rules/RuleChainTest.java b/src/test/java/org/junit/rules/RuleChainTest.java similarity index 53% rename from src/test/java/org/junit/tests/experimental/rules/RuleChainTest.java rename to src/test/java/org/junit/rules/RuleChainTest.java index 968ea0def779..914b6a9088c5 100644 --- a/src/test/java/org/junit/tests/experimental/rules/RuleChainTest.java +++ b/src/test/java/org/junit/rules/RuleChainTest.java @@ -1,19 +1,26 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.junit.experimental.results.PrintableResult.testResult; import static org.junit.rules.RuleChain.outerRule; +import java.io.PrintWriter; +import java.io.StringWriter; 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.internal.Throwables; import org.junit.runner.Description; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; public class RuleChainTest { private static final List LOG = new ArrayList(); @@ -57,4 +64,33 @@ public void executeRulesInCorrectOrder() throws Exception { "finished outer rule"); assertEquals(expectedLog, LOG); } + + @Test + public void aroundShouldNotAllowNullRules() { + RuleChain chain = RuleChain.emptyRuleChain(); + try { + chain.around(null); + fail("around() should not allow null rules"); + } catch (NullPointerException e) { + assertThat(e.getMessage(), equalTo("The enclosed rule must not be null")); + } + } + + public static class RuleChainWithNullRules { + @Rule + public final RuleChain chain = outerRule(new LoggingRule("outer rule")) + .around(null); + + @Test + public void example() {} + } + + @Test + public void whenRuleChainHasNullRuleTheStacktraceShouldPointToIt() { + Result result = JUnitCore.runClasses(RuleChainWithNullRules.class); + + assertThat(result.getFailures().size(), equalTo(1)); + String stacktrace = Throwables.getStacktrace(result.getFailures().get(0).getException()); + assertThat(stacktrace, containsString("\tat org.junit.rules.RuleChainTest$RuleChainWithNullRules.(RuleChainTest.java:")); + } } \ No newline at end of file diff --git a/src/test/java/org/junit/tests/experimental/rules/RuleMemberValidatorTest.java b/src/test/java/org/junit/rules/RuleMemberValidatorTest.java similarity index 92% rename from src/test/java/org/junit/tests/experimental/rules/RuleMemberValidatorTest.java rename to src/test/java/org/junit/rules/RuleMemberValidatorTest.java index c56c69bef24c..01465a661230 100644 --- a/src/test/java/org/junit/tests/experimental/rules/RuleMemberValidatorTest.java +++ b/src/test/java/org/junit/rules/RuleMemberValidatorTest.java @@ -1,4 +1,4 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static org.junit.Assert.assertEquals; import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR; @@ -12,10 +12,6 @@ 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.rules.TestWatchman; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.junit.runners.model.TestClass; @@ -77,10 +73,10 @@ static class NonPublicTestWithClassRule { * {@link TestRule} * *

      This case has been added with - * Issue #1019 + * Issue #1019 */ @Test - public void rejectClassRuleThatIsImplemetationOfMethodRule() { + public void rejectClassRuleThatIsImplementationOfMethodRule() { TestClass target = new TestClass(TestWithClassRuleIsImplementationOfMethodRule.class); CLASS_RULE_VALIDATOR.validate(target, errors); assertOneErrorWithMessage("The @ClassRule 'classRule' must implement TestRule."); @@ -101,7 +97,7 @@ public Statement apply(Statement base, FrameworkMethod method, Object target) { * implementation of {@link TestRule} * *

      This case has been added with - * Issue #1019 + * Issue #1019 */ @Test public void rejectClassRuleThatReturnsImplementationOfMethodRule() { @@ -127,7 +123,7 @@ public Statement apply(Statement base, FrameworkMethod method, Object target) { * {@link TestRule} * *

      This case has been added with - * Issue #1019 + * Issue #1019 */ @Test public void rejectClassRuleIsAnArbitraryObject() throws Exception { @@ -146,7 +142,7 @@ public static class TestWithClassRuleIsAnArbitraryObject { * implementation of {@link TestRule} * *

      This case has been added with - * Issue #1019 + * Issue #1019 */ @Test public void rejectClassRuleMethodReturnsAnArbitraryObject() throws Exception { @@ -190,13 +186,12 @@ public static class TestWithStaticTestRule { public void rejectStaticMethodRule() { TestClass target = new TestClass(TestWithStaticMethodRule.class); RULE_VALIDATOR.validate(target, errors); - assertOneErrorWithMessage("The @Rule 'testWatchman' must not be static."); + assertOneErrorWithMessage("The @Rule 'someMethodRule' must not be static."); } public static class TestWithStaticMethodRule { - @SuppressWarnings("deprecation") @Rule - public static MethodRule testWatchman = new TestWatchman(); + public static MethodRule someMethodRule = new SomeMethodRule(); } @Test @@ -303,13 +298,12 @@ public static TestRule getTemporaryFolder() { public void rejectMethodStaticMethodRule() { TestClass target = new TestClass(TestMethodWithStaticMethodRule.class); RULE_METHOD_VALIDATOR.validate(target, errors); - assertOneErrorWithMessage("The @Rule 'getTestWatchman' must not be static."); + assertOneErrorWithMessage("The @Rule 'getSomeMethodRule' must not be static."); } public static class TestMethodWithStaticMethodRule { - @SuppressWarnings("deprecation") @Rule - public static MethodRule getTestWatchman() { return new TestWatchman(); } + public static MethodRule getSomeMethodRule() { return new SomeMethodRule(); } } @Test @@ -353,4 +347,10 @@ private void assertOneErrorWithMessage(String message) { private void assertNumberOfErrors(int numberOfErrors) { assertEquals("Wrong number of errors:", numberOfErrors, errors.size()); } + + private static final class SomeMethodRule implements MethodRule { + public Statement apply(Statement base, FrameworkMethod method, Object target) { + return base; + } + } } diff --git a/src/test/java/org/junit/rules/StopwatchTest.java b/src/test/java/org/junit/rules/StopwatchTest.java index deeab3263f37..69fbcb03ec68 100644 --- a/src/test/java/org/junit/rules/StopwatchTest.java +++ b/src/test/java/org/junit/rules/StopwatchTest.java @@ -1,24 +1,23 @@ package org.junit.rules; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + import java.util.concurrent.TimeUnit; import org.junit.AssumptionViolatedException; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.Stopwatch; import org.junit.runner.Description; import org.junit.runner.JUnitCore; import org.junit.runner.Request; import org.junit.runner.Result; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assume.assumeTrue; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.junit.Assert.assertNotEquals; /** * @author tibor17 diff --git a/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java b/src/test/java/org/junit/rules/TempFolderRuleTest.java similarity index 78% rename from src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java rename to src/test/java/org/junit/rules/TempFolderRuleTest.java index 9c82b785e51b..b120e71e610e 100644 --- a/src/test/java/org/junit/tests/experimental/rules/TempFolderRuleTest.java +++ b/src/test/java/org/junit/rules/TempFolderRuleTest.java @@ -1,23 +1,30 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import static org.junit.experimental.results.PrintableResult.testResult; import static org.junit.experimental.results.ResultMatchers.failureCountIs; import static org.junit.experimental.results.ResultMatchers.isSuccessful; import java.io.File; import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import org.junit.After; +import org.junit.AssumptionViolatedException; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TemporaryFolder; public class TempFolderRuleTest { private static File[] createdFiles = new File[20]; @@ -31,6 +38,13 @@ public void testUsingTempFolder() throws IOException { createdFiles[0] = folder.newFile("myfile.txt"); assertTrue(createdFiles[0].exists()); } + + @Test + public void testTempFolderLocation() throws IOException { + File folderRoot = folder.getRoot(); + String tmpRoot = System.getProperty("java.io.tmpdir"); + assertTrue(folderRoot.toString().startsWith(tmpRoot)); + } } @Test @@ -175,6 +189,34 @@ public void recursiveDeleteFolderWithZeroElements() throws IOException { assertFalse(folder.getRoot().exists()); } + @Test + public void tempFolderIsOnlyAccessibleByOwner() throws IOException { + TemporaryFolder folder = new TemporaryFolder(); + folder.create(); + + Set expectedPermissions = new TreeSet(Arrays.asList("OWNER_READ", "OWNER_WRITE", "OWNER_EXECUTE")); + Set actualPermissions = getPosixFilePermissions(folder.getRoot()); + assertEquals(expectedPermissions, actualPermissions); + } + + private Set getPosixFilePermissions(File root) { + try { + Class pathClass = Class.forName("java.nio.file.Path"); + Object linkOptionArray = Array.newInstance(Class.forName("java.nio.file.LinkOption"), 0); + Class filesClass = Class.forName("java.nio.file.Files"); + Object path = File.class.getDeclaredMethod("toPath").invoke(root); + Method posixFilePermissionsMethod = filesClass.getDeclaredMethod("getPosixFilePermissions", pathClass, linkOptionArray.getClass()); + Set permissions = (Set) posixFilePermissionsMethod.invoke(null, path, linkOptionArray); + SortedSet convertedPermissions = new TreeSet(); + for (Object item : permissions) { + convertedPermissions.add(item.toString()); + } + return convertedPermissions; + } catch (Exception e) { + throw new AssumptionViolatedException("Test requires at least Java 1.7", e); + } + } + public static class NameClashes { @Rule public TemporaryFolder folder = new TemporaryFolder(); diff --git a/src/test/java/org/junit/rules/TemporaryFolderRuleAssuredDeletionTest.java b/src/test/java/org/junit/rules/TemporaryFolderRuleAssuredDeletionTest.java new file mode 100644 index 000000000000..48cbb44e4950 --- /dev/null +++ b/src/test/java/org/junit/rules/TemporaryFolderRuleAssuredDeletionTest.java @@ -0,0 +1,45 @@ +package org.junit.rules; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.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 org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.results.PrintableResult; + +public class TemporaryFolderRuleAssuredDeletionTest { + + public static class TestClass { + static TemporaryFolder injectedRule; + + @Rule + public TemporaryFolder folder = injectedRule; + + @Test + public void alwaysPassesButDeletesRootFolder() { + //we delete the folder in the test so that it cannot be deleted by + //the rule + folder.getRoot().delete(); + } + } + + @Test + public void testFailsWhenCreatedFolderCannotBeDeletedButDeletionIsAssured() { + TestClass.injectedRule = TemporaryFolder.builder() + .assureDeletion() + .build(); + PrintableResult result = testResult(TestClass.class); + assertThat(result, failureCountIs(1)); + assertThat(result.toString(), containsString("Unable to clean up temporary folder")); + } + + @Test + public void byDefaultTestDoesNotFailWhenCreatedFolderCannotBeDeleted() { + TestClass.injectedRule = new TemporaryFolder(); + PrintableResult result = testResult(TestClass.class); + assertThat(result, isSuccessful()); + } +} diff --git a/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java b/src/test/java/org/junit/rules/TemporaryFolderUsageTest.java similarity index 59% rename from src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java rename to src/test/java/org/junit/rules/TemporaryFolderUsageTest.java index 314a14101236..584a29603f64 100644 --- a/src/test/java/org/junit/tests/experimental/rules/TemporaryFolderUsageTest.java +++ b/src/test/java/org/junit/rules/TemporaryFolderUsageTest.java @@ -1,10 +1,11 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import java.io.File; import java.io.IOException; @@ -13,8 +14,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; /** * TemporaryFolderUsageTest provides tests for API usage correctness @@ -55,7 +54,7 @@ public void newFileWithGivenNameThrowsIllegalStateExceptionIfCreateWasNotInvoked } @Test - public void newFileWithGivenFilenameThrowsIllegalArgumentExceptionIfFileExists() throws IOException { + public void newFileWithGivenFilenameThrowsIOExceptionIfFileExists() throws IOException { tempFolder.create(); tempFolder.newFile("MyFile.txt"); @@ -76,47 +75,121 @@ public void newFolderWithGivenPathThrowsIllegalStateExceptionIfCreateWasNotInvok } @Test - public void newFolderWithGivenFolderThrowsIllegalArgumentExceptionIfFolderExists() throws IOException { + public void newFolderWithGivenFolderThrowsIOExceptionIfFolderExists() throws IOException { tempFolder.create(); tempFolder.newFolder("level1"); thrown.expect(IOException.class); - thrown.expectMessage("a folder with the name 'level1' already exists"); + thrown.expectMessage("a folder with the path 'level1' already exists"); + tempFolder.newFolder("level1"); + } + + @Test + public void newFolderWithGivenFolderThrowsIOExceptionIfFileExists() throws IOException { + tempFolder.create(); + File file = new File(tempFolder.getRoot(), "level1"); + assertTrue("Could not create" + file, file.createNewFile()); + + thrown.expect(IOException.class); + thrown.expectMessage("a file with the path 'level1' exists"); + tempFolder.newFolder("level1"); + } + + @Test + public void newFolderWithGivenFolderThrowsIOExceptionWhenFolderCannotBeCreated() throws IOException { + tempFolder.create(); + assumeTrue("Could not make folder " + tempFolder.getRoot() + " read only.", + tempFolder.getRoot().setReadOnly()); + + thrown.expect(IOException.class); + thrown.expectMessage("could not create a folder with the path 'level1'"); tempFolder.newFolder("level1"); } @Test - public void newFolderWithGivenFolderThrowsIOExceptionIfFolderNameConsistsOfMultiplePathComponents() + public void newFolderWithPathStartingWithFileSeparatorThrowsIOException() throws IOException { + String fileAtRoot; + File[] roots = File.listRoots(); + if (roots != null && roots.length > 0) { + fileAtRoot = roots[0].getAbsolutePath() + "temp1"; + } else { + fileAtRoot = File.separator + "temp1"; + } tempFolder.create(); thrown.expect(IOException.class); - thrown.expectMessage("name cannot consist of multiple path components"); + thrown.expectMessage("folder path '" + fileAtRoot + "' is not a relative path"); + tempFolder.newFolder(fileAtRoot); + } + + @Test + public void newFolderWithPathContainingFileSeparatorCreatesDirectories() + throws IOException { + tempFolder.create(); + tempFolder.newFolder("temp1" + File.separator + "temp2"); + File temp1 = new File(tempFolder.getRoot(), "temp1"); + assertFileIsDirectory(temp1); + assertFileIsDirectory(new File(temp1, "temp2")); + } + + @Test + public void newFolderWithPathContainingForwardSlashCreatesDirectories() + throws IOException { + tempFolder.create(); tempFolder.newFolder("temp1/temp2"); + File temp1 = new File(tempFolder.getRoot(), "temp1"); + assertFileIsDirectory(temp1); + assertFileIsDirectory(new File(temp1, "temp2")); } @Test - public void newFolderWithGivenPathThrowsIllegalArgumentExceptionIfPathExists() throws IOException { + public void newFolderWithGivenPathThrowsIOExceptionIfFolderExists() throws IOException { tempFolder.create(); tempFolder.newFolder("level1", "level2", "level3"); thrown.expect(IOException.class); - thrown.expectMessage("a folder with the name 'level3' already exists"); + String path = "level1" + File.separator + "level2" + File.separator + "level3"; + thrown.expectMessage("a folder with the path '" + path + "' already exists"); tempFolder.newFolder("level1", "level2", "level3"); } @Test - public void newFolderWithGivenPathThrowsIOExceptionIfFolderNamesConsistOfMultiplePathComponents() + public void newFolderWithGivenEmptyArrayThrowsIllegalArgumentException() throws IOException { + tempFolder.create(); + + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("must pass at least one path"); + tempFolder.newFolder(new String[0]); + } + + @Test + public void newFolderWithPathsContainingForwardSlashCreatesFullPath() throws IOException { tempFolder.create(); - thrown.expect(IOException.class); - thrown.expectMessage("name cannot consist of multiple path components"); tempFolder.newFolder("temp1", "temp2", "temp3/temp4"); + + File directory = new File(tempFolder.getRoot(), "temp1"); + assertFileIsDirectory(directory); + directory = new File(directory, "temp2/temp3/temp4"); + assertFileIsDirectory(directory); + } + + @Test + public void newFolderWithPathsContainingFileSeparatorCreatesFullPath() + throws IOException { + tempFolder.create(); + tempFolder.newFolder("temp1", "temp2", "temp3" + File.separator + "temp4"); + + File directory = new File(tempFolder.getRoot(), "temp1"); + assertFileIsDirectory(directory); + directory = new File(directory, "temp2/temp3/temp4"); + assertFileIsDirectory(directory); } @Test public void createInitializesRootFolder() throws IOException { tempFolder.create(); - assertFileExists(tempFolder.getRoot()); + assertFileIsDirectory(tempFolder.getRoot()); } @Test @@ -157,7 +230,7 @@ public void newRandomFolderIsCreatedUnderRootFolder() throws IOException { tempFolder.create(); File f = tempFolder.newFolder(); - assertFileExists(f); + assertFileIsDirectory(f); assertFileCreatedUnderRootFolder("Random folder", f); } @@ -166,7 +239,7 @@ public void newNestedFoldersCreatedUnderRootFolder() throws IOException { tempFolder.create(); File f = tempFolder.newFolder("top", "middle", "bottom"); - assertFileExists(f); + assertFileIsDirectory(f); assertParentFolderForFileIs(f, new File(tempFolder.getRoot(), "top/middle")); assertParentFolderForFileIs(f.getParentFile(), @@ -202,8 +275,20 @@ private void checkFileExists(String msg, File file, boolean exists) { file.exists(), is(exists)); } + private void checkFileIsDirectory(String msg, File file, boolean isDirectory) { + assertThat("File is null", file, is(notNullValue())); + assertThat("File '" + file.getAbsolutePath() + "' " + msg, + file.isDirectory(), is(isDirectory)); + } + private void assertFileExists(File file) { checkFileExists("does not exist", file, true); + checkFileIsDirectory("is a directory", file, false); + } + + private void assertFileIsDirectory(File file) { + checkFileExists("does not exist", file, true); + checkFileIsDirectory("is not a directory", file, true); } private void assertFileCreatedUnderRootFolder(String msg, File f) { diff --git a/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java b/src/test/java/org/junit/rules/TestRuleTest.java similarity index 69% rename from src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java rename to src/test/java/org/junit/rules/TestRuleTest.java index f8aafc56d896..23d4bfbc8ff4 100644 --- a/src/test/java/org/junit/tests/experimental/rules/TestRuleTest.java +++ b/src/test/java/org/junit/rules/TestRuleTest.java @@ -1,9 +1,9 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; 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; @@ -19,9 +19,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.internal.AssumptionViolatedException; -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; @@ -41,8 +38,6 @@ public void evaluate() throws Throwable { wasRun = true; base.evaluate(); } - - ; }; } }; @@ -113,8 +108,6 @@ public void evaluate() throws Throwable { runCount++; base.evaluate(); } - - ; }; } } @@ -155,64 +148,6 @@ public void ignoreNonRules() { 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(); @@ -321,8 +256,6 @@ public void evaluate() throws Throwable { wasRun = true; base.evaluate(); } - - ; }; } }; @@ -391,8 +324,6 @@ public void methodRuleIsIntroducedAndEvaluatedOnSubclass() { assertTrue(wasRun); } -// private static int runCount; - public static class MethodMultipleRuleTest { private static class Increment implements TestRule { public Statement apply(final Statement base, Description description) { @@ -402,8 +333,6 @@ public void evaluate() throws Throwable { runCount++; base.evaluate(); } - - ; }; } } @@ -450,147 +379,34 @@ public void methodIgnoreNonRules() { assertEquals(0, result.getFailureCount()); } - public static class MethodOnFailureTest { - private TestRule watchman = new TestWatcher() { - @Override - protected void failed(Throwable e, Description description) { - log += description + " " + e.getClass().getSimpleName(); - } - }; + public static class BeforesAndAftersAreEnclosedByRule { + private static StringBuilder log; @Rule - public TestRule getWatchman() { - return watchman; - } - - @Test - public void nothing() { - fail(); - } - } - - @Test - public void methodOnFailure() { - log = ""; - Result result = JUnitCore.runClasses(MethodOnFailureTest.class); - assertEquals(String.format("nothing(%s) AssertionError", MethodOnFailureTest.class.getName()), log); - assertEquals(1, result.getFailureCount()); - } - - public static class MethodOnSkippedTest { - private TestRule watchman = new TestWatcher() { - @Override - protected void skipped(AssumptionViolatedException e, Description description) { - log += description + " " + e.getClass().getSimpleName(); - } - }; - - @Rule - public TestRule getWatchman() { - return watchman; - } - - @Test - public void nothing() { - Assume.assumeTrue(false); - } - } - - @Test - public void methodOnSkipped() { - log = ""; - Result result = JUnitCore.runClasses(MethodOnSkippedTest.class); - assertEquals(String.format("nothing(%s) AssumptionViolatedException", MethodOnSkippedTest.class.getName()), log); - assertEquals(0, result.getFailureCount()); - assertEquals(1, result.getRunCount()); - } - - public static class MethodWatchmanTest { - @SuppressWarnings("unused") - private static String watchedLog; - - private TestRule watchman = 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"; - } - }; - - @Rule - public TestRule getWatchman() { - return watchman; - } - - @Test - public void fails() { - fail(); - } - - @Test - public void succeeds() { - } - } - - @Test - public void methodSucceeded() { - 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 MethodBeforesAndAfters { - private static String watchedLog; + public TestRule watcher = new LoggingTestWatcher(log); @Before public void before() { - watchedLog += "before "; - } - - private TestRule watchman = new TestWatcher() { - @Override - protected void starting(Description d) { - watchedLog += "starting "; - } - - @Override - protected void finished(Description d) { - watchedLog += "finished "; - } - - @Override - protected void succeeded(Description d) { - watchedLog += "succeeded "; - } - }; - - @Rule - public TestRule getWatchman() { - return watchman; + log.append("before "); } @After public void after() { - watchedLog += "after "; + log.append("after "); } @Test public void succeeds() { - watchedLog += "test "; + log.append("test "); } } @Test - public void methodBeforesAndAfters() { - MethodBeforesAndAfters.watchedLog = ""; - JUnitCore.runClasses(MethodBeforesAndAfters.class); - assertThat(MethodBeforesAndAfters.watchedLog, is("starting before test after succeeded finished ")); + public void beforesAndAftersAreEnclosedByRule() { + BeforesAndAftersAreEnclosedByRule.log = new StringBuilder(); + JUnitCore.runClasses(BeforesAndAftersAreEnclosedByRule.class); + assertEquals("starting before test after succeeded finished ", + BeforesAndAftersAreEnclosedByRule.log.toString()); } public static class MethodWrongTypedField { @@ -676,8 +492,6 @@ public void evaluate() throws Throwable { } } - ; - public static class UsesFieldAndMethodRule { @Rule public OrderTestRule orderMethod() { @@ -700,15 +514,6 @@ public void usesFieldAndMethodRule() { assertThat(testResult(UsesFieldAndMethodRule.class), isSuccessful()); } - public static class MultipleCallsTest implements TestRule { - public int applications = 0; - - public Statement apply(Statement base, Description description) { - applications++; - return base; - } - } - public static class CallMethodOnlyOnceRule { int countOfMethodCalls = 0; @@ -719,8 +524,6 @@ public Statement apply(final Statement base, Description description) { public void evaluate() throws Throwable { base.evaluate(); } - - ; }; } } @@ -741,4 +544,71 @@ public void onlyOnce() { public void testCallMethodOnlyOnceRule() { assertTrue(JUnitCore.runClasses(CallMethodOnlyOnceRule.class).wasSuccessful()); } + + private static final StringBuilder ruleLog = new StringBuilder(); + + public static class TestRuleIsAroundMethodRule { + @Rule + public final MethodRule z = new LoggingMethodRule(ruleLog, "methodRule"); + + @Rule + public final TestRule a = new LoggingTestRule(ruleLog, "testRule"); + + @Test + public void foo() { + ruleLog.append(" foo"); + } + } + + @Test + public void testRuleIsAroundMethodRule() { + ruleLog.setLength(0); + Result result = JUnitCore.runClasses(TestRuleIsAroundMethodRule.class); + assertTrue(result.wasSuccessful()); + assertEquals(" testRule.begin methodRule.begin foo methodRule.end testRule.end", + ruleLog.toString()); + } + + public static class TestRuleOrdering { + @Rule(order = 1) + public final TestRule a = new LoggingTestRule(ruleLog, "outer"); + + @Rule(order = 2) + public final TestRule z = new LoggingTestRule(ruleLog, "inner"); + + @Test + public void foo() { + ruleLog.append(" foo"); + } + } + + @Test + public void testRuleOrdering() { + ruleLog.setLength(0); + Result result = JUnitCore.runClasses(TestRuleOrdering.class); + assertTrue(result.wasSuccessful()); + assertEquals(" outer.begin inner.begin foo inner.end outer.end", ruleLog.toString()); + } + + public static class TestRuleOrderingWithMethodRule { + @Rule(order = 1) + public final MethodRule z = new LoggingMethodRule(ruleLog, "methodRule"); + + @Rule(order = 2) + public final TestRule a = new LoggingTestRule(ruleLog, "testRule"); + + @Test + public void foo() { + ruleLog.append(" foo"); + } + } + + @Test + public void testRuleOrderingWithMethodRule() { + ruleLog.setLength(0); + Result result = JUnitCore.runClasses(TestRuleOrderingWithMethodRule.class); + assertTrue(result.wasSuccessful()); + assertEquals(" methodRule.begin testRule.begin foo testRule.end methodRule.end", + ruleLog.toString()); + } } diff --git a/src/test/java/org/junit/rules/TestWatcherTest.java b/src/test/java/org/junit/rules/TestWatcherTest.java new file mode 100644 index 000000000000..e09e23cbb909 --- /dev/null +++ b/src/test/java/org/junit/rules/TestWatcherTest.java @@ -0,0 +1,397 @@ +package org.junit.rules; + +import static java.util.Arrays.asList; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.*; +import static org.junit.Assume.assumeTrue; +import static org.junit.experimental.results.PrintableResult.testResult; +import static org.junit.experimental.results.ResultMatchers.failureCountIs; +import static org.junit.experimental.results.ResultMatchers.hasFailureContaining; +import static org.junit.rules.ExpectedException.none; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.results.PrintableResult; +import org.junit.experimental.runners.Enclosed; +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.model.Statement; + +import java.util.List; + +@RunWith(Enclosed.class) +public class TestWatcherTest { + + @RunWith(Parameterized.class) + public static class Callbacks { + + @Parameters(name = "{0}") + public static Object[][] parameters() { + return new Object[][] { + { + FailingTest.class, + "starting failed finished ", + asList("starting failed", "test failed", "failed failed", "finished failed") }, + { + InternalViolatedAssumptionTest.class, + "starting deprecated skipped finished ", + asList("starting failed", "don't run", "deprecated skipped failed", "finished failed") }, + { + SuccessfulTest.class, + "starting succeeded finished ", + asList("starting failed", "succeeded failed", "finished failed") }, + { + ViolatedAssumptionTest.class, + "starting skipped finished ", + asList("starting failed", "Test could not be skipped due to other failures", "skipped failed", "finished failed") } + }; + } + + @Parameter(0) + public Class testClass; + + @Parameter(1) + public String expectedCallbacks; + + @Parameter(2) + public List expectedFailures; + + private static TestRule selectedRule; //for injecting rule into test classes + + @Test + public void correctCallbacksCalled() { + StringBuilder log = new StringBuilder(); + selectedRule = new LoggingTestWatcher(log); + JUnitCore.runClasses(testClass); + assertEquals(expectedCallbacks, log.toString()); + } + + @Test + public void resultHasAllFailuresThrownByCallbacks() { + selectedRule = new ErroneousTestWatcher(); + PrintableResult result = testResult(testClass); + assertThat(result, failureCountIs(expectedFailures.size())); + for (String expectedFailure: expectedFailures) { + assertThat(result, hasFailureContaining(expectedFailure)); + } + } + + @Test + public void testWatcherDoesNotModifyResult() { + selectedRule = new NoOpRule(); + Result resultNoOpRule = JUnitCore.runClasses(testClass); + selectedRule = new LoggingTestWatcher(new StringBuilder()); + Result resultTestWatcher = JUnitCore.runClasses(testClass); + assertEquals( + "was successful", + resultNoOpRule.wasSuccessful(), + resultTestWatcher.wasSuccessful()); + assertEquals( + "failure count", + resultNoOpRule.getFailureCount(), + resultTestWatcher.getFailureCount()); + assertEquals( + "ignore count", + resultNoOpRule.getIgnoreCount(), + resultTestWatcher.getIgnoreCount()); + assertEquals( + "run count", + resultNoOpRule.getRunCount(), + resultTestWatcher.getRunCount()); + } + + private static class NoOpRule implements TestRule { + public Statement apply(Statement base, Description description) { + return base; + } + } + + private static class ErroneousTestWatcher extends TestWatcher { + @Override + protected void succeeded(Description description) { + throw new RuntimeException("succeeded failed"); + } + + @Override + protected void failed(Throwable e, Description description) { + throw new RuntimeException("failed failed"); + } + + @Override + protected void skipped(org.junit.AssumptionViolatedException e, Description description) { + throw new RuntimeException("skipped failed"); + } + + @Override + @SuppressWarnings("deprecation") + protected void skipped(AssumptionViolatedException e, Description description) { + throw new RuntimeException("deprecated skipped failed"); + } + + @Override + protected void starting(Description description) { + throw new RuntimeException("starting failed"); + } + + @Override + protected void finished(Description description) { + throw new RuntimeException("finished failed"); + } + } + + public static class FailingTest { + @Rule + public TestRule rule = selectedRule; + + @Test + public void test() { + fail("test failed"); + } + } + + public static class InternalViolatedAssumptionTest { + @Rule + public TestRule watcher = selectedRule; + + @SuppressWarnings("deprecation") + @Test + public void test() { + throw new AssumptionViolatedException("don't run"); + } + } + + public static class SuccessfulTest { + @Rule + public TestRule watcher = selectedRule; + + @Test + public void test() { + } + } + + public static class ViolatedAssumptionTest { + @Rule + public TestRule watcher = selectedRule; + + @Test + public void test() { + assumeTrue(false); + } + } + } + + public static class CallbackArguments { + + public static class Succeeded { + private static Description catchedDescription; + + @Rule + public final TestRule watcher = new TestWatcher() { + @Override + protected void succeeded(Description description) { + catchedDescription = description; + } + }; + + @Test + public void test() { + } + } + + @Test + public void succeeded() { + JUnitCore.runClasses(Succeeded.class); + assertEquals("test(org.junit.rules.TestWatcherTest$CallbackArguments$Succeeded)", + Succeeded.catchedDescription.getDisplayName()); + } + + public static class Failed { + private static Description catchedDescription; + private static Throwable catchedThrowable; + + @Rule + public final TestRule watcher = new TestWatcher() { + @Override + protected void failed(Throwable e, Description description) { + catchedDescription = description; + catchedThrowable = e; + } + }; + + @Test + public void test() { + fail("test failed"); + } + } + + @Test + public void failed() { + JUnitCore.runClasses(Failed.class); + assertEquals("test failed", Failed.catchedThrowable.getMessage()); + assertEquals(AssertionError.class, Failed.catchedThrowable.getClass()); + assertEquals("test(org.junit.rules.TestWatcherTest$CallbackArguments$Failed)", + Failed.catchedDescription.getDisplayName()); + } + + public static class Skipped { + private static Description catchedDescription; + private static org.junit.AssumptionViolatedException catchedException; + + @Rule + public final TestRule watcher = new TestWatcher() { + @Override + protected void skipped(org.junit.AssumptionViolatedException e, Description description) { + catchedDescription = description; + catchedException = e; + } + }; + + @Test + public void test() { + assumeTrue("test skipped", false); + } + } + + @Test + public void skipped() { + JUnitCore.runClasses(Skipped.class); + assertEquals("test skipped", Skipped.catchedException.getMessage()); + assertEquals(org.junit.AssumptionViolatedException.class, Skipped.catchedException.getClass()); + assertEquals("test(org.junit.rules.TestWatcherTest$CallbackArguments$Skipped)", + Skipped.catchedDescription.getDisplayName()); + } + + public static class DeprecatedSkipped { + private static Description catchedDescription; + private static AssumptionViolatedException catchedException; + + @Rule + public final TestRule watcher = new TestWatcher() { + @Override + @SuppressWarnings("deprecation") + protected void skipped(AssumptionViolatedException e, Description description) { + catchedDescription = description; + catchedException = e; + } + }; + + @SuppressWarnings("deprecation") + @Test + public void test() { + throw new AssumptionViolatedException("test skipped"); + } + } + + @Test + public void deprecatedSkipped() { + JUnitCore.runClasses(DeprecatedSkipped.class); + assertEquals("test skipped", DeprecatedSkipped.catchedException.getMessage()); + assertEquals(AssumptionViolatedException.class, DeprecatedSkipped.catchedException.getClass()); + assertEquals("test(org.junit.rules.TestWatcherTest$CallbackArguments$DeprecatedSkipped)", + DeprecatedSkipped.catchedDescription.getDisplayName()); + } + + public static class Starting { + private static Description catchedDescription; + + @Rule + public final TestRule watcher = new TestWatcher() { + @Override + protected void starting(Description description) { + catchedDescription = description; + } + }; + + @Test + public void test() { + } + } + + @Test + public void starting() { + JUnitCore.runClasses(Starting.class); + assertEquals("test(org.junit.rules.TestWatcherTest$CallbackArguments$Starting)", + Starting.catchedDescription.getDisplayName()); + } + + public static class Finished { + private static Description catchedDescription; + + @Rule + public final TestRule watcher = new TestWatcher() { + @Override + protected void finished(Description description) { + catchedDescription = description; + } + }; + + @Test + public void test() { + } + } + + @Test + public void finished() { + JUnitCore.runClasses(Finished.class); + assertEquals("test(org.junit.rules.TestWatcherTest$CallbackArguments$Finished)", + Finished.catchedDescription.getDisplayName()); + } + } + + //The following tests check the information in TestWatcher's Javadoc + //regarding interplay with other rules. + public static class InterplayWithOtherRules { + private static StringBuilder log; + + public static class ExpectedExceptionTest { + @Rule(order = Integer.MIN_VALUE) + //the field name must be alphabetically lower than "thrown" in order + //to make the test failing if order is not set + public final TestRule a = new LoggingTestWatcher(log); + + @Rule + public final ExpectedException thrown = none(); + + @Test + public void testWithExpectedException() { + thrown.expect(RuntimeException.class); + throw new RuntimeException("expected exception"); + } + } + + @Test + public void expectedExceptionIsSeenAsSuccessfulTest() { + log = new StringBuilder(); + JUnitCore.runClasses(ExpectedExceptionTest.class); + assertEquals("starting succeeded finished ", log.toString()); + } + + public static class ErrorCollectorTest { + @Rule(order = Integer.MIN_VALUE) + //the field name must be alphabetically lower than "collector" in + //order to make the test failing if order is not set + public final TestRule a = new LoggingTestWatcher(log); + + @Rule + public final ErrorCollector collector = new ErrorCollector(); + + @Test + public void test() { + collector.addError(new RuntimeException("expected exception")); + } + } + + @Test + public void testIsSeenAsFailedBecauseOfCollectedError() { + log = new StringBuilder(); + JUnitCore.runClasses(ErrorCollectorTest.class); + assertEquals("starting failed finished ", log.toString()); + } + } +} diff --git a/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java b/src/test/java/org/junit/rules/TestWatchmanTest.java similarity index 65% rename from src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java rename to src/test/java/org/junit/rules/TestWatchmanTest.java index f2448cccb702..b7b76be0180d 100644 --- a/src/test/java/org/junit/tests/experimental/rules/TestWatchmanTest.java +++ b/src/test/java/org/junit/rules/TestWatchmanTest.java @@ -1,21 +1,27 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static junit.framework.Assert.fail; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assume.assumeTrue; import static org.junit.runner.JUnitCore.runClasses; - +import org.junit.BeforeClass; 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 { + static StringBuilder log; + + @BeforeClass + public static void initLog() { + log = new StringBuilder(); + } + @Rule - public static LoggingTestWatchman watchman = new LoggingTestWatchman(); + public LoggingTestWatchman watchman = new LoggingTestWatchman(log); @Test public void succeeds() { @@ -26,13 +32,20 @@ public void succeeds() { @Test public void neitherLogSuccessNorFailedForViolatedAssumption() { runClasses(ViolatedAssumptionTest.class); - assertThat(ViolatedAssumptionTest.watchman.log.toString(), + assertThat(ViolatedAssumptionTest.log.toString(), is("starting finished ")); } public static class FailingTest { + static StringBuilder log; + + @BeforeClass + public static void initLog() { + log = new StringBuilder(); + } + @Rule - public static LoggingTestWatchman watchman = new LoggingTestWatchman(); + public LoggingTestWatchman watchman = new LoggingTestWatchman(log); @Test public void succeeds() { @@ -43,12 +56,16 @@ public void succeeds() { @Test public void logFailingTest() { runClasses(FailingTest.class); - assertThat(FailingTest.watchman.log.toString(), + assertThat(FailingTest.log.toString(), is("starting failed finished ")); } private static class LoggingTestWatchman extends TestWatchman { - private final StringBuilder log = new StringBuilder(); + private final StringBuilder log; + + private LoggingTestWatchman(StringBuilder log) { + this.log = log; + } @Override public void succeeded(FrameworkMethod method) { diff --git a/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java b/src/test/java/org/junit/rules/TimeoutRuleTest.java similarity index 96% rename from src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java rename to src/test/java/org/junit/rules/TimeoutRuleTest.java index 288f1bf056f6..6c0e349bd507 100644 --- a/src/test/java/org/junit/tests/experimental/rules/TimeoutRuleTest.java +++ b/src/test/java/org/junit/rules/TimeoutRuleTest.java @@ -1,8 +1,8 @@ -package org.junit.tests.experimental.rules; +package org.junit.rules; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import java.io.File; import java.io.IOException; @@ -18,9 +18,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestRule; -import org.junit.rules.Timeout; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; diff --git a/src/test/java/org/junit/rules/VerifierRuleTest.java b/src/test/java/org/junit/rules/VerifierRuleTest.java new file mode 100644 index 000000000000..4a09bc78fb04 --- /dev/null +++ b/src/test/java/org/junit/rules/VerifierRuleTest.java @@ -0,0 +1,36 @@ +package org.junit.rules; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.experimental.results.PrintableResult.testResult; +import static org.junit.experimental.results.ResultMatchers.isSuccessful; + +import org.junit.Rule; +import org.junit.Test; + +public class VerifierRuleTest { + + 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); + } +} diff --git a/src/test/java/org/junit/runner/AllRunnerTests.java b/src/test/java/org/junit/runner/AllRunnerTests.java new file mode 100644 index 000000000000..3334b40d0a0f --- /dev/null +++ b/src/test/java/org/junit/runner/AllRunnerTests.java @@ -0,0 +1,18 @@ +package org.junit.runner; + + +import org.junit.runner.notification.AllNotificationTests; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + AllNotificationTests.class, + FilterFactoriesTest.class, + FilterOptionIntegrationTest.class, + OrderWithValidatorTest.class, + JUnitCommandLineParseResultTest.class, + JUnitCoreTest.class, RequestTest.class +}) +public class AllRunnerTests { +} diff --git a/src/test/java/org/junit/runner/OrderWithValidatorTest.java b/src/test/java/org/junit/runner/OrderWithValidatorTest.java new file mode 100644 index 000000000000..cfa3c5e13462 --- /dev/null +++ b/src/test/java/org/junit/runner/OrderWithValidatorTest.java @@ -0,0 +1,50 @@ +package org.junit.runner; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.util.List; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.manipulation.Alphanumeric; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; +import org.junit.runners.model.TestClass; + +public class OrderWithValidatorTest { + private final OrderWithValidator validator = new OrderWithValidator(); + + @RunWith(JUnit4.class) + @OrderWith(Alphanumeric.class) + public static class TestWithNoValidationErrors { + @Test + public void passes() {} + } + + @RunWith(JUnit4.class) + @OrderWith(Alphanumeric.class) + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public static class TestAnnotatedWithFixMethodOrder { + @Test + public void passes() {} + } + + @Test + public void noErrorIsAddedForTestWithoutValdationErrors() { + List errors = validator.validateAnnotatedClass( + new TestClass(TestWithNoValidationErrors.class)); + + assertThat(errors.size(), is(0)); + } + + @Test + public void errorIsAddedWhenTestAnnotatedWithFixMethodOrder() { + List errors = validator.validateAnnotatedClass( + new TestClass(TestAnnotatedWithFixMethodOrder.class)); + + assertThat(errors.size(), is(1)); + Exception exception = errors.get(0); + assertThat(exception.getMessage(), is("@FixMethodOrder cannot be combined with @OrderWith")); + } +} diff --git a/src/test/java/org/junit/runner/RequestTest.java b/src/test/java/org/junit/runner/RequestTest.java new file mode 100644 index 000000000000..dc6a81108397 --- /dev/null +++ b/src/test/java/org/junit/runner/RequestTest.java @@ -0,0 +1,50 @@ +package org.junit.runner; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.rules.EventCollector.hasSingleFailureWithMessage; + +import org.junit.Test; +import org.junit.rules.EventCollector; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +public class RequestTest { + + /** + * #1320 A root of a {@link Description} produced by + * {@link Request#classes(Class...)} should be named "classes" + */ + @Test + public void createsADescriptionWithANameForClasses() { + Description description = Request + .classes(RequestTest.class, RequestTest.class).getRunner() + .getDescription(); + assertThat(description.toString(), is("classes")); + } + + @Test + public void reportsInitializationErrorThrownWhileCreatingSuite() { + EventCollector collector = new EventCollector(); + JUnitCore core = new JUnitCore(); + core.addListener(collector); + + core.run(new FailingComputer(), FooTest.class, BarTest.class); + + assertThat(collector, hasSingleFailureWithMessage("cannot create suite")); + } + + private static class FailingComputer extends Computer { + @Override + public Runner getSuite(RunnerBuilder builder, Class[] classes) + throws InitializationError { + throw new InitializationError("cannot create suite"); + } + } + + private static class FooTest { + } + + private static class BarTest { + } +} diff --git a/src/test/java/org/junit/runner/RunnerSpy.java b/src/test/java/org/junit/runner/RunnerSpy.java index 5523041ea85b..939cd75b79ea 100644 --- a/src/test/java/org/junit/runner/RunnerSpy.java +++ b/src/test/java/org/junit/runner/RunnerSpy.java @@ -7,13 +7,13 @@ public class RunnerSpy extends Runner { public static final Description DESCRIPTION = Description.TEST_MECHANISM; private RunnerBuilder invokedRunnerBuilder; - private Class invokedTestClass; + private Class invokedTestClass; - public RunnerSpy(Class testClass) { + public RunnerSpy(Class testClass) { invokedTestClass = testClass; } - public RunnerSpy(Class testClass, RunnerBuilder runnerBuilder) { + public RunnerSpy(Class testClass, RunnerBuilder runnerBuilder) { invokedTestClass = testClass; invokedRunnerBuilder = runnerBuilder; } @@ -31,7 +31,7 @@ public RunnerBuilder getInvokedRunnerBuilder() { return invokedRunnerBuilder; } - public Class getInvokedTestClass() { + public Class getInvokedTestClass() { return invokedTestClass; } } \ No newline at end of file diff --git a/src/test/java/org/junit/runner/notification/AllNotificationTests.java b/src/test/java/org/junit/runner/notification/AllNotificationTests.java new file mode 100644 index 000000000000..1c991a9e80e5 --- /dev/null +++ b/src/test/java/org/junit/runner/notification/AllNotificationTests.java @@ -0,0 +1,14 @@ +package org.junit.runner.notification; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + ConcurrentRunNotifierTest.class, + RunNotifierTest.class, + SynchronizedRunListenerTest.class +}) +public class AllNotificationTests { +} diff --git a/src/test/java/org/junit/runner/notification/ConcurrentRunNotifierTest.java b/src/test/java/org/junit/runner/notification/ConcurrentRunNotifierTest.java index 3406ed91150f..b7386e3d3635 100644 --- a/src/test/java/org/junit/runner/notification/ConcurrentRunNotifierTest.java +++ b/src/test/java/org/junit/runner/notification/ConcurrentRunNotifierTest.java @@ -13,8 +13,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** diff --git a/src/test/java/org/junit/runner/notification/RunNotifierTest.java b/src/test/java/org/junit/runner/notification/RunNotifierTest.java index 1c2e7c9f6860..c3a4a8855642 100644 --- a/src/test/java/org/junit/runner/notification/RunNotifierTest.java +++ b/src/test/java/org/junit/runner/notification/RunNotifierTest.java @@ -2,9 +2,9 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.core.Is.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; import java.util.concurrent.atomic.AtomicInteger; @@ -95,7 +95,7 @@ public void addFirstAndRemoveWithThreadSafeListener() { @Test public void wrapIfNotThreadSafeShouldNotWrapThreadSafeListeners() { - ThreadSafeListener listener = new ThreadSafeListener();; + ThreadSafeListener listener = new ThreadSafeListener(); assertSame(listener, new RunNotifier().wrapIfNotThreadSafe(listener)); } diff --git a/src/test/java/org/junit/runners/AllRunnersTests.java b/src/test/java/org/junit/runners/AllRunnersTests.java new file mode 100644 index 000000000000..a51072c054a6 --- /dev/null +++ b/src/test/java/org/junit/runners/AllRunnersTests.java @@ -0,0 +1,17 @@ +package org.junit.runners; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; +import org.junit.runners.model.AllModelTests; +import org.junit.runners.parameterized.AllParameterizedTests; + +@RunWith(Suite.class) +@SuiteClasses({ + AllModelTests.class, + AllParameterizedTests.class, + RuleContainerTest.class, + CustomBlockJUnit4ClassRunnerTest.class +}) +public class AllRunnersTests { +} diff --git a/src/test/java/org/junit/runners/CustomBlockJUnit4ClassRunnerTest.java b/src/test/java/org/junit/runners/CustomBlockJUnit4ClassRunnerTest.java new file mode 100644 index 000000000000..d9f072baacb6 --- /dev/null +++ b/src/test/java/org/junit/runners/CustomBlockJUnit4ClassRunnerTest.java @@ -0,0 +1,90 @@ +package org.junit.runners; + +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; + +/** + * Tests that verify proper behavior for custom runners that extend + * {@link BlockJUnit4ClassRunner}. + * + * @author Sam Brannen + * @since 4.13 + */ +public class CustomBlockJUnit4ClassRunnerTest { + + @Test + public void exceptionsFromMethodBlockMustNotResultInUnrootedTests() throws Exception { + TrackingRunListener listener = new TrackingRunListener(); + RunNotifier notifier = new RunNotifier(); + notifier.addListener(listener); + + new CustomBlockJUnit4ClassRunner(CustomBlockJUnit4ClassRunnerTestCase.class).run(notifier); + assertEquals("tests started.", 2, listener.testStartedCount.get()); + assertEquals("tests failed.", 1, listener.testFailureCount.get()); + assertEquals("tests finished.", 2, listener.testFinishedCount.get()); + } + + + public static class CustomBlockJUnit4ClassRunnerTestCase { + @Test public void shouldPass() { /* no-op */ } + @Test public void throwException() { /* no-op */ } + } + + /** + * Custom extension of {@link BlockJUnit4ClassRunner} that always throws + * an exception from the {@code methodBlock()} if a test method is named + * exactly {@code "throwException"}. + */ + private static class CustomBlockJUnit4ClassRunner extends BlockJUnit4ClassRunner { + + CustomBlockJUnit4ClassRunner(Class testClass) throws InitializationError { + super(testClass); + } + + @Override + protected Statement methodBlock(FrameworkMethod method) { + if ("throwException".equals(method.getName())) { + throw new RuntimeException("throwException() test method invoked"); + } + return super.methodBlock(method); + } + } + + /** + * Simple {@link RunListener} that tracks the number of times that + * certain callbacks are invoked. + */ + private static class TrackingRunListener extends RunListener { + + final AtomicInteger testStartedCount = new AtomicInteger(); + final AtomicInteger testFailureCount = new AtomicInteger(); + final AtomicInteger testFinishedCount = new AtomicInteger(); + + + @Override + public void testStarted(Description description) throws Exception { + testStartedCount.incrementAndGet(); + } + + @Override + public void testFailure(Failure failure) throws Exception { + testFailureCount.incrementAndGet(); + } + + @Override + public void testFinished(Description description) throws Exception { + testFinishedCount.incrementAndGet(); + } + } + +} diff --git a/src/test/java/org/junit/runners/RuleContainerTest.java b/src/test/java/org/junit/runners/RuleContainerTest.java new file mode 100644 index 000000000000..714d0dfdf660 --- /dev/null +++ b/src/test/java/org/junit/runners/RuleContainerTest.java @@ -0,0 +1,70 @@ +package org.junit.runners; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; +import org.junit.rules.MethodRule; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +public class RuleContainerTest { + private final RuleContainer container = new RuleContainer(); + + @Test + public void methodRulesOnly() { + container.add(MRule.M1); + container.add(MRule.M2); + assertEquals("[M1, M2]", container.getSortedRules().toString()); + container.setOrder(MRule.M2, 1); + assertEquals("[M2, M1]", container.getSortedRules().toString()); + } + + @Test + public void testRuleAroundMethodRule() { + container.add(MRule.M1); + container.add(Rule.A); + assertEquals("[M1, A]", container.getSortedRules().toString()); + } + + @Test + public void ordering1() { + container.add(MRule.M1); + container.add(Rule.A); + container.setOrder(Rule.A, 1); + assertEquals("[A, M1]", container.getSortedRules().toString()); + } + + @Test + public void ordering2() { + container.add(Rule.A); + container.add(Rule.B); + container.add(Rule.C); + assertEquals("[A, B, C]", container.getSortedRules().toString()); + container.setOrder(Rule.B, 1); + container.setOrder(Rule.C, 2); + assertEquals("[C, B, A]", container.getSortedRules().toString()); + } + + private enum Rule implements TestRule { + A, + B, + C; + + public Statement apply(Statement base, Description description) { + return base; + } + } + + private enum MRule implements MethodRule { + M1, + M2; + + public Statement apply(Statement base, FrameworkMethod method, Object target) { + return base; + } + } +} diff --git a/src/test/java/org/junit/runners/model/AllModelTests.java b/src/test/java/org/junit/runners/model/AllModelTests.java new file mode 100644 index 000000000000..b0c50d533ba6 --- /dev/null +++ b/src/test/java/org/junit/runners/model/AllModelTests.java @@ -0,0 +1,15 @@ +package org.junit.runners.model; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + FrameworkFieldTest.class, + FrameworkMethodTest.class, + InvalidTestClassErrorTest.class, + TestClassTest.class +}) +public class AllModelTests { +} diff --git a/src/test/java/org/junit/runners/model/FrameworkFieldTest.java b/src/test/java/org/junit/runners/model/FrameworkFieldTest.java index 1d185a548e72..55ba75e181c1 100644 --- a/src/test/java/org/junit/runners/model/FrameworkFieldTest.java +++ b/src/test/java/org/junit/runners/model/FrameworkFieldTest.java @@ -2,7 +2,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.rules.ExpectedException.none; diff --git a/src/test/java/org/junit/runners/model/FrameworkMethodTest.java b/src/test/java/org/junit/runners/model/FrameworkMethodTest.java index 9927d1908676..b97df8221a78 100644 --- a/src/test/java/org/junit/runners/model/FrameworkMethodTest.java +++ b/src/test/java/org/junit/runners/model/FrameworkMethodTest.java @@ -2,7 +2,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.rules.ExpectedException.none; diff --git a/src/test/java/org/junit/runners/model/InvalidTestClassErrorTest.java b/src/test/java/org/junit/runners/model/InvalidTestClassErrorTest.java new file mode 100644 index 000000000000..7d92dd42f600 --- /dev/null +++ b/src/test/java/org/junit/runners/model/InvalidTestClassErrorTest.java @@ -0,0 +1,23 @@ +package org.junit.runners.model; + +import org.junit.Test; + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +public class InvalidTestClassErrorTest { + + @Test + public void invalidTestClassErrorShouldListAllValidationErrorsInItsMessage() { + InvalidTestClassError sut = new InvalidTestClassError(SampleTestClass.class, + asList(new Throwable("validation error 1"), new Throwable("validation error 2"))); + + assertThat(sut.getMessage(), equalTo("Invalid test class '" + SampleTestClass.class.getName() + "':" + + "\n 1. validation error 1" + + "\n 2. validation error 2")); + } + + private static class SampleTestClass { + } +} \ No newline at end of file diff --git a/src/test/java/org/junit/runners/model/TestClassTest.java b/src/test/java/org/junit/runners/model/TestClassTest.java index 7682968c1742..6b5cb2857a08 100644 --- a/src/test/java/org/junit/runners/model/TestClassTest.java +++ b/src/test/java/org/junit/runners/model/TestClassTest.java @@ -1,14 +1,13 @@ package org.junit.runners.model; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.lang.annotation.Annotation; +import java.util.ArrayList; import java.util.List; import org.junit.Ignore; @@ -132,26 +131,45 @@ public String methodA() { @Test public int methodB() { return 0; - } + } + + public int methodWithoutAnnotation() { + return 0; + } } @Test public void providesAnnotatedMethodsSortedByName() { - TestClass tc = new TestClass(MethodsAnnotated.class); - List annotatedMethods = tc.getAnnotatedMethods(); - assertThat("Wrong number of annotated methods.", - annotatedMethods.size(), is(3)); - assertThat("First annotated method is wrong.", annotatedMethods - .iterator().next().getName(), is("methodA")); + TestClass tc = new TestClass(MethodsAnnotated.class); + List annotatedMethods = tc.getAnnotatedMethods(); + List methodNames = extractNames(annotatedMethods); + assertThat(methodNames.indexOf("methodA"), + lessThan(methodNames.indexOf("methodB"))); + } + + @Test + public void getAnnotatedMethodsDoesNotReturnMethodWithoutAnnotation() { + TestClass tc = new TestClass(MethodsAnnotated.class); + List annotatedMethods = tc.getAnnotatedMethods(); + List methodNames = extractNames(annotatedMethods); + assertThat(methodNames, not(hasItem("methodWithoutAnnotation"))); + } + + private List extractNames(List methods) { + List names = new ArrayList(); + for (FrameworkMethod method: methods) { + names.add(method.getName()); + } + return names; } @Test public void annotatedMethodValues() { - TestClass tc = new TestClass(MethodsAnnotated.class); - List values = tc.getAnnotatedMethodValues( - new MethodsAnnotated(), Ignore.class, String.class); - assertThat(values, hasItem("jupiter")); - assertThat(values.size(), is(1)); + TestClass tc = new TestClass(MethodsAnnotated.class); + List values = tc.getAnnotatedMethodValues( + new MethodsAnnotated(), Ignore.class, String.class); + assertThat(values, hasItem("jupiter")); + assertThat(values.size(), is(1)); } @Test diff --git a/src/test/java/org/junit/runners/parameterized/AllParameterizedTests.java b/src/test/java/org/junit/runners/parameterized/AllParameterizedTests.java new file mode 100644 index 000000000000..9a0f261d4001 --- /dev/null +++ b/src/test/java/org/junit/runners/parameterized/AllParameterizedTests.java @@ -0,0 +1,14 @@ +package org.junit.runners.parameterized; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + BlockJUnit4ClassRunnerWithParametersTest.class, + ParameterizedNamesTest.class, + TestWithParametersTest.class +}) +public class AllParameterizedTests { +} diff --git a/src/test/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersTest.java b/src/test/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersTest.java new file mode 100644 index 000000000000..0896c1f3973d --- /dev/null +++ b/src/test/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParametersTest.java @@ -0,0 +1,80 @@ +package org.junit.runners.parameterized; + +import static java.util.Collections.emptyList; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.rules.ExpectedException.none; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Collections; +import java.util.List; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.model.TestClass; + +public class BlockJUnit4ClassRunnerWithParametersTest { + private static final List NO_PARAMETERS = emptyList(); + + @Rule + public final ExpectedException thrown = none(); + + @RunWith(Parameterized.class) + @DummyAnnotation + public static class ClassWithParameterizedAnnotation { + @Test + public void dummyTest() { + } + } + + @Test + public void hasAllAnnotationsExceptRunWith() throws Exception { + TestWithParameters testWithParameters = new TestWithParameters( + "dummy name", new TestClass( + ClassWithParameterizedAnnotation.class), NO_PARAMETERS); + BlockJUnit4ClassRunnerWithParameters runner = new BlockJUnit4ClassRunnerWithParameters( + testWithParameters); + Annotation[] annotations = runner.getRunnerAnnotations(); + assertEquals(1, annotations.length); + assertEquals(annotations[0].annotationType(), DummyAnnotation.class); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + private static @interface DummyAnnotation { + } + + @RunWith(Parameterized.class) + public static class ClassWithPrivateParameter { + @Parameterized.Parameter + private String parameter; + + @Test + public void dummyTest() { + } + } + + @Test + public void providesHelpfulMessageIfParameterFieldCannotBeSet() + throws Exception { + TestWithParameters testWithParameters = new TestWithParameters( + "dummy name", + new TestClass(ClassWithPrivateParameter.class), + Collections.singletonList("dummy parameter")); + BlockJUnit4ClassRunnerWithParameters runner = new BlockJUnit4ClassRunnerWithParameters( + testWithParameters); + + thrown.expect(IllegalAccessException.class); + thrown.expectCause(instanceOf(IllegalAccessException.class)); + thrown.expectMessage("Cannot set parameter 'parameter'. Ensure that the field 'parameter' is public."); + + runner.createTest(); + } +} \ No newline at end of file diff --git a/src/test/java/org/junit/runners/parameterized/ParameterizedNamesTest.java b/src/test/java/org/junit/runners/parameterized/ParameterizedNamesTest.java index d533c6e62e6d..e04fb7610eab 100644 --- a/src/test/java/org/junit/runners/parameterized/ParameterizedNamesTest.java +++ b/src/test/java/org/junit/runners/parameterized/ParameterizedNamesTest.java @@ -17,10 +17,9 @@ */ public class ParameterizedNamesTest { @RunWith(Parameterized.class) - public static class ParametrizedWithSpecialCharsInName { + public static class ParameterizedWithSpecialCharsInName { - @SuppressWarnings("unused") - public ParametrizedWithSpecialCharsInName(String s) { + public ParameterizedWithSpecialCharsInName(String s) { } @Parameterized.Parameters(name = "{0}") @@ -42,7 +41,7 @@ public void test() { @Test public void parameterizedTestsWithSpecialCharsInName() { - Request request = Request.aClass(ParametrizedWithSpecialCharsInName.class); + Request request = Request.aClass(ParameterizedWithSpecialCharsInName.class); for (Description parent : request.getRunner().getDescription().getChildren()) { for (Description description : parent.getChildren()) { assertEquals("test" + parent.getDisplayName(), description.getMethodName()); diff --git a/src/test/java/org/junit/samples/AllSamplesTests.java b/src/test/java/org/junit/samples/AllSamplesTests.java new file mode 100644 index 000000000000..cbd5fce30dc5 --- /dev/null +++ b/src/test/java/org/junit/samples/AllSamplesTests.java @@ -0,0 +1,14 @@ +package org.junit.samples; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; +import org.junit.samples.money.MoneyTest; + +@RunWith(Suite.class) +@SuiteClasses({ + ListTest.class, + MoneyTest.class +}) +public class AllSamplesTests { +} diff --git a/src/test/java/org/junit/samples/SimpleTest.java b/src/test/java/org/junit/samples/SimpleTest.java index e2454589ae6d..02bae09e5f9b 100644 --- a/src/test/java/org/junit/samples/SimpleTest.java +++ b/src/test/java/org/junit/samples/SimpleTest.java @@ -8,6 +8,8 @@ /** * Some simple tests. + * + *

      This test is expected to fail. */ public class SimpleTest { protected int fValue1; diff --git a/src/test/java/org/junit/tests/AllTests.java b/src/test/java/org/junit/tests/AllTests.java index 00c259b77320..fd9169121d1a 100644 --- a/src/test/java/org/junit/tests/AllTests.java +++ b/src/test/java/org/junit/tests/AllTests.java @@ -3,216 +3,44 @@ import junit.framework.JUnit4TestAdapter; import junit.framework.Test; import org.junit.AssumptionViolatedExceptionTest; -import org.junit.experimental.categories.CategoryFilterFactoryTest; -import org.junit.internal.MethodSorterTest; -import org.junit.internal.matchers.StacktracePrintingMatcherTest; -import org.junit.internal.matchers.ThrowableCauseMatcherTest; -import org.junit.rules.DisableOnDebugTest; -import org.junit.rules.StopwatchTest; -import org.junit.runner.FilterFactoriesTest; -import org.junit.runner.FilterOptionIntegrationTest; -import org.junit.runner.JUnitCommandLineParseResultTest; -import org.junit.runner.JUnitCoreTest; +import org.junit.internal.AllInternalTests; +import org.junit.rules.AllRulesTests; +import org.junit.runner.AllRunnerTests; import org.junit.runner.RunWith; -import org.junit.runner.notification.ConcurrentRunNotifierTest; -import org.junit.runner.notification.RunNotifierTest; -import org.junit.runner.notification.SynchronizedRunListenerTest; +import org.junit.runners.AllRunnersTests; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; -import org.junit.runners.model.FrameworkFieldTest; -import org.junit.runners.model.FrameworkMethodTest; -import org.junit.runners.model.TestClassTest; -import org.junit.runners.parameterized.ParameterizedNamesTest; -import org.junit.runners.parameterized.TestWithParametersTest; -import org.junit.tests.assertion.AssertionTest; -import org.junit.tests.assertion.ComparisonFailureTest; -import org.junit.tests.assertion.MultipleFailureExceptionTest; -import org.junit.tests.deprecated.JUnit4ClassRunnerTest; -import org.junit.tests.description.AnnotatedDescriptionTest; -import org.junit.tests.description.SuiteDescriptionTest; -import org.junit.tests.description.TestDescriptionMethodNameTest; -import org.junit.tests.description.TestDescriptionTest; -import org.junit.tests.experimental.AssumptionTest; -import org.junit.tests.experimental.ExperimentalTests; -import org.junit.tests.experimental.MatcherTest; -import org.junit.tests.experimental.categories.CategoriesAndParameterizedTest; -import org.junit.tests.experimental.categories.CategoryTest; -import org.junit.tests.experimental.categories.JavadocTest; -import org.junit.tests.experimental.categories.MultiCategoryTest; -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.ExpectedExceptionTest; -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.RuleMemberValidatorTest; -import org.junit.tests.experimental.rules.TempFolderRuleTest; -import org.junit.tests.experimental.rules.TemporaryFolderUsageTest; -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.TestedOnSupplierTest; -import org.junit.tests.experimental.theories.internal.AllMembersSupplierTest; -import org.junit.tests.experimental.theories.internal.ParameterizedAssertionErrorTest; -import org.junit.tests.experimental.theories.internal.SpecificDataPointsSupplierTest; -import org.junit.tests.experimental.theories.runner.TheoriesPerformanceTest; -import org.junit.tests.experimental.theories.runner.WithAutoGeneratedDataPoints; -import org.junit.tests.experimental.theories.runner.WithDataPointMethod; -import org.junit.tests.experimental.theories.runner.WithNamedDataPoints; -import org.junit.tests.internal.runners.statements.FailOnTimeoutTest; -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.ClassLevelMethodsWithIgnoredTestsTest; -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.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.ValidationTest; -import org.junit.validator.PublicClassValidatorTest; +import org.junit.samples.AllSamplesTests; +import org.junit.tests.assertion.AllAssertionTests; +import org.junit.tests.deprecated.AllDeprecatedTests; +import org.junit.tests.description.AllDescriptionTests; +import org.junit.tests.experimental.AllExperimentalTests; +import org.junit.tests.junit3compatibility.AllJUnit3CompatibilityTests; +import org.junit.tests.listening.AllListeningTests; +import org.junit.tests.manipulation.AllManipulationTests; +import org.junit.tests.running.AllRunningTests; +import org.junit.tests.validation.AllValidationTests; +import org.junit.validator.AllValidatorTests; -// 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, - TestDescriptionMethodNameTest.class, - SuiteDescriptionTest.class, - AllTestsTest.class, - AnnotationTest.class, - AssertionTest.class, - CommandLineTest.class, - ExpectedTest.class, - ComparisonFailureTest.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, - ClassLevelMethodsWithIgnoredTestsTest.class, - ValidationTest.class, - UserStopTest.class, - SortableTest.class, - JUnit38ClassRunnerTest.class, - SystemExitTest.class, - JUnitCoreReturnsCorrectExitCodeTest.class, - SuiteMethodTest.class, - BadlyFormedClassesTest.class, - IgnoreClassTest.class, - OldTestClassAdaptingListenerTest.class, - AnnotatedDescriptionTest.class, + AllAssertionTests.class, + AllDeprecatedTests.class, + AllDescriptionTests.class, + AllExperimentalTests.class, + AllInternalTests.class, + AllJUnit3CompatibilityTests.class, + AllListeningTests.class, + AllManipulationTests.class, + AllRulesTests.class, + AllRunnersTests.class, + AllRunnerTests.class, + AllRunningTests.class, + AllSamplesTests.class, + AllValidationTests.class, + AllValidatorTests.class, AssumptionViolatedExceptionTest.class, - ExperimentalTests.class, - InheritedTestTest.class, - TestClassTest.class, - AllMembersSupplierTest.class, - SpecificDataPointsSupplierTest.class, - ParameterizedAssertionErrorTest.class, - WithDataPointMethod.class, - WithNamedDataPoints.class, - WithAutoGeneratedDataPoints.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, - ExpectedExceptionTest.class, - TempFolderRuleTest.class, - TemporaryFolderUsageTest.class, - ExternalResourceRuleTest.class, - VerifierRuleTest.class, - CategoryTest.class, - CategoriesAndParameterizedTest.class, - MultiCategoryTest.class, - JavadocTest.class, - ParentRunnerFilteringTest.class, - BlockJUnit4ClassRunnerOverrideTest.class, - RuleMemberValidatorTest.class, - RuleChainTest.class, - BlockJUnit4ClassRunnerTest.class, - MethodSorterTest.class, - TestedOnSupplierTest.class, - StacktracePrintingMatcherTest.class, - StopwatchTest.class, - RunNotifierTest.class, - ConcurrentRunNotifierTest.class, - SynchronizedRunListenerTest.class, - FilterOptionIntegrationTest.class, - JUnitCommandLineParseResultTest.class, - FilterFactoriesTest.class, - CategoryFilterFactoryTest.class, - FrameworkFieldTest.class, - FrameworkMethodTest.class, - FailOnTimeoutTest.class, - JUnitCoreTest.class, - TestWithParametersTest.class, - ParameterizedNamesTest.class, - PublicClassValidatorTest.class, - DisableOnDebugTest.class, - ThrowableCauseMatcherTest.class + ObjectContractTest.class }) public class AllTests { public static Test suite() { diff --git a/src/test/java/org/junit/tests/ObjectContractTest.java b/src/test/java/org/junit/tests/ObjectContractTest.java index 27172f93cb93..541a25b94a59 100644 --- a/src/test/java/org/junit/tests/ObjectContractTest.java +++ b/src/test/java/org/junit/tests/ObjectContractTest.java @@ -1,7 +1,7 @@ package org.junit.tests; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeThat; diff --git a/src/test/java/org/junit/tests/SampleJUnit4Tests.java b/src/test/java/org/junit/tests/SampleJUnit4Tests.java new file mode 100644 index 000000000000..c42026f2f79f --- /dev/null +++ b/src/test/java/org/junit/tests/SampleJUnit4Tests.java @@ -0,0 +1,48 @@ +package org.junit.tests; + +import org.junit.Test; + +/** + * Container for sample JUnit4-style tests used in integration tests. + */ +public class SampleJUnit4Tests { + + public static class TestWithOneThrowingTestMethod { + + @Test + public void alwaysThrows() { + new FakeClassUnderTest().throwsExceptionWithoutCause(); + } + } + + public static class TestWithOneThrowingTestMethodWithCause { + + @Test + public void alwaysThrows() { + new FakeClassUnderTest().throwsExceptionWithCause(); + } + } + + private static class FakeClassUnderTest { + + public void throwsExceptionWithCause() { + doThrowExceptionWithCause(); + } + + public void throwsExceptionWithoutCause() { + doThrowExceptionWithoutCause(); + } + + private void doThrowExceptionWithCause() { + try { + throwsExceptionWithoutCause(); + } catch (Exception e) { + throw new RuntimeException("outer", e); + } + } + + private void doThrowExceptionWithoutCause() { + throw new RuntimeException("cause"); + } + } +} diff --git a/src/test/java/org/junit/tests/assertion/AllAssertionTests.java b/src/test/java/org/junit/tests/assertion/AllAssertionTests.java new file mode 100644 index 000000000000..5190e9439f5e --- /dev/null +++ b/src/test/java/org/junit/tests/assertion/AllAssertionTests.java @@ -0,0 +1,14 @@ +package org.junit.tests.assertion; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + AssertionTest.class, + ComparisonFailureTest.class, + MultipleFailureExceptionTest.class +}) +public class AllAssertionTests { +} diff --git a/src/test/java/org/junit/tests/assertion/AssertionTest.java b/src/test/java/org/junit/tests/assertion/AssertionTest.java old mode 100755 new mode 100644 index 27b47cd25bd4..22907e07c56f --- a/src/test/java/org/junit/tests/assertion/AssertionTest.java +++ b/src/test/java/org/junit/tests/assertion/AssertionTest.java @@ -11,13 +11,16 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; +import java.io.IOException; import java.math.BigDecimal; import org.junit.Assert; import org.junit.ComparisonFailure; import org.junit.Test; +import org.junit.function.ThrowingRunnable; import org.junit.internal.ArrayComparisonFailure; /** @@ -31,6 +34,8 @@ public class AssertionTest { // assert false; // } + private static final String ASSERTION_ERROR_EXPECTED = "AssertionError expected"; + @Test(expected = AssertionError.class) public void fails() { Assert.fail(); @@ -42,7 +47,9 @@ public void failWithNoMessageToString() { Assert.fail(); } catch (AssertionError exception) { assertEquals("java.lang.AssertionError", exception.toString()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -51,90 +58,122 @@ public void failWithMessageToString() { Assert.fail("woops!"); } catch (AssertionError exception) { assertEquals("java.lang.AssertionError: woops!", exception.toString()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } - @Test(expected = AssertionError.class) + @Test public void arraysNotEqual() { - assertArrayEquals((new Object[]{new Object()}), (new Object[]{new Object()})); + assertArrayEqualsFailure( + new Object[]{"right"}, + new Object[]{"wrong"}, + "arrays first differed at element [0]; expected:<[right]> but was:<[wrong]>"); } - @Test(expected = AssertionError.class) + @Test public void arraysNotEqualWithMessage() { - assertArrayEquals("not equal", (new Object[]{new Object()}), (new Object[]{new Object()})); + assertArrayEqualsFailure( + "not equal", + new Object[]{"right"}, + new Object[]{"wrong"}, + "not equal: arrays first differed at element [0]; expected:<[right]> but was:<[wrong]>"); } @Test public void arraysExpectedNullMessage() { try { - assertArrayEquals("not equal", null, (new Object[]{new Object()})); + assertArrayEquals("not equal", null, new Object[]{new Object()}); } catch (AssertionError exception) { assertEquals("not equal: expected array was null", exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test public void arraysActualNullMessage() { try { - assertArrayEquals("not equal", (new Object[]{new Object()}), null); + assertArrayEquals("not equal", new Object[]{new Object()}, null); } catch (AssertionError exception) { assertEquals("not equal: actual array was null", exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @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()); - } + public void arraysDifferentLengthDifferingAtStartMessage() { + assertArrayEqualsFailure( + "not equal", + new Object[]{true}, + new Object[]{false, true}, + "not equal: array lengths differed, expected.length=1 actual.length=2; arrays first differed at element [0]; expected: but was:"); + } + + @Test + public void arraysDifferentLengthDifferingAtEndMessage() { + assertArrayEqualsFailure( + "not equal", + new Object[]{true}, + new Object[]{true, false}, + "not equal: array lengths differed, expected.length=1 actual.length=2; arrays first differed at element [1]; expected: but was:"); } - @Test(expected = ArrayComparisonFailure.class) + @Test + public void arraysDifferentLengthDifferingAtEndAndExpectedArrayLongerMessage() { + assertArrayEqualsFailure( + "not equal", + new Object[]{true, false}, + new Object[]{true}, + "not equal: array lengths differed, expected.length=2 actual.length=1; arrays first differed at element [1]; expected: but was:"); + } + + @Test 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"})); + assertArrayEqualsFailure( + "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"}, + "not equal: arrays first differed at element [0]; expected: but was:"); } @Test public void arraysDifferAtElement0nullMessage() { - try { - assertArrayEquals((new Object[]{true}), (new Object[]{false})); - } catch (AssertionError exception) { - assertEquals("arrays first differed at element [0]; expected: but was:", exception - .getMessage()); - } + assertArrayEqualsFailure( + new Object[]{true}, + new Object[]{false}, + "arrays first differed at element [0]; expected: but was:" + ); } @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: but was:", exception - .getMessage()); - } + assertArrayEqualsFailure( + new Object[]{true, true}, + new Object[]{true, false}, + "arrays first differed at element [1]; expected: but was:" + ); } @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: but was:", exception - .getMessage()); - } + assertArrayEqualsFailure( + "message", + new Object[]{true}, + new Object[]{false}, + "message: arrays first differed at element [0]; expected: but was:" + ); } @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: but was:", exception.getMessage()); - } + assertArrayEqualsFailure( + "message", + new Object[]{true, true}, + new Object[]{true, false}, + "message: arrays first differed at element [1]; expected: but was:" + ); } @Test @@ -170,7 +209,7 @@ public void oneDimensionalDoubleArraysAreNotEqual() { public void oneDimensionalFloatArraysAreNotEqual() { assertArrayEquals(new float[]{1.0f}, new float[]{2.5f}, 1.0f); } - + @Test(expected = AssertionError.class) public void oneDimensionalBooleanArraysAreNotEqual() { assertArrayEquals(new boolean[]{true}, new boolean[]{false}); @@ -193,22 +232,134 @@ public void multiDimensionalArraysDeclaredAsOneDimensionalAreEqual() { @Test public void multiDimensionalArraysAreNotEqual() { + assertArrayEqualsFailure( + "message", + new Object[][]{{true, true}, {false, false}}, + new Object[][]{{true, true}, {true, false}}, + "message: arrays first differed at element [1][0]; expected: but was:"); + } + + @Test + public void multiDimensionalArraysAreNotEqualNoMessage() { + assertArrayEqualsFailure( + new Object[][]{{true, true}, {false, false}}, + new Object[][]{{true, true}, {true, false}}, + "arrays first differed at element [1][0]; expected: but was:"); + } + + @Test + public void twoDimensionalArraysDifferentOuterLengthNotEqual() { + assertArrayEqualsFailure( + "not equal", + new Object[][]{{true}, {}}, + new Object[][]{{}}, + "not equal: array lengths differed, expected.length=1 actual.length=0; arrays first differed at element [0][0]; expected: but was:"); + assertArrayEqualsFailure( + "not equal", + new Object[][]{{}, {true}}, + new Object[][]{{}}, + "not equal: array lengths differed, expected.length=2 actual.length=1; arrays first differed at element [1]; expected: but was:"); + assertArrayEqualsFailure( + "not equal", + new Object[][]{{}}, + new Object[][]{{true}, {}}, + "not equal: array lengths differed, expected.length=0 actual.length=1; arrays first differed at element [0][0]; expected: but was:"); + assertArrayEqualsFailure( + "not equal", + new Object[][]{{}}, + new Object[][]{{}, {true}}, + "not equal: array lengths differed, expected.length=1 actual.length=2; arrays first differed at element [1]; expected: but was:"); + } + + @Test + public void primitiveArraysConvertedToStringCorrectly() { + assertArrayEqualsFailure( + "not equal", + new boolean[][]{{}, {true}}, + new boolean[][]{{}}, + "not equal: array lengths differed, expected.length=2 actual.length=1; arrays first differed at element [1]; expected: but was:"); + assertArrayEqualsFailure( + "not equal", + new int[][]{{}, {23}}, + new int[][]{{}}, + "not equal: array lengths differed, expected.length=2 actual.length=1; arrays first differed at element [1]; expected: but was:"); + } + + @Test + public void twoDimensionalArraysConvertedToStringCorrectly() { + assertArrayEqualsFailure( + "not equal", + new Object[][][]{{}, {{true}}}, + new Object[][][]{{}}, + "not equal: array lengths differed, expected.length=2 actual.length=1; arrays first differed at element [1]; expected: but was:"); + } + + @Test + public void twoDimensionalArraysDifferentInnerLengthNotEqual() { + assertArrayEqualsFailure( + "not equal", + new Object[][]{{true}, {}}, + new Object[][]{{}, {}}, + "not equal: array lengths differed, expected.length=1 actual.length=0; arrays first differed at element [0][0]; expected: but was:"); + assertArrayEqualsFailure( + "not equal", + new Object[][]{{}, {true}}, + new Object[][]{{}, {}}, + "not equal: array lengths differed, expected.length=1 actual.length=0; arrays first differed at element [1][0]; expected: but was:"); + assertArrayEqualsFailure( + "not equal", + new Object[][]{{}, {}}, + new Object[][]{{true}, {}}, + "not equal: array lengths differed, expected.length=0 actual.length=1; arrays first differed at element [0][0]; expected: but was:"); + assertArrayEqualsFailure( + "not equal", + new Object[][]{{}, {}}, + new Object[][]{{}, {true}}, + "not equal: array lengths differed, expected.length=0 actual.length=1; arrays first differed at element [1][0]; expected: but was:"); + } + + private void assertArrayEqualsFailure(Object[] expecteds, Object[] actuals, String expectedMessage) { try { - assertArrayEquals("message", (new Object[][]{{true, true}, {false, false}}), (new Object[][]{{true, true}, {true, false}})); - fail(); + assertArrayEquals(expecteds, actuals); + } catch (ArrayComparisonFailure e) { + assertEquals(expectedMessage, e.getMessage()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + private void assertArrayEqualsFailure(String message, Object[] expecteds, Object[] actuals, String expectedMessage) { + try { + assertArrayEquals(message, expecteds, actuals); + } catch (ArrayComparisonFailure e) { + assertEquals(expectedMessage, e.getMessage()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void multiDimensionalArraysDifferentLengthMessage() { + try { + assertArrayEquals("message", new Object[][]{{true, true}, {false, false}}, new Object[][]{{true, true}, {false}}); } catch (AssertionError exception) { - assertEquals("message: arrays first differed at element [1][0]; expected: but was:", exception.getMessage()); + assertEquals("message: array lengths differed, expected.length=2 actual.length=1; arrays first differed at element [1][1]; expected: but was:", exception.getMessage()); + return; } + + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test - public void multiDimensionalArraysAreNotEqualNoMessage() { + public void multiDimensionalArraysDifferentLengthNoMessage() { try { - assertArrayEquals((new Object[][]{{true, true}, {false, false}}), (new Object[][]{{true, true}, {true, false}})); - fail(); + assertArrayEquals(new Object[][]{{true, true}, {false, false}}, new Object[][]{{true, true}, {false}}); } catch (AssertionError exception) { - assertEquals("arrays first differed at element [1][0]; expected: but was:", exception.getMessage()); + assertEquals("array lengths differed, expected.length=2 actual.length=1; arrays first differed at element [1][1]; expected: but was:", exception.getMessage()); + return; } + + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -222,9 +373,11 @@ public void arraysWithNullElementEqual() { public void stringsDifferWithUserMessage() { try { assertEquals("not equal", "one", "two"); - } catch (Throwable exception) { + } catch (ComparisonFailure exception) { assertEquals("not equal expected:<[one]> but was:<[two]>", exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -273,10 +426,11 @@ public void notEqualsObjectWithNullWithMessage() { Object o = new Object(); try { assertEquals("message", null, o); - fail(); } catch (AssertionError e) { assertEquals("message expected: but was:<" + o.toString() + ">", e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -284,10 +438,11 @@ public void notEqualsNullWithObjectWithMessage() { Object o = new Object(); try { assertEquals("message", o, null); - fail(); } catch (AssertionError e) { assertEquals("message expected:<" + o.toString() + "> but was:", e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test(expected = AssertionError.class) @@ -366,24 +521,28 @@ public void naNsAreEqual() { assertEquals(Double.NaN, Double.NaN, Double.POSITIVE_INFINITY); } + @SuppressWarnings("unused") @Test public void nullNullmessage() { try { assertNull("junit"); - fail(); } catch (AssertionError e) { assertEquals("expected null, but was:", e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } + @SuppressWarnings("unused") @Test public void nullWithMessage() { try { assertNull("message", "hello"); - fail(); } catch (AssertionError exception) { assertEquals("message expected null, but was:", exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -414,21 +573,23 @@ public void objectsAreSame() { public void sameWithMessage() { try { assertSame("not same", "hello", "good-bye"); - fail(); } catch (AssertionError exception) { assertEquals("not same expected same: was not:", exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test public void sameNullMessage() { try { assertSame("hello", "good-bye"); - fail(); } catch (AssertionError exception) { assertEquals("expected same: was not:", exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -436,10 +597,11 @@ public void notSameWithMessage() { Object o = new Object(); try { assertNotSame("message", o, o); - fail(); } catch (AssertionError exception) { assertEquals("message expected not same", exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -447,10 +609,11 @@ public void notSameNullMessage() { Object o = new Object(); try { assertNotSame(o, o); - fail(); } catch (AssertionError exception) { assertEquals("expected not same", exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -460,27 +623,31 @@ public void nullMessage() { } catch (AssertionError exception) { // we used to expect getMessage() to return ""; see failWithNoMessageToString() assertNull(exception.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test public void nullMessageDisappearsWithStringAssertEquals() { try { assertEquals(null, "a", "b"); - fail(); } catch (ComparisonFailure e) { assertEquals("expected:<[a]> but was:<[b]>", e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test public void nullMessageDisappearsWithAssertEquals() { try { assertEquals(null, 1, 2); - fail(); } catch (AssertionError e) { assertEquals("expected:<1> but was:<2>", e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test(expected = AssertionError.class) @@ -514,7 +681,9 @@ public void errorMessageDistinguishesDifferentValuesWithSameToString() { assertEquals("4", new Integer(4)); } catch (AssertionError e) { assertEquals("expected: java.lang.String<4> but was: java.lang.Integer<4>", e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -528,7 +697,9 @@ public void assertThatIncludesDescriptionOfTestedValueInErrorMessage() { assertThat("identifier", actual, equalTo(expected)); } catch (AssertionError e) { assertEquals(expectedMessage, e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -539,7 +710,9 @@ public void assertThatIncludesAdvancedMismatch() { assertThat("identifier", "actual", is(instanceOf(Integer.class))); } catch (AssertionError e) { assertEquals(expectedMessage, e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -553,7 +726,9 @@ public void assertThatDescriptionCanBeElided() { assertThat(actual, equalTo(expected)); } catch (AssertionError e) { assertEquals(expectedMessage, e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -562,7 +737,9 @@ public void nullAndStringNullPrintCorrectError() { assertEquals(null, "null"); } catch (AssertionError e) { assertEquals("expected: null but was: java.lang.String", e.getMessage()); + return; } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test(expected = AssertionError.class) @@ -570,6 +747,27 @@ public void stringNullAndNullWorksToo() { assertEquals("null", null); } + private static class NullToString { + @Override + public String toString() { + return null; + } + } + + @Test + public void nullToString() { + try { + assertEquals(new NullToString(), new NullToString()); + } catch (AssertionError e) { + assertEquals("expected: org.junit.tests.assertion.AssertionTest$NullToString but " + + "was: org.junit.tests.assertion.AssertionTest$NullToString", + e.getMessage()); + return; + } + + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + @Test(expected = AssertionError.class) public void compareBigDecimalAndInteger() { final BigDecimal bigDecimal = new BigDecimal("1.2"); @@ -584,7 +782,7 @@ public void sameObjectIsNotEqual() { } @Test - public void objectsWithDiferentReferencesAreNotEqual() { + public void objectsWithDifferentReferencesAreNotEqual() { assertNotEquals(new Object(), new Object()); } @@ -601,7 +799,7 @@ public void assertNotEqualsIncludesCorrectMessage() { return; } - fail("Failed on assertion."); + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -616,7 +814,7 @@ public void assertNotEqualsIncludesTheValueBeingTested() { return; } - fail("Failed on assertion."); + throw new AssertionError(ASSERTION_ERROR_EXPECTED); } @Test @@ -648,4 +846,160 @@ public void assertNotEqualsIgnoresDeltaOnNaN() { public void assertNotEqualsIgnoresFloatDeltaOnNaN() { assertNotEquals(Float.NaN, Float.NaN, 1f); } + + @Test(expected = AssertionError.class) + public void assertThrowsRequiresAnExceptionToBeThrown() { + assertThrows(Throwable.class, nonThrowingRunnable()); + } + + @Test + public void assertThrowsIncludesAnInformativeDefaultMessage() { + try { + assertThrows(Throwable.class, nonThrowingRunnable()); + } catch (AssertionError ex) { + assertEquals("expected java.lang.Throwable to be thrown, but nothing was thrown", ex.getMessage()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsIncludesTheSpecifiedMessage() { + try { + assertThrows("Foobar", Throwable.class, nonThrowingRunnable()); + } catch (AssertionError ex) { + assertEquals( + "Foobar: expected java.lang.Throwable to be thrown, but nothing was thrown", + ex.getMessage()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsReturnsTheSameObjectThrown() { + NullPointerException npe = new NullPointerException(); + + Throwable throwable = assertThrows(Throwable.class, throwingRunnable(npe)); + + assertSame(npe, throwable); + } + + @Test(expected = AssertionError.class) + public void assertThrowsDetectsTypeMismatchesViaExplicitTypeHint() { + NullPointerException npe = new NullPointerException(); + + assertThrows(IOException.class, throwingRunnable(npe)); + } + + @Test + public void assertThrowsWrapsAndPropagatesUnexpectedExceptions() { + NullPointerException npe = new NullPointerException("inner-message"); + + try { + assertThrows(IOException.class, throwingRunnable(npe)); + } catch (AssertionError ex) { + assertSame(npe, ex.getCause()); + assertEquals("inner-message", ex.getCause().getMessage()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsSuppliesACoherentErrorMessageUponTypeMismatch() { + NullPointerException npe = new NullPointerException(); + + try { + assertThrows(IOException.class, throwingRunnable(npe)); + } catch (AssertionError error) { + assertEquals("unexpected exception type thrown; expected: but was:", + error.getMessage()); + assertSame(npe, error.getCause()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsSuppliesTheSpecifiedMessageUponTypeMismatch() { + NullPointerException npe = new NullPointerException(); + + try { + assertThrows("Foobar", IOException.class, throwingRunnable(npe)); + } catch (AssertionError error) { + assertEquals("Foobar: unexpected exception type thrown; expected: but was:", + error.getMessage()); + assertSame(npe, error.getCause()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsUsesCanonicalNameUponTypeMismatch() { + NullPointerException npe = new NullPointerException(); + + try { + assertThrows(NestedException.class, throwingRunnable(npe)); + } catch (AssertionError error) { + assertEquals( + "unexpected exception type thrown; expected:" + + " but was:", + error.getMessage()); + assertSame(npe, error.getCause()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsUsesNameUponTypeMismatchWithAnonymousClass() { + NullPointerException npe = new NullPointerException() { + }; + + try { + assertThrows(IOException.class, throwingRunnable(npe)); + } catch (AssertionError error) { + assertEquals( + "unexpected exception type thrown; expected:" + + " but was:", + error.getMessage()); + assertSame(npe, error.getCause()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsUsesCanonicalNameWhenRequiredExceptionNotThrown() { + try { + assertThrows(NestedException.class, nonThrowingRunnable()); + } catch (AssertionError error) { + assertEquals( + "expected org.junit.tests.assertion.AssertionTest.NestedException to be thrown," + + " but nothing was thrown", error.getMessage()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + private static class NestedException extends RuntimeException { + private static final long serialVersionUID = 1L; + } + + private static ThrowingRunnable nonThrowingRunnable() { + return new ThrowingRunnable() { + public void run() throws Throwable { + } + }; + } + + private static ThrowingRunnable throwingRunnable(final Throwable t) { + return new ThrowingRunnable() { + public void run() throws Throwable { + throw t; + } + }; + } } diff --git a/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java b/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java index 0c5e2d532852..18880b714e2d 100644 --- a/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java +++ b/src/test/java/org/junit/tests/assertion/MultipleFailureExceptionTest.java @@ -1,8 +1,10 @@ package org.junit.tests.assertion; +import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -11,15 +13,20 @@ import java.util.Collections; import java.util.List; +import org.hamcrest.CoreMatchers; import org.junit.Test; +import org.junit.TestCouldNotBeSkippedException; +import org.junit.internal.AssumptionViolatedException; import org.junit.runners.model.MultipleFailureException; + /** * Tests for {@link org.junit.runners.model.MultipleFailureException} * * @author kcooney@google.com (Kevin Cooney) */ public class MultipleFailureExceptionTest { + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); @Test public void assertEmptyDoesNotThrowForEmptyList() throws Exception { @@ -37,7 +44,7 @@ public void assertEmptyRethrowsSingleRuntimeException() throws Exception { assertSame(e, exception); } } - + @Test public void assertEmptyRethrowsSingleError() throws Exception { Throwable exception= new AnnotationFormatError("changeo"); @@ -51,7 +58,7 @@ public void assertEmptyRethrowsSingleError() throws Exception { } @Test - public void assertEmptyThrowsMutipleFailureExceptionForManyThrowables() throws Exception { + public void assertEmptyThrowsMultipleFailureExceptionForManyThrowables() throws Exception { List errors = new ArrayList(); errors.add(new ExpectedException("basil")); errors.add(new RuntimeException("garlic")); @@ -61,12 +68,45 @@ public void assertEmptyThrowsMutipleFailureExceptionForManyThrowables() throws E 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().startsWith("There were 2 errors:" + LINE_SEPARATOR)); + assertTrue(expected.getMessage().contains("ExpectedException(basil)" + LINE_SEPARATOR)); assertTrue(expected.getMessage().contains("RuntimeException(garlic)")); } } + @Test + public void assertEmptyErrorListConstructorFailure() { + try { + new MultipleFailureException(Collections.emptyList()); + fail(); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage(), + containsString("List of Throwables must not be empty")); + } + } + + @Test + public void assertEmptyWrapsAssumptionFailuresForManyThrowables() throws Exception { + List errors = new ArrayList(); + AssumptionViolatedException assumptionViolatedException = new AssumptionViolatedException("skip it"); + errors.add(assumptionViolatedException); + errors.add(new RuntimeException("garlic")); + + try { + MultipleFailureException.assertEmpty(errors); + fail(); + } catch (MultipleFailureException expected) { + assertThat(expected.getFailures().size(), equalTo(2)); + assertTrue(expected.getMessage().startsWith("There were 2 errors:" + LINE_SEPARATOR)); + assertTrue(expected.getMessage().contains("TestCouldNotBeSkippedException(Test could not be skipped")); + assertTrue(expected.getMessage().contains("RuntimeException(garlic)")); + Throwable first = expected.getFailures().get(0); + assertThat(first, instanceOf(TestCouldNotBeSkippedException.class)); + Throwable cause = ((TestCouldNotBeSkippedException) first).getCause(); + assertThat(cause, instanceOf(AssumptionViolatedException.class)); + assertThat((AssumptionViolatedException) cause, CoreMatchers.sameInstance(assumptionViolatedException)); + } + } private static class ExpectedException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/src/test/java/org/junit/tests/deprecated/AllDeprecatedTests.java b/src/test/java/org/junit/tests/deprecated/AllDeprecatedTests.java new file mode 100644 index 000000000000..4e1a3f42548d --- /dev/null +++ b/src/test/java/org/junit/tests/deprecated/AllDeprecatedTests.java @@ -0,0 +1,13 @@ +package org.junit.tests.deprecated; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@SuppressWarnings("deprecation") +@RunWith(Suite.class) +@SuiteClasses({ + JUnit4ClassRunnerTest.class +}) +public class AllDeprecatedTests { +} diff --git a/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java b/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java index 43983ba97637..c0c081d49279 100644 --- a/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java +++ b/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java @@ -1,7 +1,7 @@ package org.junit.tests.deprecated; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; import org.junit.Test; diff --git a/src/test/java/org/junit/tests/description/AllDescriptionTests.java b/src/test/java/org/junit/tests/description/AllDescriptionTests.java new file mode 100644 index 000000000000..6de5efb4e550 --- /dev/null +++ b/src/test/java/org/junit/tests/description/AllDescriptionTests.java @@ -0,0 +1,15 @@ +package org.junit.tests.description; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + AnnotatedDescriptionTest.class, + SuiteDescriptionTest.class, + TestDescriptionMethodNameTest.class, + TestDescriptionTest.class +}) +public class AllDescriptionTests { +} diff --git a/src/test/java/org/junit/tests/experimental/AllExperimentalTests.java b/src/test/java/org/junit/tests/experimental/AllExperimentalTests.java new file mode 100644 index 000000000000..b20ae9d0aa25 --- /dev/null +++ b/src/test/java/org/junit/tests/experimental/AllExperimentalTests.java @@ -0,0 +1,25 @@ +package org.junit.tests.experimental; + +import org.junit.experimental.categories.AllCategoriesTests; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; +import org.junit.tests.experimental.max.AllMaxTests; +import org.junit.tests.experimental.parallel.AllParallelTests; +import org.junit.tests.experimental.results.AllResultsTests; +import org.junit.tests.experimental.theories.AllTheoriesTests; +import org.junit.tests.experimental.theories.extendingwithstubs.StubbedTheoriesTest; + +@RunWith(Suite.class) +@SuiteClasses({ + AllCategoriesTests.class, + AllMaxTests.class, + AllParallelTests.class, + AllResultsTests.class, + AllTheoriesTests.class, + AssumptionTest.class, + MatcherTest.class, + StubbedTheoriesTest.class +}) +public class AllExperimentalTests { +} diff --git a/src/test/java/org/junit/tests/experimental/AssumptionTest.java b/src/test/java/org/junit/tests/experimental/AssumptionTest.java index 8d2d0a07fd62..45e94b026edc 100644 --- a/src/test/java/org/junit/tests/experimental/AssumptionTest.java +++ b/src/test/java/org/junit/tests/experimental/AssumptionTest.java @@ -2,9 +2,9 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeNoException; @@ -77,9 +77,14 @@ public void passingAssumptionsScootThrough() { assertThat(result.getFailureCount(), is(1)); } - @Test(expected = AssumptionViolatedException.class) + @Test public void assumeThatWorks() { - assumeThat(1, is(2)); + try { + assumeThat(1, is(2)); + fail("should throw AssumptionViolatedException"); + } catch (AssumptionViolatedException e) { + // expected + } } @Test @@ -94,10 +99,25 @@ public void assumeThatPassesOnStrings() { assertCompletesNormally(); } - @Test(expected = AssumptionViolatedException.class) + @Test public void assumeNotNullThrowsException() { Object[] objects = {1, 2, null}; - assumeNotNull(objects); + try { + assumeNotNull(objects); + fail("should throw AssumptionViolatedException"); + } catch (AssumptionViolatedException e) { + // expected + } + } + + @Test + public void assumeNotNullThrowsExceptionForNullArray() { + try { + assumeNotNull((Object[]) null); + fail("should throw AssumptionViolatedException"); + } catch (AssumptionViolatedException e) { + // expected + } } @Test @@ -133,9 +153,24 @@ public void assumeNoExceptionThrows() { private void assertCompletesNormally() { } - @Test(expected = AssumptionViolatedException.class) + @Test public void assumeTrueWorks() { - Assume.assumeTrue(false); + try { + Assume.assumeTrue(false); + fail("should throw AssumptionViolatedException"); + } catch (AssumptionViolatedException e) { + assertEquals("got: , expected: is ", e.getMessage()); + } + } + + @Test + public void assumeFalseWorks() { + try { + Assume.assumeFalse(true); + fail("should throw AssumptionViolatedException"); + } catch (AssumptionViolatedException e) { + assertEquals("got: , expected: is ", e.getMessage()); + } } public static class HasFailingAssumeInBefore { @@ -188,9 +223,18 @@ public void failingAssumptionInConstructorIgnoresClass() { assertThat(testResult(AssumptionFailureInConstructor.class), isSuccessful()); } - @Test(expected = IllegalArgumentException.class) - public void assumeWithExpectedException() { - assumeTrue(false); + public static class TestClassWithAssumptionFailure { + + @Test(expected = IllegalArgumentException.class) + public void assumeWithExpectedException() { + assumeTrue(false); + } + } + + @Test + public void assumeWithExpectedExceptionShouldThrowAssumptionViolatedException() { + Result result = JUnitCore.runClasses(TestClassWithAssumptionFailure.class); + assertThat(result.getAssumptionFailureCount(), is(1)); } final static String message = "Some random message string."; @@ -245,7 +289,7 @@ public void failedAssumptionsWithMessage() { final List failures = runAndGetAssumptionFailures(HasFailingAssumptionWithMessage.class); - assertEquals(failures.size(), 1); + assertEquals(1, failures.size()); assertTrue(failures.get(0).getMessage().contains(message)); } diff --git a/src/test/java/org/junit/tests/experimental/ExperimentalTests.java b/src/test/java/org/junit/tests/experimental/ExperimentalTests.java deleted file mode 100644 index 953d156ea47b..000000000000 --- a/src/test/java/org/junit/tests/experimental/ExperimentalTests.java +++ /dev/null @@ -1,37 +0,0 @@ -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.extendingwithstubs.StubbedTheoriesTest; -import org.junit.tests.experimental.theories.internal.AllMembersSupplierTest; -import org.junit.tests.experimental.theories.internal.ParameterizedAssertionErrorTest; -import org.junit.tests.experimental.theories.internal.SpecificDataPointsSupplierTest; -import org.junit.tests.experimental.theories.runner.SuccessfulWithDataPointFields; -import org.junit.tests.experimental.theories.runner.UnsuccessfulWithDataPointFields; -import org.junit.tests.experimental.theories.runner.WhenNoParametersMatch; -import org.junit.tests.experimental.theories.runner.WithAutoGeneratedDataPoints; -import org.junit.tests.experimental.theories.runner.WithDataPointMethod; -import org.junit.tests.experimental.theories.runner.WithExtendedParameterSources; -import org.junit.tests.experimental.theories.runner.WithNamedDataPoints; -import org.junit.tests.experimental.theories.runner.WithOnlyTestAnnotations; -import org.junit.tests.experimental.theories.runner.WithUnresolvedGenericTypeVariablesOnTheoryParms; - -@RunWith(Suite.class) -@SuiteClasses({ParameterizedAssertionErrorTest.class, - AllMembersSupplierTest.class, - SpecificDataPointsSupplierTest.class, - UnsuccessfulWithDataPointFields.class, - SuccessfulWithDataPointFields.class, PrintableResultTest.class, - ResultMatchersTest.class, WithDataPointMethod.class, - ParameterSignatureTest.class, WhenNoParametersMatch.class, - WithExtendedParameterSources.class, StubbedTheoriesTest.class, - WithOnlyTestAnnotations.class, WithNamedDataPoints.class, - WithUnresolvedGenericTypeVariablesOnTheoryParms.class, - WithAutoGeneratedDataPoints.class}) -public class ExperimentalTests { - -} diff --git a/src/test/java/org/junit/tests/experimental/MatcherTest.java b/src/test/java/org/junit/tests/experimental/MatcherTest.java index 6a1eb42b7c17..10f13a4eafaf 100644 --- a/src/test/java/org/junit/tests/experimental/MatcherTest.java +++ b/src/test/java/org/junit/tests/experimental/MatcherTest.java @@ -1,7 +1,7 @@ package org.junit.tests.experimental; import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assume.assumeThat; import static org.junit.experimental.results.ResultMatchers.hasFailureContaining; import static org.junit.experimental.results.ResultMatchers.hasSingleFailureContaining; diff --git a/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java b/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java deleted file mode 100644 index d01e5a7fbe9f..000000000000 --- a/src/test/java/org/junit/tests/experimental/categories/CategoriesAndParameterizedTest.java +++ /dev/null @@ -1,123 +0,0 @@ -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 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 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 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/src/test/java/org/junit/tests/experimental/max/AllMaxTests.java b/src/test/java/org/junit/tests/experimental/max/AllMaxTests.java new file mode 100644 index 000000000000..d78ca3643a27 --- /dev/null +++ b/src/test/java/org/junit/tests/experimental/max/AllMaxTests.java @@ -0,0 +1,14 @@ +package org.junit.tests.experimental.max; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + DescriptionTest.class, + JUnit38SortingTest.class, + MaxStarterTest.class +}) +public class AllMaxTests { +} diff --git a/src/test/java/org/junit/tests/experimental/max/DescriptionTest.java b/src/test/java/org/junit/tests/experimental/max/DescriptionTest.java index 4d2396ad5cbf..607bb8157d95 100644 --- a/src/test/java/org/junit/tests/experimental/max/DescriptionTest.java +++ b/src/test/java/org/junit/tests/experimental/max/DescriptionTest.java @@ -2,9 +2,9 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; import java.lang.annotation.Annotation; import java.net.URL; diff --git a/src/test/java/org/junit/tests/experimental/max/MaxStarterTest.java b/src/test/java/org/junit/tests/experimental/max/MaxStarterTest.java index 7f159226973c..d1bde455cac9 100644 --- a/src/test/java/org/junit/tests/experimental/max/MaxStarterTest.java +++ b/src/test/java/org/junit/tests/experimental/max/MaxStarterTest.java @@ -2,8 +2,8 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -248,8 +248,6 @@ private void testNothing() { } } - String fMessage = null; - @Test public void correctErrorFromMalformedTest() { Request request = Request.aClass(MalformedJUnit38TestMethod.class); diff --git a/src/test/java/org/junit/tests/experimental/parallel/AllParallelTests.java b/src/test/java/org/junit/tests/experimental/parallel/AllParallelTests.java new file mode 100644 index 000000000000..ef21dd23b66f --- /dev/null +++ b/src/test/java/org/junit/tests/experimental/parallel/AllParallelTests.java @@ -0,0 +1,13 @@ +package org.junit.tests.experimental.parallel; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + ParallelClassTest.class, + ParallelMethodTest.class +}) +public class AllParallelTests { +} diff --git a/src/test/java/org/junit/tests/experimental/parallel/ParallelClassTest.java b/src/test/java/org/junit/tests/experimental/parallel/ParallelClassTest.java index 1752c0df1be1..86a2646af84f 100644 --- a/src/test/java/org/junit/tests/experimental/parallel/ParallelClassTest.java +++ b/src/test/java/org/junit/tests/experimental/parallel/ParallelClassTest.java @@ -2,8 +2,8 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.concurrent.CountDownLatch; diff --git a/src/test/java/org/junit/tests/experimental/parallel/ParallelMethodTest.java b/src/test/java/org/junit/tests/experimental/parallel/ParallelMethodTest.java index 053e2f5a4eb4..fd4b4de99640 100644 --- a/src/test/java/org/junit/tests/experimental/parallel/ParallelMethodTest.java +++ b/src/test/java/org/junit/tests/experimental/parallel/ParallelMethodTest.java @@ -2,8 +2,8 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.concurrent.CountDownLatch; diff --git a/src/test/java/org/junit/tests/experimental/results/AllResultsTests.java b/src/test/java/org/junit/tests/experimental/results/AllResultsTests.java new file mode 100644 index 000000000000..f1975696b3d9 --- /dev/null +++ b/src/test/java/org/junit/tests/experimental/results/AllResultsTests.java @@ -0,0 +1,13 @@ +package org.junit.tests.experimental.results; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + PrintableResultTest.class, + ResultMatchersTest.class +}) +public class AllResultsTests { +} diff --git a/src/test/java/org/junit/tests/experimental/results/PrintableResultTest.java b/src/test/java/org/junit/tests/experimental/results/PrintableResultTest.java index ba9ae3d5f141..3a6e366b53b5 100644 --- a/src/test/java/org/junit/tests/experimental/results/PrintableResultTest.java +++ b/src/test/java/org/junit/tests/experimental/results/PrintableResultTest.java @@ -3,7 +3,7 @@ import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import java.util.Arrays; diff --git a/src/test/java/org/junit/tests/experimental/results/ResultMatchersTest.java b/src/test/java/org/junit/tests/experimental/results/ResultMatchersTest.java index 024fe32b09fa..768bfbab64c0 100644 --- a/src/test/java/org/junit/tests/experimental/results/ResultMatchersTest.java +++ b/src/test/java/org/junit/tests/experimental/results/ResultMatchersTest.java @@ -1,14 +1,21 @@ package org.junit.tests.experimental.results; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - import org.junit.Test; +import org.junit.experimental.results.PrintableResult; import org.junit.experimental.results.ResultMatchers; import org.junit.experimental.theories.Theory; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; + +import java.util.ArrayList; +import java.util.Collections; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; public class ResultMatchersTest { + @Test public void hasFailuresHasGoodDescription() { assertThat(ResultMatchers.failureCountIs(3).toString(), @@ -20,4 +27,20 @@ public void hasFailuresDescriptionReflectsInput(int i) { assertThat(ResultMatchers.failureCountIs(i).toString(), containsString("" + i)); } + + @Test + public void hasFailureContaining_givenResultWithNoFailures() { + PrintableResult resultWithNoFailures = new PrintableResult(new ArrayList()); + + assertThat(ResultMatchers.hasFailureContaining("").matches(resultWithNoFailures), is(false)); + } + + @Test + public void hasFailureContaining_givenResultWithOneFailure() { + PrintableResult resultWithOneFailure = new PrintableResult(Collections.singletonList( + new Failure(Description.EMPTY, new RuntimeException("my failure")))); + + assertThat(ResultMatchers.hasFailureContaining("my failure").matches(resultWithOneFailure), is(true)); + assertThat(ResultMatchers.hasFailureContaining("his failure").matches(resultWithOneFailure), is(false)); + } } diff --git a/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java b/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java deleted file mode 100644 index 5a6274813ae3..000000000000 --- a/src/test/java/org/junit/tests/experimental/rules/BlockJUnit4ClassRunnerOverrideTest.java +++ /dev/null @@ -1,92 +0,0 @@ -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; - -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 rules(Object test) { - final LinkedList methodRules = new LinkedList( - 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 getTestRules(final Object test) { - final LinkedList methodRules = new LinkedList( - 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/src/test/java/org/junit/tests/experimental/rules/ExternalResourceRuleTest.java b/src/test/java/org/junit/tests/experimental/rules/ExternalResourceRuleTest.java deleted file mode 100644 index 4ef1c1c8c5bb..000000000000 --- a/src/test/java/org/junit/tests/experimental/rules/ExternalResourceRuleTest.java +++ /dev/null @@ -1,45 +0,0 @@ -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/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java b/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java deleted file mode 100644 index af8f81f5bb77..000000000000 --- a/src/test/java/org/junit/tests/experimental/rules/TestWatcherTest.java +++ /dev/null @@ -1,191 +0,0 @@ -package org.junit.tests.experimental.rules; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeTrue; -import static org.junit.experimental.results.PrintableResult.testResult; -import static org.junit.experimental.results.ResultMatchers.failureCountIs; -import static org.junit.experimental.results.ResultMatchers.hasFailureContaining; -import static org.junit.runner.JUnitCore.runClasses; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.results.PrintableResult; -import org.junit.internal.AssumptionViolatedException; -import org.junit.rules.TestRule; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -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 skipped finished ")); - } - - public static class InternalViolatedAssumptionTest { - private static StringBuilder watchedLog = new StringBuilder(); - - @Rule - public TestRule watcher = new TestWatcher() { - @Override - protected void starting(Description description) { - watchedLog.append("starting "); - } - - @Override - protected void finished(Description description) { - watchedLog.append("finished "); - } - - protected void skipped(AssumptionViolatedException e, Description description) { - watchedLog.append("skipped "); - } - }; - - @Test - public void succeeds() { - throw new AssumptionViolatedException("don't run"); - } - } - - @Test - public void internalViolatedAssumption() { - InternalViolatedAssumptionTest.watchedLog = new StringBuilder(); - runClasses(InternalViolatedAssumptionTest.class); - assertThat(InternalViolatedAssumptionTest.watchedLog.toString(), - is("starting skipped finished ")); - } - - public static class TestWatcherSkippedThrowsExceptionTest { - @Rule - public TestRule watcher = new TestWatcher() { - @Override - protected void skipped(AssumptionViolatedException e, Description description) { - throw new RuntimeException("watcher failure"); - } - }; - - @Test - public void fails() { - throw new AssumptionViolatedException("test failure"); - } - } - - @Test - public void testWatcherSkippedThrowsException() { - PrintableResult result = testResult(TestWatcherSkippedThrowsExceptionTest.class); - assertThat(result, failureCountIs(2)); - assertThat(result, hasFailureContaining("test failure")); - assertThat(result, hasFailureContaining("watcher failure")); - } - - 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 ")); - } - - public static class TestWatcherFailedThrowsExceptionTest { - @Rule - public TestRule watcher = new TestWatcher() { - @Override - protected void failed(Throwable e, Description description) { - throw new RuntimeException("watcher failure"); - } - }; - - @Test - public void fails() { - throw new IllegalArgumentException("test failure"); - } - } - - @Test - public void testWatcherFailedThrowsException() { - PrintableResult result = testResult(TestWatcherFailedThrowsExceptionTest.class); - assertThat(result, failureCountIs(2)); - assertThat(result, hasFailureContaining("test failure")); - assertThat(result, hasFailureContaining("watcher failure")); - } - - public static class TestWatcherStartingThrowsExceptionTest { - @Rule - public TestRule watcher = new TestWatcher() { - @Override - protected void starting(Description description) { - throw new RuntimeException("watcher failure"); - } - }; - - @Test - public void fails() { - throw new IllegalArgumentException("test failure"); - } - } - - @Test - public void testWatcherStartingThrowsException() { - PrintableResult result = testResult(TestWatcherStartingThrowsExceptionTest.class); - assertThat(result, failureCountIs(2)); - assertThat(result, hasFailureContaining("test failure")); - assertThat(result, hasFailureContaining("watcher failure")); - } - - public static class TestWatcherFailedAndFinishedThrowsExceptionTest { - @Rule - public TestRule watcher = new TestWatcher() { - @Override - protected void failed(Throwable e, Description description) { - throw new RuntimeException("watcher failed failure"); - } - - @Override - protected void finished(Description description) { - throw new RuntimeException("watcher finished failure"); - } - }; - - @Test - public void fails() { - throw new IllegalArgumentException("test failure"); - } - } - - @Test - public void testWatcherFailedAndFinishedThrowsException() { - PrintableResult result = testResult(TestWatcherFailedAndFinishedThrowsExceptionTest.class); - assertThat(result, failureCountIs(3)); - assertThat(result, hasFailureContaining("test failure")); - assertThat(result, hasFailureContaining("watcher failed failure")); - assertThat(result, hasFailureContaining("watcher finished failure")); - } -} diff --git a/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java b/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java deleted file mode 100644 index f02dcb73e9b1..000000000000 --- a/src/test/java/org/junit/tests/experimental/rules/VerifierRuleTest.java +++ /dev/null @@ -1,151 +0,0 @@ -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("was <3>")); - assertThat(testResult, hasFailureContaining("was <5>")); - assertThat(testResult, hasFailureContaining("reason 1")); - assertThat(testResult, hasFailureContaining("was <7>")); - assertThat(testResult, hasFailureContaining("reason 2")); - assertThat(testResult, hasFailureContaining("was <9>")); - } - - public static class UsesErrorCollectorCheckSucceeds { - @Rule - public ErrorCollector collector = new ErrorCollector(); - - @Test - public void example() { - collector.checkSucceeds(new Callable() { - public Object call() throws Exception { - throw new RuntimeException("first!"); - } - }); - collector.checkSucceeds(new Callable() { - public Integer call() throws Exception { - throw new RuntimeException("second!"); - } - }); - Integer result = collector.checkSucceeds(new Callable() { - public Integer call() throws Exception { - return 1; - } - }); - assertEquals(Integer.valueOf(1), result); - } - } - - @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() { - 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/src/test/java/org/junit/tests/experimental/theories/AllTheoriesTests.java b/src/test/java/org/junit/tests/experimental/theories/AllTheoriesTests.java new file mode 100644 index 000000000000..41d653bcf77a --- /dev/null +++ b/src/test/java/org/junit/tests/experimental/theories/AllTheoriesTests.java @@ -0,0 +1,19 @@ +package org.junit.tests.experimental.theories; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; +import org.junit.tests.experimental.theories.internal.AllTheoriesInternalTests; +import org.junit.tests.experimental.theories.runner.AllTheoriesRunnerTests; + +@RunWith(Suite.class) +@SuiteClasses({ + AllTheoriesInternalTests.class, + AllTheoriesRunnerTests.class, + ParameterSignatureTest.class, + TestedOnSupplierTest.class, + AssumingInTheoriesTest.class, + PotentialAssignmentTest.class +}) +public class AllTheoriesTests { +} diff --git a/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java b/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java index edfcdd1c841b..cf786ba6b73b 100644 --- a/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java +++ b/src/test/java/org/junit/tests/experimental/theories/ParameterSignatureTest.java @@ -1,8 +1,8 @@ package org.junit.tests.experimental.theories; import static org.hamcrest.CoreMatchers.isA; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; diff --git a/src/test/java/org/junit/tests/experimental/theories/TestedOnSupplierTest.java b/src/test/java/org/junit/tests/experimental/theories/TestedOnSupplierTest.java index 90fcd461dd86..137617121b2d 100644 --- a/src/test/java/org/junit/tests/experimental/theories/TestedOnSupplierTest.java +++ b/src/test/java/org/junit/tests/experimental/theories/TestedOnSupplierTest.java @@ -1,7 +1,7 @@ package org.junit.tests.experimental.theories; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import java.lang.reflect.Method; import java.util.List; diff --git a/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java b/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java index abecdf792708..a86bcd69bdea 100644 --- a/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java +++ b/src/test/java/org/junit/tests/experimental/theories/extendingwithstubs/StubbedTheoriesTest.java @@ -1 +1,16 @@ -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 +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")); + } +} diff --git a/src/test/java/org/junit/tests/experimental/theories/internal/AllMembersSupplierTest.java b/src/test/java/org/junit/tests/experimental/theories/internal/AllMembersSupplierTest.java index a3ee3635bd48..64e77b1e668a 100644 --- a/src/test/java/org/junit/tests/experimental/theories/internal/AllMembersSupplierTest.java +++ b/src/test/java/org/junit/tests/experimental/theories/internal/AllMembersSupplierTest.java @@ -1,9 +1,9 @@ package org.junit.tests.experimental.theories.internal; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertThat; import static org.junit.tests.experimental.theories.TheoryTestUtils.potentialAssignments; import java.util.Arrays; diff --git a/src/test/java/org/junit/tests/experimental/theories/internal/AllTheoriesInternalTests.java b/src/test/java/org/junit/tests/experimental/theories/internal/AllTheoriesInternalTests.java new file mode 100644 index 000000000000..7c87afa35e7d --- /dev/null +++ b/src/test/java/org/junit/tests/experimental/theories/internal/AllTheoriesInternalTests.java @@ -0,0 +1,14 @@ +package org.junit.tests.experimental.theories.internal; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + AllMembersSupplierTest.class, + ParameterizedAssertionErrorTest.class, + SpecificDataPointsSupplierTest.class +}) +public class AllTheoriesInternalTests { +} diff --git a/src/test/java/org/junit/tests/experimental/theories/internal/ParameterizedAssertionErrorTest.java b/src/test/java/org/junit/tests/experimental/theories/internal/ParameterizedAssertionErrorTest.java index 2d42d992c3c2..285ebf522379 100644 --- a/src/test/java/org/junit/tests/experimental/theories/internal/ParameterizedAssertionErrorTest.java +++ b/src/test/java/org/junit/tests/experimental/theories/internal/ParameterizedAssertionErrorTest.java @@ -3,7 +3,7 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assume.assumeThat; diff --git a/src/test/java/org/junit/tests/experimental/theories/internal/SpecificDataPointsSupplierTest.java b/src/test/java/org/junit/tests/experimental/theories/internal/SpecificDataPointsSupplierTest.java index 3ccf902c9bcf..1ba6136a2150 100644 --- a/src/test/java/org/junit/tests/experimental/theories/internal/SpecificDataPointsSupplierTest.java +++ b/src/test/java/org/junit/tests/experimental/theories/internal/SpecificDataPointsSupplierTest.java @@ -2,8 +2,8 @@ import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/AllTheoriesRunnerTests.java b/src/test/java/org/junit/tests/experimental/theories/runner/AllTheoriesRunnerTests.java new file mode 100644 index 000000000000..26465caecc9a --- /dev/null +++ b/src/test/java/org/junit/tests/experimental/theories/runner/AllTheoriesRunnerTests.java @@ -0,0 +1,24 @@ +package org.junit.tests.experimental.theories.runner; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + FailingDataPointMethods.class, + SuccessfulWithDataPointFields.class, + TheoriesPerformanceTest.class, + TypeMatchingBetweenMultiDataPointsMethod.class, + UnsuccessfulWithDataPointFields.class, + WhenNoParametersMatch.class, + WithAutoGeneratedDataPoints.class, + WithDataPointMethod.class, + WithExtendedParameterSources.class, + WithNamedDataPoints.class, + WithOnlyTestAnnotations.class, + WithParameterSupplier.class, + WithUnresolvedGenericTypeVariablesOnTheoryParms.class +}) +public class AllTheoriesRunnerTests { +} diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/FailingDataPointMethods.java b/src/test/java/org/junit/tests/experimental/theories/runner/FailingDataPointMethods.java index 5abc0ea480fb..f69e5023686c 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/FailingDataPointMethods.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/FailingDataPointMethods.java @@ -1,7 +1,7 @@ package org.junit.tests.experimental.theories.runner; import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.experimental.results.PrintableResult.testResult; import static org.junit.experimental.results.ResultMatchers.isSuccessful; import org.junit.Test; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/SuccessfulWithDataPointFields.java b/src/test/java/org/junit/tests/experimental/theories/runner/SuccessfulWithDataPointFields.java index 41d766a7e9ab..2b5d587be21c 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/SuccessfulWithDataPointFields.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/SuccessfulWithDataPointFields.java @@ -1,8 +1,8 @@ package org.junit.tests.experimental.theories.runner; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/TheoriesPerformanceTest.java b/src/test/java/org/junit/tests/experimental/theories/runner/TheoriesPerformanceTest.java index 8136493a90a9..9275524777d1 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/TheoriesPerformanceTest.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/TheoriesPerformanceTest.java @@ -1,6 +1,6 @@ package org.junit.tests.experimental.theories.runner; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assume.assumeTrue; import static org.junit.experimental.results.PrintableResult.testResult; import static org.junit.experimental.results.ResultMatchers.isSuccessful; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/TypeMatchingBetweenMultiDataPointsMethod.java b/src/test/java/org/junit/tests/experimental/theories/runner/TypeMatchingBetweenMultiDataPointsMethod.java index 8232a902790c..4b7e87847f4c 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/TypeMatchingBetweenMultiDataPointsMethod.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/TypeMatchingBetweenMultiDataPointsMethod.java @@ -1,6 +1,6 @@ package org.junit.tests.experimental.theories.runner; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.experimental.results.PrintableResult.testResult; import static org.junit.experimental.results.ResultMatchers.isSuccessful; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java b/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java index e752d144bc58..57dec2d396ad 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/UnsuccessfulWithDataPointFields.java @@ -2,10 +2,8 @@ import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.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 org.hamcrest.CoreMatchers; @@ -121,11 +119,8 @@ public void numbers(int x) { public void dataPointFieldsMustBeStatic() { assertThat( testResult(DataPointFieldsMustBeStatic.class), - CoreMatchers.both(failureCountIs(2)) - .and( - hasFailureContaining("DataPoint field THREE must be static")) - .and( - hasFailureContaining("DataPoint field FOURS must be static"))); + CoreMatchers.both(hasFailureContaining("DataPoint field THREE must be static")) + .and(hasFailureContaining("DataPoint field FOURS must be static"))); } @RunWith(Theories.class) @@ -150,8 +145,7 @@ public void numbers(int x) { public void dataPointMethodsMustBeStatic() { assertThat( testResult(DataPointMethodsMustBeStatic.class), - CoreMatchers.both(failureCountIs(2)) - .and( + CoreMatchers.both( hasFailureContaining("DataPoint method singleDataPointMethod must be static")) .and( hasFailureContaining("DataPoint method dataPointArrayMethod must be static"))); @@ -186,7 +180,6 @@ public void numbers(int x) { @Test public void dataPointFieldsMustBePublic() { PrintableResult result = testResult(DataPointFieldsMustBePublic.class); - assertEquals(6, result.failureCount()); assertThat(result, allOf(hasFailureContaining("DataPoint field THREE must be public"), @@ -238,7 +231,6 @@ public void numbers(int x) { @Test public void dataPointMethodsMustBePublic() { PrintableResult result = testResult(DataPointMethodsMustBePublic.class); - assertEquals(6, result.failureCount()); assertThat(result, allOf(hasFailureContaining("DataPoint method three must be public"), diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WhenNoParametersMatch.java b/src/test/java/org/junit/tests/experimental/theories/runner/WhenNoParametersMatch.java index 17afed98029b..a8e3a847dc89 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/WhenNoParametersMatch.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/WhenNoParametersMatch.java @@ -3,7 +3,7 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assume.assumeThat; import static org.junit.experimental.results.PrintableResult.testResult; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithAutoGeneratedDataPoints.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithAutoGeneratedDataPoints.java index 26eb5156e43b..53cab0489744 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/WithAutoGeneratedDataPoints.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithAutoGeneratedDataPoints.java @@ -9,7 +9,7 @@ public class WithAutoGeneratedDataPoints { - private enum ENUM { VALUE, OTHER_VALUE, THIRD_VALUE }; + private enum ENUM { VALUE, OTHER_VALUE, THIRD_VALUE } @RunWith(Theories.class) public static class TheoryTestClassWithAutogeneratedParameterValues { diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java index c814508de897..f2b27531da55 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithDataPointMethod.java @@ -5,7 +5,7 @@ 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.hamcrest.MatcherAssert.assertThat; import static org.junit.experimental.results.PrintableResult.testResult; import static org.junit.experimental.results.ResultMatchers.isSuccessful; import static org.junit.tests.experimental.theories.TheoryTestUtils.potentialAssignments; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java index bcda189588bf..c08839f76d28 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithExtendedParameterSources.java @@ -3,7 +3,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.experimental.results.PrintableResult.testResult; import static org.junit.experimental.results.ResultMatchers.isSuccessful; @@ -113,8 +113,6 @@ public static String[] STRINGS() { return new String[]{"A", "B"}; } - ; - @Theory public void addToLog(String string) { log += string; @@ -137,8 +135,6 @@ public static String[] STRINGS() { return new String[]{"A", "B"}; } - ; - @DataPoints public static String STRING() { return "C"; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithNamedDataPoints.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithNamedDataPoints.java index 249ef1041c4b..8383a47107be 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/WithNamedDataPoints.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithNamedDataPoints.java @@ -1,8 +1,8 @@ package org.junit.tests.experimental.theories.runner; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.tests.experimental.theories.TheoryTestUtils.potentialAssignments; import java.util.List; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithOnlyTestAnnotations.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithOnlyTestAnnotations.java index 2dea231a2b88..17b2665c8909 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/WithOnlyTestAnnotations.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithOnlyTestAnnotations.java @@ -2,8 +2,8 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; 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; diff --git a/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java b/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java index 773dceec4a5e..5d466998eced 100644 --- a/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java +++ b/src/test/java/org/junit/tests/experimental/theories/runner/WithUnresolvedGenericTypeVariablesOnTheoryParms.java @@ -1,6 +1,6 @@ package org.junit.tests.experimental.theories.runner; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.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; @@ -159,7 +159,7 @@ public void forItem(T item) { @Test public void whereTypeVariablesAbound() { PrintableResult result = testResult(TypeVariablesAbound.class); - assertThat(result, failureCountIs(7)); + assertThat(result, failureCountIs(1)); assertThat(result, hasFailureContaining("unresolved type variable A")); assertThat(result, hasFailureContaining("unresolved type variable B")); assertThat(result, hasFailureContaining("unresolved type variable C")); diff --git a/src/test/java/org/junit/tests/internal/runners/ErrorReportingRunnerTest.java b/src/test/java/org/junit/tests/internal/runners/ErrorReportingRunnerTest.java deleted file mode 100644 index b6064d9568d4..000000000000 --- a/src/test/java/org/junit/tests/internal/runners/ErrorReportingRunnerTest.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.junit.tests.internal.runners; - -import org.junit.Test; -import org.junit.internal.runners.ErrorReportingRunner; - -public class ErrorReportingRunnerTest { - @Test(expected = NullPointerException.class) - public void cannotCreateWithNullClass() { - new ErrorReportingRunner(null, new RuntimeException()); - } -} diff --git a/src/test/java/org/junit/tests/junit3compatibility/AllJUnit3CompatibilityTests.java b/src/test/java/org/junit/tests/junit3compatibility/AllJUnit3CompatibilityTests.java new file mode 100644 index 000000000000..c85d01a7eaf6 --- /dev/null +++ b/src/test/java/org/junit/tests/junit3compatibility/AllJUnit3CompatibilityTests.java @@ -0,0 +1,21 @@ +package org.junit.tests.junit3compatibility; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + AllTestsTest.class, + ClassRequestTest.class, + ForwardCompatibilityPrintingTest.class, + ForwardCompatibilityTest.class, + InitializationErrorForwardCompatibilityTest.class, + JUnit38ClassRunnerTest.class, + JUnit4TestAdapterTest.class, + OldTestClassAdaptingListenerTest.class, + OldTests.class, + SuiteMethodTest.class +}) +public class AllJUnit3CompatibilityTests { +} diff --git a/src/test/java/org/junit/tests/junit3compatibility/AllTestsTest.java b/src/test/java/org/junit/tests/junit3compatibility/AllTestsTest.java index 96fad3d3ade5..99468128907a 100644 --- a/src/test/java/org/junit/tests/junit3compatibility/AllTestsTest.java +++ b/src/test/java/org/junit/tests/junit3compatibility/AllTestsTest.java @@ -1,8 +1,8 @@ package org.junit.tests.junit3compatibility; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import junit.framework.JUnit4TestAdapter; diff --git a/src/test/java/org/junit/tests/junit3compatibility/JUnit4TestAdapterTest.java b/src/test/java/org/junit/tests/junit3compatibility/JUnit4TestAdapterTest.java new file mode 100644 index 000000000000..8d20f33a0423 --- /dev/null +++ b/src/test/java/org/junit/tests/junit3compatibility/JUnit4TestAdapterTest.java @@ -0,0 +1,82 @@ +package org.junit.tests.junit3compatibility; + +import static org.junit.Assert.assertEquals; + +import java.util.Collections; + +import junit.framework.JUnit4TestAdapter; +import junit.framework.TestCase; +import junit.framework.TestResult; +import junit.framework.TestSuite; +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +public class JUnit4TestAdapterTest { + + private static void doTest(Class clazz) { + // JUnit 4 runner: + Result result = JUnitCore.runClasses(clazz); + assertEquals(1, result.getRunCount()); + assertEquals(0, result.getFailureCount()); + assertEquals(0, result.getIgnoreCount()); + + // JUnit 3 runner: + TestResult testResult = new TestResult(); + new JUnit4TestAdapter(clazz).run(testResult); + assertEquals(1, testResult.runCount()); + assertEquals(0, testResult.failureCount()); + assertEquals(Collections.emptyList(), Collections.list(testResult.errors())); + } + + public static class Test4 { + @Test + public void pass() throws Exception { + //pass + } + } + + @RunWith(Suite.class) + @Suite.SuiteClasses(Test4.class) + public static class TestSuiteFor4 { + } + + @Test + public void testJUnit4Suite() { + doTest(TestSuiteFor4.class); + } + + public static class Test3 extends TestCase { + public void testPass() throws Exception { + //pass + } + } + + @RunWith(Suite.class) + @Suite.SuiteClasses(Test3.class) + public static class TestSuiteFor3 { + } + + @Test + public void testJUnit3Suite() { + doTest(TestSuiteFor3.class); + } + + public static class TestSuite3 { + public static junit.framework.Test suite() { + return new TestSuite(Test3.class); + } + } + + @RunWith(Suite.class) + @Suite.SuiteClasses(TestSuite3.class) + public static class TestSuite4ForTestSuite3 { + } + + @Test + public void testJUnit4SuiteThatContainsJUnit3SuiteClass() { + doTest(TestSuite4ForTestSuite3.class); + } +} diff --git a/src/test/java/org/junit/tests/listening/AllListeningTests.java b/src/test/java/org/junit/tests/listening/AllListeningTests.java new file mode 100644 index 000000000000..cadbd2e332a9 --- /dev/null +++ b/src/test/java/org/junit/tests/listening/AllListeningTests.java @@ -0,0 +1,16 @@ +package org.junit.tests.listening; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + ListenerTest.class, + RunnerTest.class, + TestListenerTest.class, + TextListenerTest.class, + UserStopTest.class +}) +public class AllListeningTests { +} diff --git a/src/test/java/org/junit/tests/listening/TextListenerTest.java b/src/test/java/org/junit/tests/listening/TextListenerTest.java index c266d0c8c9ff..0cb1aff10a45 100644 --- a/src/test/java/org/junit/tests/listening/TextListenerTest.java +++ b/src/test/java/org/junit/tests/listening/TextListenerTest.java @@ -2,7 +2,7 @@ import static org.hamcrest.core.IsNot.not; import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import java.io.ByteArrayOutputStream; import java.io.OutputStream; diff --git a/src/test/java/org/junit/tests/manipulation/AllManipulationTests.java b/src/test/java/org/junit/tests/manipulation/AllManipulationTests.java new file mode 100644 index 000000000000..5989e1be7e51 --- /dev/null +++ b/src/test/java/org/junit/tests/manipulation/AllManipulationTests.java @@ -0,0 +1,17 @@ +package org.junit.tests.manipulation; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + FilterableTest.class, + FilterTest.class, + OrderableTest.class, + OrderWithTest.class, + SingleMethodTest.class, + SortableTest.class +}) +public class AllManipulationTests { +} diff --git a/src/test/java/org/junit/tests/manipulation/AlphanumericOrdering.java b/src/test/java/org/junit/tests/manipulation/AlphanumericOrdering.java new file mode 100644 index 000000000000..ff1a513e9119 --- /dev/null +++ b/src/test/java/org/junit/tests/manipulation/AlphanumericOrdering.java @@ -0,0 +1,15 @@ +package org.junit.tests.manipulation; + +import org.junit.runner.manipulation.Ordering; + +/** + * An ordering that orders tests alphanumerically by test name. + */ +public final class AlphanumericOrdering implements Ordering.Factory { + public static final ComparatorBasedOrdering INSTANCE = new ComparatorBasedOrdering( + Comparators.alphanumeric()); + + public Ordering create(Ordering.Context context) { + return INSTANCE; + } +} diff --git a/src/test/java/org/junit/tests/manipulation/ComparatorBasedOrdering.java b/src/test/java/org/junit/tests/manipulation/ComparatorBasedOrdering.java new file mode 100644 index 000000000000..6eff4a94dda9 --- /dev/null +++ b/src/test/java/org/junit/tests/manipulation/ComparatorBasedOrdering.java @@ -0,0 +1,28 @@ +package org.junit.tests.manipulation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.manipulation.Ordering; + +/** + * An ordering that internally uses a {@link Comparator}. + */ +class ComparatorBasedOrdering extends Ordering { + private final Comparator comparator; + + protected ComparatorBasedOrdering(Comparator comparator) { + this.comparator = comparator; + } + + @Override + protected List orderItems(Collection descriptions) { + List ordered = new ArrayList(descriptions); + Collections.sort(ordered, comparator); + return ordered; + } +} diff --git a/src/test/java/org/junit/tests/manipulation/Comparators.java b/src/test/java/org/junit/tests/manipulation/Comparators.java new file mode 100644 index 000000000000..8c61e89b7b26 --- /dev/null +++ b/src/test/java/org/junit/tests/manipulation/Comparators.java @@ -0,0 +1,19 @@ +package org.junit.tests.manipulation; + +import java.util.Comparator; + +import org.junit.runner.Description; +import org.junit.runner.manipulation.Alphanumeric; + +/** + * Factory and utility methods for creating {@link Comparator} instances for tests. + */ +class Comparators { + private static final Comparator ALPHANUMERIC = new Alphanumeric(); + + private Comparators() {} + + public static Comparator alphanumeric() { + return ALPHANUMERIC; + } +} diff --git a/src/test/java/org/junit/tests/manipulation/OrderWithTest.java b/src/test/java/org/junit/tests/manipulation/OrderWithTest.java new file mode 100644 index 000000000000..bfefeb35022b --- /dev/null +++ b/src/test/java/org/junit/tests/manipulation/OrderWithTest.java @@ -0,0 +1,268 @@ +package org.junit.tests.manipulation; + +import static org.junit.Assert.assertEquals; +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.OrderWith; +import org.junit.runner.Request; +import org.junit.runner.RunWith; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Alphanumeric; +import org.junit.runner.notification.RunNotifier; + +@RunWith(Enclosed.class) +public class OrderWithTest { + + public static class TestClassRunnerIsOrderableViaOrderWith { + private static String log = ""; + + public static class Unordered { + @Test + public void a() { + log += "a"; + } + + @Test + public void b() { + log += "b"; + } + + @Test + public void c() { + log += "c"; + } + } + + @OrderWith(AlphanumericOrdering.class) + public static class OrderedAlphanumerically extends Unordered { + } + + @OrderWith(ReverseAlphanumericOrdering.class) + public static class OrderedReverseAlphanumerically extends Unordered { + } + + @Before + public void resetLog() { + log = ""; + } + + @Test + public void orderingForwardWorksOnTestClassRunner() { + Request forward = Request.aClass(OrderedAlphanumerically.class); + + new JUnitCore().run(forward); + assertEquals("abc", log); + } + + @Test + public void orderingBackwardWorksOnTestClassRunner() { + Request backward = Request.aClass(OrderedReverseAlphanumerically.class); + + new JUnitCore().run(backward); + assertEquals("cba", log); + } + + @RunWith(Enclosed.class) + public static class UnorderedSuite { + 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"; + } + } + } + + @OrderWith(AlphanumericOrdering.class) + public static class SuiteOrderedAlphanumerically extends UnorderedSuite { + } + + @OrderWith(ReverseAlphanumericOrdering.class) + public static class SuiteOrderedReverseAlphanumerically extends UnorderedSuite { + } + + @Test + public void orderingForwardWorksOnSuite() { + Request forward = Request.aClass(SuiteOrderedAlphanumerically.class); + + new JUnitCore().run(forward); + assertEquals("AaAbAcBaBbBc", log); + } + + @Test + public void orderingBackwardWorksOnSuite() { + Request backward = Request.aClass(SuiteOrderedReverseAlphanumerically.class); + + new JUnitCore().run(backward); + assertEquals("BcBbBaAcAbAa", log); + } + } + + public static class TestClassRunnerIsSortableViaOrderWith { + private static String log = ""; + + public static class Unordered { + @Test + public void a() { + log += "a"; + } + + @Test + public void b() { + log += "b"; + } + + @Test + public void c() { + log += "c"; + } + } + + @Before + public void resetLog() { + log = ""; + } + + @OrderWith(Alphanumeric.class) + public static class SortedAlphanumerically extends Unordered { + } + + @OrderWith(ReverseAlphanumericSorter.class) + public static class SortedReverseAlphanumerically extends Unordered { + } + + @Test + public void sortingForwardWorksOnTestClassRunner() { + Request forward = Request.aClass(SortedAlphanumerically.class); + + new JUnitCore().run(forward); + assertEquals("abc", log); + } + + @Test + public void sortingBackwardWorksOnTestClassRunner() { + Request backward = Request.aClass(SortedReverseAlphanumerically.class); + + new JUnitCore().run(backward); + assertEquals("cba", log); + } + } + + public static class TestClassRunnerIsOrderableWithSuiteMethod { + private static String log = ""; + + public static class Unordered { + @Test + public void a() { + log += "a"; + } + + @Test + public void b() { + log += "b"; + } + + @Test + public void c() { + log += "c"; + } + } + + @OrderWith(AlphanumericOrdering.class) + public static class OrderedAlphanumerically extends Unordered { + + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(OrderedAlphanumerically.class); + } + } + + @OrderWith(ReverseAlphanumericOrdering.class) + public static class OrderedReverseAlphanumerically extends Unordered { + + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(OrderedReverseAlphanumerically.class); + } + } + + @Before + public void resetLog() { + log = ""; + } + + @Test + public void orderingForwardWorksOnTestClassRunner() { + Request forward = Request.aClass(OrderedAlphanumerically.class); + + new JUnitCore().run(forward); + assertEquals("abc", log); + } + + @Test + public void orderingBackwardWorksOnTestClassRunner() { + Request backward = Request.aClass(OrderedReverseAlphanumerically.class); + + new JUnitCore().run(backward); + assertEquals("cba", log); + } + } + + public static class UnOrderableRunnersAreHandledWithoutCrashing { + public static class UnOrderableRunner extends Runner { + public UnOrderableRunner(Class klass) { + } + + @Override + public Description getDescription() { + return Description.EMPTY; + } + + @Override + public void run(RunNotifier notifier) { + } + } + + @RunWith(UnOrderableRunner.class) + public static class UnOrderable { + @Test + public void a() { + } + } + + @Test + public void unOrderablesAreHandledWithoutCrashing() { + Request unordered = Request.aClass(UnOrderable.class).orderWith( + AlphanumericOrdering.INSTANCE); + new JUnitCore().run(unordered); + } + } +} diff --git a/src/test/java/org/junit/tests/manipulation/OrderableTest.java b/src/test/java/org/junit/tests/manipulation/OrderableTest.java new file mode 100644 index 000000000000..4adfac2250fb --- /dev/null +++ b/src/test/java/org/junit/tests/manipulation/OrderableTest.java @@ -0,0 +1,301 @@ +package org.junit.tests.manipulation; + +import static org.junit.Assert.assertEquals; +import junit.framework.JUnit4TestAdapter; +import org.junit.Before; +import org.junit.FixMethodOrder; +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.manipulation.Orderer; +import org.junit.runner.manipulation.InvalidOrderingException; +import org.junit.runner.manipulation.Orderable; +import org.junit.runner.manipulation.Sorter; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.MethodSorters; + +@RunWith(Enclosed.class) +public class OrderableTest { + + public static class TestClassRunnerIsOrderable { + private static String log = ""; + + public static class OrderMe { + @Test + public void a() { + log += "a"; + } + + @Test + public void b() { + log += "b"; + } + + @Test + public void c() { + log += "c"; + } + } + + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public static class DoNotOrderMe { + @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 orderingForwardWorksOnTestClassRunner() { + Request forward = Request.aClass(OrderMe.class).orderWith( + AlphanumericOrdering.INSTANCE); + + new JUnitCore().run(forward); + assertEquals("abc", log); + } + + @Test + public void orderingBackwardWorksOnTestClassRunner() { + Request backward = Request.aClass(OrderMe.class).orderWith( + new ReverseAlphanumericOrdering()); + + new JUnitCore().run(backward); + assertEquals("cba", log); + } + + @Test + public void orderingBackwardDoesNothingOnTestClassRunnerWithFixMethodOrder() { + Request backward = Request.aClass(DoNotOrderMe.class).orderWith( + new ReverseAlphanumericOrdering()); + + new JUnitCore().run(backward); + assertEquals("abc", 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 orderingForwardWorksOnSuite() { + Request forward = Request.aClass(Enclosing.class).orderWith( + AlphanumericOrdering.INSTANCE); + + new JUnitCore().run(forward); + assertEquals("AaAbAcBaBbBc", log); + } + + @Test + public void orderingBackwardWorksOnSuite() { + Request backward = Request.aClass(Enclosing.class).orderWith( + new ReverseAlphanumericOrdering()); + + new JUnitCore().run(backward); + assertEquals("BcBbBaAcAbAa", log); + } + } + + public static class TestOrderableClassRunnerIsSortable { + private static String log = ""; + + /** + * A Runner that implements {@link Orderable}. + */ + public static class OrderableRunner extends Runner implements Orderable { + private final BlockJUnit4ClassRunner delegate; + + public OrderableRunner(Class klass) throws Throwable { + delegate = new BlockJUnit4ClassRunner(klass); + } + + @Override + public void run(RunNotifier notifier) { + delegate.run(notifier); + } + + @Override + public Description getDescription() { + return delegate.getDescription(); + } + + public void order(Orderer orderer) throws InvalidOrderingException { + delegate.order(orderer); + } + + public void sort(Sorter sorter) { + delegate.sort(sorter); + } + } + + @RunWith(OrderableRunner.class) + public static class OrderMe { + @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 orderingorwardWorksOnTestClassRunner() { + Request forward = Request.aClass(OrderMe.class).orderWith( + AlphanumericOrdering.INSTANCE); + + new JUnitCore().run(forward); + assertEquals("abc", log); + } + + @Test + public void orderedBackwardWorksOnTestClassRunner() { + Request backward = Request.aClass(OrderMe.class).orderWith( + new ReverseAlphanumericOrdering()); + + new JUnitCore().run(backward); + assertEquals("cba", log); + } + } + + public static class TestClassRunnerIsOrderableWithSuiteMethod { + private static String log = ""; + + public static class OrderMe { + @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(OrderMe.class); + } + } + + @Before + public void resetLog() { + log = ""; + } + + @Test + public void orderingForwardWorksOnTestClassRunner() { + Request forward = Request.aClass(OrderMe.class).orderWith(AlphanumericOrdering.INSTANCE); + + new JUnitCore().run(forward); + assertEquals("abc", log); + } + + @Test + public void orderingBackwardWorksOnTestClassRunner() { + Request backward = Request.aClass(OrderMe.class).orderWith( + new ReverseAlphanumericOrdering()); + + new JUnitCore().run(backward); + assertEquals("cba", log); + } + } + + public static class UnOrderableRunnersAreHandledWithoutCrashing { + public static class UnOrderableRunner extends Runner { + public UnOrderableRunner(Class klass) { + } + + @Override + public Description getDescription() { + return Description.EMPTY; + } + + @Override + public void run(RunNotifier notifier) { + } + } + + @RunWith(UnOrderableRunner.class) + public static class UnOrderable { + @Test + public void a() { + } + } + + @Test + public void unOrderablesAreHandledWithoutCrashing() { + Request unordered = Request.aClass(UnOrderable.class).orderWith( + AlphanumericOrdering.INSTANCE); + new JUnitCore().run(unordered); + } + } +} diff --git a/src/test/java/org/junit/tests/manipulation/ReverseAlphanumericOrdering.java b/src/test/java/org/junit/tests/manipulation/ReverseAlphanumericOrdering.java new file mode 100644 index 000000000000..b93d5c6a9887 --- /dev/null +++ b/src/test/java/org/junit/tests/manipulation/ReverseAlphanumericOrdering.java @@ -0,0 +1,20 @@ +package org.junit.tests.manipulation; + +import static java.util.Collections.reverseOrder; + +import org.junit.runner.manipulation.Ordering; + +/** + * An ordering that orders tests reverse alphanumerically by test name. + */ +public final class ReverseAlphanumericOrdering extends ComparatorBasedOrdering + implements Ordering.Factory { + + public ReverseAlphanumericOrdering() { + super(reverseOrder(Comparators.alphanumeric())); + } + + public Ordering create(Context context) { + return this; + } +} diff --git a/src/test/java/org/junit/tests/manipulation/ReverseAlphanumericSorter.java b/src/test/java/org/junit/tests/manipulation/ReverseAlphanumericSorter.java new file mode 100644 index 000000000000..415253ebc62d --- /dev/null +++ b/src/test/java/org/junit/tests/manipulation/ReverseAlphanumericSorter.java @@ -0,0 +1,16 @@ +package org.junit.tests.manipulation; + +import static java.util.Collections.reverseOrder; + +import org.junit.runner.manipulation.Ordering; +import org.junit.runner.manipulation.Sorter; + +/** + * A sorter that orders tests reverse alphanumerically by test name. + */ +public final class ReverseAlphanumericSorter implements Ordering.Factory { + + public Ordering create(Ordering.Context context) { + return new Sorter(reverseOrder(Comparators.alphanumeric())); + } +} diff --git a/src/test/java/org/junit/tests/manipulation/SingleMethodTest.java b/src/test/java/org/junit/tests/manipulation/SingleMethodTest.java index c056f0a5d7dc..cf62c98e4d79 100644 --- a/src/test/java/org/junit/tests/manipulation/SingleMethodTest.java +++ b/src/test/java/org/junit/tests/manipulation/SingleMethodTest.java @@ -1,8 +1,8 @@ package org.junit.tests.manipulation; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import java.util.Arrays; import java.util.List; diff --git a/src/test/java/org/junit/tests/manipulation/SortableTest.java b/src/test/java/org/junit/tests/manipulation/SortableTest.java index 9d10ff95f313..5857ca0f719a 100644 --- a/src/test/java/org/junit/tests/manipulation/SortableTest.java +++ b/src/test/java/org/junit/tests/manipulation/SortableTest.java @@ -1,11 +1,13 @@ package org.junit.tests.manipulation; +import static java.util.Collections.reverseOrder; import static org.junit.Assert.assertEquals; import java.util.Comparator; import junit.framework.JUnit4TestAdapter; import org.junit.Before; +import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.Description; @@ -13,24 +15,21 @@ import org.junit.runner.Request; import org.junit.runner.RunWith; import org.junit.runner.Runner; +import org.junit.runner.manipulation.Orderable; +import org.junit.runner.manipulation.Sortable; +import org.junit.runner.manipulation.Sorter; import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.MethodSorters; @RunWith(Enclosed.class) public class SortableTest { private static Comparator forward() { - return new Comparator() { - public int compare(Description o1, Description o2) { - return o1.getDisplayName().compareTo(o2.getDisplayName()); - } - }; + return Comparators.alphanumeric(); } private static Comparator backward() { - return new Comparator() { - public int compare(Description o1, Description o2) { - return o2.getDisplayName().compareTo(o1.getDisplayName()); - } - }; + return reverseOrder(Comparators.alphanumeric()); } public static class TestClassRunnerIsSortable { @@ -53,6 +52,24 @@ public void c() { } } + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public static class DoNotSortMe { + @Test + public void a() { + log += "a"; + } + + @Test + public void b() { + log += "b"; + } + + @Test + public void c() { + log += "c"; + } + } + @Before public void resetLog() { log = ""; @@ -74,6 +91,14 @@ public void sortingBackwardWorksOnTestClassRunner() { assertEquals("cba", log); } + @Test + public void sortingBackwardDoesNothingOnTestClassRunnerWithFixMethodOrder() { + Request backward = Request.aClass(DoNotSortMe.class).sortWith(backward()); + + new JUnitCore().run(backward); + assertEquals("abc", log); + } + @RunWith(Enclosed.class) public static class Enclosing { public static class A { @@ -202,4 +227,76 @@ public void unsortablesAreHandledWithoutCrashing() { new JUnitCore().run(unsorted); } } + + public static class TestOnlySortableClassRunnerIsSortable { + private static String log = ""; + + /** + * A Runner that implements {@link Sortable} but not {@link Orderable}. + */ + public static class SortableRunner extends Runner implements Sortable { + private final BlockJUnit4ClassRunner delegate; + + public SortableRunner(Class klass) throws Throwable { + delegate = new BlockJUnit4ClassRunner(klass); + } + + @Override + public void run(RunNotifier notifier) { + delegate.run(notifier); + } + + @Override + public Description getDescription() { + return delegate.getDescription(); + } + + public void sort(Sorter sorter) { + delegate.sort(sorter); + } + } + + @RunWith(SortableRunner.class) + 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); + } + } } diff --git a/src/test/java/org/junit/tests/running/AllRunningTests.java b/src/test/java/org/junit/tests/running/AllRunningTests.java new file mode 100644 index 000000000000..0c05c92c2c2e --- /dev/null +++ b/src/test/java/org/junit/tests/running/AllRunningTests.java @@ -0,0 +1,17 @@ +package org.junit.tests.running; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; +import org.junit.tests.running.classes.AllClassesTests; +import org.junit.tests.running.core.AllCoreTests; +import org.junit.tests.running.methods.AllMethodsTests; + +@RunWith(Suite.class) +@SuiteClasses({ + AllClassesTests.class, + AllCoreTests.class, + AllMethodsTests.class +}) +public class AllRunningTests { +} diff --git a/src/test/java/org/junit/tests/running/classes/AllClassesTests.java b/src/test/java/org/junit/tests/running/classes/AllClassesTests.java new file mode 100644 index 000000000000..793090c34b0c --- /dev/null +++ b/src/test/java/org/junit/tests/running/classes/AllClassesTests.java @@ -0,0 +1,24 @@ +package org.junit.tests.running.classes; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; +import org.junit.tests.running.classes.parent.ParentRunnerClassLoaderTest; + +@RunWith(Suite.class) +@SuiteClasses({ + BlockJUnit4ClassRunnerTest.class, + ClassLevelMethodsWithIgnoredTestsTest.class, + EnclosedTest.class, + IgnoreClassTest.class, + ParameterizedTestTest.class, + ParentRunnerFilteringTest.class, + ParentRunnerTest.class, + ParentRunnerClassLoaderTest.class, + RunWithTest.class, + SuiteTest.class, + UseSuiteAsASuperclassTest.class, + ThreadsTest.class +}) +public class AllClassesTests { +} diff --git a/src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java b/src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java index 47405f6b1127..9a4e87a57b03 100644 --- a/src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java +++ b/src/test/java/org/junit/tests/running/classes/BlockJUnit4ClassRunnerTest.java @@ -5,6 +5,9 @@ import java.util.List; import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.JUnitCore; +import org.junit.runner.notification.RunListener; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.InitializationError; @@ -30,4 +33,36 @@ public void detectNonStaticEnclosedClass() throws Exception { causes.get(0).getMessage()); } } -} \ No newline at end of file + + private static String log; + + public static class MethodBlockAfterFireTestStarted { + public MethodBlockAfterFireTestStarted() { + log += " init"; + } + + @Test + public void test() { + log += " test"; + } + } + + @Test + public void methodBlockAfterFireTestStarted() { + log = ""; + JUnitCore junit = new JUnitCore(); + junit.addListener(new RunListener() { + @Override + public void testStarted(Description description) throws Exception { + log += " testStarted(" + description.getMethodName() + ")"; + } + + @Override + public void testFinished(Description description) throws Exception { + log += " testFinished(" + description.getMethodName() + ")"; + } + }); + junit.run(MethodBlockAfterFireTestStarted.class); + assertEquals(" testStarted(test) init test testFinished(test)", log); + } +} diff --git a/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java b/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java index 6ab94da863f3..14fb825df5bc 100644 --- a/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java +++ b/src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java @@ -1,19 +1,25 @@ package org.junit.tests.running.classes; import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import static org.junit.experimental.results.PrintableResult.testResult; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.Description; import org.junit.runner.JUnitCore; @@ -22,6 +28,7 @@ import org.junit.runner.RunWith; import org.junit.runner.Runner; import org.junit.runner.notification.Failure; +import org.junit.runners.MethodSorters; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; @@ -32,61 +39,81 @@ public class ParameterizedTestTest { @RunWith(Parameterized.class) - static public class FibonacciTest { - @Parameters(name = "{index}: fib({0})={1}") + public static class AdditionTest { + @Parameters(name = "{index}: {0} + {1} = {2}") public static Iterable data() { - return Arrays.asList(new Object[][]{{0, 0}, {1, 1}, {2, 1}, - {3, 2}, {4, 3}, {5, 5}, {6, 8}}); + return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, + { 3, 2, 5 }, { 4, 3, 7 } }); } - private final int fInput; + private int firstSummand; - private final int fExpected; + private int secondSummand; - public FibonacciTest(int input, int expected) { - fInput = input; - fExpected = expected; + private int sum; + + public AdditionTest(int firstSummand, int secondSummand, int sum) { + this.firstSummand = firstSummand; + this.secondSummand = secondSummand; + this.sum = sum; } @Test public void test() { - assertEquals(fExpected, fib(fInput)); - } - - private int fib(int x) { - return 0; + assertEquals(sum, firstSummand + secondSummand); } } @Test - public void count() { - Result result = JUnitCore.runClasses(FibonacciTest.class); - assertEquals(7, result.getRunCount()); - assertEquals(6, result.getFailureCount()); - } - - @Test - public void failuresNamedCorrectly() { - Result result = JUnitCore.runClasses(FibonacciTest.class); - assertEquals( - "test[1: fib(1)=1](" + FibonacciTest.class.getName() + ")", - result.getFailures().get(0).getTestHeader()); + public void countsRuns() { + Result result = JUnitCore.runClasses(AdditionTest.class); + assertEquals(4, result.getRunCount()); } @Test public void countBeforeRun() throws Exception { - Runner runner = Request.aClass(FibonacciTest.class).getRunner(); - assertEquals(7, runner.testCount()); + Runner runner = Request.aClass(AdditionTest.class).getRunner(); + assertEquals(4, runner.testCount()); } @Test public void plansNamedCorrectly() throws Exception { - Runner runner = Request.aClass(FibonacciTest.class).getRunner(); + Runner runner = Request.aClass(AdditionTest.class).getRunner(); Description description = runner.getDescription(); - assertEquals("[0: fib(0)=0]", description.getChildren().get(0) + assertEquals("[2: 3 + 2 = 5]", description.getChildren().get(2) .getDisplayName()); } + @RunWith(Parameterized.class) + public static class ThreeFailures { + @Parameters(name = "{index}: x={0}") + public static Collection data() { + return Arrays.asList(1, 2, 3); + } + + @Parameter(0) + public int unused; + + @Test + public void testSomething() { + fail(); + } + } + + @Test + public void countsFailures() throws Exception { + Result result = JUnitCore.runClasses(ThreeFailures.class); + assertEquals(3, result.getFailureCount()); + } + + @Test + public void failuresNamedCorrectly() { + Result result = JUnitCore.runClasses(ThreeFailures.class); + assertEquals( + "testSomething[0: x=1](" + ThreeFailures.class.getName() + ")", + result.getFailures().get(0).getTestHeader()); + } + @RunWith(Parameterized.class) public static class ParameterizedWithoutSpecialTestname { @Parameters @@ -111,55 +138,33 @@ public void usesIndexAsTestName() { } @RunWith(Parameterized.class) - static public class FibonacciWithParameterizedFieldTest { - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][]{{0, 0}, {1, 1}, {2, 1}, - {3, 2}, {4, 3}, {5, 5}, {6, 8}}); + public static class AdditionTestWithAnnotatedFields { + @Parameters(name = "{index}: {0} + {1} = {2}") + public static Iterable data() { + return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, + { 3, 2, 5 }, { 4, 3, 7 } }); } @Parameter(0) - public int fInput; + public int firstSummand; @Parameter(1) - public int fExpected; + public int secondSummand; + + @Parameter(2) + public int sum; @Test public void test() { - assertEquals(fExpected, fib(fInput)); - } - - private int fib(int x) { - return 0; + assertEquals(sum, firstSummand + secondSummand); } } @Test - public void countWithParameterizedField() { - Result result = JUnitCore.runClasses(FibonacciWithParameterizedFieldTest.class); - assertEquals(7, result.getRunCount()); - assertEquals(6, result.getFailureCount()); - } - - @Test - public void failuresNamedCorrectlyWithParameterizedField() { - Result result = JUnitCore.runClasses(FibonacciWithParameterizedFieldTest.class); - assertEquals(String - .format("test[1](%s)", FibonacciWithParameterizedFieldTest.class.getName()), result - .getFailures().get(0).getTestHeader()); - } - - @Test - public void countBeforeRunWithParameterizedField() throws Exception { - Runner runner = Request.aClass(FibonacciWithParameterizedFieldTest.class).getRunner(); - assertEquals(7, runner.testCount()); - } - - @Test - public void plansNamedCorrectlyWithParameterizedField() throws Exception { - Runner runner = Request.aClass(FibonacciWithParameterizedFieldTest.class).getRunner(); - Description description = runner.getDescription(); - assertEquals("[0]", description.getChildren().get(0).getDisplayName()); + public void providesDataByAnnotatedFields() { + Result result = JUnitCore.runClasses(AdditionTestWithAnnotatedFields.class); + assertEquals(4, result.getRunCount()); + assertEquals(0, result.getFailureCount()); } @RunWith(Parameterized.class) @@ -187,11 +192,11 @@ private int fib(int x) { @Test public void failureOnInitialization() { Result result = JUnitCore.runClasses(BadIndexForAnnotatedFieldTest.class); - assertEquals(2, result.getFailureCount()); + assertEquals(1, result.getFailureCount()); List failures = result.getFailures(); - assertEquals("Invalid @Parameter value: 2. @Parameter fields counted: 1. Please use an index between 0 and 0.", - failures.get(0).getException().getMessage()); - assertEquals("@Parameter(0) is never used.", failures.get(1).getException().getMessage()); + assertThat(failures.get(0).getException().getMessage(), allOf( + containsString("Invalid @Parameter value: 2. @Parameter fields counted: 1. Please use an index between 0 and 0."), + containsString("@Parameter(0) is never used."))); } @RunWith(Parameterized.class) @@ -259,6 +264,228 @@ public void beforeAndAfterClassAreRun() { assertEquals("before after ", fLog); } + @RunWith(Parameterized.class) + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public static class BeforeParamAndAfterParam { + @BeforeClass + public static void before() { + fLog += "beforeClass "; + } + + @Parameterized.BeforeParam + public static void beforeParam(String x) { + fLog += "before(" + x + ") "; + } + + @Parameterized.AfterParam + public static void afterParam() { + fLog += "afterParam "; + } + + @AfterClass + public static void after() { + fLog += "afterClass "; + } + + private final String x; + + public BeforeParamAndAfterParam(String x) { + this.x = x; + } + + @Parameters + public static Collection data() { + return Arrays.asList("A", "B"); + } + + @Test + public void first() { + fLog += "first(" + x + ") "; + } + + @Test + public void second() { + fLog += "second(" + x + ") "; + } + } + + @Test + public void beforeParamAndAfterParamAreRun() { + fLog = ""; + Result result = JUnitCore.runClasses(BeforeParamAndAfterParam.class); + assertEquals(0, result.getFailureCount()); + assertEquals("beforeClass before(A) first(A) second(A) afterParam " + + "before(B) first(B) second(B) afterParam afterClass ", fLog); + } + + @RunWith(Parameterized.class) + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public static class MultipleBeforeParamAndAfterParam { + @Parameterized.BeforeParam + public static void before1() { + fLog += "before1() "; + } + + @Parameterized.BeforeParam + public static void before2(String x) { + fLog += "before2(" + x + ") "; + } + + @Parameterized.AfterParam + public static void after2() { + fLog += "after2() "; + } + + @Parameterized.AfterParam + public static void after1(String x) { + fLog += "after1(" + x + ") "; + } + + private final String x; + + public MultipleBeforeParamAndAfterParam(String x) { + this.x = x; + } + + @Parameters + public static Collection data() { + return Arrays.asList("A", "B"); + } + + @Test + public void first() { + fLog += "first(" + x + ") "; + } + + @Test + public void second() { + fLog += "second(" + x + ") "; + } + } + + @Test + public void multipleBeforeParamAndAfterParamAreRun() { + fLog = ""; + Result result = JUnitCore.runClasses(MultipleBeforeParamAndAfterParam.class); + assertEquals(0, result.getFailureCount()); + assertEquals("before1() before2(A) first(A) second(A) after1(A) after2() " + + "before1() before2(B) first(B) second(B) after1(B) after2() ", fLog); + } + + @RunWith(Parameterized.class) + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public static class MultipleParametersBeforeParamAndAfterParam { + @Parameterized.BeforeParam + public static void before(String x, int y) { + fLog += "before(" + x + "," + y + ") "; + } + + @Parameterized.AfterParam + public static void after(String x, int y) { + fLog += "after(" + x + "," + y + ") "; + } + + private final String x; + private final int y; + + public MultipleParametersBeforeParamAndAfterParam(String x, int y) { + this.x = x; + this.y = y; + } + + @Parameters + public static Collection data() { + return Arrays.asList(new Object[]{"A", 1}, new Object[]{"B", 2}); + } + + @Test + public void first() { + fLog += "first(" + x + "," + y + ") "; + } + + @Test + public void second() { + fLog += "second(" + x + "," + y + ") "; + } + } + + @Test + public void multipleParametersBeforeParamAndAfterParamAreRun() { + fLog = ""; + Result result = JUnitCore.runClasses(MultipleParametersBeforeParamAndAfterParam.class); + assertEquals(0, result.getFailureCount()); + assertEquals("before(A,1) first(A,1) second(A,1) after(A,1) " + + "before(B,2) first(B,2) second(B,2) after(B,2) ", fLog); + } + + @RunWith(Parameterized.class) + public static class BeforeParamAndAfterParamError { + @Parameterized.BeforeParam + public void beforeParam(String x) { + } + + @Parameterized.AfterParam + private static void afterParam() { + } + + public BeforeParamAndAfterParamError(String x) { + } + + @Parameters + public static Collection data() { + return Arrays.asList("A", "B"); + } + + @Test + public void test() { + } + } + + @Test + public void beforeParamAndAfterParamValidation() { + fLog = ""; + Result result = JUnitCore.runClasses(BeforeParamAndAfterParamError.class); + assertEquals(1, result.getFailureCount()); + List failures = result.getFailures(); + assertThat(failures.get(0).getMessage(), containsString("beforeParam() should be static")); + assertThat(failures.get(0).getMessage(), containsString("afterParam() should be public")); + } + + @RunWith(Parameterized.class) + public static class BeforeParamAndAfterParamErrorNumberOfParameters { + @Parameterized.BeforeParam + public static void beforeParam(String x, String y) { + } + + @Parameterized.AfterParam + public static void afterParam(String x, String y, String z) { + } + + public BeforeParamAndAfterParamErrorNumberOfParameters(String x) { + } + + @Parameters + public static Collection data() { + return Arrays.asList("A", "B", "C", "D"); + } + + @Test + public void test() { + } + } + + @Test + public void beforeParamAndAfterParamValidationNumberOfParameters() { + fLog = ""; + Result result = JUnitCore.runClasses(BeforeParamAndAfterParamErrorNumberOfParameters.class); + assertEquals(1, result.getFailureCount()); + List failures = result.getFailures(); + assertThat(failures.get(0).getMessage(), + containsString("Method beforeParam() should have 0 or 1 parameter(s)")); + assertThat(failures.get(0).getMessage(), + containsString("Method afterParam() should have 0 or 1 parameter(s)")); + } + @RunWith(Parameterized.class) static public class EmptyTest { @BeforeClass @@ -357,36 +584,32 @@ public void exceptionWhenPrivateConstructor() throws Throwable { } @RunWith(Parameterized.class) - static public class FibonacciTestWithArray { - @Parameters(name= "{index}: fib({0})={1}") + public static class AdditionTestWithArray { + @Parameters(name = "{index}: {0} + {1} = {2}") public static Object[][] data() { - return new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, - { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } }; + return new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, { 3, 2, 5 }, + { 4, 3, 7 } }; } - private final int fInput; + @Parameter(0) + public int firstSummand; - private final int fExpected; + @Parameter(1) + public int secondSummand; - public FibonacciTestWithArray(int input, int expected) { - fInput= input; - fExpected= expected; - } + @Parameter(2) + public int sum; @Test public void test() { - assertEquals(fExpected, fib(fInput)); - } - - private int fib(int x) { - return 0; + assertEquals(sum, firstSummand + secondSummand); } } @Test public void runsEveryTestOfArray() { - Result result= JUnitCore.runClasses(FibonacciTestWithArray.class); - assertEquals(7, result.getRunCount()); + Result result= JUnitCore.runClasses(AdditionTestWithArray.class); + assertEquals(4, result.getRunCount()); } @RunWith(Parameterized.class) @@ -412,9 +635,14 @@ public void runsForEverySingleArgumentOfArray() { @RunWith(Parameterized.class) static public class SingleArgumentTestWithIterable { + private static final AtomicBoolean dataCalled = new AtomicBoolean(false); + @Parameters public static Iterable data() { - return asList("first test", "second test"); + if (!dataCalled.compareAndSet(false, true)) { + fail("Should not call @Parameters method more than once"); + } + return new OneShotIterable(asList("first test", "second test")); } public SingleArgumentTestWithIterable(Object argument) { @@ -425,6 +653,22 @@ public void aTest() { } } + private static class OneShotIterable implements Iterable { + private final Iterable delegate; + private final AtomicBoolean iterated = new AtomicBoolean(false); + + OneShotIterable(Iterable delegate) { + this.delegate = delegate; + } + + public Iterator iterator() { + if (iterated.compareAndSet(false, true)) { + return delegate.iterator(); + } + throw new IllegalStateException("Cannot call iterator() more than once"); + } + } + @Test public void runsForEverySingleArgumentOfIterable() { Result result= JUnitCore @@ -432,6 +676,29 @@ public void runsForEverySingleArgumentOfIterable() { assertEquals(2, result.getRunCount()); } + @RunWith(Parameterized.class) + static public class SingleArgumentTestWithCollection { + @Parameters + public static Iterable data() { + return Collections.unmodifiableCollection(asList("first test", "second test")); + } + + public SingleArgumentTestWithCollection(Object argument) { + } + + @Test + public void aTest() { + } + } + + @Test + public void runsForEverySingleArgumentOfCollection() { + Result result= JUnitCore + .runClasses(SingleArgumentTestWithCollection.class); + assertEquals(2, result.getRunCount()); + } + + static public class ExceptionThrowingRunnerFactory implements ParametersRunnerFactory { public Runner createRunnerForTestWithParameters(TestWithParameters test) @@ -497,4 +764,46 @@ public void usesParametersRunnerFactoryThatWasSpecifiedByAnnotationInSuperClass( UseParameterizedFactoryTest.class, "Called ExceptionThrowingRunnerFactory."); } -} \ No newline at end of file + + @RunWith(Parameterized.class) + public static class AssumptionInParametersMethod { + static boolean assumptionFails; + + @Parameters + public static Iterable data() { + assumeFalse(assumptionFails); + return Collections.singletonList("foobar"); + } + + public AssumptionInParametersMethod(String parameter) { + } + + @Test + public void test1() { + } + + @Test + public void test2() { + } + } + + @Test + public void testsAreExecutedWhenAssumptionInParametersMethodDoesNotFail() { + AssumptionInParametersMethod.assumptionFails = false; + Result result = JUnitCore.runClasses(AssumptionInParametersMethod.class); + assertTrue(result.wasSuccessful()); + assertEquals(0, result.getAssumptionFailureCount()); + assertEquals(0, result.getIgnoreCount()); + assertEquals(2, result.getRunCount()); + } + + @Test + public void testsAreNotExecutedWhenAssumptionInParametersMethodFails() { + AssumptionInParametersMethod.assumptionFails = true; + Result result = JUnitCore.runClasses(AssumptionInParametersMethod.class); + assertTrue(result.wasSuccessful()); + assertEquals(1, result.getAssumptionFailureCount()); + assertEquals(0, result.getIgnoreCount()); + assertEquals(0, result.getRunCount()); + } +} diff --git a/src/test/java/org/junit/tests/running/classes/ParentRunnerFilteringTest.java b/src/test/java/org/junit/tests/running/classes/ParentRunnerFilteringTest.java index 12e12b428d86..1c1d9d1c34eb 100644 --- a/src/test/java/org/junit/tests/running/classes/ParentRunnerFilteringTest.java +++ b/src/test/java/org/junit/tests/running/classes/ParentRunnerFilteringTest.java @@ -1,7 +1,7 @@ package org.junit.tests.running.classes; +import static org.hamcrest.MatcherAssert.assertThat; 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; @@ -95,9 +95,9 @@ public void testSuiteFiltering() throws Exception { fail("Expected 'NoTestsRemainException' due to complete filtering"); } - public static class SuiteWithUnmodifyableChildList extends Suite { + public static class SuiteWithUnmodifiableChildList extends Suite { - public SuiteWithUnmodifyableChildList( + public SuiteWithUnmodifiableChildList( Class klass, RunnerBuilder builder) throws InitializationError { super(klass, builder); @@ -109,14 +109,14 @@ protected List getChildren() { } } - @RunWith(SuiteWithUnmodifyableChildList.class) + @RunWith(SuiteWithUnmodifiableChildList.class) @SuiteClasses({ExampleTest.class}) - public static class ExampleSuiteWithUnmodifyableChildList { + public static class ExampleSuiteWithUnmodifiableChildList { } @Test - public void testSuiteFilteringWithUnmodifyableChildList() throws Exception { - Runner runner = Request.aClass(ExampleSuiteWithUnmodifyableChildList.class) + public void testSuiteFilteringWithUnmodifiableChildList() throws Exception { + Runner runner = Request.aClass(ExampleSuiteWithUnmodifiableChildList.class) .getRunner(); Filter filter = notThisMethodName("test1"); try { diff --git a/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java b/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java index 70fe531ec291..9b18ed14492c 100644 --- a/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java +++ b/src/test/java/org/junit/tests/running/classes/ParentRunnerTest.java @@ -1,9 +1,9 @@ package org.junit.tests.running.classes; -import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import java.util.List; @@ -26,8 +26,8 @@ import org.junit.runners.ParentRunner; import org.junit.runners.model.InitializationError; import org.junit.runners.model.RunnerScheduler; -import org.junit.tests.experimental.rules.RuleMemberValidatorTest.TestWithNonStaticClassRule; -import org.junit.tests.experimental.rules.RuleMemberValidatorTest.TestWithProtectedClassRule; +import org.junit.rules.RuleMemberValidatorTest.TestWithNonStaticClassRule; +import org.junit.rules.RuleMemberValidatorTest.TestWithProtectedClassRule; public class ParentRunnerTest { public static String log = ""; @@ -136,6 +136,9 @@ public void failWithHelpfulMessageForNonStaticClassRule() { static class NonPublicTestClass { public NonPublicTestClass() { } + + @Test + public void alwaysPasses() {} } @Test @@ -149,9 +152,9 @@ 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.getFailureCount(), is(1)); assertThat(result.getFailures().get(0).getMessage(), - is(equalTo(message))); + containsString(message)); } public static class AssertionErrorAtParentLevelTest { @@ -167,14 +170,20 @@ public void test() {} @Test public void assertionErrorAtParentLevelTest() throws InitializationError { CountingRunListener countingRunListener = runTestWithParentRunner(AssertionErrorAtParentLevelTest.class); + Assert.assertEquals(1, countingRunListener.testSuiteStarted); + Assert.assertEquals(1, countingRunListener.testSuiteFinished); + Assert.assertEquals(1, countingRunListener.testSuiteFailure); + Assert.assertEquals(0, countingRunListener.testSuiteAssumptionFailure); + Assert.assertEquals(0, countingRunListener.testStarted); Assert.assertEquals(0, countingRunListener.testFinished); - Assert.assertEquals(1, countingRunListener.testFailure); + Assert.assertEquals(0, countingRunListener.testFailure); Assert.assertEquals(0, countingRunListener.testAssumptionFailure); Assert.assertEquals(0, countingRunListener.testIgnored); } public static class AssumptionViolatedAtParentLevelTest { + @SuppressWarnings("deprecation") @BeforeClass public static void beforeClass() { throw new AssumptionViolatedException("Thrown from @BeforeClass"); @@ -187,10 +196,15 @@ public void test() {} @Test public void assumptionViolatedAtParentLevel() throws InitializationError { CountingRunListener countingRunListener = runTestWithParentRunner(AssumptionViolatedAtParentLevelTest.class); + Assert.assertEquals(1, countingRunListener.testSuiteStarted); + Assert.assertEquals(1, countingRunListener.testSuiteFinished); + Assert.assertEquals(0, countingRunListener.testSuiteFailure); + Assert.assertEquals(1, countingRunListener.testSuiteAssumptionFailure); + Assert.assertEquals(0, countingRunListener.testStarted); Assert.assertEquals(0, countingRunListener.testFinished); Assert.assertEquals(0, countingRunListener.testFailure); - Assert.assertEquals(1, countingRunListener.testAssumptionFailure); + Assert.assertEquals(0, countingRunListener.testAssumptionFailure); Assert.assertEquals(0, countingRunListener.testIgnored); } @@ -207,6 +221,7 @@ public void fail() { @Test public void ignore() {} + @SuppressWarnings("deprecation") @Test public void assumptionFail() { throw new AssumptionViolatedException("Thrown from @Test"); @@ -216,6 +231,11 @@ public void assumptionFail() { @Test public void parentRunnerTestMethods() throws InitializationError { CountingRunListener countingRunListener = runTestWithParentRunner(TestTest.class); + Assert.assertEquals(1, countingRunListener.testSuiteStarted); + Assert.assertEquals(1, countingRunListener.testSuiteFinished); + Assert.assertEquals(0, countingRunListener.testSuiteFailure); + Assert.assertEquals(0, countingRunListener.testSuiteAssumptionFailure); + Assert.assertEquals(3, countingRunListener.testStarted); Assert.assertEquals(3, countingRunListener.testFinished); Assert.assertEquals(1, countingRunListener.testFailure); @@ -227,18 +247,33 @@ private CountingRunListener runTestWithParentRunner(Class testClass) throws I CountingRunListener listener = new CountingRunListener(); RunNotifier runNotifier = new RunNotifier(); runNotifier.addListener(listener); - ParentRunner runner = new BlockJUnit4ClassRunner(testClass); + ParentRunner runner = new BlockJUnit4ClassRunner(testClass); runner.run(runNotifier); return listener; } private static class CountingRunListener extends RunListener { + private int testSuiteStarted = 0; + private int testSuiteFinished = 0; + private int testSuiteFailure = 0; + private int testSuiteAssumptionFailure = 0; + private int testStarted = 0; private int testFinished = 0; private int testFailure = 0; private int testAssumptionFailure = 0; private int testIgnored = 0; + @Override + public void testSuiteStarted(Description description) throws Exception { + testSuiteStarted++; + } + + @Override + public void testSuiteFinished(Description description) throws Exception { + testSuiteFinished++; + } + @Override public void testStarted(Description description) throws Exception { testStarted++; @@ -251,12 +286,20 @@ public void testFinished(Description description) throws Exception { @Override public void testFailure(Failure failure) throws Exception { - testFailure++; + if (failure.getDescription().isSuite()) { + testSuiteFailure++; + } else { + testFailure++; + } } @Override public void testAssumptionFailure(Failure failure) { - testAssumptionFailure++; + if (failure.getDescription().isSuite()) { + testSuiteAssumptionFailure++; + } else { + testAssumptionFailure++; + } } @Override diff --git a/src/test/java/org/junit/tests/running/classes/SuiteTest.java b/src/test/java/org/junit/tests/running/classes/SuiteTest.java index 1d95ebc87a49..42b492edaad1 100644 --- a/src/test/java/org/junit/tests/running/classes/SuiteTest.java +++ b/src/test/java/org/junit/tests/running/classes/SuiteTest.java @@ -1,10 +1,11 @@ package org.junit.tests.running.classes; +import static org.hamcrest.MatcherAssert.assertThat; 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 static org.junit.experimental.results.ResultMatchers.isSuccessful; import java.util.List; @@ -41,6 +42,18 @@ public void fail() { public static class All { } + @RunWith(Suite.class) + @SuiteClasses(TestA.class) + static class NonPublicSuite { + } + + @RunWith(Suite.class) + @SuiteClasses(TestA.class) + static class NonPublicSuiteWithBeforeClass { + @BeforeClass + public static void doesNothing() {} + } + public static class InheritsAll extends All { } @@ -66,6 +79,19 @@ public void suiteTestCountIsCorrect() throws Exception { assertEquals(2, runner.testCount()); } + @Test + public void suiteClassDoesNotNeedToBePublic() { + JUnitCore core = new JUnitCore(); + Result result = core.run(NonPublicSuite.class); + assertEquals(1, result.getRunCount()); + assertEquals(0, result.getFailureCount()); + } + + @Test + public void nonPublicSuiteClassWithBeforeClassPasses() { + assertThat(testResult(NonPublicSuiteWithBeforeClass.class), isSuccessful()); + } + @Test public void ensureSuitesWorkWithForwardCompatibility() { junit.framework.Test test = new JUnit4TestAdapter(All.class); diff --git a/src/test/java/org/junit/tests/running/classes/ThreadsTest.java b/src/test/java/org/junit/tests/running/classes/ThreadsTest.java new file mode 100644 index 000000000000..2965187e3365 --- /dev/null +++ b/src/test/java/org/junit/tests/running/classes/ThreadsTest.java @@ -0,0 +1,83 @@ +package org.junit.tests.running.classes; + +import org.junit.AfterClass; +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.notification.RunListener; +import org.junit.runners.BlockJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; + +public class ThreadsTest { + + private List interruptedFlags = new ArrayList(); + private JUnitCore core = new JUnitCore(); + + public static class TestWithInterrupt { + + @Test + public void interruptCurrentThread() { + Thread.currentThread().interrupt(); + } + + @Test + public void otherTestCaseInterruptingCurrentThread() { + Thread.currentThread().interrupt(); + } + + } + + @Test + public void currentThreadInterruptedStatusIsClearedAfterEachTestExecution() { + core.addListener(new RunListener() { + @Override + public void testFinished(Description description) { + interruptedFlags.add(Thread.currentThread().isInterrupted()); + } + }); + + Result result = core.run(TestWithInterrupt.class); + + assertEquals(0, result.getFailureCount()); + assertEquals(asList(false, false), interruptedFlags); + } + + @RunWith(BlockJUnit4ClassRunner.class) + public static class TestWithInterruptFromAfterClass { + @AfterClass + public static void interruptCurrentThread() { + Thread.currentThread().interrupt(); + } + + @Test + public void test() { + // no-op + } + } + + @Test + public void currentThreadInterruptStatusIsClearedAfterSuiteExecution() { + core.addListener(new RunListener() { + @Override + public void testSuiteFinished(Description description) { + interruptedFlags.add(Thread.currentThread().isInterrupted()); + } + }); + + Request request = Request.aClass(TestWithInterruptFromAfterClass.class); + + Result result = core.run(request); + + assertEquals(0, result.getFailureCount()); + assertEquals(singletonList(false), interruptedFlags); + } +} diff --git a/src/test/java/org/junit/tests/running/classes/parent/ParentRunnerClassLoaderTest.java b/src/test/java/org/junit/tests/running/classes/parent/ParentRunnerClassLoaderTest.java new file mode 100644 index 000000000000..bb6ba14e4c44 --- /dev/null +++ b/src/test/java/org/junit/tests/running/classes/parent/ParentRunnerClassLoaderTest.java @@ -0,0 +1,96 @@ +package org.junit.tests.running.classes.parent; + + +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.ParentRunner; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; + +import java.lang.reflect.Field; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class ParentRunnerClassLoaderTest { + @Test + public void testClassRuleAccessToClassInAnotherClassLoader() throws Exception { + Class testClassWithOwnClassLoader = wrapToClassLoader(TestWithClassRule.class); + + runTestWithParentRunner(testClassWithOwnClassLoader); + + Field fieldWithReference = testClassWithOwnClassLoader.getDeclaredField("applyTestClass"); + Class usedClass = (Class) fieldWithReference.get(null); + + assertEquals("JUnitRunner can be located in own classLoader, so, " + + "Class.forName org.junit.runner.Description.getTestClass can not see " + + "in current classloader by execute Class.forName", + testClassWithOwnClassLoader, usedClass + ); + } + + @Test + public void testDescriptionContainCorrectTestClass() throws Exception { + Class testClassWithOwnClassLoader = wrapToClassLoader(TestWithClassRule.class); + ParentRunner runner = new BlockJUnit4ClassRunner(testClassWithOwnClassLoader); + + Description description = runner.getDescription(); + assertEquals("ParentRunner accept already instantiate Class with tests, if we lost it instance, and will " + + "use Class.forName we can not find test class again, because tests can be " + + "located in different ClassLoader", + description.getTestClass(), testClassWithOwnClassLoader + ); + } + + @Test + public void testBackwardCompatibilityWithOverrideGetName() throws Exception { + final Class originalTestClass = TestWithClassRule.class; + final Class waitClass = ParentRunnerClassLoaderTest.class; + + ParentRunner subParentRunner = new BlockJUnit4ClassRunner(originalTestClass) { + @Override + protected String getName() { + return waitClass.getName(); + } + }; + + Description description = subParentRunner.getDescription(); + Class result = description.getTestClass(); + + assertEquals("Subclass of ParentRunner can override getName method and specify another test class for run, " + + "we should maintain backwards compatibility with JUnit 4.12", + waitClass, result + ); + } + + private void runTestWithParentRunner(Class testClass) throws InitializationError { + ParentRunner runner = new BlockJUnit4ClassRunner(testClass); + runner.run(new RunNotifier()); + } + + private Class wrapToClassLoader(Class sourceClass) throws ClassNotFoundException { + URL classpath = sourceClass.getProtectionDomain().getCodeSource().getLocation(); + VisibleClassLoader loader = new VisibleClassLoader(new URL[]{classpath}, this.getClass().getClassLoader()); + Class testClassWithOwnClassLoader = loader.findClass(sourceClass.getName()); + + assert testClassWithOwnClassLoader != sourceClass; + + return testClassWithOwnClassLoader; + } + + + private static class VisibleClassLoader extends URLClassLoader { + public VisibleClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + @Override // just making public + public Class findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } + } +} diff --git a/src/test/java/org/junit/tests/running/classes/parent/TestWithClassRule.java b/src/test/java/org/junit/tests/running/classes/parent/TestWithClassRule.java new file mode 100644 index 000000000000..62c892cd010f --- /dev/null +++ b/src/test/java/org/junit/tests/running/classes/parent/TestWithClassRule.java @@ -0,0 +1,42 @@ +package org.junit.tests.running.classes.parent; + +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.lang.reflect.Field; + +/** + * Test class for validate run tests that was load in own ClassLoader + */ +public class TestWithClassRule { + public static Class applyTestClass; + + @ClassRule + public static TestRule rule = new CustomRule(); + + @Test + public void testClassRuleExecuted() throws Exception { + Assert.assertNotNull("Description should contain reference to TestClass", applyTestClass); + } + + public static final class CustomRule implements TestRule { + + public Statement apply(final Statement base, final Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + Class testClass = description.getTestClass(); + if(testClass != null) { + Field field = testClass.getDeclaredField("applyTestClass"); + field.set(null, description.getTestClass()); + } + base.evaluate(); + } + }; + } + } +} diff --git a/src/test/java/org/junit/tests/running/core/AllCoreTests.java b/src/test/java/org/junit/tests/running/core/AllCoreTests.java new file mode 100644 index 000000000000..a17a7e20cdb6 --- /dev/null +++ b/src/test/java/org/junit/tests/running/core/AllCoreTests.java @@ -0,0 +1,14 @@ +package org.junit.tests.running.core; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + CommandLineTest.class, + JUnitCoreReturnsCorrectExitCodeTest.class, + SystemExitTest.class +}) +public class AllCoreTests { +} diff --git a/src/test/java/org/junit/tests/running/core/MainRunner.java b/src/test/java/org/junit/tests/running/core/MainRunner.java index 31f01e8d707e..ea9088684af8 100644 --- a/src/test/java/org/junit/tests/running/core/MainRunner.java +++ b/src/test/java/org/junit/tests/running/core/MainRunner.java @@ -1,9 +1,7 @@ package org.junit.tests.running.core; import java.io.ByteArrayOutputStream; -import java.io.FileDescriptor; import java.io.PrintStream; -import java.net.InetAddress; import java.security.Permission; public class MainRunner { @@ -24,243 +22,21 @@ public int getStatus() { /** * A {@code NoExitSecurityManager} throws a {@link ExitException} exception - * whenever {@link #checkExit(int)} is called. All other method calls are - * delegated to the original security manager. + * whenever {@link #checkExit(int)} is called; all other permissions are allowed. */ public class NoExitSecurityManager extends SecurityManager { - private final SecurityManager originalSecurityManager; - - public NoExitSecurityManager(SecurityManager originalSecurityManager) { - this.originalSecurityManager = originalSecurityManager; - } @Override public void checkExit(int status) { throw new ExitException(status); } - @Override - public boolean getInCheck() { - return (originalSecurityManager != null) && originalSecurityManager.getInCheck(); - } - - @Override - public Object getSecurityContext() { - return (originalSecurityManager == null) ? super.getSecurityContext() : originalSecurityManager.getSecurityContext(); - } - @Override public void checkPermission(Permission perm) { - if (originalSecurityManager != null) { - originalSecurityManager.checkPermission(perm); - } - } - - @Override - public void checkPermission(Permission perm, Object context) { - if (originalSecurityManager != null) { - originalSecurityManager.checkPermission(perm, context); - } - } - - @Override - public void checkCreateClassLoader() { - if (originalSecurityManager != null) { - originalSecurityManager.checkCreateClassLoader(); - } - } - - @Override - public void checkAccess(Thread t) { - if (originalSecurityManager != null) { - originalSecurityManager.checkAccess(t); - } - } - - @Override - public void checkAccess(ThreadGroup g) { - if (originalSecurityManager != null) { - originalSecurityManager.checkAccess(g); - } - } - - @Override - public void checkExec(String cmd) { - if (originalSecurityManager != null) { - originalSecurityManager.checkExec(cmd); - } - } - - @Override - public void checkLink(String lib) { - if (originalSecurityManager != null) { - originalSecurityManager.checkLink(lib); - } - } - - @Override - public void checkRead(FileDescriptor fd) { - if (originalSecurityManager != null) { - originalSecurityManager.checkRead(fd); - } - } - - @Override - public void checkRead(String file) { - if (originalSecurityManager != null) { - originalSecurityManager.checkRead(file); - } - } - - @Override - public void checkRead(String file, Object context) { - if (originalSecurityManager != null) { - originalSecurityManager.checkRead(file, context); - } - } - - @Override - public void checkWrite(FileDescriptor fd) { - if (originalSecurityManager != null) { - originalSecurityManager.checkWrite(fd); - } - } - - @Override - public void checkWrite(String file) { - if (originalSecurityManager != null) { - originalSecurityManager.checkWrite(file); - } - } - - @Override - public void checkDelete(String file) { - if (originalSecurityManager != null) { - originalSecurityManager.checkDelete(file); - } - } - - @Override - public void checkConnect(String host, int port) { - if (originalSecurityManager != null) { - originalSecurityManager.checkConnect(host, port); - } - } - - @Override - public void checkConnect(String host, int port, Object context) { - if (originalSecurityManager != null) { - originalSecurityManager.checkConnect(host, port, context); - } - } - - @Override - public void checkListen(int port) { - if (originalSecurityManager != null) { - originalSecurityManager.checkListen(port); - } - } - - @Override - public void checkAccept(String host, int port) { - if (originalSecurityManager != null) { - originalSecurityManager.checkAccept(host, port); - } - } - - @Override - public void checkMulticast(InetAddress maddr) { - if (originalSecurityManager != null) { - originalSecurityManager.checkMulticast(maddr); - } - } - - @Override - public void checkMulticast(InetAddress maddr, byte ttl) { - if (originalSecurityManager != null) { - originalSecurityManager.checkMulticast(maddr, ttl); - } - } - - @Override - public void checkPropertiesAccess() { - if (originalSecurityManager != null) { - originalSecurityManager.checkPropertiesAccess(); - } - } - - @Override - public void checkPropertyAccess(String key) { - if (originalSecurityManager != null) { - originalSecurityManager.checkPropertyAccess(key); - } - } - - @Override - public boolean checkTopLevelWindow(Object window) { - return (originalSecurityManager == null) ? super.checkTopLevelWindow(window) : originalSecurityManager.checkTopLevelWindow(window); - } - - @Override - public void checkPrintJobAccess() { - if (originalSecurityManager != null) { - originalSecurityManager.checkPrintJobAccess(); + if (perm.getName().startsWith("exitVM")) { + super.checkPermission(perm); } } - - @Override - public void checkSystemClipboardAccess() { - if (originalSecurityManager != null) { - originalSecurityManager.checkSystemClipboardAccess(); - } - } - - @Override - public void checkAwtEventQueueAccess() { - if (originalSecurityManager != null) { - originalSecurityManager.checkAwtEventQueueAccess(); - } - } - - @Override - public void checkPackageAccess(String pkg) { - if (originalSecurityManager != null) { - originalSecurityManager.checkPackageAccess(pkg); - } - } - - @Override - public void checkPackageDefinition(String pkg) { - if (originalSecurityManager != null) { - originalSecurityManager.checkPackageDefinition(pkg); - } - } - - @Override - public void checkSetFactory() { - if (originalSecurityManager != null) { - originalSecurityManager.checkSetFactory(); - } - } - - @Override - public void checkMemberAccess(Class clazz, int which) { - if (originalSecurityManager != null) { - originalSecurityManager.checkMemberAccess(clazz, which); - } - } - - @Override - public void checkSecurityAccess(String target) { - if (originalSecurityManager != null) { - originalSecurityManager.checkSecurityAccess(target); - } - } - - @Override - public ThreadGroup getThreadGroup() { - return (originalSecurityManager == null) ? super.getThreadGroup() : originalSecurityManager.getThreadGroup(); - } } /** @@ -272,7 +48,7 @@ public ThreadGroup getThreadGroup() { */ public Integer runWithCheckForSystemExit(Runnable runnable) { SecurityManager oldSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new NoExitSecurityManager(oldSecurityManager)); + System.setSecurityManager(new NoExitSecurityManager()); PrintStream oldOut = System.out; System.setOut(new PrintStream(new ByteArrayOutputStream())); diff --git a/src/test/java/org/junit/tests/running/methods/AllMethodsTests.java b/src/test/java/org/junit/tests/running/methods/AllMethodsTests.java new file mode 100644 index 000000000000..533bb5e1318f --- /dev/null +++ b/src/test/java/org/junit/tests/running/methods/AllMethodsTests.java @@ -0,0 +1,17 @@ +package org.junit.tests.running.methods; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + AnnotationTest.class, + ExpectedTest.class, + InheritedTestTest.class, + ParameterizedTestMethodTest.class, + TestMethodTest.class, + TimeoutTest.class +}) +public class AllMethodsTests { +} diff --git a/src/test/java/org/junit/tests/running/methods/AnnotationTest.java b/src/test/java/org/junit/tests/running/methods/AnnotationTest.java index 71fd79baab13..593cdb1c27a6 100644 --- a/src/test/java/org/junit/tests/running/methods/AnnotationTest.java +++ b/src/test/java/org/junit/tests/running/methods/AnnotationTest.java @@ -2,7 +2,9 @@ import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.experimental.results.PrintableResult.testResult; +import static org.junit.experimental.results.ResultMatchers.isSuccessful; import java.util.Collection; import java.util.HashSet; @@ -13,7 +15,11 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExternalResource; +import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runner.JUnitCore; import org.junit.runner.Result; @@ -397,7 +403,7 @@ public void testErrorInAfterClass() throws Exception { assertEquals(1, result.getFailureCount()); } - static public class SuperInheritance { + static class SuperInheritance { @BeforeClass static public void beforeClassSuper() { log += "Before class super "; @@ -453,29 +459,74 @@ public void testOrderingOfInheritance() throws Exception { 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 { + static public abstract class SuperShadowing { + + @Rule + public TestRule rule() { + return new ExternalResource() { + @Override + protected void before() throws Throwable { + log += "super.rule().before() "; + } + + @Override + protected void after() { + log += "super.rule().after() "; + } + }; + } + @Before public void before() { - log += "Before super "; + log += "super.before() "; } @After public void after() { - log += "After super "; + log += "super.after() "; } } static public class SubShadowing extends SuperShadowing { + + @Override + @Rule + public TestRule rule() { + return new ExternalResource() { + @Override + protected void before() throws Throwable { + log += "sub.rule().before() "; + } + + @Override + protected void after() { + log += "sub.rule().after() "; + } + }; + } + @Override @Before public void before() { - log += "Before sub "; + super.before(); + log += "sub.before() "; + } + + @Before + public void anotherBefore() { + log += "sub.anotherBefore() "; } @Override @After public void after() { - log += "After sub "; + log += "sub.after() "; + super.after(); + } + + @After + public void anotherAfter() { + log += "sub.anotherAfter() "; } @Test @@ -486,9 +537,157 @@ public void test() { public void testShadowing() throws Exception { log = ""; - JUnitCore core = new JUnitCore(); - core.run(SubShadowing.class); - assertEquals("Before sub Test After sub ", log); + assertThat(testResult(SubShadowing.class), isSuccessful()); + assertEquals( + "sub.rule().before() sub.anotherBefore() super.before() sub.before() " + + "Test " + + "sub.anotherAfter() sub.after() super.after() sub.rule().after() ", + log); + } + + static public abstract class SuperStaticMethodShadowing { + + @ClassRule + public static TestRule rule() { + return new ExternalResource() { + @Override + protected void before() throws Throwable { + log += "super.rule().before() "; + } + + @Override + protected void after() { + log += "super.rule().after() "; + } + }; + } + } + + static public class SubStaticMethodShadowing extends SuperStaticMethodShadowing { + + @ClassRule + public static TestRule rule() { + return new ExternalResource() { + @Override + protected void before() throws Throwable { + log += "sub.rule().before() "; + } + + @Override + protected void after() { + log += "sub.rule().after() "; + } + }; + } + + @Test + public void test() { + log += "Test "; + } + } + + public void testStaticMethodsCanBeTreatedAsShadowed() throws Exception { + log = ""; + assertThat(testResult(SubStaticMethodShadowing.class), isSuccessful()); + assertEquals( + "sub.rule().before() " + + "Test " + + "sub.rule().after() ", + log); + } + + static public abstract class SuperFieldShadowing { + + @Rule + public final TestRule rule = new ExternalResource() { + @Override + protected void before() throws Throwable { + log += "super.rule.before() "; + } + + @Override + protected void after() { + log += "super.rule.after() "; + } + }; + } + + static public class SubFieldShadowing extends SuperFieldShadowing { + + @Rule + public final TestRule rule = new ExternalResource() { + @Override + protected void before() throws Throwable { + log += "sub.rule.before() "; + } + + @Override + protected void after() { + log += "sub.rule.after() "; + } + }; + + @Test + public void test() { + log += "Test "; + } + } + + public void testFieldsShadowFieldsFromParent() throws Exception { + log = ""; + assertThat(testResult(SubFieldShadowing.class), isSuccessful()); + assertEquals( + "sub.rule.before() " + + "Test " + + "sub.rule.after() ", + log); + } + + static public abstract class SuperStaticFieldShadowing { + + @ClassRule + public static TestRule rule = new ExternalResource() { + @Override + protected void before() throws Throwable { + log += "super.rule.before() "; + } + + @Override + protected void after() { + log += "super.rule.after() "; + } + }; + } + + static public class SubStaticFieldShadowing extends SuperStaticFieldShadowing { + + @ClassRule + public static TestRule rule = new ExternalResource() { + @Override + protected void before() throws Throwable { + log += "sub.rule.before() "; + } + + @Override + protected void after() { + log += "sub.rule.after() "; + } + }; + + @Test + public void test() { + log += "Test "; + } + } + + public void testStaticFieldsCanBeTreatedAsShadowed() throws Exception { + log = ""; + assertThat(testResult(SubStaticFieldShadowing.class), isSuccessful()); + assertEquals( + "sub.rule.before() " + + "Test " + + "sub.rule.after() ", + log); } static public class SuperTest { diff --git a/src/test/java/org/junit/tests/running/methods/ExpectedTest.java b/src/test/java/org/junit/tests/running/methods/ExpectedTest.java index 236de9d72908..90e55f3157f3 100644 --- a/src/test/java/org/junit/tests/running/methods/ExpectedTest.java +++ b/src/test/java/org/junit/tests/running/methods/ExpectedTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertTrue; 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; @@ -67,4 +68,16 @@ public void throwsSubclass() { public void expectsSuperclass() { assertTrue(new JUnitCore().run(ExpectSuperclass.class).wasSuccessful()); } + + public static class ExpectAssumptionViolatedException { + @Test(expected = AssumptionViolatedException.class) + public void throwsAssumptionViolatedException() { + throw new AssumptionViolatedException("expected"); + } + } + + @Test + public void expectsAssumptionViolatedException() { + assertTrue(new JUnitCore().run(ExpectAssumptionViolatedException.class).wasSuccessful()); + } } diff --git a/src/test/java/org/junit/tests/running/methods/TimeoutTest.java b/src/test/java/org/junit/tests/running/methods/TimeoutTest.java index 8d23909bd893..21095fd15742 100644 --- a/src/test/java/org/junit/tests/running/methods/TimeoutTest.java +++ b/src/test/java/org/junit/tests/running/methods/TimeoutTest.java @@ -3,8 +3,8 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; diff --git a/src/test/java/org/junit/tests/validation/AllValidationTests.java b/src/test/java/org/junit/tests/validation/AllValidationTests.java new file mode 100644 index 000000000000..f04723ef2856 --- /dev/null +++ b/src/test/java/org/junit/tests/validation/AllValidationTests.java @@ -0,0 +1,14 @@ +package org.junit.tests.validation; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + BadlyFormedClassesTest.class, + FailedConstructionTest.class, + ValidationTest.class +}) +public class AllValidationTests { +} diff --git a/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java b/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java index 44cf26479f4c..d35de2cd2f4d 100644 --- a/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java +++ b/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java @@ -1,5 +1,7 @@ package org.junit.tests.validation; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -26,8 +28,6 @@ public void someTest() { } } - ; - @RunWith(JUnit4ClassRunner.class) public static class BadBeforeMethodWithLegacyRunner { @Before @@ -40,8 +40,6 @@ public void someTest() { } } - ; - public static class NoTests { // class without tests } @@ -54,7 +52,7 @@ public void constructorException() { @Test public void noRunnableMethods() { - assertEquals("No runnable methods", exceptionMessageFrom(NoTests.class)); + assertThat(exceptionMessageFrom(NoTests.class), containsString("No runnable methods")); } @Test diff --git a/src/test/java/org/junit/tests/validation/ValidationTest.java b/src/test/java/org/junit/tests/validation/ValidationTest.java index 5e7ff5575d1f..7a81b50f7a18 100644 --- a/src/test/java/org/junit/tests/validation/ValidationTest.java +++ b/src/test/java/org/junit/tests/validation/ValidationTest.java @@ -1,5 +1,7 @@ package org.junit.tests.validation; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import org.junit.BeforeClass; @@ -35,6 +37,6 @@ public void hereBecauseEveryTestClassNeedsATest() { @Test public void nonStaticBeforeClass() { Result result = JUnitCore.runClasses(NonStaticBeforeClass.class); - assertEquals("Method before() should be static", result.getFailures().get(0).getMessage()); + assertThat(result.getFailures().get(0).getMessage(), containsString("Method before() should be static")); } } diff --git a/src/test/java/org/junit/validator/AllValidatorTests.java b/src/test/java/org/junit/validator/AllValidatorTests.java new file mode 100644 index 000000000000..f9c1ca90c40d --- /dev/null +++ b/src/test/java/org/junit/validator/AllValidatorTests.java @@ -0,0 +1,14 @@ +package org.junit.validator; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + AnnotationsValidatorTest.class, + AnnotationValidatorFactoryTest.class, + PublicClassValidatorTest.class +}) +public class AllValidatorTests { +} diff --git a/src/test/java/org/junit/validator/AnnotationValidatorFactoryTest.java b/src/test/java/org/junit/validator/AnnotationValidatorFactoryTest.java index edab6277c187..064d4a3aff77 100644 --- a/src/test/java/org/junit/validator/AnnotationValidatorFactoryTest.java +++ b/src/test/java/org/junit/validator/AnnotationValidatorFactoryTest.java @@ -1,15 +1,12 @@ package org.junit.validator; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import java.lang.annotation.Annotation; - -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; - public class AnnotationValidatorFactoryTest { @Rule @@ -17,33 +14,13 @@ public class AnnotationValidatorFactoryTest { @Test public void createAnnotationValidator() { - ValidateWith validateWith = SampleTestWithValidator.class.getAnnotation(ValidateWith.class); + ValidateWith validateWith = SampleAnnotationWithValidator.class.getAnnotation(ValidateWith.class); AnnotationValidator annotationValidator = new AnnotationValidatorFactory().createAnnotationValidator(validateWith); assertThat(annotationValidator, is(instanceOf(Validator.class))); } - @Test - public void exceptionWhenAnnotationWithNullClassIsPassedIn() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Can't create validator, value is null in " + - "annotation org.junit.validator.AnnotationValidatorFactoryTest$ValidatorWithNullValue"); - - new AnnotationValidatorFactory().createAnnotationValidator(new ValidatorWithNullValue()); - } - - - public static class ValidatorWithNullValue implements ValidateWith { - public Class value() { - return null; - } - - public Class annotationType() { - return ValidateWith.class; - } - } - @ValidateWith(value = Validator.class) - public static class SampleTestWithValidator { + public @interface SampleAnnotationWithValidator { } public static class Validator extends AnnotationValidator { @@ -51,7 +28,7 @@ public static class Validator extends AnnotationValidator { @Test public void exceptionWhenAnnotationValidatorCantBeCreated() { - ValidateWith validateWith = SampleTestWithValidatorThatThrowsException.class.getAnnotation(ValidateWith.class); + ValidateWith validateWith = SampleAnnotationWithValidatorThatThrowsException.class.getAnnotation(ValidateWith.class); exception.expect(RuntimeException.class); exception.expectMessage("Exception received when creating AnnotationValidator class " + "org.junit.validator.AnnotationValidatorFactoryTest$ValidatorThatThrowsException"); @@ -59,7 +36,7 @@ public void exceptionWhenAnnotationValidatorCantBeCreated() { } @ValidateWith(value = ValidatorThatThrowsException.class) - public static class SampleTestWithValidatorThatThrowsException { + public @interface SampleAnnotationWithValidatorThatThrowsException { } public static class ValidatorThatThrowsException extends AnnotationValidator { diff --git a/src/test/java/org/junit/validator/AnnotationsValidatorTest.java b/src/test/java/org/junit/validator/AnnotationsValidatorTest.java index 657330930274..0be3cecb5903 100644 --- a/src/test/java/org/junit/validator/AnnotationsValidatorTest.java +++ b/src/test/java/org/junit/validator/AnnotationsValidatorTest.java @@ -2,7 +2,7 @@ import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; diff --git a/src/test/resources/junit/tests/runner/testRunAssumptionFailedResultCanBeReserialised_v4_12 b/src/test/resources/junit/tests/runner/testRunAssumptionFailedResultCanBeReserialised_v4_12 new file mode 100644 index 000000000000..5eb4ef97839d Binary files /dev/null and b/src/test/resources/junit/tests/runner/testRunAssumptionFailedResultCanBeReserialised_v4_12 differ diff --git a/src/test/resources/junit/tests/runner/testRunAssumptionFailedResultCanBeReserialised_v4_13 b/src/test/resources/junit/tests/runner/testRunAssumptionFailedResultCanBeReserialised_v4_13 new file mode 100644 index 000000000000..6fa2a060b86b Binary files /dev/null and b/src/test/resources/junit/tests/runner/testRunAssumptionFailedResultCanBeReserialised_v4_13 differ diff --git a/src/test/resources/junit/tests/runner/testRunFailureResultCanBeSerialised b/src/test/resources/junit/tests/runner/testRunFailureResultCanBeReserialised_v4_12 similarity index 100% rename from src/test/resources/junit/tests/runner/testRunFailureResultCanBeSerialised rename to src/test/resources/junit/tests/runner/testRunFailureResultCanBeReserialised_v4_12 diff --git a/src/test/resources/junit/tests/runner/testRunSuccessResultCanBeSerialised b/src/test/resources/junit/tests/runner/testRunSuccessResultCanBeReserialised_v4_12 similarity index 100% rename from src/test/resources/junit/tests/runner/testRunSuccessResultCanBeSerialised rename to src/test/resources/junit/tests/runner/testRunSuccessResultCanBeReserialised_v4_12 diff --git a/src/test/resources/junit/tests/runner/testRunSuccessResultCanBeReserialised_v4_13 b/src/test/resources/junit/tests/runner/testRunSuccessResultCanBeReserialised_v4_13 new file mode 100644 index 000000000000..6c3e1b378ff3 Binary files /dev/null and b/src/test/resources/junit/tests/runner/testRunSuccessResultCanBeReserialised_v4_13 differ diff --git a/src/test/resources/org/junit/internal/arrayComparisonFailure_411 b/src/test/resources/org/junit/internal/arrayComparisonFailure_411 new file mode 100644 index 000000000000..11fe0c51d7b1 Binary files /dev/null and b/src/test/resources/org/junit/internal/arrayComparisonFailure_411 differ diff --git a/src/test/resources/org/junit/internal/arrayComparisonFailure_412 b/src/test/resources/org/junit/internal/arrayComparisonFailure_412 new file mode 100644 index 000000000000..11fe0c51d7b1 Binary files /dev/null and b/src/test/resources/org/junit/internal/arrayComparisonFailure_412 differ