diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..ff30e87e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +github: jodastephen +open_collective: joda +tidelift: maven/org.threeten:threeten-extra + +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 00000000..f8ff1f13 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,10 @@ +# Security Policy + +## Supported Versions + +If a security issue occurs, only the latest version is guaranteed to be patched. + +## Reporting a Vulnerability + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..26aa42f9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +# Dependabot config + +version: 2 +updates: +- package-ecosystem: "maven" + directory: "/" + schedule: + interval: weekly + time: "02:30" + open-pull-requests-limit: 20 diff --git a/.github/maven-settings.xml b/.github/maven-settings.xml new file mode 100644 index 00000000..5fbfc607 --- /dev/null +++ b/.github/maven-settings.xml @@ -0,0 +1,13 @@ + + + + github + + ${GITHUB_TOKEN} + + + + diff --git a/.github/website.sh b/.github/website.sh new file mode 100644 index 00000000..d112a446 --- /dev/null +++ b/.github/website.sh @@ -0,0 +1,24 @@ + +echo "## setup..." +git config --global user.name "Stephen Colebourne (CI)" +git config --global user.email "scolebourne@joda.org" +cd target + +echo "## clone..." +git clone https://${GITHUB_TOKEN}@github.com/ThreeTen/threeten.github.io.git +cd threeten.github.io +git status + +echo "## copy..." +rm -rf threeten-extra/ +cp -R ../site threeten-extra/ + +echo "## update..." +git add -A +git status +git commit --message "Update threeten-extra from Travis: Build $TRAVIS_BUILD_NUMBER" + +echo "## push..." +git push origin main + +echo "## done" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..5eb595c8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,66 @@ +name: Build + +on: + push: + branches: + - '*' + tags: + - 'v*' + - 'website*' + pull_request: + branches: + - 'main' + schedule: + - cron: '41 19 * * 2' + +permissions: + contents: read + +jobs: + build: + permissions: + security-events: write # for github/codeql-action + runs-on: ubuntu-latest + strategy: + matrix: + java: [8, 11] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up JDK + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + cache: 'maven' + + - name: Maven version + run: | + mkdir -p ./.mvn + echo '-e -B -DtrimStackTrace=false' > ./.mvn/maven.config + mvn --version + mkdir -p target + + - name: Initialize CodeQL + if: matrix.java == '11' + uses: github/codeql-action/init@v2 + with: + languages: java + + - name: Maven build + run: | + mvn install site + + - name: Perform CodeQL Analysis + if: matrix.java == '11' + uses: github/codeql-action/analyze@v2 + + - name: Website + if: matrix.java == '11' && github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/website') || startsWith(github.ref, 'refs/tags/v')) + env: + GITHUB_TOKEN: ${{ secrets.PERSONAL_TOKEN_GH }} + run: | + chmod +x ./.github/website.sh + .github/website.sh diff --git a/.gitignore b/.gitignore index 8470331c..bfab9001 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ /*.iml /*.ipr /*.iws +/pom.xml.releaseBackup +/release.properties diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c0898988..00000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -# This file enables the Travis continuous integration system, which -# automatically builds and tests the project for each GitHub commit or -# pull request on three separate JDKs. -# -# For more information, see https://travis-ci.org - -language: java - -jdk: - - oraclejdk8 diff --git a/LICENSE.txt b/LICENSE.txt index fcdfc8f0..f8f6e594 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,31 +1,29 @@ -/* - * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos. + +All rights reserved. + +* Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of JSR-310 nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index bfce2239..12a4219b 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,44 @@ This project provides some of those additional classes as a well-tested and reli ### Documentation Various documentation is available: -* The [home page](http://www.threeten.org/threeten-extra/) -* The [user guide](http://www.threeten.org/threeten-extra/userguide.html) -* The [Javadoc](http://www.threeten.org/threeten-extra/apidocs/index.html) +* The [home page](https://www.threeten.org/threeten-extra/) +* The [user guide](https://www.threeten.org/threeten-extra/userguide.html) +* The [Javadoc](https://www.threeten.org/threeten-extra/apidocs/org.threeten.extra/module-summary.html) ### Releases -Release 1.0 is the current release. -This release is considered stable and worthy of the 1.x tag. +Release 1.8.0 is the current release. +This release is considered stable and worthy of the 1.x tag as per [SemVer](https://semver.org/spec/v2.0.0.html). ThreeTen-Extra requires Java SE 8 or later and has no dependencies. -Available in the [Maven Central repository](http://search.maven.org/#artifactdetails|org.threeten|threeten-extra|1.0|jar) +Available in the [Maven Central repository](https://search.maven.org/search?q=g:org.threeten%20AND%20a:threeten-extra&core=gav) + +``` + + org.threeten + threeten-extra + 1.8.0 + +``` + +![Tidelift lifted](https://img.shields.io/badge/-lifted!-2dd160.svg?colorA=58595b&style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAOCAYAAADJ7fe0AAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAAAVhJREFUKBV1kj0vBFEUhmd2sdZHh2IlGhKFQuOviEYiNlFodCqtUqPxA%2FwCjUTnDygkGoVERFQaZFlE9nreO%2BdM5u5wkifvuee892Pu3CyEcA0DeIc%2B9IwftJsR6Cko3uCjguZdjuBZhhwmYDjGrOC96WED41UtsgEdGEAPlmAfpuAbFF%2BFZLfoMfRBGzThDtLgePPwBIpdddGzOArhPHUXowbNptE2www6a%2Fm96Y3pHN7oQ1s%2B13pxt1ENaKzBFWyWzaJ%2BRO0C9Jny6VPSoKjLVbMDC5bn5OPuJF%2BBSe95PVEMuugY5AegS9fCh7BedP45hRnj8TC34QQUe9bTZyh2KgvFk2vc8GIlXyTfsvqr6bPpNgv52ynnlomZJNpB70Xhl%2Bf6Sa02p1bApEfnETwxVa%2Faj%2BW%2FFtHltmxS%2FO3krvpTtTnVgu%2F6gvHRFvG78Ef3kOe5PimJXycY74blT5R%2BAAAAAElFTkSuQmCC) ### Support -Please use GitHub [issues](https://github.com/ThreeTen/threeten-extra/issues) and Pull Requests for support. +Please use [Stack Overflow](https://stackoverflow.com/search?q=threeten-extra) for general usage questions. +GitHub [issues](https://github.com/ThreeTen/threeten-extra/issues) and [pull requests](https://github.com/ThreeTen/threeten-extra/pulls) +should be used when you want to help advance the project. +Commercial support is available via the +[Tidelift subscription](https://tidelift.com/subscription/pkg/maven-org-threeten-threeten-extra?utm_source=maven-org-threeten-threeten-extra&utm_medium=referral&utm_campaign=readme). + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. + + +### Release process + +* Update version (README.md, index.md, changes.xml) +* Commit and push +* Run `mvn clean release:clean release:prepare release:perform` on Java 11 +* Website will be built and released by GitHub Actions diff --git a/pom.xml b/pom.xml index 391cd616..84075d26 100644 --- a/pom.xml +++ b/pom.xml @@ -1,16 +1,17 @@ - + + + + + 4.0.0 org.threeten threeten-extra jar ThreeTen-Extra - 1.1-SNAPSHOT - Additional functionality that enhances JSR-310 dates and times in JDK 8 + 1.8.1-SNAPSHOT + Additional functionality that enhances JSR-310 dates and times in Java SE 8 and later https://www.threeten.org/threeten-extra @@ -25,7 +26,6 @@ jodastephen Stephen Colebourne - Project Lead @@ -38,53 +38,145 @@ Carlo Dapor https://github.com/catull + + Octavi Fornés + https://github.com/ofornes + + + Nick Glorioso + https://github.com/nglorioso + Jim Gough https://github.com/jpgough + + Monica Guzik + https://github.com/monicagg + Christian Heinemann https://github.com/cheinema + + John Hill + https://github.com/jjcard + + + Michael Hixson + https://github.com/michaelhixson + Stephen A. Imhoff https://github.com/Clockwork-Muse + + Johannes Jensen + https://github.com/spand + + + M. Justin + https://github.com/mjustin + + + Bruno P. Kinoshita + https://github.com/kinow + + + Kurt Alfred Kluever + https://github.com/kluever + + + Martin Kröning + https://github.com/mwkroening + + + Harald Kuhr + https://github.com/haraldk + + + Sebastian Lövdahl + https://github.com/slovdahl + Steven McCoy https://github.com/steve-o - Bjorn Raupach + JB Nizet + https://github.com/jnizet + + + Steven Paligo + https://github.com/stevenpaligo + + + Bjørn Erik Pedersen + https://github.com/bep + + + Erik van Paassen + https://github.com/evpaassen + + + Max Poliakov + https://github.com/Jaimies + + + Björn Raupach https://github.com/raupachz + + Michel Schudel + https://github.com/MichelSchudel + + + Michał Sobkiewicz + https://github.com/perceptron8 + Nils Sommer https://github.com/nsommer + + Tristan Swadell + https://github.com/TristonianJones + + + Roberto Tyley + https://github.com/rtyley + + + Dimo Velev + https://github.com/dimovelev + BSD 3-clause - https://raw.githubusercontent.com/ThreeTen/threeten-extra/master/LICENSE.txt + https://raw.githubusercontent.com/ThreeTen/threeten-extra/main/LICENSE.txt repo - scm:git:git@github.com:ThreeTen/threeten-extra.git - scm:git:git@github.com:ThreeTen/threeten-extra.git + scm:git:https://github.com/ThreeTen/threeten-extra.git + scm:git:https://github.com/ThreeTen/threeten-extra.git https://github.com/ThreeTen/threeten-extra + HEAD ThreeTen.org - http://www.threeten.org + https://www.threeten.org + + src/main/resources + META-INF ${project.basedir} @@ -92,69 +184,44 @@ LICENSE.txt - - ${basedir}/src/main/resources - + org.apache.maven.plugins maven-checkstyle-plugin + + + + org.jacoco + jacoco-maven-plugin + + + + org.apache.maven.plugins + maven-enforcer-plugin - run-checkstyle - process-sources + enforce-maven - checkstyle + enforce + + + + 3.6.0 + + + - - org.apache.maven.plugins - maven-surefire-plugin - - - **/Test*.java - - -Xmx2G - classes - 4 - - - - usedefaultlisteners - false - - - listener - org.testng.reporters.ExitCodeListener - - - reporter - org.testng.reporters.FailedReporter,org.testng.reporters.XMLReporter,org.testng.reporters.JUnitReportReporter - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - true - true - - - - + org.apache.felix maven-bundle-plugin - 2.4.0 + ${maven-bundle-plugin.version} bundle-manifest @@ -162,22 +229,30 @@ manifest + + + org.threeten.extra,org.threeten.extra.chrono,org.threeten.extra.scale + osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" + + + org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - package - - jar - - - + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + true + true + + + + org.apache.maven.plugins maven-source-plugin @@ -191,48 +266,6 @@ - - org.apache.maven.plugins - maven-site-plugin - - true - - - - lt.velykis.maven.skins - reflow-velocity-tools - 1.1.1 - - - org.apache.velocity - velocity - 1.7 - - - - - com.github.github - site-maven-plugin - 0.12 - - - github-site - - site - - site-deploy - - - - Create website for ${project.artifactId} v${project.version} - threeten-extra - true - github - ThreeTen - threeten.github.io - refs/heads/master - - @@ -268,6 +301,11 @@ maven-dependency-plugin ${maven-dependency-plugin.version} + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven-enforcer-plugin.version} + org.apache.maven.plugins maven-gpg-plugin @@ -318,11 +356,6 @@ maven-resources-plugin ${maven-resources-plugin.version} - - org.apache.maven.plugins - maven-site-plugin - ${maven-site-plugin.version} - org.apache.maven.plugins maven-source-plugin @@ -343,6 +376,94 @@ maven-toolchains-plugin ${maven-toolchains-plugin.version} + + + org.apache.maven.plugins + maven-release-plugin + ${maven-release-plugin.version} + + -Doss.repo + true + v@{project.version} + true + + + + org.kohsuke + github-api + ${github-api.version} + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin.version} + + + run-checkstyle + process-sources + + checkstyle + + + + + module-info.java + + + + com.puppycrawl.tools + checkstyle + ${checkstyle.version} + + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-maven-plugin.version} + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + org.apache.maven.plugins + maven-site-plugin + ${maven-site-plugin.version} + + true + + + + org.joda.external + reflow-velocity-tools + ${reflow-velocity-tools.version} + + + + org.eclipse.m2e lifecycle-mapping @@ -354,56 +475,88 @@ org.apache.felix maven-bundle-plugin - [2.4.0,) + [2.5.4,) manifest - - - - - - org.apache.maven.plugins - maven-toolchains-plugin - [1.0,) - - toolchain - - - - + - - org.apache.maven.plugins - maven-checkstyle-plugin - ${maven-checkstyle-plugin.version} - - - 3.0.4 - + + + + org.junit + junit-bom + ${junit.version} + pom + import + + + + + org.joda + joda-convert + ${joda-convert.version} + compile + true + com.google.guava guava - 19.0 + ${guava.version} test + + + com.google.code.findbugs + jsr305 + + + org.checkerframework + checker-qual + + + com.google.errorprone + error_prone_annotations + + + com.google.j2objc + j2objc-annotations + + - org.testng - testng - 6.10 + com.google.guava + guava-testlib + ${guava.version} + test + + + org.junit.jupiter + junit-jupiter + test + + + org.junit-pioneer + junit-pioneer + ${pioneer.version} + test + + + org.assertj + assertj-core + ${assertj.version} test @@ -411,24 +564,39 @@ + org.apache.maven.plugins maven-project-info-reports-plugin - ${maven-project-info-plugin.version} + ${maven-project-info-reports-plugin.version} + ci-management dependencies dependency-info - issue-tracking - license - project-team + issue-management + licenses + team scm summary + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin.version} + + false + false + false + module-info.java + + + org.apache.maven.plugins maven-javadoc-plugin @@ -441,14 +609,16 @@ + org.apache.maven.plugins maven-surefire-report-plugin ${maven-surefire-report-plugin.version} - true + true + org.apache.maven.plugins maven-changes-plugin @@ -461,26 +631,34 @@ + org.apache.maven.plugins - maven-jxr-plugin - ${maven-jxr-plugin.version} - - - - jxr - - - + maven-pmd-plugin + ${maven-pmd-plugin.version} + + 100 + ${maven.compiler.target} + + module-info.java + + + - org.apache.maven.plugins - maven-checkstyle-plugin - ${maven-checkstyle-plugin.version} + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-maven-plugin.version} + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} - checkstyle + report @@ -493,83 +671,209 @@ sonatype-threeten-staging Sonatype OSS staging repository - http://oss.sonatype.org/service/local/staging/deploy/maven2/ + https://oss.sonatype.org/service/local/staging/deploy/maven2/ default false sonatype-threeten-snapshot Sonatype OSS snapshot repository - http://oss.sonatype.org/content/repositories/threeten-snapshots + https://oss.sonatype.org/content/repositories/threeten-snapshots default - http://oss.sonatype.org/content/repositories/threeten-releases + https://oss.sonatype.org/content/repositories/threeten-releases + - activate-jdk8 + java8 - - jdk8 - + [1.6,9) + + + org.apache.maven.plugins + maven-compiler-plugin + + + module-info.java + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + module-info.java + + + + + + + + org.apache.maven.plugins - maven-toolchains-plugin + maven-javadoc-plugin + + true + + + + + + + + java9plus + + [9,) + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + compile + + copy-dependencies + + + ${project.build.directory}/dependencies + true + true + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + default-test + + true + --add-modules org.joda.convert --module-path ${project.build.directory}/dependencies ${argLine} + + + + test-without-modules + test + + test + + + false + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + package + + jar + + + + + 11 + + + + + org.apache.maven.plugins + maven-compiler-plugin + - validate + default-compile + + 9 + + + + + base-compile - toolchain + compile + + + module-info.java + + + - - - 1.8 - oracle - - + 8 + false + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + 11 + + + + + - repo-sign-artifacts + release-artifacts oss.repo - true + org.apache.maven.plugins - maven-toolchains-plugin + maven-enforcer-plugin - validate + enforce-java - toolchain + enforce + + + + [9,) + + + - - - - 1.8 - oracle - - - + org.apache.maven.plugins maven-gpg-plugin @@ -583,6 +887,43 @@ + + + + + de.jutzig + github-release-plugin + ${github-release-plugin.version} + + Release v${project.version} + See the [change notes](https://www.threeten.org/threeten-extra/changes-report.html) for more information. + v${project.version} + true + + + + github-releases + deploy + + release + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + true + + https://oss.sonatype.org/ + sonatype-joda-staging + true + true + 20 + + @@ -590,43 +931,58 @@ + + 3.24.2 + 2.2.3 + 5.10.1 + 1.9.1 + 32.1.3-jre - 2.5.5 - 2.11 - 2.16 - 2.6.1 - 3.3 - 2.8.2 - 2.10 - 1.6 - 2.5.2 - 2.6 - 2.10.3 - 2.5 - 3.4 - 3.5 - 2.8 + 3.7.1 + 5.1.8 + 2.12.1 + 3.2.0 + 3.3.2 + 3.13.0 + 3.1.1 + 3.6.1 + 3.4.1 + 3.2.3 + 3.1.0 + 3.4.0 + 3.6.3 + 3.3.0 + 3.12.0 + 3.21.2 + 3.5.0 + 3.0.1 2.4 - 2.7 - 3.4 - 2.4 - 2.18.1 - 2.18.1 - 1.1 + 3.3.1 + 3.12.1 + 3.2.1 + 3.2.5 + 3.2.5 + 3.1.0 + + 1.321 + 1.4.0 + 0.8.12 + 1.6.13 + 1.2 + 4.8.4.0 1.8 1.8 1.8 true - true - true - true false true - -Xdoclint:none + none - ${project.basedir}/src/main/checkstyle/checkstyle.xml + 8.41 + src/main/checkstyle/checkstyle.xml + false UTF-8 UTF-8 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 79c6a7f6..359abbc3 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -7,7 +7,247 @@ - + + + Add HourMinute. New class representing time but constrained to hours and minutes only. + + + Add YearHalf. New class representing a half-year, such as 2024-H1. + + + Add Interval.of(duration, end), providing another way to create an interval. + + + + + Adds offset for AccountingChronology, which is essential for some retail calendars, particularly the NRF. + Fixes #223, #201. + + + Update CodeQL. + + + Switch master to main. + + + + + Add utilities to work with durations as numbers. + Fixes #147. + + + Fix YearWeek.isSupported. + Fixes #192. + + + Fix InternationalFixedEra era value. + Fixes #205. + + + + + + Additional comparison methods on UtcInstant/TaiInstant. + Fixes #189. + + + Additional comparison methods on Interval. + Fixes #174. + + + Meaningful factory methods for unbounded intervals. + Fixes #174. + + + Add Go-compatible duration parsing. + Fixes #182. + + + Cache UtcInstant::toString(). + Fixes #177. + + + Enhance OffsetDate tests. + Fixes #181. + + + + + Add OffsetDate. + Fixes #137. + + + Add factory methods taking Year and Quarter objects. + Fixes #155, #156. + + + Add isZero(), isPositive(), isNegative() to temporal amount classes. + Fixes #148. + + + Make YearWeek implement Temporal. + Fixes #165, #163, #115. + + + Fix UtcInstant.isLeapSecond(). + Fixes #153. + + + Add Farsi translations for word-based formatting. + Fixes #131. + + + Add Bulgarian translations for word-based formatting. + Fixes #129. + + + Add Finnish translations for word-based formatting. + Fixes #127. + + + Add Swedish translations for word-based formatting. + Fixes #126. + + + Add Norwegian Bokml and Norwegian Nynorsk translations for word-based formatting. + Fixes #125. + + + Fix Interval Javadoc. + Fixes #171. + + + Fix Interval Javadoc. + Fixes #159. + + + + + Add stream-returning method YearQuarter.quartersUntil(YearQuarter). + Fixes #122. + + + Add word-based period formatting. + Note that textual data can only be altered by PRs to ThreeTen-Extra. + Based on original code from Joda-Time. + Fixes #113, #41. + + + Add Catalan translation for word-based formatting. + Fixes #123. + + + Add Joda-Convert annotations. + The additional Joda-Convert dependency is optional (except that on Scala it is apparently mandatory). + + + Add Tidelift commercial support and security policy. + + + + + Enhance LocalDateRange. + Add more factory methods for empty and unbounded. + Ensure that unbounded ranges are more clearly specified. + Reject certain ranges near LocalDate.MIN/LocalDate.MAX. + Alter behaviour of lengthInDays() and toPeriod(). + Fixes #100. + + + Fix build for Java 9. + Resource files cannot be read from other modules in Java 9. + As such, the `LeapSeconds.txt` file has moved to be under META-INF, + `META-INF/org/threeten/extra/scale/LeapSeconds.txt`. + + + Fix OSGi for Java 9. + Now that the build is on Java 9, the OSGi data had to be updated. + See #92, #94. + + + Add Temporals.nextWorkingDayOrSame() and Temporals.previousWorkingDayOrSame(). + Fixes #101. + + + Fix test parameter order. + See #98, #99. + + + + + Fix build for Java 8. + Found actual issue with Javac was in the pom.xml. + See #91. + + + + + Fix build for Java 8. + Javac release flag is not correctly ignoring new overloaded methods. + Fixes #91. + + + + + Support Java 9. + Update and redesign build. + + + Switch from TestNG to JUnit 4. + + + Error message and Javadoc fixes in Interval. + See #89. + + + Interval.parse now handles Instant.MIN/MAX. + See #80. + + + YearWeek.atDay now correctly handles the end of the year. + See #87. + + + Add MutableClock. + See #83, #84. + + + + + Add plusYears/minusYears to YearWeek. + See #78. + + + Add plusWeeks/minusWeeks to YearWeek. + See #78. + + + + + Add PeriodDuration, combining Period and Duration. + See #74. + + + Fix incorrect method name in Hours. + toPeriod() should have been toDuration(). + Fixes #76. + + + Extend formats parsed by Hours, Minutes and Seconds. + Fixes #77. + + + Extend formats parsed by Interval, allowing end instant to have offset inferred from start instant. + See #75. + + + Extend formats parsed by Interval, allowing years, months, weeks and days. + See #70. + + + Add Seconds temporal amount class. + See #73. + Add Temporals.parseFirstMatching(). This allows text to be parsed against a number of different formats. diff --git a/src/main/checkstyle/checkstyle.xml b/src/main/checkstyle/checkstyle.xml index 27af249f..f7a7b6d5 100644 --- a/src/main/checkstyle/checkstyle.xml +++ b/src/main/checkstyle/checkstyle.xml @@ -5,7 +5,6 @@ - @@ -31,12 +30,6 @@ - - - - - - @@ -44,11 +37,6 @@ - - - - - @@ -61,6 +49,9 @@ + + + @@ -118,25 +109,34 @@ + + + + + + + + + + + + - - - - - - - - - + + + + + + diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 00000000..60a3e7a6 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * ThreeTen-Extra provides additional date-time classes that complement those in Java SE 8. + *

+ * Not every piece of date/time logic is destined for the JDK. Some concepts are too + * specialized or too bulky to make it in. This project provides some of those additional + * classes as a well-tested and reliable module. + */ +module org.threeten.extra { + + // only annotations are used, thus they are optional + requires static org.joda.convert; + + // export all packages + exports org.threeten.extra; + exports org.threeten.extra.chrono; + exports org.threeten.extra.scale; + + // provide the services + provides java.time.chrono.Chronology + with org.threeten.extra.chrono.BritishCutoverChronology, + org.threeten.extra.chrono.CopticChronology, + org.threeten.extra.chrono.DiscordianChronology, + org.threeten.extra.chrono.EthiopicChronology, + org.threeten.extra.chrono.InternationalFixedChronology, + org.threeten.extra.chrono.JulianChronology, + org.threeten.extra.chrono.PaxChronology, + org.threeten.extra.chrono.Symmetry010Chronology, + org.threeten.extra.chrono.Symmetry454Chronology; + +} diff --git a/src/main/java/org/threeten/extra/AmountFormats.java b/src/main/java/org/threeten/extra/AmountFormats.java new file mode 100644 index 00000000..facbf480 --- /dev/null +++ b/src/main/java/org/threeten/extra/AmountFormats.java @@ -0,0 +1,693 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import java.time.Duration; +import java.time.Period; +import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAmount; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Optional; +import java.util.ResourceBundle; +import java.util.function.Function; +import java.util.function.IntPredicate; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +/** + * Provides the ability to format a temporal amount. + *

+ * This allows a {@link TemporalAmount}, such as {@link Duration} or {@link Period}, + * to be formatted. Only selected formatting options are provided. + * + *

Implementation Requirements:

+ * This class is immutable and thread-safe. + */ +public final class AmountFormats { + + /** + * The number of days per week. + */ + private static final int DAYS_PER_WEEK = 7; + /** + * The number of hours per day. + */ + private static final int HOURS_PER_DAY = 24; + /** + * The number of minutes per hour. + */ + private static final int MINUTES_PER_HOUR = 60; + /** + * The number of seconds per minute. + */ + private static final int SECONDS_PER_MINUTE = 60; + /** + * The number of nanosecond per millisecond. + */ + private static final int NANOS_PER_MILLIS = 1000_000; + /** + * The resource bundle name. + */ + private static final String BUNDLE_NAME = "org.threeten.extra.wordbased"; + /** + * The pattern to split lists with. + */ + private static final Pattern SPLITTER = Pattern.compile("[|][|][|]"); + /** + * The property file key for the separator ", ". + */ + private static final String WORDBASED_COMMASPACE = "WordBased.commaspace"; + /** + * The property file key for the separator " and ". + */ + private static final String WORDBASED_SPACEANDSPACE = "WordBased.spaceandspace"; + /** + * The property file key for the word "year". + */ + private static final String WORDBASED_YEAR = "WordBased.year"; + /** + * The property file key for the word "month". + */ + private static final String WORDBASED_MONTH = "WordBased.month"; + /** + * The property file key for the word "week". + */ + private static final String WORDBASED_WEEK = "WordBased.week"; + /** + * The property file key for the word "day". + */ + private static final String WORDBASED_DAY = "WordBased.day"; + /** + * The property file key for the word "hour". + */ + private static final String WORDBASED_HOUR = "WordBased.hour"; + /** + * The property file key for the word "minute". + */ + private static final String WORDBASED_MINUTE = "WordBased.minute"; + /** + * The property file key for the word "second". + */ + private static final String WORDBASED_SECOND = "WordBased.second"; + /** + * The property file key for the word "millisecond". + */ + private static final String WORDBASED_MILLISECOND = "WordBased.millisecond"; + /** + * The predicate that matches 1 or -1. + */ + private static final IntPredicate PREDICATE_1 = value -> value == 1 || value == -1; + /** + * The predicate that matches numbers ending 1 but not ending 11. + */ + private static final IntPredicate PREDICATE_END1_NOT11 = value -> { + int abs = Math.abs(value); + int last = abs % 10; + int secondLast = (abs % 100) / 10; + return (last == 1 && secondLast != 1); + }; + /** + * The predicate that matches numbers ending 2, 3 or 4, but not ending 12, 13 or 14. + */ + private static final IntPredicate PREDICATE_END234_NOTTEENS = value -> { + int abs = Math.abs(value); + int last = abs % 10; + int secondLast = (abs % 100) / 10; + return (last >= 2 && last <= 4 && secondLast != 1); + }; + /** + * List of DurationUnit values ordered by longest suffix first. + */ + private static final List DURATION_UNITS = + Arrays.asList(new DurationUnit("ns", Duration.ofNanos(1)), + new DurationUnit("µs", Duration.ofNanos(1000)), // U+00B5 = micro symbol + new DurationUnit("μs", Duration.ofNanos(1000)), // U+03BC = Greek letter mu + new DurationUnit("us", Duration.ofNanos(1000)), + new DurationUnit("ms", Duration.ofMillis(1)), + new DurationUnit("s", Duration.ofSeconds(1)), + new DurationUnit("m", Duration.ofMinutes(1)), + new DurationUnit("h", Duration.ofHours(1))); + /** + * Zero value for an absent fractional component of a numeric duration string. + */ + private static final FractionScalarPart EMPTY_FRACTION = new FractionScalarPart(0, 0); + + //----------------------------------------------------------------------- + /** + * Formats a period and duration to a string in ISO-8601 format. + *

+ * To obtain the ISO-8601 format of a {@code Period} or {@code Duration} + * individually, simply call {@code toString()}. + * See also {@link PeriodDuration}. + * + * @param period the period to format + * @param duration the duration to format + * @return the ISO-8601 format for the period and duration + */ + public static String iso8601(Period period, Duration duration) { + Objects.requireNonNull(period, "period must not be null"); + Objects.requireNonNull(duration, "duration must not be null"); + if (period.isZero()) { + return duration.toString(); + } + if (duration.isZero()) { + return period.toString(); + } + return period.toString() + duration.toString().substring(1); + } + + //------------------------------------------------------------------------- + /** + * Formats a period to a string in a localized word-based format. + *

+ * This returns a word-based format for the period. + * The year and month are printed as supplied unless the signs differ, in which case they are normalized. + * The words are configured in a resource bundle text file - + * {@code org.threeten.extra.wordbased.properties} - with overrides per language. + * + * @param period the period to format + * @param locale the locale to use + * @return the localized word-based format for the period + */ + public static String wordBased(Period period, Locale locale) { + Objects.requireNonNull(period, "period must not be null"); + Objects.requireNonNull(locale, "locale must not be null"); + ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME, locale); + UnitFormat[] formats = { + UnitFormat.of(bundle, WORDBASED_YEAR), + UnitFormat.of(bundle, WORDBASED_MONTH), + UnitFormat.of(bundle, WORDBASED_WEEK), + UnitFormat.of(bundle, WORDBASED_DAY)}; + WordBased wb = new WordBased(formats, bundle.getString(WORDBASED_COMMASPACE), bundle.getString(WORDBASED_SPACEANDSPACE)); + + Period normPeriod = oppositeSigns(period.getMonths(), period.getYears()) ? period.normalized() : period; + int weeks = 0; + int days = 0; + if (normPeriod.getDays() % DAYS_PER_WEEK == 0) { + weeks = normPeriod.getDays() / DAYS_PER_WEEK; + } else { + days = normPeriod.getDays(); + } + int[] values = {normPeriod.getYears(), normPeriod.getMonths(), weeks, days}; + return wb.format(values); + } + + /** + * Formats a duration to a string in a localized word-based format. + *

+ * This returns a word-based format for the duration. + * The words are configured in a resource bundle text file - + * {@code org.threeten.extra.wordbased.properties} - with overrides per language. + * + * @param duration the duration to format + * @param locale the locale to use + * @return the localized word-based format for the duration + */ + public static String wordBased(Duration duration, Locale locale) { + Objects.requireNonNull(duration, "duration must not be null"); + Objects.requireNonNull(locale, "locale must not be null"); + ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME, locale); + UnitFormat[] formats = { + UnitFormat.of(bundle, WORDBASED_HOUR), + UnitFormat.of(bundle, WORDBASED_MINUTE), + UnitFormat.of(bundle, WORDBASED_SECOND), + UnitFormat.of(bundle, WORDBASED_MILLISECOND)}; + WordBased wb = new WordBased(formats, bundle.getString(WORDBASED_COMMASPACE), bundle.getString(WORDBASED_SPACEANDSPACE)); + + long hours = duration.toHours(); + long mins = duration.toMinutes() % MINUTES_PER_HOUR; + long secs = duration.getSeconds() % SECONDS_PER_MINUTE; + int millis = duration.getNano() / NANOS_PER_MILLIS; + int[] values = {(int) hours, (int) mins, (int) secs, millis}; + return wb.format(values); + } + + /** + * Formats a period and duration to a string in a localized word-based format. + *

+ * This returns a word-based format for the period. + * The year and month are printed as supplied unless the signs differ, in which case they are normalized. + * The words are configured in a resource bundle text file - + * {@code org.threeten.extra.wordbased.properties} - with overrides per language. + * + * @param period the period to format + * @param duration the duration to format + * @param locale the locale to use + * @return the localized word-based format for the period and duration + */ + public static String wordBased(Period period, Duration duration, Locale locale) { + Objects.requireNonNull(period, "period must not be null"); + Objects.requireNonNull(duration, "duration must not be null"); + Objects.requireNonNull(locale, "locale must not be null"); + ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME, locale); + UnitFormat[] formats = { + UnitFormat.of(bundle, WORDBASED_YEAR), + UnitFormat.of(bundle, WORDBASED_MONTH), + UnitFormat.of(bundle, WORDBASED_WEEK), + UnitFormat.of(bundle, WORDBASED_DAY), + UnitFormat.of(bundle, WORDBASED_HOUR), + UnitFormat.of(bundle, WORDBASED_MINUTE), + UnitFormat.of(bundle, WORDBASED_SECOND), + UnitFormat.of(bundle, WORDBASED_MILLISECOND)}; + WordBased wb = new WordBased(formats, bundle.getString(WORDBASED_COMMASPACE), bundle.getString(WORDBASED_SPACEANDSPACE)); + + Period normPeriod = oppositeSigns(period.getMonths(), period.getYears()) ? period.normalized() : period; + int weeks = 0; + int days = 0; + if (normPeriod.getDays() % DAYS_PER_WEEK == 0) { + weeks = normPeriod.getDays() / DAYS_PER_WEEK; + } else { + days = normPeriod.getDays(); + } + long totalHours = duration.toHours(); + days += (int) (totalHours / HOURS_PER_DAY); + int hours = (int) (totalHours % HOURS_PER_DAY); + int mins = (int) (duration.toMinutes() % MINUTES_PER_HOUR); + int secs = (int) (duration.getSeconds() % SECONDS_PER_MINUTE); + int millis = duration.getNano() / NANOS_PER_MILLIS; + int[] values = { + normPeriod.getYears(), normPeriod.getMonths(), weeks, days, + (int) hours, mins, secs, millis}; + return wb.format(values); + } + + // are the signs opposite + private static boolean oppositeSigns(int a, int b) { + return a < 0 ? (b >= 0) : (b < 0); + } + + // ------------------------------------------------------------------------- + /** + * Parses formatted durations based on units. + *

+ * The behaviour matches the Golang + * duration parser, however, infinite durations are not supported. + *

+ * The duration format is a possibly signed sequence of decimal numbers, each with optional + * fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are + * "ns", "us" (or "µs"), "ms", "s", "m", "h". + *

+ * Note, the value "0" is specially supported as {@code Duration.ZERO}. + * + * @param durationText the formatted unit-based duration string. + * @return the {@code Duration} value represented by the string, if possible. + */ + public static Duration parseUnitBasedDuration(CharSequence durationText) { + Objects.requireNonNull(durationText, "durationText must not be null"); + + // variables for tracking error positions during parsing. + int offset = 0; + CharSequence original = durationText; + + // consume the leading sign - or + if one is present. + int sign = 1; + Optional updatedText = consumePrefix(durationText, '-'); + if (updatedText.isPresent()) { + sign = -1; + offset += 1; + durationText = updatedText.get(); + } else { + updatedText = consumePrefix(durationText, '+'); + if (updatedText.isPresent()) { + offset += 1; + } + durationText = updatedText.orElse(durationText); + } + // special case for a string of "0" + if (durationText.equals("0")) { + return Duration.ZERO; + } + // special case, empty string as an invalid duration. + if (durationText.length() == 0) { + throw new DateTimeParseException("Not a numeric value", original, 0); + } + + Duration value = Duration.ZERO; + int durationTextLength = durationText.length(); + while (durationTextLength > 0) { + ParsedUnitPart integerPart = + consumeDurationLeadingInt(durationText, original, offset); + offset += (durationText.length() - integerPart.remainingText().length()); + durationText = integerPart.remainingText(); + DurationScalar leadingInt = integerPart; + DurationScalar fraction = EMPTY_FRACTION; + Optional dot = consumePrefix(durationText, '.'); + if (dot.isPresent()) { + offset += 1; + durationText = dot.get(); + ParsedUnitPart fractionPart = + consumeDurationFraction(durationText, original, offset); + // update the remaining string and fraction. + offset += (durationText.length() - fractionPart.remainingText().length()); + durationText = fractionPart.remainingText(); + fraction = fractionPart; + } + + Optional optUnit = findUnit(durationText); + if (!optUnit.isPresent()) { + throw new DateTimeParseException( + "Invalid duration unit", original, offset); + } + DurationUnit unit = optUnit.get(); + try { + Duration unitValue = leadingInt.applyTo(unit); + Duration fractionValue = fraction.applyTo(unit); + unitValue = unitValue.plus(fractionValue); + value = value.plus(unitValue); + } catch (ArithmeticException e) { + throw new DateTimeParseException( + "Duration string exceeds valid numeric range", + original, offset, e); + } + // update the remaining text and text length. + CharSequence remainingText = unit.consumeDurationUnit(durationText); + offset += (durationText.length() - remainingText.length()); + durationText = remainingText; + durationTextLength = durationText.length(); + } + return sign < 0 ? value.negated() : value; + } + + // consume the fractional part of a unit-based duration, e.g. + // .. + private static ParsedUnitPart consumeDurationLeadingInt(CharSequence text, + CharSequence original, int offset) { + long integerPart = 0; + int i = 0; + int valueLength = text.length(); + for ( ; i < valueLength; i++) { + char c = text.charAt(i); + if (c < '0' || c > '9') { + break; + } + // overflow of a single numeric specifier for a duration. + if (integerPart > Long.MAX_VALUE / 10) { + throw new DateTimeParseException( + "Duration string exceeds valid numeric range", + original, i + offset); + } + integerPart *= 10; + integerPart += (long) (c - '0'); + // overflow of a single numeric specifier for a duration. + if (integerPart < 0) { + throw new DateTimeParseException( + "Duration string exceeds valid numeric range", + original, i + offset); + } + } + // if no text was consumed, return empty. + if (i == 0) { + throw new DateTimeParseException("Missing leading integer", original, offset); + } + return new ParsedUnitPart(text.subSequence(i, text.length()), + new IntegerScalarPart(integerPart)); + } + + // consume the fractional part of a unit-based duration, e.g. + // .. + private static ParsedUnitPart consumeDurationFraction(CharSequence text, + CharSequence original, int offset) { + int i = 0; + long fraction = 0; + long scale = 1; + boolean overflow = false; + for ( ; i < text.length(); i++) { + char c = text.charAt(i); + if (c < '0' || c > '9') { + break; + } + // for the fractional part, it's possible to overflow; however, + // this does not invalidate the duration, but rather it means that + // the precision of the fractional part is truncated to 999,999,999. + if (overflow || fraction > Long.MAX_VALUE / 10) { + continue; + } + long tmp = fraction * 10 + (long) (c - '0'); + if (tmp < 0) { + overflow = true; + continue; + } + fraction = tmp; + scale *= 10; + } + if (i == 0) { + throw new DateTimeParseException( + "Missing numeric fraction after '.'", original, offset); + } + return new ParsedUnitPart(text.subSequence(i, text.length()), + new FractionScalarPart(fraction, scale)); + } + + // find the duration unit at the beginning of the input text, if present. + private static Optional findUnit(CharSequence text) { + return DURATION_UNITS.stream() + .sequential() + .filter(du -> du.prefixMatchesUnit(text)) + .findFirst(); + } + + // consume the indicated {@code prefix} if it exists at the beginning of the + // text, returning the + // remaining string if the prefix was consumed. + private static Optional consumePrefix(CharSequence text, char prefix) { + if (text.length() > 0 && text.charAt(0) == prefix) { + return Optional.of(text.subSequence(1, text.length())); + } + return Optional.empty(); + } + + private AmountFormats() { + } + + //------------------------------------------------------------------------- + // data holder for word-based formats + static final class WordBased { + private final UnitFormat[] units; + private final String separator; + private final String lastSeparator; + + public WordBased(UnitFormat[] units, String separator, String lastSeparator) { + this.units = units; + this.separator = separator; + this.lastSeparator = lastSeparator; + } + + String format(int[] values) { + StringBuilder buf = new StringBuilder(32); + int nonZeroCount = 0; + for (int i = 0; i < values.length; i++) { + if (values[i] != 0) { + nonZeroCount++; + } + } + int count = 0; + for (int i = 0; i < values.length; i++) { + if (values[i] != 0 || (count == 0 && i == values.length - 1)) { + units[i].formatTo(values[i], buf); + if (count < nonZeroCount - 2) { + buf.append(separator); + } else if (count == nonZeroCount - 2) { + buf.append(lastSeparator); + } + count++; + } + } + return buf.toString(); + } + } + + // data holder for single/plural formats + static interface UnitFormat { + + static UnitFormat of(ResourceBundle bundle, String keyStem) { + if (bundle.containsKey(keyStem + "s.predicates")) { + String predicateList = bundle.getString(keyStem + "s.predicates"); + String textList = bundle.getString(keyStem + "s.list"); + String[] regexes = SPLITTER.split(predicateList); + String[] text = SPLITTER.split(textList); + return new PredicateFormat(regexes, text); + } else { + String single = bundle.getString(keyStem); + String plural = bundle.getString(keyStem + "s"); + return new SinglePluralFormat(single, plural); + } + } + + void formatTo(int value, StringBuilder buf); + } + + // data holder for single/plural formats + static final class SinglePluralFormat implements UnitFormat { + private final String single; + private final String plural; + + SinglePluralFormat(String single, String plural) { + this.single = single; + this.plural = plural; + } + + @Override + public void formatTo(int value, StringBuilder buf) { + buf.append(value).append(value == 1 || value == -1 ? single : plural); + } + } + + // data holder for predicate formats + static final class PredicateFormat implements UnitFormat { + private final IntPredicate[] predicates; + private final String[] text; + + PredicateFormat(String[] predicateStrs, String[] text) { + if (predicateStrs.length + 1 != text.length) { + throw new IllegalStateException("Invalid word-based resource"); + } + this.predicates = Stream.of(predicateStrs) + .map(predicateStr -> findPredicate(predicateStr)) + .toArray(IntPredicate[]::new); + this.text = text; + } + + private IntPredicate findPredicate(String predicateStr) { + switch (predicateStr) { + case "One": return PREDICATE_1; + case "End234NotTeens": return PREDICATE_END234_NOTTEENS; + case "End1Not11": return PREDICATE_END1_NOT11; + default: throw new IllegalStateException("Invalid word-based resource"); + } + } + + @Override + public void formatTo(int value, StringBuilder buf) { + for (int i = 0; i < predicates.length; i++) { + if (predicates[i].test(value)) { + buf.append(value).append(text[i]); + return; + } + } + buf.append(value).append(text[predicates.length]); + } + } + + // ------------------------------------------------------------------------- + // data holder for a duration unit string and its associated Duration value. + static final class DurationUnit { + private final String abbrev; + private final Duration value; + + private DurationUnit(String abbrev, Duration value) { + this.abbrev = abbrev; + this.value = value; + } + + // whether the input text starts with the unit abbreviation. + boolean prefixMatchesUnit(CharSequence text) { + return text.length() >= abbrev.length() + && abbrev.equals(text.subSequence(0, abbrev.length())); + } + + // consume the duration unit and returning the remaining text. + CharSequence consumeDurationUnit(CharSequence text) { + return text.subSequence(abbrev.length(), text.length()); + } + + // scale the unit by the input scalingFunction, returning a value if + // one is produced, or an empty result when the operation results in an + // arithmetic overflow. + Duration scaleBy(Function scaleFunc) { + return scaleFunc.apply(value); + } + } + + // interface for computing a duration from a duration unit and a scalar. + static interface DurationScalar { + // returns a duration value on a successful computation, and an empty + // result otherwise. + Duration applyTo(DurationUnit unit); + } + + // data holder for parsed fragments of a floating point duration scalar. + static final class ParsedUnitPart implements DurationScalar { + private final CharSequence remainingText; + private final DurationScalar scalar; + + private ParsedUnitPart(CharSequence remainingText, DurationScalar scalar) { + this.remainingText = remainingText; + this.scalar = scalar; + } + + @Override + public Duration applyTo(DurationUnit unit) { + return scalar.applyTo(unit); + } + + CharSequence remainingText() { + return remainingText; + } + } + + // data holder for the leading integer value of a duration scalar. + static final class IntegerScalarPart implements DurationScalar { + private final long value; + + private IntegerScalarPart(long value) { + this.value = value; + } + + @Override + public Duration applyTo(DurationUnit unit) { + return unit.scaleBy(d -> d.multipliedBy(value)); + } + } + + // data holder for the fractional floating point value of a duration + // scalar. + static final class FractionScalarPart implements DurationScalar { + private final long value; + private final long scale; + + private FractionScalarPart(long value, long scale) { + this.value = value; + this.scale = scale; + } + + @Override + public Duration applyTo(DurationUnit unit) { + if (value == 0) { + return Duration.ZERO; + } + return unit.scaleBy(d -> d.multipliedBy(value).dividedBy(scale)); + } + } +} diff --git a/src/main/java/org/threeten/extra/Days.java b/src/main/java/org/threeten/extra/Days.java index e0724cad..8ae5a269 100644 --- a/src/main/java/org/threeten/extra/Days.java +++ b/src/main/java/org/threeten/extra/Days.java @@ -48,6 +48,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * A day-based amount of time, such as '12 days'. *

@@ -203,11 +206,12 @@ public static Days from(TemporalAmount amount) { * @return the parsed period, not null * @throws DateTimeParseException if the text cannot be parsed to a period */ + @FromString public static Days parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { - int negate = ("-".equals(matcher.group(1)) ? -1 : 1); + int negate = "-".equals(matcher.group(1)) ? -1 : 1; String weeksStr = matcher.group(2); String daysStr = matcher.group(3); if (weeksStr != null || daysStr != null) { @@ -281,7 +285,7 @@ private Object readResolve() { */ @Override public long get(TemporalUnit unit) { - if (unit == ChronoUnit.DAYS) { + if (unit == DAYS) { return days; } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); @@ -312,6 +316,33 @@ public int getAmount() { return days; } + /** + * Checks if the amount is negative. + * + * @return true if the amount is negative, false if the amount is zero or positive + */ + public boolean isNegative() { + return getAmount() < 0; + } + + /** + * Checks if the amount is zero. + * + * @return true if the amount is zero, false if not + */ + public boolean isZero() { + return getAmount() == 0; + } + + /** + * Checks if the amount is positive. + * + * @return true if the amount is positive, false if the amount is zero or negative + */ + public boolean isPositive() { + return getAmount() > 0; + } + //----------------------------------------------------------------------- /** * Returns a copy of this amount with the specified amount added. @@ -353,13 +384,13 @@ public Days plus(int days) { *

* This instance is immutable and unaffected by this method call. * - * @param amountToAdd the amount to add, not null + * @param amountToSubtract the amount to subtract, not null * @return a {@code Days} based on this instance with the requested amount subtracted, not null * @throws DateTimeException if the specified amount contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ - public Days minus(TemporalAmount amountToAdd) { - return minus(Days.from(amountToAdd).getAmount()); + public Days minus(TemporalAmount amountToSubtract) { + return minus(Days.from(amountToSubtract).getAmount()); } /** @@ -574,6 +605,7 @@ public int hashCode() { * @return the number of days in ISO-8601 string format */ @Override + @ToString public String toString() { return "P" + days + "D"; } diff --git a/src/main/java/org/threeten/extra/Half.java b/src/main/java/org/threeten/extra/Half.java new file mode 100644 index 00000000..99d63561 --- /dev/null +++ b/src/main/java/org/threeten/extra/Half.java @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static org.threeten.extra.TemporalFields.HALF_OF_YEAR; +import static org.threeten.extra.TemporalFields.HALF_YEARS; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.Month; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.TextStyle; +import java.time.temporal.ChronoField; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalQuery; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; +import java.util.Locale; + +/** + * A half-of-year, such as 'H2'. + *

+ * {@code Half} is an enum representing the 2 halves of the year - H1 and H2. + * These are defined as January to June and July to December. + *

+ * The {@code int} value follows the half, from 1 (H1) to 2 (H2). + * It is recommended that applications use the enum rather than the {@code int} value + * to ensure code clarity. + *

+ * Do not use {@code ordinal()} to obtain the numeric representation of {@code Half}. + * Use {@code getValue()} instead. + * + *

Implementation Requirements:

+ * This is an immutable and thread-safe enum. + */ +public enum Half implements TemporalAccessor, TemporalAdjuster { + + /** + * The singleton instance for the first half-of-year, from January to June. + * This has the numeric value of {@code 1}. + */ + H1, + /** + * The singleton instance for the second half-of-year, from July to December. + * This has the numeric value of {@code 2}. + */ + H2; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Half} from an {@code int} value. + *

+ * {@code Half} is an enum representing the 2 halves of the year. + * This factory allows the enum to be obtained from the {@code int} value. + * The {@code int} value follows the half, from 1 (H1) to 2 (H2). + * + * @param halfOfYear the half-of-year to represent, from 1 (H1) to 2 (H2) + * @return the half-of-year, not null + * @throws DateTimeException if the half-of-year is invalid + */ + public static Half of(int halfOfYear) { + switch (halfOfYear) { + case 1: + return H1; + case 2: + return H2; + default: + throw new DateTimeException("Invalid value for Half: " + halfOfYear); + } + } + + /** + * Obtains an instance of {@code Half} from a month-of-year. + *

+ * {@code Half} is an enum representing the 2 halves of the year. + * This factory allows the enum to be obtained from the {@code Month} value. + *

+ * January to June are H1 and July to December are H2. + * + * @param monthOfYear the month-of-year to convert from, from 1 to 12 + * @return the half-of-year, not null + * @throws DateTimeException if the month-of-year is invalid + */ + public static Half ofMonth(int monthOfYear) { + MONTH_OF_YEAR.range().checkValidValue(monthOfYear, MONTH_OF_YEAR); + return of(monthOfYear <= 6 ? 1 : 2); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Half} from a temporal object. + *

+ * This obtains a half based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code Half}. + *

+ * The conversion extracts the {@link TemporalFields#HALF_OF_YEAR HALF_OF_YEAR} field. + * The extraction is only permitted if the temporal object has an ISO + * chronology, or can be converted to a {@code LocalDate}. + *

+ * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code Half::from}. + * + * @param temporal the temporal-time object to convert, not null + * @return the half-of-year, not null + * @throws DateTimeException if unable to convert to a {@code Half} + */ + public static Half from(TemporalAccessor temporal) { + if (temporal instanceof Half) { + return (Half) temporal; + } else if (temporal instanceof Month) { + Month month = (Month) temporal; + return of(month.ordinal() / 6 + 1); + } + try { + TemporalAccessor adjusted = + !IsoChronology.INSTANCE.equals(Chronology.from(temporal)) ? LocalDate.from(temporal) : temporal; + // need to use getLong() as JDK Parsed class get() doesn't work properly + int qoy = Math.toIntExact(adjusted.getLong(HALF_OF_YEAR)); + return of(qoy); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain Half from TemporalAccessor: " + + temporal + " of type " + temporal.getClass().getName(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the half-of-year {@code int} value. + *

+ * The values are numbered following the ISO-8601 standard, + * from 1 (H1) to 2 (H2). + * + * @return the half-of-year, from 1 (H1) to 2 (H2) + */ + public int getValue() { + return ordinal() + 1; + } + + //----------------------------------------------------------------------- + /** + * Gets the textual representation, such as 'H1' or '4th half'. + *

+ * This returns the textual name used to identify the half-of-year, + * suitable for presentation to the user. + * The parameters control the style of the returned text and the locale. + *

+ * If no textual mapping is found then the {@link #getValue() numeric value} is returned. + * + * @param style the length of the text required, not null + * @param locale the locale to use, not null + * @return the text value of the half-of-year, not null + */ + public String getDisplayName(TextStyle style, Locale locale) { + return new DateTimeFormatterBuilder().appendText(HALF_OF_YEAR, style).toFormatter(locale).format(this); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

+ * This checks if this half-of-year can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

+ * If the field is {@link TemporalFields#HALF_OF_YEAR HALF_OF_YEAR} then + * this method returns true. + * All {@code ChronoField} instances will return false. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this half-of-year, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field == HALF_OF_YEAR) { + return true; + } else if (field instanceof ChronoField) { + return false; + } + return field != null && field.isSupportedBy(this); + } + + /** + * Gets the range of valid values for the specified field. + *

+ * The range object expresses the minimum and maximum valid values for a field. + * This half is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is {@link TemporalFields#HALF_OF_YEAR HALF_OF_YEAR} then the + * range of the half-of-year, from 1 to 2, will be returned. + * All {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + * @throws UnsupportedTemporalTypeException if the field is not supported + */ + @Override + public ValueRange range(TemporalField field) { + if (field == HALF_OF_YEAR) { + return field.range(); + } else if (field instanceof ChronoField) { + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + return TemporalAccessor.super.range(field); + } + + /** + * Gets the value of the specified field from this half-of-year as an {@code int}. + *

+ * This queries this half for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is {@link TemporalFields#HALF_OF_YEAR HALF_OF_YEAR} then the + * value of the half-of-year, from 1 to 2, will be returned. + * All {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field, within the valid range of values + * @throws DateTimeException if a value for the field cannot be obtained or + * the value is outside the range of valid values for the field + * @throws UnsupportedTemporalTypeException if the field is not supported or + * the range of values exceeds an {@code int} + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public int get(TemporalField field) { + if (field == HALF_OF_YEAR) { + return getValue(); + } else if (field instanceof ChronoField) { + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + return TemporalAccessor.super.get(field); + } + + /** + * Gets the value of the specified field from this half-of-year as a {@code long}. + *

+ * This queries this half for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is {@link TemporalFields#HALF_OF_YEAR HALF_OF_YEAR} then the + * value of the half-of-year, from 1 to 2, will be returned. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field == HALF_OF_YEAR) { + return getValue(); + } else if (field instanceof ChronoField) { + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + return field.getFrom(this); + } + + //----------------------------------------------------------------------- + /** + * Returns the half that is the specified number of halves after this one. + *

+ * The calculation rolls around the end of the year from H2 to H1. + * The specified period may be negative. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param halves the halves to add, positive or negative + * @return the resulting half, not null + */ + public Half plus(long halves) { + int amount = (int) halves % 2; + return values()[(ordinal() + (amount + 2)) % 2]; + } + + /** + * Returns the half that is the specified number of halves before this one. + *

+ * The calculation rolls around the start of the year from H1 to H2. + * The specified period may be negative. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param halves the halves to subtract, positive or negative + * @return the resulting half, not null + */ + public Half minus(long halves) { + return plus(-(halves % 2)); + } + + //----------------------------------------------------------------------- + /** + * Gets the length of this half in days. + *

+ * This takes a flag to determine whether to return the length for a leap year or not. + *

+ * H1 has 181 in a standard year and 182 days in a leap year. + * H2 has 184 days. + * + * @param leapYear true if the length is required for a leap year + * @return the length of this month in days, 181, 182 or 184 + */ + public int length(boolean leapYear) { + return this == H1 ? (leapYear ? 182 : 181) : 184; + } + + //----------------------------------------------------------------------- + /** + * Gets the first of the six months that this half refers to. + *

+ * H1 will return January.
+ * H2 will return July. + * + * @return the first month in the half, not null + */ + public Month firstMonth() { + return this == H1 ? Month.JANUARY : Month.JULY; + } + + //----------------------------------------------------------------------- + /** + * Queries this half-of-year using the specified query. + *

+ * This queries this half-of-year using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

+ * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == TemporalQueries.chronology()) { + return (R) IsoChronology.INSTANCE; + } else if (query == TemporalQueries.precision()) { + return (R) HALF_YEARS; + } + return TemporalAccessor.super.query(query); + } + + /** + * Adjusts the specified temporal object to have this half-of-year. + *

+ * This returns a temporal object of the same observable type as the input + * with the half-of-year changed to be the same as this. + *

+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * passing {@link TemporalFields#HALF_OF_YEAR} as the field. + * If the specified temporal object does not use the ISO calendar system then + * a {@code DateTimeException} is thrown. + *

+ * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisHalf.adjustInto(temporal);
+     *   temporal = temporal.with(thisHalf);
+     * 
+ *

+ * For example, given a date in May, the following are output: + *

+     *   dateInMay.with(H1);    // no change
+     *   dateInMay.with(H2);    // six months later
+     * 
+ *

+ * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) { + throw new DateTimeException("Adjustment only supported on ISO date-time"); + } + return temporal.with(HALF_OF_YEAR, getValue()); + } + +} diff --git a/src/main/java/org/threeten/extra/HourMinute.java b/src/main/java/org/threeten/extra/HourMinute.java new file mode 100644 index 00000000..d91de31b --- /dev/null +++ b/src/main/java/org/threeten/extra/HourMinute.java @@ -0,0 +1,1090 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +import static java.time.temporal.ChronoField.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoUnit.HALF_DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MINUTES; + +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.Period; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; +import java.util.Objects; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; + +/** + * An hour-minute, such as {@code 12:31}. + *

+ * This class is similar to {@link LocalTime} but has a precision of minutes. + * Seconds and nanoseconds cannot be represented by this class. + * + *

Implementation Requirements:

+ * This class is immutable and thread-safe. + *

+ * This class must be treated as a value type. Do not synchronize, rely on the + * identity hash code or use the distinction between equals() and ==. + */ +public final class HourMinute + implements Temporal, TemporalAdjuster, Comparable, Serializable { + + /** + * The time of midnight at the start of the day, '00:00'. + */ + public static final HourMinute MIDNIGHT = new HourMinute(0, 0); + + /** + * Serialization version. + */ + private static final long serialVersionUID = -2532872925L; + /** + * Parser. + */ + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .toFormatter(); + /** + * Hours per day. + */ + private static final int HOURS_PER_DAY = 24; + /** + * Minutes per hour. + */ + private static final int MINUTES_PER_HOUR = 60; + /** + * Minutes per day. + */ + private static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY; + + /** + * The hour-of-day. + */ + private final int hour; + /** + * The minute-of-hour. + */ + private final int minute; + + //----------------------------------------------------------------------- + /** + * Obtains the current hour-minute from the system clock in the default time-zone. + *

+ * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current hour-minute. + * The zone and offset will be set based on the time-zone in the clock. + *

+ * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current hour-minute using the system clock and default time-zone, not null + */ + public static HourMinute now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current hour-minute from the system clock in the specified time-zone. + *

+ * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current hour-minute. + * Specifying the time-zone avoids dependence on the default time-zone. + *

+ * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current hour-minute using the system clock, not null + */ + public static HourMinute now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current hour-minute from the specified clock. + *

+ * This will query the specified clock to obtain the current hour-minute. + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current hour-minute, not null + */ + public static HourMinute now(Clock clock) { + final LocalTime now = LocalTime.now(clock); // called once + return HourMinute.of(now.getHour(), now.getMinute()); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code HourMinute} from a hour and minute. + * + * @param hour the hour to represent, from 0 to 23 + * @param minute the minute-of-hour to represent, from 0 to 59 + * @return the hour-minute, not null + * @throws DateTimeException if either field value is invalid + */ + public static HourMinute of(int hour, int minute) { + HOUR_OF_DAY.checkValidValue(hour); + MINUTE_OF_HOUR.checkValidValue(minute); + return new HourMinute(hour, minute); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code HourMinute} from a temporal object. + *

+ * This obtains a hour-minute based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code HourMinute}. + *

+ * The conversion extracts the {@link ChronoField#HOUR_OF_DAY HOUR_OF_DAY} and + * {@link ChronoField#MINUTE_OF_HOUR MINUTE_OF_HOUR} fields. + *

+ * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code HourMinute::from}. + * + * @param temporal the temporal object to convert, not null + * @return the hour-minute, not null + * @throws DateTimeException if unable to convert to a {@code HourMinute} + */ + public static HourMinute from(TemporalAccessor temporal) { + if (temporal instanceof HourMinute) { + return (HourMinute) temporal; + } + Objects.requireNonNull(temporal, "temporal"); + try { + // need to use getLong() as JDK Parsed class get() doesn't work properly + int hour = Math.toIntExact(temporal.getLong(HOUR_OF_DAY)); + int minute = Math.toIntExact(temporal.getLong(MINUTE_OF_HOUR)); + return of(hour, minute); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain HourMinute from TemporalAccessor: " + + temporal + " of type " + temporal.getClass().getName(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code HourMinute} from a text string such as {@code 12:31}. + *

+ * The string must represent a valid hour-minute. + * The format must be {@code HH:mm}. + * + * @param text the text to parse such as "12:31", not null + * @return the parsed hour-minute, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + @FromString + public static HourMinute parse(CharSequence text) { + return parse(text, PARSER); + } + + /** + * Obtains an instance of {@code HourMinute} from a text string using a specific formatter. + *

+ * The text is parsed using the formatter, returning a hour-minute. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed hour-minute, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static HourMinute parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, HourMinute::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param hour the hour to represent, validated from 0 to 23 + * @param minute the minute-of-hour to represent, validated from 0 to 59 + */ + private HourMinute(int hour, int minute) { + this.hour = hour; + this.minute = minute; + } + + /** + * Validates the input. + * + * @return the valid object, not null + */ + private Object readResolve() { + return of(hour, minute); + } + + /** + * Returns a copy of this hour-minute with the new hour and minute, checking + * to see if a new object is in fact required. + * + * @param newYear the hour to represent, validated from 0 to 23 + * @param newMinute the minute-of-hour to represent, validated from 0 to 59 + * @return the hour-minute, not null + */ + private HourMinute with(int newYear, int newMinute) { + if (hour == newYear && minute == newMinute) { + return this; + } + return new HourMinute(newYear, newMinute); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

+ * This checks if this hour-minute can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + *

    + *
  • {@code MINUTE_OF_HOUR} + *
  • {@code MINUTE_OF_DAY} + *
  • {@code HOUR_OF_AMPM} + *
  • {@code CLOCK_HOUR_OF_AMPM} + *
  • {@code HOUR_OF_DAY} + *
  • {@code CLOCK_HOUR_OF_DAY} + *
  • {@code AMPM_OF_DAY} + *
+ * All other {@code ChronoField} instances will return false. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this hour-minute, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return field == MINUTE_OF_HOUR || + field == MINUTE_OF_DAY || + field == HOUR_OF_AMPM || + field == CLOCK_HOUR_OF_AMPM || + field == HOUR_OF_DAY || + field == CLOCK_HOUR_OF_DAY || + field == AMPM_OF_DAY; + } + return field != null && field.isSupportedBy(this); + } + + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this hour-minute. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

    + *
  • {@code MINUTES} + *
  • {@code HOURS} + *
  • {@code HALF_DAYS} + *
+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit == MINUTES || unit == HOURS || unit == HALF_DAYS; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the range of valid values for the specified field. + *

+ * The range object expresses the minimum and maximum valid values for a field. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + * @throws UnsupportedTemporalTypeException if the field is not supported + */ + @Override + public ValueRange range(TemporalField field) { + return Temporal.super.range(field); + } + + /** + * Gets the value of the specified field from this hour-minute as an {@code int}. + *

+ * This queries this hour-minute for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this hour-minute,. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained or + * the value is outside the range of valid values for the field + * @throws UnsupportedTemporalTypeException if the field is not supported or + * the range of values exceeds an {@code int} + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public int get(TemporalField field) { + if (field instanceof ChronoField) { + return get0(field); + } + return Temporal.super.get(field); + } + + /** + * Gets the value of the specified field from this hour-minute as a {@code long}. + *

+ * This queries this hour-minute for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this hour-minute. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + return get0(field); + } + return field.getFrom(this); + } + + private int get0(TemporalField field) { + switch ((ChronoField) field) { + case MINUTE_OF_HOUR: + return minute; + case MINUTE_OF_DAY: + return hour * 60 + minute; + case HOUR_OF_AMPM: + return hour % 12; + case CLOCK_HOUR_OF_AMPM: + int ham = hour % 12; + return (ham % 12 == 0 ? 12 : ham); + case HOUR_OF_DAY: + return hour; + case CLOCK_HOUR_OF_DAY: + return (hour == 0 ? 24 : hour); + case AMPM_OF_DAY: + return hour / 12; + default: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the hour field, from 0 to 23. + *

+ * This method returns the hour as an {@code int} from 0 to 23. + * + * @return the hour, from 0 to 23 + */ + public int getHour() { + return hour; + } + + /** + * Gets the minute-of-hour field from 0 to 59. + *

+ * This method returns the minute as an {@code int} from 0 to 59. + * + * @return the minute-of-hour, from 0 to 59 + */ + public int getMinute() { + return minute; + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this hour-minute. + *

+ * This returns a {@code HourMinute} based on this one, with the hour-minute adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

+ * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return a {@code HourMinute} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public HourMinute with(TemporalAdjuster adjuster) { + return (HourMinute) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this hour-minute with the specified field set to a new value. + *

+ * This returns a {@code HourMinute} based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the hour or minute. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the adjustment is implemented here. + * The supported fields behave as follows: + *

    + *
  • {@code MINUTE_OF_HOUR} - + * Returns a {@code HourMinute} with the specified minute-of-hour. + * The hour will be unchanged. + *
  • {@code MINUTE_OF_DAY} - + * Returns a {@code HourMinute} with the specified minute-of-day. + *
  • {@code HOUR_OF_AMPM} - + * Returns a {@code HourMinute} with the specified hour-of-am-pm. + * The AM/PM and minute-of-hour will be unchanged. + *
  • {@code CLOCK_HOUR_OF_AMPM} - + * Returns a {@code HourMinute} with the specified clock-hour-of-am-pm. + * The AM/PM and minute-of-hour will be unchanged. + *
  • {@code HOUR_OF_DAY} - + * Returns a {@code HourMinute} with the specified hour-of-day. + * The minute-of-hour will be unchanged. + *
  • {@code CLOCK_HOUR_OF_DAY} - + * Returns a {@code HourMinute} with the specified clock-hour-of-day. + * The minute-of-hour will be unchanged. + *
  • {@code AMPM_OF_DAY} - + * Returns a {@code HourMinute} with the specified AM/PM. + * The hour-of-am-pm and minute-of-hour will be unchanged. + *
+ *

+ * In all cases, if the new value is outside the valid range of values for the field + * then a {@code DateTimeException} will be thrown. + *

+ * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return a {@code HourMinute} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public HourMinute with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + f.checkValidValue(newValue); + switch (f) { + case MINUTE_OF_HOUR: + return withMinute((int) newValue); + case MINUTE_OF_DAY: + return plusMinutes(newValue - (hour * MINUTES_PER_HOUR + minute)); + case HOUR_OF_AMPM: + return plusHours(newValue - (hour % 12)); + case CLOCK_HOUR_OF_AMPM: + return plusHours((newValue == 12 ? 0 : newValue) - (hour % 12)); + case HOUR_OF_DAY: + return withHour((int) newValue); + case CLOCK_HOUR_OF_DAY: + return withHour((int) (newValue == 24 ? 0 : newValue)); + case AMPM_OF_DAY: + return plusHours((newValue - (hour / 12)) * 12); + default: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + } + return field.adjustInto(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code HourMinute} with the hour altered. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param hour the hour to set in the returned hour-minute, from 0 to 23 + * @return a {@code HourMinute} based on this hour-minute with the requested hour, not null + * @throws DateTimeException if the hour value is invalid + */ + public HourMinute withHour(int hour) { + HOUR_OF_DAY.checkValidValue(hour); + return with(hour, minute); + } + + /** + * Returns a copy of this {@code HourMinute} with the minute-of-hour altered. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param minute the minute-of-hour to set in the returned hour-minute, from 0 to 59 + * @return a {@code HourMinute} based on this hour-minute with the requested minute, not null + * @throws DateTimeException if the minute-of-hour value is invalid + */ + public HourMinute withMinute(int minute) { + MINUTE_OF_HOUR.checkValidValue(minute); + return with(hour, minute); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this hour-minute with the specified amount added. + *

+ * This returns a {@code HourMinute} based on this one, with the specified amount added. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

+ * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return a {@code HourMinute} based on this hour-minute with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public HourMinute plus(TemporalAmount amountToAdd) { + return (HourMinute) amountToAdd.addTo(this); + } + + /** + * Returns a copy of this hour-minute with the specified amount added. + *

+ * This returns a {@code HourMinute} based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoUnit} then the addition is implemented here. + * The supported fields behave as follows: + *

    + *
  • {@code MINUTES} - + * Returns a {@code LocalTime} with the specified number of minutes added. + * This is equivalent to {@link #plusMinutes(long)}. + *
  • {@code HOURS} - + * Returns a {@code LocalTime} with the specified number of hours added. + * This is equivalent to {@link #plusHours(long)}. + *
  • {@code HALF_DAYS} - + * Returns a {@code LocalTime} with the specified number of half-days added. + * This is equivalent to {@link #plusHours(long)} with the amount + * multiplied by 12. + *
+ *

+ * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the amount to add, not null + * @return a {@code HourMinute} based on this hour-minute with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public HourMinute plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + switch ((ChronoUnit) unit) { + case MINUTES: + return plusMinutes(amountToAdd); + case HOURS: + return plusHours(amountToAdd); + case HALF_DAYS: + return plusHours((amountToAdd % 2) * 12); + default: + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + } + return unit.addTo(this, amountToAdd); + } + + /** + * Returns a copy of this {@code HourMinute} with the specified number of hours added. + *

+ * This adds the specified number of hours to this time, returning a new time. + * The calculation wraps around midnight. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param hoursToAdd the hours to add, may be negative + * @return an {@code HourMinute} based on this time with the hours added, not null + */ + public HourMinute plusHours(long hoursToAdd) { + if (hoursToAdd == 0) { + return this; + } + int newHour = ((int) (hoursToAdd % HOURS_PER_DAY) + hour + HOURS_PER_DAY) % HOURS_PER_DAY; + return with(newHour, minute); + } + + /** + * Returns a copy of this {@code HourMinute} with the specified number of minutes added. + *

+ * This adds the specified number of minutes to this time, returning a new time. + * The calculation wraps around midnight. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param minutesToAdd the minutes to add, may be negative + * @return an {@code HourMinute} based on this time with the minutes added, not null + */ + public HourMinute plusMinutes(long minutesToAdd) { + if (minutesToAdd == 0) { + return this; + } + int mofd = hour * MINUTES_PER_HOUR + minute; + int newMofd = ((int) (minutesToAdd % MINUTES_PER_DAY) + mofd + MINUTES_PER_DAY) % MINUTES_PER_DAY; + if (mofd == newMofd) { + return this; + } + int newHour = newMofd / MINUTES_PER_HOUR; + int newMinute = newMofd % MINUTES_PER_HOUR; + return with(newHour, newMinute); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this hour-minute with the specified amount subtracted. + *

+ * This returns a {@code HourMinute} based on this one, with the specified amount subtracted. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

+ * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount to subtract, not null + * @return a {@code HourMinute} based on this hour-minute with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public HourMinute minus(TemporalAmount amountToSubtract) { + return (HourMinute) amountToSubtract.subtractFrom(this); + } + + /** + * Returns a copy of this hour-minute with the specified amount subtracted. + *

+ * This returns a {@code HourMinute} based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + *

+ * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the amount to subtract, not null + * @return a {@code HourMinute} based on this hour-minute with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public HourMinute minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + /** + * Returns a copy of this hour-minute with the specified period in hours subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param hoursToSubtract the hours to subtract, may be negative + * @return a {@code HourMinute} based on this hour-minute with the hours subtracted, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public HourMinute minusHours(long hoursToSubtract) { + return (hoursToSubtract == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hoursToSubtract)); + } + + /** + * Returns a copy of this hour-minute with the specified period in minutes subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param minutesToSubtract the minutes to subtract, may be negative + * @return a {@code HourMinute} based on this hour-minute with the minutes subtracted, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public HourMinute minusMinutes(long minutesToSubtract) { + return (minutesToSubtract == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutesToSubtract)); + } + + //----------------------------------------------------------------------- + /** + * Queries this hour-minute using the specified query. + *

+ * This queries this hour-minute using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

+ * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == TemporalQueries.localTime()) { + return (R) toLocalTime(); + } else if (query == TemporalQueries.precision()) { + return (R) MINUTES; + } + return Temporal.super.query(query); + } + + /** + * Adjusts the specified temporal object to have this hour-minute. + * Note that if the target has a second or nanosecond field, that is not altered by this method. + *

+ * This returns a temporal object of the same observable type as the input + * with the hour and minute changed to be the same as this. + *

+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * passing {@link ChronoField#MINUTE_OF_DAY} as the field. + * Note that this does not affect any second/nanosecond field in the target. + *

+ * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisHourMinute.adjustInto(temporal);
+     *   temporal = temporal.with(thisHourMinute);
+     * 
+ *

+ * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + return temporal.with(MINUTE_OF_DAY, hour * MINUTES_PER_HOUR + minute); + } + + /** + * Calculates the amount of time until another hour-minute in terms of the specified unit. + *

+ * This calculates the amount of time between two {@code HourMinute} + * objects in terms of a single {@code TemporalUnit}. + * The start and end points are {@code this} and the specified hour-minute. + * The result will be negative if the end is before the start. + * The {@code Temporal} passed to this method is converted to a + * {@code HourMinute} using {@link #from(TemporalAccessor)}. + * For example, the period in hours between two hour-minutes can be calculated + * using {@code startHourMinute.until(endHourMinute, YEARS)}. + *

+ * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported. + * Other {@code ChronoUnit} values will throw an exception. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param endExclusive the end date, exclusive, which is converted to a {@code HourMinute}, not null + * @param unit the unit to measure the amount in, not null + * @return the amount of time between this hour-minute and the end hour-minute + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code HourMinute} + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long until(Temporal endExclusive, TemporalUnit unit) { + HourMinute end = HourMinute.from(endExclusive); + long minutesUntil = (end.hour * MINUTES_PER_HOUR + end.minute) - (hour * MINUTES_PER_HOUR + minute); // no overflow + if (unit instanceof ChronoUnit) { + switch ((ChronoUnit) unit) { + case MINUTES: + return minutesUntil; + case HOURS: + return minutesUntil / MINUTES_PER_HOUR; + case HALF_DAYS: + return minutesUntil / (12 * MINUTES_PER_HOUR); + default: + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + } + return unit.between(this, end); + } + + /** + * Formats this hour-minute using the specified formatter. + *

+ * This hour-minute will be passed to the formatter to produce a string. + * + * @param formatter the formatter to use, not null + * @return the formatted hour-minute string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String format(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.format(this); + } + + //----------------------------------------------------------------------- + /** + * Combines this time with a date to create a {@code LocalDateTime}. + *

+ * This returns a {@code LocalDateTime} formed from this time at the specified date. + * All possible combinations of date and time are valid. + * + * @param date the date to combine with, not null + * @return the local date-time formed from this time and the specified date, not null + */ + public LocalDateTime atDate(LocalDate date) { + return LocalDateTime.of(date, toLocalTime()); + } + + /** + * Combines this time with an offset to create an {@code OffsetTime}. + *

+ * This returns an {@code OffsetTime} formed from this time at the specified offset. + * All possible combinations of time and offset are valid. + * + * @param offset the offset to combine with, not null + * @return the offset time formed from this time and the specified offset, not null + */ + public OffsetTime atOffset(ZoneOffset offset) { + return OffsetTime.of(toLocalTime(), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns the equivalent {@code LocalTime}. + *

+ * This returns a {@code LocalTime} formed from this hour and minute. + * + * @return the equivalent local time, not null + */ + public LocalTime toLocalTime() { + return LocalTime.of(hour, minute); + } + + //------------------------------------------------------------------------- + /** + * Compares this hour-minute to another + *

+ * The comparison is based first on the value of the hour, then on the value of the minute. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other hour-minute to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(HourMinute other) { + int cmp = (hour - other.hour); + if (cmp == 0) { + cmp = (minute - other.minute); + } + return cmp; + } + + /** + * Is this hour-minute after the specified hour-minute. + * + * @param other the other hour-minute to compare to, not null + * @return true if this is after the specified hour-minute + */ + public boolean isAfter(HourMinute other) { + return compareTo(other) > 0; + } + + /** + * Is this hour-minute before the specified hour-minute. + * + * @param other the other hour-minute to compare to, not null + * @return true if this point is before the specified hour-minute + */ + public boolean isBefore(HourMinute other) { + return compareTo(other) < 0; + } + + //----------------------------------------------------------------------- + /** + * Checks if this hour-minute is equal to another hour-minute. + *

+ * The comparison is based on the time-line position of the hour-minute. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other hour-minute + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HourMinute) { + HourMinute other = (HourMinute) obj; + return hour == other.hour && minute == other.minute; + } + return false; + } + + /** + * A hash code for this hour-minute. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return hour * MINUTES_PER_HOUR + minute; + } + + //----------------------------------------------------------------------- + /** + * Outputs this hour-minute as a {@code String}, such as {@code 12:31}. + * + * @return a string representation of this hour-minute, not null + */ + @Override + @ToString + public String toString() { + return new StringBuilder(5) + .append(hour < 10 ? "0" : "").append(hour) + .append(minute < 10 ? ":0" : ":").append(minute) + .toString(); + } + +} diff --git a/src/main/java/org/threeten/extra/Hours.java b/src/main/java/org/threeten/extra/Hours.java index 5d829167..75e1420a 100644 --- a/src/main/java/org/threeten/extra/Hours.java +++ b/src/main/java/org/threeten/extra/Hours.java @@ -48,6 +48,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * A hour-based amount of time, such as '4 hours'. *

@@ -75,12 +78,19 @@ public final class Hours */ private static final long serialVersionUID = -8494096666041369608L; + /** + * The number of hours per day. + */ + private static final int HOURS_PER_DAY = 24; + /** * The pattern for parsing. */ private static final Pattern PATTERN = - Pattern.compile("([-+]?)PT" - + "(?:([-+]?[0-9]+)H)?", Pattern.CASE_INSENSITIVE); + Pattern.compile("([-+]?)P" + + "(?:([-+]?[0-9]+)D)?" + + "(?:T" + + "(?:([-+]?[0-9]+)H)?)?", Pattern.CASE_INSENSITIVE); /** * The number of hours. @@ -145,19 +155,25 @@ public static Hours from(TemporalAmount amount) { /** * Obtains a {@code Hours} from a text string such as {@code PTnH}. *

- * This will parse the string produced by {@code toString()} which is - * based on the ISO-8601 period format {@code PTnH}. + * This will parse the string produced by {@code toString()} and other + * related formats based on ISO-8601 {@code PnDTnH}. *

* The string starts with an optional sign, denoted by the ASCII negative * or positive symbol. If negative, the whole amount is negated. - * The ASCII letters "P" and "T" are next in upper or lower case. - * The section has the suffix "H" in ASCII in either upper or lower case. - * The number part must consist of ASCII digits. The number may be prefixed - * by the ASCII negative or positive symbol. The number must parse to an - * {@code int}. - *

- * The leading plus/minus sign, and negative value for hours is not part of - * the ISO-8601 standard. + * The ASCII letter "P" is next in upper or lower case. + * There are two sections consisting of a number and a suffix. + * There is one section for days suffixed by "D", + * followed by one section for hours suffixed by "H". + * At least one section must be present. + * If the hours section is present it must be prefixed by "T". + * If the hours section is omitted the "T" must be omitted. + * Letters must be in ASCII upper or lower case. + * The number part of each section must consist of ASCII digits. + * The number may be prefixed by the ASCII negative or positive symbol. + * The number must parse to an {@code int}. + *

+ * The leading plus/minus sign, and negative values for days and hours + * are not part of the ISO-8601 standard. *

* For example, the following are valid inputs: *

@@ -165,43 +181,58 @@ public static Hours from(TemporalAmount amount) {
      *   "PT-HM"           -- Hours.of(-2)
      *   "-PT2H"           -- Hours.of(-2)
      *   "-PT-2H"          -- Hours.of(2)
+     *   "P3D"             -- Hours.of(3 * 24)
+     *   "P3DT2H"          -- Hours.of(3 * 24 + 2)
      * 
* * @param text the text to parse, not null * @return the parsed period, not null * @throws DateTimeParseException if the text cannot be parsed to a period */ + @FromString public static Hours parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { - int negate = ("-".equals(matcher.group(1)) ? -1 : 1); - String hoursStr = matcher.group(2); - if (hoursStr != null) { - try { - int hours = Integer.parseInt(hoursStr); - return of(negate * hours); - } catch (NumberFormatException ex) { - throw new DateTimeParseException("Text cannot be parsed to Hours, non-numeric hours", text, 0, ex); + int negate = "-".equals(matcher.group(1)) ? -1 : 1; + String daysStr = matcher.group(2); + String hoursStr = matcher.group(3); + if (daysStr != null || hoursStr != null) { + int hours = 0; + if (hoursStr != null) { + try { + hours = Integer.parseInt(hoursStr); + } catch (NumberFormatException ex) { + throw new DateTimeParseException("Text cannot be parsed to Hours, non-numeric hours", text, 0, ex); + } + } + if (daysStr != null) { + try { + int daysAsHours = Math.multiplyExact(Integer.parseInt(daysStr), HOURS_PER_DAY); + hours = Math.addExact(hours, daysAsHours); + } catch (NumberFormatException ex) { + throw new DateTimeParseException("Text cannot be parsed to Hours, non-numeric days", text, 0, ex); + } } + return of(Math.multiplyExact(hours, negate)); } } - throw new DateTimeParseException("Text cannot be parsed to a Hours", text, 0); + throw new DateTimeParseException("Text cannot be parsed to Hours", text, 0); } //----------------------------------------------------------------------- /** - * Obtains a {@code Hours} consisting of the number of hours between two dates. + * Obtains a {@code Hours} consisting of the number of hours between two temporals. *

- * The start date is included, but the end date is not. + * The start temporal is included, but the end temporal is not. * The result of this method can be negative if the end is before the start. * - * @param startDateInclusive the start date, inclusive, not null - * @param endDateExclusive the end date, exclusive, not null - * @return the number of hours between this date and the end date, not null + * @param startInclusive the start temporal, inclusive, not null + * @param endExclusive the end temporal, exclusive, not null + * @return the number of hours between the start and end temporals, not null */ - public static Hours between(Temporal startDateInclusive, Temporal endDateExclusive) { - return of(Math.toIntExact(HOURS.between(startDateInclusive, endDateExclusive))); + public static Hours between(Temporal startInclusive, Temporal endExclusive) { + return of(Math.toIntExact(HOURS.between(startInclusive, endExclusive))); } //----------------------------------------------------------------------- @@ -254,7 +285,7 @@ public long get(TemporalUnit unit) { */ @Override public List getUnits() { - return Collections.singletonList(ChronoUnit.HOURS); + return Collections.singletonList(HOURS); } //----------------------------------------------------------------------- @@ -267,6 +298,33 @@ public int getAmount() { return hours; } + /** + * Checks if the amount is negative. + * + * @return true if the amount is negative, false if the amount is zero or positive + */ + public boolean isNegative() { + return getAmount() < 0; + } + + /** + * Checks if the amount is zero. + * + * @return true if the amount is zero, false if not + */ + public boolean isZero() { + return getAmount() == 0; + } + + /** + * Checks if the amount is positive. + * + * @return true if the amount is positive, false if the amount is zero or negative + */ + public boolean isPositive() { + return getAmount() > 0; + } + //----------------------------------------------------------------------- /** * Returns a copy of this amount with the specified amount added. @@ -308,13 +366,13 @@ public Hours plus(int hours) { *

* This instance is immutable and unaffected by this method call. * - * @param amountToAdd the amount to add, not null + * @param amountToSubtract the amount to subtract, not null * @return a {@code Hours} based on this instance with the requested amount subtracted, not null * @throws DateTimeException if the specified amount contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ - public Hours minus(TemporalAmount amountToAdd) { - return minus(Hours.from(amountToAdd).getAmount()); + public Hours minus(TemporalAmount amountToSubtract) { + return minus(Hours.from(amountToSubtract).getAmount()); } /** @@ -400,14 +458,28 @@ public Hours abs() { /** * Gets the number of hours as a {@code Duration}. *

- * This returns a duration with the same number of months. + * This returns a duration with the same number of hours. * * @return the equivalent duration, not null + * @deprecated Use {@link #toDuration()} */ + @Deprecated public Duration toPeriod() { return Duration.ofHours(hours); } + //------------------------------------------------------------------------- + /** + * Gets the number of hours as a {@code Duration}. + *

+ * This returns a duration with the same number of hours. + * + * @return the equivalent duration, not null + */ + public Duration toDuration() { + return Duration.ofHours(hours); + } + //----------------------------------------------------------------------- /** * Adds this amount to the specified temporal object. @@ -529,6 +601,7 @@ public int hashCode() { * @return the number of hours in ISO-8601 string format */ @Override + @ToString public String toString() { return "PT" + hours + "H"; } diff --git a/src/main/java/org/threeten/extra/Interval.java b/src/main/java/org/threeten/extra/Interval.java index f4b900fb..3b50b7c4 100644 --- a/src/main/java/org/threeten/extra/Interval.java +++ b/src/main/java/org/threeten/extra/Interval.java @@ -35,10 +35,17 @@ import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; +import java.time.LocalDateTime; import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAccessor; import java.util.Objects; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * An immutable interval of time between two instants. *

@@ -86,8 +93,8 @@ public final class Interval *

* The end instant must not be before the start instant. * - * @param startInclusive the start instant, inclusive, MIN_DATE treated as unbounded, not null - * @param endExclusive the end instant, exclusive, MAX_DATE treated as unbounded, not null + * @param startInclusive the start instant, inclusive, {@link Instant#MIN} treated as unbounded, not null + * @param endExclusive the end instant, exclusive, {@link Instant#MAX} treated as unbounded, not null * @return the half-open interval, not null * @throws DateTimeException if the end is before the start */ @@ -95,7 +102,7 @@ public static Interval of(Instant startInclusive, Instant endExclusive) { Objects.requireNonNull(startInclusive, "startInclusive"); Objects.requireNonNull(endExclusive, "endExclusive"); if (endExclusive.isBefore(startInclusive)) { - throw new DateTimeException("End instant must on or after start instant"); + throw new DateTimeException("End instant must be equal or after start instant"); } return new Interval(startInclusive, endExclusive); } @@ -117,59 +124,161 @@ public static Interval of(Instant startInclusive, Duration duration) { Objects.requireNonNull(startInclusive, "startInclusive"); Objects.requireNonNull(duration, "duration"); if (duration.isNegative()) { - throw new DateTimeException("Duration must not be zero or negative"); + throw new DateTimeException("Duration must not be negative"); } return new Interval(startInclusive, startInclusive.plus(duration)); } + /** + * Obtains an instance of {@code Interval} from the duration and the end. + *

+ * The start instant is calculated as the end minus the duration. + * The duration must not be negative. + * + * @param duration the duration from the start to the end, not null + * @param endExclusive the end instant, exclusive, not null + * @return the interval, not null + * @throws DateTimeException if the end is before the start, + * or if the duration addition cannot be made + * @throws ArithmeticException if numeric overflow occurs when subtracting the duration + */ + public static Interval of(Duration duration, Instant endExclusive) { + Objects.requireNonNull(duration, "duration"); + Objects.requireNonNull(endExclusive, "endExclusive"); + if (duration.isNegative()) { + throw new DateTimeException("Duration must not be negative"); + } + return new Interval(endExclusive.minus(duration), endExclusive); + } + + /** + * Obtains an instance of {@code Interval} with the specified start instant and unbounded end. + * + * @param startInclusive the start instant, inclusive, not null + * @return a new {@code Instant} with the specified start instant. + */ + public static Interval startingAt(Instant startInclusive) { + Objects.requireNonNull(startInclusive, "startInclusive"); + return Interval.ALL.withStart(startInclusive); + } + + /** + * Obtains an instance of {@code Interval} with unbounded start and the specified end instant. + * + * @param endExclusive the end instant, exclusive, not null + * @return a new {@code Instant} with the specified end instant. + */ + public static Interval endingAt(Instant endExclusive) { + Objects.requireNonNull(endExclusive, "endExclusive"); + return Interval.ALL.withEnd(endExclusive); + } + //----------------------------------------------------------------------- /** * Obtains an instance of {@code Interval} from a text string such as * {@code 2007-12-03T10:15:30Z/2007-12-04T10:15:30Z}, where the end instant is exclusive. *

- * The string must consist of one of the following three formats: + * The string must consist of one of the following four formats: *

    *
  • a representations of an {@link OffsetDateTime}, followed by a forward slash, * followed by a representation of a {@link OffsetDateTime} + *
  • a representations of an {@link OffsetDateTime}, followed by a forward slash, + * followed by a representation of a {@link LocalDateTime}, where the end offset is implied. *
  • a representation of an {@link OffsetDateTime}, followed by a forward slash, - * followed by a representation of a {@link Duration} - *
  • a representation of a {@link Duration}, followed by a forward slash, + * followed by a representation of a {@link PeriodDuration} + *
  • a representation of a {@link PeriodDuration}, followed by a forward slash, * followed by a representation of an {@link OffsetDateTime} *
- * + *

+ * ISO-8601 supports a very wide range of possible inputs, many of which are not supported here. + * For example, basic format, week-based dates, ordinal dates and date-style period formats are not supported. * * @param text the text to parse, not null * @return the parsed interval, not null * @throws DateTimeParseException if the text cannot be parsed */ + @FromString public static Interval parse(CharSequence text) { Objects.requireNonNull(text, "text"); for (int i = 0; i < text.length(); i++) { if (text.charAt(i) == '/') { - char firstChar = text.charAt(0); - if (firstChar == 'P' || firstChar == 'p') { - // duration followed by instant - Duration duration = Duration.parse(text.subSequence(0, i)); - Instant end = OffsetDateTime.parse(text.subSequence(i + 1, text.length())).toInstant(); - return Interval.of(end.minus(duration), end); - } else { - // instant followed by instant or duration - Instant start = OffsetDateTime.parse(text.subSequence(0, i)).toInstant(); - if (i + 1 < text.length()) { - char c = text.charAt(i + 1); - if (c == 'P' || c == 'p') { - Duration duration = Duration.parse(text.subSequence(i + 1, text.length())); - return Interval.of(start, start.plus(duration)); - } - } - Instant end = OffsetDateTime.parse(text.subSequence(i + 1, text.length())).toInstant(); - return Interval.of(start, end); - } + return parseSplit(text.subSequence(0, i), text.subSequence(i + 1, text.length())); } } throw new DateTimeParseException("Interval cannot be parsed, no forward slash found", text, 0); } + private static Interval parseSplit(CharSequence startStr, CharSequence endStr) { + char firstChar = startStr.charAt(0); + if (firstChar == 'P' || firstChar == 'p') { + // duration followed by instant + PeriodDuration amount = PeriodDuration.parse(startStr); + try { + OffsetDateTime end = OffsetDateTime.parse(endStr); + return Interval.of(end.minus(amount).toInstant(), end.toInstant()); + } catch (DateTimeParseException ex) { + // handle case where Instant is outside the bounds of OffsetDateTime + Instant end = Instant.parse(endStr); + // addition of PeriodDuration only supported by OffsetDateTime, + // but to make that work need to move point being subtracted from closer to EPOCH + long move = end.isBefore(Instant.EPOCH) ? 1000 * 86400 : -1000 * 86400; + Instant start = end.plusSeconds(move).atOffset(ZoneOffset.UTC).minus(amount).toInstant().minusSeconds(move); + return Interval.of(start, end); + } + } + // instant followed by instant or duration + OffsetDateTime start; + try { + start = OffsetDateTime.parse(startStr); + } catch (DateTimeParseException ex) { + return parseStartExtended(startStr, endStr); + } + if (endStr.length() > 0) { + char c = endStr.charAt(0); + if (c == 'P' || c == 'p') { + PeriodDuration amount = PeriodDuration.parse(endStr); + return Interval.of(start.toInstant(), start.plus(amount).toInstant()); + } + } + return parseEndDateTime(start.toInstant(), start.getOffset(), endStr); + } + + // handle case where Instant is outside the bounds of OffsetDateTime + private static Interval parseStartExtended(CharSequence startStr, CharSequence endStr) { + Instant start = Instant.parse(startStr); + if (endStr.length() > 0) { + char c = endStr.charAt(0); + if (c == 'P' || c == 'p') { + PeriodDuration amount = PeriodDuration.parse(endStr); + // addition of PeriodDuration only supported by OffsetDateTime, + // but to make that work need to move point being added to closer to EPOCH + long move = start.isBefore(Instant.EPOCH) ? 1000 * 86400 : -1000 * 86400; + Instant end = start.plusSeconds(move).atOffset(ZoneOffset.UTC).plus(amount).toInstant().minusSeconds(move); + return Interval.of(start, end); + } + } + // infer offset from start if not specified by end + return parseEndDateTime(start, ZoneOffset.UTC, endStr); + } + + // parse when there are two date-times + private static Interval parseEndDateTime(Instant start, ZoneOffset offset, CharSequence endStr) { + try { + TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest(endStr, OffsetDateTime::from, LocalDateTime::from); + if (temporal instanceof OffsetDateTime) { + OffsetDateTime odt = (OffsetDateTime) temporal; + return Interval.of(start, odt.toInstant()); + } else { + // infer offset from start if not specified by end + LocalDateTime ldt = (LocalDateTime) temporal; + return Interval.of(start, ldt.toInstant(offset)); + } + } catch (DateTimeParseException ex) { + Instant end = Instant.parse(endStr); + return Interval.of(start, end); + } + } + //----------------------------------------------------------------------- /** * Constructor. @@ -195,7 +304,7 @@ public Instant getStart() { return start; } - /** + /** * Gets the end of this time interval, exclusive. *

* This will return {@link Instant#MAX} if the range is unbounded at the end. @@ -212,7 +321,7 @@ public Instant getEnd() { * Checks if the range is empty. *

* An empty range occurs when the start date equals the inclusive end date. - * + * * @return true if the range is empty */ public boolean isEmpty() { @@ -221,7 +330,7 @@ public boolean isEmpty() { /** * Checks if the start of the interval is unbounded. - * + * * @return true if start is unbounded */ public boolean isUnboundedStart() { @@ -230,7 +339,7 @@ public boolean isUnboundedStart() { /** * Checks if the end of the interval is unbounded. - * + * * @return true if end is unbounded */ public boolean isUnboundedEnd() { @@ -261,22 +370,6 @@ public Interval withEnd(Instant end) { } //----------------------------------------------------------------------- - /** - * Checks if this interval contains the specified instant. - *

- * This checks if the specified instant is within the bounds of this interval. - * If this range has an unbounded start then {@code contains(Instant#MIN)} returns true. - * If this range has an unbounded end then {@code contains(Instant#MAX)} returns true. - * If this range is empty then this method always returns false. - * - * @param instant the instant, not null - * @return true if this interval contains the instant - */ - public boolean contains(Instant instant) { - Objects.requireNonNull(instant, "instant"); - return start.compareTo(instant) <= 0 && (instant.compareTo(end) < 0 || isUnboundedEnd()); - } - /** * Checks if this interval encloses the specified interval. *

@@ -324,7 +417,7 @@ public boolean isConnected(Interval other) { /** * Checks if this interval overlaps the specified interval. *

- * The result is true if the the two intervals share some part of the time-line. + * The result is true if the two intervals share some part of the time-line. * An empty interval overlaps itself. *

* This is equivalent to {@code (isConnected(other) && !abuts(other))}. @@ -343,7 +436,7 @@ public boolean overlaps(Interval other) { *

* This finds the intersection of two intervals. * This throws an exception if the two intervals are not {@linkplain #isConnected(Interval) connected}. - * + * * @param other the other interval to check for, not null * @return the interval that is the intersection of the two intervals * @throws DateTimeException if the intervals do not connect @@ -371,7 +464,7 @@ public Interval intersection(Interval other) { *

* This finds the union of two intervals. * This throws an exception if the two intervals are not {@linkplain #isConnected(Interval) connected}. - * + * * @param other the other interval to check for, not null * @return the interval that is the union of the two intervals * @throws DateTimeException if the intervals do not connect @@ -399,7 +492,7 @@ public Interval union(Interval other) { *

* The result of this method will {@linkplain #encloses(Interval) enclose} * this interval and the specified interval. - * + * * @param other the other interval to check for, not null * @return the interval that spans the two intervals */ @@ -414,62 +507,197 @@ public Interval span(Interval other) { //------------------------------------------------------------------------- /** - * Checks if this interval is after the specified instant. + * Checks if this interval is after the specified interval. *

- * The result is true if the this instant starts after the specified instant. + * The result is true if this interval starts after the end of the specified interval. + * Since intervals do not include their end points, this will return true if the + * two intervals abut. * An empty interval behaves as though it is an instant for comparison purposes. * - * @param instant the other instant to compare to, not null - * @return true if the start of this interval is after the specified instant + * @param interval the other interval to compare to, not null + * @return true if this interval is after the specified interval */ - public boolean isAfter(Instant instant) { - return start.compareTo(instant) > 0; + public boolean isAfter(Interval interval) { + return start.compareTo(interval.end) >= 0 && !interval.equals(this); } /** - * Checks if this interval is before the specified instant. + * Checks if this interval is before the specified interval. *

- * The result is true if the this instant ends before the specified instant. + * The result is true if this interval ends before the start of the specified interval. * Since intervals do not include their end points, this will return true if the - * instant equals the end of the interval. + * two intervals abut. * An empty interval behaves as though it is an instant for comparison purposes. * - * @param instant the other instant to compare to, not null - * @return true if the start of this interval is before the specified instant + * @param interval the other interval to compare to, not null + * @return true if this interval is before the specified interval */ - public boolean isBefore(Instant instant) { - return end.compareTo(instant) <= 0 && start.compareTo(instant) < 0; + public boolean isBefore(Interval interval) { + return end.compareTo(interval.start) <= 0 && !interval.equals(this); } //------------------------------------------------------------------------- /** - * Checks if this interval is after the specified interval. + * Checks if this interval starts on or before the specified instant. *

- * The result is true if the this instant starts after the end of the specified interval. - * Since intervals do not include their end points, this will return true if the - * instant equals the end of the interval. + * This method compares the start of the interval to the instant. + * An interval with an unbounded start is considered to start at {@code Instant.MIN}. + * + * @param instant the instant, not null + * @return true if this interval starts before the instant + */ + public boolean startsBefore(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return start.compareTo(instant) < 0; + } + + /** + * Checks if this interval starts at or before the specified instant. + *

+ * This method compares the start of the interval to the instant. + * An interval with an unbounded start is considered to start at {@code Instant.MIN}. + * + * @param instant the instant, not null + * @return true if this interval starts at or before the instant + */ + public boolean startsAtOrBefore(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return start.compareTo(instant) <= 0; + } + + /** + * Checks if this interval starts on or after the specified instant. + *

+ * This method compares the start of the interval to the instant. + * An interval with an unbounded start is considered to start at {@code Instant.MIN}. + * + * @param instant the instant, not null + * @return true if this interval starts after the instant + */ + public boolean startsAfter(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return start.compareTo(instant) > 0; + } + + /** + * Checks if this interval starts at or after the specified instant. + *

+ * This method compares the start of the interval to the instant. + * An interval with an unbounded start is considered to start at {@code Instant.MIN}. + * + * @param instant the instant, not null + * @return true if this interval starts at or after the instant + */ + public boolean startsAtOrAfter(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return start.compareTo(instant) >= 0; + } + + //------------------------------------------------------------------------- + /** + * Checks if this interval ends before the specified instant. + *

+ * This method compares the end of the interval to the instant. + * An interval with an unbounded end is considered to end after {@code Instant.MAX}. + * + * @param instant the instant, not null + * @return true if this interval ends before the instant + */ + public boolean endsBefore(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return end.compareTo(instant) < 0 && !isUnboundedEnd(); + } + + /** + * Checks if this interval ends at or before the specified instant. + *

+ * This method compares the end of the interval to the instant. + * An interval with an unbounded end is considered to end after {@code Instant.MAX}. + * + * @param instant the instant, not null + * @return true if this interval ends at or before the instant + */ + public boolean endsAtOrBefore(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return end.compareTo(instant) <= 0 && !isUnboundedEnd(); + } + + /** + * Checks if this interval ends after the specified instant. + *

+ * This method compares the end of the interval to the instant. + * An interval with an unbounded end is considered to end after {@code Instant.MAX}. + * + * @param instant the instant, not null + * @return true if this interval ends after the instant + */ + public boolean endsAfter(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return end.compareTo(instant) > 0 || isUnboundedEnd(); + } + + /** + * Checks if this interval ends after the specified instant. + *

+ * This method compares the end of the interval to the instant. + * An interval with an unbounded end is considered to end after {@code Instant.MAX}. + * + * @param instant the instant, not null + * @return true if this interval ends at or after the instant + */ + public boolean endsAtOrAfter(Instant instant) { + Objects.requireNonNull(instant, "instant"); + return end.compareTo(instant) >= 0 || isUnboundedEnd(); + } + + //------------------------------------------------------------------------- + /** + * Checks if this interval contains the specified instant. + *

+ * This checks if the specified instant is within the bounds of this interval. + * If this interval has an unbounded start then {@code contains(Instant#MIN)} returns true. + * If this interval has an unbounded end then {@code contains(Instant#MAX)} returns true. + * Otherwise, if this interval is empty then this method returns false. + *

+ * This is equivalent to {@link #startsAtOrBefore(Instant)} {@code &&} {@link #endsAfter(Instant)}. + * + * @param instant the instant, not null + * @return true if this interval contains the instant + */ + public boolean contains(Instant instant) { + return startsAtOrBefore(instant) && endsAfter(instant); + } + + /** + * Checks if this interval is after the specified instant. + *

+ * The result is true if this interval starts after the specified instant. * An empty interval behaves as though it is an instant for comparison purposes. + *

+ * This is equivalent to {@link #startsAfter(Instant)}. * - * @param interval the other interval to compare to, not null - * @return true if this instant is after the specified instant + * @param instant the other instant to compare to, not null + * @return true if the start of this interval is after the specified instant */ - public boolean isAfter(Interval interval) { - return start.compareTo(interval.end) >= 0 && !interval.equals(this); + public boolean isAfter(Instant instant) { + return startsAfter(instant); } /** - * Checks if this interval is before the specified interval. + * Checks if this interval is before the specified instant. *

- * The result is true if the this instant ends before the start of the specified interval. + * The result is true if this interval ends before the specified instant. * Since intervals do not include their end points, this will return true if the - * two intervals abut. + * instant equals the end of the interval. * An empty interval behaves as though it is an instant for comparison purposes. + *

+ * This is equivalent to {@link #endsAtOrBefore(Instant)} {@code &&} {@link #startsBefore(Instant)}. * - * @param interval the other interval to compare to, not null - * @return true if this instant is before the specified instant + * @param instant the other instant to compare to, not null + * @return true if the end of this interval is before or equal to the specified instant */ - public boolean isBefore(Interval interval) { - return end.compareTo(interval.start) <= 0 && !interval.equals(this); + public boolean isBefore(Instant instant) { + return endsAtOrBefore(instant) && startsBefore(instant); } //----------------------------------------------------------------------- @@ -528,6 +756,7 @@ public int hashCode() { * @return a string representation of this instant, not null */ @Override + @ToString public String toString() { return start.toString() + '/' + end.toString(); } diff --git a/src/main/java/org/threeten/extra/LocalDateRange.java b/src/main/java/org/threeten/extra/LocalDateRange.java index 5e397bea..5e168552 100644 --- a/src/main/java/org/threeten/extra/LocalDateRange.java +++ b/src/main/java/org/threeten/extra/LocalDateRange.java @@ -37,13 +37,17 @@ import java.time.Period; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAdjuster; -import java.util.Iterator; +import java.util.Comparator; import java.util.Objects; import java.util.Spliterator; import java.util.Spliterators; +import java.util.function.Consumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * A range of local dates. *

@@ -52,12 +56,17 @@ * Internally, the class stores the start and end dates, with the start inclusive and the end exclusive. * The end date is always greater than or equal to the start date. *

- * The constants {@link LocalDate#MIN} and {@link LocalDate#MAX} can be used + * The constants {@code LocalDate.MIN} and {@code LocalDate.MAX} can be used * to indicate an unbounded far-past or far-future. Note that there is no difference - * between a half-open and a closed range when the end is {@link LocalDate#MAX}. + * between a half-open and a closed range when the end is {@code LocalDate.MAX}. + * Empty ranges are allowed. + *

+ * No range can end at {@code LocalDate.MIN} or {@code LocalDate.MIN.plusDays(1)}. + * No range can start at {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)}. + * No empty range can exist at {@code LocalDate.MIN} or {@code LocalDate.MAX}. *

* Date ranges are not comparable. To compare the length of two ranges, it is - * generally recommended to compare the number of days the contain. + * generally recommended to compare the number of days they contain. * *

Implementation Requirements:

* This class is immutable and thread-safe. @@ -68,6 +77,14 @@ public final class LocalDateRange implements Serializable { + /** + * The day after the MIN date. + */ + private static final LocalDate MINP1 = LocalDate.MIN.plusDays(1); + /** + * The day before the MAX date. + */ + private static final LocalDate MAXM1 = LocalDate.MAX.minusDays(1); /** * A range over the whole time-line. */ @@ -91,22 +108,27 @@ public final class LocalDateRange /** * Obtains a half-open range of dates, including the start and excluding the end. *

- * The range includes the start date and excludes the end date, unless the end - * is {@link LocalDate#MAX}. + * The range includes the start date and excludes the end date, unless the end is {@code LocalDate.MAX}. * The end date must be equal to or after the start date. * This definition permits an empty range located at a specific date. + *

+ * The constants {@code LocalDate.MIN} and {@code LocalDate.MAX} can be used + * to indicate an unbounded far-past or far-future. + *

+ * The start inclusive date must not be {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)}. + * The end inclusive date must not be {@code LocalDate.MIN} or {@code LocalDate.MIN.plusDays(1)}. + * No empty range can exist at {@code LocalDate.MIN} or {@code LocalDate.MAX}. * - * @param startInclusive the start date, inclusive, LocalDate.MIN treated as unbounded, not null - * @param endExclusive the end date, exclusive, LocalDate.MAX treated as unbounded, not null + * @param startInclusive the inclusive start date, not null + * @param endExclusive the exclusive end date, not null * @return the half-open range, not null - * @throws DateTimeException if the end is before the start + * @throws DateTimeException if the end is before the start, + * or the start date is {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)}, + * or the end date is {@code LocalDate.MIN} or {@code LocalDate.MIN.plusDays(1)} */ public static LocalDateRange of(LocalDate startInclusive, LocalDate endExclusive) { Objects.requireNonNull(startInclusive, "startInclusive"); Objects.requireNonNull(endExclusive, "endExclusive"); - if (endExclusive.isBefore(startInclusive)) { - throw new DateTimeException("End date must on or after start date"); - } return new LocalDateRange(startInclusive, endExclusive); } @@ -115,17 +137,26 @@ public static LocalDateRange of(LocalDate startInclusive, LocalDate endExclusive *

* The range includes the start date and the end date. * The end date must be equal to or after the start date. + *

+ * The constants {@code LocalDate.MIN} and {@code LocalDate.MAX} can be used + * to indicate an unbounded far-past or far-future. In addition, an end date of + * {@code LocalDate.MAX.minusDays(1)} will also create an unbounded far-future range. + *

+ * The start inclusive date must not be {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)}. + * The end inclusive date must not be {@code LocalDate.MIN}. * - * @param startInclusive the inclusive start date, LocalDate.MIN treated as unbounded, not null - * @param endInclusive the inclusive end date, LocalDate.MAX treated as unbounded, not null + * @param startInclusive the inclusive start date, not null + * @param endInclusive the inclusive end date, not null * @return the closed range - * @throws DateTimeException if the end is before the start + * @throws DateTimeException if the end is before the start, + * or the start date is {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)}, + * or the end date is {@code LocalDate.MIN} */ public static LocalDateRange ofClosed(LocalDate startInclusive, LocalDate endInclusive) { Objects.requireNonNull(startInclusive, "startInclusive"); Objects.requireNonNull(endInclusive, "endInclusive"); if (endInclusive.isBefore(startInclusive)) { - throw new DateTimeException("Start date must on or before end date"); + throw new DateTimeException("Start date must be on or before end date"); } LocalDate end = (endInclusive.equals(LocalDate.MAX) ? LocalDate.MAX : endInclusive.plusDays(1)); return new LocalDateRange(startInclusive, end); @@ -136,8 +167,12 @@ public static LocalDateRange ofClosed(LocalDate startInclusive, LocalDate endInc *

* The end date is calculated as the start plus the duration. * The period must not be negative. + *

+ * The constant {@code LocalDate.MIN} can be used to indicate an unbounded far-past. + *

+ * The period must not be zero or one day when the start date is {@code LocalDate.MIN}. * - * @param startInclusive the start date, inclusive, not null + * @param startInclusive the inclusive start date, not null * @param period the period from the start to the end, not null * @return the range, not null * @throws DateTimeException if the end is before the start, @@ -153,6 +188,60 @@ public static LocalDateRange of(LocalDate startInclusive, Period period) { return new LocalDateRange(startInclusive, startInclusive.plus(period)); } + /** + * Obtains an empty date range located at the specified date. + *

+ * The empty range has zero length and contains no other dates or ranges. + * An empty range cannot be located at {@code LocalDate.MIN}, {@code LocalDate.MIN.plusDays(1)}, + * {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)}. + * + * @param date the date where the empty range is located, not null + * @return the empty range, not null + * @throws DateTimeException if the date is {@code LocalDate.MIN}, {@code LocalDate.MIN.plusDays(1)}, + * {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)} + */ + public static LocalDateRange ofEmpty(LocalDate date) { + Objects.requireNonNull(date, "date"); + return new LocalDateRange(date, date); + } + + /** + * Obtains a range that is unbounded at the start and end. + * + * @return the range, with an unbounded start and unbounded end + */ + public static LocalDateRange ofUnbounded() { + return ALL; + } + + /** + * Obtains a range up to, but not including, the specified end date. + *

+ * The range includes all dates from the unbounded start, denoted by {@code LocalDate.MIN}, to the end date. + * The end date is exclusive and cannot be {@code LocalDate.MIN} or {@code LocalDate.MIN.plusDays(1)}. + * + * @param endExclusive the exclusive end date, {@code LocalDate.MAX} treated as unbounded, not null + * @return the range, with an unbounded start + * @throws DateTimeException if the end date is {@code LocalDate.MIN} or {@code LocalDate.MIN.plusDays(1)} + */ + public static LocalDateRange ofUnboundedStart(LocalDate endExclusive) { + return LocalDateRange.of(LocalDate.MIN, endExclusive); + } + + /** + * Obtains a range from and including the specified start date. + *

+ * The range includes all dates from the start date to the unbounded end, denoted by {@code LocalDate.MAX}. + * The start date is inclusive and cannot be {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)}. + * + * @param startInclusive the inclusive start date, {@code LocalDate.MIN} treated as unbounded, not null + * @return the range, with an unbounded end + * @throws DateTimeException if the start date is {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)} + */ + public static LocalDateRange ofUnboundedEnd(LocalDate startInclusive) { + return LocalDateRange.of(startInclusive, LocalDate.MAX); + } + //----------------------------------------------------------------------- /** * Obtains an instance of {@code LocalDateRange} from a text string such as @@ -172,6 +261,7 @@ public static LocalDateRange of(LocalDate startInclusive, Period period) { * @return the parsed range, not null * @throws DateTimeParseException if the text cannot be parsed */ + @FromString public static LocalDateRange parse(CharSequence text) { Objects.requireNonNull(text, "text"); for (int i = 0; i < text.length(); i++) { @@ -208,6 +298,18 @@ public static LocalDateRange parse(CharSequence text) { * @param endExclusive the end date, exclusive, validated not null */ private LocalDateRange(LocalDate startInclusive, LocalDate endExclusive) { + if (endExclusive.isBefore(startInclusive)) { + throw new DateTimeException("End date must be on or after start date"); + } + if (startInclusive.equals(MAXM1)) { + throw new DateTimeException("Range must not start at LocalDate.MAX.minusDays(1)"); + } + if (endExclusive.equals(MINP1)) { + throw new DateTimeException("Range must not end at LocalDate.MIN.plusDays(1)"); + } + if (endExclusive.equals(LocalDate.MIN) || startInclusive.equals(LocalDate.MAX)) { + throw new DateTimeException("Empty range must not be at LocalDate.MIN or LocalDate.MAX"); + } this.start = startInclusive; this.end = endExclusive; } @@ -216,8 +318,10 @@ private LocalDateRange(LocalDate startInclusive, LocalDate endExclusive) { /** * Gets the start date of this range, inclusive. *

- * This will return {@link LocalDate#MIN} if the range is unbounded at the start. + * This will return {@code LocalDate#MIN} if the range is unbounded at the start. * In this case, the range includes all dates into the far-past. + *

+ * This never returns {@code LocalDate.MAX} or {@code LocalDate.MAX.minusDays(1)}. * * @return the start date */ @@ -228,8 +332,10 @@ public LocalDate getStart() { /** * Gets the end date of this range, exclusive. *

- * This will return {@link LocalDate#MAX} if the range is unbounded at the end. + * This will return {@code LocalDate.MAX} if the range is unbounded at the end. * In this case, the range includes all dates into the far-future. + *

+ * This never returns {@code LocalDate.MIN} or {@code LocalDate.MIN.plusDays(1)}. * * @return the end date, exclusive */ @@ -240,8 +346,12 @@ public LocalDate getEnd() { /** * Gets the end date of this range, inclusive. *

- * This will return {@link LocalDate#MAX} if the range is unbounded at the end. + * This will return {@code LocalDate.MAX} if the range is unbounded at the end. * In this case, the range includes all dates into the far-future. + *

+ * This returns the date before the end date. + *

+ * This never returns {@code LocalDate.MIN}. * * @return the end date, inclusive */ @@ -249,9 +359,6 @@ public LocalDate getEndInclusive() { if (isUnboundedEnd()) { return LocalDate.MAX; } - if (end.equals(LocalDate.MIN)) { - return LocalDate.MIN; - } return end.minusDays(1); } @@ -259,7 +366,9 @@ public LocalDate getEndInclusive() { /** * Checks if the range is empty. *

- * An empty range occurs when the start date equals the inclusive end date. + * An empty range occurs when the start date equals the end date. + *

+ * An empty range is never unbounded. * * @return true if the range is empty */ @@ -269,6 +378,8 @@ public boolean isEmpty() { /** * Checks if the start of the range is unbounded. + *

+ * An unbounded range is never empty. * * @return true if start is unbounded */ @@ -278,6 +389,8 @@ public boolean isUnboundedStart() { /** * Checks if the end of the range is unbounded. + *

+ * An unbounded range is never empty. * * @return true if end is unbounded */ @@ -295,7 +408,7 @@ public boolean isUnboundedEnd() { *

* For example, to adjust the start to one week earlier: *

-     *  range = range.withStart(date -> date.minus(1, ChronoUnit.WEEKS));
+     *  range = range.withStart(date -> date.minus(1, ChronoUnit.WEEKS));
      * 
* * @param adjuster the adjuster to use, not null @@ -315,7 +428,7 @@ public LocalDateRange withStart(TemporalAdjuster adjuster) { *

* For example, to adjust the end to one week later: *

-     *  range = range.withEnd(date -> date.plus(1, ChronoUnit.WEEKS));
+     *  range = range.withEnd(date -> date.plus(1, ChronoUnit.WEEKS));
      * 
* * @param adjuster the adjuster to use, not null @@ -331,9 +444,9 @@ public LocalDateRange withEnd(TemporalAdjuster adjuster) { * Checks if this range contains the specified date. *

* This checks if the specified date is within the bounds of this range. - * If this range has an unbounded start then {@code contains(LocalDate#MIN)} returns true. - * If this range has an unbounded end then {@code contains(LocalDate#MAX)} returns true. * If this range is empty then this method always returns false. + * Else if this range has an unbounded start then {@code contains(LocalDate#MIN)} returns true. + * Else if this range has an unbounded end then {@code contains(LocalDate#MAX)} returns true. * * @param date the date to check for, not null * @return true if this range contains the date @@ -390,7 +503,7 @@ public boolean isConnected(LocalDateRange other) { /** * Checks if this range overlaps the specified range. *

- * The result is true if the the two ranges share some part of the time-line. + * The result is true if the two ranges share some part of the time-line. * An empty range overlaps itself. *

* This is equivalent to {@code (isConnected(other) && !abuts(other))}. @@ -488,25 +601,36 @@ public LocalDateRange span(LocalDateRange other) { * @return the stream of dates from the start to the end */ public Stream stream() { - Iterator it = new Iterator() { - private LocalDate current = start; + long count = end.toEpochDay() - start.toEpochDay() + (isUnboundedEnd() ? 1 : 0); + Spliterator spliterator = new Spliterators.AbstractSpliterator( + count, + Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.ORDERED | + Spliterator.SORTED | Spliterator.SIZED | Spliterator.SUBSIZED) { + private LocalDate current = start; + @Override - public LocalDate next() { - LocalDate result = current; - current = current.plusDays(1); - return result; + public boolean tryAdvance(Consumer action) { + if (current != null) { + if (current.isBefore(end)) { + action.accept(current); + current = current.plusDays(1); + return true; + } + if (current.equals(LocalDate.MAX)) { + action.accept(LocalDate.MAX); + current = null; + return true; + } + } + return false; } - + @Override - public boolean hasNext() { - return current.isBefore(end); + public Comparator getComparator() { + return null; } }; - long count = end.toEpochDay() - start.toEpochDay() + 1; - Spliterator spliterator = Spliterators.spliterator(it, count, - Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.ORDERED | - Spliterator.SORTED | Spliterator.SIZED | Spliterator.SUBSIZED); return StreamSupport.stream(spliterator, false); } @@ -569,23 +693,33 @@ public boolean isBefore(LocalDateRange range) { * Obtains the length of this range in days. *

* This returns the number of days between the start and end dates. + * If the range is too large, the length will be {@code Integer.MAX_VALUE}. + * Unbounded ranges return {@code Integer.MAX_VALUE}. * - * @return the length in days - * @throws ArithmeticException if the length exceeds the capacity of an {@code int} + * @return the length in days, Integer.MAX_VALUE if unbounded or too large */ public int lengthInDays() { - return Math.toIntExact(end.toEpochDay() - start.toEpochDay()); + if (isUnboundedStart() || isUnboundedEnd()) { + return Integer.MAX_VALUE; + } + long length = end.toEpochDay() - start.toEpochDay(); + return length > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) length; } /** * Obtains the length of this range as a period. *

* This returns the {@link Period} between the start and end dates. + * Unbounded ranges throw {@link ArithmeticException}. * * @return the period of the range - * @throws ArithmeticException if the calculation exceeds the capacity of {@code Period} + * @throws ArithmeticException if the calculation exceeds the capacity of {@code Period}, + * or the range is unbounded */ public Period toPeriod() { + if (isUnboundedStart() || isUnboundedEnd()) { + throw new ArithmeticException("Unbounded range cannot be converted to a Period"); + } return Period.between(start, end); } @@ -631,6 +765,7 @@ public int hashCode() { * @return a string representation of this date, not null */ @Override + @ToString public String toString() { return start.toString() + '/' + end.toString(); } diff --git a/src/main/java/org/threeten/extra/Minutes.java b/src/main/java/org/threeten/extra/Minutes.java index 87e3d588..e3994d0b 100644 --- a/src/main/java/org/threeten/extra/Minutes.java +++ b/src/main/java/org/threeten/extra/Minutes.java @@ -48,6 +48,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * A minute-based amount of time, such as '8 minutes'. *

@@ -75,6 +78,10 @@ public final class Minutes */ private static final long serialVersionUID = 2602801843170589407L; + /** + * The number of minutes per day. + */ + private static final int MINUTES_PER_DAY = 24 * 60; /** * The number of minutes per hour. */ @@ -84,9 +91,11 @@ public final class Minutes * The pattern for parsing. */ private static final Pattern PATTERN = - Pattern.compile("([-+]?)PT" + Pattern.compile("([-+]?)P" + + "(?:([-+]?[0-9]+)D)?" + + "(?:T" + "(?:([-+]?[0-9]+)H)?" - + "(?:([-+]?[0-9]+)M)?", Pattern.CASE_INSENSITIVE); + + "(?:([-+]?[0-9]+)M)?)?", Pattern.CASE_INSENSITIVE); /** * The number of minutes. @@ -168,22 +177,26 @@ public static Minutes from(TemporalAmount amount) { /** * Obtains a {@code Minutes} from a text string such as {@code PTnM}. *

- * This will parse the string produced by {@code toString()} which is - * based on the ISO-8601 period format {@code PTnHnM}. + * This will parse the string produced by {@code toString()} and other + * related formats based on ISO-8601 {@code PnDTnHnM}. *

* The string starts with an optional sign, denoted by the ASCII negative * or positive symbol. If negative, the whole amount is negated. - * The ASCII letters "P" and "T" are next in upper or lower case. - * There are then two sections, each consisting of a number and a suffix. - * At least one of the two sections must be present. - * The sections have suffixes in ASCII of "H" and "M" for hours and minutes, - * accepted in upper or lower case. The suffixes must occur in order. + * The ASCII letter "P" is next in upper or lower case. + * There are three sections consisting of a number and a suffix. + * There is one section for days suffixed by "D", + * followed by one section for hours suffixed by "H", + * followed by one section for minutes suffixed by "M". + * At least one section must be present. + * If the hours or minutes section is present it must be prefixed by "T". + * If the hours or minutes section is omitted the "T" must be omitted. + * Letters must be in ASCII upper or lower case. * The number part of each section must consist of ASCII digits. * The number may be prefixed by the ASCII negative or positive symbol. * The number must parse to an {@code int}. *

- * The leading plus/minus sign, and negative values for hours and minutes are - * not part of the ISO-8601 standard. + * The leading plus/minus sign, and negative values for days, hours and + * minutes are not part of the ISO-8601 standard. *

* For example, the following are valid inputs: *

@@ -193,55 +206,67 @@ public static Minutes from(TemporalAmount amount) {
      *   "-PT-2M"          -- Minutes.of(2)
      *   "PT3H"            -- Minutes.of(3 * 60)
      *   "PT3H-2M"         -- Minutes.of(3 * 60 - 2)
+     *   "P3D"             -- Minutes.of(3 * 24 * 60)
+     *   "P3DT2M"          -- Minutes.of(3 * 24 * 60 + 2)
      * 
* * @param text the text to parse, not null * @return the parsed period, not null * @throws DateTimeParseException if the text cannot be parsed to a period */ + @FromString public static Minutes parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { - int negate = ("-".equals(matcher.group(1)) ? -1 : 1); - String hoursStr = matcher.group(2); - String minutesStr = matcher.group(3); - if (hoursStr != null || minutesStr != null) { + int negate = "-".equals(matcher.group(1)) ? -1 : 1; + String daysStr = matcher.group(2); + String hoursStr = matcher.group(3); + String minutesStr = matcher.group(4); + if (daysStr != null || hoursStr != null || minutesStr != null) { int minutes = 0; if (minutesStr != null) { try { minutes = Integer.parseInt(minutesStr); } catch (NumberFormatException ex) { - throw new DateTimeParseException("Text cannot be parsed to a Minutes, non-numeric minutes", text, 0, ex); + throw new DateTimeParseException("Text cannot be parsed to Minutes, non-numeric minutes", text, 0, ex); } } if (hoursStr != null) { try { - int hours = Math.multiplyExact(Integer.parseInt(hoursStr), MINUTES_PER_HOUR); - minutes = Math.addExact(minutes, hours); + int hoursAsMins = Math.multiplyExact(Integer.parseInt(hoursStr), MINUTES_PER_HOUR); + minutes = Math.addExact(minutes, hoursAsMins); + } catch (NumberFormatException ex) { + throw new DateTimeParseException("Text cannot be parsed to Minutes, non-numeric hours", text, 0, ex); + } + } + if (daysStr != null) { + try { + int daysAsMins = Math.multiplyExact(Integer.parseInt(daysStr), MINUTES_PER_DAY); + minutes = Math.addExact(minutes, daysAsMins); } catch (NumberFormatException ex) { - throw new DateTimeParseException("Text cannot be parsed to a Minutes, non-numeric minutes", text, 0, ex); + throw new DateTimeParseException("Text cannot be parsed to Minutes, non-numeric days", text, 0, ex); } } return of(Math.multiplyExact(minutes, negate)); } } - throw new DateTimeParseException("Text cannot be parsed to a Minutes", text, 0); + throw new DateTimeParseException("Text cannot be parsed to Minutes", text, 0); } //----------------------------------------------------------------------- /** - * Obtains a {@code Minutes} consisting of the number of minutes between two dates. + * Obtains a {@code Minutes} consisting of the number of minutes between two temporals. *

- * The start date is included, but the end date is not. + * The start temporal is included, but the end temporal is not. * The result of this method can be negative if the end is before the start. * - * @param startDateInclusive the start date, inclusive, not null - * @param endDateExclusive the end date, exclusive, not null - * @return the number of minutes between this date and the end date, not null + * @param startInclusive the start temporal, inclusive, not null + * @param endExclusive the end temporal, exclusive, not null + * @return the number of minutes between the start and end temporals, not null */ - public static Minutes between(Temporal startDateInclusive, Temporal endDateExclusive) { - return of(Math.toIntExact(MINUTES.between(startDateInclusive, endDateExclusive))); + public static Minutes between(Temporal startInclusive, Temporal endExclusive) { + return of(Math.toIntExact(MINUTES.between(startInclusive, endExclusive))); } //----------------------------------------------------------------------- @@ -307,6 +332,33 @@ public int getAmount() { return minutes; } + /** + * Checks if the amount is negative. + * + * @return true if the amount is negative, false if the amount is zero or positive + */ + public boolean isNegative() { + return getAmount() < 0; + } + + /** + * Checks if the amount is zero. + * + * @return true if the amount is zero, false if not + */ + public boolean isZero() { + return getAmount() == 0; + } + + /** + * Checks if the amount is positive. + * + * @return true if the amount is positive, false if the amount is zero or negative + */ + public boolean isPositive() { + return getAmount() > 0; + } + //----------------------------------------------------------------------- /** * Returns a copy of this amount with the specified amount added. @@ -348,13 +400,13 @@ public Minutes plus(int minutes) { *

* This instance is immutable and unaffected by this method call. * - * @param amountToAdd the amount to add, not null + * @param amountToSubtract the amount to subtract, not null * @return a {@code Minutes} based on this instance with the requested amount subtracted, not null * @throws DateTimeException if the specified amount contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ - public Minutes minus(TemporalAmount amountToAdd) { - return minus(Minutes.from(amountToAdd).getAmount()); + public Minutes minus(TemporalAmount amountToSubtract) { + return minus(Minutes.from(amountToSubtract).getAmount()); } /** @@ -569,6 +621,7 @@ public int hashCode() { * @return the number of minutes in ISO-8601 string format */ @Override + @ToString public String toString() { return "PT" + minutes + "M"; } diff --git a/src/main/java/org/threeten/extra/Months.java b/src/main/java/org/threeten/extra/Months.java index 39bd5da1..542b9393 100644 --- a/src/main/java/org/threeten/extra/Months.java +++ b/src/main/java/org/threeten/extra/Months.java @@ -48,6 +48,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * A month-based amount of time, such as '12 months'. *

@@ -203,11 +206,12 @@ public static Months from(TemporalAmount amount) { * @return the parsed period, not null * @throws DateTimeParseException if the text cannot be parsed to a period */ + @FromString public static Months parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { - int negate = ("-".equals(matcher.group(1)) ? -1 : 1); + int negate = "-".equals(matcher.group(1)) ? -1 : 1; String weeksStr = matcher.group(2); String daysStr = matcher.group(3); if (weeksStr != null || daysStr != null) { @@ -281,7 +285,7 @@ private Object readResolve() { */ @Override public long get(TemporalUnit unit) { - if (unit == ChronoUnit.MONTHS) { + if (unit == MONTHS) { return months; } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); @@ -312,6 +316,33 @@ public int getAmount() { return months; } + /** + * Checks if the amount is negative. + * + * @return true if the amount is negative, false if the amount is zero or positive + */ + public boolean isNegative() { + return getAmount() < 0; + } + + /** + * Checks if the amount is zero. + * + * @return true if the amount is zero, false if not + */ + public boolean isZero() { + return getAmount() == 0; + } + + /** + * Checks if the amount is positive. + * + * @return true if the amount is positive, false if the amount is zero or negative + */ + public boolean isPositive() { + return getAmount() > 0; + } + //----------------------------------------------------------------------- /** * Returns a copy of this amount with the specified amount added. @@ -353,13 +384,13 @@ public Months plus(int months) { *

* This instance is immutable and unaffected by this method call. * - * @param amountToAdd the amount to add, not null + * @param amountToSubtract the amount to subtract, not null * @return a {@code Months} based on this instance with the requested amount subtracted, not null * @throws DateTimeException if the specified amount contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ - public Months minus(TemporalAmount amountToAdd) { - return minus(Months.from(amountToAdd).getAmount()); + public Months minus(TemporalAmount amountToSubtract) { + return minus(Months.from(amountToSubtract).getAmount()); } /** @@ -574,6 +605,7 @@ public int hashCode() { * @return the number of months in ISO-8601 string format */ @Override + @ToString public String toString() { return "P" + months + "M"; } diff --git a/src/main/java/org/threeten/extra/MutableClock.java b/src/main/java/org/threeten/extra/MutableClock.java new file mode 100644 index 00000000..bd0b5362 --- /dev/null +++ b/src/main/java/org/threeten/extra/MutableClock.java @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.Instant.EPOCH; +import static java.time.ZoneOffset.UTC; + +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.util.Objects; + +/** + * A clock that does not advance on its own and that must be updated manually. + *

+ * This class is designed for testing clock-sensitive components by simulating + * the passage of time. This class differs from {@link + * Clock#fixed(Instant, ZoneId)} and {@link Clock#offset(Clock, Duration)} in + * that it permits arbitrary, unrestricted updates to its instant. This allows + * for testing patterns that are not well-supported by the {@code fixed} and + * {@code offset} clocks such as the following pattern: + *

    + *
  1. Create the clock-sensitive component to be tested + *
  2. Verify some behavior of the component in the initial state + *
  3. Advance the clock without recreating the component + *
  4. Verify that the component behaves as expected given the (artificial) + * delta in clock time since the initial state + *
+ *

+ * This class is mutable. The time-zone of the clock is fixed, but the instant + * may be updated at will. + *

+ * The instant may be set to any value even if that new value is less than the + * previous value. Caution should be exercised when moving the clock backwards, + * since clock-sensitive components are likely to assume that time is + * monotonically increasing. + *

+ * Update semantics are expressed in terms of {@link ZonedDateTime}. The steps + * of each update are as follows: + *

    + *
  1. The clock captures its own state in a {@code ZonedDateTime} via {@link + * ZonedDateTime#now(Clock)} (or the equivalent thereof) + *
  2. The update operation is applied to that {@code ZonedDateTime}, producing + * a new {@code ZonedDateTime} + *
  3. The resulting {@code ZonedDateTime} is converted to an instant via {@link + * ZonedDateTime#toInstant()} (or the equivalent thereof) + *
  4. The clock's instant is set to that new instant + *
+ *

+ * Therefore, whenever there is a question about what argument types, units, + * fields, or values an update operation supports, or what the result will be, + * refer to the corresponding method of {@code ZonedDateTime}. Links are + * provided from the documentation of each update operation of this class to the + * corresponding method of {@code ZonedDateTime}. + * + *

Implementation Requirements:

+ * This class is thread-safe. Updates are atomic and synchronized. + *

+ * While update semantics are expressed in terms of {@code ZonedDateTime}, that + * imposes no requirements on implementation details. The implementation may + * avoid using {@code ZonedDateTime} completely or only sometimes, for + * convenience, efficiency, or any other reason. + * + * @serial exclude + */ +public final class MutableClock + extends Clock + implements Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -6152029959790119695L; + + /** + * The mutable instant of this clock. + */ + private final transient InstantHolder instantHolder; + + /** + * The fixed time-zone of this clock. + */ + private final transient ZoneId zone; + + /** + * Obtains a new {@code MutableClock} set to the epoch of + * 1970-01-01T00:00:00Z, converting to date and time using the UTC + * time-zone. + *

+ * Use this method when a {@code MutableClock} is needed and neither its + * initial value nor its time-zone are important. This is often true when + * testing behavior that depends on elapsed relative time rather + * than absolute time. + * + * @return a new {@code MutableClock}, not null + */ + public static MutableClock epochUTC() { + return MutableClock.of(EPOCH, UTC); + } + + /** + * Obtains a new {@code MutableClock} set to the specified instant, + * converting to date and time using the specified time-zone. + * + * @param instant the initial value for the clock, not null + * @param zone the time-zone to use, not null + * @return a new {@code MutableClock}, not null + */ + public static MutableClock of(Instant instant, ZoneId zone) { + Objects.requireNonNull(instant, "instant"); + Objects.requireNonNull(zone, "zone"); + return new MutableClock(new InstantHolder(instant), zone); + } + + /** + * Constructor. + * + * @param instantHolder the mutable instant, validated not null + * @param zone the fixed time-zone, validated not null + */ + private MutableClock(InstantHolder instantHolder, ZoneId zone) { + this.instantHolder = instantHolder; + this.zone = zone; + } + + /** + * Overrides the instant of this clock with the specified value. + * + * @param instant the new instant for this clock, not null + */ + public void setInstant(Instant instant) { + Objects.requireNonNull(instant, "instant"); + instantHolder.set(instant); + } + + /** + * Adds the specified amount to this clock. + *

+ * Atomically updates this clock to the value of the following expression: + *

+     *   ZonedDateTime.now(thisClock)
+     *                .plus(amountToAdd)
+     *                .toInstant()
+     * 
+ * + * @param amountToAdd the amount to add, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + * @see ZonedDateTime#plus(TemporalAmount) + */ + public void add(TemporalAmount amountToAdd) { + Objects.requireNonNull(amountToAdd, "amountToAdd"); + synchronized (instantHolder) { + ZonedDateTime current = ZonedDateTime.ofInstant(instantHolder.get(), zone); + ZonedDateTime result = current.plus(amountToAdd); + instantHolder.set(result.toInstant()); + } + } + + /** + * Adds the specified amount to this clock. + *

+ * Atomically updates this clock to the value of the following expression: + *

+     *   ZonedDateTime.now(thisClock)
+     *                .plus(amountToAdd, unit)
+     *                .toInstant()
+     * 
+ * + * @param amountToAdd the amount of the specified unit to add, may be negative + * @param unit the unit of the amount to add, not null + * @throws DateTimeException if the unit cannot be added + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + * @see ZonedDateTime#plus(long, TemporalUnit) + */ + public void add(long amountToAdd, TemporalUnit unit) { + Objects.requireNonNull(unit, "unit"); + synchronized (instantHolder) { + ZonedDateTime current = ZonedDateTime.ofInstant(instantHolder.get(), zone); + ZonedDateTime result = current.plus(amountToAdd, unit); + instantHolder.set(result.toInstant()); + } + } + + /** + * Adjusts this clock. + *

+ * Atomically updates this clock to the value of the following expression: + *

+     *   ZonedDateTime.now(thisClock)
+     *                .with(adjuster)
+     *                .toInstant()
+     * 
+ * + * @param adjuster the adjuster to use, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + * @see ZonedDateTime#with(TemporalAdjuster) + */ + public void set(TemporalAdjuster adjuster) { + Objects.requireNonNull(adjuster, "adjuster"); + synchronized (instantHolder) { + ZonedDateTime current = ZonedDateTime.ofInstant(instantHolder.get(), zone); + ZonedDateTime result = current.with(adjuster); + instantHolder.set(result.toInstant()); + } + } + + /** + * Alters the specified field of this clock. + *

+ * Atomically updates this clock to the value of the following expression: + *

+     *   ZonedDateTime.now(thisClock)
+     *                .with(field, newValue)
+     *                .toInstant()
+     * 
+ * + * @param field the field to set, not null + * @param newValue the new value of the field + * @throws DateTimeException if the field cannot be set + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + * @see ZonedDateTime#with(TemporalField, long) + */ + public void set(TemporalField field, long newValue) { + Objects.requireNonNull(field, "field"); + synchronized (instantHolder) { + ZonedDateTime current = ZonedDateTime.ofInstant(instantHolder.get(), zone); + ZonedDateTime result = current.with(field, newValue); + instantHolder.set(result.toInstant()); + } + } + + @Override + public ZoneId getZone() { + return zone; + } + + /** + * Returns a {@code MutableClock} that uses the specified time-zone and that + * has shared updates with this clock. + *

+ * Two clocks with shared updates always have the same instant, and all + * updates applied to either clock affect both clocks. + * + * @param zone the time-zone to use for the returned clock, not null + * @return a view of this clock in the specified time-zone, not null + */ + @Override + public MutableClock withZone(ZoneId zone) { + Objects.requireNonNull(zone, "zone"); + if (zone.equals(this.zone)) { + return this; + } + return new MutableClock(instantHolder, zone); + } + + @Override + public Instant instant() { + return instantHolder.get(); + } + + /** + * Returns {@code true} if {@code obj} is a {@code MutableClock} that uses + * the same time-zone as this clock and has shared updates with this clock. + *

+ * Two clocks with shared updates always have the same instant, and all + * updates applied to either clock affect both clocks. + *

+ * A deserialized {@code MutableClock} is not equal to the original clock + * that was serialized, since the two clocks do not have shared updates. + * + * @param obj the object to check, null returns {@code false} + * @return {@code true} if this is equal to the other clock + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MutableClock) { + MutableClock other = (MutableClock) obj; + return instantHolder == other.instantHolder && zone.equals(other.zone); + } + return false; + } + + /** + * A hash code for this clock, which is constant for this instance. + * + * @return a constant hash code for this instance + */ + @Override + public int hashCode() { + return System.identityHashCode(instantHolder) ^ zone.hashCode(); + } + + @Override + public String toString() { + return "MutableClock[" + instant() + "," + getZone() + "]"; + } + + /** + * Returns the serialization proxy to replace this {@code MutableClock}. + * + * @return the serialization proxy, not null + */ + private Object writeReplace() { + return new SerializationProxy(this); + } + + /** + * Throws {@link InvalidObjectException}. + * + * @param s ignored + * @throws InvalidObjectException always + */ + private void readObject(ObjectInputStream s) throws InvalidObjectException { + throw new InvalidObjectException("Proxy required"); + } + + /** + * The serialized form of a {@code MutableClock}. + * + * @serial include + */ + private static final class SerializationProxy + implements Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = 8602110640241828260L; + + /** + * A snapshot of the instant of the {@code MutableClock}, taken when the + * clock was serialized, not null. + * + * @serial + */ + private final Instant instant; + + /** + * The time-zone of the {@code MutableClock}, not null. + * + * @serial + */ + private final ZoneId zone; + + /** + * Constructor. + * + * @param clock the {@code MutableClock} to be serialized, not null + */ + SerializationProxy(MutableClock clock) { + instant = clock.instant(); + zone = clock.getZone(); + } + + /** + * Returns the {@code MutableClock} to replace this serialization proxy. + * + * @return the {@code MutableClock}, not null + * @throws InvalidObjectException if the instant or time-zone is null + */ + private Object readResolve() throws InvalidObjectException { + if (instant == null) { + throw new InvalidObjectException("null instant"); + } + if (zone == null) { + throw new InvalidObjectException("null zone"); + } + return MutableClock.of(instant, zone); + } + } + + /** + * An identity-having holder object for a mutable instant value. + *

+ * Clocks have shared updates when they share a holder object. Clocks rely + * on the identity of the holder object in their {@code equals} and {@code + * hashCode} methods. + *

+ * Reads of the value are volatile and are never stale. Blind writes to the + * value are volatile and do not need to synchronize. Atomic read-and-write + * operations must synchronize on the holder object instance. + */ + private static final class InstantHolder { + /** + * The current value. + */ + private volatile Instant value; + + /** + * Constructor. + * + * @param value the initial value, validated not null + */ + InstantHolder(Instant value) { + this.value = value; + } + + /** + * Reads the value. + * + * @return the current value, not null + */ + Instant get() { + return value; + } + + /** + * Writes the value. + * + * @param value the new value, validated not null + */ + void set(Instant value) { + this.value = value; + } + } +} diff --git a/src/main/java/org/threeten/extra/OffsetDate.java b/src/main/java/org/threeten/extra/OffsetDate.java new file mode 100644 index 00000000..1f3731d7 --- /dev/null +++ b/src/main/java/org/threeten/extra/OffsetDate.java @@ -0,0 +1,1368 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoUnit.DAYS; + +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.DayOfWeek; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Month; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.Period; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAdjusters; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; +import java.time.zone.ZoneRules; +import java.util.Objects; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; + +/** + * A date with an offset from UTC/Greenwich in the ISO-8601 calendar system, + * such as {@code 2007-12-03+01:00}. + *

+ * {@code OffsetDate} is an immutable date-time object that represents a date, often viewed + * as year-month-day-offset. This object can also access other date fields such as + * day-of-year, day-of-week and week-of-year. + *

+ * This class does not store or represent a time. + * For example, the value "2nd October 2007 +02:00" can be stored + * in an {@code OffsetDate}. + * + *

Implementation Requirements:

+ * This class is immutable and thread-safe. + *

+ * This class must be treated as a value type. Do not synchronize, rely on the + * identity hash code or use the distinction between equals() and ==. + */ +public final class OffsetDate + implements Temporal, TemporalAdjuster, Comparable, Serializable { + + /** + * The minimum supported {@code OffsetDate}, '-999999999-01-01+18:00'. + * This is the minimum local date in the maximum offset + * (larger offsets are earlier on the time-line). + * This combines {@link LocalDate#MIN} and {@link ZoneOffset#MAX}. + * This could be used by an application as a "far past" date. + */ + public static final OffsetDate MIN = OffsetDate.of(LocalDate.MIN, ZoneOffset.MAX); + /** + * The maximum supported {@code OffsetDate}, '+999999999-12-31-18:00'. + * This is the maximum local date in the minimum offset + * (larger negative offsets are later on the time-line). + * This combines {@link LocalDate#MAX} and {@link ZoneOffset#MIN}. + * This could be used by an application as a "far future" date. + */ + public static final OffsetDate MAX = OffsetDate.of(LocalDate.MAX, ZoneOffset.MIN); + + /** + * Serialization version. + */ + private static final long serialVersionUID = -4382054179074397774L; + + /** + * The number of seconds per day. + */ + private static final long SECONDS_PER_DAY = 86400; + + /** + * The local date. + */ + private final LocalDate date; + /** + * The offset from UTC/Greenwich. + */ + private final ZoneOffset offset; + + //----------------------------------------------------------------------- + /** + * Obtains the current date from the system clock in the default time-zone. + *

+ * This will query the {@link Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current date. + * The offset will be calculated from the time-zone in the clock. + *

+ * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current date using the system clock, not null + */ + public static OffsetDate now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current date from the system clock in the specified time-zone. + *

+ * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date. + * Specifying the time-zone avoids dependence on the default time-zone. + * The offset will be calculated from the specified time-zone. + *

+ * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current date using the system clock, not null + */ + public static OffsetDate now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current date from the specified clock. + *

+ * This will query the specified clock to obtain the current date - today. + * The offset will be calculated from the time-zone in the clock. + *

+ * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current date, not null + */ + public static OffsetDate now(Clock clock) { + Objects.requireNonNull(clock, "clock"); + final Instant now = clock.instant(); // called once + return ofInstant(now, clock.getZone().getRules().getOffset(now)); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDate} from a local date and an offset. + * + * @param date the local date, not null + * @param offset the zone offset, not null + * @return the offset date, not null + */ + public static OffsetDate of(LocalDate date, ZoneOffset offset) { + return new OffsetDate(date, offset); + } + + /** + * Obtains an instance of {@code OffsetDate} from a year, month, day + * and offset. + *

+ * This creates an offset date with the four specified fields. + *

+ * This method exists primarily for writing test cases. + * Non test-code will typically use other methods to create an offset time. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, from 1 (January) to 12 (December) + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @param offset the zone offset, not null + * @return the offset date, not null + * @throws DateTimeException if the value of any field is out of range, or + * if the day-of-month is invalid for the month-year + */ + public static OffsetDate of(int year, int month, int dayOfMonth, ZoneOffset offset) { + LocalDate d = LocalDate.of(year, month, dayOfMonth); + return new OffsetDate(d, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDate} from an {@code Instant} and zone ID. + *

+ * This creates an offset date with the same instant as midnight at the + * start of day of the instant specified. + * Finding the offset from UTC/Greenwich is simple as there is only one valid + * offset for each instant. + * + * @param instant the instant to create the time from, not null + * @param zone the time-zone, which may be an offset, not null + * @return the offset time, not null + */ + public static OffsetDate ofInstant(Instant instant, ZoneId zone) { + Objects.requireNonNull(instant, "instant"); + Objects.requireNonNull(zone, "zone"); + ZoneRules rules = zone.getRules(); + ZoneOffset offset = rules.getOffset(instant); + long epochSec = instant.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later + long epochDay = Math.floorDiv(epochSec, SECONDS_PER_DAY); + LocalDate date = LocalDate.ofEpochDay(epochDay); + return new OffsetDate(date, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDate} from a temporal object. + *

+ * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code OffsetDate}. + *

+ * The conversion extracts and combines {@code LocalDate} and {@code ZoneOffset}. + *

+ * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code OffsetDate::from}. + * + * @param temporal the temporal object to convert, not null + * @return the offset date, not null + * @throws DateTimeException if unable to convert to an {@code OffsetDate} + */ + public static OffsetDate from(TemporalAccessor temporal) { + if (temporal instanceof OffsetDate) { + return (OffsetDate) temporal; + } + try { + LocalDate date = LocalDate.from(temporal); + ZoneOffset offset = ZoneOffset.from(temporal); + return new OffsetDate(date, offset); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain OffsetDate from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDate} from a text string such as {@code 2007-12-03+01:00}. + *

+ * The string must represent a valid date and is parsed using + * {@link DateTimeFormatter#ISO_OFFSET_DATE}. + * + * @param text the text to parse such as "2007-12-03+01:00", not null + * @return the parsed offset date, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + @FromString + public static OffsetDate parse(CharSequence text) { + return parse(text, DateTimeFormatter.ISO_OFFSET_DATE); + } + + /** + * Obtains an instance of {@code OffsetDate} from a text string using a specific formatter. + *

+ * The text is parsed using the formatter, returning a date. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed offset date, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetDate parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, OffsetDate::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param date the local date, not null + * @param offset the zone offset, not null + */ + private OffsetDate(LocalDate date, ZoneOffset offset) { + this.date = Objects.requireNonNull(date, "date"); + this.offset = Objects.requireNonNull(offset, "offset"); + } + + /** + * Validates the input. + * + * @return the valid object, not null + */ + private Object readResolve() { + return of(date, offset); + } + + /** + * Returns a new date based on this one, returning {@code this} where possible. + * + * @param date the date to create with, not null + * @param offset the zone offset to create with, not null + */ + private OffsetDate with(LocalDate date, ZoneOffset offset) { + if (this.date == date && this.offset.equals(offset)) { + return this; + } + return new OffsetDate(date, offset); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

+ * This checks if this date can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + *

    + *
  • {@code DAY_OF_WEEK} + *
  • {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} + *
  • {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} + *
  • {@code DAY_OF_MONTH} + *
  • {@code DAY_OF_YEAR} + *
  • {@code EPOCH_DAY} + *
  • {@code ALIGNED_WEEK_OF_MONTH} + *
  • {@code ALIGNED_WEEK_OF_YEAR} + *
  • {@code MONTH_OF_YEAR} + *
  • {@code PROLEPTIC_MONTH} + *
  • {@code YEAR_OF_ERA} + *
  • {@code YEAR} + *
  • {@code ERA} + *
  • {@code OFFSET_SECONDS} + *
+ * All other {@code ChronoField} instances will return false. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this date, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return field.isDateBased() || field == OFFSET_SECONDS; + } + return field != null && field.isSupportedBy(this); + } + + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

    + *
  • {@code DAYS} + *
  • {@code WEEKS} + *
  • {@code MONTHS} + *
  • {@code YEARS} + *
  • {@code DECADES} + *
  • {@code CENTURIES} + *
  • {@code MILLENNIA} + *
  • {@code ERAS} + *
+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isDateBased(); + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the range of valid values for the specified field. + *

+ * The range object expresses the minimum and maximum valid values for a field. + * This date is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + * @throws UnsupportedTemporalTypeException if the field is not supported + */ + @Override + public ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + return field.range(); + } + return date.range(field); + } + return field.rangeRefinedBy(this); + } + + /** + * Gets the value of the specified field from this date as an {@code int}. + *

+ * This queries this date for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date, except {@code EPOCH_DAY} and {@code PROLEPTIC_MONTH} + * which are too large to fit in an {@code int} and throw a {@code DateTimeException}. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained or + * the value is outside the range of valid values for the field + * @throws UnsupportedTemporalTypeException if the field is not supported or + * the range of values exceeds an {@code int} + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc + public int get(TemporalField field) { + return Temporal.super.get(field); + } + + /** + * Gets the value of the specified field from this date as a {@code long}. + *

+ * This queries this date for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + return getOffset().getTotalSeconds(); + } + return date.getLong(field); + } + return field.getFrom(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the zone offset, such as '+01:00'. + *

+ * This is the offset of the local date from UTC/Greenwich. + * + * @return the zone offset, not null + */ + public ZoneOffset getOffset() { + return offset; + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified offset ensuring + * that the result has the same local date. + *

+ * This method returns an object with the same {@code LocalDate} and the specified {@code ZoneOffset}. + * No calculation is needed or performed. + * For example, if this time represents {@code 2007-12-03+02:00} and the offset specified is + * {@code +03:00}, then this method will return {@code 2007-12-03+03:00}. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param offset the zone offset to change to, not null + * @return an {@code OffsetDate} based on this date with the requested offset, not null + */ + public OffsetDate withOffsetSameLocal(ZoneOffset offset) { + Objects.requireNonNull(offset, "offset"); + return with(date, offset); + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalDate} part of this date. + *

+ * This returns a {@code LocalDate} with the same year, month and day + * as this date. + * + * @return the date part of this date, not null + */ + public LocalDate toLocalDate() { + return date; + } + + //----------------------------------------------------------------------- + /** + * Gets the year field. + *

+ * This method returns the primitive {@code int} value for the year. + *

+ * The year returned by this method is proleptic as per {@code get(YEAR)}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return date.getYear(); + } + + /** + * Gets the month-of-year field from 1 to 12. + *

+ * This method returns the month as an {@code int} from 1 to 12. + * Application code is frequently clearer if the enum {@link Month} + * is used by calling {@link #getMonth()}. + * + * @return the month-of-year, from 1 to 12 + * @see #getMonth() + */ + public int getMonthValue() { + return date.getMonthValue(); + } + + /** + * Gets the month-of-year field using the {@code Month} enum. + *

+ * This method returns the enum {@link Month} for the month. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link Month#getValue() int value}. + * + * @return the month-of-year, not null + * @see #getMonthValue() + */ + public Month getMonth() { + return date.getMonth(); + } + + /** + * Gets the day-of-month field. + *

+ * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return date.getDayOfMonth(); + } + + /** + * Gets the day-of-year field. + *

+ * This method returns the primitive {@code int} value for the day-of-year. + * + * @return the day-of-year, from 1 to 365, or 366 in a leap year + */ + public int getDayOfYear() { + return date.getDayOfYear(); + } + + /** + * Gets the day-of-week field, which is an enum {@code DayOfWeek}. + *

+ * This method returns the enum {@link DayOfWeek} for the day-of-week. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link DayOfWeek#getValue() int value}. + *

+ * Additional information can be obtained from the {@code DayOfWeek}. + * This includes textual names of the values. + * + * @return the day-of-week, not null + */ + public DayOfWeek getDayOfWeek() { + return date.getDayOfWeek(); + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this date. + *

+ * This returns an {@code OffsetDate} based on this one, with the date adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

+ * A simple adjuster might simply set the one of the fields, such as the year field. + * A more complex adjuster might set the date to the last day of the month. + * A selection of common adjustments is provided in {@link TemporalAdjusters}. + * These include finding the "last day of the month" and "next Wednesday". + * Key date-time classes also implement the {@code TemporalAdjuster} interface, + * such as {@link Month} and {@link MonthDay MonthDay}. + * The adjuster is responsible for handling special cases, such as the varying + * lengths of month and leap years. + *

+ * For example this code returns a date on the last day of July: + *

+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.TemporalAdjusters.*;
+     *
+     *  result = offsetDate.with(JULY).with(lastDayOfMonth());
+     * 
+ *

+ * The classes {@link LocalDate} and {@link ZoneOffset} implement {@code TemporalAdjuster}, + * thus this method can be used to change the date or offset: + *

+     *  result = offsetDate.with(date);
+     *  result = offsetDate.with(offset);
+     * 
+ *

+ * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return an {@code OffsetDate} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate with(TemporalAdjuster adjuster) { + // optimizations + if (adjuster instanceof LocalDate) { + return with((LocalDate) adjuster, offset); + } else if (adjuster instanceof ZoneOffset) { + return with(date, (ZoneOffset) adjuster); + } else if (adjuster instanceof OffsetDate) { + return (OffsetDate) adjuster; + } + return (OffsetDate) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this date with the specified field set to a new value. + *

+ * This returns an {@code OffsetDate} based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the year, month or day-of-month. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

+ * In some cases, changing the specified field can cause the resulting date to become invalid, + * such as changing the month from 31st January to February would make the day-of-month invalid. + * In cases like this, the field is responsible for resolving the date. Typically it will choose + * the previous valid date, which would be the last valid day of February in this example. + *

+ * If the field is a {@link ChronoField} then the adjustment is implemented here. + *

+ * The {@code OFFSET_SECONDS} field will return a date with the specified offset. + * The local date is unaltered. If the new offset value is outside the valid range + * then a {@code DateTimeException} will be thrown. + *

+ * The other {@link #isSupported(TemporalField) supported fields} will behave as per + * the matching method on {@link LocalDate#with(TemporalField, long)} LocalDate}. + * In this case, the offset is not part of the calculation and will be unchanged. + *

+ * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return an {@code OffsetDate} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + ChronoField f = (ChronoField) field; + return with(date, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue))); + } + return with(date.with(field, newValue), offset); + } + return field.adjustInto(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDate} with the year altered. + *

+ * The offset does not affect the calculation and will be the same in the result. + * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR + * @return an {@code OffsetDate} based on this date with the requested year, not null + * @throws DateTimeException if the year value is invalid + */ + public OffsetDate withYear(int year) { + return with(date.withYear(year), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the month-of-year altered. + *

+ * The offset does not affect the calculation and will be the same in the result. + * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the result, from 1 (January) to 12 (December) + * @return an {@code OffsetDate} based on this date with the requested month, not null + * @throws DateTimeException if the month-of-year value is invalid + */ + public OffsetDate withMonth(int month) { + return with(date.withMonth(month), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the day-of-month altered. + *

+ * If the resulting date is invalid, an exception is thrown. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31 + * @return an {@code OffsetDate} based on this date with the requested day, not null + * @throws DateTimeException if the day-of-month value is invalid, + * or if the day-of-month is invalid for the month-year + */ + public OffsetDate withDayOfMonth(int dayOfMonth) { + return with(date.withDayOfMonth(dayOfMonth), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the day-of-year altered. + *

+ * If the resulting date is invalid, an exception is thrown. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366 + * @return an {@code OffsetDate} based on this date with the requested day, not null + * @throws DateTimeException if the day-of-year value is invalid, + * or if the day-of-year is invalid for the year + */ + public OffsetDate withDayOfYear(int dayOfYear) { + return with(date.withDayOfYear(dayOfYear), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period added. + *

+ * This returns an {@code OffsetDate} based on this one, with the specified amount added. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

+ * This uses {@link TemporalAmount#addTo(Temporal)} to perform the calculation. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return an {@code OffsetDate} based on this date with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate plus(TemporalAmount amountToAdd) { + return (OffsetDate) amountToAdd.addTo(this); + } + + /** + * Returns a copy of this date with the specified amount added. + *

+ * This returns an {@code OffsetDate} based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoUnit} then the addition is implemented by + * {@link LocalDate#plus(long, TemporalUnit)}. + * The offset is not part of the calculation and will be unchanged in the result. + *

+ * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the amount to add, not null + * @return an {@code OffsetDate} based on this date with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return with(date.plus(amountToAdd, unit), offset); + } + return unit.addTo(this, amountToAdd); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDate} with the specified number of years added. + *

+ * This uses {@link LocalDate#plusYears(long)} to add the years. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param years the years to add, may be negative + * @return an {@code OffsetDate} based on this date with the years added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate plusYears(long years) { + return with(date.plusYears(years), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified number of months added. + *

+ * This uses {@link LocalDate#plusMonths(long)} to add the months. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param months the months to add, may be negative + * @return an {@code OffsetDate} based on this date with the months added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate plusMonths(long months) { + return with(date.plusMonths(months), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified number of weeks added. + *

+ * This uses {@link LocalDate#plusWeeks(long)} to add the weeks. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param weeks the weeks to add, may be negative + * @return an {@code OffsetDate} based on this date with the weeks added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate plusWeeks(long weeks) { + return with(date.plusWeeks(weeks), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified number of days added. + *

+ * This uses {@link LocalDate#plusDays(long)} to add the days. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param days the days to add, may be negative + * @return an {@code OffsetDate} based on this date with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate plusDays(long days) { + return with(date.plusDays(days), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified amount subtracted. + *

+ * This returns am {@code OffsetDate} based on this one, with the specified amount subtracted. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

+ * This uses {@link TemporalAmount#subtractFrom(Temporal)} to perform the calculation. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount to subtract, not null + * @return an {@code OffsetDate} based on this date with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate minus(TemporalAmount amountToSubtract) { + return (OffsetDate) amountToSubtract.subtractFrom(this); + } + + /** + * Returns a copy of this date with the specified amount subtracted. + *

+ * This returns an {@code OffsetDate} based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + *

+ * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the amount to subtract, not null + * @return an {@code OffsetDate} based on this date with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDate} with the specified number of years subtracted. + *

+ * This uses {@link LocalDate#minusYears(long)} to subtract the years. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param years the years to subtract, may be negative + * @return an {@code OffsetDate} based on this date with the years subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate minusYears(long years) { + return with(date.minusYears(years), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified number of months subtracted. + *

+ * This uses {@link LocalDate#minusMonths(long)} to subtract the months. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param months the months to subtract, may be negative + * @return an {@code OffsetDate} based on this date with the months subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate minusMonths(long months) { + return with(date.minusMonths(months), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified number of weeks subtracted. + *

+ * This uses {@link LocalDate#minusWeeks(long)} to subtract the weeks. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param weeks the weeks to subtract, may be negative + * @return an {@code OffsetDate} based on this date with the weeks subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate minusWeeks(long weeks) { + return with(date.minusWeeks(weeks), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified number of days subtracted. + *

+ * This uses {@link LocalDate#minusDays(long)} to subtract the days. + * The offset does not affect the calculation and will be the same in the result. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param days the days to subtract, may be negative + * @return an {@code OffsetDate} based on this date with the days subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate minusDays(long days) { + return with(date.minusDays(days), offset); + } + + //----------------------------------------------------------------------- + /** + * Queries this date using the specified query. + *

+ * This queries this date using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

+ * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == TemporalQueries.chronology()) { + return (R) IsoChronology.INSTANCE; + } else if (query == TemporalQueries.precision()) { + return (R) DAYS; + } else if (query == TemporalQueries.offset() || query == TemporalQueries.zone()) { + return (R) getOffset(); + } + return Temporal.super.query(query); + } + + /** + * Adjusts the specified temporal object to have the same offset and date + * as this object. + *

+ * This returns a temporal object of the same observable type as the input + * with the offset and date changed to be the same as this. + *

+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * twice, passing {@link ChronoField#OFFSET_SECONDS} and + * {@link ChronoField#EPOCH_DAY} as the fields. + *

+ * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisOffsetDate.adjustInto(temporal);
+     *   temporal = temporal.with(thisOffsetDate);
+     * 
+ *

+ * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + return temporal + .with(OFFSET_SECONDS, getOffset().getTotalSeconds()) + .with(EPOCH_DAY, toLocalDate().toEpochDay()); + } + + /** + * Calculates the period between this date and another date in + * terms of the specified unit. + *

+ * This calculates the period between two dates in terms of a single unit. + * The start and end points are {@code this} and the specified date. + * The result will be negative if the end is before the start. + * For example, the period in days between two dates can be calculated + * using {@code startDate.until(endDate, DAYS)}. + *

+ * The {@code Temporal} passed to this method is converted to a + * {@code OffsetDate} using {@link #from(TemporalAccessor)}. + * If the offset differs between the two times, then the specified + * end time is normalized to have the same offset as this time. + *

+ * The calculation returns a whole number, representing the number of + * complete units between the two dates. + * For example, the period in months between 2012-06-15Z and 2012-08-14Z + * will only be one month as it is one day short of two months. + *

+ * There are two equivalent ways of using this method. + * The first is to invoke this method. + * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: + *

+     *   // these two lines are equivalent
+     *   amount = start.until(end, DAYS);
+     *   amount = DAYS.between(start, end);
+     * 
+ * The choice should be made based on which makes the code more readable. + *

+ * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS}, + * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} + * are supported. Other {@code ChronoUnit} values will throw an exception. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param endExclusive the end time, exclusive, which is converted to an {@code OffsetDate}, not null + * @param unit the unit to measure the amount in, not null + * @return the amount of time between this date and the end date + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to an {@code OffsetDate} + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long until(Temporal endExclusive, TemporalUnit unit) { + OffsetDate end = OffsetDate.from(endExclusive); + if (unit instanceof ChronoUnit) { + long offsetDiff = end.offset.getTotalSeconds() - offset.getTotalSeconds(); + LocalDate endLocal = end.date.plusDays(Math.floorDiv(-offsetDiff, SECONDS_PER_DAY)); + return date.until(endLocal, unit); + } + return unit.between(this, end); + } + + /** + * Formats this date using the specified formatter. + *

+ * This date will be passed to the formatter to produce a string. + * + * @param formatter the formatter to use, not null + * @return the formatted date string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String format(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.format(this); + } + + //----------------------------------------------------------------------- + /** + * Returns an offset date-time formed from this date at the specified time. + *

+ * This combines this date with the specified time to form an {@code OffsetDateTime}. + * All possible combinations of date and time are valid. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param time the time to combine with, not null + * @return the offset date-time formed from this date and the specified time, not null + */ + public OffsetDateTime atTime(LocalTime time) { + return OffsetDateTime.of(date, time, offset); + } + + //----------------------------------------------------------------------- + /** + * Converts this date to midnight at the start of day in epoch seconds. + * + * @return the epoch seconds value + */ + private long toEpochSecond() { + long epochDay = date.toEpochDay(); + long secs = epochDay * SECONDS_PER_DAY; + return secs - offset.getTotalSeconds(); + } + + /** + * Converts this {@code OffsetDate} to the number of seconds since the epoch + * of 1970-01-01T00:00:00Z. + *

+ * This combines this offset date with the specified time + * to calculate the epoch-second value, which is the + * number of elapsed seconds from 1970-01-01T00:00:00Z. + * Instants on the time-line after the epoch are positive, earlier + * are negative. + * + * @param time the local time, not null + * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative + */ + public long toEpochSecond(LocalTime time) { + Objects.requireNonNull(time, "time"); + return toEpochSecond() + time.toSecondOfDay(); + } + + //----------------------------------------------------------------------- + /** + * Compares this {@code OffsetDate} to another date. + *

+ * The comparison is based first on the UTC equivalent instant, then on the local date. + * It is "consistent with equals", as defined by {@link Comparable}. + *

+ * For example, the following is the comparator order: + *

    + *
  1. 2008-06-29-11:00
  2. + *
  3. 2008-06-29-12:00
  4. + *
  5. 2008-06-30+12:00
  6. + *
  7. 2008-06-29-13:00
  8. + *
+ * Values #2 and #3 represent the same instant on the time-line. + * When two values represent the same instant, the local date is compared + * to distinguish them. This step is needed to make the ordering + * consistent with {@code equals()}. + *

+ * To compare the underlying local date of two {@code TemporalAccessor} instances, + * use {@link ChronoField#EPOCH_DAY} as a comparator. + * + * @param other the other date to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(OffsetDate other) { + if (offset.equals(other.offset)) { + return date.compareTo(other.date); + } + int compare = Long.compare(toEpochSecond(), other.toEpochSecond()); + if (compare == 0) { + compare = date.compareTo(other.date); + } + return compare; + } + + //----------------------------------------------------------------------- + /** + * Checks if the instant of midnight at the start of this {@code OffsetDate} + * is after midnight at the start of the specified date. + *

+ * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the date. This is equivalent to using + * {@code date1.toEpochSecond().isAfter(date2.toEpochSecond())}. + * + * @param other the other date to compare to, not null + * @return true if this is after the instant of the specified date + */ + public boolean isAfter(OffsetDate other) { + return toEpochSecond() > other.toEpochSecond(); + } + + /** + * Checks if the instant of midnight at the start of this {@code OffsetDate} + * is before midnight at the start of the specified date. + *

+ * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the date. This is equivalent to using + * {@code date1.toEpochSecond().isBefore(date2.toEpochSecond())}. + * + * @param other the other date to compare to, not null + * @return true if this is before the instant of the specified date + */ + public boolean isBefore(OffsetDate other) { + return toEpochSecond() < other.toEpochSecond(); + } + + /** + * Checks if the instant of midnight at the start of this {@code OffsetDate} + * equals midnight at the start of the specified date. + *

+ * This method differs from the comparison in {@link #compareTo} and {@link #equals} + * in that it only compares the instant of the date. This is equivalent to using + * {@code date1.toEpochSecond().equals(date2.toEpochSecond())}. + * + * @param other the other date to compare to, not null + * @return true if the instant equals the instant of the specified date + */ + public boolean isEqual(OffsetDate other) { + return toEpochSecond() == other.toEpochSecond(); + } + + //----------------------------------------------------------------------- + /** + * Checks if this date is equal to another date. + *

+ * The comparison is based on the local-date and the offset. + * To compare for the same instant on the time-line, use {@link #isEqual(OffsetDate)}. + *

+ * Only objects of type {@code OffsetDate} are compared, other types return false. + * To compare the underlying local date of two {@code TemporalAccessor} instances, + * use {@link ChronoField#EPOCH_DAY} as a comparator. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OffsetDate) { + OffsetDate other = (OffsetDate) obj; + return date.equals(other.date) && offset.equals(other.offset); + } + return false; + } + + /** + * A hash code for this date. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return date.hashCode() ^ offset.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Outputs this date as a {@code String}, such as {@code 2007-12-03+01:00}. + *

+ * The output will be in the ISO-8601 format {@code yyyy-MM-ddXXXXX}. + * + * @return a string representation of this date, not null + */ + @Override + @ToString + public String toString() { + return date.toString() + offset.toString(); + } + +} diff --git a/src/main/java/org/threeten/extra/PackedFields.java b/src/main/java/org/threeten/extra/PackedFields.java index 91b34e91..cd7fa1cb 100644 --- a/src/main/java/org/threeten/extra/PackedFields.java +++ b/src/main/java/org/threeten/extra/PackedFields.java @@ -155,7 +155,7 @@ public boolean isSupportedBy(TemporalAccessor temporal) { @Override public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - if (isSupportedBy(temporal) == false) { + if (!temporal.isSupported(this)) { throw new DateTimeException("Unsupported field: " + this); } return range(); @@ -260,7 +260,7 @@ public boolean isSupportedBy(TemporalAccessor temporal) { @Override public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - if (isSupportedBy(temporal) == false) { + if (!temporal.isSupported(this)) { throw new DateTimeException("Unsupported field: " + this); } return range(); @@ -351,7 +351,7 @@ public boolean isSupportedBy(TemporalAccessor temporal) { @Override public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - if (isSupportedBy(temporal) == false) { + if (!temporal.isSupported(this)) { throw new DateTimeException("Unsupported field: " + this); } return range(); diff --git a/src/main/java/org/threeten/extra/PeriodDuration.java b/src/main/java/org/threeten/extra/PeriodDuration.java new file mode 100644 index 00000000..136a1944 --- /dev/null +++ b/src/main/java/org/threeten/extra/PeriodDuration.java @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.YEARS; + +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Period; +import java.time.chrono.ChronoPeriod; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; + +/** + * An amount of time in the ISO-8601 calendar system that combines a period and a duration. + *

+ * This class models a quantity or amount of time in terms of a {@code Period} and {@code Duration}. + * A period is a date-based amount of time, consisting of years, months and days. + * A duration is a time-based amount of time, consisting of seconds and nanoseconds. + * See the {@link Period} and {@link Duration} classes for more details. + *

+ * The days in a period take account of daylight saving changes (23 or 25 hour days). + * When performing calculations, the period is added first, then the duration. + *

+ * The model is of a directed amount, meaning that the amount may be negative. + * + *

Implementation Requirements:

+ * This class is immutable and thread-safe. + *

+ * This class must be treated as a value type. Do not synchronize, rely on the + * identity hash code or use the distinction between equals() and ==. + */ +public final class PeriodDuration + implements TemporalAmount, Serializable { + + /** + * A constant for a duration of zero. + */ + public static final PeriodDuration ZERO = new PeriodDuration(Period.ZERO, Duration.ZERO); + + /** + * A serialization identifier for this class. + */ + private static final long serialVersionUID = 8815521625671589L; + /** + * The supported units. + */ + private static final List SUPPORTED_UNITS = + Collections.unmodifiableList(Arrays.asList(YEARS, MONTHS, DAYS, SECONDS, NANOS)); + /** + * The number of seconds per day. + */ + private static final long SECONDS_PER_DAY = 86400; + + /** + * The period. + */ + private final Period period; + /** + * The duration. + */ + private final Duration duration; + + //----------------------------------------------------------------------- + /** + * Obtains an instance based on a period and duration. + *

+ * The total amount of time of the resulting instance is the period plus the duration. + * + * @param period the period, not null + * @param duration the duration, not null + * @return the combined period-duration, not null + */ + public static PeriodDuration of(Period period, Duration duration) { + Objects.requireNonNull(period, "The period must not be null"); + Objects.requireNonNull(duration, "The duration must not be null"); + return new PeriodDuration(period, duration); + } + + /** + * Obtains an instance based on a period. + *

+ * The duration will be zero. + * + * @param period the period, not null + * @return the combined period-duration, not null + */ + public static PeriodDuration of(Period period) { + Objects.requireNonNull(period, "The period must not be null"); + return new PeriodDuration(period, Duration.ZERO); + } + + /** + * Obtains an instance based on a duration. + *

+ * The period will be zero. + * + * @param duration the duration, not null + * @return the combined period-duration, not null + */ + public static PeriodDuration of(Duration duration) { + Objects.requireNonNull(duration, "The duration must not be null"); + return new PeriodDuration(Period.ZERO, duration); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance from a temporal amount. + *

+ * This obtains an instance based on the specified amount. + * A {@code TemporalAmount} represents an amount of time which this factory + * extracts to a {@code PeriodDuration}. + *

+ * The result is calculated by looping around each unit in the specified amount. + * Any amount that is zero is ignore. + * If a unit has an exact duration, it will be totalled using {@link Duration#plus(Duration)}. + * If the unit is days or weeks, it will be totalled into the days part of the period. + * If the unit is months or quarters, it will be totalled into the months part of the period. + * If the unit is years, decades, centuries or millennia, it will be totalled into the years part of the period. + * + * @param amount the temporal amount to convert, not null + * @return the equivalent duration, not null + * @throws DateTimeException if unable to convert to a {@code Duration} + * @throws ArithmeticException if numeric overflow occurs + */ + public static PeriodDuration from(TemporalAmount amount) { + if (amount instanceof PeriodDuration) { + return (PeriodDuration) amount; + } + if (amount instanceof Period) { + return PeriodDuration.of((Period) amount); + } + if (amount instanceof Duration) { + return PeriodDuration.of((Duration) amount); + } + if (amount instanceof ChronoPeriod) { + if (IsoChronology.INSTANCE.equals(((ChronoPeriod) amount).getChronology()) == false) { + throw new DateTimeException("Period requires ISO chronology: " + amount); + } + } + Objects.requireNonNull(amount, "amount"); + int years = 0; + int months = 0; + int days = 0; + Duration duration = Duration.ZERO; + for (TemporalUnit unit : amount.getUnits()) { + long value = amount.get(unit); + if (value != 0) { + // ignore unless non-zero + if (unit.isDurationEstimated()) { + if (unit == ChronoUnit.DAYS) { + days = Math.addExact(days, Math.toIntExact(value)); + } else if (unit == ChronoUnit.WEEKS) { + days = Math.addExact(days, Math.toIntExact(Math.multiplyExact(value, 7))); + } else if (unit == ChronoUnit.MONTHS) { + months = Math.addExact(months, Math.toIntExact(value)); + } else if (unit == IsoFields.QUARTER_YEARS) { + months = Math.addExact(months, Math.toIntExact(Math.multiplyExact(value, 3))); + } else if (unit == ChronoUnit.YEARS) { + years = Math.addExact(years, Math.toIntExact(value)); + } else if (unit == ChronoUnit.DECADES) { + years = Math.addExact(years, Math.toIntExact(Math.multiplyExact(value, 10))); + } else if (unit == ChronoUnit.CENTURIES) { + years = Math.addExact(years, Math.toIntExact(Math.multiplyExact(value, 100))); + } else if (unit == ChronoUnit.MILLENNIA) { + years = Math.addExact(years, Math.toIntExact(Math.multiplyExact(value, 1000))); + } else { + throw new DateTimeException("Unknown unit: " + unit); + } + } else { + // total of exact durations + duration = duration.plus(amount.get(unit), unit); + } + } + } + return PeriodDuration.of(Period.of(years, months, days), duration); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance from a text string such as {@code PnYnMnDTnHnMnS}. + *

+ * This will parse the string produced by {@code toString()} which is + * based on the ISO-8601 period formats {@code PnYnMnDTnHnMnS} and {@code PnW}. + *

+ * The string starts with an optional sign, denoted by the ASCII negative + * or positive symbol. If negative, the whole amount is negated. + * The ASCII letter "P" is next in upper or lower case. + * There are then a number of sections, each consisting of a number and a suffix. + * At least one of the sections must be present. + * The sections have suffixes in ASCII of "Y" for years, "M" for months, + * "W" for weeks, "D" for days, "H" for hours, "M" for minutes, "S" for seconds, + * accepted in upper or lower case. Note that the ASCII letter "T" separates + * the date and time parts and must be present if any time part is present. + * The suffixes must occur in order. + * The number part of each section must consist of ASCII digits. + * The number may be prefixed by the ASCII negative or positive symbol. + * The number must parse to an {@code int}. + * Any week-based input is multiplied by 7 and treated as a number of days. + *

+ * The leading plus/minus sign, and negative values for weeks and days are + * not part of the ISO-8601 standard. + *

+ * Note that the date style format {@code PYYYY-MM-DDTHH:MM:SS} is not supported. + *

+ * For example, the following are valid inputs: + *

+     *   "P2Y"             -- PeriodDuration.of(Period.ofYears(2))
+     *   "P3M"             -- PeriodDuration.of(Period.ofMonths(3))
+     *   "P4W"             -- PeriodDuration.of(Period.ofWeeks(4))
+     *   "P5D"             -- PeriodDuration.of(Period.ofDays(5))
+     *   "PT6H"            -- PeriodDuration.of(Duration.ofHours(6))
+     *   "P1Y2M3D"         -- PeriodDuration.of(Period.of(1, 2, 3))
+     *   "P1Y2M3W4DT8H"    -- PeriodDuration.of(Period.of(1, 2, 25), Duration.ofHours(8))
+     *   "P-1Y2M"          -- PeriodDuration.of(Period.of(-1, 2, 0))
+     *   "-P1Y2M"          -- PeriodDuration.of(Period.of(-1, -2, 0))
+     * 
+ * + * @param text the text to parse, not null + * @return the parsed period, not null + * @throws DateTimeParseException if the text cannot be parsed to a period + */ + @FromString + public static PeriodDuration parse(CharSequence text) { + Objects.requireNonNull(text, "text"); + String upper = text.toString().toUpperCase(Locale.ENGLISH); + String negate = ""; + if (upper.startsWith("+")) { + upper = upper.substring(1); + } else if (upper.startsWith("-")) { + upper = upper.substring(1); + negate = "-"; + } + // duration only, parse original text so it does negation + if (upper.startsWith("PT")) { + return PeriodDuration.of(Duration.parse(text)); + } + // period only, parse original text so it does negation + int tpos = upper.indexOf('T'); + if (tpos < 0) { + return PeriodDuration.of(Period.parse(text)); + } + // period and duration + Period period = Period.parse(negate + upper.substring(0, tpos)); + Duration duration = Duration.parse(negate + "P" + upper.substring(tpos)); + return PeriodDuration.of(period, duration); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance consisting of the amount of time between two temporals. + *

+ * The start is included, but the end is not. + * The result of this method can be negative if the end is before the start. + *

+ * The calculation examines the temporals and extracts {@link LocalDate} and {@link LocalTime}. + * If the time is missing, it will be defaulted to midnight. + * If one date is missing, it will be defaulted to the other date. + * It then finds the amount of time between the two dates and between the two times. + * + * @param startInclusive the start, inclusive, not null + * @param endExclusive the end, exclusive, not null + * @return the number of days between this date and the end date, not null + */ + public static PeriodDuration between(Temporal startInclusive, Temporal endExclusive) { + LocalDate startDate = startInclusive.query(TemporalQueries.localDate()); + LocalDate endDate = endExclusive.query(TemporalQueries.localDate()); + Period period = Period.ZERO; + if (startDate != null && endDate != null) { + period = Period.between(startDate, endDate); + } + LocalTime startTime = startInclusive.query(TemporalQueries.localTime()); + LocalTime endTime = endExclusive.query(TemporalQueries.localTime()); + startTime = startTime != null ? startTime : LocalTime.MIDNIGHT; + endTime = endTime != null ? endTime : LocalTime.MIDNIGHT; + Duration duration = Duration.between(startTime, endTime); + return PeriodDuration.of(period, duration); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance. + * + * @param period the period + * @param duration the duration + */ + private PeriodDuration(Period period, Duration duration) { + this.period = period; + this.duration = duration; + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return PeriodDuration.of(period, duration); + } + + //----------------------------------------------------------------------- + /** + * Gets the value of the requested unit. + *

+ * This returns a value for the supported units - {@link ChronoUnit#YEARS}, + * {@link ChronoUnit#MONTHS}, {@link ChronoUnit#DAYS}, {@link ChronoUnit#SECONDS} + * and {@link ChronoUnit#NANOS}. + * All other units throw an exception. + * Note that hours and minutes throw an exception. + * + * @param unit the {@code TemporalUnit} for which to return the value + * @return the long value of the unit + * @throws UnsupportedTemporalTypeException if the unit is not supported + */ + @Override + public long get(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + switch ((ChronoUnit) unit) { + case YEARS: + return period.getYears(); + case MONTHS: + return period.getMonths(); + case DAYS: + return period.getDays(); + case SECONDS: + return duration.getSeconds(); + case NANOS: + return duration.getNano(); + default: + break; + } + } + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + + /** + * Gets the set of units supported by this amount. + *

+ * This returns the list {@link ChronoUnit#YEARS}, {@link ChronoUnit#MONTHS}, + * {@link ChronoUnit#DAYS}, {@link ChronoUnit#SECONDS} and {@link ChronoUnit#NANOS}. + *

+ * This set can be used in conjunction with {@link #get(TemporalUnit)} + * to access the entire state of the amount. + * + * @return a list containing the days unit, not null + */ + @Override + public List getUnits() { + return SUPPORTED_UNITS; + } + + //----------------------------------------------------------------------- + /** + * Gets the period part. + * + * @return the period part + */ + public Period getPeriod() { + return period; + } + + /** + * Returns a copy of this period-duration with a different period. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param period the new period + * @return the updated period-duration + */ + public PeriodDuration withPeriod(Period period) { + return PeriodDuration.of(period, duration); + } + + /** + * Gets the duration part. + * + * @return the duration part + */ + public Duration getDuration() { + return duration; + } + + /** + * Returns a copy of this period-duration with a different duration. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param duration the new duration + * @return the updated period-duration + */ + public PeriodDuration withDuration(Duration duration) { + return PeriodDuration.of(period, duration); + } + + //----------------------------------------------------------------------- + /** + * Checks if all parts of this amount are zero. + *

+ * This returns true if both {@link Period#isZero()} and {@link Duration#isZero()} + * return true. + * + * @return true if this period is zero-length + */ + public boolean isZero() { + return period.isZero() && duration.isZero(); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this amount with the specified amount added. + *

+ * The parameter is converted using {@link PeriodDuration#from(TemporalAmount)}. + * The period and duration are combined separately. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return a {@code Days} based on this instance with the requested amount added, not null + * @throws DateTimeException if the specified amount contains an invalid unit + * @throws ArithmeticException if numeric overflow occurs + */ + public PeriodDuration plus(TemporalAmount amountToAdd) { + PeriodDuration other = PeriodDuration.from(amountToAdd); + return of(period.plus(other.period), duration.plus(other.duration)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this amount with the specified amount subtracted. + *

+ * The parameter is converted using {@link PeriodDuration#from(TemporalAmount)}. + * The period and duration are combined separately. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return a {@code Days} based on this instance with the requested amount subtracted, not null + * @throws DateTimeException if the specified amount contains an invalid unit + * @throws ArithmeticException if numeric overflow occurs + */ + public PeriodDuration minus(TemporalAmount amountToAdd) { + PeriodDuration other = PeriodDuration.from(amountToAdd); + return of(period.minus(other.period), duration.minus(other.duration)); + } + + //----------------------------------------------------------------------- + /** + * Returns an instance with the amount multiplied by the specified scalar. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param scalar the scalar to multiply by, not null + * @return the amount multiplied by the specified scalar, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public PeriodDuration multipliedBy(int scalar) { + if (scalar == 1) { + return this; + } + return of(period.multipliedBy(scalar), duration.multipliedBy(scalar)); + } + + /** + * Returns an instance with the amount negated. + *

+ * This instance is immutable and unaffected by this method call. + * + * @return the negated amount, not null + * @throws ArithmeticException if numeric overflow occurs, which only happens if + * the amount is {@code Long.MIN_VALUE} + */ + public PeriodDuration negated() { + return multipliedBy(-1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this instance with the years and months exactly normalized. + *

+ * This normalizes the years and months units, leaving the days unit unchanged. + * The result is exact, always representing the same amount of time. + *

+ * The months unit is adjusted to have an absolute value less than 11, + * with the years unit being adjusted to compensate. For example, a period of + * "1 year and 15 months" will be normalized to "2 years and 3 months". + *

+ * The sign of the years and months units will be the same after normalization. + * For example, a period of "1 year and -25 months" will be normalized to + * "-1 year and -1 month". + *

+ * Note that no normalization is performed on the days or duration. + *

+ * This instance is immutable and unaffected by this method call. + * + * @return a {@code PeriodDuration} based on this one with excess months normalized to years, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public PeriodDuration normalizedYears() { + return withPeriod(period.normalized()); + } + + /** + * Returns a copy of this instance with the days and duration normalized using the standard day of 24 hours. + *

+ * This normalizes the days and duration, leaving the years and months unchanged. + * The result uses a standard day length of 24 hours. + *

+ * This combines the duration seconds with the number of days and shares the total + * seconds between the two fields. For example, a period of + * "2 days and 86401 seconds" will be normalized to "3 days and 1 second". + *

+ * The sign of the days and duration will be the same after normalization. + * For example, a period of "1 day and -172801 seconds" will be normalized to + * "-1 day and -1 second". + *

+ * Note that no normalization is performed on the years or months. + *

+ * This instance is immutable and unaffected by this method call. + * + * @return a {@code PeriodDuration} based on this one with excess duration normalized to days, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public PeriodDuration normalizedStandardDays() { + long totalSecs = period.getDays() * SECONDS_PER_DAY + duration.getSeconds(); + int splitDays = Math.toIntExact(totalSecs / SECONDS_PER_DAY); + long splitSecs = totalSecs % SECONDS_PER_DAY; + if (splitDays == period.getDays() && splitSecs == duration.getSeconds()) { + return this; + } + return PeriodDuration.of(period.withDays(splitDays), duration.withSeconds(splitSecs)); + } + + //----------------------------------------------------------------------- + /** + * Adds this amount to the specified temporal object. + *

+ * This returns a temporal object of the same observable type as the input + * with this amount added. This simply adds the period and duration to the temporal. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same type with the adjustment made, not null + * @throws DateTimeException if unable to add + * @throws UnsupportedTemporalTypeException if the DAYS unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal addTo(Temporal temporal) { + return temporal.plus(period).plus(duration); + } + + /** + * Subtracts this amount from the specified temporal object. + *

+ * This returns a temporal object of the same observable type as the input + * with this amount subtracted. This simply subtracts the period and duration from the temporal. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same type with the adjustment made, not null + * @throws DateTimeException if unable to subtract + * @throws UnsupportedTemporalTypeException if the DAYS unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal subtractFrom(Temporal temporal) { + return temporal.minus(period).minus(duration); + } + + //----------------------------------------------------------------------- + /** + * Checks if this amount is equal to the specified {@code PeriodDuration}. + *

+ * The comparison is based on the underlying period and duration. + * + * @param otherAmount the other amount, null returns false + * @return true if the other amount is equal to this one + */ + @Override + public boolean equals(Object otherAmount) { + if (this == otherAmount) { + return true; + } + if (otherAmount instanceof PeriodDuration) { + PeriodDuration other = (PeriodDuration) otherAmount; + return this.period.equals(other.period) && this.duration.equals(other.duration); + } + return false; + } + + /** + * A hash code for this amount. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return period.hashCode() ^ duration.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Returns a string representation of the amount. + * This will be in the format 'PnYnMnDTnHnMnS', with sections omitted as necessary. + * An empty amount will return "PT0S". + * + * @return the period in ISO-8601 string format + */ + @Override + @ToString + public String toString() { + if (period.isZero()) { + return duration.toString(); + } + if (duration.isZero()) { + return period.toString(); + } + return period.toString() + duration.toString().substring(1); + } + +} diff --git a/src/main/java/org/threeten/extra/Quarter.java b/src/main/java/org/threeten/extra/Quarter.java index 5f29118b..04265ce8 100644 --- a/src/main/java/org/threeten/extra/Quarter.java +++ b/src/main/java/org/threeten/extra/Quarter.java @@ -57,9 +57,8 @@ /** * A quarter-of-year, such as 'Q2'. *

- * {@code Quarter} is an enum representing the 4 quarters of the year - - * Q1, Q2, Q3 and Q4. These are defined as January to March, April to June, - * July to September and October to December. + * {@code Quarter} is an enum representing the 4 quarters of the year - Q1, Q2, Q3 and Q4. + * These are defined as January to March, April to June, July to September and October to December. *

* The {@code int} value follows the quarter, from 1 (Q1) to 4 (Q4). * It is recommended that applications use the enum rather than the {@code int} value @@ -170,10 +169,11 @@ public static Quarter from(TemporalAccessor temporal) { return of(month.ordinal() / 3 + 1); } try { - if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { - temporal = LocalDate.from(temporal); - } - return of(temporal.get(QUARTER_OF_YEAR)); + TemporalAccessor adjusted = + !IsoChronology.INSTANCE.equals(Chronology.from(temporal)) ? LocalDate.from(temporal) : temporal; + // need to use getLong() as JDK Parsed class get() doesn't work properly + int qoy = Math.toIntExact(adjusted.getLong(QUARTER_OF_YEAR)); + return of(qoy); } catch (DateTimeException ex) { throw new DateTimeException("Unable to obtain Quarter from TemporalAccessor: " + temporal + " of type " + temporal.getClass().getName(), ex); diff --git a/src/main/java/org/threeten/extra/Seconds.java b/src/main/java/org/threeten/extra/Seconds.java new file mode 100644 index 00000000..d3cb18a3 --- /dev/null +++ b/src/main/java/org/threeten/extra/Seconds.java @@ -0,0 +1,664 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoUnit.SECONDS; + +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; + +/** + * A second-based amount of time, such as '8 seconds'. + *

+ * This class models a quantity or amount of time in terms of seconds. + * It is a type-safe way of representing a number of seconds in an application. + * Note that {@link Duration} also models time in terms of seconds, but that + * class allows nanoseconds, which this class does not. + *

+ * The model is of a directed amount, meaning that the amount may be negative. + * + *

Implementation Requirements:

+ * This class is immutable and thread-safe. + *

+ * This class must be treated as a value type. Do not synchronize, rely on the + * identity hash code or use the distinction between equals() and ==. + */ +public final class Seconds + implements TemporalAmount, Comparable, Serializable { + + /** + * A constant for zero seconds. + */ + public static final Seconds ZERO = new Seconds(0); + + /** + * A serialization identifier for this class. + */ + private static final long serialVersionUID = 2602801843170589407L; + + /** + * The number of seconds per day. + */ + private static final int SECONDS_PER_DAY = 86400; + /** + * The number of seconds per hour. + */ + private static final int SECONDS_PER_HOUR = 3600; + /** + * The number of seconds per minute. + */ + private static final int SECONDS_PER_MINUTE = 60; + + /** + * The pattern for parsing. + */ + private static final Pattern PATTERN = + Pattern.compile("([-+]?)P" + + "(?:([-+]?[0-9]+)D)?" + + "(?:T" + + "(?:([-+]?[0-9]+)H)?" + + "(?:([-+]?[0-9]+)M)?" + + "(?:([-+]?[0-9]+)S)?)?", Pattern.CASE_INSENSITIVE); + + /** + * The number of seconds. + */ + private final int seconds; + + /** + * Obtains a {@code Seconds} representing a number of seconds. + *

+ * The resulting amount will have the specified seconds. + * + * @param seconds the number of seconds, positive or negative + * @return the number of seconds, not null + */ + public static Seconds of(int seconds) { + if (seconds == 0) { + return ZERO; + } + return new Seconds(seconds); + } + + /** + * Obtains a {@code Seconds} representing the number of seconds + * equivalent to a number of hours. + *

+ * The resulting amount will be second-based, with the number of seconds + * equal to the number of hours multiplied by 3600. + * + * @param hours the number of hours, positive or negative + * @return the amount with the input hours converted to seconds, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public static Seconds ofHours(int hours) { + if (hours == 0) { + return ZERO; + } + return new Seconds(Math.multiplyExact(hours, SECONDS_PER_HOUR)); + } + + /** + * Obtains a {@code Seconds} representing the number of seconds + * equivalent to a number of hours. + *

+ * The resulting amount will be second-based, with the number of seconds + * equal to the number of minutes multiplied by 60. + * + * @param minutes the number of minutes, positive or negative + * @return the amount with the input minutes converted to seconds, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public static Seconds ofMinutes(int minutes) { + if (minutes == 0) { + return ZERO; + } + return new Seconds(Math.multiplyExact(minutes, SECONDS_PER_MINUTE)); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Seconds} from a temporal amount. + *

+ * This obtains an instance based on the specified amount. + * A {@code TemporalAmount} represents an amount of time, which may be + * date-based or time-based, which this factory extracts to a {@code Seconds}. + *

+ * The result is calculated by looping around each unit in the specified amount. + * Each amount is converted to seconds using {@link Temporals#convertAmount}. + * If the conversion yields a remainder, an exception is thrown. + * If the amount is zero, the unit is ignored. + * + * @param amount the temporal amount to convert, not null + * @return the equivalent amount, not null + * @throws DateTimeException if unable to convert to a {@code Seconds} + * @throws ArithmeticException if numeric overflow occurs + */ + public static Seconds from(TemporalAmount amount) { + if (amount instanceof Seconds) { + return (Seconds) amount; + } + Objects.requireNonNull(amount, "amount"); + int seconds = 0; + for (TemporalUnit unit : amount.getUnits()) { + long value = amount.get(unit); + if (value != 0) { + long[] converted = Temporals.convertAmount(value, unit, SECONDS); + if (converted[1] != 0) { + throw new DateTimeException( + "Amount could not be converted to a whole number of seconds: " + value + " " + unit); + } + seconds = Math.addExact(seconds, Math.toIntExact(converted[0])); + } + } + return of(seconds); + } + + //----------------------------------------------------------------------- + /** + * Obtains a {@code Seconds} from a text string such as {@code PTnS}. + *

+ * This will parse the string produced by {@code toString()} and other + * related formats based on ISO-8601 {@code PnDTnHnMnS}. + *

+ * The string starts with an optional sign, denoted by the ASCII negative + * or positive symbol. If negative, the whole amount is negated. + * The ASCII letter "P" is next in upper or lower case. + * There are four sections consisting of a number and a suffix. + * There is one section for days suffixed by "D", + * followed by one section for hours suffixed by "H", + * followed by one section for minutes suffixed by "M", + * followed by one section for seconds suffixed by "S". + * At least one section must be present. + * If the hours, minutes or seconds section is present it must be prefixed by "T". + * If the hours, minutes or seconds section is omitted the "T" must be omitted. + * Letters must be in ASCII upper or lower case. + * The number part of each section must consist of ASCII digits. + * The number may be prefixed by the ASCII negative or positive symbol. + * The number must parse to an {@code int}. + *

+ * The leading plus/minus sign, and negative values for days, hours, minutes + * and seconds are not part of the ISO-8601 standard. + *

+ * For example, the following are valid inputs: + *

+     *   "PT2S"            -- Seconds.of(2)
+     *   "PT-2S"           -- Seconds.of(-2)
+     *   "-PT2S"           -- Seconds.of(-2)
+     *   "-PT-2S"          -- Seconds.of(2)
+     *   "PT3S"            -- Seconds.of(3 * 60)
+     *   "PT3H-2M7S"       -- Seconds.of(3 * 3600 - 2 * 60 + 7)
+     *   "P2D"             -- Seconds.of(2 * 86400)
+     *   "P2DT3H"          -- Seconds.of(2 * 86400 + 3 * 3600)
+     * 
+ * + * @param text the text to parse, not null + * @return the parsed period, not null + * @throws DateTimeParseException if the text cannot be parsed to a period + */ + @FromString + public static Seconds parse(CharSequence text) { + Objects.requireNonNull(text, "text"); + Matcher matcher = PATTERN.matcher(text); + if (matcher.matches()) { + int negate = "-".equals(matcher.group(1)) ? -1 : 1; + String daysStr = matcher.group(2); + String hoursStr = matcher.group(3); + String minutesStr = matcher.group(4); + String secondsStr = matcher.group(5); + if (daysStr != null || hoursStr != null || minutesStr != null || secondsStr != null) { + int seconds = 0; + if (secondsStr != null) { + try { + seconds = Integer.parseInt(secondsStr); + } catch (NumberFormatException ex) { + throw new DateTimeParseException("Text cannot be parsed to Seconds, non-numeric seconds", text, 0, ex); + } + } + if (minutesStr != null) { + try { + int minutesAsSecs = Math.multiplyExact(Integer.parseInt(minutesStr), SECONDS_PER_MINUTE); + seconds = Math.addExact(seconds, minutesAsSecs); + } catch (NumberFormatException ex) { + throw new DateTimeParseException("Text cannot be parsed to Seconds, non-numeric minutes", text, 0, ex); + } + } + if (hoursStr != null) { + try { + int hoursAsSecs = Math.multiplyExact(Integer.parseInt(hoursStr), SECONDS_PER_HOUR); + seconds = Math.addExact(seconds, hoursAsSecs); + } catch (NumberFormatException ex) { + throw new DateTimeParseException("Text cannot be parsed to Seconds, non-numeric hours", text, 0, ex); + } + } + if (daysStr != null) { + try { + int daysAsSecs = Math.multiplyExact(Integer.parseInt(daysStr), SECONDS_PER_DAY); + seconds = Math.addExact(seconds, daysAsSecs); + } catch (NumberFormatException ex) { + throw new DateTimeParseException("Text cannot be parsed to Seconds, non-numeric days", text, 0, ex); + } + } + return of(Math.multiplyExact(seconds, negate)); + } + } + throw new DateTimeParseException("Text cannot be parsed to Seconds", text, 0); + } + + //----------------------------------------------------------------------- + /** + * Obtains a {@code Seconds} consisting of the number of seconds between two temporals. + *

+ * The start temporal is included, but the end temporal is not. + * The result of this method can be negative if the end is before the start. + * + * @param startInclusive the start temporal, inclusive, not null + * @param endExclusive the end temporal, exclusive, not null + * @return the number of seconds between the start and end temporals, not null + */ + public static Seconds between(Temporal startInclusive, Temporal endExclusive) { + return of(Math.toIntExact(SECONDS.between(startInclusive, endExclusive))); + } + + //----------------------------------------------------------------------- + /** + * Constructs an instance using a specific number of seconds. + * + * @param seconds the amount of seconds + */ + private Seconds(int seconds) { + this.seconds = seconds; + } + + /** + * Resolves singletons. + * + * @return the singleton instance + */ + private Object readResolve() { + return Seconds.of(seconds); + } + + //----------------------------------------------------------------------- + /** + * Gets the value of the requested unit. + *

+ * This returns a value for the supported unit - {@link ChronoUnit#SECONDS SECONDS}. + * All other units throw an exception. + * + * @param unit the {@code TemporalUnit} for which to return the value + * @return the long value of the unit + * @throws UnsupportedTemporalTypeException if the unit is not supported + */ + @Override + public long get(TemporalUnit unit) { + if (unit == SECONDS) { + return seconds; + } + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + + /** + * Gets the set of units supported by this amount. + *

+ * The single supported unit is {@link ChronoUnit#SECONDS SECONDS}. + *

+ * This set can be used in conjunction with {@link #get(TemporalUnit)} to + * access the entire state of the amount. + * + * @return a list containing the seconds unit, not null + */ + @Override + public List getUnits() { + return Collections.singletonList(SECONDS); + } + + //----------------------------------------------------------------------- + /** + * Gets the number of seconds in this amount. + * + * @return the number of seconds + */ + public int getAmount() { + return seconds; + } + + /** + * Checks if the amount is negative. + * + * @return true if the amount is negative, false if the amount is zero or positive + */ + public boolean isNegative() { + return getAmount() < 0; + } + + /** + * Checks if the amount is zero. + * + * @return true if the amount is zero, false if not + */ + public boolean isZero() { + return getAmount() == 0; + } + + /** + * Checks if the amount is positive. + * + * @return true if the amount is positive, false if the amount is zero or negative + */ + public boolean isPositive() { + return getAmount() > 0; + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this amount with the specified amount added. + *

+ * The parameter is converted using {@link Seconds#from(TemporalAmount)}. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return a {@code Seconds} based on this instance with the requested amount added, not null + * @throws DateTimeException if the specified amount contains an invalid unit + * @throws ArithmeticException if numeric overflow occurs + */ + public Seconds plus(TemporalAmount amountToAdd) { + return plus(Seconds.from(amountToAdd).getAmount()); + } + + /** + * Returns a copy of this amount with the specified number of seconds added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to add, may be negative + * @return a {@code Seconds} based on this instance with the requested amount added, not null + * @throws ArithmeticException if the result overflows an int + */ + public Seconds plus(int seconds) { + if (seconds == 0) { + return this; + } + return of(Math.addExact(this.seconds, seconds)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this amount with the specified amount subtracted. + *

+ * The parameter is converted using {@link Seconds#from(TemporalAmount)}. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount to subtract, not null + * @return a {@code Seconds} based on this instance with the requested amount subtracted, not null + * @throws DateTimeException if the specified amount contains an invalid unit + * @throws ArithmeticException if numeric overflow occurs + */ + public Seconds minus(TemporalAmount amountToSubtract) { + return minus(Seconds.from(amountToSubtract).getAmount()); + } + + /** + * Returns a copy of this amount with the specified number of seconds subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to add, may be negative + * @return a {@code Seconds} based on this instance with the requested amount subtracted, not null + * @throws ArithmeticException if the result overflows an int + */ + public Seconds minus(int seconds) { + if (seconds == 0) { + return this; + } + return of(Math.subtractExact(this.seconds, seconds)); + } + + //----------------------------------------------------------------------- + /** + * Returns an instance with the amount multiplied by the specified scalar. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param scalar the scalar to multiply by, not null + * @return the amount multiplied by the specified scalar, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Seconds multipliedBy(int scalar) { + if (scalar == 1) { + return this; + } + return of(Math.multiplyExact(seconds, scalar)); + } + + /** + * Returns an instance with the amount divided by the specified divisor. + *

+ * The calculation uses integer division, thus 3 divided by 2 is 1. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param divisor the amount to divide by, may be negative + * @return the amount divided by the specified divisor, not null + * @throws ArithmeticException if the divisor is zero + */ + public Seconds dividedBy(int divisor) { + if (divisor == 1) { + return this; + } + return of(seconds / divisor); + } + + /** + * Returns an instance with the amount negated. + *

+ * This instance is immutable and unaffected by this method call. + * + * @return the negated amount, not null + * @throws ArithmeticException if numeric overflow occurs, which only happens if + * the amount is {@code Long.MIN_VALUE} + */ + public Seconds negated() { + return multipliedBy(-1); + } + + /** + * Returns a copy of this duration with a positive length. + *

+ * This method returns a positive duration by effectively removing the sign from any negative total length. + *

+ * This instance is immutable and unaffected by this method call. + * + * @return the absolute amount, not null + * @throws ArithmeticException if numeric overflow occurs, which only happens if + * the amount is {@code Long.MIN_VALUE} + */ + public Seconds abs() { + return seconds < 0 ? negated() : this; + } + + //------------------------------------------------------------------------- + /** + * Gets the number of seconds as a {@code Duration}. + *

+ * This returns a duration with the same number of seconds. + * + * @return the equivalent duration, not null + */ + public Duration toDuration() { + return Duration.ofSeconds(seconds); + } + + //----------------------------------------------------------------------- + /** + * Adds this amount to the specified temporal object. + *

+ * This returns a temporal object of the same observable type as the input + * with this amount added. + *

+ * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#plus(TemporalAmount)}. + *

+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisAmount.addTo(dateTime);
+     *   dateTime = dateTime.plus(thisAmount);
+     * 
+ *

+ * Only non-zero amounts will be added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same type with the adjustment made, not null + * @throws DateTimeException if unable to add + * @throws UnsupportedTemporalTypeException if the SECONDS unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal addTo(Temporal temporal) { + if (seconds != 0) { + temporal = temporal.plus(seconds, SECONDS); + } + return temporal; + } + + /** + * Subtracts this amount from the specified temporal object. + *

+ * This returns a temporal object of the same observable type as the input + * with this amount subtracted. + *

+ * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#minus(TemporalAmount)}. + *

+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisAmount.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(thisAmount);
+     * 
+ *

+ * Only non-zero amounts will be subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same type with the adjustment made, not null + * @throws DateTimeException if unable to subtract + * @throws UnsupportedTemporalTypeException if the SECONDS unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal subtractFrom(Temporal temporal) { + if (seconds != 0) { + temporal = temporal.minus(seconds, SECONDS); + } + return temporal; + } + + //----------------------------------------------------------------------- + /** + * Compares this amount to the specified {@code Seconds}. + *

+ * The comparison is based on the total length of the amounts. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param otherAmount the other amount, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(Seconds otherAmount) { + int thisValue = this.seconds; + int otherValue = otherAmount.seconds; + return Integer.compare(thisValue, otherValue); + } + + //----------------------------------------------------------------------- + /** + * Checks if this amount is equal to the specified {@code Seconds}. + *

+ * The comparison is based on the total length of the durations. + * + * @param otherAmount the other amount, null returns false + * @return true if the other amount is equal to this one + */ + @Override + public boolean equals(Object otherAmount) { + if (this == otherAmount) { + return true; + } + if (otherAmount instanceof Seconds) { + Seconds other = (Seconds) otherAmount; + return this.seconds == other.seconds; + } + return false; + } + + /** + * A hash code for this amount. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return seconds; + } + + //----------------------------------------------------------------------- + /** + * Returns a string representation of the number of seconds. + * This will be in the format 'PTnS' where n is the number of seconds. + * + * @return the number of seconds in ISO-8601 string format + */ + @Override + @ToString + public String toString() { + return "PT" + seconds + "S"; + } + +} diff --git a/src/main/java/org/threeten/extra/TemporalFields.java b/src/main/java/org/threeten/extra/TemporalFields.java new file mode 100644 index 00000000..d2d207ef --- /dev/null +++ b/src/main/java/org/threeten/extra/TemporalFields.java @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.YEARS; +import static java.time.temporal.IsoFields.QUARTER_OF_YEAR; +import static java.time.temporal.IsoFields.QUARTER_YEARS; + +import java.time.DateTimeException; +import java.time.Duration; +import java.time.LocalDate; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.IsoChronology; +import java.time.format.ResolverStyle; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; +import java.util.Map; + +/** + * Additional Temporal fields. + *

+ * This provides additional fields and units not in the JDK. + */ +public final class TemporalFields { + + /** + * The field that represents the day-of-half. + *

+ * This field allows the day-of-half value to be queried and set. + * The day-of-half has values from 1 to 181 in H1 of a standard year, from 1 to 182 + * in H1 of a leap year and from 1 to 184 in H2. + *

+ * The day-of-half can only be calculated if the day-of-year, month-of-year and year + * are available. + *

+ * When setting this field, the value is allowed to be partially lenient, taking any + * value from 1 to 184. If the half has less than 184 days, then the day will end up + * in the following half-year. + *

+ * In the resolving phase of parsing, a date can be created from a year, + * half-of-year and day-of-half. + *

+ * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are + * validated against their range of valid values. The day-of-half field + * is validated from 1 to 181, 182 or 184 depending on the year and half. + *

+ * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are + * validated against their range of valid values. The day-of-half field is + * validated between 1 and 184, ignoring the actual range based on the year and half. + * If the day-of-half exceeds the actual range, then the resulting date is in the next half-year. + *

+ * In {@linkplain ResolverStyle#LENIENT lenient mode}, only the year is validated + * against the range of valid values. The resulting date is calculated equivalent to + * the following three stage approach. First, create a date on the first of January + * in the requested year. Then take the half-of-year, subtract one, and add the + * amount in halves to the date. Finally, take the day-of-half, subtract one, + * and add the amount in days to the date. + *

+ * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalField DAY_OF_HALF = DayOfHalfField.INSTANCE; + /** + * The field that represents the half-of-year. + *

+ * This field allows the half-of-year value to be queried and set. + * The half-of-year has values from 1 to 2. + *

+ * The half-of-year can only be calculated if the month-of-year is available. + *

+ * In the resolving phase of parsing, a date can be created from a year, + * half-of-year and day-of-half. + * See {@link #DAY_OF_HALF} for details. + *

+ * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalField HALF_OF_YEAR = HalfOfYearField.INSTANCE; + /** + * Unit that represents the concept of a half-year. + * For the ISO calendar system, it is equal to 6 months. + * The estimated duration of a half-year is one half of {@code 365.2425 Days}. + *

+ * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalUnit HALF_YEARS = HalfUnit.INSTANCE; + + /** + * Restricted constructor. + */ + private TemporalFields() { + } + + //------------------------------------------------------------------------- + /** + * Implementation of day-of-half. + */ + private static enum DayOfHalfField implements TemporalField { + INSTANCE; + + private static final ValueRange RANGE = ValueRange.of(1, 181, 184); + private static final long serialVersionUID = 262362728L; + + //----------------------------------------------------------------------- + @Override + public TemporalUnit getBaseUnit() { + return DAYS; + } + + @Override + public TemporalUnit getRangeUnit() { + return HALF_YEARS; + } + + @Override + public boolean isDateBased() { + return true; + } + + @Override + public boolean isTimeBased() { + return false; + } + + @Override + public ValueRange range() { + return RANGE; + } + + //----------------------------------------------------------------------- + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + return temporal.isSupported(DAY_OF_YEAR) && + temporal.isSupported(MONTH_OF_YEAR) && + temporal.isSupported(YEAR); + } + + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + if (!temporal.isSupported(this)) { + throw new DateTimeException("Unsupported field: DayOfHalf"); + } + long hoy = temporal.getLong(HALF_OF_YEAR); + if (hoy == 1) { + long year = temporal.getLong(YEAR); + return (IsoChronology.INSTANCE.isLeapYear(year) ? ValueRange.of(1, 182) : ValueRange.of(1, 181)); + } else if (hoy == 2) { + return ValueRange.of(1, 184); + } // else value not from 1 to 2, so drop through + return range(); + } + + @Override + public long getFrom(TemporalAccessor temporal) { + if (isSupportedBy(temporal) == false) { + throw new UnsupportedTemporalTypeException("Unsupported field: DayOfHalf"); + } + int doy = temporal.get(DAY_OF_YEAR); + int moy = temporal.get(MONTH_OF_YEAR); + long year = temporal.getLong(YEAR); + return moy <= 6 ? doy : doy - 181 - (IsoChronology.INSTANCE.isLeapYear(year) ? 1 : 0); + } + + @SuppressWarnings("unchecked") + @Override + public R adjustInto(R temporal, long newValue) { + // calls getFrom() to check if supported + long curValue = getFrom(temporal); + range().checkValidValue(newValue, this); // leniently check from 1 to 184 + return (R) temporal.with(DAY_OF_YEAR, temporal.getLong(DAY_OF_YEAR) + (newValue - curValue)); + } + + //----------------------------------------------------------------------- + @Override + public ChronoLocalDate resolve( + Map fieldValues, + TemporalAccessor partialTemporal, + ResolverStyle resolverStyle) { + + Long yearLong = fieldValues.get(YEAR); + Long hoyLong = fieldValues.get(HALF_OF_YEAR); + if (yearLong == null || hoyLong == null) { + return null; + } + int y = YEAR.checkValidIntValue(yearLong); // always validate + long doh = fieldValues.get(DAY_OF_HALF); + LocalDate date; + if (resolverStyle == ResolverStyle.LENIENT) { + date = LocalDate.of(y, 1, 1).plusMonths(Math.multiplyExact(Math.subtractExact(hoyLong, 1), 6)); + doh = Math.subtractExact(doh, 1); + } else { + int qoy = HALF_OF_YEAR.range().checkValidIntValue(hoyLong, HALF_OF_YEAR); // validated + date = LocalDate.of(y, ((qoy - 1) * 6) + 1, 1); + if (doh < 1 || doh > 181) { + if (resolverStyle == ResolverStyle.STRICT) { + rangeRefinedBy(date).checkValidValue(doh, this); // only allow exact range + } else { // SMART + range().checkValidValue(doh, this); // allow 1-184 rolling into next quarter + } + } + doh--; + } + fieldValues.remove(this); + fieldValues.remove(YEAR); + fieldValues.remove(HALF_OF_YEAR); + return date.plusDays(doh); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + return "DayOfHalf"; + } + } + + //------------------------------------------------------------------------- + /** + * Implementation of half-of-year. + */ + private static enum HalfOfYearField implements TemporalField { + INSTANCE; + + private static final long serialVersionUID = -29115701L; + + //----------------------------------------------------------------------- + @Override + public TemporalUnit getBaseUnit() { + return HALF_YEARS; + } + + @Override + public TemporalUnit getRangeUnit() { + return YEARS; + } + + @Override + public boolean isDateBased() { + return true; + } + + @Override + public boolean isTimeBased() { + return false; + } + + @Override + public ValueRange range() { + return ValueRange.of(1, 2); + } + + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + return temporal.isSupported(QUARTER_OF_YEAR); + } + + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + return range(); + } + + @Override + public long getFrom(TemporalAccessor temporal) { + if (isSupportedBy(temporal) == false) { + throw new UnsupportedTemporalTypeException("Unsupported field: HalfOfYear"); + } + long qoy = temporal.get(QUARTER_OF_YEAR); + return qoy <= 2 ? 1 : 2; + } + + @SuppressWarnings("unchecked") + @Override + public R adjustInto(R temporal, long newValue) { + // calls getFrom() to check if supported + long curValue = getFrom(temporal); + range().checkValidValue(newValue, this); // strictly check from 1 to 2 + return (R) temporal.with(MONTH_OF_YEAR, temporal.getLong(MONTH_OF_YEAR) + (newValue - curValue) * 6); + } + + @Override + public String toString() { + return "HalfOfYear"; + } + } + + //----------------------------------------------------------------------- + /** + * Implementation of the half-year unit. + */ + private static enum HalfUnit implements TemporalUnit { + + /** + * Unit that represents the concept of a week-based-year. + */ + INSTANCE; + + @Override + public Duration getDuration() { + return Duration.ofSeconds(31556952L / 2); + } + + @Override + public boolean isDurationEstimated() { + return true; + } + + @Override + public boolean isDateBased() { + return true; + } + + @Override + public boolean isTimeBased() { + return false; + } + + @Override + public boolean isSupportedBy(Temporal temporal) { + return temporal.isSupported(QUARTER_OF_YEAR); + } + + @SuppressWarnings("unchecked") + @Override + public R addTo(R temporal, long amount) { + return (R) temporal.plus(Math.multiplyExact(amount, 2), QUARTER_YEARS); + } + + @Override + public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) { + if (temporal1Inclusive.getClass() != temporal2Exclusive.getClass()) { + return temporal1Inclusive.until(temporal2Exclusive, this); + } + return temporal1Inclusive.until(temporal2Exclusive, QUARTER_YEARS) / 2; + } + + @Override + public String toString() { + return "HalfYears"; + } + } + +} diff --git a/src/main/java/org/threeten/extra/Temporals.java b/src/main/java/org/threeten/extra/Temporals.java index 797ea8c2..0b856bc5 100644 --- a/src/main/java/org/threeten/extra/Temporals.java +++ b/src/main/java/org/threeten/extra/Temporals.java @@ -37,8 +37,12 @@ import static java.time.temporal.ChronoUnit.FOREVER; import static java.time.temporal.ChronoUnit.WEEKS; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; import java.text.ParsePosition; import java.time.DateTimeException; +import java.time.Duration; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; @@ -87,6 +91,19 @@ public static TemporalAdjuster nextWorkingDay() { return Adjuster.NEXT_WORKING; } + /** + * Returns an adjuster that returns the next working day or same day if already working day, ignoring Saturday and Sunday. + *

+ * Some territories have weekends that do not consist of Saturday and Sunday. + * No implementation is supplied to support this, however an adjuster + * can be easily written to do so. + * + * @return the next working day or same adjuster, not null + */ + public static TemporalAdjuster nextWorkingDayOrSame() { + return Adjuster.NEXT_WORKING_OR_SAME; + } + /** * Returns an adjuster that returns the previous working day, ignoring Saturday and Sunday. *

@@ -100,6 +117,19 @@ public static TemporalAdjuster previousWorkingDay() { return Adjuster.PREVIOUS_WORKING; } + /** + * Returns an adjuster that returns the previous working day or same day if already working day, ignoring Saturday and Sunday. + *

+ * Some territories have weekends that do not consist of Saturday and Sunday. + * No implementation is supplied to support this, however an adjuster + * can be easily written to do so. + * + * @return the previous working day or same adjuster, not null + */ + public static TemporalAdjuster previousWorkingDayOrSame() { + return Adjuster.PREVIOUS_WORKING_OR_SAME; + } + //----------------------------------------------------------------------- /** * Enum implementing the adjusters. @@ -135,6 +165,36 @@ public Temporal adjustInto(Temporal temporal) { } } }, + /** Next working day or same adjuster. */ + NEXT_WORKING_OR_SAME { + @Override + public Temporal adjustInto(Temporal temporal) { + int dow = temporal.get(DAY_OF_WEEK); + switch (dow) { + case 6: // Saturday + return temporal.plus(2, DAYS); + case 7: // Sunday + return temporal.plus(1, DAYS); + default: + return temporal; + } + } + }, + /** Previous working day or same adjuster. */ + PREVIOUS_WORKING_OR_SAME { + @Override + public Temporal adjustInto(Temporal temporal) { + int dow = temporal.get(DAY_OF_WEEK); + switch (dow) { + case 6: //Saturday + return temporal.minus(1, DAYS); + case 7: // Sunday + return temporal.minus(2, DAYS); + default: + return temporal; + } + } + } } //------------------------------------------------------------------------- @@ -330,4 +390,91 @@ private static int monthMonthFactor(TemporalUnit unit, TemporalUnit fromUnit, Te return 3; // quarters } + //------------------------------------------------------------------------- + /** + * Converts a duration to a {@code BigDecimal} with a scale of 9. + * + * @param duration the duration to convert, not null + * @return the {@code BigDecimal} equivalent of the duration, in seconds with a scale of 9 + */ + public static BigDecimal durationToBigDecimalSeconds(Duration duration) { + return BigDecimal.valueOf(duration.getSeconds()).add(BigDecimal.valueOf(duration.getNano(), 9)); + } + + /** + * Converts a {@code BigDecimal} representing seconds to a duration, saturating if necessary. + *

+ * No exception is thrown by this method. + * Numbers are rounded up to the nearest nanosecond (away from zero). + * The duration will saturate at the biggest positive or negative {@code Duration}. + * + * @param seconds the number of seconds to convert, positive or negative + * @return a {@code Duration}, not null + */ + public static Duration durationFromBigDecimalSeconds(BigDecimal seconds) { + BigInteger nanos = seconds.setScale(9, RoundingMode.UP).max(BigDecimalSeconds.MIN).min(BigDecimalSeconds.MAX).unscaledValue(); + BigInteger[] secondsNanos = nanos.divideAndRemainder(BigInteger.valueOf(1_000_000_000)); + return Duration.ofSeconds(secondsNanos[0].longValue(), secondsNanos[1].intValue()); + } + + /** + * Converts a duration to a {@code double}. + * + * @param duration the duration to convert, not null + * @return the {@code double} equivalent of the duration, in seconds + */ + public static double durationToDoubleSeconds(Duration duration) { + if (duration.getSeconds() < 1_000_000_000) { + return duration.toNanos() / 1_000_000_000d; + } + return durationToBigDecimalSeconds(duration).doubleValue(); + } + + /** + * Converts a {@code double} representing seconds to a duration, saturating if necessary. + *

+ * No exception is thrown by this method. + * Numbers are rounded up to the nearest nanosecond (away from zero). + * The duration will saturate at the biggest positive or negative {@code Duration}. + * + * @param seconds the number of seconds to convert, positive or negative + * @return a {@code Duration}, not null + */ + public static Duration durationFromDoubleSeconds(double seconds) { + return durationFromBigDecimalSeconds(BigDecimal.valueOf(seconds)); + } + + /** + * Multiplies a duration by a {@code double}. + *

+ * The amount is rounded away from zero, thus the result is only zero if zero is passed in. + * See {@link #durationToBigDecimalSeconds(Duration)} and {@link #durationFromBigDecimalSeconds(BigDecimal)}. + * Note that due to the rounding up, 1 nanosecond multiplied by any number smaller than 1 will still be 1 nanosecond. + * + * @param duration the duration to multiply, not null + * @param multiplicand the multiplication factor + * @return the multiplied duration, not null + */ + public static Duration multiply(Duration duration, double multiplicand) { + if (multiplicand == 0d || duration.isZero()) { + return Duration.ZERO; + } + if (multiplicand == 1d) { + return duration; + } + BigDecimal amount = durationToBigDecimalSeconds(duration); + amount = amount.multiply(BigDecimal.valueOf(multiplicand)); + return durationFromBigDecimalSeconds(amount); + } + + /** + * Useful Duration constants expressed as BigDecimal seconds with a scale of 9. + */ + private static final class BigDecimalSeconds { + public static final BigDecimal MIN = BigDecimal.valueOf(Long.MIN_VALUE).add(BigDecimal.valueOf(0, 9)); + public static final BigDecimal MAX = BigDecimal.valueOf(Long.MAX_VALUE).add(BigDecimal.valueOf(999_999_999, 9)); + + private BigDecimalSeconds() { + } + } } diff --git a/src/main/java/org/threeten/extra/Weeks.java b/src/main/java/org/threeten/extra/Weeks.java index 261a93c7..659abadf 100644 --- a/src/main/java/org/threeten/extra/Weeks.java +++ b/src/main/java/org/threeten/extra/Weeks.java @@ -48,6 +48,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * A week-based amount of time, such as '12 weeks'. *

@@ -173,11 +176,12 @@ public static Weeks from(TemporalAmount amount) { * @return the parsed period, not null * @throws DateTimeParseException if the text cannot be parsed to a period */ + @FromString public static Weeks parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { - int negate = ("-".equals(matcher.group(1)) ? -1 : 1); + int negate = "-".equals(matcher.group(1)) ? -1 : 1; String str = matcher.group(2); try { int val = Integer.parseInt(str); @@ -237,7 +241,7 @@ private Object readResolve() { */ @Override public long get(TemporalUnit unit) { - if (unit == ChronoUnit.WEEKS) { + if (unit == WEEKS) { return weeks; } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); @@ -268,6 +272,33 @@ public int getAmount() { return weeks; } + /** + * Checks if the amount is negative. + * + * @return true if the amount is negative, false if the amount is zero or positive + */ + public boolean isNegative() { + return getAmount() < 0; + } + + /** + * Checks if the amount is zero. + * + * @return true if the amount is zero, false if not + */ + public boolean isZero() { + return getAmount() == 0; + } + + /** + * Checks if the amount is positive. + * + * @return true if the amount is positive, false if the amount is zero or negative + */ + public boolean isPositive() { + return getAmount() > 0; + } + //----------------------------------------------------------------------- /** * Returns a copy of this amount with the specified amount added. @@ -309,13 +340,13 @@ public Weeks plus(int weeks) { *

* This instance is immutable and unaffected by this method call. * - * @param amountToAdd the amount to add, not null + * @param amountToSubtract the amount to subtract, not null * @return a {@code Weeks} based on this instance with the requested amount subtracted, not null * @throws DateTimeException if the specified amount contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ - public Weeks minus(TemporalAmount amountToAdd) { - return minus(Weeks.from(amountToAdd).getAmount()); + public Weeks minus(TemporalAmount amountToSubtract) { + return minus(Weeks.from(amountToSubtract).getAmount()); } /** @@ -530,6 +561,7 @@ public int hashCode() { * @return the number of weeks in ISO-8601 string format */ @Override + @ToString public String toString() { return "P" + weeks + "W"; } diff --git a/src/main/java/org/threeten/extra/YearHalf.java b/src/main/java/org/threeten/extra/YearHalf.java new file mode 100644 index 00000000..49436413 --- /dev/null +++ b/src/main/java/org/threeten/extra/YearHalf.java @@ -0,0 +1,1288 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.MILLENNIA; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.threeten.extra.TemporalFields.DAY_OF_HALF; +import static org.threeten.extra.TemporalFields.HALF_OF_YEAR; +import static org.threeten.extra.TemporalFields.HALF_YEARS; + +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.Month; +import java.time.Period; +import java.time.Year; +import java.time.ZoneId; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.format.SignStyle; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; +import java.util.Objects; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; + +/** + * A year-half in the ISO-8601 calendar system, such as {@code 2007-H2}. + *

+ * {@code YearHalf} is an immutable date-time object that represents the combination + * of a year and a half-year. Any field that can be derived from a year and a half-year can be obtained. + * A half is defined by {@link Half} - H1 and H2. + * H1 is January to June, H2 is July to December. + *

+ * This class does not store or represent a day, time or time-zone. + * For example, the value "2nd half 2007" can be stored in a {@code YearHalf}. + *

+ * The ISO-8601 calendar system is the modern civil calendar system used today + * in most of the world. It is equivalent to the proleptic Gregorian calendar + * system, in which today's rules for leap years are applied for all time. + * For most applications written today, the ISO-8601 rules are entirely suitable. + * However, any application that makes use of historical dates, and requires them + * to be accurate will find the ISO-8601 approach unsuitable. + * Note that the ISO-8601 standard does not define or refer to halves. + * + *

Implementation Requirements:

+ * This class is immutable and thread-safe. + *

+ * This class must be treated as a value type. Do not synchronize, rely on the + * identity hash code or use the distinction between equals() and ==. + */ +public final class YearHalf + implements Temporal, TemporalAdjuster, Comparable, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = 782467825761518L; + /** + * Parser. + */ + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .appendLiteral('-') + .appendLiteral('H') + .appendValue(HALF_OF_YEAR, 1) + .toFormatter(); + + /** + * The year. + */ + private final int year; + /** + * The half-of-year, not null. + */ + private final Half half; + + //----------------------------------------------------------------------- + /** + * Obtains the current year-half from the system clock in the default time-zone. + *

+ * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current year-half. + * The zone and offset will be set based on the time-zone in the clock. + *

+ * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current year-half using the system clock and default time-zone, not null + */ + public static YearHalf now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current year-half from the system clock in the specified time-zone. + *

+ * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current year-half. + * Specifying the time-zone avoids dependence on the default time-zone. + *

+ * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current year-half using the system clock, not null + */ + public static YearHalf now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current year-half from the specified clock. + *

+ * This will query the specified clock to obtain the current year-half. + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current year-half, not null + */ + public static YearHalf now(Clock clock) { + final LocalDate now = LocalDate.now(clock); // called once + return YearHalf.of(now.getYear(), Half.from(now.getMonth())); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code YearHalf} from a year and half. + * + * @param year the year to represent, not null + * @param half the half-of-year to represent, not null + * @return the year-half, not null + */ + public static YearHalf of(Year year, Half half) { + return of(year.getValue(), half); + } + + /** + * Obtains an instance of {@code YearHalf} from a year and half. + * + * @param year the year to represent, not null + * @param half the half-of-year to represent, from 1 to 2 + * @return the year-half, not null + * @throws DateTimeException if the half value is invalid + */ + public static YearHalf of(Year year, int half) { + return of(year.getValue(), Half.of(half)); + } + + /** + * Obtains an instance of {@code YearHalf} from a year and half. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param half the half-of-year to represent, not null + * @return the year-half, not null + * @throws DateTimeException if the year value is invalid + */ + public static YearHalf of(int year, Half half) { + YEAR.checkValidValue(year); + Objects.requireNonNull(half, "half"); + return new YearHalf(year, half); + } + + /** + * Obtains an instance of {@code YearHalf} from a year and half. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param half the half-of-year to represent, from 1 to 2 + * @return the year-half, not null + * @throws DateTimeException if either field value is invalid + */ + public static YearHalf of(int year, int half) { + YEAR.checkValidValue(year); + return new YearHalf(year, Half.of(half)); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code YearHalf} from a temporal object. + *

+ * This obtains a year-half based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code YearHalf}. + *

+ * The conversion extracts the {@link ChronoField#YEAR YEAR} and + * {@link TemporalFields#HALF_OF_YEAR HALF_OF_YEAR} fields. + * The extraction is only permitted if the temporal object has an ISO + * chronology, or can be converted to a {@code LocalDate}. + *

+ * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code YearHalf::from}. + * + * @param temporal the temporal object to convert, not null + * @return the year-half, not null + * @throws DateTimeException if unable to convert to a {@code YearHalf} + */ + public static YearHalf from(TemporalAccessor temporal) { + if (temporal instanceof YearHalf) { + return (YearHalf) temporal; + } + Objects.requireNonNull(temporal, "temporal"); + try { + TemporalAccessor adjusted = + !IsoChronology.INSTANCE.equals(Chronology.from(temporal)) ? LocalDate.from(temporal) : temporal; + // need to use getLong() as JDK Parsed class get() doesn't work properly + int year = Math.toIntExact(adjusted.getLong(YEAR)); + int hoy = Math.toIntExact(adjusted.getLong(HALF_OF_YEAR)); + return of(year, hoy); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain YearHalf from TemporalAccessor: " + + temporal + " of type " + temporal.getClass().getName(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code YearHalf} from a text string such as {@code 2007-H2}. + *

+ * The string must represent a valid year-half. + * The format must be {@code uuuu-'Q'Q} where the 'Q' is case insensitive. + * Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol. + * + * @param text the text to parse such as "2007-H2", not null + * @return the parsed year-half, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + @FromString + public static YearHalf parse(CharSequence text) { + return parse(text, PARSER); + } + + /** + * Obtains an instance of {@code YearHalf} from a text string using a specific formatter. + *

+ * The text is parsed using the formatter, returning a year-half. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed year-half, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static YearHalf parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, YearHalf::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param year the year to represent, validated from MIN_YEAR to MAX_YEAR + * @param half the half-of-year to represent, validated not null + */ + private YearHalf(int year, Half half) { + this.year = year; + this.half = half; + } + + /** + * Validates the input. + * + * @return the valid object, not null + */ + private Object readResolve() { + return of(year, half); + } + + /** + * Returns a copy of this year-half with the new year and half, checking + * to see if a new object is in fact required. + * + * @param newYear the year to represent, validated from MIN_YEAR to MAX_YEAR + * @param newHalf the half-of-year to represent, validated not null + * @return the year-half, not null + */ + private YearHalf with(int newYear, Half newHalf) { + if (year == newYear && half == newHalf) { + return this; + } + return new YearHalf(newYear, newHalf); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

+ * This checks if this year-half can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + *

    + *
  • {@code HALF_OF_YEAR} + *
  • {@code YEAR_OF_ERA} + *
  • {@code YEAR} + *
  • {@code ERA} + *
+ * All other {@code ChronoField} instances will return false. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this year-half, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field == HALF_OF_YEAR) { + return true; + } else if (field instanceof ChronoField) { + return field == YEAR || field == YEAR_OF_ERA || field == ERA; + } + return field != null && field.isSupportedBy(this); + } + + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this year-half. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

    + *
  • {@code HALF_YEARS} + *
  • {@code YEARS} + *
  • {@code DECADES} + *
  • {@code CENTURIES} + *
  • {@code MILLENNIA} + *
  • {@code ERAS} + *
+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit == HALF_YEARS) { + return true; + } else if (unit instanceof ChronoUnit) { + return unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the range of valid values for the specified field. + *

+ * The range object expresses the minimum and maximum valid values for a field. + * This year-half is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + * @throws UnsupportedTemporalTypeException if the field is not supported + */ + @Override + public ValueRange range(TemporalField field) { + if (field == HALF_OF_YEAR) { + return HALF_OF_YEAR.range(); + } + if (field == YEAR_OF_ERA) { + return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE)); + } + return Temporal.super.range(field); + } + + /** + * Gets the value of the specified field from this year-half as an {@code int}. + *

+ * This queries this year-half for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this year-half,. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained or + * the value is outside the range of valid values for the field + * @throws UnsupportedTemporalTypeException if the field is not supported or + * the range of values exceeds an {@code int} + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public int get(TemporalField field) { + if (field == HALF_OF_YEAR) { + return half.getValue(); + } else if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case YEAR_OF_ERA: + return (year < 1 ? 1 - year : year); + case YEAR: + return year; + case ERA: + return (year < 1 ? 0 : 1); + default: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + } + return Temporal.super.get(field); + } + + /** + * Gets the value of the specified field from this year-half as a {@code long}. + *

+ * This queries this year-half for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this year-half. + * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field == HALF_OF_YEAR) { + return half.getValue(); + } else if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case YEAR_OF_ERA: + return (year < 1 ? 1 - year : year); + case YEAR: + return year; + case ERA: + return (year < 1 ? 0 : 1); + default: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + } + return field.getFrom(this); + } + + private long getProlepticHalf() { + return year * 2L + (half.getValue() - 1); + } + + //----------------------------------------------------------------------- + /** + * Gets the year field. + *

+ * This method returns the primitive {@code int} value for the year. + *

+ * The year returned by this method is proleptic as per {@code get(YEAR)}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return year; + } + + /** + * Gets the half-of-year field from 1 to 2. + *

+ * This method returns the half as an {@code int} from 1 to 2. + * Application code is frequently clearer if the enum {@link Half} + * is used by calling {@link #getHalf()}. + * + * @return the half-of-year, from 1 to 2 + * @see #getHalf() + */ + public int getHalfValue() { + return half.getValue(); + } + + /** + * Gets the half-of-year field using the {@code Half} enum. + *

+ * This method returns the enum {@link Half} for the half. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link Half#getValue() int value}. + * + * @return the half-of-year, not null + * @see #getHalfValue() + */ + public Half getHalf() { + return half; + } + + //----------------------------------------------------------------------- + /** + * Checks if the year is a leap year, according to the ISO proleptic + * calendar system rules. + *

+ * This method applies the current rules for leap years across the whole time-line. + * In general, a year is a leap year if it is divisible by four without + * remainder. However, years divisible by 100, are not leap years, with + * the exception of years divisible by 400 which are. + *

+ * For example, 1904 is a leap year it is divisible by 4. + * 1900 was not a leap year as it is divisible by 100, however 2000 was a + * leap year as it is divisible by 400. + *

+ * The calculation is proleptic - applying the same rules into the far future and far past. + * This is historically inaccurate, but is correct for the ISO-8601 standard. + * + * @return true if the year is leap, false otherwise + */ + public boolean isLeapYear() { + return IsoChronology.INSTANCE.isLeapYear(year); + } + + /** + * Checks if the day-of-half is valid for this year-half. + *

+ * This method checks whether this year and half and the input day form + * a valid date. + * + * @param dayOfHalf the day-of-half to validate, from 1 to 181, 182 or 184, invalid value returns false + * @return true if the day is valid for this year-half + */ + public boolean isValidDay(int dayOfHalf) { + return dayOfHalf >= 1 && dayOfHalf <= lengthOfHalf(); + } + + /** + * Returns the length of the half, taking account of the year. + *

+ * This returns the length of the half in days. + * + * @return the length of the half in days, 181, 182 or 184 + */ + public int lengthOfHalf() { + return half.length(isLeapYear()); + } + + /** + * Returns the length of the year. + *

+ * This returns the length of the year in days, either 365 or 366. + * + * @return 366 if the year is leap, 365 otherwise + */ + public int lengthOfYear() { + return (isLeapYear() ? 366 : 365); + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this year-half. + *

+ * This returns a {@code YearHalf} based on this one, with the year-half adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

+ * A simple adjuster might simply set the one of the fields, such as the year field. + * A more complex adjuster might set the year-half to the next half that + * Halley's comet will pass the Earth. + *

+ * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return a {@code YearHalf} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearHalf with(TemporalAdjuster adjuster) { + return (YearHalf) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this year-half with the specified field set to a new value. + *

+ * This returns a {@code YearHalf} based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the year or half. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the adjustment is implemented here. + * The supported fields behave as follows: + *

    + *
  • {@code HALF_OF_YEAR} - + * Returns a {@code YearHalf} with the specified half-of-year. + * The year will be unchanged. + *
  • {@code YEAR_OF_ERA} - + * Returns a {@code YearHalf} with the specified year-of-era + * The half and era will be unchanged. + *
  • {@code YEAR} - + * Returns a {@code YearHalf} with the specified year. + * The half will be unchanged. + *
  • {@code ERA} - + * Returns a {@code YearHalf} with the specified era. + * The half and year-of-era will be unchanged. + *
+ *

+ * In all cases, if the new value is outside the valid range of values for the field + * then a {@code DateTimeException} will be thrown. + *

+ * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return a {@code YearHalf} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearHalf with(TemporalField field, long newValue) { + if (field == HALF_OF_YEAR) { + return withHalf(HALF_OF_YEAR.range().checkValidIntValue(newValue, HALF_OF_YEAR)); + } else if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + f.checkValidValue(newValue); + switch (f) { + case YEAR_OF_ERA: + return withYear((int) (year < 1 ? 1 - newValue : newValue)); + case YEAR: + return withYear((int) newValue); + case ERA: + return (getLong(ERA) == newValue ? this : withYear(1 - year)); + default: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + } + return field.adjustInto(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code YearHalf} with the year altered. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param year the year to set in the returned year-half, from MIN_YEAR to MAX_YEAR + * @return a {@code YearHalf} based on this year-half with the requested year, not null + * @throws DateTimeException if the year value is invalid + */ + public YearHalf withYear(int year) { + YEAR.checkValidValue(year); + return with(year, half); + } + + /** + * Returns a copy of this {@code YearHalf} with the half-of-year altered. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param half the half-of-year to set in the returned year-half, from 1 to 2 + * @return a {@code YearHalf} based on this year-half with the requested half, not null + * @throws DateTimeException if the half-of-year value is invalid + */ + public YearHalf withHalf(int half) { + HALF_OF_YEAR.range().checkValidValue(half, HALF_OF_YEAR); + return with(year, Half.of(half)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-half with the specified amount added. + *

+ * This returns a {@code YearHalf} based on this one, with the specified amount added. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

+ * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return a {@code YearHalf} based on this year-half with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearHalf plus(TemporalAmount amountToAdd) { + return (YearHalf) amountToAdd.addTo(this); + } + + /** + * Returns a copy of this year-half with the specified amount added. + *

+ * This returns a {@code YearHalf} based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoUnit} then the addition is implemented here. + * The supported fields behave as follows: + *

    + *
  • {@code HALF_YEARS} - + * Returns a {@code YearHalf} with the specified number of halves added. + * This is equivalent to {@link #plusHalves(long)}. + *
  • {@code YEARS} - + * Returns a {@code YearHalf} with the specified number of years added. + * This is equivalent to {@link #plusYears(long)}. + *
  • {@code DECADES} - + * Returns a {@code YearHalf} with the specified number of decades added. + * This is equivalent to calling {@link #plusYears(long)} with the amount + * multiplied by 10. + *
  • {@code CENTURIES} - + * Returns a {@code YearHalf} with the specified number of centuries added. + * This is equivalent to calling {@link #plusYears(long)} with the amount + * multiplied by 100. + *
  • {@code MILLENNIA} - + * Returns a {@code YearHalf} with the specified number of millennia added. + * This is equivalent to calling {@link #plusYears(long)} with the amount + * multiplied by 1,000. + *
  • {@code ERAS} - + * Returns a {@code YearHalf} with the specified number of eras added. + * Only two eras are supported so the amount must be one, zero or minus one. + * If the amount is non-zero then the year is changed such that the year-of-era + * is unchanged. + *
+ *

+ * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the amount to add, not null + * @return a {@code YearHalf} based on this year-half with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearHalf plus(long amountToAdd, TemporalUnit unit) { + if (unit == HALF_YEARS) { + return plusHalves(amountToAdd); + } else if (unit instanceof ChronoUnit) { + switch ((ChronoUnit) unit) { + case YEARS: + return plusYears(amountToAdd); + case DECADES: + return plusYears(Math.multiplyExact(amountToAdd, 10)); + case CENTURIES: + return plusYears(Math.multiplyExact(amountToAdd, 100)); + case MILLENNIA: + return plusYears(Math.multiplyExact(amountToAdd, 1000)); + case ERAS: + return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); + default: + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + } + return unit.addTo(this, amountToAdd); + } + + /** + * Returns a copy of this year-half with the specified period in years added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param yearsToAdd the years to add, may be negative + * @return a {@code YearHalf} based on this year-half with the years added, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public YearHalf plusYears(long yearsToAdd) { + if (yearsToAdd == 0) { + return this; + } + int newYear = YEAR.checkValidIntValue(year + yearsToAdd); // safe overflow + return with(newYear, half); + } + + /** + * Returns a copy of this year-half with the specified period in halves added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param halvesToAdd the halves to add, may be negative + * @return a {@code YearHalf} based on this year-half with the halves added, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public YearHalf plusHalves(long halvesToAdd) { + if (halvesToAdd == 0) { + return this; + } + long halfCount = year * 2L + (half.getValue() - 1); + long calcHalves = halfCount + halvesToAdd; // safe overflow + int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcHalves, 2)); + int newHalf = (int) Math.floorMod(calcHalves, 2L) + 1; + return with(newYear, Half.of(newHalf)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-half with the specified amount subtracted. + *

+ * This returns a {@code YearHalf} based on this one, with the specified amount subtracted. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

+ * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount to subtract, not null + * @return a {@code YearHalf} based on this year-half with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearHalf minus(TemporalAmount amountToSubtract) { + return (YearHalf) amountToSubtract.subtractFrom(this); + } + + /** + * Returns a copy of this year-half with the specified amount subtracted. + *

+ * This returns a {@code YearHalf} based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + *

+ * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the amount to subtract, not null + * @return a {@code YearHalf} based on this year-half with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearHalf minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + /** + * Returns a copy of this year-half with the specified period in years subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param yearsToSubtract the years to subtract, may be negative + * @return a {@code YearHalf} based on this year-half with the years subtracted, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public YearHalf minusYears(long yearsToSubtract) { + return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract)); + } + + /** + * Returns a copy of this year-half with the specified period in halves subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param halvesToSubtract the halves to subtract, may be negative + * @return a {@code YearHalf} based on this year-half with the halves subtracted, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public YearHalf minusHalves(long halvesToSubtract) { + return (halvesToSubtract == Long.MIN_VALUE ? plusHalves(Long.MAX_VALUE).plusHalves(1) : plusHalves(-halvesToSubtract)); + } + + //----------------------------------------------------------------------- + /** + * Queries this year-half using the specified query. + *

+ * This queries this year-half using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

+ * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == TemporalQueries.chronology()) { + return (R) IsoChronology.INSTANCE; + } else if (query == TemporalQueries.precision()) { + return (R) HALF_YEARS; + } + return Temporal.super.query(query); + } + + /** + * Adjusts the specified temporal object to have this year-half. + *

+ * This returns a temporal object of the same observable type as the input + * with the year and half changed to be the same as this. + *

+ * The adjustment is equivalent to using {@link Temporal#plus(long, TemporalUnit)} + * passing the number of halves to adjust by. + * If the specified temporal object does not use the ISO calendar system then + * a {@code DateTimeException} is thrown. + *

+ * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisYearHalf.adjustInto(temporal);
+     *   temporal = temporal.with(thisYearHalf);
+     * 
+ *

+ * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) { + throw new DateTimeException("Adjustment only supported on ISO date-time"); + } + long newProlepticHalf = getProlepticHalf(); + long oldProlepticHalf = temporal.get(YEAR) * 2L + (temporal.get(HALF_OF_YEAR) - 1); + return temporal.plus(newProlepticHalf - oldProlepticHalf, HALF_YEARS); + } + + /** + * Calculates the amount of time until another year-half in terms of the specified unit. + *

+ * This calculates the amount of time between two {@code YearHalf} + * objects in terms of a single {@code TemporalUnit}. + * The start and end points are {@code this} and the specified year-half. + * The result will be negative if the end is before the start. + * The {@code Temporal} passed to this method is converted to a + * {@code YearHalf} using {@link #from(TemporalAccessor)}. + * For example, the period in years between two year-halves can be calculated + * using {@code startYearHalf.until(endYearHalf, YEARS)}. + *

+ * The calculation returns a whole number, representing the number of + * complete units between the two year-halves. + * For example, the period in decades between 2012-H2 and 2032-H1 + * will only be one decade as it is one half short of two decades. + *

+ * There are two equivalent ways of using this method. + * The first is to invoke this method. + * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: + *

+     *   // these two lines are equivalent
+     *   amount = start.until(end, HALF_YEARS);
+     *   amount = HALF_YEARS.between(start, end);
+     * 
+ * The choice should be made based on which makes the code more readable. + *

+ * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code HALF_YEARS}, {@code YEARS}, {@code DECADES}, + * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported. + * Other {@code ChronoUnit} values will throw an exception. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param endExclusive the end date, exclusive, which is converted to a {@code YearHalf}, not null + * @param unit the unit to measure the amount in, not null + * @return the amount of time between this year-half and the end year-half + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code YearHalf} + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long until(Temporal endExclusive, TemporalUnit unit) { + YearHalf end = YearHalf.from(endExclusive); + long halvesUntil = end.getProlepticHalf() - getProlepticHalf(); // no overflow + if (unit == HALF_YEARS) { + return halvesUntil; + } else if (unit instanceof ChronoUnit) { + switch ((ChronoUnit) unit) { + case YEARS: + return halvesUntil / 2; + case DECADES: + return halvesUntil / 20; + case CENTURIES: + return halvesUntil / 200; + case MILLENNIA: + return halvesUntil / 2000; + case ERAS: + return end.getLong(ERA) - getLong(ERA); + default: + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + } + return unit.between(this, end); + } + + /** + * Returns a sequential ordered stream of year-half. The returned stream starts from this year-half + * (inclusive) and goes to {@code endExclusive} (exclusive) by an incremental step of 1 {@code HALF_YEARS}. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param endExclusive the end year-half, exclusive, not null + * @return a sequential {@code Stream} for the range of {@code YearHalf} values + * @throws IllegalArgumentException if end year-half is before this year-half + */ + public Stream halvesUntil(YearHalf endExclusive) { + if (endExclusive.isBefore(this)) { + throw new IllegalArgumentException(endExclusive + " < " + this); + } + long intervalLength = until(endExclusive, HALF_YEARS); + return LongStream.range(0, intervalLength).mapToObj(n -> plusHalves(n)); + } + + /** + * Formats this year-half using the specified formatter. + *

+ * This year-half will be passed to the formatter to produce a string. + * + * @param formatter the formatter to use, not null + * @return the formatted year-half string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String format(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.format(this); + } + + //----------------------------------------------------------------------- + /** + * Combines this year-half with a day-of-half to create a {@code LocalDate}. + *

+ * This returns a {@code LocalDate} formed from this year-half and the specified day-of-half. + *

+ * The day-of-half value must be valid for the year-half. + *

+ * This method can be used as part of a chain to produce a date: + *

+     *  LocalDate date = yearHalf.atDay(day);
+     * 
+ * + * @param dayOfHalf the day-of-half to use, from 1 to 184 + * @return the date formed from this year-half and the specified day, not null + * @throws DateTimeException if the day is invalid for the year-half + * @see #isValidDay(int) + */ + public LocalDate atDay(int dayOfHalf) { + ValueRange.of(1, lengthOfHalf()).checkValidValue(dayOfHalf, DAY_OF_HALF); + boolean leap = Year.isLeap(year); + Month month = half.firstMonth(); + int dom = dayOfHalf; + while (dom > month.length(leap)) { + dom -= month.length(leap); + month = month.plus(1); + } + return LocalDate.of(year, month, dom); + } + + /** + * Returns a {@code LocalDate} at the end of the half. + *

+ * This returns a {@code LocalDate} based on this year-half. + * The day-of-half is set to the last valid day of the half, taking + * into account leap years. + *

+ * This method can be used as part of a chain to produce a date: + *

+     *  LocalDate date = year.atHalf(half).atEndOfHalf();
+     * 
+ * + * @return the last valid date of this year-half, not null + */ + public LocalDate atEndOfHalf() { + Month month = half.firstMonth().plus(5); + return LocalDate.of(year, month, month.maxLength()); + } + + //----------------------------------------------------------------------- + /** + * Compares this year-half to another + *

+ * The comparison is based first on the value of the year, then on the value of the half. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other year-half to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(YearHalf other) { + int cmp = (year - other.year); + if (cmp == 0) { + cmp = half.compareTo(other.half); + } + return cmp; + } + + /** + * Is this year-half after the specified year-half. + * + * @param other the other year-half to compare to, not null + * @return true if this is after the specified year-half + */ + public boolean isAfter(YearHalf other) { + return compareTo(other) > 0; + } + + /** + * Is this year-half before the specified year-half. + * + * @param other the other year-half to compare to, not null + * @return true if this point is before the specified year-half + */ + public boolean isBefore(YearHalf other) { + return compareTo(other) < 0; + } + + //----------------------------------------------------------------------- + /** + * Checks if this year-half is equal to another year-half. + *

+ * The comparison is based on the time-line position of the year-halves. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other year-half + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof YearHalf) { + YearHalf other = (YearHalf) obj; + return year == other.year && half == other.half; + } + return false; + } + + /** + * A hash code for this year-half. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return year ^ (half.getValue() << 28); + } + + //----------------------------------------------------------------------- + /** + * Outputs this year-half as a {@code String}, such as {@code 2007-H2}. + * + * @return a string representation of this year-half, not null + */ + @Override + @ToString + public String toString() { + int absYear = Math.abs(year); + StringBuilder buf = new StringBuilder(10); + if (absYear < 1000) { + if (year < 0) { + buf.append(year - 10000).deleteCharAt(1); + } else { + buf.append(year + 10000).deleteCharAt(0); + } + } else { + if (year > 9999) { + buf.append('+'); + } + buf.append(year); + } + return buf.append('-').append(half).toString(); + } + +} diff --git a/src/main/java/org/threeten/extra/YearQuarter.java b/src/main/java/org/threeten/extra/YearQuarter.java index d7ff44ba..5d455abc 100644 --- a/src/main/java/org/threeten/extra/YearQuarter.java +++ b/src/main/java/org/threeten/extra/YearQuarter.java @@ -71,6 +71,11 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +import org.joda.convert.FromString; +import org.joda.convert.ToString; /** * A year-quarter in the ISO-8601 calendar system, such as {@code 2007-Q2}. @@ -173,6 +178,29 @@ public static YearQuarter now(Clock clock) { } //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code YearQuarter} from a year and quarter. + * + * @param year the year to represent, not null + * @param quarter the quarter-of-year to represent, not null + * @return the year-quarter, not null + */ + public static YearQuarter of(Year year, Quarter quarter) { + return of(year.getValue(), quarter); + } + + /** + * Obtains an instance of {@code YearQuarter} from a year and quarter. + * + * @param year the year to represent, not null + * @param quarter the quarter-of-year to represent, from 1 to 4 + * @return the year-quarter, not null + * @throws DateTimeException if the quarter value is invalid + */ + public static YearQuarter of(Year year, int quarter) { + return of(year.getValue(), Quarter.of(quarter)); + } + /** * Obtains an instance of {@code YearQuarter} from a year and quarter. * @@ -226,10 +254,12 @@ public static YearQuarter from(TemporalAccessor temporal) { } Objects.requireNonNull(temporal, "temporal"); try { - if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { - temporal = LocalDate.from(temporal); - } - return of(temporal.get(YEAR), temporal.get(QUARTER_OF_YEAR)); + TemporalAccessor adjusted = + !IsoChronology.INSTANCE.equals(Chronology.from(temporal)) ? LocalDate.from(temporal) : temporal; + // need to use getLong() as JDK Parsed class get() doesn't work properly + int year = Math.toIntExact(adjusted.getLong(YEAR)); + int qoy = Math.toIntExact(adjusted.getLong(QUARTER_OF_YEAR)); + return of(year, qoy); } catch (DateTimeException ex) { throw new DateTimeException("Unable to obtain YearQuarter from TemporalAccessor: " + temporal + " of type " + temporal.getClass().getName(), ex); @@ -248,6 +278,7 @@ public static YearQuarter from(TemporalAccessor temporal) { * @return the parsed year-quarter, not null * @throws DateTimeParseException if the text cannot be parsed */ + @FromString public static YearQuarter parse(CharSequence text) { return parse(text, PARSER); } @@ -343,7 +374,7 @@ public boolean isSupported(TemporalField field) { /** * Checks if the specified unit is supported. *

- * This checks if the specified unit can be added to, or subtracted from, this date-time. + * This checks if the specified unit can be added to, or subtracted from, this year-quarter. * If false, then calling the {@link #plus(long, TemporalUnit)} and * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. *

@@ -403,6 +434,9 @@ public boolean isSupported(TemporalUnit unit) { */ @Override public ValueRange range(TemporalField field) { + if (field == QUARTER_OF_YEAR) { + return QUARTER_OF_YEAR.range(); + } if (field == YEAR_OF_ERA) { return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE)); } @@ -437,6 +471,20 @@ public ValueRange range(TemporalField field) { */ @Override public int get(TemporalField field) { + if (field == QUARTER_OF_YEAR) { + return quarter.getValue(); + } else if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case YEAR_OF_ERA: + return (year < 1 ? 1 - year : year); + case YEAR: + return year; + case ERA: + return (year < 1 ? 0 : 1); + default: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + } return Temporal.super.get(field); } @@ -591,7 +639,7 @@ public int lengthOfYear() { /** * Returns an adjusted copy of this year-quarter. *

- * This returns a {@code YearQuarter}, based on this one, with the year-quarter adjusted. + * This returns a {@code YearQuarter} based on this one, with the year-quarter adjusted. * The adjustment takes place using the specified adjuster strategy object. * Read the documentation of the adjuster to understand what adjustment will be made. *

@@ -618,7 +666,7 @@ public YearQuarter with(TemporalAdjuster adjuster) { /** * Returns a copy of this year-quarter with the specified field set to a new value. *

- * This returns a {@code YearQuarter}, based on this one, with the value + * This returns a {@code YearQuarter} based on this one, with the value * for the specified field changed. * This can be used to change any supported field, such as the year or quarter. * If it is not possible to set the value, because the field is not supported or for @@ -714,7 +762,7 @@ public YearQuarter withQuarter(int quarter) { /** * Returns a copy of this year-quarter with the specified amount added. *

- * This returns a {@code YearQuarter}, based on this one, with the specified amount added. + * This returns a {@code YearQuarter} based on this one, with the specified amount added. * The amount is typically {@link Period} but may be any other type implementing * the {@link TemporalAmount} interface. *

@@ -739,7 +787,7 @@ public YearQuarter plus(TemporalAmount amountToAdd) { /** * Returns a copy of this year-quarter with the specified amount added. *

- * This returns a {@code YearQuarter}, based on this one, with the amount + * This returns a {@code YearQuarter} based on this one, with the amount * in terms of the unit added. If it is not possible to add the amount, because the * unit is not supported or for some other reason, an exception is thrown. *

@@ -843,7 +891,7 @@ public YearQuarter plusQuarters(long quartersToAdd) { long quarterCount = year * 4L + (quarter.getValue() - 1); long calcQuarters = quarterCount + quartersToAdd; // safe overflow int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcQuarters, 4)); - int newQuarter = (int) Math.floorMod(calcQuarters, 4) + 1; + int newQuarter = (int) Math.floorMod(calcQuarters, 4L) + 1; return with(newYear, Quarter.of(newQuarter)); } @@ -851,7 +899,7 @@ public YearQuarter plusQuarters(long quartersToAdd) { /** * Returns a copy of this year-quarter with the specified amount subtracted. *

- * This returns a {@code YearQuarter}, based on this one, with the specified amount subtracted. + * This returns a {@code YearQuarter} based on this one, with the specified amount subtracted. * The amount is typically {@link Period} but may be any other type implementing * the {@link TemporalAmount} interface. *

@@ -876,7 +924,7 @@ public YearQuarter minus(TemporalAmount amountToSubtract) { /** * Returns a copy of this year-quarter with the specified amount subtracted. *

- * This returns a {@code YearQuarter}, based on this one, with the amount + * This returns a {@code YearQuarter} based on this one, with the amount * in terms of the unit subtracted. If it is not possible to subtract the amount, * because the unit is not supported or for some other reason, an exception is thrown. *

@@ -1061,6 +1109,24 @@ public long until(Temporal endExclusive, TemporalUnit unit) { return unit.between(this, end); } + /** + * Returns a sequential ordered stream of year-quarter. The returned stream starts from this year-quarter + * (inclusive) and goes to {@code endExclusive} (exclusive) by an incremental step of 1 {@code QUARTER_YEARS}. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param endExclusive the end year-quarter, exclusive, not null + * @return a sequential {@code Stream} for the range of {@code YearQuarter} values + * @throws IllegalArgumentException if end year-quarter is before this year-quarter + */ + public Stream quartersUntil(YearQuarter endExclusive) { + if (endExclusive.isBefore(this)) { + throw new IllegalArgumentException(endExclusive + " < " + this); + } + long intervalLength = until(endExclusive, QUARTER_YEARS); + return LongStream.range(0, intervalLength).mapToObj(n -> plusQuarters(n)); + } + /** * Formats this year-quarter using the specified formatter. *

@@ -1097,11 +1163,12 @@ public LocalDate atDay(int dayOfQuarter) { ValueRange.of(1, lengthOfQuarter()).checkValidValue(dayOfQuarter, DAY_OF_QUARTER); boolean leap = Year.isLeap(year); Month month = quarter.firstMonth(); - while (dayOfQuarter > month.length(leap)) { - dayOfQuarter -= month.length(leap); + int dom = dayOfQuarter; + while (dom > month.length(leap)) { + dom -= month.length(leap); month = month.plus(1); } - return LocalDate.of(year, month, dayOfQuarter); + return LocalDate.of(year, month, dom); } /** @@ -1202,6 +1269,7 @@ public int hashCode() { * @return a string representation of this year-quarter, not null */ @Override + @ToString public String toString() { int absYear = Math.abs(year); StringBuilder buf = new StringBuilder(10); diff --git a/src/main/java/org/threeten/extra/YearWeek.java b/src/main/java/org/threeten/extra/YearWeek.java index 17cbae23..148212ae 100644 --- a/src/main/java/org/threeten/extra/YearWeek.java +++ b/src/main/java/org/threeten/extra/YearWeek.java @@ -31,9 +31,12 @@ */ package org.threeten.extra; +import static java.time.DayOfWeek.MONDAY; import static java.time.DayOfWeek.THURSDAY; import static java.time.DayOfWeek.WEDNESDAY; +import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.IsoFields.WEEK_BASED_YEAR; +import static java.time.temporal.IsoFields.WEEK_BASED_YEARS; import static java.time.temporal.IsoFields.WEEK_OF_WEEK_BASED_YEAR; import java.io.Serializable; @@ -41,6 +44,7 @@ import java.time.DateTimeException; import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.Period; import java.time.Year; import java.time.ZoneId; import java.time.chrono.Chronology; @@ -50,17 +54,23 @@ import java.time.format.DateTimeParseException; import java.time.format.SignStyle; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.time.temporal.IsoFields; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQueries; import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * A year-week in the ISO week date system such as {@code 2015-W13} *

@@ -89,7 +99,7 @@ * identity hash code or use the distinction between equals() and ==. */ public final class YearWeek - implements TemporalAccessor, TemporalAdjuster, Comparable, Serializable { + implements Temporal, TemporalAdjuster, Comparable, Serializable { /** * Serialization version. @@ -164,6 +174,28 @@ public static YearWeek now(Clock clock) { } //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code YearWeek} from a year and week. + *

+ * If the week is 53 and the year does not have 53 weeks, week one of the following + * year is selected. + *

+ * Note that this class is based on the week-based-year which aligns to Monday to Sunday weeks, + * whereas {@code Year} is intended to represent standard years aligned from January to December. + * This difference may be seen at the start and/or end of the year. + * This method treats the standard year as though it is the week-based-year. + * Thus, {@code YearWeek.of(Year.of(2020), 1)} creates an object where Monday and Tuesday of the week + * are actually the last two days of 2019. + * + * @param year the year to represent, not null + * @param week the week-of-week-based-year to represent, from 1 to 53 + * @return the year-week, not null + * @throws DateTimeException if the week value is invalid + */ + public static YearWeek of(Year year, int week) { + return of(year.getValue(), week); + } + /** * Obtains an instance of {@code YearWeek} from a week-based-year and week. *

@@ -189,7 +221,7 @@ public static YearWeek of(int weekBasedYear, int week) { // from IsoFields in ThreeTen-Backport private static int weekRange(int weekBasedYear) { LocalDate date = LocalDate.of(weekBasedYear, 1, 1); - // 53 weeks if standard year starts on Thursday, or Wed in a leap year + // 53 weeks if year starts on Thursday, or Wed in a leap year if (date.getDayOfWeek() == THURSDAY || (date.getDayOfWeek() == WEDNESDAY && date.isLeapYear())) { return 53; } @@ -222,10 +254,13 @@ public static YearWeek from(TemporalAccessor temporal) { } Objects.requireNonNull(temporal, "temporal"); try { - if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { + if (!IsoChronology.INSTANCE.equals(Chronology.from(temporal))) { temporal = LocalDate.from(temporal); } - return of(temporal.get(WEEK_BASED_YEAR), (int) temporal.getLong(WEEK_OF_WEEK_BASED_YEAR)); + // need to use getLong() as JDK Parsed class get() doesn't work properly + int year = Math.toIntExact(temporal.getLong(WEEK_BASED_YEAR)); + int week = Math.toIntExact(temporal.getLong(WEEK_OF_WEEK_BASED_YEAR)); + return of(year, week); } catch (DateTimeException ex) { throw new DateTimeException("Unable to obtain YearWeek from TemporalAccessor: " + temporal + " of type " + temporal.getClass().getName(), ex); @@ -245,6 +280,7 @@ public static YearWeek from(TemporalAccessor temporal) { * @return the parsed year-week, not null * @throws DateTimeParseException if the text cannot be parsed */ + @FromString public static YearWeek parse(CharSequence text) { return parse(text, PARSER); } @@ -308,13 +344,12 @@ private YearWeek with(int newYear, int newWeek) { * If false, then calling the {@link #range(TemporalField) range} and * {@link #get(TemporalField) get} methods will throw an exception. *

- * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: *

    *
  • {@code WEEK_OF_WEEK_BASED_YEAR} *
  • {@code WEEK_BASED_YEAR} *
- * All {@code ChronoField} instances will return false. + * All other {@code ChronoField} instances will return false. *

* If the field is not a {@code ChronoField}, then the result of this method * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} @@ -334,6 +369,38 @@ public boolean isSupported(TemporalField field) { return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * The supported units are: + *

    + *
  • {@code WEEKS} + *
  • {@code WEEK_BASED_YEARS} + *
+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit == WEEKS || unit == WEEK_BASED_YEARS) { + return true; + } else if (unit instanceof ChronoUnit) { + return false; + } + return unit != null && unit.isSupportedBy(this); + } + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. @@ -360,7 +427,7 @@ public ValueRange range(TemporalField field) { if (field == WEEK_OF_WEEK_BASED_YEAR) { return ValueRange.of(1, weekRange(year)); } - return TemporalAccessor.super.range(field); + return Temporal.super.range(field); } /** @@ -391,7 +458,7 @@ public int get(TemporalField field) { if (field == WEEK_OF_WEEK_BASED_YEAR) { return week; } - return TemporalAccessor.super.get(field); + return Temporal.super.get(field); } /** @@ -475,6 +542,75 @@ public int lengthOfYear() { } //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this year-week. + *

+ * This returns a {@code YearWeek}, based on this one, with the year-week adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

+ * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return a {@code YearWeek} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearWeek with(TemporalAdjuster adjuster) { + return (YearWeek) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this year-week with the specified field set to a new value. + *

+ * This returns a {@code YearWeek}, based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the year or week. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoField} then the adjustment is implemented here. + * The supported fields behave as follows: + *

    + *
  • {@code WEEK_OF_WEEK_BASED_YEAR} - + * Returns a {@code YearWeek} with the specified week-of-year set as per {@link #withWeek(int)}. + *
  • {@code WEEK_BASED_YEAR} - + * Returns a {@code YearWeek} with the specified year set as per {@link #withYear(int)}. + *
+ *

+ * All {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return a {@code YearWeek} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws UnsupportedTemporalTypeException if the field is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearWeek with(TemporalField field, long newValue) { + if (field == WEEK_OF_WEEK_BASED_YEAR) { + return withWeek(WEEK_OF_WEEK_BASED_YEAR.range().checkValidIntValue(newValue, WEEK_OF_WEEK_BASED_YEAR)); + } else if (field == WEEK_BASED_YEAR) { + return withYear(WEEK_BASED_YEAR.range().checkValidIntValue(newValue, WEEK_BASED_YEAR)); + } else if (field instanceof ChronoField) { + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); + } + return field.adjustInto(this, newValue); + } + /** * Returns a copy of this {@code YearWeek} with the week-based-year altered. *

@@ -512,6 +648,196 @@ public YearWeek withWeek(int week) { return with(year, week); } + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-week with the specified amount added. + *

+ * This returns a {@code YearWeek}, based on this one, with the specified amount added. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

+ * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return a {@code YearWeek} based on this year-week with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearWeek plus(TemporalAmount amountToAdd) { + return (YearWeek) amountToAdd.addTo(this); + } + + /** + * Returns a copy of this year-week with the specified amount added. + *

+ * This returns a {@code YearWeek}, based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + *

+ * If the field is a {@link ChronoUnit} then the addition is implemented here. + * The supported fields behave as follows: + *

    + *
  • {@code WEEKS} - + * Returns a {@code YearWeek} with the weeks added as per {@link #plusWeeks(long)}. + *
  • {@code WEEK_BASED_YEARS} - + * Returns a {@code YearWeek} with the years added as per {@link #plusYears(long)}. + *
+ *

+ * All {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}. + *

+ * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the amount to add, not null + * @return a {@code YearWeek} based on this year-week with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearWeek plus(long amountToAdd, TemporalUnit unit) { + if (unit == WEEKS) { + return plusWeeks(amountToAdd); + } else if (unit == WEEK_BASED_YEARS) { + return plusYears(amountToAdd); + } else if (unit instanceof ChronoUnit) { + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + return unit.addTo(this, amountToAdd); + } + + /** + * Returns a copy of this year-week with the specified number of years added. + *

+ * If the week of this instance is 53 and the new year does not have 53 weeks, + * the week will be adjusted to be 52. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param yearsToAdd the years to add, may be negative + * @return the year-week with the years added, not null + */ + public YearWeek plusYears(long yearsToAdd) { + if (yearsToAdd == 0) { + return this; + } + int newYear = Math.toIntExact(Math.addExact(year, yearsToAdd)); + return withYear(newYear); + } + + /** + * Returns a copy of this year-week with the specified number of weeks added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param weeksToAdd the weeks to add, may be negative + * @return the year-week with the weeks added, not null + */ + public YearWeek plusWeeks(long weeksToAdd) { + if (weeksToAdd == 0) { + return this; + } + LocalDate mondayOfWeek = atDay(MONDAY).plusWeeks(weeksToAdd); + return YearWeek.from(mondayOfWeek); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-week with the specified amount subtracted. + *

+ * This returns a {@code YearWeek}, based on this one, with the specified amount subtracted. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

+ * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount to subtract, not null + * @return a {@code YearWeek} based on this year-week with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearWeek minus(TemporalAmount amountToSubtract) { + return (YearWeek) amountToSubtract.subtractFrom(this); + } + + /** + * Returns a copy of this year-week with the specified amount subtracted. + *

+ * This returns a {@code YearWeek}, based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + *

+ * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the amount to subtract, not null + * @return a {@code YearWeek} based on this year-week with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearWeek minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + /** + * Returns a copy of this year-week with the specified number of years subtracted. + *

+ * If the week of this instance is 53 and the new year does not have 53 weeks, + * the week will be adjusted to be 52. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param yearsToSubtract the years to subtract, may be negative + * @return the year-week with the years subtracted, not null + */ + public YearWeek minusYears(long yearsToSubtract) { + if (yearsToSubtract == 0) { + return this; + } + int newYear = Math.toIntExact(Math.subtractExact(year, yearsToSubtract)); + return withYear(newYear); + } + + /** + * Returns a copy of this year-week with the specified number of weeks subtracted. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param weeksToSubtract the weeks to subtract, may be negative + * @return the year-week with the weeks subtracted, not null + */ + public YearWeek minusWeeks(long weeksToSubtract) { + if (weeksToSubtract == 0) { + return this; + } + LocalDate mondayOfWeek = atDay(MONDAY).minusWeeks(weeksToSubtract); + return YearWeek.from(mondayOfWeek); + } + //----------------------------------------------------------------------- /** * Queries this year-week using the specified query. @@ -537,7 +863,7 @@ public R query(TemporalQuery query) { if (query == TemporalQueries.chronology()) { return (R) IsoChronology.INSTANCE; } - return TemporalAccessor.super.query(query); + return Temporal.super.query(query); } /** @@ -569,12 +895,89 @@ public R query(TemporalQuery query) { */ @Override public Temporal adjustInto(Temporal temporal) { - if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) { + if (!Chronology.from(temporal).equals(IsoChronology.INSTANCE)) { throw new DateTimeException("Adjustment only supported on ISO date-time"); } return temporal.with(WEEK_BASED_YEAR, year).with(WEEK_OF_WEEK_BASED_YEAR, week); } + /** + * Calculates the amount of time until another year-week in terms of the specified unit. + *

+ * This calculates the amount of time between two {@code YearWeek} + * objects in terms of a single {@code TemporalUnit}. + * The start and end points are {@code this} and the specified year-week. + * The result will be negative if the end is before the start. + * The {@code Temporal} passed to this method is converted to a + * {@code YearWeek} using {@link #from(TemporalAccessor)}. + * For example, the period in years between two year-weeks can be calculated + * using {@code startYearWeek.until(endYearWeek, YEARS)}. + *

+ * The calculation returns a whole number, representing the number of + * complete units between the two year-weeks. + * For example, the period in years between 2012-W23 and 2032-W22 + * will only be 9 years as it is one week short of 10 years. + *

+ * There are two equivalent ways of using this method. + * The first is to invoke this method. + * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: + *

+     *   // these two lines are equivalent
+     *   amount = start.until(end, WEEKS);
+     *   amount = WEEKS.between(start, end);
+     * 
+ * The choice should be made based on which makes the code more readable. + *

+ * The calculation is implemented in this method for units {@code WEEKS} + * and {@code WEEK_BASED_YEARS}. + * Other {@code ChronoUnit} values will throw an exception. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param endExclusive the end date, exclusive, which is converted to a {@code YearWeek}, not null + * @param unit the unit to measure the amount in, not null + * @return the amount of time between this year-week and the end year-week + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code YearWeek} + * @throws UnsupportedTemporalTypeException if the unit is not supported + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long until(Temporal endExclusive, TemporalUnit unit) { + YearWeek end = YearWeek.from(endExclusive); + if (unit == WEEKS) { + return daysUntil(end); + } else if (unit == WEEK_BASED_YEARS) { + return yearsUntil(end); + } else if (unit instanceof ChronoUnit) { + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + return unit.between(this, end); + } + + private long daysUntil(YearWeek end) { + LocalDate startDate = this.atDay(MONDAY); + LocalDate endDate = end.atDay(MONDAY); + long days = endDate.toEpochDay() - startDate.toEpochDay(); + return days / 7; + } + + private long yearsUntil(YearWeek end) { + long yearsDiff = end.year - this.year; + if (yearsDiff > 0 && end.week < this.week) { + return yearsDiff - 1; + } + if (yearsDiff < 0 && end.week > this.week) { + return yearsDiff + 1; + } + return yearsDiff; + } + /** * Formats this year-week using the specified formatter. *

@@ -607,6 +1010,10 @@ public LocalDate atDay(DayOfWeek dayOfWeek) { Objects.requireNonNull(dayOfWeek, "dayOfWeek"); int correction = LocalDate.of(year, 1, 4).getDayOfWeek().getValue() + 3; int dayOfYear = week * 7 + dayOfWeek.getValue() - correction; + int maxDaysOfYear = Year.isLeap(year) ? 366 : 365; + if (dayOfYear > maxDaysOfYear) { + return LocalDate.ofYearDay(year + 1, dayOfYear - maxDaysOfYear); + } if (dayOfYear > 0) { return LocalDate.ofYearDay(year, dayOfYear); } else { @@ -692,6 +1099,7 @@ public int hashCode() { * @return a string representation of this year-week, not null */ @Override + @ToString public String toString() { int absYear = Math.abs(year); StringBuilder buf = new StringBuilder(10); diff --git a/src/main/java/org/threeten/extra/Years.java b/src/main/java/org/threeten/extra/Years.java index 22b7a20d..780aab54 100644 --- a/src/main/java/org/threeten/extra/Years.java +++ b/src/main/java/org/threeten/extra/Years.java @@ -48,6 +48,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * A year-based amount of time, such as '12 years'. *

@@ -173,11 +176,12 @@ public static Years from(TemporalAmount amount) { * @return the parsed period, not null * @throws DateTimeParseException if the text cannot be parsed to a period */ + @FromString public static Years parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { - int negate = ("-".equals(matcher.group(1)) ? -1 : 1); + int negate = "-".equals(matcher.group(1)) ? -1 : 1; String str = matcher.group(2); try { int val = Integer.parseInt(str); @@ -237,7 +241,7 @@ private Object readResolve() { */ @Override public long get(TemporalUnit unit) { - if (unit == ChronoUnit.YEARS) { + if (unit == YEARS) { return years; } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); @@ -268,6 +272,33 @@ public int getAmount() { return years; } + /** + * Checks if the amount is negative. + * + * @return true if the amount is negative, false if the amount is zero or positive + */ + public boolean isNegative() { + return getAmount() < 0; + } + + /** + * Checks if the amount is zero. + * + * @return true if the amount is zero, false if not + */ + public boolean isZero() { + return getAmount() == 0; + } + + /** + * Checks if the amount is positive. + * + * @return true if the amount is positive, false if the amount is zero or negative + */ + public boolean isPositive() { + return getAmount() > 0; + } + //----------------------------------------------------------------------- /** * Returns a copy of this amount with the specified amount added. @@ -309,13 +340,13 @@ public Years plus(int years) { *

* This instance is immutable and unaffected by this method call. * - * @param amountToAdd the amount to add, not null + * @param amountToSubtract the amount to subtract, not null * @return a {@code Years} based on this instance with the requested amount subtracted, not null * @throws DateTimeException if the specified amount contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ - public Years minus(TemporalAmount amountToAdd) { - return minus(Years.from(amountToAdd).getAmount()); + public Years minus(TemporalAmount amountToSubtract) { + return minus(Years.from(amountToSubtract).getAmount()); } /** @@ -530,6 +561,7 @@ public int hashCode() { * @return the number of years in ISO-8601 string format */ @Override + @ToString public String toString() { return "P" + years + "Y"; } diff --git a/src/main/java/org/threeten/extra/chrono/AccountingChronology.java b/src/main/java/org/threeten/extra/chrono/AccountingChronology.java index 3def5e1a..fafcda3d 100644 --- a/src/main/java/org/threeten/extra/chrono/AccountingChronology.java +++ b/src/main/java/org/threeten/extra/chrono/AccountingChronology.java @@ -44,6 +44,7 @@ import java.time.chrono.AbstractChronology; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; @@ -57,8 +58,8 @@ * An Accounting calendar system. *

* This chronology defines the rules of a proleptic 52/53-week Accounting calendar system. - * This calendar system follows the rules as laid down in IRS Publication 538 - * and the International Financial Reporting Standards. + * This calendar system follows the rules as laid down in IRS Publication 538 + * and the International Financial Reporting Standards. * The start of the Accounting calendar will vary against the ISO calendar. * Depending on options chosen, it can start as early as {@code 0000-01-26 (ISO)} or as late as {@code 0001-01-04 (ISO)}. *

@@ -112,7 +113,7 @@ public final class AccountingChronology extends AbstractChronology implements Se */ private final DayOfWeek endsOn; /** - * Whether the calendar ends in the last week of a given Gregorian/ISO month, + * Whether the calendar ends in the last week of a given Gregorian/ISO month, * or nearest to the last day of the month (will sometimes be in the next month). */ private final boolean inLastWeek; @@ -128,12 +129,16 @@ public final class AccountingChronology extends AbstractChronology implements Se * The month which will have the leap-week added. */ private final int leapWeekInMonth; + /** + * The year offset. + */ + private final int yearOffset; /** * Difference in days between accounting year end and ISO month end, in ISO year 0. */ private final transient int yearZeroDifference; - /** + /** * Number of weeks in a month range. */ private final transient ValueRange alignedWeekOfMonthRange; @@ -150,7 +155,7 @@ public final class AccountingChronology extends AbstractChronology implements Se /** * Creates an {@code AccountingChronology} validating the input. * Package private as only meant to be called from the builder. - * + * * @param endsOn The day-of-week a given year ends on. * @param end The month-end the year is based on. * @param inLastWeek Whether the year ends in the last week of the month, or nearest the end-of-month. @@ -159,7 +164,8 @@ public final class AccountingChronology extends AbstractChronology implements Se * @return The created Chronology, not null. * @throws DateTimeException if the chronology cannot be built. */ - static AccountingChronology create(DayOfWeek endsOn, Month end, boolean inLastWeek, AccountingYearDivision division, int leapWeekInMonth) { + static AccountingChronology create(DayOfWeek endsOn, Month end, boolean inLastWeek, AccountingYearDivision division, + int leapWeekInMonth, int yearOffset) { if (endsOn == null || end == null || division == null || leapWeekInMonth == 0) { throw new IllegalStateException("AccountingCronology cannot be built: " + (endsOn == null ? "| ending day-of-week |" : "") @@ -169,13 +175,13 @@ static AccountingChronology create(DayOfWeek endsOn, Month end, boolean inLastWe + " not set."); } if (!division.getMonthsInYearRange().isValidValue(leapWeekInMonth)) { - throw new IllegalStateException("Leap week cannot not be placed in non-existant month " + leapWeekInMonth + throw new IllegalStateException("Leap week cannot not be placed in non-existent month " + leapWeekInMonth + ", range is [" + division.getMonthsInYearRange() + "]."); } // Derive cached information. - LocalDate endingLimit = inLastWeek ? LocalDate.of(0, end, 1).with(TemporalAdjusters.lastDayOfMonth()) : - LocalDate.of(0, end, 1).with(TemporalAdjusters.lastDayOfMonth()).plusDays(3); + LocalDate endingLimit = inLastWeek ? LocalDate.of(0 + yearOffset, end, 1).with(TemporalAdjusters.lastDayOfMonth()) : + LocalDate.of(0 + yearOffset, end, 1).with(TemporalAdjusters.lastDayOfMonth()).plusDays(3); LocalDate yearZeroEnd = endingLimit.with(TemporalAdjusters.previousOrSame(endsOn)); int yearZeroDifference = (int) yearZeroEnd.until(endingLimit, ChronoUnit.DAYS); // Longest/shortest month lengths and related @@ -190,13 +196,14 @@ static AccountingChronology create(DayOfWeek endsOn, Month end, boolean inLastWe ValueRange dayOfMonthRange = ValueRange.of(1, shortestMonthLength * 7, longestMonthLength * 7); int daysToEpoch = Math.toIntExact(0 - yearZeroEnd.plusDays(1).toEpochDay()); - return new AccountingChronology(endsOn, end, inLastWeek, division, leapWeekInMonth, yearZeroDifference, alignedWeekOfMonthRange, dayOfMonthRange, daysToEpoch); + return new AccountingChronology(endsOn, end, inLastWeek, division, leapWeekInMonth, yearZeroDifference, + alignedWeekOfMonthRange, dayOfMonthRange, daysToEpoch, yearOffset); } //----------------------------------------------------------------------- /** * Creates an instance from validated data, and cached data. - * + * * @param endsOn The day-of-week a given year ends on. * @param end The month-end the year is based on. * @param inLastWeek Whether the year ends in the last week of the month, or nearest the end-of-month. @@ -208,7 +215,7 @@ static AccountingChronology create(DayOfWeek endsOn, Month end, boolean inLastWe * @param daysToEpoch The number of days between the start of Accounting 1 and ISO 1970. */ private AccountingChronology(DayOfWeek endsOn, Month end, boolean inLastWeek, AccountingYearDivision division, int leapWeekInMonth, int yearZeroDifference, ValueRange alignedWeekOfMonthRange, - ValueRange dayOfMonthRange, int daysToEpoch) { + ValueRange dayOfMonthRange, int daysToEpoch, int yearOffset) { this.endsOn = endsOn; this.end = end; this.inLastWeek = inLastWeek; @@ -218,6 +225,7 @@ private AccountingChronology(DayOfWeek endsOn, Month end, boolean inLastWeek, Ac this.alignedWeekOfMonthRange = alignedWeekOfMonthRange; this.dayOfMonthRange = dayOfMonthRange; this.days0001ToIso1970 = daysToEpoch; + this.yearOffset = yearOffset; } /** @@ -226,7 +234,7 @@ private AccountingChronology(DayOfWeek endsOn, Month end, boolean inLastWeek, Ac * @return a built, validated instance. */ private Object readResolve() { - return AccountingChronology.create(endsOn, end, inLastWeek, getDivision(), leapWeekInMonth); + return AccountingChronology.create(endsOn, end, inLastWeek, getDivision(), leapWeekInMonth, yearOffset); } //----------------------------------------------------------------------- @@ -246,9 +254,9 @@ int getDays0001ToIso1970() { /** * Gets the ID of the chronology - 'Accounting'. *

- * The ID uniquely identifies the {@code Chronology}, + * The ID uniquely identifies the {@code Chronology}, * but does not differentiate between instances of {@code AccountingChronology}. - * It cannot be used to lookup the {@code Chronology} using {@link #of(String)}, + * It cannot be used to lookup the {@code Chronology} using {@link Chronology#of(String)}, * because each instance requires setup. * * @return the chronology ID - 'Accounting' @@ -264,7 +272,7 @@ public String getId() { *

* The Unicode Locale Data Markup Language (LDML) specification * does not define an identifier for 52/53 week calendars used for accounting purposes, - * and given that setup required is unlikely to do so. + * and given that setup required is unlikely to do so. * For this reason, the calendar type is null. * * @return null, as the calendar is unlikely to be specified in LDML @@ -459,7 +467,7 @@ public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId /** * Checks if the specified year is a leap year. *

- * An Accounting proleptic-year is leap if the time between the end of the previous year + * An Accounting proleptic-year is leap if the time between the end of the previous year * and the end of the current year is 371 days. * This method does not validate the year passed in, and only has a * well-defined result for years in the supported range. @@ -477,26 +485,26 @@ public boolean isLeapYear(long prolepticYear) { * Return the number of ISO Leap Years since Accounting Year 1. *

* This method calculates how many ISO leap years have passed since year 1. - * The count returned will be negative for years before 1. + * The count returned may be negative for years before 1. * This method does not validate the year passed in, and only has a * well-defined result for years in the supported range. - * + * * @param prolepticYear the proleptic-year to check, not validated for range * @return the count of leap years since year 1. */ private long getISOLeapYearCount(long prolepticYear) { - long offsetYear = prolepticYear - (end == Month.JANUARY ? 1 : 0) - 1; - return Math.floorDiv(offsetYear, 4) - Math.floorDiv(offsetYear, 100) + Math.floorDiv(offsetYear, 400) + (end == Month.JANUARY ? 1 : 0); + long offsetYear = prolepticYear - (end == Month.JANUARY? 1 : 0) - 1 + yearOffset; + return Math.floorDiv(offsetYear, 4) - Math.floorDiv(offsetYear, 100) + Math.floorDiv(offsetYear, 400) + (end == Month.JANUARY && yearOffset == 0 ? 1 : 0); } /** * Returns the count of leap years since year 1. *

* This method calculates how many Accounting leap years have passed since year 1. - * The count returned will be negative for years before 1. + * The count returned may be negative for years before 1. * This method does not validate the year passed in, and only has a * well-defined result for years in the supported range. - * + * * @param prolepticYear the proleptic-year to check, not validated for range * @return the count of leap years since year 1. */ @@ -556,7 +564,8 @@ public boolean equals(Object obj) { this.inLastWeek == other.inLastWeek && this.end == other.end && this.getDivision() == other.getDivision() && - this.leapWeekInMonth == other.leapWeekInMonth; + this.leapWeekInMonth == other.leapWeekInMonth && + this.yearOffset == other.yearOffset; } return false; } @@ -570,6 +579,7 @@ public int hashCode() { result = prime * result + end.hashCode(); result = prime * result + leapWeekInMonth; result = prime * result + getDivision().hashCode(); + result = prime * result + yearOffset; return result; } @@ -584,7 +594,8 @@ public String toString() { .append(", year divided in ") .append(getDivision()) .append(" with leap-week in month ") - .append(leapWeekInMonth); + .append(leapWeekInMonth) + .append(yearOffset == 0 ? " ending in the given ISO year" : " starting in the given ISO year"); return bld.toString(); } diff --git a/src/main/java/org/threeten/extra/chrono/AccountingChronologyBuilder.java b/src/main/java/org/threeten/extra/chrono/AccountingChronologyBuilder.java index 9016e8de..28ecd608 100644 --- a/src/main/java/org/threeten/extra/chrono/AccountingChronologyBuilder.java +++ b/src/main/java/org/threeten/extra/chrono/AccountingChronologyBuilder.java @@ -45,13 +45,15 @@ *

  • last-in-month vs. nearest-end-of-month - Whether the ending day-of-week is the last in the month, * or the nearest to the end of the month (will sometimes be in the next month. *
  • month end - Which Gregorian/ISO end-of-month the year ends in/is nearest to. - *
  • year division - How many 'months' (periods) to divide the accounting year into, + *
  • year division - How many 'months' (periods) to divide the accounting year into, * and how many weeks are in each. - *
  • leap-week month - Which month will have the leap 'week' added to it. + *
  • leap-week month - Which month will have the leap 'week' added to it. * In practice this is probably the last one, but this does not seem to be required. + *
  • year start/end offset - Whether the fiscal year starts or ends in the similarly numbered ISO year. + * If nearest-end-of-month is set and the ending month is December, the effective offset will shift over time. * *

    - * There are approximately 7 x 2 x 12 x 4 x 12/13 = 4032 combinations. + * There are approximately 7 x 2 x 12 x 4 x 12/13 x 2 = 8064 combinations. * *

    Implementation Requirements

    * This class is a mutable builder suitable for use from a single thread. @@ -63,7 +65,7 @@ public final class AccountingChronologyBuilder { */ private DayOfWeek endsOn; /** - * Whether the calendar ends in the last week of a given Gregorian/ISO month, + * Whether the calendar ends in the last week of a given Gregorian/ISO month, * or nearest to the last day of the month (will sometimes be in the next month). */ private boolean inLastWeek; @@ -80,6 +82,11 @@ public final class AccountingChronologyBuilder { */ private int leapWeekInMonth; + /** + * The offset to apply to the year. + */ + private int yearOffset; + /** * Constructs a new instance of the builder. */ @@ -89,9 +96,9 @@ public AccountingChronologyBuilder() { /** * Sets the day-of-week on which a given Accounting calendar year ends. - * + * * @param endsOn The day-of-week on which a given Accounting calendar year ends. - * + * * @return this, for chaining, not null. */ public AccountingChronologyBuilder endsOn(DayOfWeek endsOn) { @@ -103,9 +110,9 @@ public AccountingChronologyBuilder endsOn(DayOfWeek endsOn) { * Sets the Gregorian/ISO month-end which a given Accounting calendar year ends nearest to. * Calendars setup this way will occasionally end in the start of the next month. * For example, for July, the month ends on any day from July 28th to August 3rd. - * + * * @param end The Gregorian/ISO month-end a given Accounting calendar year ends nearest to. - * + * * @return this, for chaining, not null. */ public AccountingChronologyBuilder nearestEndOf(Month end) { @@ -118,9 +125,9 @@ public AccountingChronologyBuilder nearestEndOf(Month end) { * Sets the Gregorian/ISO month-end in which a given Accounting calendar year ends. * Calendars setup this way will always end in the last week of the given month. * For example, for July, the month ends on any day from July 25th to July 31st. - * + * * @param end The Gregorian/ISO month-end a given Accounting calendar year ends in the last week of. - * + * * @return this, for chaining, not null. */ public AccountingChronologyBuilder inLastWeekOf(Month end) { @@ -131,9 +138,9 @@ public AccountingChronologyBuilder inLastWeekOf(Month end) { /** * Sets how a given Accounting year will be divided. - * + * * @param division How to divide a given calendar year. - * + * * @return this, for chaining, not null. */ public AccountingChronologyBuilder withDivision(AccountingYearDivision division) { @@ -143,9 +150,9 @@ public AccountingChronologyBuilder withDivision(AccountingYearDivision division) /** * Sets the month in which the leap-week occurs. - * + * * @param leapWeekInMonth The month in which the leap-week occurs. - * + * * @return this, for chaining, not null. */ public AccountingChronologyBuilder leapWeekInMonth(int leapWeekInMonth) { @@ -153,14 +160,35 @@ public AccountingChronologyBuilder leapWeekInMonth(int leapWeekInMonth) { return this; } + /** + * Sets the proleptic accounting year to end in the matching Iso year. + * + * @return this, for chaining, not null. + */ + public AccountingChronologyBuilder accountingYearEndsInIsoYear() { + this.yearOffset = 0; + return this; + } + + + /** + * Sets the proleptic accounting year to start in the matching Iso year. + * + * @return this, for chaining, not null. + */ + public AccountingChronologyBuilder accountingYearStartsInIsoYear() { + this.yearOffset = 1; + return this; + } + /** * Completes this builder by creating the {@code AccountingChronology}. - * + * * @return the created chronology, not null. * @throws DateTimeException if the chronology cannot be built. */ public AccountingChronology toChronology() { - return AccountingChronology.create(endsOn, end, inLastWeek, division, leapWeekInMonth); + return AccountingChronology.create(endsOn, end, inLastWeek, division, leapWeekInMonth, yearOffset); } } diff --git a/src/main/java/org/threeten/extra/chrono/AccountingDate.java b/src/main/java/org/threeten/extra/chrono/AccountingDate.java index cf14c1df..409ff8a7 100644 --- a/src/main/java/org/threeten/extra/chrono/AccountingDate.java +++ b/src/main/java/org/threeten/extra/chrono/AccountingDate.java @@ -407,7 +407,7 @@ public int lengthOfMonth() { @Override public int lengthOfYear() { return (WEEKS_IN_YEAR + (isLeapYear() ? 1 : 0)) * DAYS_IN_WEEK; - }; + } //------------------------------------------------------------------------- @Override @@ -445,7 +445,7 @@ public AccountingDate minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/AccountingYearDivision.java b/src/main/java/org/threeten/extra/chrono/AccountingYearDivision.java index 4688966d..f4155e06 100644 --- a/src/main/java/org/threeten/extra/chrono/AccountingYearDivision.java +++ b/src/main/java/org/threeten/extra/chrono/AccountingYearDivision.java @@ -200,7 +200,7 @@ int getMonthFromElapsedWeeks(int weeksElapsed) { */ int getMonthFromElapsedWeeks(int weeksElapsed, int leapWeekInMonth) { if (weeksElapsed < 0 || weeksElapsed >= (leapWeekInMonth == 0 ? 52 : 53)) { - throw new DateTimeException("Count of '" + elapsedWeeks + "' elapsed weeks not valid," + throw new DateTimeException("Count of '" + elapsedWeeks.length + "' elapsed weeks not valid," + " should be in the range [0, " + (leapWeekInMonth == 0 ? 52 : 53) + ")"); } leapWeekInMonth = (leapWeekInMonth == 0 ? 0 : monthsInYearRange.checkValidIntValue(leapWeekInMonth, ChronoField.MONTH_OF_YEAR)); diff --git a/src/main/java/org/threeten/extra/chrono/BritishCutoverChronology.java b/src/main/java/org/threeten/extra/chrono/BritishCutoverChronology.java index 5cd61052..ee8f936a 100644 --- a/src/main/java/org/threeten/extra/chrono/BritishCutoverChronology.java +++ b/src/main/java/org/threeten/extra/chrono/BritishCutoverChronology.java @@ -40,6 +40,7 @@ import java.time.chrono.AbstractChronology; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.IsoChronology; import java.time.format.ResolverStyle; @@ -183,7 +184,7 @@ public LocalDate getCutover() { * Gets the ID of the chronology - 'BritishCutover'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'BritishCutover' * @see #getCalendarType() diff --git a/src/main/java/org/threeten/extra/chrono/BritishCutoverDate.java b/src/main/java/org/threeten/extra/chrono/BritishCutoverDate.java index 17d69f55..fb4eb5a1 100644 --- a/src/main/java/org/threeten/extra/chrono/BritishCutoverDate.java +++ b/src/main/java/org/threeten/extra/chrono/BritishCutoverDate.java @@ -370,6 +370,8 @@ BritishCutoverDate resolvePrevious(int year, int month, int dayOfMonth) { case 11: dayOfMonth = Math.min(dayOfMonth, 30); break; + default: + break; } return create(year, month, dayOfMonth); } @@ -469,7 +471,7 @@ public BritishCutoverDate minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override @@ -520,7 +522,7 @@ public R query(TemporalQuery query) { if (query == TemporalQueries.localDate()) { return (R) isoDate; } - return ChronoLocalDate.super.query(query); + return super.query(query); } //------------------------------------------------------------------------- diff --git a/src/main/java/org/threeten/extra/chrono/CopticChronology.java b/src/main/java/org/threeten/extra/chrono/CopticChronology.java index 46479e74..4cb39ce7 100644 --- a/src/main/java/org/threeten/extra/chrono/CopticChronology.java +++ b/src/main/java/org/threeten/extra/chrono/CopticChronology.java @@ -38,6 +38,7 @@ import java.time.ZoneId; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.format.ResolverStyle; import java.time.temporal.TemporalAccessor; @@ -108,7 +109,7 @@ private Object readResolve() { * Gets the ID of the chronology - 'Coptic'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'Coptic' * @see #getCalendarType() @@ -123,7 +124,7 @@ public String getId() { *

    * The calendar type is an identifier defined by the * Unicode Locale Data Markup Language (LDML) specification. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * It can also be used as part of a locale, accessible via * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. * diff --git a/src/main/java/org/threeten/extra/chrono/CopticDate.java b/src/main/java/org/threeten/extra/chrono/CopticDate.java index 003352ad..1698811b 100644 --- a/src/main/java/org/threeten/extra/chrono/CopticDate.java +++ b/src/main/java/org/threeten/extra/chrono/CopticDate.java @@ -380,7 +380,7 @@ public CopticDate minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/DiscordianChronology.java b/src/main/java/org/threeten/extra/chrono/DiscordianChronology.java index 6b0152cb..13d23323 100644 --- a/src/main/java/org/threeten/extra/chrono/DiscordianChronology.java +++ b/src/main/java/org/threeten/extra/chrono/DiscordianChronology.java @@ -39,6 +39,7 @@ import java.time.chrono.AbstractChronology; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; @@ -172,7 +173,7 @@ private Object readResolve() { * Gets the ID of the chronology - 'Discordian'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'Discordian' * @see #getCalendarType() diff --git a/src/main/java/org/threeten/extra/chrono/DiscordianDate.java b/src/main/java/org/threeten/extra/chrono/DiscordianDate.java index a6372678..4023fc35 100644 --- a/src/main/java/org/threeten/extra/chrono/DiscordianDate.java +++ b/src/main/java/org/threeten/extra/chrono/DiscordianDate.java @@ -326,7 +326,7 @@ static DiscordianDate create(int prolepticYear, int month, int dayOfMonth) { if (month == 0 || dayOfMonth == 0) { if (month != 0 || dayOfMonth != 0) { - throw new DateTimeException("Invalid date '" + month + " " + dayOfMonth + "' as St. Tib's Day is the only special day inserted in a nonexistant month."); + throw new DateTimeException("Invalid date '" + month + " " + dayOfMonth + "' as St. Tib's Day is the only special day inserted in a non-existent month."); } else if (!DiscordianChronology.INSTANCE.isLeapYear(prolepticYear)) { throw new DateTimeException("Invalid date 'St. Tibs Day' as '" + prolepticYear + "' is not a leap year"); } @@ -665,7 +665,7 @@ public DiscordianDate minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/EthiopicChronology.java b/src/main/java/org/threeten/extra/chrono/EthiopicChronology.java index 3442006b..7f33b7d1 100644 --- a/src/main/java/org/threeten/extra/chrono/EthiopicChronology.java +++ b/src/main/java/org/threeten/extra/chrono/EthiopicChronology.java @@ -38,6 +38,7 @@ import java.time.ZoneId; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.format.ResolverStyle; import java.time.temporal.TemporalAccessor; @@ -108,7 +109,7 @@ private Object readResolve() { * Gets the ID of the chronology - 'Ethiopic'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'Ethiopic' * @see #getCalendarType() @@ -123,7 +124,7 @@ public String getId() { *

    * The calendar type is an identifier defined by the * Unicode Locale Data Markup Language (LDML) specification. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * It can also be used as part of a locale, accessible via * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. * diff --git a/src/main/java/org/threeten/extra/chrono/EthiopicDate.java b/src/main/java/org/threeten/extra/chrono/EthiopicDate.java index 78aacb78..b9bb1318 100644 --- a/src/main/java/org/threeten/extra/chrono/EthiopicDate.java +++ b/src/main/java/org/threeten/extra/chrono/EthiopicDate.java @@ -382,7 +382,7 @@ public EthiopicDate minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/InternationalFixedChronology.java b/src/main/java/org/threeten/extra/chrono/InternationalFixedChronology.java index b585be4e..fdef876a 100644 --- a/src/main/java/org/threeten/extra/chrono/InternationalFixedChronology.java +++ b/src/main/java/org/threeten/extra/chrono/InternationalFixedChronology.java @@ -39,6 +39,7 @@ import java.time.chrono.AbstractChronology; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; @@ -183,7 +184,7 @@ private Object readResolve() { * Gets the ID of the chronology - 'Ifc'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'Ifc' * @see #getCalendarType() @@ -466,8 +467,7 @@ public int prolepticYear(Era era, int yearOfEra) { if (!(era instanceof InternationalFixedEra)) { throw new ClassCastException("Invalid era: " + era); } - YEAR_RANGE.checkValidIntValue(yearOfEra, ChronoField.YEAR_OF_ERA); - return yearOfEra; + return YEAR_RANGE.checkValidIntValue(yearOfEra, ChronoField.YEAR_OF_ERA); } /** diff --git a/src/main/java/org/threeten/extra/chrono/InternationalFixedDate.java b/src/main/java/org/threeten/extra/chrono/InternationalFixedDate.java index 5fd9f597..e42659e8 100644 --- a/src/main/java/org/threeten/extra/chrono/InternationalFixedDate.java +++ b/src/main/java/org/threeten/extra/chrono/InternationalFixedDate.java @@ -634,7 +634,6 @@ InternationalFixedDate plusWeeks(long weeks) { int newYear = Math.toIntExact(Math.floorDiv(calcEm, WEEKS_IN_YEAR)); int newWeek = Math.toIntExact(Math.floorMod(calcEm, WEEKS_IN_YEAR)); int newMonth = 1 + Math.floorDiv(newWeek, WEEKS_IN_MONTH); - //int newDay = 1 + ((newWeek * DAYS_IN_WEEK + ((day - 1) % DAYS_IN_WEEK)) % DAYS_IN_MONTH); int newDay = 1 + ((newWeek * DAYS_IN_WEEK + 8 + (isLeapDay ? 0 : isYearDay ? -1 : (day - 1) % DAYS_IN_WEEK) - 1) % DAYS_IN_MONTH); return create(newYear, newMonth, newDay); @@ -677,7 +676,7 @@ public InternationalFixedDate minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/InternationalFixedEra.java b/src/main/java/org/threeten/extra/chrono/InternationalFixedEra.java index b851c056..a8accea1 100644 --- a/src/main/java/org/threeten/extra/chrono/InternationalFixedEra.java +++ b/src/main/java/org/threeten/extra/chrono/InternationalFixedEra.java @@ -37,7 +37,7 @@ /** * An era in the International Fixed calendar system. *

    - * The International Fixed calendar system only has one era. + * The International Fixed calendar system officially only has one era. * The current era, for years from 1 onwards, is known as 'Current Era'. * All previous years are invalid. *

    @@ -85,7 +85,7 @@ public static InternationalFixedEra of(final int era) { */ @Override public int getValue() { - return ordinal(); + return 1; } } diff --git a/src/main/java/org/threeten/extra/chrono/JulianChronology.java b/src/main/java/org/threeten/extra/chrono/JulianChronology.java index d9bca63d..ca73e03f 100644 --- a/src/main/java/org/threeten/extra/chrono/JulianChronology.java +++ b/src/main/java/org/threeten/extra/chrono/JulianChronology.java @@ -39,6 +39,7 @@ import java.time.chrono.AbstractChronology; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; @@ -128,7 +129,7 @@ private Object readResolve() { * Gets the ID of the chronology - 'Julian'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'Julian' * @see #getCalendarType() diff --git a/src/main/java/org/threeten/extra/chrono/JulianDate.java b/src/main/java/org/threeten/extra/chrono/JulianDate.java index aaf287f1..9f01ee0a 100644 --- a/src/main/java/org/threeten/extra/chrono/JulianDate.java +++ b/src/main/java/org/threeten/extra/chrono/JulianDate.java @@ -255,6 +255,8 @@ private static JulianDate resolvePreviousValid(int prolepticYear, int month, int case 11: day = Math.min(day, 30); break; + default: + break; } return new JulianDate(prolepticYear, month, day); } @@ -285,6 +287,8 @@ static JulianDate create(int prolepticYear, int month, int dayOfMonth) { case 11: dom = 30; break; + default: + break; } if (dayOfMonth > dom) { if (dayOfMonth == 29) { @@ -437,7 +441,7 @@ public JulianDate minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/PaxChronology.java b/src/main/java/org/threeten/extra/chrono/PaxChronology.java index c7b4c48e..ea66e8d8 100644 --- a/src/main/java/org/threeten/extra/chrono/PaxChronology.java +++ b/src/main/java/org/threeten/extra/chrono/PaxChronology.java @@ -39,6 +39,7 @@ import java.time.chrono.AbstractChronology; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; @@ -74,7 +75,7 @@ *

  • leap-year - Leap years occur in every year whose last two digits are divisible by {@code 6}, are {@code 99}, or are {@code 00} and the year is not divisible by 400. * *

    - * For more information, please read the Pax Calendar Wikipedia article. + * For more information, please read the Pax Calendar Wikipedia article. * *

    Implementation Requirements

    * This class is immutable and thread-safe. @@ -164,7 +165,7 @@ private Object readResolve() { * Gets the ID of the chronology - 'Pax'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'Pax' * @see #getCalendarType() diff --git a/src/main/java/org/threeten/extra/chrono/PaxDate.java b/src/main/java/org/threeten/extra/chrono/PaxDate.java index c0c95c23..f5e31f1d 100644 --- a/src/main/java/org/threeten/extra/chrono/PaxDate.java +++ b/src/main/java/org/threeten/extra/chrono/PaxDate.java @@ -72,7 +72,7 @@ * The Pax differs from the Gregorian in terms of month count and length, and the leap year rule. * Dates are aligned such that {@code 0001-01-01 (Pax)} is {@code 0000-12-31 (ISO)}. *

    - * More information is available in the Pax Calendar Wikipedia article. + * More information is available in the Pax Calendar Wikipedia article. * *

    Implementation Requirements

    * This class is immutable and thread-safe. @@ -347,11 +347,6 @@ private static PaxDate resolvePreviousValid(int prolepticYear, int month, int da private static long getLeapMonthsBefore(long prolepticMonth) { long offsetMonth = prolepticMonth - (prolepticMonth <= 0 ? 13 : 13 - 1); // First, see getLeapYearsBefore(...) for explanations. - // return 18 * Math.floorDiv(offsetMonth, 100 * MONTHS_IN_YEAR + (getLeapYearsBefore(100) + 1)) - // - Math.floorDiv(offsetMonth, 400 * MONTHS_IN_YEAR + (getLeapYearsBefore(400) + 1)) - // + (((Math.floorMod(offsetMonth, 100 * MONTHS_IN_YEAR + (getLeapYearsBefore(100) + 1)) - (offsetMonth <= 0 ? 100 * MONTHS_IN_YEAR + getLeapYearsBefore(100) : 0)) - // / (99 * MONTHS_IN_YEAR + (getLeapYearsBefore(99) + 1))) + (offsetMonth <= 0 ? 1 : 0)) - // + (Math.floorMod(offsetMonth, 100 * MONTHS_IN_YEAR + (getLeapYearsBefore(100) + 1)) + (offsetMonth <= 0 ? 2 * MONTHS_IN_YEAR - 1 : 0)) / (6 * MONTHS_IN_YEAR + 1); return 18L * Math.floorDiv(offsetMonth, 1318) - Math.floorDiv(offsetMonth, 5272) + (((Math.floorMod(offsetMonth, 1318) - (offsetMonth <= 0 ? 1317 : 0)) / 1304) + (offsetMonth <= 0 ? 1 : 0)) @@ -622,7 +617,7 @@ public PaxDate minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/Symmetry010Chronology.java b/src/main/java/org/threeten/extra/chrono/Symmetry010Chronology.java index 894d0a56..e1dd3ade 100644 --- a/src/main/java/org/threeten/extra/chrono/Symmetry010Chronology.java +++ b/src/main/java/org/threeten/extra/chrono/Symmetry010Chronology.java @@ -39,6 +39,7 @@ import java.time.chrono.AbstractChronology; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.IsoEra; import java.time.temporal.ChronoField; @@ -72,7 +73,7 @@ *
  • day-of-year - There are 364 days in a standard Symmetry010 year and 371 days in a leap year. * The days are numbered accordingly. *
  • leap-year - Leap years occur every 5 or 6 years, evenly spread over 293 years according the formula: - * (52 > ((52 * year + 146) % 293)). + * (52 > ((52 * year + 146) % 293)). *
  • Week day - every year and every quarter starts on a Monday. * In each quarter, the first month starts on a Monday, the second month on a Wednesday and the 3rd on a Saturday. * There are no days outside of the week or month. @@ -151,8 +152,6 @@ public final class Symmetry010Chronology * There are 6 full 293-year cycles from CE 1 to 1758, with 6 * 52 leap years, i.e. 312. * There are 37 leap years from CE 1758 to 1970. */ - //public static final long DAYS_0001_TO_1970 = (DAYS_PER_CYCLE * 6L) + 211L * DAYS_IN_YEAR + 37 * DAYS_IN_WEEK; - //public static final long DAYS_0001_TO_1970_ISO = IsoChronology.INSTANCE.date(1,1,1).toEpochDay() * -1; public static final long DAYS_0001_TO_1970 = (146097 * 5L) - (31L * 365L + 7L) - 1; /** * Highest year in the range. @@ -215,7 +214,7 @@ private Object readResolve() { * Gets the ID of the chronology - 'Sym010'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'Sym010' * @see #getCalendarType() @@ -498,10 +497,7 @@ public int prolepticYear(Era era, int yearOfEra) { if (!(era instanceof IsoEra)) { throw new ClassCastException("Invalid era: " + era); } - - YEAR_RANGE.checkValidIntValue(yearOfEra, ChronoField.YEAR_OF_ERA); - - return yearOfEra; + return YEAR_RANGE.checkValidIntValue(yearOfEra, ChronoField.YEAR_OF_ERA); } /** diff --git a/src/main/java/org/threeten/extra/chrono/Symmetry010Date.java b/src/main/java/org/threeten/extra/chrono/Symmetry010Date.java index 5777b443..16a85e25 100644 --- a/src/main/java/org/threeten/extra/chrono/Symmetry010Date.java +++ b/src/main/java/org/threeten/extra/chrono/Symmetry010Date.java @@ -92,8 +92,8 @@ * The 13th day of a month is always a Saturday. *

    * More information is available on Wikipedia at - * Symmetry010 or on the calendar's - * home page. + * Symmetry010 or on the calendar's + * home page. *

    * *

    Implementation Requirements

    @@ -575,7 +575,7 @@ public Symmetry010Date minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/Symmetry454Chronology.java b/src/main/java/org/threeten/extra/chrono/Symmetry454Chronology.java index f395833f..75e87c0b 100644 --- a/src/main/java/org/threeten/extra/chrono/Symmetry454Chronology.java +++ b/src/main/java/org/threeten/extra/chrono/Symmetry454Chronology.java @@ -39,6 +39,7 @@ import java.time.chrono.AbstractChronology; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.IsoEra; import java.time.temporal.ChronoField; @@ -71,7 +72,7 @@ *
  • day-of-year - There are 364 days in a standard Symmetry454 year and 371 days in a leap year. * The days are numbered accordingly. *
  • leap-year - Leap years occur every 5 or 6 years, evenly spread over 293 years according the formula: - * (52 > ((52 * year + 146) % 293)). + * (52 > ((52 * year + 146) % 293)). *
  • Week day - every month starts on a Monday. There are no days outside of the week or month. * * @@ -144,8 +145,6 @@ public final class Symmetry454Chronology * There are 6 full 293-year cycles from CE 1 to 1758, with 6 * 52 leap years, i.e. 312. * There are 37 leap years from CE 1758 to 1970. */ - //public static final long DAYS_0001_TO_1970 = (DAYS_PER_CYCLE * 6L) + 211L * DAYS_IN_YEAR + 37 * DAYS_IN_WEEK; - //public static final long DAYS_0001_TO_1970_ISO = IsoChronology.INSTANCE.date(1,1,1).toEpochDay() * -1; public static final long DAYS_0001_TO_1970 = (146097 * 5L) - (31L * 365L + 7L) - 1; /** * Highest year in the range. @@ -208,7 +207,7 @@ private Object readResolve() { * Gets the ID of the chronology - 'Sym454'. *

    * The ID uniquely identifies the {@code Chronology}. - * It can be used to lookup the {@code Chronology} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. * * @return the chronology ID - 'Sym454' * @see #getCalendarType() @@ -491,10 +490,7 @@ public int prolepticYear(Era era, int yearOfEra) { if (!(era instanceof IsoEra)) { throw new ClassCastException("Invalid era: " + era); } - - YEAR_RANGE.checkValidIntValue(yearOfEra, ChronoField.YEAR_OF_ERA); - - return yearOfEra; + return YEAR_RANGE.checkValidIntValue(yearOfEra, ChronoField.YEAR_OF_ERA); } /** diff --git a/src/main/java/org/threeten/extra/chrono/Symmetry454Date.java b/src/main/java/org/threeten/extra/chrono/Symmetry454Date.java index 517c1e07..e4fa1a99 100644 --- a/src/main/java/org/threeten/extra/chrono/Symmetry454Date.java +++ b/src/main/java/org/threeten/extra/chrono/Symmetry454Date.java @@ -91,8 +91,8 @@ * The 13th day of a month is always a Saturday. *

    * More information is available on Wikipedia at - * Symmetry454 or on the calendar's - * home page. + * Symmetry454 or on the calendar's + * home page. *

    * *

    Implementation Requirements

    @@ -593,7 +593,7 @@ public Symmetry454Date minus(long amountToSubtract, TemporalUnit unit) { @Override // for covariant return type @SuppressWarnings("unchecked") public ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime) ChronoLocalDate.super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override diff --git a/src/main/java/org/threeten/extra/chrono/package-info.java b/src/main/java/org/threeten/extra/chrono/package-info.java new file mode 100644 index 00000000..46c815a7 --- /dev/null +++ b/src/main/java/org/threeten/extra/chrono/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Additional chronologies (calendar systems) that extend {@code java.time.*}. + */ +package org.threeten.extra.chrono; diff --git a/src/main/java/org/threeten/extra/package-info.java b/src/main/java/org/threeten/extra/package-info.java new file mode 100644 index 00000000..bb7d000e --- /dev/null +++ b/src/main/java/org/threeten/extra/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Value types and utilities that extend {@code java.time.*}. + */ +package org.threeten.extra; diff --git a/src/main/java/org/threeten/extra/scale/SystemUtcRules.java b/src/main/java/org/threeten/extra/scale/SystemUtcRules.java index 1c9f65f9..f1ac8dbe 100644 --- a/src/main/java/org/threeten/extra/scale/SystemUtcRules.java +++ b/src/main/java/org/threeten/extra/scale/SystemUtcRules.java @@ -58,6 +58,10 @@ */ final class SystemUtcRules extends UtcRules implements Serializable { + /** + * The leap seconds config file. + */ + private static final String LEAP_SECONDS_TXT = "org/threeten/extra/scale/LeapSeconds.txt"; /** * Leap second file format. */ @@ -213,7 +217,17 @@ private static Data loadLeapSeconds() { Data bestData = null; URL url = null; try { - Enumeration en = Thread.currentThread().getContextClassLoader().getResources("org/threeten/extra/scale/LeapSeconds.txt"); + // this is the new location of the file, working on Java 8, Java 9 class path and Java 9 module path + Enumeration en = Thread.currentThread().getContextClassLoader().getResources("META-INF/" + LEAP_SECONDS_TXT); + while (en.hasMoreElements()) { + url = en.nextElement(); + Data candidate = loadLeapSeconds(url); + if (bestData == null || candidate.getNewestDate() > bestData.getNewestDate()) { + bestData = candidate; + } + } + // this location does not work on Java 9 module path because the resource is encapsulated + en = Thread.currentThread().getContextClassLoader().getResources(LEAP_SECONDS_TXT); while (en.hasMoreElements()) { url = en.nextElement(); Data candidate = loadLeapSeconds(url); @@ -221,6 +235,14 @@ private static Data loadLeapSeconds() { bestData = candidate; } } + // this location is the canonical one, and class-based loading works on Java 9 module path + url = SystemUtcRules.class.getResource("/" + LEAP_SECONDS_TXT); + if (url != null) { + Data candidate = loadLeapSeconds(url); + if (bestData == null || candidate.getNewestDate() > bestData.getNewestDate()) { + bestData = candidate; + } + } } catch (Exception ex) { throw new RuntimeException("Unable to load time-zone rule data: " + url, ex); } @@ -239,7 +261,7 @@ private static Data loadLeapSeconds() { * @throws Exception if an error occurs */ private static Data loadLeapSeconds(URL url) throws ClassNotFoundException, IOException { - List lines = new ArrayList<>(); + List lines; try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) { lines = reader.lines().collect(Collectors.toList()); } diff --git a/src/main/java/org/threeten/extra/scale/TaiInstant.java b/src/main/java/org/threeten/extra/scale/TaiInstant.java index e4bb7e5a..125d43d7 100644 --- a/src/main/java/org/threeten/extra/scale/TaiInstant.java +++ b/src/main/java/org/threeten/extra/scale/TaiInstant.java @@ -40,6 +40,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * An instantaneous point on the time-line measured in the TAI time-scale. *

    @@ -144,7 +147,7 @@ public static TaiInstant ofTaiSeconds(long taiSeconds, long nanoAdjustment) { * This method uses the latest available system rules. * The conversion first maps from UTC-SLS to UTC, then converts to TAI. *

    - * Conversion from an {@code Instant} will not be completely accurate near + * Conversion from an {@link Instant} will not be completely accurate near * a leap second in accordance with UTC-SLS. * * @param instant the instant to convert, not null @@ -189,12 +192,13 @@ public static TaiInstant of(UtcInstant instant) { * The seconds part must contain only numbers and a possible leading negative sign. * The nanoseconds part must contain exactly nine digits. * The trailing literal must be exactly specified. - * This format parses the {@code toString} format. + * This format parses the {@link #toString()} format. * * @param text the text to parse such as "12345.123456789s(TAI)", not null * @return the parsed instant, not null * @throws DateTimeParseException if the text cannot be parsed */ + @FromString public static TaiInstant parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PARSER.matcher(text); @@ -229,7 +233,7 @@ private TaiInstant(long taiSeconds, int nanoOfSecond) { *

    * The TAI second count is a simple incrementing count of seconds where * second 0 is 1958-01-01T00:00:00(TAI). - * The nanosecond part of the day is returned by {@code getNanosOfSecond}. + * The nanosecond part of the second is returned by {@link #getNano()}. * * @return the seconds from the epoch of 1958-01-01T00:00:00(TAI) */ @@ -243,7 +247,7 @@ public long getTaiSeconds() { *

    * The TAI second count is a simple incrementing count of seconds where * second 0 is 1958-01-01T00:00:00(TAI). - * The nanosecond part of the day is returned by {@code getNanosOfSecond}. + * The nanosecond offset of the second is returned by {@code getNano}. *

    * This instance is immutable and unaffected by this method call. * @@ -259,7 +263,7 @@ public TaiInstant withTaiSeconds(long taiSeconds) { * of the second. *

    * The nanosecond-of-second value measures the total number of nanoseconds from - * the second returned by {@code getTaiSeconds()}. + * the second returned by {@link #getTaiSeconds()}. * * @return the nanoseconds within the second, from 0 to 999,999,999 */ @@ -271,7 +275,7 @@ public int getNano() { * Returns a copy of this {@code TaiInstant} with the nano-of-second value changed. *

    * The nanosecond-of-second value measures the total number of nanoseconds from - * the second returned by {@code getTaiSeconds()}. + * the second returned by {@link #getTaiSeconds()}. *

    * This instance is immutable and unaffected by this method call. * @@ -364,7 +368,7 @@ public Duration durationUntil(TaiInstant otherInstant) { * This method uses the latest available system rules. * The conversion first maps from TAI to UTC, then converts to UTC-SLS. *

    - * Conversion to an {@code Instant} will not be completely accurate near + * Conversion to an {@link Instant} will not be completely accurate near * a leap second in accordance with UTC-SLS. * * @return an {@code Instant} representing the best approximation of this instant, not null @@ -381,7 +385,7 @@ public Instant toInstant() { * Converting a TAI instant to UTC requires leap second rules. * This method uses the latest available system rules. *

    - * The {@code UtcInstant} will represent exactly the same point on the + * The {@link UtcInstant} will represent exactly the same point on the * time-line as per the available leap-second rules. * If the leap-second rules change then conversion back to TAI may * result in a different instant. @@ -410,6 +414,32 @@ public int compareTo(TaiInstant otherInstant) { return nanos - otherInstant.nanos; } + /** + * Checks if this instant is after the specified instant. + *

    + * The comparison is based on the time-line position of the instants. + * + * @param otherInstant the other instant to compare to, not null + * @return true if this instant is after the specified instant + * @throws NullPointerException if otherInstant is null + */ + public boolean isAfter(TaiInstant otherInstant) { + return compareTo(otherInstant) > 0; + } + + /** + * Checks if this instant is before the specified instant. + *

    + * The comparison is based on the time-line position of the instants. + * + * @param otherInstant the other instant to compare to, not null + * @return true if this instant is before the specified instant + * @throws NullPointerException if otherInstant is null + */ + public boolean isBefore(TaiInstant otherInstant) { + return compareTo(otherInstant) < 0; + } + //----------------------------------------------------------------------- /** * Checks if this instant is equal to the specified {@code TaiInstant}. @@ -452,6 +482,7 @@ public int hashCode() { * @return a representation of this instant, not null */ @Override + @ToString public String toString() { StringBuilder buf = new StringBuilder(); buf.append(seconds); diff --git a/src/main/java/org/threeten/extra/scale/UtcInstant.java b/src/main/java/org/threeten/extra/scale/UtcInstant.java index 0607e60d..db7f28ce 100644 --- a/src/main/java/org/threeten/extra/scale/UtcInstant.java +++ b/src/main/java/org/threeten/extra/scale/UtcInstant.java @@ -47,6 +47,9 @@ import java.time.temporal.JulianFields; import java.time.temporal.TemporalAccessor; +import org.joda.convert.FromString; +import org.joda.convert.ToString; + /** * An instantaneous point on the time-line measured in the UTC time-scale * with leap seconds. @@ -123,6 +126,10 @@ public final class UtcInstant * This is always positive and includes leap seconds. */ private final long nanoOfDay; + /** + * A cache of the result from {@link #toString()} + */ + private transient String toString; //----------------------------------------------------------------------- /** @@ -192,17 +199,18 @@ public static UtcInstant of(TaiInstant instant) { //------------------------------------------------------------------------- /** - * Obtains an instance of {@code UtcInstant} from a text string - * {@code 2007-12-03T10:15:30.00Z}. + * Obtains an instance of {@code UtcInstant} from a text string, + * such as {@code 2007-12-03T10:15:30.00Z}. *

    * The string must represent a valid instant in UTC and is parsed using * {@link DateTimeFormatter#ISO_INSTANT} with leap seconds handled. * - * @param text the text to parse such as "12345.123456789s(TAI)", not null + * @param text the text to parse such as "2007-12-03T10:15:30.00Z", not null * @return the parsed instant, not null * @throws DateTimeParseException if the text cannot be parsed * @throws DateTimeException if parsed text represents an invalid leap second */ + @FromString public static UtcInstant parse(CharSequence text) { TemporalAccessor parsed = DateTimeFormatter.ISO_INSTANT.parse(text); long epochSecond = parsed.getLong(INSTANT_SECONDS); @@ -302,7 +310,7 @@ public UtcInstant withNanoOfDay(long nanoOfDay) { * @return true if this instant is within a leap second */ public boolean isLeapSecond() { - return nanoOfDay > SECS_PER_DAY * NANOS_PER_SECOND; + return nanoOfDay >= SECS_PER_DAY * NANOS_PER_SECOND; } //----------------------------------------------------------------------- @@ -418,6 +426,32 @@ public int compareTo(UtcInstant otherInstant) { return Long.compare(nanoOfDay, otherInstant.nanoOfDay); } + /** + * Checks if this instant is after the specified instant. + *

    + * The comparison is based on the time-line position of the instants. + * + * @param otherInstant the other instant to compare to, not null + * @return true if this instant is after the specified instant + * @throws NullPointerException if otherInstant is null + */ + public boolean isAfter(UtcInstant otherInstant) { + return compareTo(otherInstant) > 0; + } + + /** + * Checks if this instant is before the specified instant. + *

    + * The comparison is based on the time-line position of the instants. + * + * @param otherInstant the other instant to compare to, not null + * @return true if this instant is before the specified instant + * @throws NullPointerException if otherInstant is null + */ + public boolean isBefore(UtcInstant otherInstant) { + return compareTo(otherInstant) < 0; + } + //----------------------------------------------------------------------- /** * Checks if this instant is equal to the specified {@code UtcInstant}. @@ -461,8 +495,20 @@ public int hashCode() { * @return a representation of this instant, not null */ @Override + @ToString public String toString() { - LocalDate date = LocalDate.MAX.with(JulianFields.MODIFIED_JULIAN_DAY, mjDay); // TODO: capacity/import issues + // racy single-check idiom + String currentStringValue = toString; + if (currentStringValue == null) { + currentStringValue = buildToString(); + toString = currentStringValue; + } + return currentStringValue; + } + + // produces the string representation of this instant + private String buildToString() { + LocalDate date = LocalDate.MAX.with(JulianFields.MODIFIED_JULIAN_DAY, mjDay); // TODO: capacity/import issues StringBuilder buf = new StringBuilder(30); int sod = (int) (nanoOfDay / NANOS_PER_SECOND); int hourValue = sod / (60 * 60); diff --git a/src/main/java/org/threeten/extra/scale/UtcRules.java b/src/main/java/org/threeten/extra/scale/UtcRules.java index a977fb71..212ffc2a 100644 --- a/src/main/java/org/threeten/extra/scale/UtcRules.java +++ b/src/main/java/org/threeten/extra/scale/UtcRules.java @@ -45,9 +45,11 @@ * These are used by default in {@code UtcInstant} and {@code TaiInstant}. * Using other rules requires manual use of this class. *

    - * The system rules can be updated using the file {@code org/threeten/extra/scale/LeapSeconds.txt}. - * You can create your own version of this file and place it on the classpath - * and it will be used. + * The system rules can be updated using a {@code LeapSeconds.txt}} file. + * You can create your own version of this file and place it in on the classpath + * and it will be used. Due to Java 9 module restrictions, the file is located + * under META-INF to avoid module encapsulation problems - + * {@code META-INF/org/threeten/extra/scale/LeapSeconds.txt}. * *

    Implementation Requirements:

    * This is an abstract class and must be implemented with care diff --git a/src/main/java/org/threeten/extra/scale/package-info.java b/src/main/java/org/threeten/extra/scale/package-info.java new file mode 100644 index 00000000..525b80bc --- /dev/null +++ b/src/main/java/org/threeten/extra/scale/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Support for time scales that extend {@code java.time.*}. + */ +package org.threeten.extra.scale; diff --git a/src/main/resources/org/threeten/extra/wordbased.properties b/src/main/resources/org/threeten/extra/wordbased.properties new file mode 100644 index 00000000..bc4624c1 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,and +WordBased.commaspaceand=, and +WordBased.commaspace=, +WordBased.spaceandspace=\ and +WordBased.year=\ year +WordBased.years=\ years +WordBased.month=\ month +WordBased.months=\ months +WordBased.week=\ week +WordBased.weeks=\ weeks +WordBased.day=\ day +WordBased.days=\ days +WordBased.hour=\ hour +WordBased.hours=\ hours +WordBased.minute=\ minute +WordBased.minutes=\ minutes +WordBased.second=\ second +WordBased.seconds=\ seconds +WordBased.millisecond=\ millisecond +WordBased.milliseconds=\ milliseconds diff --git a/src/main/resources/org/threeten/extra/wordbased_bg.properties b/src/main/resources/org/threeten/extra/wordbased_bg.properties new file mode 100644 index 00000000..c6b94a05 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_bg.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,и +WordBased.commaspaceand=, и +WordBased.commaspace=, +WordBased.spaceandspace=\ и +WordBased.year=\ година +WordBased.years=\ години +WordBased.month=\ месец +WordBased.months=\ месеца +WordBased.week=\ седмица +WordBased.weeks=\ седмици +WordBased.day=\ ден +WordBased.days=\ дни +WordBased.hour=\ час +WordBased.hours=\ часа +WordBased.minute=\ минута +WordBased.minutes=\ минути +WordBased.second=\ секунда +WordBased.seconds=\ секунди +WordBased.millisecond=\ милисекунда +WordBased.milliseconds=\ милисекунди diff --git a/src/main/resources/org/threeten/extra/wordbased_ca.properties b/src/main/resources/org/threeten/extra/wordbased_ca.properties new file mode 100644 index 00000000..381b7475 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_ca.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,i +WordBased.commaspaceand=, i +WordBased.commaspace=, +WordBased.spaceandspace=\ i +WordBased.year=\ any +WordBased.years=\ anys +WordBased.month=\ mes +WordBased.months=\ mesos +WordBased.week=\ setmana +WordBased.weeks=\ setmanes +WordBased.day=\ dia +WordBased.days=\ dies +WordBased.hour=\ hora +WordBased.hours=\ hores +WordBased.minute=\ minut +WordBased.minutes=\ minuts +WordBased.second=\ segon +WordBased.seconds=\ segons +WordBased.millisecond=\ mil·lisegon +WordBased.milliseconds=\ mil·lisegons diff --git a/src/main/resources/org/threeten/extra/wordbased_cs.properties b/src/main/resources/org/threeten/extra/wordbased_cs.properties new file mode 100644 index 00000000..67bb462d --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_cs.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,a +WordBased.commaspaceand=, a +WordBased.commaspace=, +WordBased.spaceandspace=\ a +WordBased.years.predicates=One|||End234NotTeens +WordBased.years.list=\ rok||| roky||| let +WordBased.months.predicates=One|||End234NotTeens +WordBased.months.list=\ měsíc||| měsíce||| měsíců +WordBased.weeks.predicates=One|||End234NotTeens +WordBased.weeks.list=\ týden||| týdny||| týdnů +WordBased.days.predicates=One|||End234NotTeens +WordBased.days.list=\ den||| dny||| dnů +WordBased.hours.predicates=One|||End234NotTeens +WordBased.hours.list=\ hodina||| hodiny||| hodin +WordBased.minutes.predicates=One|||End234NotTeens +WordBased.minutes.list=\ minuta||| minuty||| minut +WordBased.seconds.predicates=One|||End234NotTeens +WordBased.seconds.list=\ sekunda||| sekundy||| sekund +WordBased.milliseconds.predicates=One|||End234NotTeens +WordBased.milliseconds.list=\ milisekunda||| milisekundy||| milisekund diff --git a/src/main/resources/org/threeten/extra/wordbased_da.properties b/src/main/resources/org/threeten/extra/wordbased_da.properties new file mode 100644 index 00000000..11d0fca8 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_da.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,og +WordBased.commaspaceand=, og +WordBased.commaspace=,\ +WordBased.spaceandspace=\ og\ +WordBased.year=\ \u00e5r +WordBased.years=\ \u00e5r +WordBased.month=\ m\u00e5ned +WordBased.months=\ m\u00e5neder +WordBased.week=\ uge +WordBased.weeks=\ uger +WordBased.day=\ dag +WordBased.days=\ dage +WordBased.hour=\ time +WordBased.hours=\ timer +WordBased.minute=\ minut +WordBased.minutes=\ minutter +WordBased.second=\ sekund +WordBased.seconds=\ sekunder +WordBased.millisecond=\ millisekund +WordBased.milliseconds=\ millisekunder diff --git a/src/main/resources/org/threeten/extra/wordbased_de.properties b/src/main/resources/org/threeten/extra/wordbased_de.properties new file mode 100644 index 00000000..02b40167 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_de.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,und +WordBased.commaspaceand=, und +WordBased.commaspace=, +WordBased.spaceandspace=\ und +WordBased.year=\ Jahr +WordBased.years=\ Jahre +WordBased.month=\ Monat +WordBased.months=\ Monate +WordBased.week=\ Woche +WordBased.weeks=\ Wochen +WordBased.day=\ Tag +WordBased.days=\ Tage +WordBased.hour=\ Stunde +WordBased.hours=\ Stunden +WordBased.minute=\ Minute +WordBased.minutes=\ Minuten +WordBased.second=\ Sekunde +WordBased.seconds=\ Sekunden +WordBased.millisecond=\ Millisekunde +WordBased.milliseconds=\ Millisekunden diff --git a/src/main/resources/org/threeten/extra/wordbased_en.properties b/src/main/resources/org/threeten/extra/wordbased_en.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_en.properties @@ -0,0 +1 @@ + diff --git a/src/main/resources/org/threeten/extra/wordbased_es.properties b/src/main/resources/org/threeten/extra/wordbased_es.properties new file mode 100644 index 00000000..1f901e2d --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_es.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,y +WordBased.commaspaceand=, y +WordBased.commaspace=, +WordBased.spaceandspace=\ y +WordBased.year=\ a\u00f1o +WordBased.years=\ a\u00f1os +WordBased.month=\ mes +WordBased.months=\ meses +WordBased.week=\ semana +WordBased.weeks=\ semanas +WordBased.day=\ d\u00eda +WordBased.days=\ d\u00edas +WordBased.hour=\ hora +WordBased.hours=\ horas +WordBased.minute=\ minuto +WordBased.minutes=\ minutos +WordBased.second=\ segundo +WordBased.seconds=\ segundos +WordBased.millisecond=\ milisegundo +WordBased.milliseconds=\ milisegundos diff --git a/src/main/resources/org/threeten/extra/wordbased_fa.properties b/src/main/resources/org/threeten/extra/wordbased_fa.properties new file mode 100644 index 00000000..4edf3b06 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_fa.properties @@ -0,0 +1,23 @@ +WordBased.space=\u0020 +WordBased.comma=, +WordBased.commandand=,\u0648 +WordBased.commaspaceand=, \u0648 +WordBased.commaspace=, +WordBased.spaceandspace=\ \u0648 +#In Farsi, to denote a time period or time duration is always in singular form, never plural. +WordBased.year=\ \u0633\u0627\u0644 +WordBased.years=\ \u0633\u0627\u0644 +WordBased.month=\ \u0645\u0627\u0647 +WordBased.months=\ \u0645\u0627\u0647 +WordBased.week=\ \u0647\u0641\u062A\u0647 +WordBased.weeks=\ \u0647\u0641\u062A\u0647 +WordBased.day=\ \u0631\u0648\u0632 +WordBased.days=\ \u0631\u0648\u0632 +WordBased.hour=\ \u0633\u0627\u0639\u062A +WordBased.hours=\ \u0633\u0627\u0639\u062A +WordBased.minute=\ \u062f\u0642\u06cc\u0642\u0647 +WordBased.minutes=\ \u062f\u0642\u06cc\u0642\u0647 +WordBased.second=\ \u062b\u0627\u0646\u06cc\u0647 +WordBased.seconds=\ \u062b\u0627\u0646\u06cc\u0647 +WordBased.millisecond=\ \u0645\u06cc\u0644\u06cc\u0020\u062b\u0627\u0646\u06cc\u0647 +WordBased.milliseconds=\ \u0645\u06cc\u0644\u06cc\u0020\u062b\u0627\u0646\u06cc\u0647 diff --git a/src/main/resources/org/threeten/extra/wordbased_fi.properties b/src/main/resources/org/threeten/extra/wordbased_fi.properties new file mode 100644 index 00000000..16fd346c --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_fi.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,ja +WordBased.commaspaceand=, ja +WordBased.commaspace=, +WordBased.spaceandspace=\ ja +WordBased.year=\ vuosi +WordBased.years=\ vuotta +WordBased.month=\ kuukausi +WordBased.months=\ kuukautta +WordBased.week=\ viikko +WordBased.weeks=\ viikkoa +WordBased.day=\ päivä +WordBased.days=\ päivää +WordBased.hour=\ tunti +WordBased.hours=\ tuntia +WordBased.minute=\ minuutti +WordBased.minutes=\ minuttia +WordBased.second=\ sekunti +WordBased.seconds=\ sekuntia +WordBased.millisecond=\ millisekunti +WordBased.milliseconds=\ millisekuntia diff --git a/src/main/resources/org/threeten/extra/wordbased_fr.properties b/src/main/resources/org/threeten/extra/wordbased_fr.properties new file mode 100644 index 00000000..63b89d2f --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_fr.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,et +WordBased.commaspaceand=, et +WordBased.commaspace=, +WordBased.spaceandspace=\ et +WordBased.year=\ ann\u00e9e +WordBased.years=\ ann\u00e9es +WordBased.month=\ mois +WordBased.months=\ mois +WordBased.week=\ semaine +WordBased.weeks=\ semaines +WordBased.day=\ jour +WordBased.days=\ jours +WordBased.hour=\ heure +WordBased.hours=\ heures +WordBased.minute=\ minute +WordBased.minutes=\ minutes +WordBased.second=\ seconde +WordBased.seconds=\ secondes +WordBased.millisecond=\ milliseconde +WordBased.milliseconds=\ millisecondes diff --git a/src/main/resources/org/threeten/extra/wordbased_it.properties b/src/main/resources/org/threeten/extra/wordbased_it.properties new file mode 100644 index 00000000..c6df8b36 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_it.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,e +WordBased.commaspaceand=, e +WordBased.commaspace=, +WordBased.spaceandspace=\ e +WordBased.year=\ anno +WordBased.years=\ anni +WordBased.month=\ mese +WordBased.months=\ mesi +WordBased.week=\ settimana +WordBased.weeks=\ settimane +WordBased.day=\ giorno +WordBased.days=\ giorni +WordBased.hour=\ ora +WordBased.hours=\ ore +WordBased.minute=\ minuto +WordBased.minutes=\ minuti +WordBased.second=\ secondo +WordBased.seconds=\ secondi +WordBased.millisecond=\ millisecondo +WordBased.milliseconds=\ millisecondi diff --git a/src/main/resources/org/threeten/extra/wordbased_ja.properties b/src/main/resources/org/threeten/extra/wordbased_ja.properties new file mode 100644 index 00000000..4f322799 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_ja.properties @@ -0,0 +1,22 @@ +WordBased.space= +WordBased.comma= +WordBased.commandand= +WordBased.commaspaceand= +WordBased.commaspace= +WordBased.spaceandspace= +WordBased.year=\u5E74 +WordBased.years=\u5E74 +WordBased.month=\u304B\u6708 +WordBased.months=\u304B\u6708 +WordBased.week=\u9031\u9593 +WordBased.weeks=\u9031\u9593 +WordBased.day=\u65E5 +WordBased.days=\u65E5 +WordBased.hour=\u6642\u9593 +WordBased.hours=\u6642\u9593 +WordBased.minute=\u5206 +WordBased.minutes=\u5206 +WordBased.second=\u79D2 +WordBased.seconds=\u79D2 +WordBased.millisecond=\u30DF\u30EA\u79D2 +WordBased.milliseconds=\u30DF\u30EA\u79D2 diff --git a/src/main/resources/org/threeten/extra/wordbased_nb.properties b/src/main/resources/org/threeten/extra/wordbased_nb.properties new file mode 100644 index 00000000..93c587e9 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_nb.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,og +WordBased.commaspaceand=, og +WordBased.commaspace=, +WordBased.spaceandspace=\ og +WordBased.year=\ år +WordBased.years=\ år +WordBased.month=\ måned +WordBased.months=\ måneder +WordBased.week=\ uke +WordBased.weeks=\ uker +WordBased.day=\ dag +WordBased.days=\ dager +WordBased.hour=\ time +WordBased.hours=\ timer +WordBased.minute=\ minutt +WordBased.minutes=\ minutt +WordBased.second=\ sekund +WordBased.seconds=\ sekund +WordBased.millisecond=\ millisekund +WordBased.milliseconds=\ millisekund diff --git a/src/main/resources/org/threeten/extra/wordbased_nl.properties b/src/main/resources/org/threeten/extra/wordbased_nl.properties new file mode 100644 index 00000000..2561c7f6 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_nl.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,en +WordBased.commaspaceand=, en +WordBased.commaspace=, +WordBased.spaceandspace=\ en +WordBased.year=\ jaar +WordBased.years=\ jaar +WordBased.month=\ maand +WordBased.months=\ maanden +WordBased.week=\ week +WordBased.weeks=\ weken +WordBased.day=\ dag +WordBased.days=\ dagen +WordBased.hour=\ uur +WordBased.hours=\ uur +WordBased.minute=\ minuut +WordBased.minutes=\ minuten +WordBased.second=\ seconde +WordBased.seconds=\ seconden +WordBased.millisecond=\ milliseconde +WordBased.milliseconds=\ milliseconden diff --git a/src/main/resources/org/threeten/extra/wordbased_nn.properties b/src/main/resources/org/threeten/extra/wordbased_nn.properties new file mode 100644 index 00000000..12dc8f24 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_nn.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,og +WordBased.commaspaceand=, og +WordBased.commaspace=, +WordBased.spaceandspace=\ og +WordBased.year=\ år +WordBased.years=\ år +WordBased.month=\ månad +WordBased.months=\ månader +WordBased.week=\ veke +WordBased.weeks=\ veker +WordBased.day=\ dag +WordBased.days=\ dagar +WordBased.hour=\ time +WordBased.hours=\ timar +WordBased.minute=\ minutt +WordBased.minutes=\ minutt +WordBased.second=\ sekund +WordBased.seconds=\ sekund +WordBased.millisecond=\ millisekund +WordBased.milliseconds=\ millisekund diff --git a/src/main/resources/org/threeten/extra/wordbased_pl.properties b/src/main/resources/org/threeten/extra/wordbased_pl.properties new file mode 100644 index 00000000..02f717f4 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_pl.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,i +WordBased.commaspaceand=, i +WordBased.commaspace=, +WordBased.spaceandspace=\ i +WordBased.years.predicates=One|||End234NotTeens +WordBased.years.list=\ rok||| lata||| lat +WordBased.months.predicates=One|||End234NotTeens +WordBased.months.list=\ miesi\u0105c||| miesi\u0105ce||| miesi\u0119cy +WordBased.weeks.predicates=One|||End234NotTeens +WordBased.weeks.list=\ tydzie\u0144||| tygodnie||| tygodni +WordBased.day=\ dzie\u0144 +WordBased.days=\ dni +WordBased.hours.predicates=One|||End234NotTeens +WordBased.hours.list=\ godzina||| godziny||| godzin +WordBased.minutes.predicates=One|||End234NotTeens +WordBased.minutes.list=\ minuta||| minuty||| minut +WordBased.seconds.predicates=One|||End234NotTeens +WordBased.seconds.list=\ sekunda||| sekundy||| sekund +WordBased.milliseconds.predicates=One|||End234NotTeens +WordBased.milliseconds.list=\ milisekunda||| milisekundy||| milisekund diff --git a/src/main/resources/org/threeten/extra/wordbased_pt.properties b/src/main/resources/org/threeten/extra/wordbased_pt.properties new file mode 100644 index 00000000..95db4d60 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_pt.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,e +WordBased.commaspaceand=, e +WordBased.commaspace=, +WordBased.spaceandspace=\ e +WordBased.year=\ ano +WordBased.years=\ anos +WordBased.month=\ m\u00eas +WordBased.months=\ meses +WordBased.week=\ semana +WordBased.weeks=\ semanas +WordBased.day=\ dia +WordBased.days=\ dias +WordBased.hour=\ hora +WordBased.hours=\ horas +WordBased.minute=\ minuto +WordBased.minutes=\ minutos +WordBased.second=\ segundo +WordBased.seconds=\ segundos +WordBased.millisecond=\ milissegundo +WordBased.milliseconds=\ milissegundos diff --git a/src/main/resources/org/threeten/extra/wordbased_ro.properties b/src/main/resources/org/threeten/extra/wordbased_ro.properties new file mode 100644 index 00000000..e9d96576 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_ro.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,\u0219i +WordBased.commaspaceand=, \u0219i +WordBased.commaspace=, +WordBased.spaceandspace=\ \u0219i +WordBased.year=\ an +WordBased.years=\ ani +WordBased.month=\ lun\u0103 +WordBased.months=\ luni +WordBased.week=\ s\u0103pt\u0103m\u00E2n\u0103 +WordBased.weeks=\ s\u0103pt\u0103m\u00E2ni +WordBased.day=\ zi +WordBased.days=\ zile +WordBased.hour=\ or\u0103 +WordBased.hours=\ ore +WordBased.minute=\ minut +WordBased.minutes=\ minute +WordBased.second=\ secund\u0103 +WordBased.seconds=\ secunde +WordBased.millisecond=\ milisecund\u0103 +WordBased.milliseconds=\ milisecunde diff --git a/src/main/resources/org/threeten/extra/wordbased_ru.properties b/src/main/resources/org/threeten/extra/wordbased_ru.properties new file mode 100644 index 00000000..cea63ec6 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_ru.properties @@ -0,0 +1,22 @@ +WordBased.space=\u0020 +WordBased.comma=, +WordBased.commandand=,\u0438 +WordBased.commaspaceand=, \u0438 +WordBased.commaspace=,\u0020 +WordBased.spaceandspace=\ \u0438\u0020 +WordBased.years.predicates=End1Not11|||End234NotTeens +WordBased.years.list=\ \u0433\u043E\u0434||| \u0433\u043E\u0434\u0430||| \u043B\u0435\u0442 +WordBased.months.predicates=End1Not11|||End234NotTeens +WordBased.months.list=\ \u043C\u0435\u0441\u044F\u0446||| \u043C\u0435\u0441\u044F\u0446\u0430||| \u043C\u0435\u0441\u044F\u0446\u0435\u0432 +WordBased.weeks.predicates=End1Not11|||End234NotTeens +WordBased.weeks.list=\ \u043D\u0435\u0434\u0435\u043B\u044F||| \u043D\u0435\u0434\u0435\u043B\u0438||| \u043D\u0435\u0434\u0435\u043B\u044C +WordBased.days.predicates=End1Not11|||End234NotTeens +WordBased.days.list=\ \u0434\u0435\u043D\u044C||| \u0434\u043D\u044F||| \u0434\u043D\u0435\u0439 +WordBased.hours.predicates=End1Not11|||End234NotTeens +WordBased.hours.list=\ \u0447\u0430\u0441||| \u0447\u0430\u0441\u0430||| \u0447\u0430\u0441\u043E\u0432 +WordBased.minutes.predicates=End1Not11|||End234NotTeens +WordBased.minutes.list=\ \u043C\u0438\u043D\u0443\u0442\u0430||| \u043C\u0438\u043D\u0443\u0442\u044B||| \u043C\u0438\u043D\u0443\u0442 +WordBased.seconds.predicates=End1Not11|||End234NotTeens +WordBased.seconds.list=\ \u0441\u0435\u043A\u0443\u043D\u0434\u0430||| \u0441\u0435\u043A\u0443\u043D\u0434\u044B||| \u0441\u0435\u043A\u0443\u043D\u0434 +WordBased.milliseconds.predicates=End1Not11|||End234NotTeens +WordBased.milliseconds.list=\ \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u0430||| \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B||| \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434 diff --git a/src/main/resources/org/threeten/extra/wordbased_sv.properties b/src/main/resources/org/threeten/extra/wordbased_sv.properties new file mode 100644 index 00000000..cd0c10ee --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_sv.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,och +WordBased.commaspaceand=, och +WordBased.commaspace=, +WordBased.spaceandspace=\ och +WordBased.year=\ år +WordBased.years=\ år +WordBased.month=\ månad +WordBased.months=\ månader +WordBased.week=\ vecka +WordBased.weeks=\ veckor +WordBased.day=\ dag +WordBased.days=\ dagar +WordBased.hour=\ timme +WordBased.hours=\ timmar +WordBased.minute=\ minut +WordBased.minutes=\ minuter +WordBased.second=\ sekund +WordBased.seconds=\ sekunder +WordBased.millisecond=\ millisekund +WordBased.milliseconds=\ millisekunder diff --git a/src/main/resources/org/threeten/extra/wordbased_tr.properties b/src/main/resources/org/threeten/extra/wordbased_tr.properties new file mode 100644 index 00000000..25629c42 --- /dev/null +++ b/src/main/resources/org/threeten/extra/wordbased_tr.properties @@ -0,0 +1,22 @@ +WordBased.space=\ +WordBased.comma=, +WordBased.commandand=,ve +WordBased.commaspaceand=, ve +WordBased.commaspace=, +WordBased.spaceandspace=\ ve +WordBased.year=\ y\u0131l +WordBased.years=\ y\u0131l +WordBased.month=\ ay +WordBased.months=\ ay +WordBased.week=\ hafta +WordBased.weeks=\ hafta +WordBased.day=\ g\u00fcn +WordBased.days=\ g\u00fcn +WordBased.hour=\ saat +WordBased.hours=\ saat +WordBased.minute=\ dakika +WordBased.minutes=\ dakika +WordBased.second=\ saniye +WordBased.seconds=\ saniye +WordBased.millisecond=\ milisaniye +WordBased.milliseconds=\ milisaniye diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 371153b3..f77158c0 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -6,31 +6,38 @@ Not every piece of date/time logic is destined for the JDK. Some concepts are too specialized or too bulky to make it in. This project provides some of those additional classes as a well-tested and reliable jar. -It is curated by the primary author of the Java 8 date and time library, [Stephen Colebourne](http://www.joda.org/). +It is curated by the primary author of the Java 8 date and time library, [Stephen Colebourne](https://www.joda.org/). -ThreeTen-Extra is licensed under the business-friendly [BSD 3-clause license](license.html). +ThreeTen-Extra is licensed under the business-friendly [BSD 3-clause license](licenses.html). ## Features The following features are included: -* [`DayOfMonth`](apidocs/org/threeten/extra/DayOfMonth.html) - a day-of-month without month or year -* [`DayOfYear`](apidocs/org/threeten/extra/DayOfYear.html) - a day-of-year without year -* [`AmPm`](apidocs/org/threeten/extra/AmPm.html) - before or after midday -* [`Quarter`](apidocs/org/threeten/extra/Quarter.html) - the four quarters, Q1, Q2, Q3 and Q4 -* [`YearQuarter`](apidocs/org/threeten/extra/YearQuarter.html) - combines a year and quarter, 2014-Q4 -* [`YearWeek`](apidocs/org/threeten/extra/YearWeek.html) - combines a week-based-year and a week, 2014-W06 -* [`Days`](apidocs/org/threeten/extra/Days.html), -[`Weeks`](apidocs/org/threeten/extra/Weeks.html), -[`Months`](apidocs/org/threeten/extra/Months.html) and -[`Years`](apidocs/org/threeten/extra/Years.html) - amounts of time -* [`Interval`](apidocs/org/threeten/extra/Interval.html) - an interval between two instants -* Weekend adjusters -* [Coptic](apidocs/org/threeten/extra/chrono/CopticChronology.html) calendar system -* [Ethiopic](apidocs/org/threeten/extra/chrono/EthiopicChronology.html) calendar system -* [Julian](apidocs/org/threeten/extra/chrono/JulianChronology.html) calendar system -* Support for the TAI and UTC [time-scales](apidocs/org/threeten/extra/scale/package-summary.html) +* [`DayOfMonth`](apidocs/org.threeten.extra/org/threeten/extra/DayOfMonth.html) - a day-of-month without month or year +* [`DayOfYear`](apidocs/org.threeten.extra/org/threeten/extra/DayOfYear.html) - a day-of-year without year +* [`AmPm`](apidocs/org.threeten.extra/org/threeten/extra/AmPm.html) - before or after midday +* [`Quarter`](apidocs/org.threeten.extra/org/threeten/extra/Quarter.html) - the four quarters, Q1, Q2, Q3 and Q4 +* [`YearQuarter`](apidocs/org.threeten.extra/org/threeten/extra/YearQuarter.html) - combines year and quarter, 2014-Q4 +* [`YearWeek`](apidocs/org.threeten.extra/org/threeten/extra/YearWeek.html) - a week in a week-based-year, 2014-W06 +* [`YearHalf`](apidocs/org.threeten.extra/org/threeten/extra/YearHalf.html) - a half-year, 2014-H1 +* [`OffsetDate`](apidocs/org.threeten.extra/org/threeten/extra/OffsetDate.html) - combines `LocalDate` and `ZoneOffset` +* [`HourMinute`](apidocs/org.threeten.extra/org/threeten/extra/HourMinute.html) - time to minute precision, 10:24 +* [`Seconds`](apidocs/org.threeten.extra/org/threeten/extra/Seconds.html), +[`Minutes`](apidocs/org.threeten.extra/org/threeten/extra/Minutes.html), +[`Hours`](apidocs/org.threeten.extra/org/threeten/extra/Hours.html), +[`Days`](apidocs/org.threeten.extra/org/threeten/extra/Days.html), +[`Weeks`](apidocs/org.threeten.extra/org/threeten/extra/Weeks.html), +[`Months`](apidocs/org.threeten.extra/org/threeten/extra/Months.html) and +[`Years`](apidocs/org.threeten.extra/org/threeten/extra/Years.html) - amounts of time +* [`Interval`](apidocs/org.threeten.extra/org/threeten/extra/Interval.html) - an interval between two instants +* [`LocalDateRange`](apidocs/org.threeten.extra/org/threeten/extra/LocalDateRange.html) - a range between two dates +* [`PeriodDuration`](apidocs/org.threeten.extra/org/threeten/extra/PeriodDuration.html) - combines `Period` and `Duration` +* More [utilities](apidocs/org.threeten.extra/org/threeten/extra/Temporals.html), such as weekend adjusters +* Extended [formatting](apidocs/org.threeten.extra/org/threeten/extra/AmountFormats.html) of periods and durations, including word-based formatting +* Additional [calendar systems](apidocs/org.threeten.extra/org/threeten/extra/chrono/package-summary.html) +* Support for the TAI and UTC [time-scales](apidocs/org.threeten.extra/org/threeten/extra/scale/package-summary.html) ## Documentation @@ -38,7 +45,8 @@ The following features are included: Various documentation is available: * The helpful [user guide](userguide.html) -* The [Javadoc](apidocs/index.html) +* The list of [related projects](related.html) +* The [Javadoc](apidocs/org.threeten.extra/module-summary.html) * The [change notes](changes-report.html) for each release * The [GitHub](https://github.com/ThreeTen/threeten-extra) source repository @@ -46,18 +54,18 @@ Various documentation is available: ## Releases -Release 1.0 is the current release. -This release is considered stable and worthy of the 1.x tag. +Release 1.8.0 is the current release. +This release is considered stable and worthy of the 1.x tag as per [SemVer](https://semver.org/spec/v2.0.0.html). ThreeTen-Extra requires Java SE 8 or later and has no [dependencies](dependencies.html). -Available in [Maven Central](http://search.maven.org/#artifactdetails%7Corg.threeten%7Cthreeten-extra%7C1.0%7Cjar). +Available in [Maven Central](https://search.maven.org/search?q=g:org.threeten%20AND%20a:threeten-extra&core=gav). ```xml org.threeten threeten-extra - 1.0 + 1.8.0 ``` @@ -65,10 +73,11 @@ Available in [Maven Central](http://search.maven.org/#artifactdetails%7Corg.thre ### Support -Support on bugs, library usage or enhancement requests is available on a best efforts basis. - -To suggest enhancements or contribute, please [fork the source code](https://github.com/ThreeTen/threeten-extra) -on GitHub and send a Pull Request. - -Alternatively, use GitHub [issues](https://github.com/ThreeTen/threeten-extra/issues). +Please use [Stack Overflow](https://stackoverflow.com/search?q=threeten-extra) for general usage questions. +GitHub [issues](https://github.com/ThreeTen/threeten-extra/issues) and [pull requests](https://github.com/ThreeTen/threeten-extra/pulls) +should be used when you want to help advance the project. +Commercial support is available via the +[Tidelift subscription](https://tidelift.com/subscription/pkg/maven-org-threeten-threeten-extra?utm_source=maven-org-threeten-threeten-extra&utm_medium=referral&utm_campaign=website). +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. diff --git a/src/site/markdown/related.md b/src/site/markdown/related.md new file mode 100644 index 00000000..dead271e --- /dev/null +++ b/src/site/markdown/related.md @@ -0,0 +1,12 @@ +## Related projects + +Here are links to a number of projects related to **JSR-310** or **ThreeTen-Extra**. +These projects are independent - no guarantees of quality are given! + +* [JPA adapters](https://github.com/marschall/threeten-jpa) - Integration with JPA +* [JAXB adapters](https://github.com/threeten-jaxb/threeten-jaxb) - Integration with JAXB +* [ObjectLab Holiday calculation](http://objectlabkit.sourceforge.net/) - Support for working and non-working days, plus how to calculate and resolve holidays, from a finance industry perspective. +* [MyBatis Type Handlers](https://github.com/mybatis/typehandlers-threeten-extra) - The MyBatis type handlers supporting types of ThreeTen-Extra. + +If your open source library provides a value added feature on top of JSR-310 or ThreeTen-Extra, +then let us know! Just send a pull request to edit this page. diff --git a/src/site/markdown/userguide.md b/src/site/markdown/userguide.md index 040561c6..7a1a65ca 100644 --- a/src/site/markdown/userguide.md +++ b/src/site/markdown/userguide.md @@ -9,17 +9,38 @@ ThreeTen-Extra is a small library that builds on the Java SE 8 The additional value types operate exactly as per similar classes in Java SE 8. These include: -* [`DayOfMonth`](apidocs/org/threeten/extra/DayOfMonth.html) - a day-of-month without month or year -* [`DayOfYear`](apidocs/org/threeten/extra/DayOfYear.html) - a day-of-year without year -* [`AmPm`](apidocs/org/threeten/extra/AmPm.html) - before or after midday -* [`Quarter`](apidocs/org/threeten/extra/Quarter.html) - the four quarters, Q1, Q2, Q3 and Q4 -* [`YearQuarter`](apidocs/org/threeten/extra/YearQuarter.html) - combines a year and quarter, 2014-Q4 -* [`YearWeek`](apidocs/org/threeten/extra/YearWeek.html) - combines a week-based-year and a week, 2014-W06 -* [`Days`](apidocs/org/threeten/extra/Days.html) - an amount of time measured in days -* [`Weeks`](apidocs/org/threeten/extra/Weeks.html) - an amount of time measured in weeks -* [`Months`](apidocs/org/threeten/extra/Months.html) - an amount of time measured in months -* [`Years`](apidocs/org/threeten/extra/Years.html) - an amount of time measured in years -* [`Interval`](apidocs/org/threeten/extra/Interval.html) - an interval between two instants +* [`DayOfMonth`](apidocs/org.threeten.extra/org/threeten/extra/DayOfMonth.html) - a day-of-month without month or year +* [`DayOfYear`](apidocs/org.threeten.extra/org/threeten/extra/DayOfYear.html) - a day-of-year without year +* [`AmPm`](apidocs/org.threeten.extra/org/threeten/extra/AmPm.html) - before or after midday +* [`Quarter`](apidocs/org.threeten.extra/org/threeten/extra/Quarter.html) - the four quarters, Q1, Q2, Q3 and Q4 +* [`YearQuarter`](apidocs/org.threeten.extra/org/threeten/extra/YearQuarter.html) - combines a year and quarter, 2014-Q4 +* [`YearWeek`](apidocs/org.threeten.extra/org/threeten/extra/YearWeek.html) - combines a week-based-year and a week, 2014-W06 +* [`OffsetDate`](apidocs/org.threeten.extra/org/threeten/extra/OffsetDate.html) - combines `LocalDate` and `ZoneOffset` +* [`Seconds`](apidocs/org.threeten.extra/org/threeten/extra/Seconds.html) - an amount of time measured in seconds +* [`Minutes`](apidocs/org.threeten.extra/org/threeten/extra/Minutes.html) - an amount of time measured in minutes +* [`Hours`](apidocs/org.threeten.extra/org/threeten/extra/Hours.html) - an amount of time measured in hours +* [`Days`](apidocs/org.threeten.extra/org/threeten/extra/Days.html) - an amount of time measured in days +* [`Weeks`](apidocs/org.threeten.extra/org/threeten/extra/Weeks.html) - an amount of time measured in weeks +* [`Months`](apidocs/org.threeten.extra/org/threeten/extra/Months.html) - an amount of time measured in months +* [`Years`](apidocs/org.threeten.extra/org/threeten/extra/Years.html) - an amount of time measured in years +* [`Interval`](apidocs/org.threeten.extra/org/threeten/extra/Interval.html) - an interval between two instants +* [`LocalDateRange`](apidocs/org.threeten.extra/org/threeten/extra/LocalDateRange.html) - a range between two dates +* [`PeriodDuration`](apidocs/org.threeten.extra/org/threeten/extra/PeriodDuration.html) - combines `Period` and `Duration` + + +## Period/Duration formatting + +The JDK does not provide a mechanism to format periods or durations beyond ISO-8601. +A simple mechanism is provided here in [`AmountFormats`](apidocs/org.threeten.extra/org/threeten/extra/AmountFormats.html): + +``` + Period period = Period.of(1, 6, 5); + String str = AmountFormats.wordBased(period, Locale.ENGLISH); + // output: "1 year, 6 months and 5 days" +``` + +Translations are provided for bg, ca, cs, da, de, en, es, fa, fi, fr, it, ja, nb, nl, nn, pl, pt, ro, ru, sv, tr. +Feel free to raise PRs for other languages. ## Calendar systems @@ -27,16 +48,16 @@ These include: The additional calendar systems operate exactly as per similar classes in Java SE 8. These include: -* [Accounting](apidocs/org/threeten/extra/chrono/AccountingChronology.html) calendar system -* [British Cutover](apidocs/org/threeten/extra/chrono/BritishCutoverChronology.html) calendar system -* [Coptic](apidocs/org/threeten/extra/chrono/CopticChronology.html) calendar system -* [Discordian](apidocs/org/threeten/extra/chrono/DiscordianChronology.html) calendar system -* [Ethiopic](apidocs/org/threeten/extra/chrono/EthiopicChronology.html) calendar system -* [International Fixed](apidocs/org/threeten/extra/chrono/InternationalFixedChronology.html) calendar system -* [Julian](apidocs/org/threeten/extra/chrono/JulianChronology.html) calendar system -* [Pax](apidocs/org/threeten/extra/chrono/PaxChronology.html) calendar system -* [Symmetry010](apidocs/org/threeten/extra/chrono/Symmetry010Chronology.html) calendar system -* [Symmetry454](apidocs/org/threeten/extra/chrono/Symmetry454Chronology.html) calendar system +* [Accounting](apidocs/org.threeten.extra/org/threeten/extra/chrono/AccountingChronology.html) calendar system +* [British Cutover](apidocs/org.threeten.extra/org/threeten/extra/chrono/BritishCutoverChronology.html) calendar system +* [Coptic](apidocs/org.threeten.extra/org/threeten/extra/chrono/CopticChronology.html) calendar system +* [Discordian](apidocs/org.threeten.extra/org/threeten/extra/chrono/DiscordianChronology.html) calendar system +* [Ethiopic](apidocs/org.threeten.extra/org/threeten/extra/chrono/EthiopicChronology.html) calendar system +* [International Fixed](apidocs/org.threeten.extra/org/threeten/extra/chrono/InternationalFixedChronology.html) calendar system +* [Julian](apidocs/org.threeten.extra/org/threeten/extra/chrono/JulianChronology.html) calendar system +* [Pax](apidocs/org.threeten.extra/org/threeten/extra/chrono/PaxChronology.html) calendar system +* [Symmetry010](apidocs/org.threeten.extra/org/threeten/extra/chrono/Symmetry010Chronology.html) calendar system +* [Symmetry454](apidocs/org.threeten.extra/org/threeten/extra/chrono/Symmetry454Chronology.html) calendar system ## Time scales @@ -52,5 +73,13 @@ They were not included as they were deemed to be too specialized for the JDK. Use `TaiInstant` if you need an instant using the TAI time-scale. Use `UtcInstant` if you need an instant using the UTC time-scale. -The leap second data is provided in a text file loaded via the `ServiceLoader`. + +The leap second data is provided in a text file loaded from the classpath. Only whole leap seconds are handled, and data starts from 1972 by default. +To replace the built in leap seconds file, create a file `META-INF/org/threeten/extra/scale/LeapSeconds.txt`. +The content should have two columns as per [this format](https://github.com/ThreeTen/threeten-extra/blob/0cf61e35fc165062eb70a66b026c54c261dce46d/src/main/resources/org/threeten/extra/scale/LeapSeconds.txt). + + +## Related projects + +See also the list of [related projects](related.html). diff --git a/src/site/site.xml b/src/site/site.xml index 1cb60d32..fe8438a7 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -5,9 +5,9 @@ UA-1425975-2 - lt.velykis.maven.skins + org.joda.external reflow-maven-skin - 1.1.1 + 1.2 @@ -34,6 +34,7 @@ false false false + true @@ -59,21 +60,22 @@ - - + + ]]> - - + + - + @@ -83,8 +85,8 @@ - - + + diff --git a/src/test/java/org/threeten/extra/AbstractDateTimeTest.java b/src/test/java/org/threeten/extra/AbstractDateTimeTest.java new file mode 100644 index 00000000..f6265a1b --- /dev/null +++ b/src/test/java/org/threeten/extra/AbstractDateTimeTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.DateTimeException; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.util.List; + +import org.junit.jupiter.api.Test; + +/** + * Base test class for {@code DateTime}. + */ +public abstract class AbstractDateTimeTest { + + /** + * Sample {@code DateTime} objects. + * @return the objects, not null + */ + protected abstract List samples(); + + /** + * List of valid supported fields. + * @return the fields, not null + */ + protected abstract List validFields(); + + /** + * List of invalid unsupported fields. + * @return the fields, not null + */ + protected abstract List invalidFields(); + + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void basicTest_isSupported_TemporalField_supported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : validFields()) { + assertTrue(sample.isSupported(field), "Failed on " + sample + " " + field); + } + } + } + + @Test + public void basicTest_isSupported_TemporalField_unsupported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : invalidFields()) { + assertFalse(sample.isSupported(field), "Failed on " + sample + " " + field); + } + } + } + + @Test + public void basicTest_isSupported_TemporalField_null() { + for (TemporalAccessor sample : samples()) { + assertFalse(sample.isSupported(null), "Failed on " + sample); + } + } + + //----------------------------------------------------------------------- + // range(TemporalField) + //----------------------------------------------------------------------- + @Test + public void basicTest_range_TemporalField_supported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : validFields()) { + assertDoesNotThrow(() -> sample.range(field)); + } + } + } + + @Test + public void basicTest_range_TemporalField_unsupported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : invalidFields()) { + assertThrows(DateTimeException.class, () -> sample.range(field), "Failed on " + sample + " " + field); + } + } + } + + @Test + public void basicTest_range_TemporalField_null() { + for (TemporalAccessor sample : samples()) { + assertThrows(NullPointerException.class, () -> sample.range(null), "Failed on " + sample); + } + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void basicTest_get_TemporalField_supported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : validFields()) { + if (sample.range(field).isIntValue()) { + assertDoesNotThrow(() -> sample.get(field)); + } else { + assertThrows(DateTimeException.class, () -> sample.get(field), "Failed on " + sample + " " + field); + } + } + } + } + + @Test + public void basicTest_get_TemporalField_unsupported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : invalidFields()) { + assertThrows(DateTimeException.class, () -> sample.get(field), "Failed on " + sample + " " + field); + } + } + } + + @Test + public void basicTest_get_TemporalField_null() { + for (TemporalAccessor sample : samples()) { + assertThrows(NullPointerException.class, () -> sample.get(null), "Failed on " + sample); + } + } + + //----------------------------------------------------------------------- + // getLong(TemporalField) + //----------------------------------------------------------------------- + @Test + public void basicTest_getLong_TemporalField_supported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : validFields()) { + assertDoesNotThrow(() -> sample.getLong(field)); + } + } + } + + @Test + public void basicTest_getLong_TemporalField_unsupported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : invalidFields()) { + assertThrows(DateTimeException.class, () -> sample.getLong(field), "Failed on " + sample + " " + field); + } + } + } + + @Test + public void basicTest_getLong_TemporalField_null() { + for (TemporalAccessor sample : samples()) { + assertThrows(NullPointerException.class, () -> sample.getLong(null), "Failed on " + sample); + } + } + + //----------------------------------------------------------------------- + @Test + public void basicTest_query() { + for (TemporalAccessor sample : samples()) { + assertEquals("foo", sample.query(dateTime -> "foo")); + } + } + +} + diff --git a/src/test/java/org/threeten/extra/MockSimplePeriod.java b/src/test/java/org/threeten/extra/MockSimplePeriod.java new file mode 100644 index 00000000..00ccb1dc --- /dev/null +++ b/src/test/java/org/threeten/extra/MockSimplePeriod.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.SECONDS; + +import java.time.DateTimeException; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalUnit; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Mock period of time measured using a single unit, such as {@code 3 Days}. + */ +public final class MockSimplePeriod + implements TemporalAmount, Comparable { + + /** + * A constant for a period of zero, measured in days. + */ + public static final MockSimplePeriod ZERO_DAYS = new MockSimplePeriod(0, DAYS); + /** + * A constant for a period of zero, measured in seconds. + */ + public static final MockSimplePeriod ZERO_SECONDS = new MockSimplePeriod(0, SECONDS); + + /** + * The amount of the period. + */ + private final long amount; + /** + * The unit the period is measured in. + */ + private final TemporalUnit unit; + + /** + * Obtains a {@code MockSimplePeriod} from an amount and unit. + *

    + * The parameters represent the two parts of a phrase like '6 Days'. + * + * @param amount the amount of the period, measured in terms of the unit, positive or negative + * @param unit the unit that the period is measured in, must not be the 'Forever' unit, not null + * @return the {@code MockSimplePeriod} instance, not null + * @throws DateTimeException if the period unit is {@link java.time.temporal.ChronoUnit#FOREVER}. + */ + public static MockSimplePeriod of(long amount, TemporalUnit unit) { + return new MockSimplePeriod(amount, unit); + } + + private MockSimplePeriod(long amount, TemporalUnit unit) { + Objects.requireNonNull(unit, "unit"); + if (unit == FOREVER) { + throw new DateTimeException("Cannot create a period of the Forever unit"); + } + this.amount = amount; + this.unit = unit; + } + + //----------------------------------------------------------------------- + @Override + public List getUnits() { + return Collections.singletonList(unit); + } + + @Override + public long get(TemporalUnit unit) { + if (this.unit.equals(unit)) { + return amount; + } + throw new DateTimeException("Unsupported unit: " + unit); + } + + //----------------------------------------------------------------------- + public long getAmount() { + return amount; + } + + public TemporalUnit getUnit() { + return unit; + } + + //------------------------------------------------------------------------- + @Override + public Temporal addTo(Temporal dateTime) { + return dateTime.plus(amount, unit); + } + + @Override + public Temporal subtractFrom(Temporal dateTime) { + return dateTime.minus(amount, unit); + } + + //----------------------------------------------------------------------- + @Override + public int compareTo(MockSimplePeriod otherPeriod) { + if (unit.equals(otherPeriod.getUnit()) == false) { + throw new IllegalArgumentException("Units cannot be compared: " + unit + " and " + otherPeriod.getUnit()); + } + return Long.compare(amount, otherPeriod.amount); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MockSimplePeriod) { + MockSimplePeriod other = (MockSimplePeriod) obj; + return this.amount == other.amount && + this.unit.equals(other.unit); + } + return false; + } + + @Override + public int hashCode() { + return unit.hashCode() ^ (int) (amount ^ (amount >>> 32)); + } + + @Override + public String toString() { + return amount + " " + unit; + } + +} diff --git a/src/test/java/org/threeten/extra/TestAmPm.java b/src/test/java/org/threeten/extra/TestAmPm.java index 3c1a6ee3..4dc74d45 100644 --- a/src/test/java/org/threeten/extra/TestAmPm.java +++ b/src/test/java/org/threeten/extra/TestAmPm.java @@ -62,8 +62,10 @@ import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; import static java.time.temporal.ChronoUnit.HALF_DAYS; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.Serializable; import java.time.DateTimeException; @@ -75,19 +77,13 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.util.Locale; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; /** * Test AmPm. */ -@Test public class TestAmPm { - @BeforeMethod - public void setUp() { - } - //----------------------------------------------------------------------- @Test public void test_interfaces() { @@ -104,18 +100,18 @@ public void test_interfaces() { public void test_of_int_singleton_equals() { for (int i = 0; i <= 1; i++) { AmPm test = AmPm.of(i); - assertEquals(test.getValue(), i); + assertEquals(i, test.getValue()); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_valueTooLow() { - AmPm.of(-1); + assertThrows(DateTimeException.class, () -> AmPm.of(-1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_valueTooHigh() { - AmPm.of(2); + assertThrows(DateTimeException.class, () -> AmPm.of(2)); } //----------------------------------------------------------------------- @@ -124,21 +120,21 @@ public void test_of_int_valueTooHigh() { @Test public void test_ofHour_int_singleton() { for (int i = 0; i < 12; i++) { - assertEquals(AmPm.ofHour(i), AmPm.AM); + assertSame(AmPm.AM, AmPm.ofHour(i)); } for (int i = 12; i < 24; i++) { - assertEquals(AmPm.ofHour(i), AmPm.PM); + assertSame(AmPm.PM, AmPm.ofHour(i)); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_ofHour_int_valueTooLow() { - AmPm.ofHour(-1); + assertThrows(DateTimeException.class, () -> AmPm.ofHour(-1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_ofHour_int_valueTooHigh() { - AmPm.ofHour(24); + assertThrows(DateTimeException.class, () -> AmPm.ofHour(24)); } //----------------------------------------------------------------------- @@ -146,18 +142,18 @@ public void test_ofHour_int_valueTooHigh() { //----------------------------------------------------------------------- @Test public void test_from_TemporalAccessor() { - assertEquals(AmPm.from(LocalTime.of(8, 30)), AmPm.AM); - assertEquals(AmPm.from(LocalTime.of(17, 30)), AmPm.PM); + assertEquals(AmPm.AM, AmPm.from(LocalTime.of(8, 30))); + assertEquals(AmPm.PM, AmPm.from(LocalTime.of(17, 30))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_TemporalAccessor_invalid_noDerive() { - AmPm.from(LocalDate.of(2007, 7, 30)); + assertThrows(DateTimeException.class, () -> AmPm.from(LocalDate.of(2007, 7, 30))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_TemporalAccessor_null() { - AmPm.from((TemporalAccessor) null); + assertThrows(NullPointerException.class, () -> AmPm.from((TemporalAccessor) null)); } //----------------------------------------------------------------------- @@ -165,108 +161,112 @@ public void test_from_TemporalAccessor_null() { //----------------------------------------------------------------------- @Test public void test_getDisplayName() { - assertEquals(AmPm.AM.getDisplayName(TextStyle.SHORT, Locale.US), "AM"); + assertEquals("AM", AmPm.AM.getDisplayName(TextStyle.SHORT, Locale.US)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getDisplayName_nullStyle() { - AmPm.AM.getDisplayName(null, Locale.US); + assertThrows(NullPointerException.class, () -> AmPm.AM.getDisplayName(null, Locale.US)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getDisplayName_nullLocale() { - AmPm.AM.getDisplayName(TextStyle.FULL, null); + assertThrows(NullPointerException.class, () -> AmPm.AM.getDisplayName(TextStyle.FULL, null)); } //----------------------------------------------------------------------- // isSupported() //----------------------------------------------------------------------- + @Test public void test_isSupported() { AmPm test = AmPm.AM; - assertEquals(test.isSupported(null), false); - assertEquals(test.isSupported(NANO_OF_SECOND), false); - assertEquals(test.isSupported(NANO_OF_DAY), false); - assertEquals(test.isSupported(MICRO_OF_SECOND), false); - assertEquals(test.isSupported(MICRO_OF_DAY), false); - assertEquals(test.isSupported(MILLI_OF_SECOND), false); - assertEquals(test.isSupported(MILLI_OF_DAY), false); - assertEquals(test.isSupported(SECOND_OF_MINUTE), false); - assertEquals(test.isSupported(SECOND_OF_DAY), false); - assertEquals(test.isSupported(MINUTE_OF_HOUR), false); - assertEquals(test.isSupported(MINUTE_OF_DAY), false); - assertEquals(test.isSupported(HOUR_OF_AMPM), false); - assertEquals(test.isSupported(CLOCK_HOUR_OF_AMPM), false); - assertEquals(test.isSupported(HOUR_OF_DAY), false); - assertEquals(test.isSupported(CLOCK_HOUR_OF_DAY), false); - assertEquals(test.isSupported(AMPM_OF_DAY), true); - assertEquals(test.isSupported(DAY_OF_WEEK), false); - assertEquals(test.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH), false); - assertEquals(test.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR), false); - assertEquals(test.isSupported(DAY_OF_MONTH), false); - assertEquals(test.isSupported(DAY_OF_YEAR), false); - assertEquals(test.isSupported(EPOCH_DAY), false); - assertEquals(test.isSupported(ALIGNED_WEEK_OF_MONTH), false); - assertEquals(test.isSupported(ALIGNED_WEEK_OF_YEAR), false); - assertEquals(test.isSupported(MONTH_OF_YEAR), false); - assertEquals(test.isSupported(PROLEPTIC_MONTH), false); - assertEquals(test.isSupported(YEAR_OF_ERA), false); - assertEquals(test.isSupported(YEAR), false); - assertEquals(test.isSupported(ERA), false); - assertEquals(test.isSupported(INSTANT_SECONDS), false); - assertEquals(test.isSupported(OFFSET_SECONDS), false); + assertEquals(false, test.isSupported(null)); + assertEquals(false, test.isSupported(NANO_OF_SECOND)); + assertEquals(false, test.isSupported(NANO_OF_DAY)); + assertEquals(false, test.isSupported(MICRO_OF_SECOND)); + assertEquals(false, test.isSupported(MICRO_OF_DAY)); + assertEquals(false, test.isSupported(MILLI_OF_SECOND)); + assertEquals(false, test.isSupported(MILLI_OF_DAY)); + assertEquals(false, test.isSupported(SECOND_OF_MINUTE)); + assertEquals(false, test.isSupported(SECOND_OF_DAY)); + assertEquals(false, test.isSupported(MINUTE_OF_HOUR)); + assertEquals(false, test.isSupported(MINUTE_OF_DAY)); + assertEquals(false, test.isSupported(HOUR_OF_AMPM)); + assertEquals(false, test.isSupported(CLOCK_HOUR_OF_AMPM)); + assertEquals(false, test.isSupported(HOUR_OF_DAY)); + assertEquals(false, test.isSupported(CLOCK_HOUR_OF_DAY)); + assertEquals(true, test.isSupported(AMPM_OF_DAY)); + assertEquals(false, test.isSupported(DAY_OF_WEEK)); + assertEquals(false, test.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(false, test.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(false, test.isSupported(DAY_OF_MONTH)); + assertEquals(false, test.isSupported(DAY_OF_YEAR)); + assertEquals(false, test.isSupported(EPOCH_DAY)); + assertEquals(false, test.isSupported(ALIGNED_WEEK_OF_MONTH)); + assertEquals(false, test.isSupported(ALIGNED_WEEK_OF_YEAR)); + assertEquals(false, test.isSupported(MONTH_OF_YEAR)); + assertEquals(false, test.isSupported(PROLEPTIC_MONTH)); + assertEquals(false, test.isSupported(YEAR_OF_ERA)); + assertEquals(false, test.isSupported(YEAR)); + assertEquals(false, test.isSupported(ERA)); + assertEquals(false, test.isSupported(INSTANT_SECONDS)); + assertEquals(false, test.isSupported(OFFSET_SECONDS)); } //----------------------------------------------------------------------- // range() //----------------------------------------------------------------------- + @Test public void test_range() { - assertEquals(AmPm.AM.range(AMPM_OF_DAY), AMPM_OF_DAY.range()); + assertEquals(AMPM_OF_DAY.range(), AmPm.AM.range(AMPM_OF_DAY)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_invalidField() { - AmPm.AM.range(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> AmPm.AM.range(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_range_null() { - AmPm.AM.range(null); + assertThrows(NullPointerException.class, () -> AmPm.AM.range(null)); } //----------------------------------------------------------------------- // get() //----------------------------------------------------------------------- + @Test public void test_get() { - assertEquals(AmPm.AM.get(AMPM_OF_DAY), 0); - assertEquals(AmPm.PM.get(AMPM_OF_DAY), 1); + assertEquals(0, AmPm.AM.get(AMPM_OF_DAY)); + assertEquals(1, AmPm.PM.get(AMPM_OF_DAY)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_get_invalidField() { - AmPm.PM.get(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> AmPm.PM.get(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_get_null() { - AmPm.PM.get(null); + assertThrows(NullPointerException.class, () -> AmPm.PM.get(null)); } //----------------------------------------------------------------------- // getLong() //----------------------------------------------------------------------- + @Test public void test_getLong() { - assertEquals(AmPm.AM.getLong(AMPM_OF_DAY), 0); - assertEquals(AmPm.PM.getLong(AMPM_OF_DAY), 1); + assertEquals(0, AmPm.AM.getLong(AMPM_OF_DAY)); + assertEquals(1, AmPm.PM.getLong(AMPM_OF_DAY)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_invalidField() { - AmPm.PM.getLong(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> AmPm.PM.getLong(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getLong_null() { - AmPm.PM.getLong(null); + assertThrows(NullPointerException.class, () -> AmPm.PM.getLong(null)); } //----------------------------------------------------------------------- @@ -274,13 +274,13 @@ public void test_getLong_null() { //----------------------------------------------------------------------- @Test public void test_query() { - assertEquals(AmPm.AM.query(TemporalQueries.chronology()), null); - assertEquals(AmPm.AM.query(TemporalQueries.localDate()), null); - assertEquals(AmPm.AM.query(TemporalQueries.localTime()), null); - assertEquals(AmPm.AM.query(TemporalQueries.offset()), null); - assertEquals(AmPm.AM.query(TemporalQueries.precision()), HALF_DAYS); - assertEquals(AmPm.AM.query(TemporalQueries.zone()), null); - assertEquals(AmPm.AM.query(TemporalQueries.zoneId()), null); + assertEquals(null, AmPm.AM.query(TemporalQueries.chronology())); + assertEquals(null, AmPm.AM.query(TemporalQueries.localDate())); + assertEquals(null, AmPm.AM.query(TemporalQueries.localTime())); + assertEquals(null, AmPm.AM.query(TemporalQueries.offset())); + assertEquals(HALF_DAYS, AmPm.AM.query(TemporalQueries.precision())); + assertEquals(null, AmPm.AM.query(TemporalQueries.zone())); + assertEquals(null, AmPm.AM.query(TemporalQueries.zoneId())); } //----------------------------------------------------------------------- @@ -288,8 +288,8 @@ public void test_query() { //----------------------------------------------------------------------- @Test public void test_toString() { - assertEquals(AmPm.AM.toString(), "AM"); - assertEquals(AmPm.PM.toString(), "PM"); + assertEquals("AM", AmPm.AM.toString()); + assertEquals("PM", AmPm.PM.toString()); } //----------------------------------------------------------------------- @@ -297,8 +297,8 @@ public void test_toString() { //----------------------------------------------------------------------- @Test public void test_enum() { - assertEquals(AmPm.valueOf("AM"), AmPm.AM); - assertEquals(AmPm.values()[0], AmPm.AM); + assertEquals(AmPm.AM, AmPm.valueOf("AM")); + assertEquals(AmPm.AM, AmPm.values()[0]); } } diff --git a/src/test/java/org/threeten/extra/TestAmountFormats.java b/src/test/java/org/threeten/extra/TestAmountFormats.java new file mode 100644 index 00000000..a91e1e26 --- /dev/null +++ b/src/test/java/org/threeten/extra/TestAmountFormats.java @@ -0,0 +1,610 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.Duration; +import java.time.Period; +import java.time.format.DateTimeParseException; +import java.util.Locale; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * Test AmountFormats. + */ +public class TestAmountFormats { + + private static final Locale PL = new Locale("pl"); + private static final Locale RU = new Locale("ru"); + + //----------------------------------------------------------------------- + @Test + public void test_iso8601() { + assertEquals("P12M6DT8H30M", AmountFormats.iso8601(Period.of(0, 12, 6), Duration.ofMinutes(8 * 60 + 30))); + assertEquals("PT8H30M", AmountFormats.iso8601(Period.ZERO, Duration.ofMinutes(8 * 60 + 30))); + assertEquals("P12M6D", AmountFormats.iso8601(Period.of(0, 12, 6), Duration.ZERO)); + } + + //----------------------------------------------------------------------- + public static Object[][] data_wordBased() { + return new Object[][] { + {Period.ofYears(0), Locale.ROOT, "0 days"}, + {Period.ofYears(1), Locale.ROOT, "1 year"}, + {Period.ofYears(2), Locale.ROOT, "2 years"}, + {Period.ofYears(12), Locale.ROOT, "12 years"}, + {Period.ofYears(-1), Locale.ROOT, "-1 year"}, + + {Period.ofWeeks(0), Locale.ENGLISH, "0 days"}, + {Period.ofWeeks(1), Locale.ENGLISH, "1 week"}, + {Period.ofWeeks(4), Locale.ENGLISH, "4 weeks"}, + + {Period.ofMonths(0), Locale.ENGLISH, "0 days"}, + {Period.ofMonths(1), Locale.ENGLISH, "1 month"}, + {Period.ofMonths(4), Locale.ENGLISH, "4 months"}, + {Period.ofMonths(14), Locale.ENGLISH, "14 months"}, + {Period.ofMonths(14).normalized(), Locale.ENGLISH, "1 year and 2 months"}, + {Period.ofYears(2).plusMonths(-10).normalized(), Locale.ENGLISH, "1 year and 2 months"}, + + {Period.ofDays(1), Locale.ENGLISH, "1 day"}, + {Period.ofDays(2), Locale.ENGLISH, "2 days"}, + {Period.ofDays(5), Locale.ENGLISH, "5 days"}, + {Period.ofDays(7), Locale.ENGLISH, "1 week"}, + {Period.ofDays(-1), Locale.ENGLISH, "-1 day"}, + + {Period.ofDays(1), new Locale("ro"), "1 zi"}, + {Period.ofDays(2), new Locale("ro"), "2 zile"}, + {Period.ofDays(5), new Locale("ro"), "5 zile"}, + {Period.ofDays(7), new Locale("ro"), "1 săptămână"}, + {Period.ofWeeks(3), new Locale("ro"), "3 săptămâni"}, + {Period.ofMonths(14).normalized(), new Locale("ro"), "1 an și 2 luni"}, + {Period.ofMonths(1), new Locale("ro"), "1 lună"}, + {Period.ofYears(2), new Locale("ro"), "2 ani"}, + }; + } + + @ParameterizedTest + @MethodSource("data_wordBased") + public void test_wordBased(Period period, Locale locale, String expected) { + assertEquals(expected, AmountFormats.wordBased(period, locale)); + } + + public static Object[][] duration_wordBased() { + return new Object[][] { + {Duration.ofMinutes(180 + 2), Locale.ENGLISH, "3 hours and 2 minutes"}, + {Duration.ofMinutes(-60 - 40), Locale.ENGLISH, "-1 hour and -40 minutes"}, + {Duration.ofSeconds(180), Locale.ENGLISH, "3 minutes"}, + {Duration.ofSeconds(100), Locale.ENGLISH, "1 minute and 40 seconds"}, + {Duration.ofSeconds(-140), Locale.ENGLISH, "-2 minutes and -20 seconds"}, + {Duration.ofSeconds(-90), Locale.ENGLISH, "-1 minute and -30 seconds"}, + {Duration.ofSeconds(-40), Locale.ENGLISH, "-40 seconds"}, + {Duration.ofMillis(1_000), Locale.ENGLISH, "1 second"}, + {Duration.ofMillis(3_000), Locale.ENGLISH, "3 seconds"}, + {Duration.ofNanos(1_000_000), Locale.ENGLISH, "1 millisecond"}, + {Duration.ofNanos(1000_000_000 + 2_000_000), Locale.ENGLISH, "1 second and 2 milliseconds"}, + + {Duration.ofMinutes(60 + 1), new Locale("ro"), "1 oră și 1 minut"}, + {Duration.ofMinutes(180 + 2), new Locale("ro"), "3 ore și 2 minute"}, + {Duration.ofMinutes(-60 - 40), new Locale("ro"), "-1 oră și -40 minute"}, + {Duration.ofSeconds(-90), new Locale("ro"), "-1 minut și -30 secunde"}, + {Duration.ofNanos(1_000_000), new Locale("ro"), "1 milisecundă"}, + {Duration.ofNanos(1000_000_000 + 2_000_000), new Locale("ro"), "1 secundă și 2 milisecunde"}, + + {Duration.ofHours(5).plusMinutes(6).plusSeconds(7).plusNanos(8_000_000L), PL, + "5 godzin, 6 minut, 7 sekund i 8 milisekund"}, + + {Duration.ofMinutes(60 + 1), new Locale("fa"), + "1 \u0633\u0627\u0639\u062A \u0648 1 \u062f\u0642\u06cc\u0642\u0647"} + }; + } + + @ParameterizedTest + @MethodSource("duration_wordBased") + public void test_wordBased(Duration duration, Locale locale, String expected) { + assertEquals(expected, AmountFormats.wordBased(duration, locale)); + } + + public static Object[][] period_duration_wordBased() { + return new Object[][] { + {Period.ofDays(1), Duration.ofMinutes(180 + 2), Locale.ROOT, "1 day, 3 hours and 2 minutes"}, + {Period.ofDays(2), Duration.ofSeconds(180), Locale.ROOT, "2 days and 3 minutes"}, + {Period.ofDays(7), Duration.ofMinutes(80), Locale.ROOT, "1 week, 1 hour and 20 minutes"}, + {Period.ZERO, Duration.ofMillis(1_000), Locale.ROOT, "1 second"}, + + {Period.ofMonths(0), Duration.ofSeconds(0), Locale.ENGLISH, "0 milliseconds"}, + {Period.ofMonths(0), Duration.ofHours(9), Locale.ENGLISH, "9 hours"}, + {Period.ofMonths(1), Duration.ZERO, Locale.ENGLISH, "1 month"}, + {Period.ofMonths(4), Duration.ZERO, Locale.ENGLISH, "4 months"}, + {Period.of(1, 2, 5), Duration.ofHours(4), Locale.ENGLISH, "1 year, 2 months, 5 days and 4 hours"}, + {Period.ofDays(5), Duration.ofDays(2).plusHours(6), Locale.ENGLISH, "7 days and 6 hours"}, + {Period.ofDays(5), Duration.ofDays(-2).plusHours(-6), Locale.ENGLISH, "3 days and -6 hours"}, + + {Period.ofDays(1), Duration.ofHours(5).plusMinutes(6).plusSeconds(7).plusNanos(8_000_000L), PL, + "1 dzie\u0144, 5 godzin, 6 minut, 7 sekund i 8 milisekund"}, + }; + } + + @ParameterizedTest + @MethodSource("period_duration_wordBased") + public void test_wordBased(Period period, Duration duration, Locale locale, String expected) { + assertEquals(expected, AmountFormats.wordBased(period, duration, locale)); + } + + //----------------------------------------------------------------------- + @Test + public void test_wordBased_pl_formatStandard() { + Period p = Period.ofDays(1); + Duration d = Duration.ofHours(5).plusMinutes(6).plusSeconds(7).plusNanos(8_000_000L); + assertEquals("1 dzie\u0144, 5 godzin, 6 minut, 7 sekund i 8 milisekund", AmountFormats.wordBased(p, d, PL)); + } + + @Test + public void test_wordBased_pl_predicate() { + assertEquals("1 rok", AmountFormats.wordBased(Period.ofYears(1), PL)); + assertEquals("2 lata", AmountFormats.wordBased(Period.ofYears(2), PL)); + assertEquals("5 lat", AmountFormats.wordBased(Period.ofYears(5), PL)); + assertEquals("12 lat", AmountFormats.wordBased(Period.ofYears(12), PL)); + assertEquals("15 lat", AmountFormats.wordBased(Period.ofYears(15), PL)); + assertEquals("1112 lat", AmountFormats.wordBased(Period.ofYears(1112), PL)); + assertEquals("1115 lat", AmountFormats.wordBased(Period.ofYears(1115), PL)); + assertEquals("2112 lat", AmountFormats.wordBased(Period.ofYears(2112), PL)); + assertEquals("2115 lat", AmountFormats.wordBased(Period.ofYears(2115), PL)); + assertEquals("2212 lat", AmountFormats.wordBased(Period.ofYears(2212), PL)); + assertEquals("2215 lat", AmountFormats.wordBased(Period.ofYears(2215), PL)); + assertEquals("22 lata", AmountFormats.wordBased(Period.ofYears(22), PL)); + assertEquals("25 lat", AmountFormats.wordBased(Period.ofYears(25), PL)); + assertEquals("1122 lata", AmountFormats.wordBased(Period.ofYears(1122), PL)); + assertEquals("1125 lat", AmountFormats.wordBased(Period.ofYears(1125), PL)); + assertEquals("2122 lata", AmountFormats.wordBased(Period.ofYears(2122), PL)); + assertEquals("2125 lat", AmountFormats.wordBased(Period.ofYears(2125), PL)); + assertEquals("2222 lata", AmountFormats.wordBased(Period.ofYears(2222), PL)); + assertEquals("2225 lat", AmountFormats.wordBased(Period.ofYears(2225), PL)); + + assertEquals("1 miesi\u0105c", AmountFormats.wordBased(Period.ofMonths(1), PL)); + assertEquals("2 miesi\u0105ce", AmountFormats.wordBased(Period.ofMonths(2), PL)); + assertEquals("5 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(5), PL)); + assertEquals("12 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(12), PL)); + assertEquals("15 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(15), PL)); + assertEquals("1112 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(1112), PL)); + assertEquals("1115 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(1115), PL)); + assertEquals("2112 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(2112), PL)); + assertEquals("2115 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(2115), PL)); + assertEquals("2212 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(2212), PL)); + assertEquals("2215 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(2215), PL)); + assertEquals("22 miesi\u0105ce", AmountFormats.wordBased(Period.ofMonths(22), PL)); + assertEquals("25 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(25), PL)); + assertEquals("1122 miesi\u0105ce", AmountFormats.wordBased(Period.ofMonths(1122), PL)); + assertEquals("1125 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(1125), PL)); + assertEquals("2122 miesi\u0105ce", AmountFormats.wordBased(Period.ofMonths(2122), PL)); + assertEquals("2125 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(2125), PL)); + assertEquals("2222 miesi\u0105ce", AmountFormats.wordBased(Period.ofMonths(2222), PL)); + assertEquals("2225 miesi\u0119cy", AmountFormats.wordBased(Period.ofMonths(2225), PL)); + + assertEquals("1 tydzie\u0144", AmountFormats.wordBased(Period.ofWeeks(1), PL)); + assertEquals("2 tygodnie", AmountFormats.wordBased(Period.ofWeeks(2), PL)); + assertEquals("5 tygodni", AmountFormats.wordBased(Period.ofWeeks(5), PL)); + assertEquals("12 tygodni", AmountFormats.wordBased(Period.ofWeeks(12), PL)); + assertEquals("15 tygodni", AmountFormats.wordBased(Period.ofWeeks(15), PL)); + assertEquals("1112 tygodni", AmountFormats.wordBased(Period.ofWeeks(1112), PL)); + assertEquals("1115 tygodni", AmountFormats.wordBased(Period.ofWeeks(1115), PL)); + assertEquals("2112 tygodni", AmountFormats.wordBased(Period.ofWeeks(2112), PL)); + assertEquals("2115 tygodni", AmountFormats.wordBased(Period.ofWeeks(2115), PL)); + assertEquals("2212 tygodni", AmountFormats.wordBased(Period.ofWeeks(2212), PL)); + assertEquals("2215 tygodni", AmountFormats.wordBased(Period.ofWeeks(2215), PL)); + assertEquals("22 tygodnie", AmountFormats.wordBased(Period.ofWeeks(22), PL)); + assertEquals("25 tygodni", AmountFormats.wordBased(Period.ofWeeks(25), PL)); + assertEquals("1122 tygodnie", AmountFormats.wordBased(Period.ofWeeks(1122), PL)); + assertEquals("1125 tygodni", AmountFormats.wordBased(Period.ofWeeks(1125), PL)); + assertEquals("2122 tygodnie", AmountFormats.wordBased(Period.ofWeeks(2122), PL)); + assertEquals("2125 tygodni", AmountFormats.wordBased(Period.ofWeeks(2125), PL)); + assertEquals("2222 tygodnie", AmountFormats.wordBased(Period.ofWeeks(2222), PL)); + assertEquals("2225 tygodni", AmountFormats.wordBased(Period.ofWeeks(2225), PL)); + + assertEquals("1 dzie\u0144", AmountFormats.wordBased(Period.ofDays(1), PL)); + assertEquals("2 dni", AmountFormats.wordBased(Period.ofDays(2), PL)); + assertEquals("5 dni", AmountFormats.wordBased(Period.ofDays(5), PL)); + assertEquals("12 dni", AmountFormats.wordBased(Period.ofDays(12), PL)); + assertEquals("15 dni", AmountFormats.wordBased(Period.ofDays(15), PL)); + assertEquals("22 dni", AmountFormats.wordBased(Period.ofDays(22), PL)); + assertEquals("25 dni", AmountFormats.wordBased(Period.ofDays(25), PL)); + + assertEquals("1 godzina", AmountFormats.wordBased(Duration.ofHours(1), PL)); + assertEquals("2 godziny", AmountFormats.wordBased(Duration.ofHours(2), PL)); + assertEquals("5 godzin", AmountFormats.wordBased(Duration.ofHours(5), PL)); + assertEquals("12 godzin", AmountFormats.wordBased(Duration.ofHours(12), PL)); + assertEquals("15 godzin", AmountFormats.wordBased(Duration.ofHours(15), PL)); + assertEquals("1112 godzin", AmountFormats.wordBased(Duration.ofHours(1112), PL)); + assertEquals("1115 godzin", AmountFormats.wordBased(Duration.ofHours(1115), PL)); + assertEquals("2112 godzin", AmountFormats.wordBased(Duration.ofHours(2112), PL)); + assertEquals("2115 godzin", AmountFormats.wordBased(Duration.ofHours(2115), PL)); + assertEquals("2212 godzin", AmountFormats.wordBased(Duration.ofHours(2212), PL)); + assertEquals("2215 godzin", AmountFormats.wordBased(Duration.ofHours(2215), PL)); + assertEquals("22 godziny", AmountFormats.wordBased(Duration.ofHours(22), PL)); + assertEquals("25 godzin", AmountFormats.wordBased(Duration.ofHours(25), PL)); + assertEquals("1122 godziny", AmountFormats.wordBased(Duration.ofHours(1122), PL)); + assertEquals("1125 godzin", AmountFormats.wordBased(Duration.ofHours(1125), PL)); + assertEquals("2122 godziny", AmountFormats.wordBased(Duration.ofHours(2122), PL)); + assertEquals("2125 godzin", AmountFormats.wordBased(Duration.ofHours(2125), PL)); + assertEquals("2222 godziny", AmountFormats.wordBased(Duration.ofHours(2222), PL)); + assertEquals("2225 godzin", AmountFormats.wordBased(Duration.ofHours(2225), PL)); + + assertEquals("1 minuta", AmountFormats.wordBased(Duration.ofMinutes(1), PL)); + assertEquals("2 minuty", AmountFormats.wordBased(Duration.ofMinutes(2), PL)); + assertEquals("5 minut", AmountFormats.wordBased(Duration.ofMinutes(5), PL)); + assertEquals("12 minut", AmountFormats.wordBased(Duration.ofMinutes(12), PL)); + assertEquals("15 minut", AmountFormats.wordBased(Duration.ofMinutes(15), PL)); + assertEquals("18 godzin i 32 minuty", AmountFormats.wordBased(Duration.ofMinutes(1112), PL)); + assertEquals("18 godzin i 35 minut", AmountFormats.wordBased(Duration.ofMinutes(1115), PL)); + assertEquals("35 godzin i 12 minut", AmountFormats.wordBased(Duration.ofMinutes(2112), PL)); + assertEquals("35 godzin i 15 minut", AmountFormats.wordBased(Duration.ofMinutes(2115), PL)); + assertEquals("36 godzin i 52 minuty", AmountFormats.wordBased(Duration.ofMinutes(2212), PL)); + assertEquals("36 godzin i 55 minut", AmountFormats.wordBased(Duration.ofMinutes(2215), PL)); + } + + // ----------------------------------------------------------------------- + // wordBased "ru" locale + // ----------------------------------------------------------------------- + @Test + public void test_wordBased_ru_formatStandard() { + Period period = Period.ofYears(1).plusMonths(2).plusDays(3); + Duration duration = Duration.ofHours(5).plusMinutes(6).plusSeconds(7).plusNanos(8_000_000L); + + String expected = "1 \u0433\u043E\u0434, 2 \u043C\u0435\u0441\u044F\u0446\u0430," + + " 3 \u0434\u043D\u044F, 5 \u0447\u0430\u0441\u043e\u0432, 6 \u043c\u0438\u043d\u0443\u0442," + + " 7 \u0441\u0435\u043A\u0443\u043D\u0434 \u0438 8 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434"; + + assertEquals(expected, AmountFormats.wordBased(period, duration, RU)); + } + + // ----------------------------------------------------------------------- + @ParameterizedTest + @MethodSource("wordBased_ru_formatSeparator") + public void test_wordBased_ru_formatSeparator(String expected, Duration duration) { + assertEquals(expected, AmountFormats.wordBased(duration, RU)); + } + + public static Object[][] wordBased_ru_formatSeparator() { + return new Object[][]{ + {"18 \u0447\u0430\u0441\u043E\u0432 \u0438 32 \u043C\u0438\u043D\u0443\u0442\u044B", Duration.ofMinutes(1112)}, + {"1 \u0441\u0435\u043A\u0443\u043D\u0434\u0430 \u0438 112 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(1112)}, + }; + } + + // ----------------------------------------------------------------------- + @ParameterizedTest + @MethodSource("wordBased_ru_period_predicate") + public void test_wordBased_ru_period_predicate(String expected, Period period) { + assertEquals(expected, AmountFormats.wordBased(period, RU)); + } + + public static Object[][] wordBased_ru_period_predicate() { + return new Object[][]{ + +// год \u0433\u043E\u0434 +// года \u0433\u043E\u0434\u0430 +// лет \u043B\u0435\u0442 + {"1 \u0433\u043E\u0434", Period.ofYears(1)}, + {"11 \u043B\u0435\u0442", Period.ofYears(11)}, + {"101 \u0433\u043E\u0434", Period.ofYears(101)}, + {"111 \u043B\u0435\u0442", Period.ofYears(111)}, + {"121 \u0433\u043E\u0434", Period.ofYears(121)}, + {"2001 \u0433\u043E\u0434", Period.ofYears(2001)}, + {"2 \u0433\u043E\u0434\u0430", Period.ofYears(2)}, + {"3 \u0433\u043E\u0434\u0430", Period.ofYears(3)}, + {"4 \u0433\u043E\u0434\u0430", Period.ofYears(4)}, + {"12 \u043B\u0435\u0442", Period.ofYears(12)}, + {"13 \u043B\u0435\u0442", Period.ofYears(13)}, + {"14 \u043B\u0435\u0442", Period.ofYears(14)}, + {"21 \u0433\u043E\u0434", Period.ofYears(21)}, + {"22 \u0433\u043E\u0434\u0430", Period.ofYears(22)}, + {"23 \u0433\u043E\u0434\u0430", Period.ofYears(23)}, + {"24 \u0433\u043E\u0434\u0430", Period.ofYears(24)}, + {"102 \u0433\u043E\u0434\u0430", Period.ofYears(102)}, + {"105 \u043B\u0435\u0442", Period.ofYears(105)}, + {"112 \u043B\u0435\u0442", Period.ofYears(112)}, + {"113 \u043B\u0435\u0442", Period.ofYears(113)}, + {"124 \u0433\u043E\u0434\u0430", Period.ofYears(124)}, + {"5 \u043B\u0435\u0442", Period.ofYears(5)}, + {"15 \u043B\u0435\u0442", Period.ofYears(15)}, + {"25 \u043B\u0435\u0442", Period.ofYears(25)}, + {"106 \u043B\u0435\u0442", Period.ofYears(106)}, + {"1005 \u043B\u0435\u0442", Period.ofYears(1005)}, + {"31 \u0433\u043E\u0434", Period.ofYears(31)}, + {"32 \u0433\u043E\u0434\u0430", Period.ofYears(32)}, + +// месяц \u043C\u0435\u0441\u044F\u0446 +// месяца \u043C\u0435\u0441\u044F\u0446\u0430 +// месяцев \u043C\u0435\u0441\u044F\u0446\u0435\u0432 + {"1 \u043C\u0435\u0441\u044F\u0446", Period.ofMonths(1)}, + {"11 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(11)}, + {"21 \u043C\u0435\u0441\u044F\u0446", Period.ofMonths(21)}, + {"101 \u043C\u0435\u0441\u044F\u0446", Period.ofMonths(101)}, + {"111 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(111)}, + {"121 \u043C\u0435\u0441\u044F\u0446", Period.ofMonths(121)}, + {"2001 \u043C\u0435\u0441\u044F\u0446", Period.ofMonths(2001)}, + {"2 \u043C\u0435\u0441\u044F\u0446\u0430", Period.ofMonths(2)}, + {"3 \u043C\u0435\u0441\u044F\u0446\u0430", Period.ofMonths(3)}, + {"4 \u043C\u0435\u0441\u044F\u0446\u0430", Period.ofMonths(4)}, + {"12 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(12)}, + {"13 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(13)}, + {"14 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(14)}, + {"22 \u043C\u0435\u0441\u044F\u0446\u0430", Period.ofMonths(22)}, + {"23 \u043C\u0435\u0441\u044F\u0446\u0430", Period.ofMonths(23)}, + {"24 \u043C\u0435\u0441\u044F\u0446\u0430", Period.ofMonths(24)}, + {"102 \u043C\u0435\u0441\u044F\u0446\u0430", Period.ofMonths(102)}, + {"112 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(112)}, + {"124 \u043C\u0435\u0441\u044F\u0446\u0430", Period.ofMonths(124)}, + {"5 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(5)}, + {"15 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(15)}, + {"25 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(25)}, + {"105 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(105)}, + {"1005 \u043C\u0435\u0441\u044F\u0446\u0435\u0432", Period.ofMonths(1005)}, + +// неделя \u043D\u0435\u0434\u0435\u043B\u044F +// недели \u043D\u0435\u0434\u0435\u043B\u0438 +// недель \u043D\u0435\u0434\u0435\u043B\u044C + {"1 \u043D\u0435\u0434\u0435\u043B\u044F", Period.ofWeeks(1)}, + {"11 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(11)}, + {"21 \u043D\u0435\u0434\u0435\u043B\u044F", Period.ofWeeks(21)}, + {"101 \u043D\u0435\u0434\u0435\u043B\u044F", Period.ofWeeks(101)}, + {"111 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(111)}, + {"121 \u043D\u0435\u0434\u0435\u043B\u044F", Period.ofWeeks(121)}, + {"2001 \u043D\u0435\u0434\u0435\u043B\u044F", Period.ofWeeks(2001)}, + {"2 \u043D\u0435\u0434\u0435\u043B\u0438", Period.ofWeeks(2)}, + {"3 \u043D\u0435\u0434\u0435\u043B\u0438", Period.ofWeeks(3)}, + {"4 \u043D\u0435\u0434\u0435\u043B\u0438", Period.ofWeeks(4)}, + {"12 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(12)}, + {"13 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(13)}, + {"14 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(14)}, + {"22 \u043D\u0435\u0434\u0435\u043B\u0438", Period.ofWeeks(22)}, + {"23 \u043D\u0435\u0434\u0435\u043B\u0438", Period.ofWeeks(23)}, + {"24 \u043D\u0435\u0434\u0435\u043B\u0438", Period.ofWeeks(24)}, + {"102 \u043D\u0435\u0434\u0435\u043B\u0438", Period.ofWeeks(102)}, + {"112 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(112)}, + {"124 \u043D\u0435\u0434\u0435\u043B\u0438", Period.ofWeeks(124)}, + {"5 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(5)}, + {"15 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(15)}, + {"25 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(25)}, + {"105 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(105)}, + {"1005 \u043D\u0435\u0434\u0435\u043B\u044C", Period.ofWeeks(1005)}, + +// день \u0434\u0435\u043D\u044C +// дня \u0434\u043D\u044F +// дней \u0434\u043D\u0435\u0439 + {"1 \u0434\u0435\u043D\u044C", Period.ofDays(1)}, + {"11 \u0434\u043D\u0435\u0439", Period.ofDays(11)}, + {"101 \u0434\u0435\u043D\u044C", Period.ofDays(101)}, + {"111 \u0434\u043D\u0435\u0439", Period.ofDays(111)}, + {"121 \u0434\u0435\u043D\u044C", Period.ofDays(121)}, + {"31 \u0434\u0435\u043D\u044C", Period.ofDays(31)}, + {"2001 \u0434\u0435\u043D\u044C", Period.ofDays(2001)}, + {"2 \u0434\u043D\u044F", Period.ofDays(2)}, + {"3 \u0434\u043D\u044F", Period.ofDays(3)}, + {"4 \u0434\u043D\u044F", Period.ofDays(4)}, + {"12 \u0434\u043D\u0435\u0439", Period.ofDays(12)}, + {"13 \u0434\u043D\u0435\u0439", Period.ofDays(13)}, + {"22 \u0434\u043D\u044F", Period.ofDays(22)}, + {"23 \u0434\u043D\u044F", Period.ofDays(23)}, + {"24 \u0434\u043D\u044F", Period.ofDays(24)}, + {"102 \u0434\u043D\u044F", Period.ofDays(102)}, + {"113 \u0434\u043D\u0435\u0439", Period.ofDays(113)}, + {"124 \u0434\u043D\u044F", Period.ofDays(124)}, + {"5 \u0434\u043D\u0435\u0439", Period.ofDays(5)}, + {"15 \u0434\u043D\u0435\u0439", Period.ofDays(15)}, + {"25 \u0434\u043D\u0435\u0439", Period.ofDays(25)}, + {"106 \u0434\u043D\u0435\u0439", Period.ofDays(106)}, + {"1005 \u0434\u043D\u0435\u0439", Period.ofDays(1005)} + }; + } + + // ----------------------------------------------------------------------- + @ParameterizedTest + @MethodSource("wordBased_ru_duration_predicate") + public void test_wordBased_ru_duration_predicate(String expected, Duration duration) { + assertEquals(expected, AmountFormats.wordBased(duration, RU)); + } + + public static Object[][] wordBased_ru_duration_predicate() { + return new Object[][]{ + +// час \u0447\u0430\u0441 +// часа \u0447\u0430\u0441\u0430 +// часов \u0447\u0430\u0441\u043E\u0432 + {"1 \u0447\u0430\u0441", Duration.ofHours(1)}, + {"11 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(11)}, + {"21 \u0447\u0430\u0441", Duration.ofHours(21)}, + {"101 \u0447\u0430\u0441", Duration.ofHours(101)}, + {"111 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(111)}, + {"121 \u0447\u0430\u0441", Duration.ofHours(121)}, + {"2001 \u0447\u0430\u0441", Duration.ofHours(2001)}, + {"2 \u0447\u0430\u0441\u0430", Duration.ofHours(2)}, + {"3 \u0447\u0430\u0441\u0430", Duration.ofHours(3)}, + {"4 \u0447\u0430\u0441\u0430", Duration.ofHours(4)}, + {"12 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(12)}, + {"13 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(13)}, + {"14 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(14)}, + {"22 \u0447\u0430\u0441\u0430", Duration.ofHours(22)}, + {"23 \u0447\u0430\u0441\u0430", Duration.ofHours(23)}, + {"24 \u0447\u0430\u0441\u0430", Duration.ofHours(24)}, + {"102 \u0447\u0430\u0441\u0430", Duration.ofHours(102)}, + {"112 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(112)}, + {"124 \u0447\u0430\u0441\u0430", Duration.ofHours(124)}, + {"5 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(5)}, + {"15 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(15)}, + {"25 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(25)}, + {"105 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(105)}, + {"1005 \u0447\u0430\u0441\u043e\u0432", Duration.ofHours(1005)}, + +// минута \u043C\u0438\u043D\u0443\u0442\u0430 +// минуты \u043C\u0438\u043D\u0443\u0442\u044B +// минут \u043C\u0438\u043D\u0443\u0442 + {"1 \u043c\u0438\u043d\u0443\u0442\u0430", Duration.ofMinutes(1)}, + {"11 \u043c\u0438\u043d\u0443\u0442", Duration.ofMinutes(11)}, + {"21 \u043c\u0438\u043d\u0443\u0442\u0430", Duration.ofMinutes(21)}, + {"2 \u043c\u0438\u043d\u0443\u0442\u044b", Duration.ofMinutes(2)}, + {"3 \u043c\u0438\u043d\u0443\u0442\u044b", Duration.ofMinutes(3)}, + {"4 \u043c\u0438\u043d\u0443\u0442\u044b", Duration.ofMinutes(4)}, + {"12 \u043c\u0438\u043d\u0443\u0442", Duration.ofMinutes(12)}, + {"13 \u043c\u0438\u043d\u0443\u0442", Duration.ofMinutes(13)}, + {"14 \u043c\u0438\u043d\u0443\u0442", Duration.ofMinutes(14)}, + {"22 \u043c\u0438\u043d\u0443\u0442\u044b", Duration.ofMinutes(22)}, + {"23 \u043c\u0438\u043d\u0443\u0442\u044b", Duration.ofMinutes(23)}, + {"24 \u043c\u0438\u043d\u0443\u0442\u044b", Duration.ofMinutes(24)}, + {"5 \u043c\u0438\u043d\u0443\u0442", Duration.ofMinutes(5)}, + {"15 \u043c\u0438\u043d\u0443\u0442", Duration.ofMinutes(15)}, + {"25 \u043c\u0438\u043d\u0443\u0442", Duration.ofMinutes(25)}, + +// секунда \u0441\u0435\u043A\u0443\u043D\u0434\u0430 +// секунды \u0441\u0435\u043A\u0443\u043D\u0434\u044B +// секунд \u0441\u0435\u043A\u0443\u043D\u0434 + {"1 \u0441\u0435\u043A\u0443\u043D\u0434\u0430", Duration.ofSeconds(1)}, + {"11 \u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofSeconds(11)}, + {"21 \u0441\u0435\u043A\u0443\u043D\u0434\u0430", Duration.ofSeconds(21)}, + {"2 \u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofSeconds(2)}, + {"3 \u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofSeconds(3)}, + {"4 \u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofSeconds(4)}, + {"12 \u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofSeconds(12)}, + {"13 \u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofSeconds(13)}, + {"14 \u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofSeconds(14)}, + {"22 \u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofSeconds(22)}, + {"23 \u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofSeconds(23)}, + {"24 \u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofSeconds(24)}, + {"5 \u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofSeconds(5)}, + {"15 \u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofSeconds(15)}, + {"25 \u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofSeconds(25)}, + +// миллисекунда \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u0430 +// миллисекунды \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B +// миллисекунд \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434 + {"1 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u0430", Duration.ofMillis(1)}, + {"11 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(11)}, + {"21 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u0430", Duration.ofMillis(21)}, + {"101 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u0430", Duration.ofMillis(101)}, + {"111 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(111)}, + {"121 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u0430", Duration.ofMillis(121)}, + {"2 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofMillis(2)}, + {"3 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofMillis(3)}, + {"4 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofMillis(4)}, + {"12 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(12)}, + {"13 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(13)}, + {"14 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(14)}, + {"22 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofMillis(22)}, + {"23 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofMillis(23)}, + {"24 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofMillis(24)}, + {"102 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofMillis(102)}, + {"112 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(112)}, + {"124 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434\u044B", Duration.ofMillis(124)}, + {"5 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(5)}, + {"15 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(15)}, + {"25 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(25)}, + {"105 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434", Duration.ofMillis(105)} + }; + } + + // ----------------------------------------------------------------------- + @ParameterizedTest + @MethodSource("duration_unitBased") + public void test_parseUnitBasedDuration(Duration expected, String input) { + assertEquals(expected, AmountFormats.parseUnitBasedDuration(input)); + } + + public static Object[][] duration_unitBased() { + return new Object[][] { + {Duration.ZERO, "0"}, + {Duration.ofHours(1), "+1h"}, + {Duration.ofHours(1).negated(), "-1h"}, + {Duration.ofHours(1).plusMinutes(15).negated(), "-1.25h"}, + {Duration.ofSeconds(15).plusMillis(110), "15.11s"}, + {Duration.ofHours(1).plusMinutes(2).plusSeconds(3).plusMillis(400), "1h2m3.4s"}, + {Duration.ofMinutes(1), "1m"}, + {Duration.ofSeconds(1), "1s"}, + {Duration.ofMillis(1), "1ms"}, + {Duration.ofNanos(1000), "1us"}, + {Duration.ofNanos(1000), "1µs"}, // U+00B5 = micro symbol + {Duration.ofNanos(1000), "1μs"}, // U+03BC = Greek letter mu + {Duration.ofNanos(1), "1ns"}, + {Duration.ofHours(1).plusMinutes(1).plusSeconds(1), "1h1m1s"}, + // Loss of precision, but still a valid duration. + {Duration.ofSeconds(1).plusNanos(999_999_999), "1.9999999999999999999999999999s"}, + // Adding duration values to exactly the max duration. + {Duration.ofSeconds(Long.MAX_VALUE), String.format("%ds%ds", Long.MAX_VALUE - 2, 2)}, + }; + } + + @ParameterizedTest + @MethodSource("duration_unitBasedErrors") + public void test_parseUnitBasedDurationErrors(Exception e, String input) { + Exception thrown = + assertThrows(e.getClass(), () -> AmountFormats.parseUnitBasedDuration(input)); + assertEquals(e.getMessage(), thrown.getMessage()); + if (e instanceof DateTimeParseException) { + DateTimeParseException expected = (DateTimeParseException) e; + DateTimeParseException actual = (DateTimeParseException) thrown; + assertEquals(expected.getParsedString(), actual.getParsedString()); + assertEquals(expected.getErrorIndex(), actual.getErrorIndex()); + } + } + + public static Object[][] duration_unitBasedErrors() { + return new Object[][] { + {new NullPointerException("durationText must not be null"), null}, + {new DateTimeParseException("Not a numeric value", "", 0), ""}, + {new DateTimeParseException("Not a numeric value", "+", 0), "+"}, + {new DateTimeParseException("Not a numeric value", "-", 0), "-"}, + {new DateTimeParseException("Missing leading integer", ".", 0), "."}, + {new DateTimeParseException("Missing leading integer", ".1s", 0), ".1s"}, + {new DateTimeParseException("Missing leading integer", "inf", 0), "inf"}, + {new DateTimeParseException("Missing leading integer", "-inf", 1), "-inf"}, + {new DateTimeParseException("Missing numeric fraction after '.'", "1.b", 2), "1.b"}, + {new DateTimeParseException("Invalid duration unit", "1.1ps", 3), "1.1ps"}, + {new DateTimeParseException( + "Duration string exceeds valid numeric range", "9223372036854775807h", 19), + String.format("%dh", Long.MAX_VALUE)}, // overflow in create duration + {new DateTimeParseException( + "Duration string exceeds valid numeric range", "-9223372036854775808h", 19), + String.format("%dh", Long.MAX_VALUE + 1)}, // overflow in leading int + {new DateTimeParseException( + "Duration string exceeds valid numeric range", + "9223372036854775806s2s", 21), + String.format("%ds2s", Long.MAX_VALUE - 1)}, // overflow on int add + // overflow on fraction add + {new DateTimeParseException( + "Duration string exceeds valid numeric range", + "9223372036854775805.1s2.999999999s", 33), + String.format("%d.1s2.999999999s", Long.MAX_VALUE - 2)} + }; + } +} diff --git a/src/test/java/org/threeten/extra/TestConvert.java b/src/test/java/org/threeten/extra/TestConvert.java new file mode 100644 index 00000000..5ff8ef8d --- /dev/null +++ b/src/test/java/org/threeten/extra/TestConvert.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.Period; + +import org.joda.convert.StringConvert; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.threeten.extra.scale.TaiInstant; +import org.threeten.extra.scale.UtcInstant; + +public class TestConvert { + + public static Object[][] data_inputs() { + return new Object[][] { + {Seconds.of(23), "PT23S"}, + {Minutes.of(23), "PT23M"}, + {Hours.of(23), "PT23H"}, + {Days.of(23), "P23D"}, + {Weeks.of(23), "P23W"}, + {Months.of(23), "P23M"}, + {Years.of(23), "P23Y"}, + {YearWeek.of(2019, 3), "2019-W03"}, + {YearQuarter.of(2019, 3), "2019-Q3"}, + {PeriodDuration.of(Period.of(1, 2, 3), Duration.ofHours(6)), "P1Y2M3DT6H"}, + {Interval.of(Instant.ofEpochSecond(60), Duration.ofHours(6)), "1970-01-01T00:01:00Z/1970-01-01T06:01:00Z"}, + {LocalDateRange.of(LocalDate.of(2018, 6, 1), LocalDate.of(2018, 9, 15)), "2018-06-01/2018-09-15"}, + {TaiInstant.ofTaiSeconds(123, 456), "123.000000456s(TAI)"}, + {UtcInstant.ofModifiedJulianDay(0, 1123456789L), "1858-11-17T00:00:01.123456789Z"}, + }; + } + + @ParameterizedTest + @MethodSource("data_inputs") + public void test_convertToString(Object obj, String str) { + assertEquals(str, StringConvert.INSTANCE.convertToString(obj)); + } + + @ParameterizedTest + @MethodSource("data_inputs") + public void test_convertFromString(Object obj, String str) { + assertEquals(obj, StringConvert.INSTANCE.convertFromString(obj.getClass(), str)); + } + +} diff --git a/src/test/java/org/threeten/extra/TestDayOfMonth.java b/src/test/java/org/threeten/extra/TestDayOfMonth.java index 3ef1b28e..fa1f7e24 100644 --- a/src/test/java/org/threeten/extra/TestDayOfMonth.java +++ b/src/test/java/org/threeten/extra/TestDayOfMonth.java @@ -73,8 +73,11 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -92,31 +95,86 @@ import java.time.YearMonth; import java.time.ZoneId; import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseDate; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.RetryingTest; + +import com.google.common.testing.EqualsTester; /** * Test DayOfMonth. */ -@Test public class TestDayOfMonth { private static final int MAX_LENGTH = 31; private static final DayOfMonth TEST = DayOfMonth.of(12); private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); - @BeforeMethod - public void setUp() { + private static class TestingField implements TemporalField { + + public static final TestingField INSTANCE = new TestingField(); + + @Override + public TemporalUnit getBaseUnit() { + return ChronoUnit.DAYS; + } + + @Override + public TemporalUnit getRangeUnit() { + return ChronoUnit.MONTHS; + } + + @Override + public ValueRange range() { + return ValueRange.of(1, 28, 31); + } + + @Override + public boolean isDateBased() { + return true; + } + + @Override + public boolean isTimeBased() { + return false; + } + + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + return temporal.isSupported(DAY_OF_MONTH); + } + + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + return range(); + } + + @Override + public long getFrom(TemporalAccessor temporal) { + return temporal.getLong(DAY_OF_MONTH); + } + + @Override + @SuppressWarnings("unchecked") + public R adjustInto(R temporal, long newValue) { + return (R) temporal.with(DAY_OF_MONTH, newValue); + } } //----------------------------------------------------------------------- + @Test public void test_interfaces() { assertTrue(Serializable.class.isAssignableFrom(DayOfMonth.class)); assertTrue(Comparable.class.isAssignableFrom(DayOfMonth.class)); @@ -124,206 +182,260 @@ public void test_interfaces() { assertTrue(TemporalAccessor.class.isAssignableFrom(DayOfMonth.class)); } + @Test public void test_serialization() throws IOException, ClassNotFoundException { DayOfMonth test = DayOfMonth.of(1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(test); - oos.close(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertEquals(test, ois.readObject()); + } + } - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( - baos.toByteArray())); - assertEquals(ois.readObject(), test); + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @RetryingTest(100) + public void test_now() { + assertEquals(LocalDate.now().getDayOfMonth(), DayOfMonth.now().getValue()); + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @RetryingTest(100) + public void test_now_ZoneId() { + ZoneId zone = ZoneId.of("Asia/Tokyo"); + assertEquals(LocalDate.now(zone).getDayOfMonth(), DayOfMonth.now(zone).getValue()); } //----------------------------------------------------------------------- // of(int) //----------------------------------------------------------------------- + @Test public void test_of_int_singleton() { for (int i = 1; i <= MAX_LENGTH; i++) { DayOfMonth test = DayOfMonth.of(i); - assertEquals(test.getValue(), i); - assertEquals(DayOfMonth.of(i), test); + assertEquals(i, test.getValue()); + assertSame(test, DayOfMonth.of(i)); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_tooLow() { - DayOfMonth.of(0); + assertThrows(DateTimeException.class, () -> DayOfMonth.of(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_tooHigh() { - DayOfMonth.of(32); + assertThrows(DateTimeException.class, () -> DayOfMonth.of(32)); } //----------------------------------------------------------------------- // from(TemporalAccessor) //----------------------------------------------------------------------- + @Test public void test_from_TemporalAccessor_notLeapYear() { LocalDate date = LocalDate.of(2007, 1, 1); for (int i = 1; i <= 31; i++) { // Jan - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 28; i++) { // Feb - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 31; i++) { // Mar - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 30; i++) { // Apr - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 31; i++) { // May - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 30; i++) { // Jun - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 31; i++) { // Jul - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 31; i++) { // Aug - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 30; i++) { // Sep - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 31; i++) { // Oct - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 30; i++) { // Nov - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 31; i++) { // Dec - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } } + @Test public void test_from_TemporalAccessor_leapYear() { LocalDate date = LocalDate.of(2008, 1, 1); for (int i = 1; i <= 31; i++) { // Jan - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 29; i++) { // Feb - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } for (int i = 1; i <= 31; i++) { // Mar - assertEquals(DayOfMonth.from(date).getValue(), i); + assertEquals(i, DayOfMonth.from(date).getValue()); date = date.plusDays(1); } } - @Test(expectedExceptions = DateTimeException.class) + @Test + public void test_from_TemporalAccessor_DayOfMonth() { + DayOfMonth dom = DayOfMonth.of(6); + assertEquals(dom, DayOfMonth.from(dom)); + } + + @Test + public void test_from_TemporalAccessor_nonIso() { + LocalDate date = LocalDate.now(); + assertEquals(date.getDayOfMonth(), DayOfMonth.from(JapaneseDate.from(date)).getValue()); + } + + @Test public void test_from_TemporalAccessor_noDerive() { - DayOfMonth.from(LocalTime.NOON); + assertThrows(DateTimeException.class, () -> DayOfMonth.from(LocalTime.NOON)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_TemporalAccessor_null() { - DayOfMonth.from((TemporalAccessor) null); + assertThrows(NullPointerException.class, () -> DayOfMonth.from((TemporalAccessor) null)); + } + + @Test + public void test_from_parse_CharSequence() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d"); + assertEquals(DayOfMonth.of(3), formatter.parse("3", DayOfMonth::from)); } //----------------------------------------------------------------------- // isSupported(TemporalField) //----------------------------------------------------------------------- + @Test public void test_isSupported() { - assertEquals(TEST.isSupported((TemporalField) null), false); - assertEquals(TEST.isSupported(NANO_OF_SECOND), false); - assertEquals(TEST.isSupported(NANO_OF_DAY), false); - assertEquals(TEST.isSupported(MICRO_OF_SECOND), false); - assertEquals(TEST.isSupported(MICRO_OF_DAY), false); - assertEquals(TEST.isSupported(MILLI_OF_SECOND), false); - assertEquals(TEST.isSupported(MILLI_OF_DAY), false); - assertEquals(TEST.isSupported(SECOND_OF_MINUTE), false); - assertEquals(TEST.isSupported(SECOND_OF_DAY), false); - assertEquals(TEST.isSupported(MINUTE_OF_HOUR), false); - assertEquals(TEST.isSupported(MINUTE_OF_DAY), false); - assertEquals(TEST.isSupported(HOUR_OF_AMPM), false); - assertEquals(TEST.isSupported(CLOCK_HOUR_OF_AMPM), false); - assertEquals(TEST.isSupported(HOUR_OF_DAY), false); - assertEquals(TEST.isSupported(CLOCK_HOUR_OF_DAY), false); - assertEquals(TEST.isSupported(AMPM_OF_DAY), false); - assertEquals(TEST.isSupported(DAY_OF_WEEK), false); - assertEquals(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH), false); - assertEquals(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR), false); - assertEquals(TEST.isSupported(DAY_OF_MONTH), true); - assertEquals(TEST.isSupported(DAY_OF_YEAR), false); - assertEquals(TEST.isSupported(EPOCH_DAY), false); - assertEquals(TEST.isSupported(ALIGNED_WEEK_OF_MONTH), false); - assertEquals(TEST.isSupported(ALIGNED_WEEK_OF_YEAR), false); - assertEquals(TEST.isSupported(MONTH_OF_YEAR), false); - assertEquals(TEST.isSupported(PROLEPTIC_MONTH), false); - assertEquals(TEST.isSupported(YEAR_OF_ERA), false); - assertEquals(TEST.isSupported(YEAR), false); - assertEquals(TEST.isSupported(ERA), false); - assertEquals(TEST.isSupported(INSTANT_SECONDS), false); - assertEquals(TEST.isSupported(OFFSET_SECONDS), false); + assertEquals(false, TEST.isSupported((TemporalField) null)); + assertEquals(false, TEST.isSupported(NANO_OF_SECOND)); + assertEquals(false, TEST.isSupported(NANO_OF_DAY)); + assertEquals(false, TEST.isSupported(MICRO_OF_SECOND)); + assertEquals(false, TEST.isSupported(MICRO_OF_DAY)); + assertEquals(false, TEST.isSupported(MILLI_OF_SECOND)); + assertEquals(false, TEST.isSupported(MILLI_OF_DAY)); + assertEquals(false, TEST.isSupported(SECOND_OF_MINUTE)); + assertEquals(false, TEST.isSupported(SECOND_OF_DAY)); + assertEquals(false, TEST.isSupported(MINUTE_OF_HOUR)); + assertEquals(false, TEST.isSupported(MINUTE_OF_DAY)); + assertEquals(false, TEST.isSupported(HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(AMPM_OF_DAY)); + assertEquals(false, TEST.isSupported(DAY_OF_WEEK)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(true, TEST.isSupported(DAY_OF_MONTH)); + assertEquals(false, TEST.isSupported(DAY_OF_YEAR)); + assertEquals(false, TEST.isSupported(EPOCH_DAY)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_YEAR)); + assertEquals(false, TEST.isSupported(MONTH_OF_YEAR)); + assertEquals(false, TEST.isSupported(PROLEPTIC_MONTH)); + assertEquals(false, TEST.isSupported(YEAR_OF_ERA)); + assertEquals(false, TEST.isSupported(YEAR)); + assertEquals(false, TEST.isSupported(ERA)); + assertEquals(false, TEST.isSupported(INSTANT_SECONDS)); + assertEquals(false, TEST.isSupported(OFFSET_SECONDS)); + assertEquals(false, TEST.isSupported(IsoFields.DAY_OF_QUARTER)); + assertEquals(true, TEST.isSupported(TestingField.INSTANCE)); } //----------------------------------------------------------------------- // range(TemporalField) //----------------------------------------------------------------------- + @Test public void test_range() { - assertEquals(TEST.range(DAY_OF_MONTH), DAY_OF_MONTH.range()); + assertEquals(DAY_OF_MONTH.range(), TEST.range(DAY_OF_MONTH)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_invalidField() { - TEST.range(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.range(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_range_null() { - TEST.range((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.range((TemporalField) null)); } //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- + @Test public void test_get() { - assertEquals(TEST.get(DAY_OF_MONTH), 12); + assertEquals(12, TEST.get(DAY_OF_MONTH)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_get_invalidField() { - TEST.get(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.get(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_get_null() { - TEST.get((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.get((TemporalField) null)); } //----------------------------------------------------------------------- // getLong(TemporalField) //----------------------------------------------------------------------- + @Test public void test_getLong() { - assertEquals(TEST.getLong(DAY_OF_MONTH), 12L); + assertEquals(12L, TEST.getLong(DAY_OF_MONTH)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test + public void test_getLong_derivedField() { + assertEquals(12L, TEST.getLong(TestingField.INSTANCE)); + } + + @Test public void test_getLong_invalidField() { - TEST.getLong(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.getLong(MONTH_OF_YEAR)); + } + + @Test + public void test_getLong_invalidField2() { + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.getLong(IsoFields.DAY_OF_QUARTER)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getLong_null() { - TEST.getLong((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.getLong((TemporalField) null)); } //----------------------------------------------------------------------- @@ -332,70 +444,75 @@ public void test_getLong_null() { @Test public void test_isValidYearMonth_31() { DayOfMonth test = DayOfMonth.of(31); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 1)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 2)), false); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 3)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 4)), false); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 5)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 6)), false); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 7)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 8)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 9)), false); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 10)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 11)), false); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 12)), true); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 1))); + assertEquals(false, test.isValidYearMonth(YearMonth.of(2012, 2))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 3))); + assertEquals(false, test.isValidYearMonth(YearMonth.of(2012, 4))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 5))); + assertEquals(false, test.isValidYearMonth(YearMonth.of(2012, 6))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 7))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 8))); + assertEquals(false, test.isValidYearMonth(YearMonth.of(2012, 9))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 10))); + assertEquals(false, test.isValidYearMonth(YearMonth.of(2012, 11))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 12))); } @Test public void test_isValidYearMonth_30() { DayOfMonth test = DayOfMonth.of(30); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 1)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 2)), false); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 3)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 4)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 5)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 6)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 7)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 8)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 9)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 10)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 11)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 12)), true); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 1))); + assertEquals(false, test.isValidYearMonth(YearMonth.of(2012, 2))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 3))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 4))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 5))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 6))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 7))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 8))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 9))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 10))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 11))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 12))); } @Test public void test_isValidYearMonth_29() { DayOfMonth test = DayOfMonth.of(29); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 1)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 2)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 3)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 4)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 5)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 6)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 7)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 8)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 9)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 10)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 11)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 12)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2011, 2)), false); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 1))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 2))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 3))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 4))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 5))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 6))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 7))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 8))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 9))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 10))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 11))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 12))); + assertEquals(false, test.isValidYearMonth(YearMonth.of(2011, 2))); } @Test public void test_isValidYearMonth_28() { DayOfMonth test = DayOfMonth.of(28); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 1)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 2)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 3)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 4)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 5)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 6)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 7)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 8)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 9)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 10)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 11)), true); - assertEquals(test.isValidYearMonth(YearMonth.of(2012, 12)), true); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 1))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 2))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 3))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 4))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 5))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 6))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 7))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 8))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 9))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 10))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 11))); + assertEquals(true, test.isValidYearMonth(YearMonth.of(2012, 12))); + } + + @Test + public void test_isValidYearMonth_null() { + assertFalse(TEST.isValidYearMonth((YearMonth) null)); } //----------------------------------------------------------------------- @@ -403,45 +520,51 @@ public void test_isValidYearMonth_28() { //----------------------------------------------------------------------- @Test public void test_query() { - assertEquals(TEST.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); - assertEquals(TEST.query(TemporalQueries.localDate()), null); - assertEquals(TEST.query(TemporalQueries.localTime()), null); - assertEquals(TEST.query(TemporalQueries.offset()), null); - assertEquals(TEST.query(TemporalQueries.precision()), null); - assertEquals(TEST.query(TemporalQueries.zone()), null); - assertEquals(TEST.query(TemporalQueries.zoneId()), null); + assertEquals(IsoChronology.INSTANCE, TEST.query(TemporalQueries.chronology())); + assertEquals(null, TEST.query(TemporalQueries.localDate())); + assertEquals(null, TEST.query(TemporalQueries.localTime())); + assertEquals(null, TEST.query(TemporalQueries.offset())); + assertEquals(null, TEST.query(TemporalQueries.precision())); + assertEquals(null, TEST.query(TemporalQueries.zone())); + assertEquals(null, TEST.query(TemporalQueries.zoneId())); } //----------------------------------------------------------------------- // adjustInto(Temporal) //----------------------------------------------------------------------- + @Test public void test_adjustInto() { LocalDate base = LocalDate.of(2007, 1, 1); LocalDate expected = base; for (int i = 1; i <= MAX_LENGTH; i++) { // Jan Temporal result = DayOfMonth.of(i).adjustInto(base); - assertEquals(result, expected); + assertEquals(expected, result); expected = expected.plusDays(1); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjustInto_april31() { LocalDate base = LocalDate.of(2007, 4, 1); DayOfMonth test = DayOfMonth.of(31); - test.adjustInto(base); + assertThrows(DateTimeException.class, () -> test.adjustInto(base)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjustInto_february29_notLeapYear() { LocalDate base = LocalDate.of(2007, 2, 1); DayOfMonth test = DayOfMonth.of(29); - test.adjustInto(base); + assertThrows(DateTimeException.class, () -> test.adjustInto(base)); + } + + @Test + public void test_adjustInto_nonIso() { + assertThrows(DateTimeException.class, () -> TEST.adjustInto(JapaneseDate.now())); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_adjustInto_null() { - TEST.adjustInto((Temporal) null); + assertThrows(NullPointerException.class, () -> TEST.adjustInto((Temporal) null)); } //----------------------------------------------------------------------- @@ -450,40 +573,40 @@ public void test_adjustInto_null() { @Test public void test_atMonth_Month_31() { DayOfMonth test = DayOfMonth.of(31); - assertEquals(test.atMonth(JANUARY), MonthDay.of(1, 31)); - assertEquals(test.atMonth(FEBRUARY), MonthDay.of(2, 29)); - assertEquals(test.atMonth(MARCH), MonthDay.of(3, 31)); - assertEquals(test.atMonth(APRIL), MonthDay.of(4, 30)); - assertEquals(test.atMonth(MAY), MonthDay.of(5, 31)); - assertEquals(test.atMonth(JUNE), MonthDay.of(6, 30)); - assertEquals(test.atMonth(JULY), MonthDay.of(7, 31)); - assertEquals(test.atMonth(AUGUST), MonthDay.of(8, 31)); - assertEquals(test.atMonth(SEPTEMBER), MonthDay.of(9, 30)); - assertEquals(test.atMonth(OCTOBER), MonthDay.of(10, 31)); - assertEquals(test.atMonth(NOVEMBER), MonthDay.of(11, 30)); - assertEquals(test.atMonth(DECEMBER), MonthDay.of(12, 31)); + assertEquals(MonthDay.of(1, 31), test.atMonth(JANUARY)); + assertEquals(MonthDay.of(2, 29), test.atMonth(FEBRUARY)); + assertEquals(MonthDay.of(3, 31), test.atMonth(MARCH)); + assertEquals(MonthDay.of(4, 30), test.atMonth(APRIL)); + assertEquals(MonthDay.of(5, 31), test.atMonth(MAY)); + assertEquals(MonthDay.of(6, 30), test.atMonth(JUNE)); + assertEquals(MonthDay.of(7, 31), test.atMonth(JULY)); + assertEquals(MonthDay.of(8, 31), test.atMonth(AUGUST)); + assertEquals(MonthDay.of(9, 30), test.atMonth(SEPTEMBER)); + assertEquals(MonthDay.of(10, 31), test.atMonth(OCTOBER)); + assertEquals(MonthDay.of(11, 30), test.atMonth(NOVEMBER)); + assertEquals(MonthDay.of(12, 31), test.atMonth(DECEMBER)); } @Test public void test_atMonth_Month_28() { DayOfMonth test = DayOfMonth.of(28); - assertEquals(test.atMonth(JANUARY), MonthDay.of(1, 28)); - assertEquals(test.atMonth(FEBRUARY), MonthDay.of(2, 28)); - assertEquals(test.atMonth(MARCH), MonthDay.of(3, 28)); - assertEquals(test.atMonth(APRIL), MonthDay.of(4, 28)); - assertEquals(test.atMonth(MAY), MonthDay.of(5, 28)); - assertEquals(test.atMonth(JUNE), MonthDay.of(6, 28)); - assertEquals(test.atMonth(JULY), MonthDay.of(7, 28)); - assertEquals(test.atMonth(AUGUST), MonthDay.of(8, 28)); - assertEquals(test.atMonth(SEPTEMBER), MonthDay.of(9, 28)); - assertEquals(test.atMonth(OCTOBER), MonthDay.of(10, 28)); - assertEquals(test.atMonth(NOVEMBER), MonthDay.of(11, 28)); - assertEquals(test.atMonth(DECEMBER), MonthDay.of(12, 28)); - } - - @Test(expectedExceptions = NullPointerException.class) + assertEquals(MonthDay.of(1, 28), test.atMonth(JANUARY)); + assertEquals(MonthDay.of(2, 28), test.atMonth(FEBRUARY)); + assertEquals(MonthDay.of(3, 28), test.atMonth(MARCH)); + assertEquals(MonthDay.of(4, 28), test.atMonth(APRIL)); + assertEquals(MonthDay.of(5, 28), test.atMonth(MAY)); + assertEquals(MonthDay.of(6, 28), test.atMonth(JUNE)); + assertEquals(MonthDay.of(7, 28), test.atMonth(JULY)); + assertEquals(MonthDay.of(8, 28), test.atMonth(AUGUST)); + assertEquals(MonthDay.of(9, 28), test.atMonth(SEPTEMBER)); + assertEquals(MonthDay.of(10, 28), test.atMonth(OCTOBER)); + assertEquals(MonthDay.of(11, 28), test.atMonth(NOVEMBER)); + assertEquals(MonthDay.of(12, 28), test.atMonth(DECEMBER)); + } + + @Test public void test_atMonth_null() { - TEST.atMonth((Month) null); + assertThrows(NullPointerException.class, () -> TEST.atMonth((Month) null)); } //----------------------------------------------------------------------- @@ -492,45 +615,45 @@ public void test_atMonth_null() { @Test public void test_atMonth_int_31() { DayOfMonth test = DayOfMonth.of(31); - assertEquals(test.atMonth(1), MonthDay.of(1, 31)); - assertEquals(test.atMonth(2), MonthDay.of(2, 29)); - assertEquals(test.atMonth(3), MonthDay.of(3, 31)); - assertEquals(test.atMonth(4), MonthDay.of(4, 30)); - assertEquals(test.atMonth(5), MonthDay.of(5, 31)); - assertEquals(test.atMonth(6), MonthDay.of(6, 30)); - assertEquals(test.atMonth(7), MonthDay.of(7, 31)); - assertEquals(test.atMonth(8), MonthDay.of(8, 31)); - assertEquals(test.atMonth(9), MonthDay.of(9, 30)); - assertEquals(test.atMonth(10), MonthDay.of(10, 31)); - assertEquals(test.atMonth(11), MonthDay.of(11, 30)); - assertEquals(test.atMonth(12), MonthDay.of(12, 31)); + assertEquals(MonthDay.of(1, 31), test.atMonth(1)); + assertEquals(MonthDay.of(2, 29), test.atMonth(2)); + assertEquals(MonthDay.of(3, 31), test.atMonth(3)); + assertEquals(MonthDay.of(4, 30), test.atMonth(4)); + assertEquals(MonthDay.of(5, 31), test.atMonth(5)); + assertEquals(MonthDay.of(6, 30), test.atMonth(6)); + assertEquals(MonthDay.of(7, 31), test.atMonth(7)); + assertEquals(MonthDay.of(8, 31), test.atMonth(8)); + assertEquals(MonthDay.of(9, 30), test.atMonth(9)); + assertEquals(MonthDay.of(10, 31), test.atMonth(10)); + assertEquals(MonthDay.of(11, 30), test.atMonth(11)); + assertEquals(MonthDay.of(12, 31), test.atMonth(12)); } @Test public void test_atMonth_int_28() { DayOfMonth test = DayOfMonth.of(28); - assertEquals(test.atMonth(1), MonthDay.of(1, 28)); - assertEquals(test.atMonth(2), MonthDay.of(2, 28)); - assertEquals(test.atMonth(3), MonthDay.of(3, 28)); - assertEquals(test.atMonth(4), MonthDay.of(4, 28)); - assertEquals(test.atMonth(5), MonthDay.of(5, 28)); - assertEquals(test.atMonth(6), MonthDay.of(6, 28)); - assertEquals(test.atMonth(7), MonthDay.of(7, 28)); - assertEquals(test.atMonth(8), MonthDay.of(8, 28)); - assertEquals(test.atMonth(9), MonthDay.of(9, 28)); - assertEquals(test.atMonth(10), MonthDay.of(10, 28)); - assertEquals(test.atMonth(11), MonthDay.of(11, 28)); - assertEquals(test.atMonth(12), MonthDay.of(12, 28)); - } - - @Test(expectedExceptions = DateTimeException.class) + assertEquals(MonthDay.of(1, 28), test.atMonth(1)); + assertEquals(MonthDay.of(2, 28), test.atMonth(2)); + assertEquals(MonthDay.of(3, 28), test.atMonth(3)); + assertEquals(MonthDay.of(4, 28), test.atMonth(4)); + assertEquals(MonthDay.of(5, 28), test.atMonth(5)); + assertEquals(MonthDay.of(6, 28), test.atMonth(6)); + assertEquals(MonthDay.of(7, 28), test.atMonth(7)); + assertEquals(MonthDay.of(8, 28), test.atMonth(8)); + assertEquals(MonthDay.of(9, 28), test.atMonth(9)); + assertEquals(MonthDay.of(10, 28), test.atMonth(10)); + assertEquals(MonthDay.of(11, 28), test.atMonth(11)); + assertEquals(MonthDay.of(12, 28), test.atMonth(12)); + } + + @Test public void test_atMonth_tooLow() { - TEST.atMonth(0); + assertThrows(DateTimeException.class, () -> TEST.atMonth(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atMonth_tooHigh() { - TEST.atMonth(13); + assertThrows(DateTimeException.class, () -> TEST.atMonth(13)); } //----------------------------------------------------------------------- @@ -539,115 +662,105 @@ public void test_atMonth_tooHigh() { @Test public void test_atYearMonth_31() { DayOfMonth test = DayOfMonth.of(31); - assertEquals(test.atYearMonth(YearMonth.of(2012, 1)), LocalDate.of(2012, 1, 31)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 2)), LocalDate.of(2012, 2, 29)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 3)), LocalDate.of(2012, 3, 31)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 4)), LocalDate.of(2012, 4, 30)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 5)), LocalDate.of(2012, 5, 31)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 6)), LocalDate.of(2012, 6, 30)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 7)), LocalDate.of(2012, 7, 31)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 8)), LocalDate.of(2012, 8, 31)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 9)), LocalDate.of(2012, 9, 30)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 10)), LocalDate.of(2012, 10, 31)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 11)), LocalDate.of(2012, 11, 30)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 12)), LocalDate.of(2012, 12, 31)); - assertEquals(test.atYearMonth(YearMonth.of(2011, 2)), LocalDate.of(2011, 2, 28)); + assertEquals(LocalDate.of(2012, 1, 31), test.atYearMonth(YearMonth.of(2012, 1))); + assertEquals(LocalDate.of(2012, 2, 29), test.atYearMonth(YearMonth.of(2012, 2))); + assertEquals(LocalDate.of(2012, 3, 31), test.atYearMonth(YearMonth.of(2012, 3))); + assertEquals(LocalDate.of(2012, 4, 30), test.atYearMonth(YearMonth.of(2012, 4))); + assertEquals(LocalDate.of(2012, 5, 31), test.atYearMonth(YearMonth.of(2012, 5))); + assertEquals(LocalDate.of(2012, 6, 30), test.atYearMonth(YearMonth.of(2012, 6))); + assertEquals(LocalDate.of(2012, 7, 31), test.atYearMonth(YearMonth.of(2012, 7))); + assertEquals(LocalDate.of(2012, 8, 31), test.atYearMonth(YearMonth.of(2012, 8))); + assertEquals(LocalDate.of(2012, 9, 30), test.atYearMonth(YearMonth.of(2012, 9))); + assertEquals(LocalDate.of(2012, 10, 31), test.atYearMonth(YearMonth.of(2012, 10))); + assertEquals(LocalDate.of(2012, 11, 30), test.atYearMonth(YearMonth.of(2012, 11))); + assertEquals(LocalDate.of(2012, 12, 31), test.atYearMonth(YearMonth.of(2012, 12))); + assertEquals(LocalDate.of(2011, 2, 28), test.atYearMonth(YearMonth.of(2011, 2))); } @Test public void test_atYearMonth_28() { DayOfMonth test = DayOfMonth.of(28); - assertEquals(test.atYearMonth(YearMonth.of(2012, 1)), LocalDate.of(2012, 1, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 2)), LocalDate.of(2012, 2, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 3)), LocalDate.of(2012, 3, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 4)), LocalDate.of(2012, 4, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 5)), LocalDate.of(2012, 5, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 6)), LocalDate.of(2012, 6, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 7)), LocalDate.of(2012, 7, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 8)), LocalDate.of(2012, 8, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 9)), LocalDate.of(2012, 9, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 10)), LocalDate.of(2012, 10, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 11)), LocalDate.of(2012, 11, 28)); - assertEquals(test.atYearMonth(YearMonth.of(2012, 12)), LocalDate.of(2012, 12, 28)); - } - - @Test(expectedExceptions = NullPointerException.class) + assertEquals(LocalDate.of(2012, 1, 28), test.atYearMonth(YearMonth.of(2012, 1))); + assertEquals(LocalDate.of(2012, 2, 28), test.atYearMonth(YearMonth.of(2012, 2))); + assertEquals(LocalDate.of(2012, 3, 28), test.atYearMonth(YearMonth.of(2012, 3))); + assertEquals(LocalDate.of(2012, 4, 28), test.atYearMonth(YearMonth.of(2012, 4))); + assertEquals(LocalDate.of(2012, 5, 28), test.atYearMonth(YearMonth.of(2012, 5))); + assertEquals(LocalDate.of(2012, 6, 28), test.atYearMonth(YearMonth.of(2012, 6))); + assertEquals(LocalDate.of(2012, 7, 28), test.atYearMonth(YearMonth.of(2012, 7))); + assertEquals(LocalDate.of(2012, 8, 28), test.atYearMonth(YearMonth.of(2012, 8))); + assertEquals(LocalDate.of(2012, 9, 28), test.atYearMonth(YearMonth.of(2012, 9))); + assertEquals(LocalDate.of(2012, 10, 28), test.atYearMonth(YearMonth.of(2012, 10))); + assertEquals(LocalDate.of(2012, 11, 28), test.atYearMonth(YearMonth.of(2012, 11))); + assertEquals(LocalDate.of(2012, 12, 28), test.atYearMonth(YearMonth.of(2012, 12))); + } + + @Test public void test_atYearMonth_null() { - TEST.atYearMonth((YearMonth) null); + assertThrows(NullPointerException.class, () -> TEST.atYearMonth((YearMonth) null)); } //----------------------------------------------------------------------- // compareTo() //----------------------------------------------------------------------- + @Test public void test_compareTo() { for (int i = 1; i <= MAX_LENGTH; i++) { DayOfMonth a = DayOfMonth.of(i); for (int j = 1; j <= MAX_LENGTH; j++) { DayOfMonth b = DayOfMonth.of(j); if (i < j) { - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); + assertEquals(true, a.compareTo(b) < 0); + assertEquals(true, b.compareTo(a) > 0); } else if (i > j) { - assertEquals(a.compareTo(b) > 0, true); - assertEquals(b.compareTo(a) < 0, true); + assertEquals(true, a.compareTo(b) > 0); + assertEquals(true, b.compareTo(a) < 0); } else { - assertEquals(a.compareTo(b), 0); - assertEquals(b.compareTo(a), 0); + assertEquals(0, a.compareTo(b)); + assertEquals(0, b.compareTo(a)); } } } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_nullDayOfMonth() { - DayOfMonth doy = null; + DayOfMonth dom = null; DayOfMonth test = DayOfMonth.of(1); - test.compareTo(doy); + assertThrows(NullPointerException.class, () -> test.compareTo(dom)); } //----------------------------------------------------------------------- // equals() / hashCode() //----------------------------------------------------------------------- - public void test_equals() { + @Test + public void test_equals_and_hashCode() { + EqualsTester equalsTester = new EqualsTester(); for (int i = 1; i <= MAX_LENGTH; i++) { - DayOfMonth a = DayOfMonth.of(i); - for (int j = 1; j <= MAX_LENGTH; j++) { - DayOfMonth b = DayOfMonth.of(j); - assertEquals(a.equals(b), i == j); - assertEquals(a.hashCode() == b.hashCode(), i == j); - } + equalsTester.addEqualityGroup(DayOfMonth.of(i), DayOfMonth.of(i)); } - } - - public void test_equals_nullDayOfMonth() { - DayOfMonth doy = null; - DayOfMonth test = DayOfMonth.of(1); - assertEquals(test.equals(doy), false); - } - - public void test_equals_incorrectType() { - DayOfMonth test = DayOfMonth.of(1); - assertEquals(test.equals("Incorrect type"), false); + equalsTester.testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- + @Test public void test_toString() { for (int i = 1; i <= MAX_LENGTH; i++) { DayOfMonth a = DayOfMonth.of(i); - assertEquals(a.toString(), "DayOfMonth:" + i); + assertEquals("DayOfMonth:" + i, a.toString()); } } //----------------------------------------------------------------------- // now(Clock) //----------------------------------------------------------------------- + @Test public void test_now_clock() { for (int i = 1; i <= 31; i++) { // Jan Instant instant = LocalDate.of(2008, 1, i).atStartOfDay(PARIS).toInstant(); Clock clock = Clock.fixed(instant, PARIS); - assertEquals(DayOfMonth.now(clock).getValue(), i); + assertEquals(i, DayOfMonth.now(clock).getValue()); } } diff --git a/src/test/java/org/threeten/extra/TestDayOfYear.java b/src/test/java/org/threeten/extra/TestDayOfYear.java index fef88590..24952ae0 100644 --- a/src/test/java/org/threeten/extra/TestDayOfYear.java +++ b/src/test/java/org/threeten/extra/TestDayOfYear.java @@ -61,8 +61,10 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -78,20 +80,27 @@ import java.time.Year; import java.time.ZoneId; import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseDate; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.RetryingTest; + +import com.google.common.testing.EqualsTester; /** * Test DayOfYear. */ -@Test public class TestDayOfYear { private static final Year YEAR_STANDARD = Year.of(2007); @@ -101,11 +110,59 @@ public class TestDayOfYear { private static final DayOfYear TEST = DayOfYear.of(12); private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); - @BeforeMethod - public void setUp() { + private static class TestingField implements TemporalField { + + public static final TestingField INSTANCE = new TestingField(); + + @Override + public TemporalUnit getBaseUnit() { + return ChronoUnit.DAYS; + } + + @Override + public TemporalUnit getRangeUnit() { + return ChronoUnit.YEARS; + } + + @Override + public ValueRange range() { + return ValueRange.of(1, 365, 366); + } + + @Override + public boolean isDateBased() { + return true; + } + + @Override + public boolean isTimeBased() { + return false; + } + + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + return temporal.isSupported(DAY_OF_YEAR); + } + + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + return range(); + } + + @Override + public long getFrom(TemporalAccessor temporal) { + return temporal.getLong(DAY_OF_YEAR); + } + + @Override + @SuppressWarnings("unchecked") + public R adjustInto(R temporal, long newValue) { + return (R) temporal.with(DAY_OF_YEAR, newValue); + } } //----------------------------------------------------------------------- + @Test public void test_interfaces() { assertTrue(Serializable.class.isAssignableFrom(DayOfYear.class)); assertTrue(Comparable.class.isAssignableFrom(DayOfYear.class)); @@ -113,176 +170,230 @@ public void test_interfaces() { assertTrue(TemporalAccessor.class.isAssignableFrom(DayOfYear.class)); } + @Test public void test_serialization() throws IOException, ClassNotFoundException { DayOfYear test = DayOfYear.of(1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(test); - oos.close(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } + } - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( - baos.toByteArray())); - assertEquals(ois.readObject(), test); + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @RetryingTest(100) + public void test_now() { + assertEquals(LocalDate.now().getDayOfYear(), DayOfYear.now().getValue()); + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @RetryingTest(100) + public void test_now_ZoneId() { + ZoneId zone = ZoneId.of("Asia/Tokyo"); + assertEquals(LocalDate.now(zone).getDayOfYear(), DayOfYear.now(zone).getValue()); } //----------------------------------------------------------------------- // of(int) //----------------------------------------------------------------------- + @Test public void test_of_int() { for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.getValue(), i); - assertEquals(DayOfYear.of(i), test); + assertEquals(i, test.getValue()); + assertSame(test, DayOfYear.of(i)); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_tooLow() { - DayOfYear.of(0); + assertThrows(DateTimeException.class, () -> DayOfYear.of(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_tooHigh() { - DayOfYear.of(367); + assertThrows(DateTimeException.class, () -> DayOfYear.of(367)); } //----------------------------------------------------------------------- // from(TemporalAccessor) //----------------------------------------------------------------------- + @Test public void test_from_TemporalAccessor_notLeapYear() { LocalDate date = LocalDate.of(2007, 1, 1); for (int i = 1; i <= STANDARD_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.from(date); - assertEquals(test.getValue(), i); + assertEquals(i, test.getValue()); date = date.plusDays(1); } DayOfYear test = DayOfYear.from(date); - assertEquals(test.getValue(), 1); + assertEquals(1, test.getValue()); } + @Test public void test_from_TemporalAccessor_leapYear() { LocalDate date = LocalDate.of(2008, 1, 1); for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.from(date); - assertEquals(test.getValue(), i); + assertEquals(i, test.getValue()); date = date.plusDays(1); } } - @Test(expectedExceptions = DateTimeException.class) + @Test + public void test_from_TemporalAccessor_DayOfYear() { + DayOfYear dom = DayOfYear.of(6); + assertEquals(dom, DayOfYear.from(dom)); + } + + @Test + public void test_from_TemporalAccessor_nonIso() { + LocalDate date = LocalDate.now(); + assertEquals(date.getDayOfYear(), DayOfYear.from(JapaneseDate.from(date)).getValue()); + } + + @Test public void test_from_TemporalAccessor_noDerive() { - DayOfYear.from(LocalTime.NOON); + assertThrows(DateTimeException.class, () -> DayOfYear.from(LocalTime.NOON)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_TemporalAccessor_null() { - DayOfYear.from((TemporalAccessor) null); + assertThrows(NullPointerException.class, () -> DayOfYear.from((TemporalAccessor) null)); + } + + @Test + public void test_from_parse_CharSequence() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("D"); + assertEquals(DayOfYear.of(76), formatter.parse("76", DayOfYear::from)); } //----------------------------------------------------------------------- // isSupported(TemporalField) //----------------------------------------------------------------------- + @Test public void test_isSupported() { - assertEquals(TEST.isSupported((TemporalField) null), false); - assertEquals(TEST.isSupported(NANO_OF_SECOND), false); - assertEquals(TEST.isSupported(NANO_OF_DAY), false); - assertEquals(TEST.isSupported(MICRO_OF_SECOND), false); - assertEquals(TEST.isSupported(MICRO_OF_DAY), false); - assertEquals(TEST.isSupported(MILLI_OF_SECOND), false); - assertEquals(TEST.isSupported(MILLI_OF_DAY), false); - assertEquals(TEST.isSupported(SECOND_OF_MINUTE), false); - assertEquals(TEST.isSupported(SECOND_OF_DAY), false); - assertEquals(TEST.isSupported(MINUTE_OF_HOUR), false); - assertEquals(TEST.isSupported(MINUTE_OF_DAY), false); - assertEquals(TEST.isSupported(HOUR_OF_AMPM), false); - assertEquals(TEST.isSupported(CLOCK_HOUR_OF_AMPM), false); - assertEquals(TEST.isSupported(HOUR_OF_DAY), false); - assertEquals(TEST.isSupported(CLOCK_HOUR_OF_DAY), false); - assertEquals(TEST.isSupported(AMPM_OF_DAY), false); - assertEquals(TEST.isSupported(DAY_OF_WEEK), false); - assertEquals(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH), false); - assertEquals(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR), false); - assertEquals(TEST.isSupported(DAY_OF_MONTH), false); - assertEquals(TEST.isSupported(DAY_OF_YEAR), true); - assertEquals(TEST.isSupported(EPOCH_DAY), false); - assertEquals(TEST.isSupported(ALIGNED_WEEK_OF_MONTH), false); - assertEquals(TEST.isSupported(ALIGNED_WEEK_OF_YEAR), false); - assertEquals(TEST.isSupported(MONTH_OF_YEAR), false); - assertEquals(TEST.isSupported(PROLEPTIC_MONTH), false); - assertEquals(TEST.isSupported(YEAR_OF_ERA), false); - assertEquals(TEST.isSupported(YEAR), false); - assertEquals(TEST.isSupported(ERA), false); - assertEquals(TEST.isSupported(INSTANT_SECONDS), false); - assertEquals(TEST.isSupported(OFFSET_SECONDS), false); + assertEquals(false, TEST.isSupported((TemporalField) null)); + assertEquals(false, TEST.isSupported(NANO_OF_SECOND)); + assertEquals(false, TEST.isSupported(NANO_OF_DAY)); + assertEquals(false, TEST.isSupported(MICRO_OF_SECOND)); + assertEquals(false, TEST.isSupported(MICRO_OF_DAY)); + assertEquals(false, TEST.isSupported(MILLI_OF_SECOND)); + assertEquals(false, TEST.isSupported(MILLI_OF_DAY)); + assertEquals(false, TEST.isSupported(SECOND_OF_MINUTE)); + assertEquals(false, TEST.isSupported(SECOND_OF_DAY)); + assertEquals(false, TEST.isSupported(MINUTE_OF_HOUR)); + assertEquals(false, TEST.isSupported(MINUTE_OF_DAY)); + assertEquals(false, TEST.isSupported(HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(AMPM_OF_DAY)); + assertEquals(false, TEST.isSupported(DAY_OF_WEEK)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(false, TEST.isSupported(DAY_OF_MONTH)); + assertEquals(true, TEST.isSupported(DAY_OF_YEAR)); + assertEquals(false, TEST.isSupported(EPOCH_DAY)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_YEAR)); + assertEquals(false, TEST.isSupported(MONTH_OF_YEAR)); + assertEquals(false, TEST.isSupported(PROLEPTIC_MONTH)); + assertEquals(false, TEST.isSupported(YEAR_OF_ERA)); + assertEquals(false, TEST.isSupported(YEAR)); + assertEquals(false, TEST.isSupported(ERA)); + assertEquals(false, TEST.isSupported(INSTANT_SECONDS)); + assertEquals(false, TEST.isSupported(OFFSET_SECONDS)); + assertEquals(true, TEST.isSupported(TestingField.INSTANCE)); } //----------------------------------------------------------------------- // range(TemporalField) //----------------------------------------------------------------------- + @Test public void test_range() { - assertEquals(TEST.range(DAY_OF_YEAR), DAY_OF_YEAR.range()); + assertEquals(DAY_OF_YEAR.range(), TEST.range(DAY_OF_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_invalidField() { - TEST.range(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.range(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_range_null() { - TEST.range((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.range((TemporalField) null)); } //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- + @Test public void test_get() { - assertEquals(TEST.get(DAY_OF_YEAR), 12); + assertEquals(12, TEST.get(DAY_OF_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_get_invalidField() { - TEST.get(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.get(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_get_null() { - TEST.get((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.get((TemporalField) null)); } //----------------------------------------------------------------------- // getLong(TemporalField) //----------------------------------------------------------------------- + @Test public void test_getLong() { - assertEquals(TEST.getLong(DAY_OF_YEAR), 12L); + assertEquals(12L, TEST.getLong(DAY_OF_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test + public void test_getLong_derivedField() { + assertEquals(12L, TEST.getLong(TestingField.INSTANCE)); + } + + @Test public void test_getLong_invalidField() { - TEST.getLong(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.getLong(MONTH_OF_YEAR)); + } + + @Test + public void test_getLong_invalidField2() { + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.getLong(IsoFields.DAY_OF_QUARTER)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getLong_null() { - TEST.getLong((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.getLong((TemporalField) null)); } //----------------------------------------------------------------------- // isValidYear(int) //----------------------------------------------------------------------- @Test - public void test_isValidYearMonth_366() { + public void test_isValidYear_366() { DayOfYear test = DayOfYear.of(366); - assertEquals(test.isValidYear(2011), false); - assertEquals(test.isValidYear(2012), true); - assertEquals(test.isValidYear(2013), false); + assertEquals(false, test.isValidYear(2011)); + assertEquals(true, test.isValidYear(2012)); + assertEquals(false, test.isValidYear(2013)); } - public void test_isValidYearMonth_365() { + @Test + public void test_isValidYear_365() { DayOfYear test = DayOfYear.of(365); - assertEquals(test.isValidYear(2011), true); - assertEquals(test.isValidYear(2012), true); - assertEquals(test.isValidYear(2013), true); + assertEquals(true, test.isValidYear(2011)); + assertEquals(true, test.isValidYear(2012)); + assertEquals(true, test.isValidYear(2013)); } //----------------------------------------------------------------------- @@ -290,226 +401,230 @@ public void test_isValidYearMonth_365() { //----------------------------------------------------------------------- @Test public void test_query() { - assertEquals(TEST.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); - assertEquals(TEST.query(TemporalQueries.localDate()), null); - assertEquals(TEST.query(TemporalQueries.localTime()), null); - assertEquals(TEST.query(TemporalQueries.offset()), null); - assertEquals(TEST.query(TemporalQueries.precision()), null); - assertEquals(TEST.query(TemporalQueries.zone()), null); - assertEquals(TEST.query(TemporalQueries.zoneId()), null); + assertEquals(IsoChronology.INSTANCE, TEST.query(TemporalQueries.chronology())); + assertEquals(null, TEST.query(TemporalQueries.localDate())); + assertEquals(null, TEST.query(TemporalQueries.localTime())); + assertEquals(null, TEST.query(TemporalQueries.offset())); + assertEquals(null, TEST.query(TemporalQueries.precision())); + assertEquals(null, TEST.query(TemporalQueries.zone())); + assertEquals(null, TEST.query(TemporalQueries.zoneId())); } //----------------------------------------------------------------------- // adjustInto(Temporal) //----------------------------------------------------------------------- + @Test public void test_adjustInto_fromStartOfYear_notLeapYear() { LocalDate base = LocalDate.of(2007, 1, 1); LocalDate expected = base; for (int i = 1; i <= STANDARD_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.adjustInto(base), expected); + assertEquals(expected, test.adjustInto(base)); expected = expected.plusDays(1); } } + @Test public void test_adjustInto_fromEndOfYear_notLeapYear() { LocalDate base = LocalDate.of(2007, 12, 31); LocalDate expected = LocalDate.of(2007, 1, 1); for (int i = 1; i <= STANDARD_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.adjustInto(base), expected); + assertEquals(expected, test.adjustInto(base)); expected = expected.plusDays(1); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjustInto_fromStartOfYear_notLeapYear_day366() { LocalDate base = LocalDate.of(2007, 1, 1); DayOfYear test = DayOfYear.of(LEAP_YEAR_LENGTH); - test.adjustInto(base); + assertThrows(DateTimeException.class, () -> test.adjustInto(base)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjustInto_fromEndOfYear_notLeapYear_day366() { LocalDate base = LocalDate.of(2007, 12, 31); DayOfYear test = DayOfYear.of(LEAP_YEAR_LENGTH); - test.adjustInto(base); + assertThrows(DateTimeException.class, () -> test.adjustInto(base)); } + @Test public void test_adjustInto_fromStartOfYear_leapYear() { LocalDate base = LocalDate.of(2008, 1, 1); LocalDate expected = base; for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.adjustInto(base), expected); + assertEquals(expected, test.adjustInto(base)); expected = expected.plusDays(1); } } + @Test public void test_adjustInto_fromEndOfYear_leapYear() { LocalDate base = LocalDate.of(2008, 12, 31); LocalDate expected = LocalDate.of(2008, 1, 1); for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.adjustInto(base), expected); + assertEquals(expected, test.adjustInto(base)); expected = expected.plusDays(1); } } - @Test(expectedExceptions = NullPointerException.class) + @Test + public void test_adjustInto_nonIso() { + assertThrows(DateTimeException.class, () -> TEST.adjustInto(JapaneseDate.now())); + } + + @Test public void test_adjustInto_null() { - TEST.adjustInto((Temporal) null); + assertThrows(NullPointerException.class, () -> TEST.adjustInto((Temporal) null)); } //----------------------------------------------------------------------- // atYear(Year) //----------------------------------------------------------------------- + @Test public void test_atYear_Year_notLeapYear() { LocalDate expected = LocalDate.of(2007, 1, 1); for (int i = 1; i <= STANDARD_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.atYear(YEAR_STANDARD), expected); + assertEquals(expected, test.atYear(YEAR_STANDARD)); expected = expected.plusDays(1); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atYear_fromStartOfYear_notLeapYear_day366() { DayOfYear test = DayOfYear.of(LEAP_YEAR_LENGTH); - test.atYear(YEAR_STANDARD); + assertThrows(DateTimeException.class, () -> test.atYear(YEAR_STANDARD)); } + @Test public void test_atYear_Year_leapYear() { LocalDate expected = LocalDate.of(2008, 1, 1); for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.atYear(YEAR_LEAP), expected); + assertEquals(expected, test.atYear(YEAR_LEAP)); expected = expected.plusDays(1); } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_atYear_Year_nullYear() { - TEST.atYear((Year) null); + assertThrows(NullPointerException.class, () -> TEST.atYear((Year) null)); } //----------------------------------------------------------------------- // atYear(int) //----------------------------------------------------------------------- + @Test public void test_atYear_int_notLeapYear() { LocalDate expected = LocalDate.of(2007, 1, 1); for (int i = 1; i <= STANDARD_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.atYear(2007), expected); + assertEquals(expected, test.atYear(2007)); expected = expected.plusDays(1); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atYear_int_fromStartOfYear_notLeapYear_day366() { DayOfYear test = DayOfYear.of(LEAP_YEAR_LENGTH); - test.atYear(2007); + assertThrows(DateTimeException.class, () -> test.atYear(2007)); } + @Test public void test_atYear_int_leapYear() { LocalDate expected = LocalDate.of(2008, 1, 1); for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { DayOfYear test = DayOfYear.of(i); - assertEquals(test.atYear(2008), expected); + assertEquals(expected, test.atYear(2008)); expected = expected.plusDays(1); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atYear_int_invalidDay() { - TEST.atYear(Year.MIN_VALUE - 1); + assertThrows(DateTimeException.class, () -> TEST.atYear(Year.MIN_VALUE - 1)); } //----------------------------------------------------------------------- // compareTo() //----------------------------------------------------------------------- + @Test public void test_compareTo() { for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { DayOfYear a = DayOfYear.of(i); for (int j = 1; j <= LEAP_YEAR_LENGTH; j++) { DayOfYear b = DayOfYear.of(j); if (i < j) { - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); + assertEquals(true, a.compareTo(b) < 0); + assertEquals(true, b.compareTo(a) > 0); } else if (i > j) { - assertEquals(a.compareTo(b) > 0, true); - assertEquals(b.compareTo(a) < 0, true); + assertEquals(true, a.compareTo(b) > 0); + assertEquals(true, b.compareTo(a) < 0); } else { - assertEquals(a.compareTo(b), 0); - assertEquals(b.compareTo(a), 0); + assertEquals(0, a.compareTo(b)); + assertEquals(0, b.compareTo(a)); } } } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_nullDayOfYear() { DayOfYear doy = null; DayOfYear test = DayOfYear.of(1); - test.compareTo(doy); + assertThrows(NullPointerException.class, () -> test.compareTo(doy)); } //----------------------------------------------------------------------- // equals() / hashCode() //----------------------------------------------------------------------- - public void test_equals() { + @Test + public void test_equals_and_hashCode() { + EqualsTester equalsTester = new EqualsTester(); for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { - DayOfYear a = DayOfYear.of(i); - for (int j = 1; j <= LEAP_YEAR_LENGTH; j++) { - DayOfYear b = DayOfYear.of(j); - assertEquals(a.equals(b), i == j); - assertEquals(a.hashCode() == b.hashCode(), i == j); - } + equalsTester.addEqualityGroup(DayOfYear.of(i), DayOfYear.of(i)); } - } - - public void test_equals_nullDayOfYear() { - DayOfYear doy = null; - DayOfYear test = DayOfYear.of(1); - assertEquals(test.equals(doy), false); - } - - public void test_equals_incorrectType() { - DayOfYear test = DayOfYear.of(1); - assertEquals(test.equals("Incorrect type"), false); + equalsTester.testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- + @Test public void test_toString() { for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { DayOfYear a = DayOfYear.of(i); - assertEquals(a.toString(), "DayOfYear:" + i); + assertEquals("DayOfYear:" + i, a.toString()); } } //----------------------------------------------------------------------- // now(Clock) //----------------------------------------------------------------------- + @Test public void test_now_clock_notLeapYear() { LocalDate date = LocalDate.of(2007, 1, 1); for (int i = 1; i <= STANDARD_YEAR_LENGTH; i++) { Instant instant = date.atStartOfDay(PARIS).toInstant(); Clock clock = Clock.fixed(instant, PARIS); DayOfYear test = DayOfYear.now(clock); - assertEquals(test.getValue(), i); + assertEquals(i, test.getValue()); date = date.plusDays(1); } } + @Test public void test_now_clock_leapYear() { LocalDate date = LocalDate.of(2008, 1, 1); for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { Instant instant = date.atStartOfDay(PARIS).toInstant(); Clock clock = Clock.fixed(instant, PARIS); DayOfYear test = DayOfYear.now(clock); - assertEquals(test.getValue(), i); + assertEquals(i, test.getValue()); date = date.plusDays(1); } } diff --git a/src/test/java/org/threeten/extra/TestDays.java b/src/test/java/org/threeten/extra/TestDays.java index 743b60b6..a64416b8 100644 --- a/src/test/java/org/threeten/extra/TestDays.java +++ b/src/test/java/org/threeten/extra/TestDays.java @@ -31,9 +31,11 @@ */ package org.threeten.extra; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -42,116 +44,145 @@ import java.io.Serializable; import java.time.DateTimeException; import java.time.Duration; +import java.time.LocalDate; import java.time.Period; import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAmount; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test class. */ -@Test public class TestDays { //----------------------------------------------------------------------- + @Test public void test_isSerializable() { assertTrue(Serializable.class.isAssignableFrom(Days.class)); } //----------------------------------------------------------------------- + @Test public void test_deserializationSingleton() throws Exception { - Days orginal = Days.ZERO; + Days test = Days.ZERO; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Days ser = (Days) in.readObject(); - assertSame(Days.ZERO, ser); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } } //----------------------------------------------------------------------- + @Test public void test_ZERO() { - assertSame(Days.of(0), Days.ZERO); - assertSame(Days.of(0), Days.ZERO); - assertEquals(Days.ZERO.getAmount(), 0); + assertSame(Days.ZERO, Days.of(0)); + assertEquals(Days.ZERO, Days.of(0)); + assertEquals(0, Days.ZERO.getAmount()); + assertFalse(Days.ZERO.isNegative()); + assertTrue(Days.ZERO.isZero()); + assertFalse(Days.ZERO.isPositive()); } + @Test public void test_ONE() { - assertSame(Days.of(1), Days.ONE); - assertSame(Days.of(1), Days.ONE); - assertEquals(Days.ONE.getAmount(), 1); + assertSame(Days.ONE, Days.of(1)); + assertEquals(Days.ONE, Days.of(1)); + assertEquals(1, Days.ONE.getAmount()); + assertFalse(Days.ONE.isNegative()); + assertFalse(Days.ONE.isZero()); + assertTrue(Days.ONE.isPositive()); } //----------------------------------------------------------------------- + @Test public void test_of() { - assertEquals(Days.of(0).getAmount(), 0); - assertEquals(Days.of(1).getAmount(), 1); - assertEquals(Days.of(2).getAmount(), 2); - assertEquals(Days.of(Integer.MAX_VALUE).getAmount(), Integer.MAX_VALUE); - assertEquals(Days.of(-1).getAmount(), -1); - assertEquals(Days.of(-2).getAmount(), -2); - assertEquals(Days.of(Integer.MIN_VALUE).getAmount(), Integer.MIN_VALUE); + assertEquals(0, Days.of(0).getAmount()); + assertEquals(1, Days.of(1).getAmount()); + assertEquals(2, Days.of(2).getAmount()); + assertEquals(Integer.MAX_VALUE, Days.of(Integer.MAX_VALUE).getAmount()); + assertEquals(-1, Days.of(-1).getAmount()); + assertEquals(-2, Days.of(-2).getAmount()); + assertEquals(Integer.MIN_VALUE, Days.of(Integer.MIN_VALUE).getAmount()); + } + + @Test + public void test_ofMinusOne() { + assertEquals(-1, Days.of(-1).getAmount()); + assertTrue(Days.of(-1).isNegative()); + assertFalse(Days.of(-1).isZero()); + assertFalse(Days.of(-1).isPositive()); } //----------------------------------------------------------------------- + @Test public void test_ofWeeks() { - assertEquals(Days.ofWeeks(0).getAmount(), 0); - assertEquals(Days.ofWeeks(1).getAmount(), 7); - assertEquals(Days.ofWeeks(2).getAmount(), 14); - assertEquals(Days.ofWeeks(Integer.MAX_VALUE / 7).getAmount(), (Integer.MAX_VALUE / 7) * 7); - assertEquals(Days.ofWeeks(-1).getAmount(), -7); - assertEquals(Days.ofWeeks(-2).getAmount(), -14); - assertEquals(Days.ofWeeks(Integer.MIN_VALUE / 7).getAmount(), (Integer.MIN_VALUE / 7) * 7); + assertEquals(0, Days.ofWeeks(0).getAmount()); + assertEquals(7, Days.ofWeeks(1).getAmount()); + assertEquals(14, Days.ofWeeks(2).getAmount()); + assertEquals((Integer.MAX_VALUE / 7) * 7, Days.ofWeeks(Integer.MAX_VALUE / 7).getAmount()); + assertEquals(-7, Days.ofWeeks(-1).getAmount()); + assertEquals(-14, Days.ofWeeks(-2).getAmount()); + assertEquals((Integer.MIN_VALUE / 7) * 7, Days.ofWeeks(Integer.MIN_VALUE / 7).getAmount()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_ofWeeks_overflow() { - Days.ofWeeks((Integer.MAX_VALUE / 7) + 7); + assertThrows(ArithmeticException.class, () -> Days.ofWeeks((Integer.MAX_VALUE / 7) + 7)); } //----------------------------------------------------------------------- + @Test public void test_from_Period_P0D() { - assertEquals(Days.from(Period.ofDays(0)), Days.of(0)); + assertEquals(Days.of(0), Days.from(Period.ofDays(0))); } + @Test public void test_from_Period_P2D() { - assertEquals(Days.from(Period.ofDays(2)), Days.of(2)); + assertEquals(Days.of(2), Days.from(Period.ofDays(2))); } + @Test public void test_from_P2W() { - assertEquals(Days.from(new MockWeeksDays(2, 0)), Days.of(14)); + assertEquals(Days.of(14), Days.from(new MockWeeksDays(2, 0))); } + @Test public void test_from_P2W3D() { - assertEquals(Days.from(new MockWeeksDays(2, 3)), Days.of(17)); + assertEquals(Days.of(17), Days.from(new MockWeeksDays(2, 3))); } + @Test public void test_from_Duration() { - assertEquals(Days.from(Duration.ofDays(2)), Days.of(2)); + assertEquals(Days.of(2), Days.from(Duration.ofDays(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_wrongUnit_remainder() { - Days.from(Duration.ofHours(3)); + assertThrows(DateTimeException.class, () -> Days.from(Duration.ofHours(3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_wrongUnit_noConversion() { - Days.from(Period.ofMonths(2)); + assertThrows(DateTimeException.class, () -> Days.from(Period.ofMonths(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_null() { - Days.from((TemporalAmount) null); + assertThrows(NullPointerException.class, () -> Days.from((TemporalAmount) null)); } //----------------------------------------------------------------------- - @DataProvider(name = "parseValid") - Object[][] data_valid() { + public static Object[][] data_valid() { return new Object[][] { {"P0D", 0}, {"P1D", 1}, @@ -181,23 +212,25 @@ Object[][] data_valid() { }; } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid(String str, int expectedDays) { - assertEquals(Days.parse(str), Days.of(expectedDays)); + assertEquals(Days.of(expectedDays), Days.parse(str)); } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid_initialPlus(String str, int expectedDays) { - assertEquals(Days.parse("+" + str), Days.of(expectedDays)); + assertEquals(Days.of(expectedDays), Days.parse("+" + str)); } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid_initialMinus(String str, int expectedDays) { - assertEquals(Days.parse("-" + str), Days.of(-expectedDays)); + assertEquals(Days.of(-expectedDays), Days.parse("-" + str)); } - @DataProvider(name = "parseInvalid") - Object[][] data_invalid() { + public static Object[][] data_invalid() { return new Object[][] { {"P3Y"}, {"P3M"}, @@ -216,17 +249,46 @@ Object[][] data_invalid() { }; } - @Test(expectedExceptions = DateTimeParseException.class, dataProvider = "parseInvalid") + @ParameterizedTest + @MethodSource("data_invalid") public void test_parse_CharSequence_invalid(String str) { - Days.parse(str); + assertThrows(DateTimeParseException.class, () -> Days.parse(str)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequence_null() { - Days.parse((CharSequence) null); + assertThrows(NullPointerException.class, () -> Days.parse((CharSequence) null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_get() { + assertEquals(6, Days.of(6).get(ChronoUnit.DAYS)); + } + + @Test + public void test_get_invalidType() { + assertThrows(DateTimeException.class, () -> Days.of(6).get(IsoFields.QUARTER_YEARS)); } //----------------------------------------------------------------------- + @Test + public void test_between() { + assertEquals(Days.of(365 + 366), Days.between(LocalDate.of(2019, 1, 1), LocalDate.of(2021, 1, 1))); + } + + @Test + public void test_between_date_null() { + assertThrows(NullPointerException.class, () -> Days.between(LocalDate.now(), (Temporal) null)); + } + + @Test + public void test_between_null_date() { + assertThrows(NullPointerException.class, () -> Days.between((Temporal) null, LocalDate.now())); + } + + //----------------------------------------------------------------------- + @Test public void test_plus_TemporalAmount_Days() { Days test5 = Days.of(5); assertEquals(Days.of(5), test5.plus(Days.of(0))); @@ -236,6 +298,7 @@ public void test_plus_TemporalAmount_Days() { assertEquals(Days.of(Integer.MIN_VALUE), Days.of(Integer.MIN_VALUE + 1).plus(Days.of(-1))); } + @Test public void test_plus_TemporalAmount_Period() { Days test5 = Days.of(5); assertEquals(Days.of(5), test5.plus(Period.ofDays(0))); @@ -245,32 +308,33 @@ public void test_plus_TemporalAmount_Period() { assertEquals(Days.of(Integer.MIN_VALUE), Days.of(Integer.MIN_VALUE + 1).plus(Period.ofDays(-1))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_TemporalAmount_PeriodYears() { - Days.of(1).plus(Period.ofYears(2)); + assertThrows(DateTimeException.class, () -> Days.of(1).plus(Period.ofYears(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_TemporalAmount_Duration() { - Days.of(1).plus(Duration.ofHours(2)); + assertThrows(DateTimeException.class, () -> Days.of(1).plus(Duration.ofHours(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooBig() { - Days.of(Integer.MAX_VALUE - 1).plus(Days.of(2)); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MAX_VALUE - 1).plus(Days.of(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooSmall() { - Days.of(Integer.MIN_VALUE + 1).plus(Days.of(-2)); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MIN_VALUE + 1).plus(Days.of(-2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_plus_TemporalAmount_null() { - Days.of(Integer.MIN_VALUE + 1).plus(null); + assertThrows(NullPointerException.class, () -> Days.of(Integer.MIN_VALUE + 1).plus(null)); } //----------------------------------------------------------------------- + @Test public void test_plus_int() { Days test5 = Days.of(5); assertEquals(Days.of(5), test5.plus(0)); @@ -280,17 +344,18 @@ public void test_plus_int() { assertEquals(Days.of(Integer.MIN_VALUE), Days.of(Integer.MIN_VALUE + 1).plus(-1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooBig() { - Days.of(Integer.MAX_VALUE - 1).plus(2); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MAX_VALUE - 1).plus(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooSmall() { - Days.of(Integer.MIN_VALUE + 1).plus(-2); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MIN_VALUE + 1).plus(-2)); } //----------------------------------------------------------------------- + @Test public void test_minus_TemporalAmount_Days() { Days test5 = Days.of(5); assertEquals(Days.of(5), test5.minus(Days.of(0))); @@ -300,6 +365,7 @@ public void test_minus_TemporalAmount_Days() { assertEquals(Days.of(Integer.MIN_VALUE), Days.of(Integer.MIN_VALUE + 1).minus(Days.of(1))); } + @Test public void test_minus_TemporalAmount_Period() { Days test5 = Days.of(5); assertEquals(Days.of(5), test5.minus(Period.ofDays(0))); @@ -309,32 +375,33 @@ public void test_minus_TemporalAmount_Period() { assertEquals(Days.of(Integer.MIN_VALUE), Days.of(Integer.MIN_VALUE + 1).minus(Period.ofDays(1))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_TemporalAmount_PeriodYears() { - Days.of(1).minus(Period.ofYears(2)); + assertThrows(DateTimeException.class, () -> Days.of(1).minus(Period.ofYears(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_TemporalAmount_Duration() { - Days.of(1).minus(Duration.ofHours(2)); + assertThrows(DateTimeException.class, () -> Days.of(1).minus(Duration.ofHours(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooBig() { - Days.of(Integer.MAX_VALUE - 1).minus(Days.of(-2)); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MAX_VALUE - 1).minus(Days.of(-2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooSmall() { - Days.of(Integer.MIN_VALUE + 1).minus(Days.of(2)); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MIN_VALUE + 1).minus(Days.of(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_minus_TemporalAmount_null() { - Days.of(Integer.MIN_VALUE + 1).minus(null); + assertThrows(NullPointerException.class, () -> Days.of(Integer.MIN_VALUE + 1).minus(null)); } //----------------------------------------------------------------------- + @Test public void test_minus_int() { Days test5 = Days.of(5); assertEquals(Days.of(5), test5.minus(0)); @@ -344,17 +411,18 @@ public void test_minus_int() { assertEquals(Days.of(Integer.MIN_VALUE), Days.of(Integer.MIN_VALUE + 1).minus(1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooBig() { - Days.of(Integer.MAX_VALUE - 1).minus(-2); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MAX_VALUE - 1).minus(-2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooSmall() { - Days.of(Integer.MIN_VALUE + 1).minus(2); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MIN_VALUE + 1).minus(2)); } //----------------------------------------------------------------------- + @Test public void test_multipliedBy() { Days test5 = Days.of(5); assertEquals(Days.of(0), test5.multipliedBy(0)); @@ -364,22 +432,24 @@ public void test_multipliedBy() { assertEquals(Days.of(-15), test5.multipliedBy(-3)); } + @Test public void test_multipliedBy_negate() { Days test5 = Days.of(5); assertEquals(Days.of(-15), test5.multipliedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooBig() { - Days.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooSmall() { - Days.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2)); } //----------------------------------------------------------------------- + @Test public void test_dividedBy() { Days test12 = Days.of(12); assertEquals(Days.of(12), test12.dividedBy(1)); @@ -391,17 +461,19 @@ public void test_dividedBy() { assertEquals(Days.of(-4), test12.dividedBy(-3)); } + @Test public void test_dividedBy_negate() { Days test12 = Days.of(12); assertEquals(Days.of(-4), test12.dividedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_dividedBy_divideByZero() { - Days.of(1).dividedBy(0); + assertThrows(ArithmeticException.class, () -> Days.of(1).dividedBy(0)); } //----------------------------------------------------------------------- + @Test public void test_negated() { assertEquals(Days.of(0), Days.of(0).negated()); assertEquals(Days.of(-12), Days.of(12).negated()); @@ -409,12 +481,13 @@ public void test_negated() { assertEquals(Days.of(-Integer.MAX_VALUE), Days.of(Integer.MAX_VALUE).negated()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_negated_overflow() { - Days.of(Integer.MIN_VALUE).negated(); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MIN_VALUE).negated()); } //----------------------------------------------------------------------- + @Test public void test_abs() { assertEquals(Days.of(0), Days.of(0).abs()); assertEquals(Days.of(12), Days.of(12).abs()); @@ -423,19 +496,34 @@ public void test_abs() { assertEquals(Days.of(Integer.MAX_VALUE), Days.of(-Integer.MAX_VALUE).abs()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_abs_overflow() { - Days.of(Integer.MIN_VALUE).abs(); + assertThrows(ArithmeticException.class, () -> Days.of(Integer.MIN_VALUE).abs()); } //----------------------------------------------------------------------- + @Test + public void test_addTo() { + assertEquals(LocalDate.of(2019, 1, 10), Days.of(0).addTo(LocalDate.of(2019, 1, 10))); + assertEquals(LocalDate.of(2019, 1, 15), Days.of(5).addTo(LocalDate.of(2019, 1, 10))); + } + + @Test + public void test_subtractFrom() { + assertEquals(LocalDate.of(2019, 1, 10), Days.of(0).subtractFrom(LocalDate.of(2019, 1, 10))); + assertEquals(LocalDate.of(2019, 1, 5), Days.of(5).subtractFrom(LocalDate.of(2019, 1, 10))); + } + + //----------------------------------------------------------------------- + @Test public void test_toPeriod() { for (int i = -20; i < 20; i++) { - assertEquals(Days.of(i).toPeriod(), Period.ofDays(i)); + assertEquals(Period.ofDays(i), Days.of(i).toPeriod()); } } //----------------------------------------------------------------------- + @Test public void test_compareTo() { Days test5 = Days.of(5); Days test6 = Days.of(6); @@ -444,40 +532,23 @@ public void test_compareTo() { assertEquals(1, test6.compareTo(test5)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_null() { Days test5 = Days.of(5); - test5.compareTo(null); + assertThrows(NullPointerException.class, () -> test5.compareTo(null)); } //----------------------------------------------------------------------- - public void test_equals() { - Days test5 = Days.of(5); - Days test6 = Days.of(6); - assertEquals(true, test5.equals(test5)); - assertEquals(false, test5.equals(test6)); - assertEquals(false, test6.equals(test5)); - } - - public void test_equals_null() { - Days test5 = Days.of(5); - assertEquals(false, test5.equals(null)); - } - - public void test_equals_otherClass() { - Days test5 = Days.of(5); - assertEquals(false, test5.equals("")); - } - - //----------------------------------------------------------------------- - public void test_hashCode() { - Days test5 = Days.of(5); - Days test6 = Days.of(6); - assertEquals(true, test5.hashCode() == test5.hashCode()); - assertEquals(false, test5.hashCode() == test6.hashCode()); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Days.of(5), Days.of(5)) + .addEqualityGroup(Days.of(6), Days.of(6)) + .testEquals(); } //----------------------------------------------------------------------- + @Test public void test_toString() { Days test5 = Days.of(5); assertEquals("P5D", test5.toString()); diff --git a/src/test/java/org/threeten/extra/TestHalf.java b/src/test/java/org/threeten/extra/TestHalf.java new file mode 100644 index 00000000..fa4c1259 --- /dev/null +++ b/src/test/java/org/threeten/extra/TestHalf.java @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; +import static java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.IsoFields.QUARTER_OF_YEAR; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.threeten.extra.TemporalFields.HALF_OF_YEAR; +import static org.threeten.extra.TemporalFields.HALF_YEARS; + +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.TextStyle; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.util.Locale; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * Test Half. + */ +public class TestHalf { + + //----------------------------------------------------------------------- + @Test + public void test_interfaces() { + assertTrue(Enum.class.isAssignableFrom(Half.class)); + assertTrue(Serializable.class.isAssignableFrom(Half.class)); + assertTrue(Comparable.class.isAssignableFrom(Half.class)); + assertTrue(TemporalAccessor.class.isAssignableFrom(Half.class)); + } + + //----------------------------------------------------------------------- + // of(int) + //----------------------------------------------------------------------- + @Test + public void test_of_int() { + assertEquals(1, Half.of(1).getValue()); + assertEquals(2, Half.of(2).getValue()); + assertThrows(DateTimeException.class, () -> Half.of(0)); + assertThrows(DateTimeException.class, () -> Half.of(3)); + } + + //----------------------------------------------------------------------- + // ofMonth(int) + //----------------------------------------------------------------------- + @Test + public void test_ofMonth_int_singleton() { + assertSame(Half.H1, Half.ofMonth(1)); + assertSame(Half.H1, Half.ofMonth(2)); + assertSame(Half.H1, Half.ofMonth(3)); + assertSame(Half.H1, Half.ofMonth(4)); + assertSame(Half.H1, Half.ofMonth(5)); + assertSame(Half.H1, Half.ofMonth(6)); + assertSame(Half.H2, Half.ofMonth(7)); + assertSame(Half.H2, Half.ofMonth(8)); + assertSame(Half.H2, Half.ofMonth(9)); + assertSame(Half.H2, Half.ofMonth(10)); + assertSame(Half.H2, Half.ofMonth(11)); + assertSame(Half.H2, Half.ofMonth(12)); + } + + @Test + public void test_ofMonth_int_valueTooLow() { + assertThrows(DateTimeException.class, () -> Half.ofMonth(0)); + } + + @Test + public void test_ofMonth_int_valueTooHigh() { + assertThrows(DateTimeException.class, () -> Half.ofMonth(13)); + } + + //----------------------------------------------------------------------- + // from(TemporalAccessor) + //----------------------------------------------------------------------- + @Test + public void test_from_TemporalAccessor() { + assertEquals(Half.H2, Half.from(LocalDate.of(2011, 7, 6))); + assertEquals(Half.H1, Half.from(LocalDateTime.of(2012, 2, 3, 12, 30))); + } + + @Test + public void test_from_TemporalAccessor_Month() { + assertEquals(Half.H1, Half.from(Month.JANUARY)); + assertEquals(Half.H1, Half.from(Month.FEBRUARY)); + assertEquals(Half.H1, Half.from(Month.MARCH)); + assertEquals(Half.H1, Half.from(Month.APRIL)); + assertEquals(Half.H1, Half.from(Month.MAY)); + assertEquals(Half.H1, Half.from(Month.JUNE)); + assertEquals(Half.H2, Half.from(Month.JULY)); + assertEquals(Half.H2, Half.from(Month.AUGUST)); + assertEquals(Half.H2, Half.from(Month.SEPTEMBER)); + assertEquals(Half.H2, Half.from(Month.OCTOBER)); + assertEquals(Half.H2, Half.from(Month.NOVEMBER)); + assertEquals(Half.H2, Half.from(Month.DECEMBER)); + + assertEquals(Half.H1, Half.from(Half.H1)); + assertEquals(Half.H2, Half.from(Half.H2)); + } + + @Test + public void test_from_TemporalAccessorl_invalid_noDerive() { + assertThrows(DateTimeException.class, () -> Half.from(LocalTime.of(12, 30))); + } + + @Test + public void test_from_TemporalAccessor_null() { + assertThrows(NullPointerException.class, () -> Half.from((TemporalAccessor) null)); + } + + @Test + public void test_from_parse_CharSequence() { + DateTimeFormatter formatter = new DateTimeFormatterBuilder() + .appendLiteral('H') + .appendValue(HALF_OF_YEAR, 1) + .toFormatter(); + assertEquals(Half.H2, formatter.parse("H2", Half::from)); + } + + //----------------------------------------------------------------------- + // getDisplayName() + //----------------------------------------------------------------------- + @Test + public void test_getDisplayName() { + assertTrue(Half.H1.getDisplayName(TextStyle.SHORT, Locale.US).contains("1")); + } + + @Test + public void test_getDisplayName_nullStyle() { + assertThrows(NullPointerException.class, () -> Half.H1.getDisplayName(null, Locale.US)); + } + + @Test + public void test_getDisplayName_nullLocale() { + assertThrows(NullPointerException.class, () -> Half.H1.getDisplayName(TextStyle.FULL, null)); + } + + //----------------------------------------------------------------------- + // isSupported() + //----------------------------------------------------------------------- + @Test + public void test_isSupported() { + Half test = Half.H1; + assertEquals(false, test.isSupported(null)); + assertEquals(false, test.isSupported(NANO_OF_SECOND)); + assertEquals(false, test.isSupported(NANO_OF_DAY)); + assertEquals(false, test.isSupported(MICRO_OF_SECOND)); + assertEquals(false, test.isSupported(MICRO_OF_DAY)); + assertEquals(false, test.isSupported(MILLI_OF_SECOND)); + assertEquals(false, test.isSupported(MILLI_OF_DAY)); + assertEquals(false, test.isSupported(SECOND_OF_MINUTE)); + assertEquals(false, test.isSupported(SECOND_OF_DAY)); + assertEquals(false, test.isSupported(MINUTE_OF_HOUR)); + assertEquals(false, test.isSupported(MINUTE_OF_DAY)); + assertEquals(false, test.isSupported(HOUR_OF_AMPM)); + assertEquals(false, test.isSupported(CLOCK_HOUR_OF_AMPM)); + assertEquals(false, test.isSupported(HOUR_OF_DAY)); + assertEquals(false, test.isSupported(CLOCK_HOUR_OF_DAY)); + assertEquals(false, test.isSupported(AMPM_OF_DAY)); + assertEquals(false, test.isSupported(DAY_OF_WEEK)); + assertEquals(false, test.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(false, test.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(false, test.isSupported(DAY_OF_MONTH)); + assertEquals(false, test.isSupported(DAY_OF_YEAR)); + assertEquals(false, test.isSupported(EPOCH_DAY)); + assertEquals(false, test.isSupported(ALIGNED_WEEK_OF_MONTH)); + assertEquals(false, test.isSupported(ALIGNED_WEEK_OF_YEAR)); + assertEquals(false, test.isSupported(MONTH_OF_YEAR)); + assertEquals(false, test.isSupported(PROLEPTIC_MONTH)); + assertEquals(false, test.isSupported(YEAR_OF_ERA)); + assertEquals(false, test.isSupported(YEAR)); + assertEquals(false, test.isSupported(ERA)); + assertEquals(false, test.isSupported(INSTANT_SECONDS)); + assertEquals(false, test.isSupported(OFFSET_SECONDS)); + assertEquals(false, test.isSupported(QUARTER_OF_YEAR)); + assertEquals(true, test.isSupported(HALF_OF_YEAR)); + } + + //----------------------------------------------------------------------- + // range() + //----------------------------------------------------------------------- + @Test + public void test_range() { + assertEquals(HALF_OF_YEAR.range(), Half.H1.range(HALF_OF_YEAR)); + } + + @Test + public void test_range_invalidField() { + assertThrows(UnsupportedTemporalTypeException.class, () -> Half.H1.range(MONTH_OF_YEAR)); + } + + @Test + public void test_range_null() { + assertThrows(NullPointerException.class, () -> Half.H1.range(null)); + } + + //----------------------------------------------------------------------- + // get() + //----------------------------------------------------------------------- + @Test + public void test_get() { + assertEquals(1, Half.H1.get(HALF_OF_YEAR)); + assertEquals(2, Half.H2.get(HALF_OF_YEAR)); + } + + @Test + public void test_get_invalidField() { + assertThrows(UnsupportedTemporalTypeException.class, () -> Half.H2.get(MONTH_OF_YEAR)); + } + + @Test + public void test_get_null() { + assertThrows(NullPointerException.class, () -> Half.H2.get(null)); + } + + //----------------------------------------------------------------------- + // getLong() + //----------------------------------------------------------------------- + @Test + public void test_getLong() { + assertEquals(1, Half.H1.getLong(HALF_OF_YEAR)); + assertEquals(2, Half.H2.getLong(HALF_OF_YEAR)); + } + + @Test + public void test_getLong_invalidField() { + assertThrows(UnsupportedTemporalTypeException.class, () -> Half.H2.getLong(MONTH_OF_YEAR)); + } + + @Test + public void test_getLong_null() { + assertThrows(NullPointerException.class, () -> Half.H2.getLong(null)); + } + + //----------------------------------------------------------------------- + // plus(long), plus(long,unit) + //----------------------------------------------------------------------- + public static Object[][] data_plus() { + return new Object[][] { + {1, -4, 1}, + {1, -3, 2}, + {1, -2, 1}, + {1, -1, 2}, + {1, 0, 1}, + {1, 1, 2}, + {1, 2, 1}, + {1, 3, 2}, + {1, 4, 1}, + }; + } + + @ParameterizedTest + @MethodSource("data_plus") + public void test_plus_long(int base, long amount, int expected) { + assertEquals(Half.of(expected), Half.of(base).plus(amount)); + } + + //----------------------------------------------------------------------- + // minus(long), minus(long,unit) + //----------------------------------------------------------------------- + public static Object[][] data_minus() { + return new Object[][] { + {1, -4, 1}, + {1, -3, 2}, + {1, -2, 1}, + {1, -1, 2}, + {1, 0, 1}, + {1, 1, 2}, + {1, 2, 1}, + {1, 3, 2}, + {1, 4, 1}, + }; + } + + @ParameterizedTest + @MethodSource("data_minus") + public void test_minus_long(int base, long amount, int expected) { + assertEquals(Half.of(expected), Half.of(base).minus(amount)); + } + + //----------------------------------------------------------------------- + // length(boolean) + //----------------------------------------------------------------------- + @Test + public void test_length_boolean() { + assertEquals(182, Half.H1.length(true)); + assertEquals(181, Half.H1.length(false)); + assertEquals(184, Half.H2.length(true)); + assertEquals(184, Half.H2.length(false)); + } + + //----------------------------------------------------------------------- + // firstMonth() + //----------------------------------------------------------------------- + @Test + public void test_firstMonth() { + assertEquals(Month.JANUARY, Half.H1.firstMonth()); + assertEquals(Month.JULY, Half.H2.firstMonth()); + } + + //----------------------------------------------------------------------- + // query() + //----------------------------------------------------------------------- + @Test + public void test_query() { + assertEquals(IsoChronology.INSTANCE, Half.H1.query(TemporalQueries.chronology())); + assertEquals(null, Half.H1.query(TemporalQueries.localDate())); + assertEquals(null, Half.H1.query(TemporalQueries.localTime())); + assertEquals(null, Half.H1.query(TemporalQueries.offset())); + assertEquals(HALF_YEARS, Half.H1.query(TemporalQueries.precision())); + assertEquals(null, Half.H1.query(TemporalQueries.zone())); + assertEquals(null, Half.H1.query(TemporalQueries.zoneId())); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test + public void test_toString() { + assertEquals("H1", Half.H1.toString()); + assertEquals("H2", Half.H2.toString()); + } + + //----------------------------------------------------------------------- + // generated methods + //----------------------------------------------------------------------- + @Test + public void test_enum() { + assertEquals(Half.H2, Half.valueOf("H2")); + assertEquals(Half.H1, Half.values()[0]); + } + +} diff --git a/src/test/java/org/threeten/extra/TestHourMinute.java b/src/test/java/org/threeten/extra/TestHourMinute.java new file mode 100644 index 00000000..e3376b1a --- /dev/null +++ b/src/test/java/org/threeten/extra/TestHourMinute.java @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; +import static java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.HALF_DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MICROS; +import static java.time.temporal.ChronoUnit.MILLENNIA; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; +import static java.time.temporal.IsoFields.DAY_OF_QUARTER; +import static java.time.temporal.IsoFields.QUARTER_OF_YEAR; +import static java.time.temporal.IsoFields.QUARTER_YEARS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; +import static org.threeten.extra.TemporalFields.DAY_OF_HALF; +import static org.threeten.extra.TemporalFields.HALF_OF_YEAR; +import static org.threeten.extra.TemporalFields.HALF_YEARS; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; + +/** + * Test HourMinute. + */ +public class TestHourMinute { + + private static final HourMinute TEST = HourMinute.of(12, 31); + + //----------------------------------------------------------------------- + @Test + public void test_interfaces() { + assertThat(HourMinute.class) + .isAssignableTo(Serializable.class) + .isAssignableTo(Comparable.class) + .isAssignableTo(TemporalAdjuster.class) + .isAssignableTo(TemporalAccessor.class); + } + + @Test + public void test_serialization() throws IOException, ClassNotFoundException { + HourMinute test = HourMinute.of(12, 31); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertThat(ois.readObject()).isEqualTo(test); + } + } + + //----------------------------------------------------------------------- + // of(int,int) / getters + //----------------------------------------------------------------------- + @Test + public void test_of_int_int() { + for (int hour = 0; hour <= 23; hour++) { + for (int minute = 0; minute <= 59; minute++) { + HourMinute test = HourMinute.of(hour, minute); + assertThat(test.getHour()).isEqualTo(hour); + assertThat(test.getMinute()).isEqualTo(minute); + assertThat(test) + .isEqualTo(HourMinute.of(hour, minute)) + .hasSameHashCodeAs(HourMinute.of(hour, minute)); + } + } + } + + @Test + public void test_of_int_int_invalid() { + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> HourMinute.of(-1, 0)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> HourMinute.of(24, 0)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> HourMinute.of(1, -1)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> HourMinute.of(1, 60)); + } + + //----------------------------------------------------------------------- + // from(TemporalAccessor) + //----------------------------------------------------------------------- + @Test + public void test_from_TemporalAccessor() { + for (int hour = 0; hour <= 23; hour++) { + for (int minute = 0; minute <= 59; minute++) { + HourMinute expected = HourMinute.of(hour, minute); + assertThat(HourMinute.from(expected)).isEqualTo(expected); + assertThat(HourMinute.from(LocalTime.of(hour, minute))).isEqualTo(expected); + assertThat(HourMinute.from(LocalDateTime.of(2020, 6, 3, hour, minute))).isEqualTo(expected); + } + } + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> HourMinute.from(LocalDate.of(2020, 6, 3))); + assertThatNullPointerException().isThrownBy(() -> HourMinute.from((TemporalAccessor) null)); + } + + //----------------------------------------------------------------------- + // parse(CharSequence) + //----------------------------------------------------------------------- + static Object[][] data_parse_CharSequence() { + return new Object[][] { + {HourMinute.of(0, 0), "00:00"}, + {HourMinute.of(9, 9), "09:09"}, + {HourMinute.of(10, 10), "10:10"}, + {HourMinute.of(19, 59), "19:59"}, + {HourMinute.of(23, 59), "23:59"}, + }; + } + + @ParameterizedTest + @MethodSource("data_parse_CharSequence") + public void test_parse_CharSequence(HourMinute hourMin, String str) { + assertThat(HourMinute.parse(str)).isEqualTo(hourMin); + assertThat(hourMin).hasToString(str); + } + + @Test + public void test_parse_CharSequence_invalid() { + assertThatNullPointerException().isThrownBy(() -> HourMinute.parse((CharSequence) null)); + } + + //----------------------------------------------------------------------- + // parse(CharSequence,DateTimeFormatter) + //----------------------------------------------------------------------- + @Test + public void test_parse_CharSequenceDateTimeFormatter() { + assertThat(HourMinute.parse("23:30+01:00", DateTimeFormatter.ISO_OFFSET_TIME)).isEqualTo(HourMinute.of(23, 30)); + } + + @Test + public void test_parse_CharSequenceDateTimeFormatter_invalid() { + assertThatNullPointerException().isThrownBy(() -> HourMinute.parse((CharSequence) null, DateTimeFormatter.ISO_OFFSET_TIME)); + assertThatNullPointerException().isThrownBy(() -> HourMinute.parse("23:59", (DateTimeFormatter) null)); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertThat(TEST.isSupported((TemporalField) null)).isFalse(); + assertThat(TEST.isSupported(NANO_OF_SECOND)).isFalse(); + assertThat(TEST.isSupported(NANO_OF_DAY)).isFalse(); + assertThat(TEST.isSupported(MICRO_OF_SECOND)).isFalse(); + assertThat(TEST.isSupported(MICRO_OF_DAY)).isFalse(); + assertThat(TEST.isSupported(MILLI_OF_SECOND)).isFalse(); + assertThat(TEST.isSupported(MILLI_OF_DAY)).isFalse(); + assertThat(TEST.isSupported(SECOND_OF_MINUTE)).isFalse(); + assertThat(TEST.isSupported(SECOND_OF_DAY)).isFalse(); + assertThat(TEST.isSupported(MINUTE_OF_HOUR)).isTrue(); + assertThat(TEST.isSupported(MINUTE_OF_DAY)).isTrue(); + assertThat(TEST.isSupported(HOUR_OF_AMPM)).isTrue(); + assertThat(TEST.isSupported(CLOCK_HOUR_OF_AMPM)).isTrue(); + assertThat(TEST.isSupported(HOUR_OF_DAY)).isTrue(); + assertThat(TEST.isSupported(CLOCK_HOUR_OF_DAY)).isTrue(); + assertThat(TEST.isSupported(AMPM_OF_DAY)).isTrue(); + assertThat(TEST.isSupported(DAY_OF_WEEK)).isFalse(); + assertThat(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)).isFalse(); + assertThat(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)).isFalse(); + assertThat(TEST.isSupported(DAY_OF_MONTH)).isFalse(); + assertThat(TEST.isSupported(DAY_OF_YEAR)).isFalse(); + assertThat(TEST.isSupported(EPOCH_DAY)).isFalse(); + assertThat(TEST.isSupported(ALIGNED_WEEK_OF_MONTH)).isFalse(); + assertThat(TEST.isSupported(ALIGNED_WEEK_OF_YEAR)).isFalse(); + assertThat(TEST.isSupported(MONTH_OF_YEAR)).isFalse(); + assertThat(TEST.isSupported(PROLEPTIC_MONTH)).isFalse(); + assertThat(TEST.isSupported(YEAR_OF_ERA)).isFalse(); + assertThat(TEST.isSupported(YEAR)).isFalse(); + assertThat(TEST.isSupported(ERA)).isFalse(); + assertThat(TEST.isSupported(INSTANT_SECONDS)).isFalse(); + assertThat(TEST.isSupported(OFFSET_SECONDS)).isFalse(); + assertThat(TEST.isSupported(QUARTER_OF_YEAR)).isFalse(); + assertThat(TEST.isSupported(DAY_OF_QUARTER)).isFalse(); + assertThat(TEST.isSupported(HALF_OF_YEAR)).isFalse(); + assertThat(TEST.isSupported(DAY_OF_HALF)).isFalse(); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertThat(TEST.isSupported((TemporalUnit) null)).isFalse(); + assertThat(TEST.isSupported(NANOS)).isFalse(); + assertThat(TEST.isSupported(MICROS)).isFalse(); + assertThat(TEST.isSupported(MILLIS)).isFalse(); + assertThat(TEST.isSupported(SECONDS)).isFalse(); + assertThat(TEST.isSupported(MINUTES)).isTrue(); + assertThat(TEST.isSupported(HOURS)).isTrue(); + assertThat(TEST.isSupported(HALF_DAYS)).isTrue(); + assertThat(TEST.isSupported(DAYS)).isFalse(); + assertThat(TEST.isSupported(WEEKS)).isFalse(); + assertThat(TEST.isSupported(MONTHS)).isFalse(); + assertThat(TEST.isSupported(YEARS)).isFalse(); + assertThat(TEST.isSupported(DECADES)).isFalse(); + assertThat(TEST.isSupported(CENTURIES)).isFalse(); + assertThat(TEST.isSupported(MILLENNIA)).isFalse(); + assertThat(TEST.isSupported(ERA)).isFalse(); + assertThat(TEST.isSupported(FOREVER)).isFalse(); + assertThat(TEST.isSupported(QUARTER_YEARS)).isFalse(); + assertThat(TEST.isSupported(HALF_YEARS)).isFalse(); + } + + //----------------------------------------------------------------------- + // range(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_range() { + assertThat(TEST.range(MINUTE_OF_HOUR)).isEqualTo(MINUTE_OF_HOUR.range()); + assertThat(TEST.range(MINUTE_OF_DAY)).isEqualTo(MINUTE_OF_DAY.range()); + assertThat(TEST.range(HOUR_OF_DAY)).isEqualTo(HOUR_OF_DAY.range()); + assertThat(TEST.range(CLOCK_HOUR_OF_DAY)).isEqualTo(CLOCK_HOUR_OF_DAY.range()); + assertThat(TEST.range(HOUR_OF_AMPM)).isEqualTo(HOUR_OF_AMPM.range()); + assertThat(TEST.range(CLOCK_HOUR_OF_AMPM)).isEqualTo(CLOCK_HOUR_OF_AMPM.range()); + assertThat(TEST.range(AMPM_OF_DAY)).isEqualTo(AMPM_OF_DAY.range()); + } + + @Test + public void test_range_invalid() { + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.range(SECOND_OF_MINUTE)); + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.range(NANO_OF_SECOND)); + assertThatNullPointerException().isThrownBy(() -> TEST.range((TemporalField) null)); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get() { + assertThat(TEST.get(MINUTE_OF_HOUR)).isEqualTo(31); + assertThat(TEST.get(MINUTE_OF_DAY)).isEqualTo(12 * 60 + 31); + assertThat(TEST.get(HOUR_OF_DAY)).isEqualTo(12); + assertThat(TEST.get(CLOCK_HOUR_OF_DAY)).isEqualTo(12); + assertThat(TEST.get(HOUR_OF_AMPM)).isEqualTo(0); + assertThat(TEST.get(CLOCK_HOUR_OF_AMPM)).isEqualTo(12); + assertThat(TEST.get(AMPM_OF_DAY)).isEqualTo(1); + } + + @Test + public void test_get_invalid() { + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.get(SECOND_OF_MINUTE)); + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.get(NANO_OF_SECOND)); + assertThatNullPointerException().isThrownBy(() -> TEST.get((TemporalField) null)); + } + + //----------------------------------------------------------------------- + // getLong(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_getLong() { + assertThat(TEST.getLong(MINUTE_OF_HOUR)).isEqualTo(31); + assertThat(TEST.getLong(MINUTE_OF_DAY)).isEqualTo(12 * 60 + 31); + assertThat(TEST.getLong(HOUR_OF_DAY)).isEqualTo(12); + assertThat(TEST.getLong(CLOCK_HOUR_OF_DAY)).isEqualTo(12); + assertThat(TEST.getLong(HOUR_OF_AMPM)).isEqualTo(0); + assertThat(TEST.getLong(CLOCK_HOUR_OF_AMPM)).isEqualTo(12); + assertThat(TEST.getLong(AMPM_OF_DAY)).isEqualTo(1); + } + + @Test + public void test_getLong_invalid() { + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.getLong(SECOND_OF_MINUTE)); + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.getLong(NANO_OF_SECOND)); + assertThatNullPointerException().isThrownBy(() -> TEST.getLong((TemporalField) null)); + } + + //----------------------------------------------------------------------- + // with(TemporalAdjuster) + //----------------------------------------------------------------------- + @Test + public void test_with_TemporalAdjuster() { + assertThat(TEST.with(HourMinute.of(9, 10))).isEqualTo(HourMinute.of(9, 10)); + assertThat(TEST.with(AmPm.AM)).isEqualTo(HourMinute.of(0, 31)); + } + + @Test + public void test_with_TemporalAdjuster_invalid() { + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.with(LocalTime.of(9, 10, 11))); + assertThatNullPointerException().isThrownBy(() -> TEST.with((TemporalAdjuster) null)); + } + + //----------------------------------------------------------------------- + // with(TemporalField, long) + //----------------------------------------------------------------------- + @Test + public void test_with_TemporalFieldlong() { + assertThat(TEST.with(MINUTE_OF_HOUR, 2)).isEqualTo(HourMinute.of(12, 2)); + assertThat(TEST.with(MINUTE_OF_DAY, 2)).isEqualTo(HourMinute.of(0, 2)); + assertThat(TEST.with(HOUR_OF_DAY, 2)).isEqualTo(HourMinute.of(2, 31)); + assertThat(TEST.with(CLOCK_HOUR_OF_DAY, 2)).isEqualTo(HourMinute.of(2, 31)); + assertThat(TEST.with(HOUR_OF_AMPM, 2)).isEqualTo(HourMinute.of(14, 31)); + assertThat(TEST.with(CLOCK_HOUR_OF_AMPM, 2)).isEqualTo(HourMinute.of(14, 31)); + assertThat(TEST.with(AMPM_OF_DAY, 0)).isEqualTo(HourMinute.of(0, 31)); + } + + @Test + public void test_with_TemporalFieldlong_invalid() { + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.with(SECOND_OF_MINUTE, 1)); + assertThatExceptionOfType(UnsupportedTemporalTypeException.class).isThrownBy(() -> TEST.with(NANO_OF_SECOND, 1)); + assertThatNullPointerException().isThrownBy(() -> TEST.with((TemporalField) null, 1)); + } + + //----------------------------------------------------------------------- + // withHour(int) / withMinute(int) + //----------------------------------------------------------------------- + @Test + public void test_with_int() { + assertThat(TEST.withHour(9)).isEqualTo(HourMinute.of(9, 31)); + assertThat(TEST.withMinute(9)).isEqualTo(HourMinute.of(12, 9)); + } + + @Test + public void test_with_int_invalid() { + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.withHour(-1)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.withHour(24)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.withMinute(-1)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.withMinute(60)); + } + + //----------------------------------------------------------------------- + // plus(TemporalAmount) + //----------------------------------------------------------------------- + @Test + public void test_plus_TemporalAmount() { + assertThat(TEST.plus(Hours.of(3))).isEqualTo(HourMinute.of(15, 31)); + assertThat(TEST.plus(Minutes.of(3))).isEqualTo(HourMinute.of(12, 34)); + } + + @Test + public void test_plus_TemporalAmount_invalid() { + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.plus(Days.of(1))); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.plus(Seconds.of(3))); + assertThatNullPointerException().isThrownBy(() -> TEST.plus(null)); + } + + //----------------------------------------------------------------------- + // plus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_plus_longTemporalUnit() { + assertThat(TEST.plus(3, HOURS)).isEqualTo(HourMinute.of(15, 31)); + assertThat(TEST.plus(3, MINUTES)).isEqualTo(HourMinute.of(12, 34)); + assertThat(TEST.plus(1, HALF_DAYS)).isEqualTo(HourMinute.of(0, 31)); + } + + @Test + public void test_plus_longTemporalUnit_invalid() { + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.plus(1, DAYS)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.plus(1, SECONDS)); + assertThatNullPointerException().isThrownBy(() -> TEST.plus(1, null)); + } + + //----------------------------------------------------------------------- + // plusHours(int) / plusMinutes(int) + //----------------------------------------------------------------------- + @Test + public void test_plus_int() { + assertThat(TEST.plusHours(3)).isEqualTo(HourMinute.of(15, 31)); + assertThat(TEST.plusMinutes(3)).isEqualTo(HourMinute.of(12, 34)); + assertThat(TEST.plusHours(-15)).isEqualTo(HourMinute.of(21, 31)); + assertThat(TEST.plusHours(25)).isEqualTo(HourMinute.of(13, 31)); + } + + //----------------------------------------------------------------------- + // minus(TemporalAmount) + //----------------------------------------------------------------------- + @Test + public void test_minus_TemporalAmount() { + assertThat(TEST.minus(Hours.of(3))).isEqualTo(HourMinute.of(9, 31)); + assertThat(TEST.minus(Minutes.of(3))).isEqualTo(HourMinute.of(12, 28)); + } + + @Test + public void test_minus_TemporalAmount_invalid() { + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.minus(Days.of(1))); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.minus(Seconds.of(3))); + assertThatNullPointerException().isThrownBy(() -> TEST.minus(null)); + } + + //----------------------------------------------------------------------- + // minus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_minus_longTemporalUnit() { + assertThat(TEST.minus(3, HOURS)).isEqualTo(HourMinute.of(9, 31)); + assertThat(TEST.minus(3, MINUTES)).isEqualTo(HourMinute.of(12, 28)); + assertThat(TEST.minus(1, HALF_DAYS)).isEqualTo(HourMinute.of(0, 31)); + } + + @Test + public void test_minus_longTemporalUnit_invalid() { + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.minus(1, DAYS)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.minus(1, SECONDS)); + assertThatNullPointerException().isThrownBy(() -> TEST.minus(1, null)); + } + + //----------------------------------------------------------------------- + // minusHours(int) / minusMinutes(int) + //----------------------------------------------------------------------- + @Test + public void test_minus_int() { + assertThat(TEST.minusHours(3)).isEqualTo(HourMinute.of(9, 31)); + assertThat(TEST.minusMinutes(3)).isEqualTo(HourMinute.of(12, 28)); + assertThat(TEST.minusHours(-15)).isEqualTo(HourMinute.of(3, 31)); + assertThat(TEST.minusHours(25)).isEqualTo(HourMinute.of(11, 31)); + } + + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @Test + public void test_query() { + assertThat(TEST.query(TemporalQueries.chronology())).isNull(); + assertThat(TEST.query(TemporalQueries.localDate())).isNull(); + assertThat(TEST.query(TemporalQueries.localTime())).isEqualTo(LocalTime.of(12, 31)); + assertThat(TEST.query(TemporalQueries.offset())).isNull(); + assertThat(TEST.query(TemporalQueries.precision())).isEqualTo(MINUTES); + assertThat(TEST.query(TemporalQueries.zone())).isNull(); + assertThat(TEST.query(TemporalQueries.zoneId())).isNull(); + } + + //----------------------------------------------------------------------- + // adjustInto(Temporal) + //----------------------------------------------------------------------- + @Test + public void test_adjustInto_Temporal() { + assertThat(TEST.adjustInto(LocalDateTime.of(2020, 6, 3, 2, 4, 6))).isEqualTo(LocalDateTime.of(2020, 6, 3, 12, 31, 6)); + } + + @Test + public void test_adjustInto_Temporal_invalid() { + assertThatNullPointerException().isThrownBy(() -> TEST.adjustInto((Temporal) null)); + } + + //----------------------------------------------------------------------- + // until(Temporal,TemporalUnit) + //----------------------------------------------------------------------- + static Object[][] data_until_TemporalTemporalUnit() { + return new Object[][] { + {HourMinute.of(12, 31), 0, 0}, + {HourMinute.of(12, 32), 0, 1}, + {HourMinute.of(13, 30), 0, 59}, + {HourMinute.of(13, 31), 1, 60}, + {HourMinute.of(13, 32), 1, 61}, + {HourMinute.of(12, 30), 0, -1}, + {HourMinute.of(11, 31), -1, -60}, + }; + } + + @ParameterizedTest + @MethodSource("data_until_TemporalTemporalUnit") + public void test_until_TemporalTemporalUnit(HourMinute target, int expectedHours, int expectedMins) { + assertThat(TEST.until(target, HOURS)).isEqualTo(expectedHours); + assertThat(TEST.until(target, MINUTES)).isEqualTo(expectedMins); + } + + @Test + public void test_until_TemporalTemporalUnit_invalid() { + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.until(HourMinute.of(0, 0), DAYS)); + assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> TEST.until(HourMinute.of(0, 0), SECONDS)); + assertThatNullPointerException().isThrownBy(() -> TEST.until(null, HOURS)); + assertThatNullPointerException().isThrownBy(() -> TEST.until(HourMinute.of(0, 0), null)); + } + + //----------------------------------------------------------------------- + // format(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test + public void test_format() { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendLiteral("Hour ") + .appendValue(HOUR_OF_DAY) + .appendLiteral(" Minute ") + .appendValue(MINUTE_OF_HOUR) + .toFormatter(); + assertThat(TEST.format(f)).isEqualTo("Hour 12 Minute 31"); + } + + @Test + public void test_format_null() { + assertThatNullPointerException().isThrownBy(() -> TEST.format(null)); + } + + //----------------------------------------------------------------------- + // atDate(LocalDate) + //----------------------------------------------------------------------- + @Test + public void test_atDate_LocalDate() { + LocalDate date = LocalDate.of(2020, 6, 3); + assertThat(TEST.atDate(date)).isEqualTo(LocalDateTime.of(date, LocalTime.of(12, 31))); + } + + @Test + public void test_atDate_LocalDate_invalid() { + assertThatNullPointerException().isThrownBy(() -> TEST.atDate(null)); + } + + //----------------------------------------------------------------------- + // atOffset(ZoneOffset) + //----------------------------------------------------------------------- + @Test + public void test_atOffset_ZoneOffset() { + ZoneOffset offset = ZoneOffset.ofHours(2); + assertThat(TEST.atOffset(offset)).isEqualTo(OffsetTime.of(LocalTime.of(12, 31), offset)); + } + + @Test + public void test_atOffset_ZoneOffset_invalid() { + assertThatNullPointerException().isThrownBy(() -> TEST.atOffset(null)); + } + + //----------------------------------------------------------------------- + // toLocalTime() + //----------------------------------------------------------------------- + @Test + public void test_toLocalTime() { + assertThat(TEST.toLocalTime()).isEqualTo(LocalTime.of(12, 31)); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test + public void test_compareTo() { + for (int hour1 = 0; hour1 <= 23; hour1++) { + for (int minute1 = 0; minute1 <= 59; minute1++) { + HourMinute a = HourMinute.of(hour1, minute1); + for (int hour2 = 0; hour2 <= 23; hour2++) { + for (int minute2 = 0; minute2 <= 59; minute2++) { + HourMinute b = HourMinute.of(hour2, minute2); + if (hour1 < hour2 || (hour1 == hour2 && minute1 < minute2)) { + assertThat(a).isLessThan(b); + assertThat(b).isGreaterThan(a); + assertThat(a.isAfter(b)).isFalse(); + assertThat(a.isBefore(b)).isTrue(); + assertThat(b.isAfter(a)).isTrue(); + assertThat(b.isBefore(a)).isFalse(); + } else if (hour1 > hour2 || (hour1 == hour2 && minute1 > minute2)) { + assertThat(a).isGreaterThan(b); + assertThat(b).isLessThan(a); + assertThat(a.isAfter(b)).isTrue(); + assertThat(a.isBefore(b)).isFalse(); + assertThat(b.isAfter(a)).isFalse(); + assertThat(b.isBefore(a)).isTrue(); + } else { + assertThat(a).isEqualByComparingTo(b); + assertThat(b).isEqualByComparingTo(a); + assertThat(a.isAfter(b)).isFalse(); + assertThat(a.isBefore(b)).isFalse(); + assertThat(b.isAfter(a)).isFalse(); + assertThat(b.isBefore(a)).isFalse(); + } + } + } + } + } + } + + @Test + public void test_compareTo_nullHourMinute() { + assertThatNullPointerException().isThrownBy(() -> TEST.compareTo(null)); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(HourMinute.of(1, 5), HourMinute.of(1, 5)) + .addEqualityGroup(HourMinute.of(14, 43), HourMinute.of(14, 43)) + .testEquals(); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test + public void test_toString() { + assertThat(HourMinute.of(0, 0)).hasToString("00:00"); + assertThat(HourMinute.of(0, 5)).hasToString("00:05"); + assertThat(HourMinute.of(9, 0)).hasToString("09:00"); + assertThat(HourMinute.of(23, 59)).hasToString("23:59"); + } + +} diff --git a/src/test/java/org/threeten/extra/TestHours.java b/src/test/java/org/threeten/extra/TestHours.java index f1d43fe2..05c3ab8b 100644 --- a/src/test/java/org/threeten/extra/TestHours.java +++ b/src/test/java/org/threeten/extra/TestHours.java @@ -31,9 +31,11 @@ */ package org.threeten.extra; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -44,54 +46,77 @@ import java.time.LocalTime; import java.time.format.DateTimeParseException; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test class. */ -@Test public class TestHours { - + //----------------------------------------------------------------------- + @Test public void test_isSerializable() { assertTrue(Serializable.class.isAssignableFrom(Hours.class)); } - + //----------------------------------------------------------------------- + @Test public void test_deserializationSingleton() throws Exception { - Hours orginal = Hours.ZERO; + Hours test = Hours.ZERO; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Hours ser = (Hours) in.readObject(); - assertSame(Hours.ZERO, ser); - } - + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } + } + //----------------------------------------------------------------------- + @Test public void test_ZERO() { - assertSame(Hours.of(0), Hours.ZERO); - assertSame(Hours.of(0), Hours.ZERO); - assertEquals(Hours.ZERO.getAmount(), 0); + assertSame(Hours.ZERO, Hours.of(0)); + assertEquals(Hours.ZERO, Hours.of(0)); + assertEquals(0, Hours.ZERO.getAmount()); + assertFalse(Hours.ZERO.isNegative()); + assertTrue(Hours.ZERO.isZero()); + assertFalse(Hours.ZERO.isPositive()); } - + //----------------------------------------------------------------------- + @Test public void test_of() { - assertEquals(Hours.of(0).getAmount(), 0); - assertEquals(Hours.of(1).getAmount(), 1); - assertEquals(Hours.of(2).getAmount(), 2); - assertEquals(Hours.of(Integer.MAX_VALUE).getAmount(), Integer.MAX_VALUE); - assertEquals(Hours.of(-1).getAmount(), -1); - assertEquals(Hours.of(-2).getAmount(), -2); - assertEquals(Hours.of(Integer.MIN_VALUE).getAmount(), Integer.MIN_VALUE); - } - + assertEquals(0, Hours.of(0).getAmount()); + assertEquals(1, Hours.of(1).getAmount()); + assertEquals(2, Hours.of(2).getAmount()); + assertEquals(Integer.MAX_VALUE, Hours.of(Integer.MAX_VALUE).getAmount()); + assertEquals(-1, Hours.of(-1).getAmount()); + assertEquals(-2, Hours.of(-2).getAmount()); + assertEquals(Integer.MIN_VALUE, Hours.of(Integer.MIN_VALUE).getAmount()); + } + + @Test + public void test_ofMinusOne() { + assertEquals(-1, Hours.of(-1).getAmount()); + assertTrue(Hours.of(-1).isNegative()); + assertFalse(Hours.of(-1).isZero()); + assertFalse(Hours.of(-1).isPositive()); + } + + @Test + public void test_ofPlusOne() { + assertEquals(1, Hours.of(1).getAmount()); + assertFalse(Hours.of(1).isNegative()); + assertFalse(Hours.of(1).isZero()); + assertTrue(Hours.of(1).isPositive()); + } + //----------------------------------------------------------------------- - @DataProvider(name = "parseValid") - Object[][] data_valid() { + public static Object[][] data_valid() { return new Object[][] { {"PT0H", 0}, {"PT1H", 1}, @@ -101,29 +126,42 @@ Object[][] data_valid() { {"PT+2H", 2}, {"PT-0H", 0}, {"PT-2H", -2}, + + {"P0D", 0 * 24}, + {"P1D", 1 * 24}, + {"P2D", 2 * 24}, + {"P1234567D", 1234567 * 24}, + {"P+0D", 0 * 24}, + {"P+2D", 2 * 24}, + {"P-0D", 0 * 24}, + {"P-2D", -2 * 24}, + + {"P0DT0H", 0}, + {"P1DT2H", 1 * 24+ 2}, }; } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid(String str, int expectedDays) { - assertEquals(Hours.parse(str), Hours.of(expectedDays)); + assertEquals(Hours.of(expectedDays), Hours.parse(str)); } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid_initialPlus(String str, int expectedDays) { - assertEquals(Hours.parse("+" + str), Hours.of(expectedDays)); + assertEquals(Hours.of(expectedDays), Hours.parse("+" + str)); } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid_initialMinus(String str, int expectedDays) { - assertEquals(Hours.parse("-" + str), Hours.of(-expectedDays)); + assertEquals(Hours.of(-expectedDays), Hours.parse("-" + str)); } - @DataProvider(name = "parseInvalid") - Object[][] data_invalid() { + public static Object[][] data_invalid() { return new Object[][] { {"P3W"}, - {"P3D"}, {"P3Q"}, {"P1M2Y"}, @@ -131,6 +169,7 @@ Object[][] data_invalid() { {"-3"}, {"3H"}, {"-3H"}, + {"P3H"}, {"P3"}, {"P-3"}, {"PH"}, @@ -139,17 +178,19 @@ Object[][] data_invalid() { }; } - @Test(expectedExceptions = DateTimeParseException.class, dataProvider = "parseInvalid") + @ParameterizedTest + @MethodSource("data_invalid") public void test_parse_CharSequence_invalid(String str) { - Hours.parse(str); + assertThrows(DateTimeParseException.class, () -> Hours.parse(str)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequence_null() { - Hours.parse((CharSequence) null); + assertThrows(NullPointerException.class, () -> Hours.parse((CharSequence) null)); } - + //----------------------------------------------------------------------- + @Test public void test_plus_TemporalAmount_Hours() { Hours test5 = Hours.of(5); assertEquals(Hours.of(5), test5.plus(Hours.of(0))); @@ -159,6 +200,7 @@ public void test_plus_TemporalAmount_Hours() { assertEquals(Hours.of(Integer.MIN_VALUE), Hours.of(Integer.MIN_VALUE + 1).plus(Hours.of(-1))); } + @Test public void test_plus_TemporalAmount_Period() { Hours test5 = Hours.of(5); assertEquals(Hours.of(5), test5.plus(Duration.ofHours(0))); @@ -168,22 +210,23 @@ public void test_plus_TemporalAmount_Period() { assertEquals(Hours.of(Integer.MIN_VALUE), Hours.of(Integer.MIN_VALUE + 1).plus(Duration.ofHours(-1))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooBig() { - Hours.of(Integer.MAX_VALUE - 1).plus(Hours.of(2)); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MAX_VALUE - 1).plus(Hours.of(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooSmall() { - Hours.of(Integer.MIN_VALUE + 1).plus(Hours.of(-2)); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MIN_VALUE + 1).plus(Hours.of(-2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_plus_TemporalAmount_null() { - Hours.of(Integer.MIN_VALUE + 1).plus(null); + assertThrows(NullPointerException.class, () -> Hours.of(Integer.MIN_VALUE + 1).plus(null)); } //----------------------------------------------------------------------- + @Test public void test_plus_int() { Hours test5 = Hours.of(5); assertEquals(Hours.of(5), test5.plus(0)); @@ -193,17 +236,18 @@ public void test_plus_int() { assertEquals(Hours.of(Integer.MIN_VALUE), Hours.of(Integer.MIN_VALUE + 1).plus(-1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooBig() { - Hours.of(Integer.MAX_VALUE - 1).plus(2); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MAX_VALUE - 1).plus(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooSmall() { - Hours.of(Integer.MIN_VALUE + 1).plus(-2); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MIN_VALUE + 1).plus(-2)); } //----------------------------------------------------------------------- + @Test public void test_minus_TemporalAmount_Hours() { Hours test5 = Hours.of(5); assertEquals(Hours.of(5), test5.minus(Hours.of(0))); @@ -213,6 +257,7 @@ public void test_minus_TemporalAmount_Hours() { assertEquals(Hours.of(Integer.MIN_VALUE), Hours.of(Integer.MIN_VALUE + 1).minus(Hours.of(1))); } + @Test public void test_minus_TemporalAmount_Duration() { Hours test5 = Hours.of(5); assertEquals(Hours.of(5), test5.minus(Duration.ofHours(0))); @@ -222,22 +267,23 @@ public void test_minus_TemporalAmount_Duration() { assertEquals(Hours.of(Integer.MIN_VALUE), Hours.of(Integer.MIN_VALUE + 1).minus(Duration.ofHours(1))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooBig() { - Hours.of(Integer.MAX_VALUE - 1).minus(Hours.of(-2)); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MAX_VALUE - 1).minus(Hours.of(-2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooSmall() { - Hours.of(Integer.MIN_VALUE + 1).minus(Hours.of(2)); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MIN_VALUE + 1).minus(Hours.of(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_minus_TemporalAmount_null() { - Hours.of(Integer.MIN_VALUE + 1).minus(null); + assertThrows(NullPointerException.class, () -> Hours.of(Integer.MIN_VALUE + 1).minus(null)); } //----------------------------------------------------------------------- + @Test public void test_minus_int() { Hours test5 = Hours.of(5); assertEquals(Hours.of(5), test5.minus(0)); @@ -247,17 +293,18 @@ public void test_minus_int() { assertEquals(Hours.of(Integer.MIN_VALUE), Hours.of(Integer.MIN_VALUE + 1).minus(1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooBig() { - Hours.of(Integer.MAX_VALUE - 1).minus(-2); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MAX_VALUE - 1).minus(-2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooSmall() { - Hours.of(Integer.MIN_VALUE + 1).minus(2); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MIN_VALUE + 1).minus(2)); } //----------------------------------------------------------------------- + @Test public void test_multipliedBy() { Hours test5 = Hours.of(5); assertEquals(Hours.of(0), test5.multipliedBy(0)); @@ -267,22 +314,24 @@ public void test_multipliedBy() { assertEquals(Hours.of(-15), test5.multipliedBy(-3)); } + @Test public void test_multipliedBy_negate() { Hours test5 = Hours.of(5); assertEquals(Hours.of(-15), test5.multipliedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooBig() { - Hours.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooSmall() { - Hours.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2)); } //----------------------------------------------------------------------- + @Test public void test_dividedBy() { Hours test12 = Hours.of(12); assertEquals(Hours.of(12), test12.dividedBy(1)); @@ -294,17 +343,19 @@ public void test_dividedBy() { assertEquals(Hours.of(-4), test12.dividedBy(-3)); } + @Test public void test_dividedBy_negate() { Hours test12 = Hours.of(12); assertEquals(Hours.of(-4), test12.dividedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_dividedBy_divideByZero() { - Hours.of(1).dividedBy(0); + assertThrows(ArithmeticException.class, () -> Hours.of(1).dividedBy(0)); } //----------------------------------------------------------------------- + @Test public void test_negated() { assertEquals(Hours.of(0), Hours.of(0).negated()); assertEquals(Hours.of(-12), Hours.of(12).negated()); @@ -312,12 +363,13 @@ public void test_negated() { assertEquals(Hours.of(-Integer.MAX_VALUE), Hours.of(Integer.MAX_VALUE).negated()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_negated_overflow() { - Hours.of(Integer.MIN_VALUE).negated(); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MIN_VALUE).negated()); } //----------------------------------------------------------------------- + @Test public void test_abs() { assertEquals(Hours.of(0), Hours.of(0).abs()); assertEquals(Hours.of(12), Hours.of(12).abs()); @@ -326,33 +378,39 @@ public void test_abs() { assertEquals(Hours.of(Integer.MAX_VALUE), Hours.of(-Integer.MAX_VALUE).abs()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_abs_overflow() { - Hours.of(Integer.MIN_VALUE).abs(); + assertThrows(ArithmeticException.class, () -> Hours.of(Integer.MIN_VALUE).abs()); } //----------------------------------------------------------------------- + @Test public void test_addTo() { LocalTime base = LocalTime.of(11, 30); - assertEquals(Hours.of(0).addTo(base), LocalTime.of(11, 30)); - assertEquals(Hours.of(6).addTo(base), LocalTime.of(17, 30)); + assertEquals(LocalTime.of(11, 30), Hours.of(0).addTo(base)); + assertEquals(LocalTime.of(17, 30), Hours.of(6).addTo(base)); } //----------------------------------------------------------------------- + @Test public void test_subtractFrom() { LocalTime base = LocalTime.of(11, 30); - assertEquals(Hours.of(0).subtractFrom(base), LocalTime.of(11, 30)); - assertEquals(Hours.of(6).subtractFrom(base), LocalTime.of(5, 30)); + assertEquals(LocalTime.of(11, 30), Hours.of(0).subtractFrom(base)); + assertEquals(LocalTime.of(5, 30), Hours.of(6).subtractFrom(base)); } //----------------------------------------------------------------------- + @SuppressWarnings("deprecation") + @Test public void test_toDuration() { for (int i = -20; i < 20; i++) { - assertEquals(Hours.of(i).toPeriod(), Duration.ofHours(i)); + assertEquals(Duration.ofHours(i), Hours.of(i).toPeriod()); + assertEquals(Duration.ofHours(i), Hours.of(i).toDuration()); } } //----------------------------------------------------------------------- + @Test public void test_compareTo() { Hours test5 = Hours.of(5); Hours test6 = Hours.of(6); @@ -361,45 +419,28 @@ public void test_compareTo() { assertEquals(1, test6.compareTo(test5)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_null() { Hours test5 = Hours.of(5); - test5.compareTo(null); + assertThrows(NullPointerException.class, () -> test5.compareTo(null)); } //----------------------------------------------------------------------- - public void test_equals() { - Hours test5 = Hours.of(5); - Hours test6 = Hours.of(6); - assertEquals(true, test5.equals(test5)); - assertEquals(false, test5.equals(test6)); - assertEquals(false, test6.equals(test5)); - } - - public void test_equals_null() { - Hours test5 = Hours.of(5); - assertEquals(false, test5.equals(null)); - } - - public void test_equals_otherClass() { - Hours test5 = Hours.of(5); - assertEquals(false, test5.equals("")); - } - - //----------------------------------------------------------------------- - public void test_hashCode() { - Hours test5 = Hours.of(5); - Hours test6 = Hours.of(6); - assertEquals(true, test5.hashCode() == test5.hashCode()); - assertEquals(false, test5.hashCode() == test6.hashCode()); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Hours.of(5), Hours.of(5)) + .addEqualityGroup(Hours.of(6), Hours.of(6)) + .testEquals(); } //----------------------------------------------------------------------- + @Test public void test_toString() { Hours test5 = Hours.of(5); assertEquals("PT5H", test5.toString()); Hours testM1 = Hours.of(-1); assertEquals("PT-1H", testM1.toString()); } - + } diff --git a/src/test/java/org/threeten/extra/TestInterval.java b/src/test/java/org/threeten/extra/TestInterval.java index 7a735b70..49685714 100644 --- a/src/test/java/org/threeten/extra/TestInterval.java +++ b/src/test/java/org/threeten/extra/TestInterval.java @@ -32,9 +32,11 @@ package org.threeten.extra; import static java.time.temporal.ChronoUnit.HOURS; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static java.time.temporal.ChronoUnit.MONTHS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -44,404 +46,526 @@ import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; +import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test class. */ -@Test public class TestInterval { - Instant NOW1 = ZonedDateTime.of(2014, 12, 1, 1, 0, 0, 0, ZoneOffset.UTC).toInstant(); - Instant NOW2 = NOW1.plusSeconds(60); - Instant NOW3 = NOW2.plusSeconds(60); - Instant NOW4 = NOW3.plusSeconds(60); + static Instant NOW1 = ZonedDateTime.of(2014, 12, 1, 1, 0, 0, 0, ZoneOffset.UTC).toInstant(); + static Instant NOW2 = NOW1.plusSeconds(60); + static Instant NOW3 = NOW2.plusSeconds(60); + static Instant NOW4 = NOW3.plusSeconds(60); + static Instant NOW11 = NOW1.plusSeconds(11); + static Instant NOW12 = NOW1.plusSeconds(12); + static Instant NOW13 = NOW1.plusSeconds(13); + static Instant NOW14 = NOW1.plusSeconds(14); + static Instant NOW15 = NOW1.plusSeconds(15); + static Instant NOW16 = NOW1.plusSeconds(16); //----------------------------------------------------------------------- + @Test public void test_isSerializable() { assertTrue(Serializable.class.isAssignableFrom(Interval.class)); } //----------------------------------------------------------------------- + @Test public void test_serialization() throws Exception { - Interval orginal = Interval.of(Instant.EPOCH, NOW1); + Interval test = Interval.of(Instant.EPOCH, NOW1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Interval ser = (Interval) in.readObject(); - assertEquals(ser, orginal); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertEquals(test, ois.readObject()); + } } //----------------------------------------------------------------------- + @Test public void test_ALL() { Interval test = Interval.ALL; - assertEquals(test.getStart(), Instant.MIN); - assertEquals(test.getEnd(), Instant.MAX); - assertEquals(test.isEmpty(), false); - assertEquals(test.isUnboundedStart(), true); - assertEquals(test.isUnboundedEnd(), true); + assertEquals(Instant.MIN, test.getStart()); + assertEquals(Instant.MAX, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(true, test.isUnboundedEnd()); } //----------------------------------------------------------------------- + @Test public void test_of_Instant_Instant() { Interval test = Interval.of(NOW1, NOW2); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW2); - assertEquals(test.isEmpty(), false); - assertEquals(test.isUnboundedStart(), false); - assertEquals(test.isUnboundedEnd(), false); + assertEquals(NOW1, test.getStart()); + assertEquals(NOW2, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); } + @Test public void test_of_Instant_Instant_empty() { Interval test = Interval.of(NOW1, NOW1); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW1); - assertEquals(test.isEmpty(), true); - assertEquals(test.isUnboundedStart(), false); - assertEquals(test.isUnboundedEnd(), false); + assertEquals(NOW1, test.getStart()); + assertEquals(NOW1, test.getEnd()); + assertEquals(true, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_Instant_Instant_badOrder() { - Interval.of(NOW2, NOW1); + assertThrows(DateTimeException.class, () -> Interval.of(NOW2, NOW1)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_of_Instant_Instant_nullStart() { - Interval.of(null, NOW2); + assertThrows(NullPointerException.class, () -> Interval.of((Instant) null, NOW2)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_of_Instant_Instant_nullEnd() { - Interval.of(NOW1, (Instant) null); + assertThrows(NullPointerException.class, () -> Interval.of(NOW1, (Instant) null)); } //----------------------------------------------------------------------- + @Test public void test_of_Instant_Duration() { Interval test = Interval.of(NOW1, Duration.ofSeconds(60)); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW2); + assertEquals(NOW1, test.getStart()); + assertEquals(NOW2, test.getEnd()); } + @Test public void test_of_Instant_Duration_zero() { Interval test = Interval.of(NOW1, Duration.ZERO); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW1); + assertEquals(NOW1, test.getStart()); + assertEquals(NOW1, test.getEnd()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_Instant_Duration_negative() { - Interval.of(NOW2, Duration.ofSeconds(-1)); + assertThrows(DateTimeException.class, () -> Interval.of(NOW2, Duration.ofSeconds(-1))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_of_Instant_Duration_nullInstant() { - Interval.of(null, Duration.ZERO); + assertThrows(NullPointerException.class, () -> Interval.of(null, Duration.ZERO)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_of_Instant_Duration_nullDuration() { - Interval.of(NOW1, (Duration) null); + assertThrows(NullPointerException.class, () -> Interval.of(NOW1, (Duration) null)); } //----------------------------------------------------------------------- - public void test_parse_CharSequence() { - Interval test = Interval.parse(NOW1 + "/" + NOW2); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW2); + @Test + public void test_of_Duration_Instant() { + Interval test = Interval.of(Duration.ofSeconds(60), NOW2); + assertEquals(NOW1, test.getStart()); + assertEquals(NOW2, test.getEnd()); + } + + @Test + public void test_of_Duration_Instant_zero() { + Interval test = Interval.of(Duration.ZERO, NOW1); + assertEquals(NOW1, test.getStart()); + assertEquals(NOW1, test.getEnd()); + } + + @Test + public void test_of_Duration_Instant_negative() { + assertThrows(DateTimeException.class, () -> Interval.of(Duration.ofSeconds(-1), NOW2)); + } + + @Test + public void test_of_Duration_Instant_nullInstant() { + assertThrows(NullPointerException.class, () -> Interval.of(Duration.ZERO, null)); + } + + @Test + public void test_of_Duration_Instant_nullDuration() { + assertThrows(NullPointerException.class, () -> Interval.of((Duration) null, NOW1)); + } + + //----------------------------------------------------------------------- + @Test + public void test_startingAt_Instant_createsUnboundedEnd() { + Interval interval = Interval.startingAt(NOW1); + + assertEquals(NOW1, interval.getStart()); + assertTrue(interval.isUnboundedEnd()); + assertFalse(interval.isEmpty()); } - public void test_parse_CharSequence_DurationInstant() { - Interval test = Interval.parse(Duration.ofHours(6) + "/" + NOW2); - assertEquals(test.getStart(), NOW2.minus(6, HOURS)); - assertEquals(test.getEnd(), NOW2); + @Test + public void test_startingAt_InstantMAX_createsUnboundedEndEmpty() { + Interval interval = Interval.startingAt(Instant.MAX); + + assertEquals(Instant.MAX, interval.getStart()); + assertTrue(interval.isUnboundedEnd()); + assertTrue(interval.isEmpty()); } - public void test_parse_CharSequence_DurationInstant_caseInsensitive() { - Interval test = Interval.parse("pt6h/" + NOW2); - assertEquals(test.getStart(), NOW2.minus(6, HOURS)); - assertEquals(test.getEnd(), NOW2); + @Test + public void test_startingAt_InstantMIN_isALL() { + Interval interval = Interval.startingAt(Instant.MIN); + + assertEquals(Interval.ALL, interval); } - public void test_parse_CharSequence_InstantDuration() { - Interval test = Interval.parse(NOW1 + "/" + Duration.ofHours(6)); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW1.plus(6, HOURS)); + @Test + public void test_startingAt_null() { + assertThrows(NullPointerException.class, () -> Interval.startingAt(null)); } - public void test_parse_CharSequence_InstantDuration_caseInsensitive() { - Interval test = Interval.parse(NOW1 + "/pt6h"); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW1.plus(6, HOURS)); + //----------------------------------------------------------------------- + @Test + public void test_endingAt_createsUnboundedStart() { + Interval interval = Interval.endingAt(NOW1); + + assertEquals(NOW1, interval.getEnd()); + assertTrue(interval.isUnboundedStart()); + assertFalse(interval.isEmpty()); + } + + @Test + public void test_sendingAt_InstantMIN_createsUnboundedStartEmpty() { + Interval interval = Interval.endingAt(Instant.MIN); + + assertEquals(Instant.MIN, interval.getEnd()); + assertTrue(interval.isUnboundedStart()); + assertTrue(interval.isEmpty()); } - public void test_parse_CharSequence_empty() { - Interval test = Interval.parse(NOW1 + "/" + NOW1); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW1); + @Test + public void test_endingAt_InstantMAX_isALL() { + Interval interval = Interval.endingAt(Instant.MAX); + + assertEquals(Interval.ALL, interval); + } + + @Test + public void test_endingAt_null() { + assertThrows(NullPointerException.class, () -> Interval.endingAt(null)); + } + + /* Lower and upper bound for Intervals */ + private static final Instant MIN_OFFSET_DATE_TIME = OffsetDateTime.MIN.plusDays(1L).toInstant(); + private static final Instant MAX_OFFSET_DATE_TIME = OffsetDateTime.MAX.minusDays(1L).toInstant(); + + //----------------------------------------------------------------------- + public static Object[][] data_parseValid() { + Instant minPlusOneDay = Instant.MIN.plus(Duration.ofDays(1)); + Instant maxMinusOneDay = Instant.MAX.minus(Duration.ofDays(1)); + return new Object[][] { + {NOW1 + "/" + NOW2, NOW1, NOW2}, + {Duration.ofHours(6) + "/" + NOW2, NOW2.minus(6, HOURS), NOW2}, + {"P6MT5H/" + NOW2, NOW2.atZone(ZoneOffset.UTC).minus(6, MONTHS).minus(5, HOURS).toInstant(), NOW2}, + {"pt6h/" + NOW2, NOW2.minus(6, HOURS), NOW2}, + {"pt6h/" + Instant.MAX, Instant.MAX.minus(6, HOURS), Instant.MAX}, + {"pt6h/" + minPlusOneDay, minPlusOneDay.minus(6, HOURS), minPlusOneDay}, + {NOW1 + "/" + Duration.ofHours(6), NOW1, NOW1.plus(6, HOURS)}, + {NOW1 + "/pt6h", NOW1, NOW1.plus(6, HOURS)}, + {Instant.MIN + "/pt6h", Instant.MIN, Instant.MIN.plus(6, HOURS)}, + {maxMinusOneDay + "/Pt6h", maxMinusOneDay, maxMinusOneDay.plus(6, HOURS)}, + {NOW1 + "/" + NOW1, NOW1, NOW1}, + {NOW1.atOffset(ZoneOffset.ofHours(2)) + "/" + NOW2.atOffset(ZoneOffset.ofHours(2)), NOW1, NOW2}, + {NOW1.atOffset(ZoneOffset.ofHours(2)) + "/" + NOW2.atOffset(ZoneOffset.ofHours(3)), NOW1, NOW2}, + {NOW1.atOffset(ZoneOffset.ofHours(2)) + "/" + NOW2.atOffset(ZoneOffset.ofHours(2)).toLocalDateTime(), NOW1, NOW2}, + {MIN_OFFSET_DATE_TIME.toString() + "/" + MAX_OFFSET_DATE_TIME, MIN_OFFSET_DATE_TIME, MAX_OFFSET_DATE_TIME}, + {NOW1 + "/" + Instant.MAX, NOW1, Instant.MAX}, + {Instant.MIN.toString() + "/" + NOW2, Instant.MIN, NOW2}, + {Instant.MIN.toString() + "/" + Instant.MAX, Instant.MIN, Instant.MAX} + }; } - - public void test_parseCharSequence_InstantInstant_with_timezones() { - Interval test = Interval.parse(NOW1.atOffset(ZoneOffset.ofHours(2)).toString() + "/" + NOW2.atOffset(ZoneOffset.ofHours(2)).toString()); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW2); + + @ParameterizedTest + @MethodSource("data_parseValid") + public void test_parse_CharSequence(String input, Instant start, Instant end) { + Interval test = Interval.parse(input); + assertEquals(start, test.getStart()); + assertEquals(end, test.getEnd()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_parse_CharSequence_badOrder() { - Interval.parse(NOW2 + "/" + NOW1); + assertThrows(DateTimeException.class, () -> Interval.parse(NOW2 + "/" + NOW1)); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_parse_CharSequence_badFormat() { - Interval.parse(NOW2 + "-" + NOW1); + assertThrows(DateTimeParseException.class, () -> Interval.parse(NOW2 + "-" + NOW1)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequence_null() { - Interval.parse(null); + assertThrows(NullPointerException.class, () -> Interval.parse(null)); } //----------------------------------------------------------------------- + @Test public void test_withStart() { Interval base = Interval.of(NOW1, NOW3); Interval test = base.withStart(NOW2); - assertEquals(test.getStart(), NOW2); - assertEquals(test.getEnd(), NOW3); + assertEquals(NOW2, test.getStart()); + assertEquals(NOW3, test.getEnd()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withStart_badOrder() { Interval base = Interval.of(NOW1, NOW2); - base.withStart(NOW3); + assertThrows(DateTimeException.class, () -> base.withStart(NOW3)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_withStart_null() { Interval base = Interval.of(NOW1, NOW2); - base.withStart(null); + assertThrows(NullPointerException.class, () -> base.withStart(null)); } //----------------------------------------------------------------------- + @Test public void test_withEnd() { Interval base = Interval.of(NOW1, NOW3); Interval test = base.withEnd(NOW2); - assertEquals(test.getStart(), NOW1); - assertEquals(test.getEnd(), NOW2); + assertEquals(NOW1, test.getStart()); + assertEquals(NOW2, test.getEnd()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withEnd_badOrder() { Interval base = Interval.of(NOW2, NOW3); - base.withEnd(NOW1); + assertThrows(DateTimeException.class, () -> base.withEnd(NOW1)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_withEnd_null() { Interval base = Interval.of(NOW1, NOW2); - base.withEnd(null); + assertThrows(NullPointerException.class, () -> base.withEnd(null)); } //----------------------------------------------------------------------- + @Test public void test_contains_Instant() { Interval test = Interval.of(NOW1, NOW2); - assertEquals(test.contains(NOW1.minusSeconds(1)), false); - assertEquals(test.contains(NOW1), true); - assertEquals(test.contains(NOW1.plusSeconds(1)), true); - assertEquals(test.contains(NOW2.minusSeconds(1)), true); - assertEquals(test.contains(NOW2), false); + assertEquals(false, test.contains(NOW1.minusSeconds(1))); + assertEquals(true, test.contains(NOW1)); + assertEquals(true, test.contains(NOW1.plusSeconds(1))); + assertEquals(true, test.contains(NOW2.minusSeconds(1))); + assertEquals(false, test.contains(NOW2)); } + @Test public void test_contains_Instant_baseEmpty() { Interval test = Interval.of(NOW1, NOW1); - assertEquals(test.contains(NOW1.minusSeconds(1)), false); - assertEquals(test.contains(NOW1), false); - assertEquals(test.contains(NOW1.plusSeconds(1)), false); + assertEquals(false, test.contains(NOW1.minusSeconds(1))); + assertEquals(false, test.contains(NOW1)); + assertEquals(false, test.contains(NOW1.plusSeconds(1))); } + @Test + public void test_contains_min() { + Interval test = Interval.of(Instant.MIN, NOW2); + assertEquals(true, test.contains(Instant.MIN)); + assertEquals(true, test.contains(NOW1)); + assertEquals(false, test.contains(NOW2)); + } + + @Test public void test_contains_max() { Interval test = Interval.of(NOW2, Instant.MAX); - assertEquals(test.contains(Instant.MIN), false); - assertEquals(test.contains(NOW1), false); - assertEquals(test.contains(NOW2), true); - assertEquals(test.contains(NOW3), true); - assertEquals(test.contains(Instant.MAX), true); + assertEquals(false, test.contains(Instant.MIN)); + assertEquals(false, test.contains(NOW1)); + assertEquals(true, test.contains(NOW2)); + assertEquals(true, test.contains(NOW3)); + assertEquals(true, test.contains(Instant.MAX)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_contains_Instant_null() { Interval base = Interval.of(NOW1, NOW2); - base.contains((Instant) null); + assertThrows(NullPointerException.class, () -> base.contains((Instant) null)); } //----------------------------------------------------------------------- + @Test public void test_encloses_Interval() { Interval test = Interval.of(NOW1, NOW2); // completely before - assertEquals(test.encloses(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.encloses(Interval.of(NOW1.minusSeconds(1), NOW1)), false); + assertEquals(false, test.encloses(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(false, test.encloses(Interval.of(NOW1.minusSeconds(1), NOW1))); // partly before - assertEquals(test.encloses(Interval.of(NOW1.minusSeconds(1), NOW2)), false); - assertEquals(test.encloses(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1))), false); + assertEquals(false, test.encloses(Interval.of(NOW1.minusSeconds(1), NOW2))); + assertEquals(false, test.encloses(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1)))); // contained - assertEquals(test.encloses(Interval.of(NOW1, NOW2.minusSeconds(1))), true); - assertEquals(test.encloses(Interval.of(NOW1, NOW2)), true); - assertEquals(test.encloses(Interval.of(NOW1.plusSeconds(1), NOW2)), true); + assertEquals(true, test.encloses(Interval.of(NOW1, NOW2.minusSeconds(1)))); + assertEquals(true, test.encloses(Interval.of(NOW1, NOW2))); + assertEquals(true, test.encloses(Interval.of(NOW1.plusSeconds(1), NOW2))); // partly after - assertEquals(test.encloses(Interval.of(NOW1, NOW2.plusSeconds(1))), false); - assertEquals(test.encloses(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1))), false); + assertEquals(false, test.encloses(Interval.of(NOW1, NOW2.plusSeconds(1)))); + assertEquals(false, test.encloses(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1)))); // completely after - assertEquals(test.encloses(Interval.of(NOW2, NOW2.plusSeconds(1))), false); - assertEquals(test.encloses(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2))), false); + assertEquals(false, test.encloses(Interval.of(NOW2, NOW2.plusSeconds(1)))); + assertEquals(false, test.encloses(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2)))); } + @Test public void test_encloses_Interval_empty() { Interval test = Interval.of(NOW1, NOW1); // completely before - assertEquals(test.encloses(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); + assertEquals(false, test.encloses(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); // partly before - assertEquals(test.encloses(Interval.of(NOW1.minusSeconds(1), NOW1)), false); + assertEquals(false, test.encloses(Interval.of(NOW1.minusSeconds(1), NOW1))); // equal - assertEquals(test.encloses(Interval.of(NOW1, NOW1)), true); + assertEquals(true, test.encloses(Interval.of(NOW1, NOW1))); // completely after - assertEquals(test.encloses(Interval.of(NOW1, NOW1.plusSeconds(1))), false); - assertEquals(test.encloses(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2))), false); + assertEquals(false, test.encloses(Interval.of(NOW1, NOW1.plusSeconds(1)))); + assertEquals(false, test.encloses(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2)))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_encloses_Interval_null() { Interval base = Interval.of(NOW1, NOW2); - base.encloses((Interval) null); + assertThrows(NullPointerException.class, () -> base.encloses((Interval) null)); } //----------------------------------------------------------------------- + @Test public void test_abuts_Interval() { Interval test = Interval.of(NOW1, NOW2); // completely before - assertEquals(test.abuts(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.abuts(Interval.of(NOW1.minusSeconds(1), NOW1)), true); + assertEquals(false, test.abuts(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(true, test.abuts(Interval.of(NOW1.minusSeconds(1), NOW1))); // partly before - assertEquals(test.abuts(Interval.of(NOW1.minusSeconds(1), NOW2)), false); - assertEquals(test.abuts(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1))), false); + assertEquals(false, test.abuts(Interval.of(NOW1.minusSeconds(1), NOW2))); + assertEquals(false, test.abuts(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1)))); // contained - assertEquals(test.abuts(Interval.of(NOW1, NOW2.minusSeconds(1))), false); - assertEquals(test.abuts(Interval.of(NOW1, NOW2)), false); - assertEquals(test.abuts(Interval.of(NOW1.plusSeconds(1), NOW2)), false); + assertEquals(false, test.abuts(Interval.of(NOW1, NOW2.minusSeconds(1)))); + assertEquals(false, test.abuts(Interval.of(NOW1, NOW2))); + assertEquals(false, test.abuts(Interval.of(NOW1.plusSeconds(1), NOW2))); // partly after - assertEquals(test.abuts(Interval.of(NOW1, NOW2.plusSeconds(1))), false); - assertEquals(test.abuts(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1))), false); + assertEquals(false, test.abuts(Interval.of(NOW1, NOW2.plusSeconds(1)))); + assertEquals(false, test.abuts(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1)))); // completely after - assertEquals(test.abuts(Interval.of(NOW2, NOW2.plusSeconds(1))), true); - assertEquals(test.abuts(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2))), false); + assertEquals(true, test.abuts(Interval.of(NOW2, NOW2.plusSeconds(1)))); + assertEquals(false, test.abuts(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2)))); } + @Test public void test_abuts_Interval_empty() { Interval test = Interval.of(NOW1, NOW1); // completely before - assertEquals(test.abuts(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.abuts(Interval.of(NOW1.minusSeconds(1), NOW1)), true); + assertEquals(false, test.abuts(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(true, test.abuts(Interval.of(NOW1.minusSeconds(1), NOW1))); // equal - assertEquals(test.abuts(Interval.of(NOW1, NOW1)), false); + assertEquals(false, test.abuts(Interval.of(NOW1, NOW1))); // completely after - assertEquals(test.abuts(Interval.of(NOW1, NOW1.plusSeconds(1))), true); - assertEquals(test.abuts(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2))), false); + assertEquals(true, test.abuts(Interval.of(NOW1, NOW1.plusSeconds(1)))); + assertEquals(false, test.abuts(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2)))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_abuts_Interval_null() { Interval base = Interval.of(NOW1, NOW2); - base.abuts((Interval) null); + assertThrows(NullPointerException.class, () -> base.abuts((Interval) null)); } //----------------------------------------------------------------------- + @Test public void test_isConnected_Interval() { Interval test = Interval.of(NOW1, NOW2); // completely before - assertEquals(test.isConnected(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.isConnected(Interval.of(NOW1.minusSeconds(1), NOW1)), true); + assertEquals(false, test.isConnected(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(true, test.isConnected(Interval.of(NOW1.minusSeconds(1), NOW1))); // partly before - assertEquals(test.isConnected(Interval.of(NOW1.minusSeconds(1), NOW2)), true); - assertEquals(test.isConnected(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1))), true); + assertEquals(true, test.isConnected(Interval.of(NOW1.minusSeconds(1), NOW2))); + assertEquals(true, test.isConnected(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1)))); // contained - assertEquals(test.isConnected(Interval.of(NOW1, NOW2.minusSeconds(1))), true); - assertEquals(test.isConnected(Interval.of(NOW1, NOW2)), true); - assertEquals(test.isConnected(Interval.of(NOW1.plusSeconds(1), NOW2)), true); + assertEquals(true, test.isConnected(Interval.of(NOW1, NOW2.minusSeconds(1)))); + assertEquals(true, test.isConnected(Interval.of(NOW1, NOW2))); + assertEquals(true, test.isConnected(Interval.of(NOW1.plusSeconds(1), NOW2))); // partly after - assertEquals(test.isConnected(Interval.of(NOW1, NOW2.plusSeconds(1))), true); - assertEquals(test.isConnected(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1))), true); + assertEquals(true, test.isConnected(Interval.of(NOW1, NOW2.plusSeconds(1)))); + assertEquals(true, test.isConnected(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1)))); // completely after - assertEquals(test.isConnected(Interval.of(NOW2, NOW2.plusSeconds(1))), true); - assertEquals(test.isConnected(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2))), false); + assertEquals(true, test.isConnected(Interval.of(NOW2, NOW2.plusSeconds(1)))); + assertEquals(false, test.isConnected(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2)))); } + @Test public void test_isConnected_Interval_empty() { Interval test = Interval.of(NOW1, NOW1); // completely before - assertEquals(test.isConnected(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.isConnected(Interval.of(NOW1.minusSeconds(1), NOW1)), true); + assertEquals(false, test.isConnected(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(true, test.isConnected(Interval.of(NOW1.minusSeconds(1), NOW1))); // equal - assertEquals(test.isConnected(Interval.of(NOW1, NOW1)), true); + assertEquals(true, test.isConnected(Interval.of(NOW1, NOW1))); // completely after - assertEquals(test.isConnected(Interval.of(NOW1, NOW1.plusSeconds(1))), true); - assertEquals(test.isConnected(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2))), false); + assertEquals(true, test.isConnected(Interval.of(NOW1, NOW1.plusSeconds(1)))); + assertEquals(false, test.isConnected(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2)))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_isConnected_Interval_null() { Interval base = Interval.of(NOW1, NOW2); - base.isConnected((Interval) null); + assertThrows(NullPointerException.class, () -> base.isConnected((Interval) null)); } //----------------------------------------------------------------------- + @Test public void test_overlaps_Interval() { Interval test = Interval.of(NOW1, NOW2); // completely before - assertEquals(test.overlaps(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.overlaps(Interval.of(NOW1.minusSeconds(1), NOW1)), false); + assertEquals(false, test.overlaps(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(false, test.overlaps(Interval.of(NOW1.minusSeconds(1), NOW1))); // partly before - assertEquals(test.overlaps(Interval.of(NOW1.minusSeconds(1), NOW2)), true); - assertEquals(test.overlaps(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1))), true); + assertEquals(true, test.overlaps(Interval.of(NOW1.minusSeconds(1), NOW2))); + assertEquals(true, test.overlaps(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1)))); // contained - assertEquals(test.overlaps(Interval.of(NOW1, NOW2.minusSeconds(1))), true); - assertEquals(test.overlaps(Interval.of(NOW1, NOW2)), true); - assertEquals(test.overlaps(Interval.of(NOW1.plusSeconds(1), NOW2)), true); + assertEquals(true, test.overlaps(Interval.of(NOW1, NOW2.minusSeconds(1)))); + assertEquals(true, test.overlaps(Interval.of(NOW1, NOW2))); + assertEquals(true, test.overlaps(Interval.of(NOW1.plusSeconds(1), NOW2))); // partly after - assertEquals(test.overlaps(Interval.of(NOW1, NOW2.plusSeconds(1))), true); - assertEquals(test.overlaps(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1))), true); + assertEquals(true, test.overlaps(Interval.of(NOW1, NOW2.plusSeconds(1)))); + assertEquals(true, test.overlaps(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1)))); // completely after - assertEquals(test.overlaps(Interval.of(NOW2, NOW2.plusSeconds(1))), false); - assertEquals(test.overlaps(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2))), false); + assertEquals(false, test.overlaps(Interval.of(NOW2, NOW2.plusSeconds(1)))); + assertEquals(false, test.overlaps(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2)))); } + @Test public void test_overlaps_Interval_empty() { Interval test = Interval.of(NOW1, NOW1); // completely before - assertEquals(test.overlaps(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.overlaps(Interval.of(NOW1.minusSeconds(1), NOW1)), false); + assertEquals(false, test.overlaps(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(false, test.overlaps(Interval.of(NOW1.minusSeconds(1), NOW1))); // equal - assertEquals(test.overlaps(Interval.of(NOW1, NOW1)), true); + assertEquals(true, test.overlaps(Interval.of(NOW1, NOW1))); // completely after - assertEquals(test.overlaps(Interval.of(NOW1, NOW1.plusSeconds(1))), false); - assertEquals(test.overlaps(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2))), false); + assertEquals(false, test.overlaps(Interval.of(NOW1, NOW1.plusSeconds(1)))); + assertEquals(false, test.overlaps(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2)))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_overlaps_Interval_null() { Interval base = Interval.of(NOW1, NOW2); - base.overlaps((Interval) null); + assertThrows(NullPointerException.class, () -> base.overlaps((Interval) null)); } //----------------------------------------------------------------------- - @DataProvider(name = "intersection") - Object[][] data_intersection() { + public static Object[][] data_intersection() { return new Object[][] { // adjacent { NOW1, NOW2, NOW2, NOW4, NOW2, NOW2 }, @@ -456,7 +580,8 @@ Object[][] data_intersection() { }; } - @Test(dataProvider = "intersection") + @ParameterizedTest + @MethodSource("data_intersection") public void test_intersection( Instant start1, Instant end1, Instant start2, Instant end2, Instant expStart, Instant expEnd) { @@ -464,10 +589,11 @@ public void test_intersection( Interval test2 = Interval.of(start2, end2); Interval expected = Interval.of(expStart, expEnd); assertTrue(test1.isConnected(test2)); - assertEquals(test1.intersection(test2), expected); + assertEquals(expected, test1.intersection(test2)); } - @Test(dataProvider = "intersection") + @ParameterizedTest + @MethodSource("data_intersection") public void test_intersection_reverse( Instant start1, Instant end1, Instant start2, Instant end2, Instant expStart, Instant expEnd) { @@ -475,25 +601,25 @@ public void test_intersection_reverse( Interval test2 = Interval.of(start2, end2); Interval expected = Interval.of(expStart, expEnd); assertTrue(test2.isConnected(test1)); - assertEquals(test2.intersection(test1), expected); + assertEquals(expected, test2.intersection(test1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_intersectionBad() { Interval test1 = Interval.of(NOW1, NOW2); Interval test2 = Interval.of(NOW3, NOW4); - assertEquals(test1.isConnected(test2), false); - test1.intersection(test2); + assertEquals(false, test1.isConnected(test2)); + assertThrows(DateTimeException.class, () -> test1.intersection(test2)); } + @Test public void test_intersection_same() { Interval test = Interval.of(NOW2, NOW4); - assertEquals(test.intersection(test), test); + assertEquals(test, test.intersection(test)); } //----------------------------------------------------------------------- - @DataProvider(name = "union") - Object[][] data_union() { + public static Object[][] data_union() { return new Object[][] { // adjacent { NOW1, NOW2, NOW2, NOW4, NOW1, NOW4 }, @@ -508,7 +634,8 @@ Object[][] data_union() { }; } - @Test(dataProvider = "union") + @ParameterizedTest + @MethodSource("data_union") public void test_unionAndSpan( Instant start1, Instant end1, Instant start2, Instant end2, Instant expStart, Instant expEnd) { @@ -516,11 +643,12 @@ public void test_unionAndSpan( Interval test2 = Interval.of(start2, end2); Interval expected = Interval.of(expStart, expEnd); assertTrue(test1.isConnected(test2)); - assertEquals(test1.union(test2), expected); - assertEquals(test1.span(test2), expected); + assertEquals(expected, test1.union(test2)); + assertEquals(expected, test1.span(test2)); } - @Test(dataProvider = "union") + @ParameterizedTest + @MethodSource("data_union") public void test_unionAndSpan_reverse( Instant start1, Instant end1, Instant start2, Instant end2, Instant expStart, Instant expEnd) { @@ -528,167 +656,281 @@ public void test_unionAndSpan_reverse( Interval test2 = Interval.of(start2, end2); Interval expected = Interval.of(expStart, expEnd); assertTrue(test2.isConnected(test1)); - assertEquals(test2.union(test1), expected); - assertEquals(test2.span(test1), expected); + assertEquals(expected, test2.union(test1)); + assertEquals(expected, test2.span(test1)); } - @Test(dataProvider = "union") + @ParameterizedTest + @MethodSource("data_union") public void test_span_enclosesInputs( Instant start1, Instant end1, Instant start2, Instant end2, Instant expStart, Instant expEnd) { Interval test1 = Interval.of(start1, end1); Interval test2 = Interval.of(start2, end2); Interval expected = Interval.of(expStart, expEnd); - assertEquals(expected.encloses(test1), true); - assertEquals(expected.encloses(test2), true); + assertEquals(true, expected.encloses(test1)); + assertEquals(true, expected.encloses(test2)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_union_disconnected() { Interval test1 = Interval.of(NOW1, NOW2); Interval test2 = Interval.of(NOW3, NOW4); assertFalse(test1.isConnected(test2)); - test1.union(test2); + assertThrows(DateTimeException.class, () -> test1.union(test2)); } + @Test public void test_span_disconnected() { Interval test1 = Interval.of(NOW1, NOW2); Interval test2 = Interval.of(NOW3, NOW4); assertFalse(test1.isConnected(test2)); - assertEquals(test1.span(test2), Interval.of(NOW1, NOW4)); + assertEquals(Interval.of(NOW1, NOW4), test1.span(test2)); } + @Test public void test_unionAndSpan_same() { Interval test = Interval.of(NOW2, NOW4); - assertEquals(test.union(test), test); - assertEquals(test.span(test), test); + assertEquals(test, test.union(test)); + assertEquals(test, test.span(test)); + } + + //----------------------------------------------------------------------- + public static Object[][] data_starts() { + return new Object[][] { + // normal + {Interval.of(NOW12, NOW14), NOW11, false, false, true, true}, + {Interval.of(NOW12, NOW14), NOW12, false, true, false, true}, + {Interval.of(NOW12, NOW14), NOW13, true, true, false, false}, + {Interval.of(NOW12, NOW14), NOW14, true, true, false, false}, + {Interval.of(NOW12, NOW14), NOW15, true, true, false, false}, + // empty interval + {Interval.of(NOW12, NOW12), NOW11, false, false, true, true}, + {Interval.of(NOW12, NOW12), NOW12, false, true, false, true}, + {Interval.of(NOW12, NOW12), NOW13, true, true, false, false}, + // unbounded start + {Interval.of(Instant.MIN, NOW12), Instant.MIN, false, true, false, true}, + {Interval.of(Instant.MIN, NOW12), NOW11, true, true, false, false}, + {Interval.of(Instant.MIN, NOW12), NOW12, true, true, false, false}, + {Interval.of(Instant.MIN, NOW12), NOW13, true, true, false, false}, + {Interval.of(Instant.MIN, NOW12), Instant.MAX, true, true, false, false}, + // unbounded end + {Interval.of(NOW12, Instant.MAX), Instant.MIN, false, false, true, true}, + {Interval.of(NOW12, Instant.MAX), NOW11, false, false, true, true}, + {Interval.of(NOW12, Instant.MAX), NOW12, false, true, false, true}, + {Interval.of(NOW12, Instant.MAX), NOW13, true, true, false, false}, + {Interval.of(NOW12, Instant.MAX), Instant.MAX, true, true, false, false}, + }; + } + + @ParameterizedTest + @MethodSource("data_starts") + public void test_starts_Instant( + Interval test, + Instant instant, + boolean expectedStartsBefore, + boolean expectedStartsAtOrBefore, + boolean expectedStartsAfter, + boolean expectedStartsAtOrAfter) { + + assertEquals(expectedStartsBefore, test.startsBefore(instant)); + assertEquals(expectedStartsAtOrBefore, test.startsAtOrBefore(instant)); + assertEquals(expectedStartsAfter, test.startsAfter(instant)); + assertEquals(expectedStartsAtOrAfter, test.startsAtOrAfter(instant)); + } + + @Test + public void test_starts_Instant_null() { + Interval base = Interval.of(NOW12, NOW14); + assertThrows(NullPointerException.class, () -> base.startsBefore((Instant) null)); + assertThrows(NullPointerException.class, () -> base.startsAtOrBefore((Instant) null)); + assertThrows(NullPointerException.class, () -> base.startsAfter((Instant) null)); + assertThrows(NullPointerException.class, () -> base.startsAtOrAfter((Instant) null)); + } + + //----------------------------------------------------------------------- + public static Object[][] data_ends() { + return new Object[][] { + // normal + {Interval.of(NOW12, NOW14), NOW11, false, false, true, true}, + {Interval.of(NOW12, NOW14), NOW12, false, false, true, true}, + {Interval.of(NOW12, NOW14), NOW13, false, false, true, true}, + {Interval.of(NOW12, NOW14), NOW14, false, true, false, true}, + {Interval.of(NOW12, NOW14), NOW15, true, true, false, false}, + // empty interval + {Interval.of(NOW12, NOW12), NOW11, false, false, true, true}, + {Interval.of(NOW12, NOW12), NOW12, false, true, false, true}, + {Interval.of(NOW12, NOW12), NOW13, true, true, false, false}, + // unbounded start + {Interval.of(Instant.MIN, NOW12), Instant.MIN, false, false, true, true}, + {Interval.of(Instant.MIN, NOW12), NOW11, false, false, true, true}, + {Interval.of(Instant.MIN, NOW12), NOW12, false, true, false, true}, + {Interval.of(Instant.MIN, NOW12), NOW13, true, true, false, false}, + {Interval.of(Instant.MIN, NOW12), Instant.MAX, true, true, false, false}, + // unbounded end + {Interval.of(NOW12, Instant.MAX), Instant.MIN, false, false, true, true}, + {Interval.of(NOW12, Instant.MAX), NOW11, false, false, true, true}, + {Interval.of(NOW12, Instant.MAX), NOW12, false, false, true, true}, + {Interval.of(NOW12, Instant.MAX), NOW13, false, false, true, true}, + {Interval.of(NOW12, Instant.MAX), Instant.MAX, false, false, true, true}, + }; + } + + @ParameterizedTest + @MethodSource("data_ends") + public void test_ends_Instant( + Interval test, + Instant instant, + boolean expectedEndsBefore, + boolean expectedEndsAtOrBefore, + boolean expectedEndsAfter, + boolean expectedEndsAtOrAfter) { + + assertEquals(expectedEndsBefore, test.endsBefore(instant)); + assertEquals(expectedEndsAtOrBefore, test.endsAtOrBefore(instant)); + assertEquals(expectedEndsAfter, test.endsAfter(instant)); + assertEquals(expectedEndsAtOrAfter, test.endsAtOrAfter(instant)); + } + + @Test + public void test_ends_Instant_null() { + Interval base = Interval.of(NOW12, NOW14); + assertThrows(NullPointerException.class, () -> base.endsBefore((Instant) null)); + assertThrows(NullPointerException.class, () -> base.endsAtOrBefore((Instant) null)); + assertThrows(NullPointerException.class, () -> base.endsAfter((Instant) null)); + assertThrows(NullPointerException.class, () -> base.endsAtOrAfter((Instant) null)); } //----------------------------------------------------------------------- + @Test public void test_isAfter_Instant() { Interval test = Interval.of(NOW1, NOW2); - assertEquals(test.isAfter(NOW1.minusSeconds(2)), true); - assertEquals(test.isAfter(NOW1.minusSeconds(1)), true); - assertEquals(test.isAfter(NOW1), false); - assertEquals(test.isAfter(NOW2), false); - assertEquals(test.isAfter(NOW2.plusSeconds(1)), false); + assertEquals(true, test.isAfter(NOW1.minusSeconds(2))); + assertEquals(true, test.isAfter(NOW1.minusSeconds(1))); + assertEquals(false, test.isAfter(NOW1)); + assertEquals(false, test.isAfter(NOW2)); + assertEquals(false, test.isAfter(NOW2.plusSeconds(1))); } + @Test public void test_isAfter_Instant_empty() { Interval test = Interval.of(NOW1, NOW1); - assertEquals(test.isAfter(NOW1.minusSeconds(2)), true); - assertEquals(test.isAfter(NOW1.minusSeconds(1)), true); - assertEquals(test.isAfter(NOW1), false); - assertEquals(test.isAfter(NOW1.plusSeconds(1)), false); + assertEquals(true, test.isAfter(NOW1.minusSeconds(2))); + assertEquals(true, test.isAfter(NOW1.minusSeconds(1))); + assertEquals(false, test.isAfter(NOW1)); + assertEquals(false, test.isAfter(NOW1.plusSeconds(1))); } //----------------------------------------------------------------------- + @Test public void test_isBefore_Instant() { Interval test = Interval.of(NOW1, NOW2); - assertEquals(test.isBefore(NOW1.minusSeconds(1)), false); - assertEquals(test.isBefore(NOW1), false); - assertEquals(test.isBefore(NOW2), true); - assertEquals(test.isBefore(NOW2.plusSeconds(1)), true); + assertEquals(false, test.isBefore(NOW1.minusSeconds(1))); + assertEquals(false, test.isBefore(NOW1)); + assertEquals(true, test.isBefore(NOW2)); + assertEquals(true, test.isBefore(NOW2.plusSeconds(1))); } + @Test public void test_isBefore_Instant_empty() { Interval test = Interval.of(NOW1, NOW1); - assertEquals(test.isBefore(NOW1.minusSeconds(1)), false); - assertEquals(test.isBefore(NOW1), false); - assertEquals(test.isBefore(NOW1.plusSeconds(1)), true); + assertEquals(false, test.isBefore(NOW1.minusSeconds(1))); + assertEquals(false, test.isBefore(NOW1)); + assertEquals(true, test.isBefore(NOW1.plusSeconds(1))); } //----------------------------------------------------------------------- + @Test public void test_isAfter_Interval() { Interval test = Interval.of(NOW1, NOW2); // completely before - assertEquals(test.isAfter(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), true); - assertEquals(test.isAfter(Interval.of(NOW1.minusSeconds(1), NOW1)), true); + assertEquals(true, test.isAfter(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(true, test.isAfter(Interval.of(NOW1.minusSeconds(1), NOW1))); // partly before - assertEquals(test.isAfter(Interval.of(NOW1.minusSeconds(1), NOW2)), false); - assertEquals(test.isAfter(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1))), false); + assertEquals(false, test.isAfter(Interval.of(NOW1.minusSeconds(1), NOW2))); + assertEquals(false, test.isAfter(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1)))); // contained - assertEquals(test.isAfter(Interval.of(NOW1, NOW2.minusSeconds(1))), false); - assertEquals(test.isAfter(Interval.of(NOW1, NOW2)), false); - assertEquals(test.isAfter(Interval.of(NOW1.plusSeconds(1), NOW2)), false); + assertEquals(false, test.isAfter(Interval.of(NOW1, NOW2.minusSeconds(1)))); + assertEquals(false, test.isAfter(Interval.of(NOW1, NOW2))); + assertEquals(false, test.isAfter(Interval.of(NOW1.plusSeconds(1), NOW2))); // partly after - assertEquals(test.isAfter(Interval.of(NOW1, NOW2.plusSeconds(1))), false); - assertEquals(test.isAfter(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1))), false); + assertEquals(false, test.isAfter(Interval.of(NOW1, NOW2.plusSeconds(1)))); + assertEquals(false, test.isAfter(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1)))); // completely after - assertEquals(test.isAfter(Interval.of(NOW2, NOW2.plusSeconds(1))), false); - assertEquals(test.isAfter(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2))), false); + assertEquals(false, test.isAfter(Interval.of(NOW2, NOW2.plusSeconds(1)))); + assertEquals(false, test.isAfter(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2)))); } + @Test public void test_isAfter_Interval_empty() { Interval test = Interval.of(NOW1, NOW1); // completely before - assertEquals(test.isAfter(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), true); - assertEquals(test.isAfter(Interval.of(NOW1.minusSeconds(1), NOW1)), true); + assertEquals(true, test.isAfter(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(true, test.isAfter(Interval.of(NOW1.minusSeconds(1), NOW1))); // equal - assertEquals(test.isAfter(Interval.of(NOW1, NOW1)), false); + assertEquals(false, test.isAfter(Interval.of(NOW1, NOW1))); // completely after - assertEquals(test.isAfter(Interval.of(NOW1, NOW1.plusSeconds(1))), false); - assertEquals(test.isAfter(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2))), false); + assertEquals(false, test.isAfter(Interval.of(NOW1, NOW1.plusSeconds(1)))); + assertEquals(false, test.isAfter(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2)))); } //----------------------------------------------------------------------- + @Test public void test_isBefore_Interval() { Interval test = Interval.of(NOW1, NOW2); // completely before - assertEquals(test.isBefore(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.isBefore(Interval.of(NOW1.minusSeconds(1), NOW1)), false); + assertEquals(false, test.isBefore(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(false, test.isBefore(Interval.of(NOW1.minusSeconds(1), NOW1))); // partly before - assertEquals(test.isBefore(Interval.of(NOW1.minusSeconds(1), NOW2)), false); - assertEquals(test.isBefore(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1))), false); + assertEquals(false, test.isBefore(Interval.of(NOW1.minusSeconds(1), NOW2))); + assertEquals(false, test.isBefore(Interval.of(NOW1.minusSeconds(1), NOW2.minusSeconds(1)))); // contained - assertEquals(test.isBefore(Interval.of(NOW1, NOW2.minusSeconds(1))), false); - assertEquals(test.isBefore(Interval.of(NOW1, NOW2)), false); - assertEquals(test.isBefore(Interval.of(NOW1.plusSeconds(1), NOW2)), false); + assertEquals(false, test.isBefore(Interval.of(NOW1, NOW2.minusSeconds(1)))); + assertEquals(false, test.isBefore(Interval.of(NOW1, NOW2))); + assertEquals(false, test.isBefore(Interval.of(NOW1.plusSeconds(1), NOW2))); // partly after - assertEquals(test.isBefore(Interval.of(NOW1, NOW2.plusSeconds(1))), false); - assertEquals(test.isBefore(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1))), false); + assertEquals(false, test.isBefore(Interval.of(NOW1, NOW2.plusSeconds(1)))); + assertEquals(false, test.isBefore(Interval.of(NOW1.plusSeconds(1), NOW2.plusSeconds(1)))); // completely after - assertEquals(test.isBefore(Interval.of(NOW2, NOW2.plusSeconds(1))), true); - assertEquals(test.isBefore(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2))), true); + assertEquals(true, test.isBefore(Interval.of(NOW2, NOW2.plusSeconds(1)))); + assertEquals(true, test.isBefore(Interval.of(NOW2.plusSeconds(1), NOW2.plusSeconds(2)))); } + @Test public void test_isBefore_Interval_empty() { Interval test = Interval.of(NOW1, NOW1); // completely before - assertEquals(test.isBefore(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1))), false); - assertEquals(test.isBefore(Interval.of(NOW1.minusSeconds(1), NOW1)), false); + assertEquals(false, test.isBefore(Interval.of(NOW1.minusSeconds(2), NOW1.minusSeconds(1)))); + assertEquals(false, test.isBefore(Interval.of(NOW1.minusSeconds(1), NOW1))); // equal - assertEquals(test.isBefore(Interval.of(NOW1, NOW1)), false); + assertEquals(false, test.isBefore(Interval.of(NOW1, NOW1))); // completely after - assertEquals(test.isBefore(Interval.of(NOW1, NOW1.plusSeconds(1))), true); - assertEquals(test.isBefore(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2))), true); + assertEquals(true, test.isBefore(Interval.of(NOW1, NOW1.plusSeconds(1)))); + assertEquals(true, test.isBefore(Interval.of(NOW1.plusSeconds(1), NOW1.plusSeconds(2)))); } //----------------------------------------------------------------------- + @Test public void test_toDuration() { Interval test = Interval.of(NOW1, NOW2); - assertEquals(test.toDuration(), Duration.between(NOW1, NOW2)); + assertEquals(Duration.between(NOW1, NOW2), test.toDuration()); } //----------------------------------------------------------------------- - public void test_equals() { - Interval a = Interval.of(NOW1, NOW2); - Interval a2 = Interval.of(NOW1, NOW2); - Interval b = Interval.of(NOW1, NOW3); - Interval c = Interval.of(NOW2, NOW2); - assertEquals(a.equals(a), true); - assertEquals(a.equals(a2), true); - assertEquals(a.equals(b), false); - assertEquals(a.equals(c), false); - assertEquals(a.equals(null), false); - assertEquals(a.equals(""), false); - assertEquals(a.hashCode() == a2.hashCode(), true); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Interval.of(NOW1, NOW2), Interval.of(NOW1, NOW2)) + .addEqualityGroup(Interval.of(NOW1, NOW3), Interval.of(NOW1, NOW3)) + .addEqualityGroup(Interval.of(NOW2, NOW2), Interval.of(NOW2, NOW2)) + .testEquals(); } //----------------------------------------------------------------------- + @Test public void test_toString() { Interval test = Interval.of(NOW1, NOW2); - assertEquals(test.toString(), NOW1 + "/" + NOW2); + assertEquals(NOW1 + "/" + NOW2, test.toString()); } } diff --git a/src/test/java/org/threeten/extra/TestLocalDateRange.java b/src/test/java/org/threeten/extra/TestLocalDateRange.java index 1b836b12..865f3faf 100644 --- a/src/test/java/org/threeten/extra/TestLocalDateRange.java +++ b/src/test/java/org/threeten/extra/TestLocalDateRange.java @@ -31,9 +31,10 @@ */ package org.threeten.extra; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -46,21 +47,28 @@ import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import org.junit.jupiter.params.provider.MethodSource; import com.google.common.collect.Range; +import com.google.common.testing.EqualsTester; /** * Test date range. */ -@Test public class TestLocalDateRange { + private static final LocalDate MINP1 = LocalDate.MIN.plusDays(1); + private static final LocalDate MINP2 = LocalDate.MIN.plusDays(2); + private static final LocalDate MINP3 = LocalDate.MIN.plusDays(3); + private static final LocalDate MAXM1 = LocalDate.MAX.minusDays(1); + private static final LocalDate MAXM2 = LocalDate.MAX.minusDays(2); private static final LocalDate DATE_2012_07_01 = LocalDate.of(2012, 7, 1); private static final LocalDate DATE_2012_07_27 = LocalDate.of(2012, 7, 27); private static final LocalDate DATE_2012_07_28 = LocalDate.of(2012, 7, 28); @@ -71,335 +79,631 @@ public class TestLocalDateRange { private static final LocalDate DATE_2012_08_31 = LocalDate.of(2012, 8, 31); //----------------------------------------------------------------------- + @Test public void test_ALL() { LocalDateRange test = LocalDateRange.ALL; - assertEquals(test.getStart(), LocalDate.MIN); - assertEquals(test.getEndInclusive(), LocalDate.MAX); - assertEquals(test.getEnd(), LocalDate.MAX); - assertEquals(test.isEmpty(), false); - assertEquals(test.isUnboundedStart(), true); - assertEquals(test.isUnboundedEnd(), true); - assertEquals(test.toString(), "-999999999-01-01/+999999999-12-31"); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(LocalDate.MAX, test.getEndInclusive()); + assertEquals(LocalDate.MAX, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(true, test.isUnboundedEnd()); + assertEquals("-999999999-01-01/+999999999-12-31", test.toString()); } //----------------------------------------------------------------------- + @Test public void test_of() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.getStart(), DATE_2012_07_28); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); - assertEquals(test.isEmpty(), false); - assertEquals(test.isUnboundedStart(), false); - assertEquals(test.isUnboundedEnd(), false); - assertEquals(test.toString(), "2012-07-28/2012-07-31"); + assertEquals(DATE_2012_07_28, test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(3, test.lengthInDays()); + assertEquals("2012-07-28/2012-07-31", test.toString()); } + @Test public void test_of_MIN() { LocalDateRange test = LocalDateRange.of(LocalDate.MIN, DATE_2012_07_31); - assertEquals(test.getStart(), LocalDate.MIN); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); - assertEquals(test.isEmpty(), false); - assertEquals(test.isUnboundedStart(), true); - assertEquals(test.isUnboundedEnd(), false); - assertEquals(test.toString(), "-999999999-01-01/2012-07-31"); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("-999999999-01-01/2012-07-31", test.toString()); } + @Test public void test_of_MAX() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, LocalDate.MAX); - assertEquals(test.getStart(), DATE_2012_07_28); - assertEquals(test.getEndInclusive(), LocalDate.MAX); - assertEquals(test.getEnd(), LocalDate.MAX); - assertEquals(test.isEmpty(), false); - assertEquals(test.isUnboundedStart(), false); - assertEquals(test.isUnboundedEnd(), true); - assertEquals(test.toString(), "2012-07-28/+999999999-12-31"); + assertEquals(DATE_2012_07_28, test.getStart()); + assertEquals(LocalDate.MAX, test.getEndInclusive()); + assertEquals(LocalDate.MAX, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(true, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("2012-07-28/+999999999-12-31", test.toString()); } + @Test public void test_of_MIN_MAX() { LocalDateRange test = LocalDateRange.of(LocalDate.MIN, LocalDate.MAX); - assertEquals(test.getStart(), LocalDate.MIN); - assertEquals(test.getEndInclusive(), LocalDate.MAX); - assertEquals(test.getEnd(), LocalDate.MAX); - assertEquals(test.isEmpty(), false); - assertEquals(test.isUnboundedStart(), true); - assertEquals(test.isUnboundedEnd(), true); - assertEquals(test.toString(), "-999999999-01-01/+999999999-12-31"); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(LocalDate.MAX, test.getEndInclusive()); + assertEquals(LocalDate.MAX, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(true, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("-999999999-01-01/+999999999-12-31", test.toString()); } + @Test public void test_of_MIN_MIN() { - LocalDateRange test = LocalDateRange.of(LocalDate.MIN, LocalDate.MIN); - assertEquals(test.getStart(), LocalDate.MIN); - assertEquals(test.getEndInclusive(), LocalDate.MIN); - assertEquals(test.getEnd(), LocalDate.MIN); - assertEquals(test.isEmpty(), true); - assertEquals(test.isUnboundedStart(), true); - assertEquals(test.isUnboundedEnd(), false); - assertEquals(test.toString(), "-999999999-01-01/-999999999-01-01"); + assertThrows(DateTimeException.class, () -> LocalDateRange.of(LocalDate.MIN, LocalDate.MIN)); } + @Test + public void test_of_MIN_MINP1() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(LocalDate.MIN, MINP1)); + } + + @Test + public void test_of_MINP1_MINP1() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(MINP1, MINP1)); + } + + @Test + public void test_of_MIN_MINP2() { + LocalDateRange test = LocalDateRange.of(LocalDate.MIN, MINP2); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(MINP1, test.getEndInclusive()); + assertEquals(MINP2, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("-999999999-01-01/-999999999-01-03", test.toString()); + } + + @Test + public void test_of_MINP1_MINP2() { + LocalDateRange test = LocalDateRange.of(MINP1, MINP2); + assertEquals(MINP1, test.getStart()); + assertEquals(MINP1, test.getEndInclusive()); + assertEquals(MINP2, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(1, test.lengthInDays()); + assertEquals("-999999999-01-02/-999999999-01-03", test.toString()); + } + + @Test + public void test_of_MINP2_MINP2() { + LocalDateRange test = LocalDateRange.of(MINP2, MINP2); + assertEquals(MINP2, test.getStart()); + assertEquals(MINP1, test.getEndInclusive()); + assertEquals(MINP2, test.getEnd()); + assertEquals(true, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(0, test.lengthInDays()); + assertEquals("-999999999-01-03/-999999999-01-03", test.toString()); + } + + @Test + public void test_of_MAX_MAX() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(LocalDate.MAX, LocalDate.MAX)); + } + + @Test + public void test_of_MAXM1_MAX() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(MAXM1, LocalDate.MAX)); + } + + @Test + public void test_of_MAXM1_MAXM1() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(MAXM1, MAXM1)); + } + + @Test public void test_of_empty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_30); - assertEquals(test.getStart(), DATE_2012_07_30); - assertEquals(test.getEndInclusive(), DATE_2012_07_29); - assertEquals(test.getEnd(), DATE_2012_07_30); - assertEquals(test.isEmpty(), true); - assertEquals(test.isUnboundedStart(), false); - assertEquals(test.isUnboundedEnd(), false); - assertEquals(test.toString(), "2012-07-30/2012-07-30"); + assertEquals(DATE_2012_07_30, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEndInclusive()); + assertEquals(DATE_2012_07_30, test.getEnd()); + assertEquals(true, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(0, test.lengthInDays()); + assertEquals("2012-07-30/2012-07-30", test.toString()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_badOrder() { - LocalDateRange.of(DATE_2012_07_31, DATE_2012_07_30); + assertThrows(DateTimeException.class, () -> LocalDateRange.of(DATE_2012_07_31, DATE_2012_07_30)); } //----------------------------------------------------------------------- + @Test public void test_ofClosed() { LocalDateRange test = LocalDateRange.ofClosed(DATE_2012_07_28, DATE_2012_07_30); - assertEquals(test.getStart(), DATE_2012_07_28); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); - assertEquals(test.isUnboundedStart(), false); - assertEquals(test.isUnboundedEnd(), false); - assertEquals(test.toString(), "2012-07-28/2012-07-31"); + assertEquals(DATE_2012_07_28, test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(3, test.lengthInDays()); + assertEquals("2012-07-28/2012-07-31", test.toString()); } + @Test public void test_ofClosed_MIN() { LocalDateRange test = LocalDateRange.ofClosed(LocalDate.MIN, DATE_2012_07_30); - assertEquals(test.getStart(), LocalDate.MIN); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); - assertEquals(test.isUnboundedStart(), true); - assertEquals(test.isUnboundedEnd(), false); - assertEquals(test.toString(), "-999999999-01-01/2012-07-31"); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("-999999999-01-01/2012-07-31", test.toString()); } + @Test public void test_ofClosed_MAX() { LocalDateRange test = LocalDateRange.ofClosed(DATE_2012_07_28, LocalDate.MAX); - assertEquals(test.getStart(), DATE_2012_07_28); - assertEquals(test.getEndInclusive(), LocalDate.MAX); - assertEquals(test.getEnd(), LocalDate.MAX); - assertEquals(test.isUnboundedStart(), false); - assertEquals(test.isUnboundedEnd(), true); - assertEquals(test.toString(), "2012-07-28/+999999999-12-31"); + assertEquals(DATE_2012_07_28, test.getStart()); + assertEquals(LocalDate.MAX, test.getEndInclusive()); + assertEquals(LocalDate.MAX, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(true, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("2012-07-28/+999999999-12-31", test.toString()); } + @Test public void test_ofClosed_MIN_MAX() { LocalDateRange test = LocalDateRange.ofClosed(LocalDate.MIN, LocalDate.MAX); - assertEquals(test.getStart(), LocalDate.MIN); - assertEquals(test.getEndInclusive(), LocalDate.MAX); - assertEquals(test.getEnd(), LocalDate.MAX); - assertEquals(test.isUnboundedStart(), true); - assertEquals(test.isUnboundedEnd(), true); - assertEquals(test.toString(), "-999999999-01-01/+999999999-12-31"); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(LocalDate.MAX, test.getEndInclusive()); + assertEquals(LocalDate.MAX, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(true, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("-999999999-01-01/+999999999-12-31", test.toString()); + } + + @Test + public void test_ofClosed_MIN_MIN() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofClosed(LocalDate.MIN, LocalDate.MIN)); + } + + @Test + public void test_ofClosed_MIN_MINP1() { + LocalDateRange test = LocalDateRange.ofClosed(LocalDate.MIN, MINP1); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(MINP1, test.getEndInclusive()); + assertEquals(MINP2, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("-999999999-01-01/-999999999-01-03", test.toString()); + } + + @Test + public void test_ofClosed_MINP1_MINP1() { + LocalDateRange test = LocalDateRange.ofClosed(MINP1, MINP1); + assertEquals(MINP1, test.getStart()); + assertEquals(MINP1, test.getEndInclusive()); + assertEquals(MINP2, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(1, test.lengthInDays()); + assertEquals("-999999999-01-02/-999999999-01-03", test.toString()); + } + + @Test + public void test_ofClosed_MIN_MINP2() { + LocalDateRange test = LocalDateRange.ofClosed(LocalDate.MIN, MINP2); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(MINP2, test.getEndInclusive()); + assertEquals(MINP3, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(Integer.MAX_VALUE, test.lengthInDays()); + assertEquals("-999999999-01-01/-999999999-01-04", test.toString()); + } + + @Test + public void test_ofClosed_MINP1_MINP2() { + LocalDateRange test = LocalDateRange.ofClosed(MINP1, MINP2); + assertEquals(MINP1, test.getStart()); + assertEquals(MINP2, test.getEndInclusive()); + assertEquals(MINP3, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(2, test.lengthInDays()); + assertEquals("-999999999-01-02/-999999999-01-04", test.toString()); + } + + @Test + public void test_ofClosed_MINP2_MINP2() { + LocalDateRange test = LocalDateRange.ofClosed(MINP2, MINP2); + assertEquals(MINP2, test.getStart()); + assertEquals(MINP2, test.getEndInclusive()); + assertEquals(MINP3, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals(1, test.lengthInDays()); + assertEquals("-999999999-01-03/-999999999-01-04", test.toString()); + } + + @Test + public void test_ofClosed_MAX_MAX() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofClosed(LocalDate.MAX, LocalDate.MAX)); + } + + @Test + public void test_ofClosed_MAXM1_MAX() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofClosed(MAXM1, LocalDate.MAX)); + } + + @Test + public void test_ofClosed_MAXM1_MAXM1() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofClosed(MAXM1, MAXM1)); + } + + @Test + public void test_ofClosed_badOrder() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofClosed(DATE_2012_07_31, DATE_2012_07_30)); } - @Test(expectedExceptions = DateTimeException.class) - public void test_ofClosed_badOrder() { - LocalDateRange.ofClosed(DATE_2012_07_31, DATE_2012_07_30); + //----------------------------------------------------------------------- + @Test + public void test_ofEmpty() { + LocalDateRange test = LocalDateRange.ofEmpty(DATE_2012_07_30); + assertEquals(DATE_2012_07_30, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEndInclusive()); + assertEquals(DATE_2012_07_30, test.getEnd()); + assertEquals(true, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals("2012-07-30/2012-07-30", test.toString()); + } + + @Test + public void test_ofEmpty_MIN() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofEmpty(LocalDate.MIN)); + } + + @Test + public void test_ofEmpty_MINP1() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofEmpty(MINP1)); + } + + @Test + public void test_ofEmpty_MAX() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofEmpty(LocalDate.MAX)); + } + + @Test + public void test_ofEmpty_MAXM1() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofEmpty(MAXM1)); } //----------------------------------------------------------------------- + @Test + public void test_ofUnbounded() { + LocalDateRange test = LocalDateRange.ofUnbounded(); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(LocalDate.MAX, test.getEndInclusive()); + assertEquals(LocalDate.MAX, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(true, test.isUnboundedEnd()); + assertEquals("-999999999-01-01/+999999999-12-31", test.toString()); + } + + //----------------------------------------------------------------------- + @Test + public void test_ofUnboundedStart() { + LocalDateRange test = LocalDateRange.ofUnboundedStart(DATE_2012_07_30); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEndInclusive()); + assertEquals(DATE_2012_07_30, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(true, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals("-999999999-01-01/2012-07-30", test.toString()); + } + + @Test + public void test_ofUnboundedStart_MIN() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofUnboundedStart(LocalDate.MIN)); + } + + @Test + public void test_ofUnboundedStart_MINP1() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofUnboundedStart(MINP1)); + } + + //----------------------------------------------------------------------- + @Test + public void test_ofUnboundedEnd() { + LocalDateRange test = LocalDateRange.ofUnboundedEnd(DATE_2012_07_30); + assertEquals(DATE_2012_07_30, test.getStart()); + assertEquals(LocalDate.MAX, test.getEndInclusive()); + assertEquals(LocalDate.MAX, test.getEnd()); + assertEquals(false, test.isEmpty()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(true, test.isUnboundedEnd()); + assertEquals("2012-07-30/+999999999-12-31", test.toString()); + } + + @Test + public void test_ofUnboundedEnd_MAX() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofUnboundedEnd(LocalDate.MAX)); + } + + @Test + public void test_ofUnboundedEnd_MAXM1() { + assertThrows(DateTimeException.class, () -> LocalDateRange.ofUnboundedEnd(MAXM1)); + } + + //----------------------------------------------------------------------- + @Test public void test_of_period() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, Period.ofDays(3)); - assertEquals(test.getStart(), DATE_2012_07_28); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); - assertEquals(test.isUnboundedStart(), false); - assertEquals(test.isUnboundedEnd(), false); - assertEquals(test.toString(), "2012-07-28/2012-07-31"); + assertEquals(DATE_2012_07_28, test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); + assertEquals(false, test.isUnboundedStart()); + assertEquals(false, test.isUnboundedEnd()); + assertEquals("2012-07-28/2012-07-31", test.toString()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_period_negative() { - LocalDateRange.of(DATE_2012_07_31, Period.ofDays(-1)); + assertThrows(DateTimeException.class, () -> LocalDateRange.of(DATE_2012_07_31, Period.ofDays(-1))); + } + + @Test + public void test_of_period_atMIN() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(LocalDate.MIN, Period.ofDays(0))); + } + + @Test + public void test_of_period_atMAX() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(LocalDate.MAX, Period.ofDays(0))); + } + + @Test + public void test_of_period_atMAXM1_0D() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(MAXM1, Period.ofDays(0))); + } + + @Test + public void test_of_period_atMAXM1_1D() { + assertThrows(DateTimeException.class, () -> LocalDateRange.of(MAXM1, Period.ofDays(1))); } //----------------------------------------------------------------------- + @Test public void test_parse_CharSequence() { LocalDateRange test = LocalDateRange.parse(DATE_2012_07_27 + "/" + DATE_2012_07_29); - assertEquals(test.getStart(), DATE_2012_07_27); - assertEquals(test.getEnd(), DATE_2012_07_29); + assertEquals(DATE_2012_07_27, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEnd()); } + @Test public void test_parse_CharSequence_PeriodLocalDate() { LocalDateRange test = LocalDateRange.parse("P2D/" + DATE_2012_07_29); - assertEquals(test.getStart(), DATE_2012_07_27); - assertEquals(test.getEnd(), DATE_2012_07_29); + assertEquals(DATE_2012_07_27, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEnd()); } + @Test public void test_parse_CharSequence_PeriodLocalDate_case() { LocalDateRange test = LocalDateRange.parse("p2d/" + DATE_2012_07_29); - assertEquals(test.getStart(), DATE_2012_07_27); - assertEquals(test.getEnd(), DATE_2012_07_29); + assertEquals(DATE_2012_07_27, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEnd()); } + @Test public void test_parse_CharSequence_LocalDatePeriod() { LocalDateRange test = LocalDateRange.parse(DATE_2012_07_27 + "/P2D"); - assertEquals(test.getStart(), DATE_2012_07_27); - assertEquals(test.getEnd(), DATE_2012_07_29); + assertEquals(DATE_2012_07_27, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEnd()); } + @Test public void test_parse_CharSequence_LocalDatePeriod_case() { LocalDateRange test = LocalDateRange.parse(DATE_2012_07_27 + "/p2d"); - assertEquals(test.getStart(), DATE_2012_07_27); - assertEquals(test.getEnd(), DATE_2012_07_29); + assertEquals(DATE_2012_07_27, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEnd()); } + @Test public void test_parse_CharSequence_empty() { LocalDateRange test = LocalDateRange.parse(DATE_2012_07_27 + "/" + DATE_2012_07_27); - assertEquals(test.getStart(), DATE_2012_07_27); - assertEquals(test.getEnd(), DATE_2012_07_27); + assertEquals(DATE_2012_07_27, test.getStart()); + assertEquals(DATE_2012_07_27, test.getEnd()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_parse_CharSequence_badOrder() { - LocalDateRange.parse(DATE_2012_07_29 + "/" + DATE_2012_07_27); + assertThrows(DateTimeException.class, () -> LocalDateRange.parse(DATE_2012_07_29 + "/" + DATE_2012_07_27)); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_parse_CharSequence_badFormat() { - LocalDateRange.parse(DATE_2012_07_29 + "-" + DATE_2012_07_27); + assertThrows(DateTimeParseException.class, () -> LocalDateRange.parse(DATE_2012_07_29 + "-" + DATE_2012_07_27)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequence_null() { - LocalDateRange.parse(null); + assertThrows(NullPointerException.class, () -> LocalDateRange.parse(null)); } //----------------------------------------------------------------------- + @Test public void test_isSerializable() { assertTrue(Serializable.class.isAssignableFrom(LocalDateRange.class)); } + @Test public void test_serialization() throws Exception { - LocalDateRange original = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); + LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(original); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - LocalDateRange ser = (LocalDateRange) in.readObject(); - assertEquals(ser, original); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertEquals(test, ois.readObject()); + } } //----------------------------------------------------------------------- + @Test public void test_withStart() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); LocalDateRange test = base.withStart(DATE_2012_07_27); - assertEquals(test.getStart(), DATE_2012_07_27); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); + assertEquals(DATE_2012_07_27, test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); } + @Test public void test_withStart_adjuster() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); LocalDateRange test = base.withStart(date -> date.minus(1, ChronoUnit.WEEKS)); - assertEquals(test.getStart(), DATE_2012_07_28.minusWeeks(1)); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); + assertEquals(DATE_2012_07_28.minusWeeks(1), test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); } + @Test public void test_withStart_min() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); LocalDateRange test = base.withStart(LocalDate.MIN); - assertEquals(test.getStart(), LocalDate.MIN); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); + assertEquals(LocalDate.MIN, test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); } + @Test public void test_withStart_empty() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); LocalDateRange test = base.withStart(DATE_2012_07_31); - assertEquals(test.getStart(), DATE_2012_07_31); - assertEquals(test.getEndInclusive(), DATE_2012_07_30); - assertEquals(test.getEnd(), DATE_2012_07_31); + assertEquals(DATE_2012_07_31, test.getStart()); + assertEquals(DATE_2012_07_30, test.getEndInclusive()); + assertEquals(DATE_2012_07_31, test.getEnd()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withStart_invalid() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_30); - base.withStart(DATE_2012_07_31); + assertThrows(DateTimeException.class, () -> base.withStart(DATE_2012_07_31)); } //----------------------------------------------------------------------- + @Test public void test_withEnd() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); LocalDateRange test = base.withEnd(DATE_2012_07_30); - assertEquals(test.getStart(), DATE_2012_07_28); - assertEquals(test.getEndInclusive(), DATE_2012_07_29); - assertEquals(test.getEnd(), DATE_2012_07_30); + assertEquals(DATE_2012_07_28, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEndInclusive()); + assertEquals(DATE_2012_07_30, test.getEnd()); } + @Test public void test_withEnd_adjuster() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); LocalDateRange test = base.withEnd(date -> date.plus(1, ChronoUnit.WEEKS)); - assertEquals(test.getStart(), DATE_2012_07_28); - assertEquals(test.getEndInclusive(), DATE_2012_07_30.plusWeeks(1)); - assertEquals(test.getEnd(), DATE_2012_07_31.plusWeeks(1)); + assertEquals(DATE_2012_07_28, test.getStart()); + assertEquals(DATE_2012_07_30.plusWeeks(1), test.getEndInclusive()); + assertEquals(DATE_2012_07_31.plusWeeks(1), test.getEnd()); } + @Test public void test_withEnd_max() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); LocalDateRange test = base.withEnd(LocalDate.MAX); - assertEquals(test.getStart(), DATE_2012_07_28); - assertEquals(test.getEndInclusive(), LocalDate.MAX); - assertEquals(test.getEnd(), LocalDate.MAX); + assertEquals(DATE_2012_07_28, test.getStart()); + assertEquals(LocalDate.MAX, test.getEndInclusive()); + assertEquals(LocalDate.MAX, test.getEnd()); } + @Test public void test_withEnd_empty() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_31); LocalDateRange test = base.withEnd(DATE_2012_07_30); - assertEquals(test.getStart(), DATE_2012_07_30); - assertEquals(test.getEndInclusive(), DATE_2012_07_29); - assertEquals(test.getEnd(), DATE_2012_07_30); + assertEquals(DATE_2012_07_30, test.getStart()); + assertEquals(DATE_2012_07_29, test.getEndInclusive()); + assertEquals(DATE_2012_07_30, test.getEnd()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withEnd_invalid() { LocalDateRange base = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - base.withEnd(DATE_2012_07_27); + assertThrows(DateTimeException.class, () -> base.withEnd(DATE_2012_07_27)); } //----------------------------------------------------------------------- + @Test public void test_contains() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.contains(LocalDate.MIN), false); - assertEquals(test.contains(DATE_2012_07_27), false); - assertEquals(test.contains(DATE_2012_07_28), true); - assertEquals(test.contains(DATE_2012_07_29), true); - assertEquals(test.contains(DATE_2012_07_30), true); - assertEquals(test.contains(DATE_2012_07_31), false); - assertEquals(test.contains(DATE_2012_08_01), false); - assertEquals(test.contains(LocalDate.MAX), false); + assertEquals(false, test.contains(LocalDate.MIN)); + assertEquals(false, test.contains(DATE_2012_07_27)); + assertEquals(true, test.contains(DATE_2012_07_28)); + assertEquals(true, test.contains(DATE_2012_07_29)); + assertEquals(true, test.contains(DATE_2012_07_30)); + assertEquals(false, test.contains(DATE_2012_07_31)); + assertEquals(false, test.contains(DATE_2012_08_01)); + assertEquals(false, test.contains(LocalDate.MAX)); } + @Test public void test_contains_baseEmpty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28); - assertEquals(test.contains(LocalDate.MIN), false); - assertEquals(test.contains(DATE_2012_07_27), false); - assertEquals(test.contains(DATE_2012_07_28), false); - assertEquals(test.contains(DATE_2012_07_29), false); - assertEquals(test.contains(LocalDate.MAX), false); + assertEquals(false, test.contains(LocalDate.MIN)); + assertEquals(false, test.contains(DATE_2012_07_27)); + assertEquals(false, test.contains(DATE_2012_07_28)); + assertEquals(false, test.contains(DATE_2012_07_29)); + assertEquals(false, test.contains(LocalDate.MAX)); } + @Test public void test_contains_max() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, LocalDate.MAX); - assertEquals(test.contains(LocalDate.MIN), false); - assertEquals(test.contains(DATE_2012_07_27), false); - assertEquals(test.contains(DATE_2012_07_28), true); - assertEquals(test.contains(DATE_2012_07_29), true); - assertEquals(test.contains(DATE_2012_07_30), true); - assertEquals(test.contains(DATE_2012_07_31), true); - assertEquals(test.contains(DATE_2012_08_01), true); - assertEquals(test.contains(LocalDate.MAX), true); + assertEquals(false, test.contains(LocalDate.MIN)); + assertEquals(false, test.contains(DATE_2012_07_27)); + assertEquals(true, test.contains(DATE_2012_07_28)); + assertEquals(true, test.contains(DATE_2012_07_29)); + assertEquals(true, test.contains(DATE_2012_07_30)); + assertEquals(true, test.contains(DATE_2012_07_31)); + assertEquals(true, test.contains(DATE_2012_08_01)); + assertEquals(true, test.contains(LocalDate.MAX)); } //----------------------------------------------------------------------- - @DataProvider(name = "queries") - Object[][] data_queries() { + public static Object[][] data_queries() { return new Object[][] { // before start { DATE_2012_07_01, DATE_2012_07_27, false, false, false, false }, @@ -447,143 +751,100 @@ Object[][] data_queries() { }; } - @Test(dataProvider = "queries") + @ParameterizedTest + @MethodSource("data_queries") public void test_encloses( LocalDate start, LocalDate end, boolean isEnclosedBy, boolean abuts, boolean isConnected, boolean overlaps) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.encloses(LocalDateRange.of(start, end)), isEnclosedBy); + assertEquals(isEnclosedBy, test.encloses(LocalDateRange.of(start, end))); } - @Test(dataProvider = "queries") + @ParameterizedTest + @MethodSource("data_queries") public void test_abuts( LocalDate start, LocalDate end, boolean isEnclosedBy, boolean abuts, boolean isConnected, boolean overlaps) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.abuts(LocalDateRange.of(start, end)), abuts); + assertEquals(abuts, test.abuts(LocalDateRange.of(start, end))); } - @Test(dataProvider = "queries") + @ParameterizedTest + @MethodSource("data_queries") public void test_isConnected( LocalDate start, LocalDate end, boolean isEnclosedBy, boolean abuts, boolean isConnected, boolean overlaps) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.isConnected(LocalDateRange.of(start, end)), isConnected); + assertEquals(isConnected, test.isConnected(LocalDateRange.of(start, end))); } - @Test(dataProvider = "queries") + @ParameterizedTest + @MethodSource("data_queries") public void test_overlaps( LocalDate start, LocalDate end, boolean isEnclosedBy, boolean abuts, boolean isConnected, boolean overlaps) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.overlaps(LocalDateRange.of(start, end)), overlaps); + assertEquals(overlaps, test.overlaps(LocalDateRange.of(start, end))); } - @Test(dataProvider = "queries") + @ParameterizedTest + @MethodSource("data_queries") public void test_crossCheck( LocalDate start, LocalDate end, boolean isEnclosedBy, boolean abuts, boolean isConnected, boolean overlaps) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); LocalDateRange input = LocalDateRange.of(start, end); - assertEquals(test.isConnected(input), test.overlaps(input) || test.abuts(input)); - assertEquals(test.overlaps(input), test.isConnected(input) && !test.abuts(input)); + assertEquals(test.overlaps(input) || test.abuts(input), test.isConnected(input)); + assertEquals(test.isConnected(input) && !test.abuts(input), test.overlaps(input)); } + @Test public void test_encloses_max() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, LocalDate.MAX); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28)), true); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29)), true); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_28, LocalDate.MAX)), true); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_01, DATE_2012_07_27)), false); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29)), false); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_27, LocalDate.MAX)), false); + assertEquals(true, test.encloses(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28))); + assertEquals(true, test.encloses(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29))); + assertEquals(true, test.encloses(LocalDateRange.of(DATE_2012_07_28, LocalDate.MAX))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_01, DATE_2012_07_27))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_27, LocalDate.MAX))); } + @Test public void test_encloses_baseEmpty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27)), false); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28)), true); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29)), false); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27)), false); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_28)), false); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29)), false); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_27, LocalDate.MAX)), false); - assertEquals(test.encloses(LocalDateRange.of(DATE_2012_07_28, LocalDate.MAX)), false); - } - - public void test_encloses_baseEmptyMax() { - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .encloses(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX)), true); - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .encloses(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX)), false); - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .encloses(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(1))), false); - assertEquals(LocalDateRange.of(LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)) - .encloses(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(1))), false); - assertEquals(LocalDateRange.of(LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)) - .encloses(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(2))), false); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27))); + assertEquals(true, test.encloses(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_28))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_27, LocalDate.MAX))); + assertEquals(false, test.encloses(LocalDateRange.of(DATE_2012_07_28, LocalDate.MAX))); } + @Test public void test_abuts_baseEmpty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28); - assertEquals(test.abuts(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27)), false); - assertEquals(test.abuts(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28)), false); - assertEquals(test.abuts(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29)), false); - assertEquals(test.abuts(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_28)), true); - assertEquals(test.abuts(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29)), true); - } - - public void test_abuts_baseEmptyMax() { - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .abuts(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX)), false); - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .abuts(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX)), true); - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .abuts(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(1))), false); - assertEquals(LocalDateRange.of(LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)) - .abuts(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(1))), true); - assertEquals(LocalDateRange.of(LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)) - .abuts(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(2))), false); + assertEquals(false, test.abuts(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27))); + assertEquals(false, test.abuts(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28))); + assertEquals(false, test.abuts(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29))); + assertEquals(true, test.abuts(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_28))); + assertEquals(true, test.abuts(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29))); } + @Test public void test_isConnected_baseEmpty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28); - assertEquals(test.isConnected(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27)), false); - assertEquals(test.isConnected(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28)), true); - assertEquals(test.isConnected(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29)), false); - } - - public void test_isConnected_baseEmptyMax() { - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .isConnected(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX)), true); - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .isConnected(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX)), true); - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .isConnected(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(1))), false); - assertEquals(LocalDateRange.of(LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)) - .isConnected(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(1))), true); - assertEquals(LocalDateRange.of(LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)) - .isConnected(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(2))), false); + assertEquals(false, test.isConnected(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27))); + assertEquals(true, test.isConnected(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28))); + assertEquals(false, test.isConnected(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29))); } + @Test public void test_overlaps_baseEmpty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28); - assertEquals(test.overlaps(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27)), false); - assertEquals(test.overlaps(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28)), true); - assertEquals(test.overlaps(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29)), false); - } - - public void test_overlaps_baseEmptyMax() { - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .overlaps(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX)), true); - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .overlaps(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX)), false); - assertEquals(LocalDateRange.of(LocalDate.MAX, LocalDate.MAX) - .overlaps(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(1))), false); - assertEquals(LocalDateRange.of(LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)) - .overlaps(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(1))), false); - assertEquals(LocalDateRange.of(LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)) - .overlaps(LocalDateRange.of(DATE_2012_07_01, LocalDate.MAX.minusDays(2))), false); + assertEquals(false, test.overlaps(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_27))); + assertEquals(true, test.overlaps(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28))); + assertEquals(false, test.overlaps(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29))); } //----------------------------------------------------------------------- - @DataProvider(name = "intersection") - Object[][] data_intersection() { + public static Object[][] data_intersection() { return new Object[][] { // adjacent { DATE_2012_07_01, DATE_2012_07_28, DATE_2012_07_28, DATE_2012_07_30, DATE_2012_07_28, DATE_2012_07_28 }, @@ -598,7 +859,8 @@ Object[][] data_intersection() { }; } - @Test(dataProvider = "intersection") + @ParameterizedTest + @MethodSource("data_intersection") public void test_intersection( LocalDate start1, LocalDate end1, LocalDate start2, LocalDate end2, LocalDate expStart, LocalDate expEnd) { @@ -606,10 +868,11 @@ public void test_intersection( LocalDateRange test2 = LocalDateRange.of(start2, end2); LocalDateRange expected = LocalDateRange.of(expStart, expEnd); assertTrue(test1.isConnected(test2)); - assertEquals(test1.intersection(test2), expected); + assertEquals(expected, test1.intersection(test2)); } - @Test(dataProvider = "intersection") + @ParameterizedTest + @MethodSource("data_intersection") public void test_intersection_reverse( LocalDate start1, LocalDate end1, LocalDate start2, LocalDate end2, LocalDate expStart, LocalDate expEnd) { @@ -617,25 +880,25 @@ public void test_intersection_reverse( LocalDateRange test2 = LocalDateRange.of(start2, end2); LocalDateRange expected = LocalDateRange.of(expStart, expEnd); assertTrue(test2.isConnected(test1)); - assertEquals(test2.intersection(test1), expected); + assertEquals(expected, test2.intersection(test1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_intersectionBad() { LocalDateRange test1 = LocalDateRange.of(DATE_2012_07_01, DATE_2012_07_28); LocalDateRange test2 = LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_30); - assertEquals(test1.isConnected(test2), false); - test1.intersection(test2); + assertEquals(false, test1.isConnected(test2)); + assertThrows(DateTimeException.class, () -> test1.intersection(test2)); } + @Test public void test_intersection_same() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.intersection(test), test); + assertEquals(test, test.intersection(test)); } //----------------------------------------------------------------------- - @DataProvider(name = "union") - Object[][] data_union() { + public static Object[][] data_union() { return new Object[][] { // adjacent { DATE_2012_07_01, DATE_2012_07_28, DATE_2012_07_28, DATE_2012_07_30, DATE_2012_07_01, DATE_2012_07_30 }, @@ -650,7 +913,8 @@ Object[][] data_union() { }; } - @Test(dataProvider = "union") + @ParameterizedTest + @MethodSource("data_union") public void test_unionAndSpan( LocalDate start1, LocalDate end1, LocalDate start2, LocalDate end2, LocalDate expStart, LocalDate expEnd) { @@ -658,11 +922,12 @@ public void test_unionAndSpan( LocalDateRange test2 = LocalDateRange.of(start2, end2); LocalDateRange expected = LocalDateRange.of(expStart, expEnd); assertTrue(test1.isConnected(test2)); - assertEquals(test1.union(test2), expected); - assertEquals(test1.span(test2), expected); + assertEquals(expected, test1.union(test2)); + assertEquals(expected, test1.span(test2)); } - @Test(dataProvider = "union") + @ParameterizedTest + @MethodSource("data_union") public void test_unionAndSpan_reverse( LocalDate start1, LocalDate end1, LocalDate start2, LocalDate end2, LocalDate expStart, LocalDate expEnd) { @@ -670,55 +935,78 @@ public void test_unionAndSpan_reverse( LocalDateRange test2 = LocalDateRange.of(start2, end2); LocalDateRange expected = LocalDateRange.of(expStart, expEnd); assertTrue(test2.isConnected(test1)); - assertEquals(test2.union(test1), expected); - assertEquals(test2.span(test1), expected); + assertEquals(expected, test2.union(test1)); + assertEquals(expected, test2.span(test1)); } - @Test(dataProvider = "union") + @ParameterizedTest + @MethodSource("data_union") public void test_span_enclosesInputs( LocalDate start1, LocalDate end1, LocalDate start2, LocalDate end2, LocalDate expStart, LocalDate expEnd) { LocalDateRange test1 = LocalDateRange.of(start1, end1); LocalDateRange test2 = LocalDateRange.of(start2, end2); LocalDateRange expected = LocalDateRange.of(expStart, expEnd); - assertEquals(expected.encloses(test1), true); - assertEquals(expected.encloses(test2), true); + assertEquals(true, expected.encloses(test1)); + assertEquals(true, expected.encloses(test2)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_union_disconnected() { LocalDateRange test1 = LocalDateRange.of(DATE_2012_07_01, DATE_2012_07_28); LocalDateRange test2 = LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_30); assertFalse(test1.isConnected(test2)); - test1.union(test2); + assertThrows(DateTimeException.class, () -> test1.union(test2)); } + @Test public void test_span_disconnected() { LocalDateRange test1 = LocalDateRange.of(DATE_2012_07_01, DATE_2012_07_28); LocalDateRange test2 = LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_30); assertFalse(test1.isConnected(test2)); - assertEquals(test1.span(test2), LocalDateRange.of(DATE_2012_07_01, DATE_2012_07_30)); + assertEquals(LocalDateRange.of(DATE_2012_07_01, DATE_2012_07_30), test1.span(test2)); } + @Test public void test_unionAndSpan_same() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.union(test), test); - assertEquals(test.span(test), test); + assertEquals(test, test.union(test)); + assertEquals(test, test.span(test)); } //----------------------------------------------------------------------- + @Test public void test_stream() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); List result = test.stream().collect(Collectors.toList()); - assertEquals(result.size(), 3); - assertEquals(result.get(0), DATE_2012_07_28); - assertEquals(result.get(1), DATE_2012_07_29); - assertEquals(result.get(2), DATE_2012_07_30); + assertEquals(3, result.size()); + assertEquals(DATE_2012_07_28, result.get(0)); + assertEquals(DATE_2012_07_29, result.get(1)); + assertEquals(DATE_2012_07_30, result.get(2)); + } + + @Test + public void test_stream_MIN_MINP3() { + LocalDateRange test = LocalDateRange.of(LocalDate.MIN, MINP3); + List result = test.stream().collect(Collectors.toList()); + assertEquals(3, result.size()); + assertEquals(LocalDate.MIN, result.get(0)); + assertEquals(MINP1, result.get(1)); + assertEquals(MINP2, result.get(2)); + } + + @Test + public void test_stream_MAXM2_MAX() { + LocalDateRange test = LocalDateRange.of(MAXM2, LocalDate.MAX); + List result = test.stream().collect(Collectors.toList()); + assertEquals(3, result.size()); + assertEquals(MAXM2, result.get(0)); + assertEquals(MAXM1, result.get(1)); + assertEquals(LocalDate.MAX, result.get(2)); } //----------------------------------------------------------------------- - @DataProvider(name = "isBefore") - Object[][] data_isBefore() { + public static Object[][] data_isBefore() { return new Object[][] { // before start { DATE_2012_07_01, DATE_2012_07_27, false }, @@ -760,38 +1048,41 @@ Object[][] data_isBefore() { }; } - @Test(dataProvider = "isBefore") + @ParameterizedTest + @MethodSource("data_isBefore") public void test_isBefore_range(LocalDate start, LocalDate end, boolean before) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.isBefore(LocalDateRange.of(start, end)), before); + assertEquals(before, test.isBefore(LocalDateRange.of(start, end))); } - @Test(dataProvider = "isBefore") + @ParameterizedTest + @MethodSource("data_isBefore") public void test_isBefore_date(LocalDate start, LocalDate end, boolean before) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.isBefore(start), before); + assertEquals(before, test.isBefore(start)); } + @Test public void test_isBefore_range_empty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29); - assertEquals(test.isBefore(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_28)), false); - assertEquals(test.isBefore(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29)), false); - assertEquals(test.isBefore(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29)), false); - assertEquals(test.isBefore(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_30)), true); - assertEquals(test.isBefore(LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_30)), true); - assertEquals(test.isBefore(LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_31)), true); + assertEquals(false, test.isBefore(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_28))); + assertEquals(false, test.isBefore(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29))); + assertEquals(false, test.isBefore(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29))); + assertEquals(true, test.isBefore(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_30))); + assertEquals(true, test.isBefore(LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_30))); + assertEquals(true, test.isBefore(LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_31))); } + @Test public void test_isBefore_date_empty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29); - assertEquals(test.isBefore(DATE_2012_07_28), false); - assertEquals(test.isBefore(DATE_2012_07_29), false); - assertEquals(test.isBefore(DATE_2012_07_30), true); + assertEquals(false, test.isBefore(DATE_2012_07_28)); + assertEquals(false, test.isBefore(DATE_2012_07_29)); + assertEquals(true, test.isBefore(DATE_2012_07_30)); } //----------------------------------------------------------------------- - @DataProvider(name = "isAfter") - Object[][] data_isAfter() { + public static Object[][] data_isAfter() { return new Object[][] { // before start { DATE_2012_07_01, DATE_2012_07_27, true }, @@ -836,68 +1127,81 @@ Object[][] data_isAfter() { }; } - @Test(dataProvider = "isAfter") + @ParameterizedTest + @MethodSource("data_isAfter") public void test_isAfter_range(LocalDate start, LocalDate end, boolean before) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.isAfter(LocalDateRange.of(start, end)), before); + assertEquals(before, test.isAfter(LocalDateRange.of(start, end))); } - @Test(dataProvider = "isAfter") + @ParameterizedTest + @MethodSource("data_isAfter") public void test_isAfter_date(LocalDate start, LocalDate end, boolean before) { LocalDateRange test = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_31); - assertEquals(test.isAfter(end.minusDays(1)), before); + assertEquals(before, test.isAfter(end.minusDays(1))); } + @Test public void test_isAfter_range_empty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29); - assertEquals(test.isAfter(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_28)), true); - assertEquals(test.isAfter(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29)), true); - assertEquals(test.isAfter(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28)), true); - assertEquals(test.isAfter(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29)), false); - assertEquals(test.isAfter(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_30)), false); - assertEquals(test.isAfter(LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_30)), false); - assertEquals(test.isAfter(LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_31)), false); + assertEquals(true, test.isAfter(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_28))); + assertEquals(true, test.isAfter(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29))); + assertEquals(true, test.isAfter(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_28))); + assertEquals(false, test.isAfter(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29))); + assertEquals(false, test.isAfter(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_30))); + assertEquals(false, test.isAfter(LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_30))); + assertEquals(false, test.isAfter(LocalDateRange.of(DATE_2012_07_30, DATE_2012_07_31))); } + @Test public void test_isAfter_date_empty() { LocalDateRange test = LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29); - assertEquals(test.isAfter(DATE_2012_07_28), true); - assertEquals(test.isAfter(DATE_2012_07_29), false); - assertEquals(test.isAfter(DATE_2012_07_30), false); + assertEquals(true, test.isAfter(DATE_2012_07_28)); + assertEquals(false, test.isAfter(DATE_2012_07_29)); + assertEquals(false, test.isAfter(DATE_2012_07_30)); } //----------------------------------------------------------------------- + @Test public void test_lengthInDays() { - assertEquals(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29).lengthInDays(), 2); - assertEquals(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29).lengthInDays(), 1); - assertEquals(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29).lengthInDays(), 0); + assertEquals(2, LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29).lengthInDays()); + assertEquals(1, LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29).lengthInDays()); + assertEquals(0, LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29).lengthInDays()); + assertEquals(Integer.MAX_VALUE, LocalDateRange.of(LocalDate.MIN, DATE_2012_07_29).lengthInDays()); + assertEquals(Integer.MAX_VALUE, LocalDateRange.of(DATE_2012_07_29, LocalDate.MAX).lengthInDays()); + assertEquals(Integer.MAX_VALUE, LocalDateRange.of(MINP1, MAXM1).lengthInDays()); } + @Test public void test_toPeriod() { - assertEquals(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29).toPeriod(), Period.ofDays(2)); - assertEquals(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29).toPeriod(), Period.ofDays(1)); - assertEquals(LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29).toPeriod(), Period.ofDays(0)); + assertEquals(Period.ofDays(2), LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29).toPeriod()); + assertEquals(Period.ofDays(1), LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29).toPeriod()); + assertEquals(Period.ofDays(0), LocalDateRange.of(DATE_2012_07_29, DATE_2012_07_29).toPeriod()); + } + + @Test + public void test_toPeriod_unbounded_MIN() { + assertThrows(ArithmeticException.class, () -> LocalDateRange.of(LocalDate.MIN, DATE_2012_07_29).toPeriod()); + } + + @Test + public void test_toPeriod_unbounded_MAX() { + assertThrows(ArithmeticException.class, () -> LocalDateRange.of(DATE_2012_07_29, LocalDate.MAX).toPeriod()); } //----------------------------------------------------------------------- - public void test_equals() { - LocalDateRange a = LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29); - LocalDateRange a2 = LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29); - LocalDateRange b = LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_30); - LocalDateRange c = LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29); - assertEquals(a.equals(a), true); - assertEquals(a.equals(a2), true); - assertEquals(a.equals(b), false); - assertEquals(a.equals(c), false); - assertEquals(a.equals(null), false); - assertEquals(a.equals(""), false); - assertEquals(a.hashCode() == a2.hashCode(), true); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29), LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_29)) + .addEqualityGroup(LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_30), LocalDateRange.of(DATE_2012_07_27, DATE_2012_07_30)) + .addEqualityGroup(LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29), LocalDateRange.of(DATE_2012_07_28, DATE_2012_07_29)) + .testEquals(); } //----------------------------------------------------------------------- - @DataProvider(name = "crossCheckGuava") - Iterator data_crossCheckGuava() { - List list = new ArrayList<>(); + public static List data_crossCheckGuava() { + List list = new ArrayList<>(); for (int i1 = 1; i1 < 5; i1++) { for (int j1 = i1; j1 < 5; j1++) { LocalDate date11 = LocalDate.of(2016, 1, i1); @@ -910,44 +1214,46 @@ Iterator data_crossCheckGuava() { LocalDate date22 = LocalDate.of(2016, 1, j2); LocalDateRange extraRange2 = LocalDateRange.of(date21, date22); Range guavaRange2 = Range.closedOpen(date21, date22); - Object[] array = {extraRange1, extraRange2, guavaRange1, guavaRange2}; - list.add(array); + list.add(arguments(extraRange1, extraRange2, guavaRange1, guavaRange2)); } } } } - return list.iterator(); + return list; } - @Test(dataProvider = "crossCheckGuava") + @ParameterizedTest + @MethodSource("data_crossCheckGuava") public void crossCheckGuava_encloses( LocalDateRange extraRange1, - LocalDateRange extraRange2, - Range guavaRange1, + LocalDateRange extraRange2, + Range guavaRange1, Range guavaRange2) { boolean extra = extraRange1.encloses(extraRange2); boolean guava = guavaRange1.encloses(guavaRange2); - assertEquals(extra, guava); + assertEquals(guava, extra); } - @Test(dataProvider = "crossCheckGuava") + @ParameterizedTest + @MethodSource("data_crossCheckGuava") public void crossCheckGuava_isConnected( LocalDateRange extraRange1, - LocalDateRange extraRange2, - Range guavaRange1, + LocalDateRange extraRange2, + Range guavaRange1, Range guavaRange2) { boolean extra = extraRange1.isConnected(extraRange2); boolean guava = guavaRange1.isConnected(guavaRange2); - assertEquals(extra, guava); + assertEquals(guava, extra); } - @Test(dataProvider = "crossCheckGuava") + @ParameterizedTest + @MethodSource("data_crossCheckGuava") public void crossCheckGuava_intersection( LocalDateRange extraRange1, - LocalDateRange extraRange2, - Range guavaRange1, + LocalDateRange extraRange2, + Range guavaRange1, Range guavaRange2) { LocalDateRange extra = null; @@ -963,24 +1269,25 @@ public void crossCheckGuava_intersection( // continue } if (extra == null) { - assertEquals(extra, guava); - } else { - assertEquals(extra.getStart(), guava.lowerEndpoint()); - assertEquals(extra.getEnd(), guava.upperEndpoint()); + assertEquals(guava, extra); + } else if (guava != null) { + assertEquals(guava.lowerEndpoint(), extra.getStart()); + assertEquals(guava.upperEndpoint(), extra.getEnd()); } } - @Test(dataProvider = "crossCheckGuava") + @ParameterizedTest + @MethodSource("data_crossCheckGuava") public void crossCheckGuava_span( LocalDateRange extraRange1, - LocalDateRange extraRange2, - Range guavaRange1, + LocalDateRange extraRange2, + Range guavaRange1, Range guavaRange2) { LocalDateRange extra = extraRange1.span(extraRange2); Range guava = guavaRange1.span(guavaRange2); - assertEquals(extra.getStart(), guava.lowerEndpoint()); - assertEquals(extra.getEnd(), guava.upperEndpoint()); + assertEquals(guava.lowerEndpoint(), extra.getStart()); + assertEquals(guava.upperEndpoint(), extra.getEnd()); } } diff --git a/src/test/java/org/threeten/extra/TestMinutes.java b/src/test/java/org/threeten/extra/TestMinutes.java index a7f44e5a..2bc1c327 100644 --- a/src/test/java/org/threeten/extra/TestMinutes.java +++ b/src/test/java/org/threeten/extra/TestMinutes.java @@ -31,9 +31,11 @@ */ package org.threeten.extra; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -44,70 +46,94 @@ import java.time.LocalTime; import java.time.format.DateTimeParseException; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test class. */ -@Test public class TestMinutes { - + //----------------------------------------------------------------------- + @Test public void test_isSerializable() { assertTrue(Serializable.class.isAssignableFrom(Minutes.class)); } //----------------------------------------------------------------------- + @Test public void test_deserializationSingleton() throws Exception { - Minutes orginal = Minutes.ZERO; + Minutes test = Minutes.ZERO; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Minutes ser = (Minutes) in.readObject(); - assertSame(Minutes.ZERO, ser); - } - + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } + } + //----------------------------------------------------------------------- + @Test public void test_ZERO() { - assertSame(Minutes.of(0), Minutes.ZERO); - assertSame(Minutes.of(0), Minutes.ZERO); - assertEquals(Minutes.ZERO.getAmount(), 0); + assertSame(Minutes.ZERO, Minutes.of(0)); + assertEquals(Minutes.ZERO, Minutes.of(0)); + assertEquals(0, Minutes.ZERO.getAmount()); + assertFalse(Minutes.ZERO.isNegative()); + assertTrue(Minutes.ZERO.isZero()); + assertFalse(Minutes.ZERO.isPositive()); } - + //----------------------------------------------------------------------- + @Test public void test_of() { - assertEquals(Minutes.of(0).getAmount(), 0); - assertEquals(Minutes.of(1).getAmount(), 1); - assertEquals(Minutes.of(2).getAmount(), 2); - assertEquals(Minutes.of(Integer.MAX_VALUE).getAmount(), Integer.MAX_VALUE); - assertEquals(Minutes.of(-1).getAmount(), -1); - assertEquals(Minutes.of(-2).getAmount(), -2); - assertEquals(Minutes.of(Integer.MIN_VALUE).getAmount(), Integer.MIN_VALUE); - } - + assertEquals(0, Minutes.of(0).getAmount()); + assertEquals(1, Minutes.of(1).getAmount()); + assertEquals(2, Minutes.of(2).getAmount()); + assertEquals(Integer.MAX_VALUE, Minutes.of(Integer.MAX_VALUE).getAmount()); + assertEquals(-1, Minutes.of(-1).getAmount()); + assertEquals(-2, Minutes.of(-2).getAmount()); + assertEquals(Integer.MIN_VALUE, Minutes.of(Integer.MIN_VALUE).getAmount()); + } + + @Test + public void test_ofMinusOne() { + assertEquals(-1, Hours.of(-1).getAmount()); + assertTrue(Minutes.of(-1).isNegative()); + assertFalse(Minutes.of(-1).isZero()); + assertFalse(Minutes.of(-1).isPositive()); + } + + @Test + public void test_ofPlusOne() { + assertEquals(1, Hours.of(1).getAmount()); + assertFalse(Minutes.of(1).isNegative()); + assertFalse(Minutes.of(1).isZero()); + assertTrue(Minutes.of(1).isPositive()); + } + //----------------------------------------------------------------------- + @Test public void test_ofHours() { - assertEquals(Minutes.ofHours(0).getAmount(), 0); - assertEquals(Minutes.ofHours(1).getAmount(), 60); - assertEquals(Minutes.ofHours(2).getAmount(), 120); - assertEquals(Minutes.ofHours(Integer.MAX_VALUE / 60).getAmount(), (Integer.MAX_VALUE / 60) * 60); - assertEquals(Minutes.ofHours(-1).getAmount(), -60); - assertEquals(Minutes.ofHours(-2).getAmount(), -120); - assertEquals(Minutes.ofHours(Integer.MIN_VALUE / 60).getAmount(), (Integer.MIN_VALUE / 60) * 60); - } - - @Test(expectedExceptions = ArithmeticException.class) + assertEquals(0, Minutes.ofHours(0).getAmount()); + assertEquals(60, Minutes.ofHours(1).getAmount()); + assertEquals(120, Minutes.ofHours(2).getAmount()); + assertEquals((Integer.MAX_VALUE / 60) * 60, Minutes.ofHours(Integer.MAX_VALUE / 60).getAmount()); + assertEquals(-60, Minutes.ofHours(-1).getAmount()); + assertEquals(-120, Minutes.ofHours(-2).getAmount()); + assertEquals((Integer.MIN_VALUE / 60) * 60, Minutes.ofHours(Integer.MIN_VALUE / 60).getAmount()); + } + + @Test public void test_ofHours_overflow() { - Minutes.ofHours((Integer.MAX_VALUE / 60) + 60); + assertThrows(ArithmeticException.class, () -> Minutes.ofHours((Integer.MAX_VALUE / 60) + 60)); } - + //----------------------------------------------------------------------- - @DataProvider(name = "parseValid") - Object[][] data_valid() { + public static Object[][] data_valid() { return new Object[][] { {"PT0M", 0}, {"PT1M", 1}, @@ -127,6 +153,15 @@ Object[][] data_valid() { {"PT-0H", 0}, {"PT-2H", -120}, + {"P0D", 0}, + {"P1D", 1 * 24 * 60}, + {"P2D", 2 * 24 * 60}, + {"P1234D", 1234 * 24 * 60}, + {"P+0D", 0}, + {"P+2D", 2 * 24 * 60}, + {"P-0D", 0}, + {"P-2D", -2 * 24 * 60}, + {"PT0H0M", 0}, {"PT2H3M", 123}, {"PT+2H3M", 123}, @@ -134,29 +169,33 @@ Object[][] data_valid() { {"PT-2H3M", -117}, {"PT2H-3M", 117}, {"PT-2H-3M", -123}, + + {"P0DT0H0M", 0}, + {"P5DT2H4M", 5 * 24 * 60 + 2 * 60 + 4}, }; } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid(String str, int expectedMinutes) { - assertEquals(Minutes.parse(str), Minutes.of(expectedMinutes)); + assertEquals(Minutes.of(expectedMinutes), Minutes.parse(str)); } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid_initialPlus(String str, int expectedMinutes) { - assertEquals(Minutes.parse("+" + str), Minutes.of(expectedMinutes)); + assertEquals(Minutes.of(expectedMinutes), Minutes.parse("+" + str)); } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid_initialMinus(String str, int expectedMinutes) { - assertEquals(Minutes.parse("-" + str), Minutes.of(-expectedMinutes)); + assertEquals(Minutes.of(-expectedMinutes), Minutes.parse("-" + str)); } - @DataProvider(name = "parseInvalid") - Object[][] data_invalid() { + public static Object[][] data_invalid() { return new Object[][] { {"P3W"}, - {"P3D"}, {"P3Q"}, {"P1M2Y"}, @@ -164,6 +203,7 @@ Object[][] data_invalid() { {"-3"}, {"3M"}, {"-3M"}, + {"P3M"}, {"P3"}, {"P-3"}, {"PM"}, @@ -174,17 +214,19 @@ Object[][] data_invalid() { }; } - @Test(expectedExceptions = DateTimeParseException.class, dataProvider = "parseInvalid") + @ParameterizedTest + @MethodSource("data_invalid") public void test_parse_CharSequence_invalid(String str) { - Minutes.parse(str); + assertThrows(DateTimeParseException.class, () -> Minutes.parse(str)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequence_null() { - Minutes.parse((CharSequence) null); + assertThrows(NullPointerException.class, () -> Minutes.parse((CharSequence) null)); } - + //----------------------------------------------------------------------- + @Test public void test_plus_TemporalAmount_Minutes() { Minutes test5 = Minutes.of(5); assertEquals(Minutes.of(5), test5.plus(Minutes.of(0))); @@ -193,23 +235,24 @@ public void test_plus_TemporalAmount_Minutes() { assertEquals(Minutes.of(Integer.MAX_VALUE), Minutes.of(Integer.MAX_VALUE - 1).plus(Minutes.of(1))); assertEquals(Minutes.of(Integer.MIN_VALUE), Minutes.of(Integer.MIN_VALUE + 1).plus(Minutes.of(-1))); } - - @Test(expectedExceptions = ArithmeticException.class) + + @Test public void test_plus_TemporalAmount_overflowTooBig() { - Minutes.of(Integer.MAX_VALUE - 1).plus(Minutes.of(2)); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MAX_VALUE - 1).plus(Minutes.of(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooSmall() { - Minutes.of(Integer.MIN_VALUE + 1).plus(Minutes.of(-2)); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MIN_VALUE + 1).plus(Minutes.of(-2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_plus_TemporalAmount_null() { - Minutes.of(Integer.MIN_VALUE + 1).plus(null); + assertThrows(NullPointerException.class, () -> Minutes.of(Integer.MIN_VALUE + 1).plus(null)); } - + //----------------------------------------------------------------------- + @Test public void test_plus_int() { Minutes test5 = Minutes.of(5); assertEquals(Minutes.of(5), test5.plus(0)); @@ -219,17 +262,18 @@ public void test_plus_int() { assertEquals(Minutes.of(Integer.MIN_VALUE), Minutes.of(Integer.MIN_VALUE + 1).plus(-1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooBig() { - Minutes.of(Integer.MAX_VALUE - 1).plus(2); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MAX_VALUE - 1).plus(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooSmall() { - Minutes.of(Integer.MIN_VALUE + 1).plus(-2); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MIN_VALUE + 1).plus(-2)); } - + //----------------------------------------------------------------------- + @Test public void test_minus_TemporalAmount_Minutes() { Minutes test5 = Minutes.of(5); assertEquals(Minutes.of(5), test5.minus(Minutes.of(0))); @@ -239,22 +283,23 @@ public void test_minus_TemporalAmount_Minutes() { assertEquals(Minutes.of(Integer.MIN_VALUE), Minutes.of(Integer.MIN_VALUE + 1).minus(Minutes.of(1))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooBig() { - Minutes.of(Integer.MAX_VALUE - 1).minus(Minutes.of(-2)); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MAX_VALUE - 1).minus(Minutes.of(-2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooSmall() { - Minutes.of(Integer.MIN_VALUE + 1).minus(Minutes.of(2)); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MIN_VALUE + 1).minus(Minutes.of(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_minus_TemporalAmount_null() { - Minutes.of(Integer.MIN_VALUE + 1).minus(null); + assertThrows(NullPointerException.class, () -> Minutes.of(Integer.MIN_VALUE + 1).minus(null)); } - + //----------------------------------------------------------------------- + @Test public void test_minus_int() { Minutes test5 = Minutes.of(5); assertEquals(Minutes.of(5), test5.minus(0)); @@ -264,17 +309,18 @@ public void test_minus_int() { assertEquals(Minutes.of(Integer.MIN_VALUE), Minutes.of(Integer.MIN_VALUE + 1).minus(1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooBig() { - Minutes.of(Integer.MAX_VALUE - 1).minus(-2); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MAX_VALUE - 1).minus(-2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooSmall() { - Minutes.of(Integer.MIN_VALUE + 1).minus(2); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MIN_VALUE + 1).minus(2)); } - + //----------------------------------------------------------------------- + @Test public void test_multipliedBy() { Minutes test5 = Minutes.of(5); assertEquals(Minutes.of(0), test5.multipliedBy(0)); @@ -284,22 +330,24 @@ public void test_multipliedBy() { assertEquals(Minutes.of(-15), test5.multipliedBy(-3)); } + @Test public void test_multipliedBy_negate() { Minutes test5 = Minutes.of(5); assertEquals(Minutes.of(-15), test5.multipliedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooBig() { - Minutes.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooSmall() { - Minutes.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2)); } - + //----------------------------------------------------------------------- + @Test public void test_dividedBy() { Minutes test12 = Minutes.of(12); assertEquals(Minutes.of(12), test12.dividedBy(1)); @@ -311,17 +359,19 @@ public void test_dividedBy() { assertEquals(Minutes.of(-4), test12.dividedBy(-3)); } + @Test public void test_dividedBy_negate() { Minutes test12 = Minutes.of(12); assertEquals(Minutes.of(-4), test12.dividedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_dividedBy_divideByZero() { - Minutes.of(1).dividedBy(0); + assertThrows(ArithmeticException.class, () -> Minutes.of(1).dividedBy(0)); } - + //----------------------------------------------------------------------- + @Test public void test_negated() { assertEquals(Minutes.of(0), Minutes.of(0).negated()); assertEquals(Minutes.of(-12), Minutes.of(12).negated()); @@ -329,12 +379,13 @@ public void test_negated() { assertEquals(Minutes.of(-Integer.MAX_VALUE), Minutes.of(Integer.MAX_VALUE).negated()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_negated_overflow() { - Minutes.of(Integer.MIN_VALUE).negated(); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MIN_VALUE).negated()); } - + //----------------------------------------------------------------------- + @Test public void test_abs() { assertEquals(Minutes.of(0), Minutes.of(0).abs()); assertEquals(Minutes.of(12), Minutes.of(12).abs()); @@ -343,33 +394,37 @@ public void test_abs() { assertEquals(Minutes.of(Integer.MAX_VALUE), Minutes.of(-Integer.MAX_VALUE).abs()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_abs_overflow() { - Minutes.of(Integer.MIN_VALUE).abs(); + assertThrows(ArithmeticException.class, () -> Minutes.of(Integer.MIN_VALUE).abs()); } - + //----------------------------------------------------------------------- + @Test public void test_addTo() { LocalTime base = LocalTime.of(11, 30); - assertEquals(Minutes.of(0).addTo(base), LocalTime.of(11, 30)); - assertEquals(Minutes.of(6).addTo(base), LocalTime.of(11, 36)); + assertEquals(LocalTime.of(11, 30), Minutes.of(0).addTo(base)); + assertEquals(LocalTime.of(11, 36), Minutes.of(6).addTo(base)); } //----------------------------------------------------------------------- + @Test public void test_subtractFrom() { LocalTime base = LocalTime.of(11, 30); - assertEquals(Minutes.of(0).subtractFrom(base), LocalTime.of(11, 30)); - assertEquals(Minutes.of(6).subtractFrom(base), LocalTime.of(11, 24)); + assertEquals(LocalTime.of(11, 30), Minutes.of(0).subtractFrom(base)); + assertEquals(LocalTime.of(11, 24), Minutes.of(6).subtractFrom(base)); } //----------------------------------------------------------------------- + @Test public void test_toDuration() { for (int i = -20; i < 20; i++) { - assertEquals(Minutes.of(i).toDuration(), Duration.ofMinutes(i)); + assertEquals(Duration.ofMinutes(i), Minutes.of(i).toDuration()); } } - + //----------------------------------------------------------------------- + @Test public void test_compareTo() { Minutes test5 = Minutes.of(5); Minutes test6 = Minutes.of(6); @@ -378,45 +433,28 @@ public void test_compareTo() { assertEquals(1, test6.compareTo(test5)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_null() { Minutes test5 = Minutes.of(5); - test5.compareTo(null); - } - - //----------------------------------------------------------------------- - public void test_equals() { - Minutes test5 = Minutes.of(5); - Minutes test6 = Minutes.of(6); - assertEquals(true, test5.equals(test5)); - assertEquals(false, test5.equals(test6)); - assertEquals(false, test6.equals(test5)); - } - - public void test_equals_null() { - Minutes test5 = Minutes.of(5); - assertEquals(false, test5.equals(null)); - } - - public void test_equals_otherClass() { - Minutes test5 = Minutes.of(5); - assertEquals(false, test5.equals("")); + assertThrows(NullPointerException.class, () -> test5.compareTo(null)); } //----------------------------------------------------------------------- - public void test_hashCode() { - Minutes test5 = Minutes.of(5); - Minutes test6 = Minutes.of(6); - assertEquals(true, test5.hashCode() == test5.hashCode()); - assertEquals(false, test5.hashCode() == test6.hashCode()); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Minutes.of(5), Minutes.of(5)) + .addEqualityGroup(Minutes.of(6), Minutes.of(6)) + .testEquals(); } //----------------------------------------------------------------------- + @Test public void test_toString() { Minutes test5 = Minutes.of(5); assertEquals("PT5M", test5.toString()); Minutes testM1 = Minutes.of(-1); assertEquals("PT-1M", testM1.toString()); } - + } diff --git a/src/test/java/org/threeten/extra/TestMonths.java b/src/test/java/org/threeten/extra/TestMonths.java index 17b01a7d..a43c6f0a 100644 --- a/src/test/java/org/threeten/extra/TestMonths.java +++ b/src/test/java/org/threeten/extra/TestMonths.java @@ -31,9 +31,11 @@ */ package org.threeten.extra; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -42,111 +44,140 @@ import java.io.Serializable; import java.time.DateTimeException; import java.time.Duration; +import java.time.LocalDate; import java.time.Period; import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAmount; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test class. */ -@Test public class TestMonths { //----------------------------------------------------------------------- + @Test public void test_isSerializable() { assertTrue(Serializable.class.isAssignableFrom(Months.class)); } //----------------------------------------------------------------------- + @Test public void test_deserializationSingleton() throws Exception { - Months orginal = Months.ZERO; + Months test = Months.ZERO; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Months ser = (Months) in.readObject(); - assertSame(Months.ZERO, ser); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } } //----------------------------------------------------------------------- + @Test public void test_ZERO() { - assertSame(Months.of(0), Months.ZERO); - assertSame(Months.of(0), Months.ZERO); - assertEquals(Months.ZERO.getAmount(), 0); + assertSame(Months.ZERO, Months.of(0)); + assertEquals(Months.ZERO, Months.of(0)); + assertEquals(0, Months.ZERO.getAmount()); + assertFalse(Months.ZERO.isNegative()); + assertTrue(Months.ZERO.isZero()); + assertFalse(Months.ZERO.isPositive()); } + @Test public void test_ONE() { - assertSame(Months.of(1), Months.ONE); - assertSame(Months.of(1), Months.ONE); - assertEquals(Months.ONE.getAmount(), 1); + assertSame(Months.ONE, Months.of(1)); + assertEquals(Months.ONE, Months.of(1)); + assertEquals(1, Months.ONE.getAmount()); + assertFalse(Months.ONE.isNegative()); + assertFalse(Months.ONE.isZero()); + assertTrue(Months.ONE.isPositive()); } //----------------------------------------------------------------------- + @Test public void test_of() { - assertEquals(Months.of(0).getAmount(), 0); - assertEquals(Months.of(1).getAmount(), 1); - assertEquals(Months.of(2).getAmount(), 2); - assertEquals(Months.of(Integer.MAX_VALUE).getAmount(), Integer.MAX_VALUE); - assertEquals(Months.of(-1).getAmount(), -1); - assertEquals(Months.of(-2).getAmount(), -2); - assertEquals(Months.of(Integer.MIN_VALUE).getAmount(), Integer.MIN_VALUE); + assertEquals(0, Months.of(0).getAmount()); + assertEquals(1, Months.of(1).getAmount()); + assertEquals(2, Months.of(2).getAmount()); + assertEquals(Integer.MAX_VALUE, Months.of(Integer.MAX_VALUE).getAmount()); + assertEquals(-1, Months.of(-1).getAmount()); + assertEquals(-2, Months.of(-2).getAmount()); + assertEquals(Integer.MIN_VALUE, Months.of(Integer.MIN_VALUE).getAmount()); + } + + @Test + public void test_ofMinusOne() { + assertEquals(-1, Months.of(-1).getAmount()); + assertTrue(Months.of(-1).isNegative()); + assertFalse(Months.of(-1).isZero()); + assertFalse(Months.of(-1).isPositive()); } //----------------------------------------------------------------------- + @Test public void test_ofYears() { - assertEquals(Months.ofYears(0).getAmount(), 0); - assertEquals(Months.ofYears(1).getAmount(), 12); - assertEquals(Months.ofYears(2).getAmount(), 24); - assertEquals(Months.ofYears(Integer.MAX_VALUE / 12).getAmount(), (Integer.MAX_VALUE / 12) * 12); - assertEquals(Months.ofYears(-1).getAmount(), -12); - assertEquals(Months.ofYears(-2).getAmount(), -24); - assertEquals(Months.ofYears(Integer.MIN_VALUE / 12).getAmount(), (Integer.MIN_VALUE / 12) * 12); + assertEquals(0, Months.ofYears(0).getAmount()); + assertEquals(12, Months.ofYears(1).getAmount()); + assertEquals(24, Months.ofYears(2).getAmount()); + assertEquals((Integer.MAX_VALUE / 12) * 12, Months.ofYears(Integer.MAX_VALUE / 12).getAmount()); + assertEquals(-12, Months.ofYears(-1).getAmount()); + assertEquals(-24, Months.ofYears(-2).getAmount()); + assertEquals((Integer.MIN_VALUE / 12) * 12, Months.ofYears(Integer.MIN_VALUE / 12).getAmount()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_ofYears_overflow() { - Months.ofYears((Integer.MAX_VALUE / 12) + 12); + assertThrows(ArithmeticException.class, () -> Months.ofYears((Integer.MAX_VALUE / 12) + 12)); } //----------------------------------------------------------------------- + @Test public void test_from_Period_P0M() { - assertEquals(Months.from(Period.ofMonths(0)), Months.of(0)); + assertEquals(Months.of(0), Months.from(Period.ofMonths(0))); } + @Test public void test_from_Period_P2M() { - assertEquals(Months.from(Period.ofMonths(2)), Months.of(2)); + assertEquals(Months.of(2), Months.from(Period.ofMonths(2))); } + @Test public void test_from_P2Y() { - assertEquals(Months.from(new MockYearsMonths(2, 0)), Months.of(24)); + assertEquals(Months.of(24), Months.from(new MockYearsMonths(2, 0))); } + @Test public void test_from_P2Y3M() { - assertEquals(Months.from(new MockYearsMonths(2, 3)), Months.of(27)); + assertEquals(Months.of(27), Months.from(new MockYearsMonths(2, 3))); } + @Test public void test_from_yearsAndMonths() { - assertEquals(Months.from(Period.of(3, 5, 0)), Months.of(41)); + assertEquals(Months.of(41), Months.from(Period.of(3, 5, 0))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_wrongUnit_noConversion() { - Months.from(Period.ofDays(2)); + assertThrows(DateTimeException.class, () -> Months.from(Period.ofDays(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_null() { - Months.from((TemporalAmount) null); + assertThrows(NullPointerException.class, () -> Months.from((TemporalAmount) null)); } //----------------------------------------------------------------------- - @DataProvider(name = "parseValid") - Object[][] data_valid() { + public static Object[][] data_valid() { return new Object[][] { {"P0M", 0}, {"P1M", 1}, @@ -176,23 +207,25 @@ Object[][] data_valid() { }; } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid(String str, int expectedDays) { - assertEquals(Months.parse(str), Months.of(expectedDays)); + assertEquals(Months.of(expectedDays), Months.parse(str)); } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid_initialPlus(String str, int expectedDays) { - assertEquals(Months.parse("+" + str), Months.of(expectedDays)); + assertEquals(Months.of(expectedDays), Months.parse("+" + str)); } - @Test(dataProvider = "parseValid") + @ParameterizedTest + @MethodSource("data_valid") public void test_parse_CharSequence_valid_initialMinus(String str, int expectedDays) { - assertEquals(Months.parse("-" + str), Months.of(-expectedDays)); + assertEquals(Months.of(-expectedDays), Months.parse("-" + str)); } - @DataProvider(name = "parseInvalid") - Object[][] data_invalid() { + public static Object[][] data_invalid() { return new Object[][] { {"P3W"}, {"P3D"}, @@ -209,17 +242,46 @@ Object[][] data_invalid() { }; } - @Test(expectedExceptions = DateTimeParseException.class, dataProvider = "parseInvalid") + @ParameterizedTest + @MethodSource("data_invalid") public void test_parse_CharSequence_invalid(String str) { - Months.parse(str); + assertThrows(DateTimeParseException.class, () -> Months.parse(str)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequence_null() { - Months.parse((CharSequence) null); + assertThrows(NullPointerException.class, () -> Months.parse((CharSequence) null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_between() { + assertEquals(Months.of(24), Months.between(LocalDate.of(2019, 1, 1), LocalDate.of(2021, 1, 1))); + } + + @Test + public void test_between_date_null() { + assertThrows(NullPointerException.class, () -> Months.between(LocalDate.now(), (Temporal) null)); + } + + @Test + public void test_between_null_date() { + assertThrows(NullPointerException.class, () -> Months.between((Temporal) null, LocalDate.now())); } //----------------------------------------------------------------------- + @Test + public void test_get() { + assertEquals(6, Months.of(6).get(ChronoUnit.MONTHS)); + } + + @Test + public void test_get_invalidType() { + assertThrows(DateTimeException.class, () -> Months.of(6).get(IsoFields.QUARTER_YEARS)); + } + + //----------------------------------------------------------------------- + @Test public void test_plus_TemporalAmount_Months() { Months test5 = Months.of(5); assertEquals(Months.of(5), test5.plus(Months.of(0))); @@ -229,6 +291,7 @@ public void test_plus_TemporalAmount_Months() { assertEquals(Months.of(Integer.MIN_VALUE), Months.of(Integer.MIN_VALUE + 1).plus(Months.of(-1))); } + @Test public void test_plus_TemporalAmount_Period() { Months test5 = Months.of(5); assertEquals(Months.of(5), test5.plus(Period.ofMonths(0))); @@ -238,32 +301,33 @@ public void test_plus_TemporalAmount_Period() { assertEquals(Months.of(Integer.MIN_VALUE), Months.of(Integer.MIN_VALUE + 1).plus(Period.ofMonths(-1))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_TemporalAmount_PeriodDays() { - Months.of(1).plus(Period.ofDays(2)); + assertThrows(DateTimeException.class, () -> Months.of(1).plus(Period.ofDays(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_TemporalAmount_Duration() { - Months.of(1).plus(Duration.ofHours(2)); + assertThrows(DateTimeException.class, () -> Months.of(1).plus(Duration.ofHours(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooBig() { - Months.of(Integer.MAX_VALUE - 1).plus(Months.of(2)); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MAX_VALUE - 1).plus(Months.of(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooSmall() { - Months.of(Integer.MIN_VALUE + 1).plus(Months.of(-2)); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MIN_VALUE + 1).plus(Months.of(-2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_plus_TemporalAmount_null() { - Months.of(Integer.MIN_VALUE + 1).plus(null); + assertThrows(NullPointerException.class, () -> Months.of(Integer.MIN_VALUE + 1).plus(null)); } //----------------------------------------------------------------------- + @Test public void test_plus_int() { Months test5 = Months.of(5); assertEquals(Months.of(5), test5.plus(0)); @@ -273,17 +337,18 @@ public void test_plus_int() { assertEquals(Months.of(Integer.MIN_VALUE), Months.of(Integer.MIN_VALUE + 1).plus(-1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooBig() { - Months.of(Integer.MAX_VALUE - 1).plus(2); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MAX_VALUE - 1).plus(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooSmall() { - Months.of(Integer.MIN_VALUE + 1).plus(-2); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MIN_VALUE + 1).plus(-2)); } //----------------------------------------------------------------------- + @Test public void test_minus_TemporalAmount_Months() { Months test5 = Months.of(5); assertEquals(Months.of(5), test5.minus(Months.of(0))); @@ -293,6 +358,7 @@ public void test_minus_TemporalAmount_Months() { assertEquals(Months.of(Integer.MIN_VALUE), Months.of(Integer.MIN_VALUE + 1).minus(Months.of(1))); } + @Test public void test_minus_TemporalAmount_Period() { Months test5 = Months.of(5); assertEquals(Months.of(5), test5.minus(Period.ofMonths(0))); @@ -302,32 +368,33 @@ public void test_minus_TemporalAmount_Period() { assertEquals(Months.of(Integer.MIN_VALUE), Months.of(Integer.MIN_VALUE + 1).minus(Period.ofMonths(1))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_TemporalAmount_PeriodDays() { - Months.of(1).minus(Period.ofDays(2)); + assertThrows(DateTimeException.class, () -> Months.of(1).minus(Period.ofDays(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_TemporalAmount_Duration() { - Months.of(1).minus(Duration.ofHours(2)); + assertThrows(DateTimeException.class, () -> Months.of(1).minus(Duration.ofHours(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooBig() { - Months.of(Integer.MAX_VALUE - 1).minus(Months.of(-2)); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MAX_VALUE - 1).minus(Months.of(-2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooSmall() { - Months.of(Integer.MIN_VALUE + 1).minus(Months.of(2)); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MIN_VALUE + 1).minus(Months.of(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_minus_TemporalAmount_null() { - Months.of(Integer.MIN_VALUE + 1).minus(null); + assertThrows(NullPointerException.class, () -> Months.of(Integer.MIN_VALUE + 1).minus(null)); } //----------------------------------------------------------------------- + @Test public void test_minus_int() { Months test5 = Months.of(5); assertEquals(Months.of(5), test5.minus(0)); @@ -337,17 +404,18 @@ public void test_minus_int() { assertEquals(Months.of(Integer.MIN_VALUE), Months.of(Integer.MIN_VALUE + 1).minus(1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooBig() { - Months.of(Integer.MAX_VALUE - 1).minus(-2); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MAX_VALUE - 1).minus(-2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooSmall() { - Months.of(Integer.MIN_VALUE + 1).minus(2); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MIN_VALUE + 1).minus(2)); } //----------------------------------------------------------------------- + @Test public void test_multipliedBy() { Months test5 = Months.of(5); assertEquals(Months.of(0), test5.multipliedBy(0)); @@ -357,22 +425,24 @@ public void test_multipliedBy() { assertEquals(Months.of(-15), test5.multipliedBy(-3)); } + @Test public void test_multipliedBy_negate() { Months test5 = Months.of(5); assertEquals(Months.of(-15), test5.multipliedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooBig() { - Months.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooSmall() { - Months.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2)); } //----------------------------------------------------------------------- + @Test public void test_dividedBy() { Months test12 = Months.of(12); assertEquals(Months.of(12), test12.dividedBy(1)); @@ -384,17 +454,19 @@ public void test_dividedBy() { assertEquals(Months.of(-4), test12.dividedBy(-3)); } + @Test public void test_dividedBy_negate() { Months test12 = Months.of(12); assertEquals(Months.of(-4), test12.dividedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_dividedBy_divideByZero() { - Months.of(1).dividedBy(0); + assertThrows(ArithmeticException.class, () -> Months.of(1).dividedBy(0)); } //----------------------------------------------------------------------- + @Test public void test_negated() { assertEquals(Months.of(0), Months.of(0).negated()); assertEquals(Months.of(-12), Months.of(12).negated()); @@ -402,12 +474,13 @@ public void test_negated() { assertEquals(Months.of(-Integer.MAX_VALUE), Months.of(Integer.MAX_VALUE).negated()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_negated_overflow() { - Months.of(Integer.MIN_VALUE).negated(); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MIN_VALUE).negated()); } //----------------------------------------------------------------------- + @Test public void test_abs() { assertEquals(Months.of(0), Months.of(0).abs()); assertEquals(Months.of(12), Months.of(12).abs()); @@ -416,19 +489,34 @@ public void test_abs() { assertEquals(Months.of(Integer.MAX_VALUE), Months.of(-Integer.MAX_VALUE).abs()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_abs_overflow() { - Months.of(Integer.MIN_VALUE).abs(); + assertThrows(ArithmeticException.class, () -> Months.of(Integer.MIN_VALUE).abs()); } //----------------------------------------------------------------------- + @Test + public void test_addTo() { + assertEquals(LocalDate.of(2019, 1, 10), Months.of(0).addTo(LocalDate.of(2019, 1, 10))); + assertEquals(LocalDate.of(2019, 6, 10), Months.of(5).addTo(LocalDate.of(2019, 1, 10))); + } + + @Test + public void test_subtractFrom() { + assertEquals(LocalDate.of(2019, 1, 10), Months.of(0).subtractFrom(LocalDate.of(2019, 1, 10))); + assertEquals(LocalDate.of(2018, 8, 10), Months.of(5).subtractFrom(LocalDate.of(2019, 1, 10))); + } + + //----------------------------------------------------------------------- + @Test public void test_toPeriod() { for (int i = -20; i < 20; i++) { - assertEquals(Months.of(i).toPeriod(), Period.ofMonths(i)); + assertEquals(Period.ofMonths(i), Months.of(i).toPeriod()); } } //----------------------------------------------------------------------- + @Test public void test_compareTo() { Months test5 = Months.of(5); Months test6 = Months.of(6); @@ -437,40 +525,23 @@ public void test_compareTo() { assertEquals(1, test6.compareTo(test5)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_null() { Months test5 = Months.of(5); - test5.compareTo(null); + assertThrows(NullPointerException.class, () -> test5.compareTo(null)); } //----------------------------------------------------------------------- - public void test_equals() { - Months test5 = Months.of(5); - Months test6 = Months.of(6); - assertEquals(true, test5.equals(test5)); - assertEquals(false, test5.equals(test6)); - assertEquals(false, test6.equals(test5)); - } - - public void test_equals_null() { - Months test5 = Months.of(5); - assertEquals(false, test5.equals(null)); - } - - public void test_equals_otherClass() { - Months test5 = Months.of(5); - assertEquals(false, test5.equals("")); - } - - //----------------------------------------------------------------------- - public void test_hashCode() { - Months test5 = Months.of(5); - Months test6 = Months.of(6); - assertEquals(true, test5.hashCode() == test5.hashCode()); - assertEquals(false, test5.hashCode() == test6.hashCode()); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Months.of(5), Months.of(5)) + .addEqualityGroup(Months.of(6), Months.of(6)) + .testEquals(); } //----------------------------------------------------------------------- + @Test public void test_toString() { Months test5 = Months.of(5); assertEquals("P5M", test5.toString()); diff --git a/src/test/java/org/threeten/extra/TestMutableClock.java b/src/test/java/org/threeten/extra/TestMutableClock.java new file mode 100644 index 00000000..f4b01e95 --- /dev/null +++ b/src/test/java/org/threeten/extra/TestMutableClock.java @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.time.DayOfWeek; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Period; +import java.time.Year; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAdjusters; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; + +import com.google.common.testing.EqualsTester; + +/** + * Test class. + */ +public class TestMutableClock { + + @Test + public void test_of() { + assertEquals( + Instant.EPOCH, + MutableClock.of(Instant.EPOCH, ZoneOffset.UTC).instant()); + assertEquals( + Instant.MIN, + MutableClock.of(Instant.MIN, ZoneOffset.UTC).instant()); + assertEquals( + Instant.MAX, + MutableClock.of(Instant.MAX, ZoneOffset.UTC).instant()); + assertEquals( + ZoneOffset.UTC, + MutableClock.of(Instant.EPOCH, ZoneOffset.UTC).getZone()); + assertEquals( + ZoneOffset.MIN, + MutableClock.of(Instant.EPOCH, ZoneOffset.MIN).getZone()); + assertEquals( + ZoneOffset.MAX, + MutableClock.of(Instant.EPOCH, ZoneOffset.MAX).getZone()); + } + + @Test + public void test_of_nullInstant() { + assertThrows(NullPointerException.class, () -> MutableClock.of(null, ZoneOffset.UTC)); + } + + @Test + public void test_of_nullZone() { + assertThrows(NullPointerException.class, () -> MutableClock.of(Instant.EPOCH, null)); + } + + @Test + public void test_epochUTC() { + assertEquals(Instant.EPOCH, MutableClock.epochUTC().instant()); + assertEquals(ZoneOffset.UTC, MutableClock.epochUTC().getZone()); + } + + @Test + public void test_setInstant() { + MutableClock clock = MutableClock.epochUTC(); + assertEquals(Instant.EPOCH, clock.instant()); + clock.setInstant(Instant.MIN); + assertEquals(Instant.MIN, clock.instant()); + clock.setInstant(Instant.MAX); + assertEquals(Instant.MAX, clock.instant()); + clock.setInstant(Instant.EPOCH.plusSeconds(10)); + assertEquals(Instant.EPOCH.plusSeconds(10), clock.instant()); + } + + @Test + public void test_setInstant_null() { + assertThrows(NullPointerException.class, () -> MutableClock.epochUTC().setInstant(null)); + } + + @Test + public void test_add_amountOnly() { + MutableClock clock = MutableClock.epochUTC(); + clock.add(Duration.ofNanos(3)); + clock.add(Period.ofMonths(2)); + clock.add(Duration.ofSeconds(-5)); + clock.add(Period.ofWeeks(-7)); + clock.add(Duration.ZERO); + clock.add(Period.ZERO); + assertEquals( + ZonedDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC) + .plusNanos(3) + .plusMonths(2) + .minusSeconds(5) + .minusWeeks(7) + .toInstant(), + clock.instant()); + } + + @Test + public void test_add_amountOnly_null() { + assertThrows(NullPointerException.class, () -> MutableClock.epochUTC().add(null)); + } + + @Test + public void test_add_amountAndUnit() { + MutableClock clock = MutableClock.epochUTC(); + clock.add(3, ChronoUnit.NANOS); + clock.add(2, ChronoUnit.MONTHS); + clock.add(-5, ChronoUnit.SECONDS); + clock.add(-7, ChronoUnit.WEEKS); + clock.add(0, ChronoUnit.MILLIS); + clock.add(0, ChronoUnit.YEARS); + assertEquals( + ZonedDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC) + .plusNanos(3) + .plusMonths(2) + .minusSeconds(5) + .minusWeeks(7) + .toInstant(), + clock.instant()); + } + + @Test + public void test_add_amountAndUnit_nullUnit() { + assertThrows(NullPointerException.class, () -> MutableClock.epochUTC().add(0, null)); + } + + @Test + public void test_set_adjuster() { + MutableClock clock = MutableClock.epochUTC(); + clock.set(LocalDate.of(0, 1, 2)); + clock.set(LocalTime.of(3, 4, 5)); + clock.set(TemporalAdjusters.firstDayOfNextMonth()); + clock.set(TemporalAdjusters.next(DayOfWeek.WEDNESDAY)); + assertEquals( + LocalDateTime.of(0, 1, 2, 3, 4, 5) + .with(TemporalAdjusters.firstDayOfNextMonth()) + .with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY)) + .atZone(ZoneOffset.UTC) + .toInstant(), + clock.instant()); + clock.set(Instant.EPOCH); + assertEquals(Instant.EPOCH, clock.instant()); + } + + @Test + public void test_set_adjuster_null() { + assertThrows(NullPointerException.class, () -> MutableClock.epochUTC().set(null)); + } + + @Test + public void test_set_fieldAndValue() { + MutableClock clock = MutableClock.epochUTC(); + clock.set(ChronoField.YEAR, 0); + clock.set(ChronoField.MONTH_OF_YEAR, 1); + clock.set(ChronoField.DAY_OF_MONTH, 2); + clock.set(ChronoField.HOUR_OF_DAY, 3); + clock.set(ChronoField.MINUTE_OF_HOUR, 4); + clock.set(ChronoField.SECOND_OF_MINUTE, 5); + assertEquals( + LocalDateTime.of(0, 1, 2, 3, 4, 5) + .atZone(ZoneOffset.UTC) + .toInstant(), + clock.instant()); + } + + @Test + public void test_set_fieldAndValue_nullField() { + assertThrows(NullPointerException.class, () -> MutableClock.epochUTC().set(null, 0)); + } + + @Test + public void test_getZone() { + MutableClock clock = MutableClock.epochUTC(); + MutableClock withOtherZone = clock.withZone(ZoneOffset.MIN); + MutableClock ofOtherZone = MutableClock.of(Instant.EPOCH, ZoneOffset.MAX); + assertEquals(ZoneOffset.UTC, clock.getZone()); + assertEquals(ZoneOffset.MIN, withOtherZone.getZone()); + assertEquals(ZoneOffset.MAX, ofOtherZone.getZone()); + } + + @Test + public void test_withZone() { + MutableClock clock = MutableClock.epochUTC(); + MutableClock withOtherZone = clock.withZone(ZoneOffset.MIN); + MutableClock withSameZone = withOtherZone.withZone(ZoneOffset.UTC); + clock.setInstant(Instant.MIN); + assertEquals(Instant.MIN, withOtherZone.instant()); + assertEquals(Instant.MIN, withSameZone.instant()); + assertEquals(ZoneOffset.MIN, withOtherZone.getZone()); + assertEquals(ZoneOffset.UTC, withSameZone.getZone()); + assertNotEquals(clock, withOtherZone); + assertEquals(clock, withSameZone); + } + + @Test + public void test_withZone_null() { + assertThrows(NullPointerException.class, () -> MutableClock.epochUTC().withZone(null)); + } + + @Test + public void test_instant() { + MutableClock clock = MutableClock.epochUTC(); + MutableClock withOtherZone = clock.withZone(ZoneOffset.MIN); + assertEquals(Instant.EPOCH, clock.instant()); + clock.add(Duration.ofSeconds(5)); + assertEquals(Instant.EPOCH.plusSeconds(5), clock.instant()); + clock.setInstant(Instant.MIN); + assertEquals(Instant.MIN, clock.instant()); + assertEquals(Instant.MIN, withOtherZone.instant()); + } + + @Test + public void test_equals() { + MutableClock clock = MutableClock.epochUTC(); + MutableClock withOtherZone = clock.withZone(ZoneOffset.MIN); + MutableClock withSameZone = withOtherZone.withZone(ZoneOffset.UTC); + MutableClock independent = MutableClock.epochUTC(); + new EqualsTester() + .addEqualityGroup(clock, clock, withSameZone) + .addEqualityGroup(withOtherZone) + .addEqualityGroup(independent) + .testEquals(); + } + + @Test + public void test_hashCode_isConstant() { + MutableClock clock = MutableClock.epochUTC(); + int hash = clock.hashCode(); + clock.add(Period.ofMonths(1)); + assertEquals(hash, clock.hashCode()); + clock.add(1, ChronoUnit.DAYS); + assertEquals(hash, clock.hashCode()); + clock.set(Year.of(2000)); + assertEquals(hash, clock.hashCode()); + clock.set(ChronoField.INSTANT_SECONDS, -1); + assertEquals(hash, clock.hashCode()); + } + + @Test + public void test_hashCode_sameWhenSharedUpdates() { + MutableClock clock = MutableClock.epochUTC(); + MutableClock withOtherZone = clock.withZone(ZoneOffset.MIN); + MutableClock withSameZone = withOtherZone.withZone(ZoneOffset.UTC); + assertEquals(clock.hashCode(), withSameZone.hashCode()); + } + + @Test + public void test_toString() { + MutableClock clock = MutableClock.epochUTC(); + assertEquals( + "MutableClock[1970-01-01T00:00:00Z,Z]", + clock.toString()); + clock.add(Period.ofYears(30)); + assertEquals( + "MutableClock[2000-01-01T00:00:00Z,Z]", + clock.toString()); + MutableClock withOtherZone = clock.withZone(ZoneOffset.MIN); + assertEquals( + "MutableClock[2000-01-01T00:00:00Z,-18:00]", + withOtherZone.toString()); + } + + @Test + public void test_isSerializable() { + assertTrue(Serializable.class.isAssignableFrom(MutableClock.class)); + } + + @Test + public void test_serialization() throws Exception { + MutableClock test = MutableClock.epochUTC(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + MutableClock ser = (MutableClock) ois.readObject(); + assertEquals(test.instant(), ser.instant()); + assertEquals(test.getZone(), ser.getZone()); + // no shared updates + assertNotEquals(ser, test); + test.add(Duration.ofSeconds(1)); + assertNotEquals(ser.instant(), test.instant()); + } + } + + @Test + public void test_updatesAreAtomic() throws Exception { + MutableClock clock = MutableClock.epochUTC(); + Duration increment = Duration.ofSeconds(1); + Callable applyOneUpdate = () -> { + clock.add(increment); + return null; + }; + int updateCount = 10000; + List> tasks = Collections.nCopies(updateCount, applyOneUpdate); + int threads = Runtime.getRuntime().availableProcessors() * 4; + ExecutorService service = Executors.newFixedThreadPool(threads); + try { + service.invokeAll(tasks); + service.shutdown(); + service.awaitTermination(1, TimeUnit.MINUTES); + } finally { + if (!service.isTerminated()) { + service.shutdownNow(); + } + } + assertEquals( + Instant.EPOCH.plus(increment.multipliedBy(updateCount)), + clock.instant()); + } +} diff --git a/src/test/java/org/threeten/extra/TestOffsetDate.java b/src/test/java/org/threeten/extra/TestOffsetDate.java new file mode 100644 index 00000000..7095e3f5 --- /dev/null +++ b/src/test/java/org/threeten/extra/TestOffsetDate.java @@ -0,0 +1,1873 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.Month.DECEMBER; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.Period; +import java.time.Year; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.JulianFields; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junitpioneer.jupiter.RetryingTest; + +import com.google.common.testing.EqualsTester; + +/** + * Test OffsetDate. + */ +public class TestOffsetDate extends AbstractDateTimeTest { + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + + private OffsetDate TEST_2007_07_15_PONE; + + @BeforeEach + public void setUp() { + TEST_2007_07_15_PONE = OffsetDate.of(2007, 7, 15, OFFSET_PONE); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_2007_07_15_PONE, OffsetDate.MIN, OffsetDate.MAX}; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + DAY_OF_WEEK, + ALIGNED_DAY_OF_WEEK_IN_MONTH, + ALIGNED_DAY_OF_WEEK_IN_YEAR, + DAY_OF_MONTH, + DAY_OF_YEAR, + EPOCH_DAY, + ALIGNED_WEEK_OF_MONTH, + ALIGNED_WEEK_OF_YEAR, + MONTH_OF_YEAR, + PROLEPTIC_MONTH, + YEAR_OF_ERA, + YEAR, + ERA, + OFFSET_SECONDS, + JulianFields.JULIAN_DAY, + JulianFields.MODIFIED_JULIAN_DAY, + JulianFields.RATA_DIE, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + return list; + } + + //----------------------------------------------------------------------- + // constants + //----------------------------------------------------------------------- + @Test + public void constant_MIN() { + check(OffsetDate.MIN, Year.MIN_VALUE, 1, 1, ZoneOffset.MAX); + } + + @Test + public void constant_MAX() { + check(OffsetDate.MAX, Year.MAX_VALUE, 12, 31, ZoneOffset.MIN); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @RetryingTest(100) + public void now() { + assertEquals(OffsetDate.now(Clock.systemDefaultZone()), OffsetDate.now()); + } + + @Test + public void now_Clock_allSecsInDay_utc() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + OffsetDate test = OffsetDate.now(clock); + check(test, 1970, 1, (i < 24 * 60 * 60 ? 1 : 2), ZoneOffset.UTC); + } + } + + @Test + public void now_Clock_allSecsInDay_beforeEpoch() { + for (int i =-1; i >= -(2 * 24 * 60 * 60); i--) { + Instant instant = Instant.ofEpochSecond(i); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + OffsetDate test = OffsetDate.now(clock); + check(test, 1969, 12, (i >= -24 * 60 * 60 ? 31 : 30), ZoneOffset.UTC); + } + } + + @Test + public void now_Clock_offsets() { + Instant base = LocalDateTime.of(1970, 1, 1, 12, 0).toInstant(ZoneOffset.UTC); + for (int i = -9; i < 15; i++) { + ZoneOffset offset = ZoneOffset.ofHours(i); + Clock clock = Clock.fixed(base, offset); + OffsetDate test = OffsetDate.now(clock); + check(test, 1970, 1, (i >= 12 ? 2 : 1), offset); + } + } + + @Test + public void now_Clock_nullZoneId() { + assertThrows(NullPointerException.class, () -> OffsetDate.now((ZoneId) null)); + } + + @Test + public void now_Clock_nullClock() { + assertThrows(NullPointerException.class, () -> OffsetDate.now((Clock) null)); + } + + //----------------------------------------------------------------------- + // factories + //----------------------------------------------------------------------- + private void check(OffsetDate test, int y, int mo, int d, ZoneOffset offset) { + assertEquals(LocalDate.of(y, mo, d), test.toLocalDate()); + assertEquals(offset, test.getOffset()); + + assertEquals(y, test.getYear()); + assertEquals(mo, test.getMonth().getValue()); + assertEquals(d, test.getDayOfMonth()); + + assertEquals(test, test); + assertEquals(test.hashCode(), test.hashCode()); + assertEquals(test, OffsetDate.of(y, mo, d, offset)); + assertEquals(test, OffsetDate.of(LocalDate.of(y, mo, d), offset)); + } + + //----------------------------------------------------------------------- + @Test + public void factory_of_intsOffset() { + OffsetDate test = OffsetDate.of(2007, 7, 15, OFFSET_PONE); + check(test, 2007, 7, 15, OFFSET_PONE); + } + + @Test + public void factory_of_ints_dayTooLow() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(2007, 1, 0, OFFSET_PONE)); + } + + @Test + public void factory_of_ints_dayTooHigh() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(2007, 1, 32, OFFSET_PONE)); + } + + @Test + public void factory_of_ints_monthTooLow() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(2007, 0, 1, OFFSET_PONE)); + } + + @Test + public void factory_of_ints_monthTooHigh() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(2007, 13, 1, OFFSET_PONE)); + } + + @Test + public void factory_of_ints_yearTooLow() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Integer.MIN_VALUE, 1, 1, OFFSET_PONE)); + } + + @Test + public void factory_of_ints_nullOffset() { + assertThrows(NullPointerException.class, () -> OffsetDate.of(2007, 1, 1, (ZoneOffset) null)); + } + + //----------------------------------------------------------------------- + @Test + public void factory_of_LocalDateZoneOffset() { + LocalDate localDate = LocalDate.of(2008, 6, 30); + OffsetDate test = OffsetDate.of(localDate, OFFSET_PONE); + check(test, 2008, 6, 30, OFFSET_PONE); + } + + @Test + public void factory_of_LocalDateZoneOffset_nullDate() { + assertThrows(NullPointerException.class, () -> OffsetDate.of((LocalDate) null, OFFSET_PONE)); + } + + @Test + public void factory_of_LocalDateZoneOffset_nullOffset() { + LocalDate localDate = LocalDate.of(2008, 6, 30); + assertThrows(NullPointerException.class, () -> OffsetDate.of(localDate, (ZoneOffset) null)); + } + + //----------------------------------------------------------------------- + // from(TemporalAccessor) + //----------------------------------------------------------------------- + @Test + public void test_from_TemporalAccessor_OD() { + assertEquals(TEST_2007_07_15_PONE, OffsetDate.from(TEST_2007_07_15_PONE)); + } + + @Test + public void test_from_TemporalAccessor_ZDT() { + ZonedDateTime base = LocalDateTime.of(2007, 7, 15, 17, 30).atZone(OFFSET_PONE); + assertEquals(TEST_2007_07_15_PONE, OffsetDate.from(base)); + } + + @Test + public void test_from_TemporalAccessor_invalid_noDerive() { + assertThrows(DateTimeException.class, () -> OffsetDate.from(LocalTime.of(12, 30))); + } + + @Test + public void test_from_TemporalAccessor_null() { + assertThrows(NullPointerException.class, () -> OffsetDate.from((TemporalAccessor) null)); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @ParameterizedTest + @MethodSource("data_sampleToString") + public void factory_parse_validText(int y, int m, int d, String offsetId, String parsable) { + OffsetDate t = OffsetDate.parse(parsable); + assertNotNull(t, parsable); + assertEquals(y, t.getYear(), parsable); + assertEquals(m, t.getMonth().getValue(), parsable); + assertEquals(d, t.getDayOfMonth(), parsable); + assertEquals(ZoneOffset.of(offsetId), t.getOffset()); + } + + public static Object[][] data_sampleBadParse() { + return new Object[][]{ + {"2008/07/05"}, + {"10000-01-01"}, + {"2008-1-1"}, + {"2008--01"}, + {"ABCD-02-01"}, + {"2008-AB-01"}, + {"2008-02-AB"}, + {"-0000-02-01"}, + {"2008-02-01Y"}, + {"2008-02-01+19:00"}, + {"2008-02-01+01/00"}, + {"2008-02-01+1900"}, + {"2008-02-01+01:60"}, + {"2008-02-01+01:30:123"}, + {"2008-02-01"}, + {"2008-02-01+01:00[Europe/Paris]"}, + }; + } + + @ParameterizedTest + @MethodSource("data_sampleBadParse") + public void factory_parse_invalidText(String unparsable) { + assertThrows(DateTimeParseException.class, () -> OffsetDate.parse(unparsable)); + } + + @Test + public void factory_parse_illegalValue() { + assertThrows(DateTimeParseException.class, () -> OffsetDate.parse("2008-06-32+01:00")); + } + + @Test + public void factory_parse_invalidValue() { + assertThrows(DateTimeParseException.class, () -> OffsetDate.parse("2008-06-31+01:00")); + } + + @Test + public void factory_parse_nullText() { + assertThrows(NullPointerException.class, () -> OffsetDate.parse((String) null)); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d XXX"); + OffsetDate test = OffsetDate.parse("2010 12 3 +01:00", f); + assertEquals(OffsetDate.of(2010, 12, 3, ZoneOffset.ofHours(1)), test); + } + + @Test + public void factory_parse_formatter_nullText() { + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d"); + assertThrows(NullPointerException.class, () -> OffsetDate.parse((String) null, f)); + } + + @Test + public void factory_parse_formatter_nullFormatter() { + assertThrows(NullPointerException.class, () -> OffsetDate.parse("ANY", null)); + } + + //----------------------------------------------------------------------- + // constructor + //----------------------------------------------------------------------- + @Test + public void constructor_nullDate() throws Throwable { + Constructor con = OffsetDate.class.getDeclaredConstructor(LocalDate.class, ZoneOffset.class); + con.setAccessible(true); + InvocationTargetException thrown = assertThrows(InvocationTargetException.class, () -> con.newInstance(null, OFFSET_PONE)); + assertInstanceOf(NullPointerException.class, thrown.getCause()); + } + + @Test + public void constructor_nullOffset() throws Throwable { + Constructor con = OffsetDate.class.getDeclaredConstructor(LocalDate.class, ZoneOffset.class); + con.setAccessible(true); + InvocationTargetException thrown = assertThrows(InvocationTargetException.class, () -> con.newInstance(LocalDate.of(2008, 6, 30), null)); + assertInstanceOf(NullPointerException.class, thrown.getCause()); + } + + //----------------------------------------------------------------------- + // basics + //----------------------------------------------------------------------- + public static Object[][] data_sampleDates() { + return new Object[][] { + {2008, 7, 5, OFFSET_PONE}, + {2008, 7, 5, OFFSET_PTWO}, + {2007, 7, 5, OFFSET_PONE}, + {2007, 7, 5, OFFSET_PTWO}, + {2007, 6, 5, OFFSET_PONE}, + {2007, 6, 5, OFFSET_PTWO}, + {2007, 6, 4, OFFSET_PONE}, + {2007, 6, 4, OFFSET_PTWO}, + {-1, 1, 2, OFFSET_PONE}, + {999999, 11, 20, ZoneOffset.ofHoursMinutesSeconds(6, 9, 12)}, + }; + } + + @ParameterizedTest + @MethodSource("data_sampleDates") + public void test_get_OffsetDate(int y, int m, int d, ZoneOffset offset) { + LocalDate localDate = LocalDate.of(y, m, d); + OffsetDate a = OffsetDate.of(localDate, offset); + + assertEquals(localDate, a.toLocalDate()); + assertEquals(offset, a.getOffset()); + assertEquals(localDate.toString() + offset.toString(), a.toString()); + assertEquals(localDate.getYear(), a.getYear()); + assertEquals(localDate.getMonth(), a.getMonth()); + assertEquals(localDate.getDayOfMonth(), a.getDayOfMonth()); + assertEquals(localDate.getDayOfYear(), a.getDayOfYear()); + assertEquals(localDate.getDayOfWeek(), a.getDayOfWeek()); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertFalse(TEST_2007_07_15_PONE.isSupported((TemporalUnit) null)); + assertFalse(TEST_2007_07_15_PONE.isSupported(ChronoUnit.NANOS)); + assertFalse(TEST_2007_07_15_PONE.isSupported(ChronoUnit.MICROS)); + assertFalse(TEST_2007_07_15_PONE.isSupported(ChronoUnit.MILLIS)); + assertFalse(TEST_2007_07_15_PONE.isSupported(ChronoUnit.SECONDS)); + assertFalse(TEST_2007_07_15_PONE.isSupported(ChronoUnit.MINUTES)); + assertFalse(TEST_2007_07_15_PONE.isSupported(ChronoUnit.HOURS)); + assertFalse(TEST_2007_07_15_PONE.isSupported(ChronoUnit.HALF_DAYS)); + assertTrue(TEST_2007_07_15_PONE.isSupported(ChronoUnit.DAYS)); + assertTrue(TEST_2007_07_15_PONE.isSupported(ChronoUnit.WEEKS)); + assertTrue(TEST_2007_07_15_PONE.isSupported(ChronoUnit.MONTHS)); + assertTrue(TEST_2007_07_15_PONE.isSupported(ChronoUnit.YEARS)); + assertTrue(TEST_2007_07_15_PONE.isSupported(ChronoUnit.DECADES)); + assertTrue(TEST_2007_07_15_PONE.isSupported(ChronoUnit.CENTURIES)); + assertTrue(TEST_2007_07_15_PONE.isSupported(ChronoUnit.MILLENNIA)); + assertTrue(TEST_2007_07_15_PONE.isSupported(ChronoUnit.ERAS)); + assertFalse(TEST_2007_07_15_PONE.isSupported(ChronoUnit.FOREVER)); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + OffsetDate test = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + assertEquals(2008, test.get(ChronoField.YEAR)); + assertEquals(6, test.get(ChronoField.MONTH_OF_YEAR)); + assertEquals(30, test.get(ChronoField.DAY_OF_MONTH)); + assertEquals(1, test.get(ChronoField.DAY_OF_WEEK)); + assertEquals(182, test.get(ChronoField.DAY_OF_YEAR)); + + assertEquals(3600, test.get(ChronoField.OFFSET_SECONDS)); + } + + @Test + public void test_getLong_TemporalField() { + OffsetDate test = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + assertEquals(2008, test.getLong(ChronoField.YEAR)); + assertEquals(6, test.getLong(ChronoField.MONTH_OF_YEAR)); + assertEquals(30, test.getLong(ChronoField.DAY_OF_MONTH)); + assertEquals(1, test.getLong(ChronoField.DAY_OF_WEEK)); + assertEquals(182, test.getLong(ChronoField.DAY_OF_YEAR)); + + assertEquals(3600, test.getLong(ChronoField.OFFSET_SECONDS)); + } + + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @Test + public void test_query_chrono() { + assertEquals(IsoChronology.INSTANCE, TEST_2007_07_15_PONE.query(TemporalQueries.chronology())); + assertEquals(IsoChronology.INSTANCE, TemporalQueries.chronology().queryFrom(TEST_2007_07_15_PONE)); + } + + @Test + public void test_query_zoneId() { + assertNull(TEST_2007_07_15_PONE.query(TemporalQueries.zoneId())); + assertNull(TemporalQueries.zoneId().queryFrom(TEST_2007_07_15_PONE)); + } + + @Test + public void test_query_precision() { + assertEquals(ChronoUnit.DAYS, TEST_2007_07_15_PONE.query(TemporalQueries.precision())); + assertEquals(ChronoUnit.DAYS, TemporalQueries.precision().queryFrom(TEST_2007_07_15_PONE)); + } + + @Test + public void test_query_offset() { + assertEquals(OFFSET_PONE, TEST_2007_07_15_PONE.query(TemporalQueries.offset())); + assertEquals(OFFSET_PONE, TemporalQueries.offset().queryFrom(TEST_2007_07_15_PONE)); + } + + @Test + public void test_query_zone() { + assertEquals(OFFSET_PONE, TEST_2007_07_15_PONE.query(TemporalQueries.zone())); + assertEquals(OFFSET_PONE, TemporalQueries.zone().queryFrom(TEST_2007_07_15_PONE)); + } + + @Test + public void test_query_null() { + assertThrows(NullPointerException.class, () -> TEST_2007_07_15_PONE.query(null)); + } + + //----------------------------------------------------------------------- + // adjustInto(Temporal) + //----------------------------------------------------------------------- + @Test + public void test_adjustInto() { + OffsetDateTime odt = OffsetDateTime.of(2007, 12, 3, 10, 15, 30, 0, ZoneOffset.UTC); + OffsetDate od = OffsetDate.of(2008, 1, 4, OFFSET_PONE); + OffsetDateTime expected = OffsetDateTime.of(2008, 1, 4, 10, 15, 30, 0, OFFSET_PONE); + assertEquals(expected, od.adjustInto(odt)); + } + + //----------------------------------------------------------------------- + // until(Temporal, TemporalUnit) + //----------------------------------------------------------------------- + public static Object[][] data_until() { + return new Object[][] { + {1, OffsetDate.of(2007, 6, 30, OFFSET_PONE), OffsetDate.of(2007, 7, 1, OFFSET_PONE), ChronoUnit.DAYS}, + {1, OffsetDate.of(2007, 6, 30, OFFSET_PONE), OffsetDate.of(2007, 8, 29, OFFSET_PONE), ChronoUnit.MONTHS}, + {2, OffsetDate.of(2007, 6, 30, OFFSET_PONE), OffsetDate.of(2007, 8, 30, OFFSET_PONE), ChronoUnit.MONTHS}, + {2, OffsetDate.of(2007, 6, 30, OFFSET_PONE), OffsetDate.of(2007, 8, 31, OFFSET_PONE), ChronoUnit.MONTHS} + }; + } + + @ParameterizedTest + @MethodSource("data_until") + public void test_until(long expected, OffsetDate od1, OffsetDate od2, TemporalUnit unit) { + assertEquals(expected, od1.until(od2, unit)); + assertEquals(-expected, od2.until(od1, unit)); + } + + @Test + public void test_until_otherType() { + OffsetDate start = OffsetDate.of(2007, 6, 30, OFFSET_PONE); + Temporal end = OffsetDateTime.of(2007, 8, 31, 12, 0, 0, 0, OFFSET_PONE); + assertEquals(2, start.until(end, ChronoUnit.MONTHS)); + } + + @Test + public void test_until_invalidType() { + OffsetDate od1 = OffsetDate.of(2012, 6, 30, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> od1.until(Instant.ofEpochSecond(7), ChronoUnit.SECONDS)); + } + + //----------------------------------------------------------------------- + // withOffsetSameLocal() + //----------------------------------------------------------------------- + @Test + public void test_withOffsetSameLocal() { + OffsetDate base = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + OffsetDate test = base.withOffsetSameLocal(OFFSET_PTWO); + assertEquals(base.toLocalDate(), test.toLocalDate()); + assertEquals(OFFSET_PTWO, test.getOffset()); + } + + @Test + public void test_withOffsetSameLocal_noChange() { + OffsetDate base = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + OffsetDate test = base.withOffsetSameLocal(OFFSET_PONE); + assertEquals(base, test); + } + + @Test + public void test_withOffsetSameLocal_null() { + assertThrows(NullPointerException.class, () -> TEST_2007_07_15_PONE.withOffsetSameLocal(null)); + } + + //----------------------------------------------------------------------- + // with(WithAdjuster) + //----------------------------------------------------------------------- + @Test + public void test_with_adjustment() { + final OffsetDate sample = OffsetDate.of(2012, 3, 4, OFFSET_PONE); + TemporalAdjuster adjuster = dateTime -> sample; + assertEquals(sample, TEST_2007_07_15_PONE.with(adjuster)); + } + + @Test + public void test_with_adjustment_LocalDate() { + OffsetDate test = TEST_2007_07_15_PONE.with(LocalDate.of(2008, 6, 30)); + assertEquals(OffsetDate.of(2008, 6, 30, OFFSET_PONE), test); + } + + @Test + public void test_with_adjustment_OffsetDate() { + OffsetDate test = TEST_2007_07_15_PONE.with(OffsetDate.of(2008, 6, 30, OFFSET_PTWO)); + assertEquals(OffsetDate.of(2008, 6, 30, OFFSET_PTWO), test); + } + + @Test + public void test_with_adjustment_ZoneOffset() { + OffsetDate test = TEST_2007_07_15_PONE.with(OFFSET_PTWO); + assertEquals(OffsetDate.of(2007, 7, 15, OFFSET_PTWO), test); + } + + @Test + public void test_with_adjustment_Month() { + OffsetDate test = TEST_2007_07_15_PONE.with(DECEMBER); + assertEquals(OffsetDate.of(2007, 12, 15, OFFSET_PONE), test); + } + + @Test + public void test_with_adjustment_offsetUnchanged() { + OffsetDate base = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + OffsetDate test = base.with(Year.of(2008)); + assertEquals(base, test); + } + + @Test + public void test_with_adjustment_noChange() { + LocalDate date = LocalDate.of(2008, 6, 30); + OffsetDate base = OffsetDate.of(date, OFFSET_PONE); + OffsetDate test = base.with(date); + assertEquals(base, test); + } + + @Test + public void test_with_adjustment_null() { + assertThrows(NullPointerException.class, () -> TEST_2007_07_15_PONE.with((TemporalAdjuster) null)); + } + + //----------------------------------------------------------------------- + // with(TemporalField, long) + //----------------------------------------------------------------------- + @Test + public void test_with_TemporalField() { + OffsetDate test = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + assertEquals(OffsetDate.of(2009, 6, 30, OFFSET_PONE), test.with(ChronoField.YEAR, 2009)); + assertEquals(OffsetDate.of(2008, 7, 30, OFFSET_PONE), test.with(ChronoField.MONTH_OF_YEAR, 7)); + assertEquals(OffsetDate.of(2008, 6, 1, OFFSET_PONE), test.with(ChronoField.DAY_OF_MONTH, 1)); + assertEquals(OffsetDate.of(2008, 7, 1, OFFSET_PONE), test.with(ChronoField.DAY_OF_WEEK, 2)); + assertEquals(OffsetDate.of(2008, 7, 1, OFFSET_PONE), test.with(ChronoField.DAY_OF_YEAR, 183)); + + assertEquals(OffsetDate.of(2008, 6, 30, ZoneOffset.ofHoursMinutesSeconds(2, 0, 5)), test.with(ChronoField.OFFSET_SECONDS, 7205)); + } + + @Test + public void test_with_TemporalField_null() { + assertThrows(NullPointerException.class, () -> TEST_2007_07_15_PONE.with((TemporalField) null, 0)); + } + + @Test + public void test_with_TemporalField_invalidField() { + assertThrows(DateTimeException.class, () -> TEST_2007_07_15_PONE.with(ChronoField.AMPM_OF_DAY, 0)); + } + + //----------------------------------------------------------------------- + // withYear() + //----------------------------------------------------------------------- + @Test + public void test_withYear_int_normal() { + OffsetDate t = TEST_2007_07_15_PONE.withYear(2008); + assertEquals(OffsetDate.of(2008, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_withYear_int_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.withYear(2007); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_withYear_int_invalid() { + assertThrows(DateTimeException.class, () -> TEST_2007_07_15_PONE.withYear(Year.MIN_VALUE - 1)); + } + + @Test + public void test_withYear_int_adjustDay() { + OffsetDate t = OffsetDate.of(2008, 2, 29, OFFSET_PONE).withYear(2007); + OffsetDate expected = OffsetDate.of(2007, 2, 28, OFFSET_PONE); + assertEquals(expected, t); + } + + //----------------------------------------------------------------------- + // withMonth() + //----------------------------------------------------------------------- + @Test + public void test_withMonth_int_normal() { + OffsetDate t = TEST_2007_07_15_PONE.withMonth(1); + assertEquals(OffsetDate.of(2007, 1, 15, OFFSET_PONE), t); + } + + @Test + public void test_withMonth_int_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.withMonth(7); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_withMonth_int_invalid() { + assertThrows(DateTimeException.class, () -> TEST_2007_07_15_PONE.withMonth(13)); + } + + @Test + public void test_withMonth_int_adjustDay() { + OffsetDate t = OffsetDate.of(2007, 12, 31, OFFSET_PONE).withMonth(11); + OffsetDate expected = OffsetDate.of(2007, 11, 30, OFFSET_PONE); + assertEquals(expected, t); + } + + //----------------------------------------------------------------------- + // withDayOfMonth() + //----------------------------------------------------------------------- + @Test + public void test_withDayOfMonth_normal() { + OffsetDate t = TEST_2007_07_15_PONE.withDayOfMonth(1); + assertEquals(OffsetDate.of(2007, 7, 1, OFFSET_PONE), t); + } + + @Test + public void test_withDayOfMonth_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.withDayOfMonth(15); + assertEquals(OffsetDate.of(2007, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_withDayOfMonth_invalidForMonth() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(2007, 11, 30, OFFSET_PONE).withDayOfMonth(31)); + } + + @Test + public void test_withDayOfMonth_invalidAlways() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(2007, 11, 30, OFFSET_PONE).withDayOfMonth(32)); + } + + //----------------------------------------------------------------------- + // withDayOfYear(int) + //----------------------------------------------------------------------- + @Test + public void test_withDayOfYear_normal() { + OffsetDate t = TEST_2007_07_15_PONE.withDayOfYear(33); + assertEquals(OffsetDate.of(2007, 2, 2, OFFSET_PONE), t); + } + + @Test + public void test_withDayOfYear_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.withDayOfYear(31 + 28 + 31 + 30 + 31 + 30 + 15); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_withDayOfYear_illegal() { + assertThrows(DateTimeException.class, () -> TEST_2007_07_15_PONE.withDayOfYear(367)); + } + + @Test + public void test_withDayOfYear_invalid() { + assertThrows(DateTimeException.class, () -> TEST_2007_07_15_PONE.withDayOfYear(366)); + } + + //----------------------------------------------------------------------- + // plus(PlusAdjuster) + //----------------------------------------------------------------------- + @Test + public void test_plus_PlusAdjuster() { + MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); + OffsetDate t = TEST_2007_07_15_PONE.plus(period); + assertEquals(OffsetDate.of(2008, 2, 15, OFFSET_PONE), t); + } + + @Test + public void test_plus_PlusAdjuster_noChange() { + MockSimplePeriod period = MockSimplePeriod.of(0, ChronoUnit.MONTHS); + OffsetDate t = TEST_2007_07_15_PONE.plus(period); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plus_PlusAdjuster_zero() { + OffsetDate t = TEST_2007_07_15_PONE.plus(Period.ZERO); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plus_PlusAdjuster_null() { + assertThrows(NullPointerException.class, () -> TEST_2007_07_15_PONE.plus((TemporalAmount) null)); + } + + //----------------------------------------------------------------------- + // plusYears() + //----------------------------------------------------------------------- + @Test + public void test_plusYears_long_normal() { + OffsetDate t = TEST_2007_07_15_PONE.plusYears(1); + assertEquals(OffsetDate.of(2008, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusYears_long_negative() { + OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1); + assertEquals(OffsetDate.of(2006, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusYears_long_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.plusYears(0); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plusYears_long_adjustDay() { + OffsetDate t = OffsetDate.of(2008, 2, 29, OFFSET_PONE).plusYears(1); + OffsetDate expected = OffsetDate.of(2009, 2, 28, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_plusYears_long_big() { + long years = 20L + Year.MAX_VALUE; + OffsetDate test = OffsetDate.of(-40, 6, 1, OFFSET_PONE).plusYears(years); + assertEquals(OffsetDate.of((int) (-40L + years), 6, 1, OFFSET_PONE), test); + } + + @Test + public void test_plusYears_long_invalidTooLarge() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MAX_VALUE, 1, 1, OFFSET_PONE).plusYears(1)); + } + + @Test + public void test_plusYears_long_invalidTooLargeMaxAddMax() { + OffsetDate test = OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> test.plusYears(Long.MAX_VALUE)); + } + + @Test + public void test_plusYears_long_invalidTooLargeMaxAddMin() { + OffsetDate test = OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> test.plusYears(Long.MIN_VALUE)); + } + + @Test + public void test_plusYears_long_invalidTooSmall() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE).plusYears(-1)); + } + + //----------------------------------------------------------------------- + // plusMonths() + //----------------------------------------------------------------------- + @Test + public void test_plusMonths_long_normal() { + OffsetDate t = TEST_2007_07_15_PONE.plusMonths(1); + assertEquals(OffsetDate.of(2007, 8, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusMonths_long_overYears() { + OffsetDate t = TEST_2007_07_15_PONE.plusMonths(25); + assertEquals(OffsetDate.of(2009, 8, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusMonths_long_negative() { + OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-1); + assertEquals(OffsetDate.of(2007, 6, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusMonths_long_negativeAcrossYear() { + OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-7); + assertEquals(OffsetDate.of(2006, 12, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusMonths_long_negativeOverYears() { + OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-31); + assertEquals(OffsetDate.of(2004, 12, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusMonths_long_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.plusMonths(0); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plusMonths_long_adjustDayFromLeapYear() { + OffsetDate t = OffsetDate.of(2008, 2, 29, OFFSET_PONE).plusMonths(12); + OffsetDate expected = OffsetDate.of(2009, 2, 28, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_plusMonths_long_adjustDayFromMonthLength() { + OffsetDate t = OffsetDate.of(2007, 3, 31, OFFSET_PONE).plusMonths(1); + OffsetDate expected = OffsetDate.of(2007, 4, 30, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_plusMonths_long_big() { + long months = 20L + Integer.MAX_VALUE; + OffsetDate test = OffsetDate.of(-40, 6, 1, OFFSET_PONE).plusMonths(months); + assertEquals(OffsetDate.of((int) (-40L + months / 12), 6 + (int) (months % 12), 1, OFFSET_PONE), test); + } + + @Test + public void test_plusMonths_long_invalidTooLarge() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE).plusMonths(1)); + } + + @Test + public void test_plusMonths_long_invalidTooLargeMaxAddMax() { + OffsetDate test = OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> test.plusMonths(Long.MAX_VALUE)); + } + + @Test + public void test_plusMonths_long_invalidTooLargeMaxAddMin() { + OffsetDate test = OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> test.plusMonths(Long.MIN_VALUE)); + } + + @Test + public void test_plusMonths_long_invalidTooSmall() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE).plusMonths(-1)); + } + + //----------------------------------------------------------------------- + // plusWeeks() + //----------------------------------------------------------------------- + public static Object[][] data_samplePlusWeeksSymmetry() { + return new Object[][] { + {OffsetDate.of(-1, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(-1, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(-1, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(-1, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(0, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(0, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(0, 2, 29, OFFSET_PTWO)}, + {OffsetDate.of(0, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(0, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2007, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2007, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2007, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2007, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2008, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2008, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2008, 2, 29, OFFSET_PTWO)}, + {OffsetDate.of(2008, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2008, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2099, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2099, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2099, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2099, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2100, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2100, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2100, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2100, 12, 31, OFFSET_PTWO)}, + }; + } + + @ParameterizedTest + @MethodSource("data_samplePlusWeeksSymmetry") + public void test_plusWeeks_symmetry(OffsetDate reference) { + for (int weeks = 0; weeks < 365 * 8; weeks++) { + OffsetDate t = reference.plusWeeks(weeks).plusWeeks(-weeks); + assertEquals(reference, t); + + t = reference.plusWeeks(-weeks).plusWeeks(weeks); + assertEquals(reference, t); + } + } + + @Test + public void test_plusWeeks_normal() { + OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(1); + assertEquals(OffsetDate.of(2007, 7, 22, OFFSET_PONE), t); + } + + @Test + public void test_plusWeeks_overMonths() { + OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(9); + assertEquals(OffsetDate.of(2007, 9, 16, OFFSET_PONE), t); + } + + @Test + public void test_plusWeeks_overYears() { + OffsetDate t = OffsetDate.of(2006, 7, 16, OFFSET_PONE).plusWeeks(52); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plusWeeks_overLeapYears() { + OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1).plusWeeks(104); + assertEquals(OffsetDate.of(2008, 7, 12, OFFSET_PONE), t); + } + + @Test + public void test_plusWeeks_negative() { + OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-1); + assertEquals(OffsetDate.of(2007, 7, 8, OFFSET_PONE), t); + } + + @Test + public void test_plusWeeks_negativeAcrossYear() { + OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-28); + assertEquals(OffsetDate.of(2006, 12, 31, OFFSET_PONE), t); + } + + @Test + public void test_plusWeeks_negativeOverYears() { + OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-104); + assertEquals(OffsetDate.of(2005, 7, 17, OFFSET_PONE), t); + } + + @Test + public void test_plusWeeks_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(0); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plusWeeks_maximum() { + OffsetDate t = OffsetDate.of(Year.MAX_VALUE, 12, 24, OFFSET_PONE).plusWeeks(1); + OffsetDate expected = OffsetDate.of(Year.MAX_VALUE, 12, 31, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_plusWeeks_minimum() { + OffsetDate t = OffsetDate.of(Year.MIN_VALUE, 1, 8, OFFSET_PONE).plusWeeks(-1); + OffsetDate expected = OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_plusWeeks_invalidTooLarge() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 25, OFFSET_PONE).plusWeeks(1)); + } + + @Test + public void test_plusWeeks_invalidTooSmall() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 7, OFFSET_PONE).plusWeeks(-1)); + } + + @Test + public void test_plusWeeks_invalidMaxMinusMax() { + assertThrows(ArithmeticException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 25, OFFSET_PONE).plusWeeks(Long.MAX_VALUE)); + } + + @Test + public void test_plusWeeks_invalidMaxMinusMin() { + assertThrows(ArithmeticException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 25, OFFSET_PONE).plusWeeks(Long.MIN_VALUE)); + } + + //----------------------------------------------------------------------- + // plusDays() + //----------------------------------------------------------------------- + public static Object[][] data_samplePlusDaysSymmetry() { + return new Object[][] { + {OffsetDate.of(-1, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(-1, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(-1, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(-1, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(0, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(0, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(0, 2, 29, OFFSET_PTWO)}, + {OffsetDate.of(0, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(0, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2007, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2007, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2007, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2007, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2008, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2008, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2008, 2, 29, OFFSET_PTWO)}, + {OffsetDate.of(2008, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2008, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2099, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2099, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2099, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2099, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2100, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2100, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2100, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2100, 12, 31, OFFSET_PTWO)}, + }; + } + + @ParameterizedTest + @MethodSource("data_samplePlusDaysSymmetry") + public void test_plusDays_symmetry(OffsetDate reference) { + for (int days = 0; days < 365 * 8; days++) { + OffsetDate t = reference.plusDays(days).plusDays(-days); + assertEquals(reference, t); + + t = reference.plusDays(-days).plusDays(days); + assertEquals(reference, t); + } + } + + @Test + public void test_plusDays_normal() { + OffsetDate t = TEST_2007_07_15_PONE.plusDays(1); + assertEquals(OffsetDate.of(2007, 7, 16, OFFSET_PONE), t); + } + + @Test + public void test_plusDays_overMonths() { + OffsetDate t = TEST_2007_07_15_PONE.plusDays(62); + assertEquals(OffsetDate.of(2007, 9, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusDays_overYears() { + OffsetDate t = OffsetDate.of(2006, 7, 14, OFFSET_PONE).plusDays(366); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plusDays_overLeapYears() { + OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1).plusDays(365 + 366); + assertEquals(OffsetDate.of(2008, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusDays_negative() { + OffsetDate t = TEST_2007_07_15_PONE.plusDays(-1); + assertEquals(OffsetDate.of(2007, 7, 14, OFFSET_PONE), t); + } + + @Test + public void test_plusDays_negativeAcrossYear() { + OffsetDate t = TEST_2007_07_15_PONE.plusDays(-196); + assertEquals(OffsetDate.of(2006, 12, 31, OFFSET_PONE), t); + } + + @Test + public void test_plusDays_negativeOverYears() { + OffsetDate t = TEST_2007_07_15_PONE.plusDays(-730); + assertEquals(OffsetDate.of(2005, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_plusDays_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.plusDays(0); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plusDays_maximum() { + OffsetDate t = OffsetDate.of(Year.MAX_VALUE, 12, 30, OFFSET_PONE).plusDays(1); + OffsetDate expected = OffsetDate.of(Year.MAX_VALUE, 12, 31, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_plusDays_minimum() { + OffsetDate t = OffsetDate.of(Year.MIN_VALUE, 1, 2, OFFSET_PONE).plusDays(-1); + OffsetDate expected = OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_plusDays_invalidTooLarge() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 31, OFFSET_PONE).plusDays(1)); + } + + @Test + public void test_plusDays_invalidTooSmall() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE).plusDays(-1)); + } + + @Test + public void test_plusDays_overflowTooLarge() { + assertThrows(ArithmeticException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 31, OFFSET_PONE).plusDays(Long.MAX_VALUE)); + } + + @Test + public void test_plusDays_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE).plusDays(Long.MIN_VALUE)); + } + + //----------------------------------------------------------------------- + // minus(MinusAdjuster) + //----------------------------------------------------------------------- + @Test + public void test_minus_MinusAdjuster() { + MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); + OffsetDate t = TEST_2007_07_15_PONE.minus(period); + assertEquals(OffsetDate.of(2006, 12, 15, OFFSET_PONE), t); + } + + @Test + public void test_minus_MinusAdjuster_noChange() { + MockSimplePeriod period = MockSimplePeriod.of(0, ChronoUnit.MONTHS); + OffsetDate t = TEST_2007_07_15_PONE.minus(period); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_minus_MinusAdjuster_zero() { + OffsetDate t = TEST_2007_07_15_PONE.minus(Period.ZERO); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_plus_MinusAdjuster_null() { + assertThrows(NullPointerException.class, () -> TEST_2007_07_15_PONE.minus((TemporalAmount) null)); + } + + //----------------------------------------------------------------------- + // minusYears() + //----------------------------------------------------------------------- + @Test + public void test_minusYears_long_normal() { + OffsetDate t = TEST_2007_07_15_PONE.minusYears(1); + assertEquals(OffsetDate.of(2006, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_minusYears_long_negative() { + OffsetDate t = TEST_2007_07_15_PONE.minusYears(-1); + assertEquals(OffsetDate.of(2008, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_minusYears_long_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.minusYears(0); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_minusYears_long_adjustDay() { + OffsetDate t = OffsetDate.of(2008, 2, 29, OFFSET_PONE).minusYears(1); + OffsetDate expected = OffsetDate.of(2007, 2, 28, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_minusYears_long_big() { + long years = 20L + Year.MAX_VALUE; + OffsetDate test = OffsetDate.of(40, 6, 1, OFFSET_PONE).minusYears(years); + assertEquals(OffsetDate.of((int) (40L - years), 6, 1, OFFSET_PONE), test); + } + + @Test + public void test_minusYears_long_invalidTooLarge() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MAX_VALUE, 1, 1, OFFSET_PONE).minusYears(-1)); + } + + @Test + public void test_minusYears_long_invalidTooLargeMaxAddMax() { + OffsetDate test = OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> test.minusYears(Long.MAX_VALUE)); + } + + @Test + public void test_minusYears_long_invalidTooLargeMaxAddMin() { + OffsetDate test = OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> test.minusYears(Long.MIN_VALUE)); + } + + @Test + public void test_minusYears_long_invalidTooSmall() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE).minusYears(1)); + } + + //----------------------------------------------------------------------- + // minusMonths() + //----------------------------------------------------------------------- + @Test + public void test_minusMonths_long_normal() { + OffsetDate t = TEST_2007_07_15_PONE.minusMonths(1); + assertEquals(OffsetDate.of(2007, 6, 15, OFFSET_PONE), t); + } + + @Test + public void test_minusMonths_long_overYears() { + OffsetDate t = TEST_2007_07_15_PONE.minusMonths(25); + assertEquals(OffsetDate.of(2005, 6, 15, OFFSET_PONE), t); + } + + @Test + public void test_minusMonths_long_negative() { + OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-1); + assertEquals(OffsetDate.of(2007, 8, 15, OFFSET_PONE), t); + } + + @Test + public void test_minusMonths_long_negativeAcrossYear() { + OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-7); + assertEquals(OffsetDate.of(2008, 2, 15, OFFSET_PONE), t); + } + + @Test + public void test_minusMonths_long_negativeOverYears() { + OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-31); + assertEquals(OffsetDate.of(2010, 2, 15, OFFSET_PONE), t); + } + + @Test + public void test_minusMonths_long_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.minusMonths(0); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_minusMonths_long_adjustDayFromLeapYear() { + OffsetDate t = OffsetDate.of(2008, 2, 29, OFFSET_PONE).minusMonths(12); + OffsetDate expected = OffsetDate.of(2007, 2, 28, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_minusMonths_long_adjustDayFromMonthLength() { + OffsetDate t = OffsetDate.of(2007, 3, 31, OFFSET_PONE).minusMonths(1); + OffsetDate expected = OffsetDate.of(2007, 2, 28, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_minusMonths_long_big() { + long months = 20L + Integer.MAX_VALUE; + OffsetDate test = OffsetDate.of(40, 6, 1, OFFSET_PONE).minusMonths(months); + assertEquals(OffsetDate.of((int) (40L - months / 12), 6 - (int) (months % 12), 1, OFFSET_PONE), test); + } + + @Test + public void test_minusMonths_long_invalidTooLarge() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE).minusMonths(-1)); + } + + @Test + public void test_minusMonths_long_invalidTooLargeMaxAddMax() { + OffsetDate test = OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> test.minusMonths(Long.MAX_VALUE)); + } + + @Test + public void test_minusMonths_long_invalidTooLargeMaxAddMin() { + OffsetDate test = OffsetDate.of(Year.MAX_VALUE, 12, 1, OFFSET_PONE); + assertThrows(DateTimeException.class, () -> test.minusMonths(Long.MIN_VALUE)); + } + + @Test + public void test_minusMonths_long_invalidTooSmall() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE).minusMonths(1)); + } + + //----------------------------------------------------------------------- + // minusWeeks() + //----------------------------------------------------------------------- + public static Object[][] data_sampleMinusWeeksSymmetry() { + return new Object[][] { + {OffsetDate.of(-1, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(-1, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(-1, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(-1, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(0, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(0, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(0, 2, 29, OFFSET_PTWO)}, + {OffsetDate.of(0, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(0, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2007, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2007, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2007, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2007, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2008, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2008, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2008, 2, 29, OFFSET_PTWO)}, + {OffsetDate.of(2008, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2008, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2099, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2099, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2099, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2099, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2100, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2100, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2100, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2100, 12, 31, OFFSET_PTWO)}, + }; + } + + @ParameterizedTest + @MethodSource("data_sampleMinusWeeksSymmetry") + public void test_minusWeeks_symmetry(OffsetDate reference) { + for (int weeks = 0; weeks < 365 * 8; weeks++) { + OffsetDate t = reference.minusWeeks(weeks).minusWeeks(-weeks); + assertEquals(reference, t); + + t = reference.minusWeeks(-weeks).minusWeeks(weeks); + assertEquals(reference, t); + } + } + + @Test + public void test_minusWeeks_normal() { + OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(1); + assertEquals(OffsetDate.of(2007, 7, 8, OFFSET_PONE), t); + } + + @Test + public void test_minusWeeks_overMonths() { + OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(9); + assertEquals(OffsetDate.of(2007, 5, 13, OFFSET_PONE), t); + } + + @Test + public void test_minusWeeks_overYears() { + OffsetDate t = OffsetDate.of(2008, 7, 13, OFFSET_PONE).minusWeeks(52); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_minusWeeks_overLeapYears() { + OffsetDate t = TEST_2007_07_15_PONE.minusYears(-1).minusWeeks(104); + assertEquals(OffsetDate.of(2006, 7, 18, OFFSET_PONE), t); + } + + @Test + public void test_minusWeeks_negative() { + OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-1); + assertEquals(OffsetDate.of(2007, 7, 22, OFFSET_PONE), t); + } + + @Test + public void test_minusWeeks_negativeAcrossYear() { + OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-28); + assertEquals(OffsetDate.of(2008, 1, 27, OFFSET_PONE), t); + } + + @Test + public void test_minusWeeks_negativeOverYears() { + OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-104); + assertEquals(OffsetDate.of(2009, 7, 12, OFFSET_PONE), t); + } + + @Test + public void test_minusWeeks_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(0); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_minusWeeks_maximum() { + OffsetDate t = OffsetDate.of(Year.MAX_VALUE, 12, 24, OFFSET_PONE).minusWeeks(-1); + OffsetDate expected = OffsetDate.of(Year.MAX_VALUE, 12, 31, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_minusWeeks_minimum() { + OffsetDate t = OffsetDate.of(Year.MIN_VALUE, 1, 8, OFFSET_PONE).minusWeeks(1); + OffsetDate expected = OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_minusWeeks_invalidTooLarge() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 25, OFFSET_PONE).minusWeeks(-1)); + } + + @Test + public void test_minusWeeks_invalidTooSmall() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 7, OFFSET_PONE).minusWeeks(1)); + } + + @Test + public void test_minusWeeks_invalidMaxMinusMax() { + assertThrows(ArithmeticException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 25, OFFSET_PONE).minusWeeks(Long.MAX_VALUE)); + } + + @Test + public void test_minusWeeks_invalidMaxMinusMin() { + assertThrows(ArithmeticException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 25, OFFSET_PONE).minusWeeks(Long.MIN_VALUE)); + } + + //----------------------------------------------------------------------- + // minusDays() + //----------------------------------------------------------------------- + public static Object[][] data_sampleMinusDaysSymmetry() { + return new Object[][] { + {OffsetDate.of(-1, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(-1, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(-1, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(-1, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(0, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(0, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(0, 2, 29, OFFSET_PTWO)}, + {OffsetDate.of(0, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(0, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2007, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2007, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2007, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2007, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2008, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2008, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2008, 2, 29, OFFSET_PTWO)}, + {OffsetDate.of(2008, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2008, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2099, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2099, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2099, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2099, 12, 31, OFFSET_PTWO)}, + {OffsetDate.of(2100, 1, 1, OFFSET_PONE)}, + {OffsetDate.of(2100, 2, 28, OFFSET_PTWO)}, + {OffsetDate.of(2100, 3, 1, OFFSET_PONE)}, + {OffsetDate.of(2100, 12, 31, OFFSET_PTWO)}, + }; + } + + @ParameterizedTest + @MethodSource("data_sampleMinusDaysSymmetry") + public void test_minusDays_symmetry(OffsetDate reference) { + for (int days = 0; days < 365 * 8; days++) { + OffsetDate t = reference.minusDays(days).minusDays(-days); + assertEquals(reference, t); + + t = reference.minusDays(-days).minusDays(days); + assertEquals(reference, t); + } + } + + @Test + public void test_minusDays_normal() { + OffsetDate t = TEST_2007_07_15_PONE.minusDays(1); + assertEquals(OffsetDate.of(2007, 7, 14, OFFSET_PONE), t); + } + + @Test + public void test_minusDays_overMonths() { + OffsetDate t = TEST_2007_07_15_PONE.minusDays(62); + assertEquals(OffsetDate.of(2007, 5, 14, OFFSET_PONE), t); + } + + @Test + public void test_minusDays_overYears() { + OffsetDate t = OffsetDate.of(2008, 7, 16, OFFSET_PONE).minusDays(367); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_minusDays_overLeapYears() { + OffsetDate t = TEST_2007_07_15_PONE.plusYears(2).minusDays(365 + 366); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_minusDays_negative() { + OffsetDate t = TEST_2007_07_15_PONE.minusDays(-1); + assertEquals(OffsetDate.of(2007, 7, 16, OFFSET_PONE), t); + } + + @Test + public void test_minusDays_negativeAcrossYear() { + OffsetDate t = TEST_2007_07_15_PONE.minusDays(-169); + assertEquals(OffsetDate.of(2007, 12, 31, OFFSET_PONE), t); + } + + @Test + public void test_minusDays_negativeOverYears() { + OffsetDate t = TEST_2007_07_15_PONE.minusDays(-731); + assertEquals(OffsetDate.of(2009, 7, 15, OFFSET_PONE), t); + } + + @Test + public void test_minusDays_noChange() { + OffsetDate t = TEST_2007_07_15_PONE.minusDays(0); + assertEquals(TEST_2007_07_15_PONE, t); + } + + @Test + public void test_minusDays_maximum() { + OffsetDate t = OffsetDate.of(Year.MAX_VALUE, 12, 30, OFFSET_PONE).minusDays(-1); + OffsetDate expected = OffsetDate.of(Year.MAX_VALUE, 12, 31, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_minusDays_minimum() { + OffsetDate t = OffsetDate.of(Year.MIN_VALUE, 1, 2, OFFSET_PONE).minusDays(1); + OffsetDate expected = OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE); + assertEquals(expected, t); + } + + @Test + public void test_minusDays_invalidTooLarge() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 31, OFFSET_PONE).minusDays(-1)); + } + + @Test + public void test_minusDays_invalidTooSmall() { + assertThrows(DateTimeException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE).minusDays(1)); + } + + @Test + public void test_minusDays_overflowTooLarge() { + assertThrows(ArithmeticException.class, () -> OffsetDate.of(Year.MAX_VALUE, 12, 31, OFFSET_PONE).minusDays(Long.MIN_VALUE)); + } + + @Test + public void test_minusDays_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> OffsetDate.of(Year.MIN_VALUE, 1, 1, OFFSET_PONE).minusDays(Long.MAX_VALUE)); + } + + //----------------------------------------------------------------------- + // format(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test + public void test_format_formatter() { + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d"); + String t = OffsetDate.of(2010, 12, 3, OFFSET_PONE).format(f); + assertEquals("2010 12 3", t); + } + + @Test + public void test_format_formatter_null() { + assertThrows(NullPointerException.class, () -> OffsetDate.of(2010, 12, 3, OFFSET_PONE).format(null)); + } + + //----------------------------------------------------------------------- + // atTime() + //----------------------------------------------------------------------- + @Test + public void test_atTime_Local() { + OffsetDate t = OffsetDate.of(2008, 6, 30, OFFSET_PTWO); + assertEquals(OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO), + t.atTime(LocalTime.of(11, 30))); + } + + @Test + public void test_atTime_Local_nullLocalTime() { + OffsetDate t = OffsetDate.of(2008, 6, 30, OFFSET_PTWO); + assertThrows(NullPointerException.class, () -> t.atTime((LocalTime) null)); + } + + //----------------------------------------------------------------------- + // toLocalDate() + //----------------------------------------------------------------------- + @ParameterizedTest + @MethodSource("data_sampleDates") + public void test_toLocalDate(int year, int month, int day, ZoneOffset offset) { + LocalDate t = LocalDate.of(year, month, day); + assertEquals(t, OffsetDate.of(year, month, day, offset).toLocalDate()); + } + + //----------------------------------------------------------------------- + // toEpochSecond(LocalTime) + //----------------------------------------------------------------------- + @Test + public void test_toEpochSecond() { + OffsetDate od = OffsetDate.of(1970, 1, 1, ZoneOffset.UTC); + assertEquals(0, od.toEpochSecond(LocalTime.MIDNIGHT)); + assertEquals(12 * 60 * 60, od.toEpochSecond(LocalTime.MIDNIGHT.plusSeconds(12 * 60 * 60))); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test + public void test_compareTo_date() { + OffsetDate a = OffsetDate.of(2008, 6, 29, OFFSET_PONE); + OffsetDate b = OffsetDate.of(2008, 6, 30, OFFSET_PONE); // a is before b due to date + assertTrue(a.compareTo(b) < 0); + assertTrue(b.compareTo(a) > 0); + assertTrue(a.compareTo(a) == 0); + assertTrue(b.compareTo(b) == 0); + assertTrue(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0); + } + + @Test + public void test_compareTo_offset() { + OffsetDate a = OffsetDate.of(2008, 6, 30, OFFSET_PTWO); + OffsetDate b = OffsetDate.of(2008, 6, 30, OFFSET_PONE); // a is before b due to offset + assertTrue(a.compareTo(b) < 0); + assertTrue(b.compareTo(a) > 0); + assertTrue(a.compareTo(a) == 0); + assertTrue(b.compareTo(b) == 0); + assertTrue(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0); + } + + @Test + public void test_compareTo_both() { + OffsetDate a = OffsetDate.of(2008, 6, 29, OFFSET_PTWO); + OffsetDate b = OffsetDate.of(2008, 6, 30, OFFSET_PONE); // a is before b on instant scale + assertTrue(a.compareTo(b) < 0); + assertTrue(b.compareTo(a) > 0); + assertTrue(a.compareTo(a) == 0); + assertTrue(b.compareTo(b) == 0); + assertTrue(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0); + } + + @Test + public void test_compareTo_24hourDifference() { + OffsetDate a = OffsetDate.of(2008, 6, 29, ZoneOffset.ofHours(-12)); + OffsetDate b = OffsetDate.of(2008, 6, 30, ZoneOffset.ofHours(12)); // a is before b despite being same time-line time + assertTrue(a.compareTo(b) < 0); + assertTrue(b.compareTo(a) > 0); + assertTrue(a.compareTo(a) == 0); + assertTrue(b.compareTo(b) == 0); + assertTrue(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) == 0); + } + + @Test + public void test_compareTo_null() { + OffsetDate a = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + assertThrows(NullPointerException.class, () -> a.compareTo(null)); + } + + @Test + @SuppressWarnings({"unchecked", "rawtypes"}) + public void compareToNonOffsetDate() { + Comparable c = TEST_2007_07_15_PONE; + assertThrows(ClassCastException.class, () -> c.compareTo(new Object())); + } + + //----------------------------------------------------------------------- + // isAfter() / isBefore() / isEqual() + //----------------------------------------------------------------------- + @Test + public void test_isBeforeIsAfterIsEqual1() { + OffsetDate a = OffsetDate.of(2008, 6, 29, OFFSET_PONE); + OffsetDate b = OffsetDate.of(2008, 6, 30, OFFSET_PONE); // a is before b due to time + assertTrue(a.isBefore(b)); + assertFalse(a.isEqual(b)); + assertFalse(a.isAfter(b)); + + assertFalse(b.isBefore(a)); + assertFalse(b.isEqual(a)); + assertTrue(b.isAfter(a)); + + assertFalse(a.isBefore(a)); + assertFalse(b.isBefore(b)); + + assertTrue(a.isEqual(a)); + assertTrue(b.isEqual(b)); + + assertFalse(a.isAfter(a)); + assertFalse(b.isAfter(b)); + } + + @Test + public void test_isBeforeIsAfterIsEqual2() { + OffsetDate a = OffsetDate.of(2008, 6, 30, OFFSET_PTWO); + OffsetDate b = OffsetDate.of(2008, 6, 30, OFFSET_PONE); // a is before b due to offset + assertTrue(a.isBefore(b)); + assertFalse(a.isEqual(b)); + assertFalse(a.isAfter(b)); + + assertFalse(b.isBefore(a)); + assertFalse(b.isEqual(a)); + assertTrue(b.isAfter(a)); + + assertFalse(a.isBefore(a)); + assertFalse(b.isBefore(b)); + + assertTrue(a.isEqual(a)); + assertTrue(b.isEqual(b)); + + assertFalse(a.isAfter(a)); + assertFalse(b.isAfter(b)); + } + + @Test + public void test_isBeforeIsAfterIsEqual_instantComparison() { + OffsetDate a = OffsetDate.of(2008, 6, 30, ZoneOffset.ofHours(12)); + OffsetDate b = OffsetDate.of(2008, 6, 29, ZoneOffset.ofHours(-12)); // a is same instant as b + assertFalse(a.isBefore(b)); + assertTrue(a.isEqual(b)); + assertFalse(a.isAfter(b)); + + assertFalse(b.isBefore(a)); + assertTrue(b.isEqual(a)); + assertFalse(b.isAfter(a)); + + assertFalse(a.isBefore(a)); + assertFalse(b.isBefore(b)); + + assertTrue(a.isEqual(a)); + assertTrue(b.isEqual(b)); + + assertFalse(a.isAfter(a)); + assertFalse(b.isAfter(b)); + } + + @Test + public void test_isBefore_null() { + OffsetDate a = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + assertThrows(NullPointerException.class, () -> a.isBefore(null)); + } + + @Test + public void test_isAfter_null() { + OffsetDate a = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + assertThrows(NullPointerException.class, () -> a.isAfter(null)); + } + + @Test + public void test_isEqual_null() { + OffsetDate a = OffsetDate.of(2008, 6, 30, OFFSET_PONE); + assertThrows(NullPointerException.class, () -> a.isEqual(null)); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test + public void test_equals_and_hashCode() { + EqualsTester equalsTester = new EqualsTester(); + for (Object[] sample : data_sampleDates()) { + int y = (int) sample[0]; + int m = (int) sample[1]; + int d = (int) sample[2]; + ZoneOffset offset = (ZoneOffset) sample[3]; + equalsTester.addEqualityGroup(OffsetDate.of(y, m, d, offset), OffsetDate.of(y, m, d, offset)); + } + equalsTester.testEquals(); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + public static Object[][] data_sampleToString() { + return new Object[][] { + {2008, 7, 5, "Z", "2008-07-05Z"}, + {2008, 7, 5, "+00", "2008-07-05Z"}, + {2008, 7, 5, "+0000", "2008-07-05Z"}, + {2008, 7, 5, "+00:00", "2008-07-05Z"}, + {2008, 7, 5, "+000000", "2008-07-05Z"}, + {2008, 7, 5, "+00:00:00", "2008-07-05Z"}, + {2008, 7, 5, "-00", "2008-07-05Z"}, + {2008, 7, 5, "-0000", "2008-07-05Z"}, + {2008, 7, 5, "-00:00", "2008-07-05Z"}, + {2008, 7, 5, "-000000", "2008-07-05Z"}, + {2008, 7, 5, "-00:00:00", "2008-07-05Z"}, + {2008, 7, 5, "+01", "2008-07-05+01:00"}, + {2008, 7, 5, "+0100", "2008-07-05+01:00"}, + {2008, 7, 5, "+01:00", "2008-07-05+01:00"}, + {2008, 7, 5, "+010000", "2008-07-05+01:00"}, + {2008, 7, 5, "+01:00:00", "2008-07-05+01:00"}, + {2008, 7, 5, "+0130", "2008-07-05+01:30"}, + {2008, 7, 5, "+01:30", "2008-07-05+01:30"}, + {2008, 7, 5, "+013000", "2008-07-05+01:30"}, + {2008, 7, 5, "+01:30:00", "2008-07-05+01:30"}, + {2008, 7, 5, "+013040", "2008-07-05+01:30:40"}, + {2008, 7, 5, "+01:30:40", "2008-07-05+01:30:40"}, + }; + } + + @ParameterizedTest + @MethodSource("data_sampleToString") + public void test_toString(int y, int m, int d, String offsetId, String expected) { + OffsetDate t = OffsetDate.of(y, m, d, ZoneOffset.of(offsetId)); + String str = t.toString(); + assertEquals(expected, str); + } + +} diff --git a/src/test/java/org/threeten/extra/TestPackedFields.java b/src/test/java/org/threeten/extra/TestPackedFields.java index 76fa6683..731610bf 100644 --- a/src/test/java/org/threeten/extra/TestPackedFields.java +++ b/src/test/java/org/threeten/extra/TestPackedFields.java @@ -35,7 +35,8 @@ import static java.time.temporal.ChronoUnit.FOREVER; import static java.time.temporal.ChronoUnit.MINUTES; import static java.time.temporal.ChronoUnit.SECONDS; -import static org.testng.AssertJUnit.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.time.DateTimeException; import java.time.LocalDate; @@ -45,17 +46,17 @@ import java.time.format.DateTimeParseException; import java.time.format.ResolverStyle; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; /** * Test PackedFields. */ -@Test public class TestPackedFields { //----------------------------------------------------------------------- // packedDate() //----------------------------------------------------------------------- + @Test public void test_date_basics() { assertEquals("PackedDate", PackedFields.PACKED_DATE.toString()); assertEquals(DAYS, PackedFields.PACKED_DATE.getBaseUnit()); @@ -68,47 +69,51 @@ public void test_date_basics() { assertEquals(99991231, PackedFields.PACKED_DATE.range().getMaximum()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_date_rangeRefinedBy_time() { - PackedFields.PACKED_DATE.rangeRefinedBy(LocalTime.of(11, 30)); + assertThrows(DateTimeException.class, () -> PackedFields.PACKED_DATE.rangeRefinedBy(LocalTime.of(11, 30))); } + @Test public void test_date_getFrom() { assertEquals(20151203, LocalDate.of(2015, 12, 3).get(PackedFields.PACKED_DATE)); assertEquals(10000101, LocalDate.of(1000, 1, 1).get(PackedFields.PACKED_DATE)); assertEquals(99991231, LocalDate.of(9999, 12, 31).get(PackedFields.PACKED_DATE)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_date_getFrom_rangeLow() { - PackedFields.PACKED_DATE.getFrom(LocalDate.of(999, 12, 31)); + assertThrows(DateTimeException.class, () -> PackedFields.PACKED_DATE.getFrom(LocalDate.of(999, 12, 31))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_date_getFrom_rangeHigh() { - PackedFields.PACKED_DATE.getFrom(LocalDate.of(10000, 1, 1)); + assertThrows(DateTimeException.class, () -> PackedFields.PACKED_DATE.getFrom(LocalDate.of(10000, 1, 1))); } + @Test public void test_date_adjustInto() { assertEquals(LocalDate.of(2015, 12, 3), LocalDate.MIN.with(PackedFields.PACKED_DATE, 20151203)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_date_adjustInto_range() { - LocalDate.MIN.with(PackedFields.PACKED_DATE, 1230101); + assertThrows(DateTimeException.class, () -> LocalDate.MIN.with(PackedFields.PACKED_DATE, 1230101)); } + @Test public void test_date_resolve() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_DATE).toFormatter(); assertEquals(LocalDate.of(2015, 12, 3), LocalDate.parse("20151203", f)); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_date_resolve_invalid_smart() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_DATE).toFormatter(); - LocalDate.parse("20151403", f.withResolverStyle(ResolverStyle.SMART)); + assertThrows(DateTimeParseException.class, () -> LocalDate.parse("20151403", f.withResolverStyle(ResolverStyle.SMART))); } + @Test public void test_date_resolve_invalid_lenient() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_DATE).toFormatter(); assertEquals(LocalDate.of(2016, 2, 3), LocalDate.parse("20151403", f.withResolverStyle(ResolverStyle.LENIENT))); @@ -117,6 +122,7 @@ public void test_date_resolve_invalid_lenient() { //----------------------------------------------------------------------- // packedHourMin() //----------------------------------------------------------------------- + @Test public void test_hourMin_basics() { assertEquals("PackedHourMin", PackedFields.PACKED_HOUR_MIN.toString()); assertEquals(MINUTES, PackedFields.PACKED_HOUR_MIN.getBaseUnit()); @@ -129,36 +135,40 @@ public void test_hourMin_basics() { assertEquals(2359, PackedFields.PACKED_HOUR_MIN.range().getMaximum()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_hourMin_rangeRefinedBy_time() { - PackedFields.PACKED_HOUR_MIN.rangeRefinedBy(LocalDate.of(2015, 12, 3)); + assertThrows(DateTimeException.class, () -> PackedFields.PACKED_HOUR_MIN.rangeRefinedBy(LocalDate.of(2015, 12, 3))); } + @Test public void test_hourMin_getFrom() { assertEquals(1130, LocalTime.of(11, 30).get(PackedFields.PACKED_HOUR_MIN)); assertEquals(121, LocalTime.of(1, 21).get(PackedFields.PACKED_HOUR_MIN)); } + @Test public void test_hourMin_adjustInto() { assertEquals(LocalTime.of(11, 30), LocalTime.MIDNIGHT.with(PackedFields.PACKED_HOUR_MIN, 1130)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_hourMin_adjustInto_value() { - LocalDate.MIN.with(PackedFields.PACKED_HOUR_MIN, 1273); + assertThrows(DateTimeException.class, () -> LocalDate.MIN.with(PackedFields.PACKED_HOUR_MIN, 1273)); } + @Test public void test_hourMin_resolve() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_HOUR_MIN).toFormatter(); assertEquals(LocalTime.of(11, 30), LocalTime.parse("1130", f)); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_hourMin_resolve_invalid_smart() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_HOUR_MIN).toFormatter(); - LocalTime.parse("1173", f.withResolverStyle(ResolverStyle.SMART)); + assertThrows(DateTimeParseException.class, () -> LocalTime.parse("1173", f.withResolverStyle(ResolverStyle.SMART))); } + @Test public void test_hourMin_resolve_invalid_lenient() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_HOUR_MIN).toFormatter(); assertEquals(LocalTime.of(12, 13), LocalTime.parse("1173", f.withResolverStyle(ResolverStyle.LENIENT))); @@ -167,6 +177,7 @@ public void test_hourMin_resolve_invalid_lenient() { //----------------------------------------------------------------------- // packedTime() //----------------------------------------------------------------------- + @Test public void test_time_basics() { assertEquals("PackedTime", PackedFields.PACKED_TIME.toString()); assertEquals(SECONDS, PackedFields.PACKED_TIME.getBaseUnit()); @@ -179,37 +190,41 @@ public void test_time_basics() { assertEquals(235959, PackedFields.PACKED_TIME.range().getMaximum()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_time_rangeRefinedBy_time() { - PackedFields.PACKED_TIME.rangeRefinedBy(LocalDate.of(2015, 12, 3)); + assertThrows(DateTimeException.class, () -> PackedFields.PACKED_TIME.rangeRefinedBy(LocalDate.of(2015, 12, 3))); } + @Test public void test_time_getFrom() { assertEquals(113052, LocalTime.of(11, 30, 52).get(PackedFields.PACKED_TIME)); assertEquals(113000, LocalTime.of(11, 30).get(PackedFields.PACKED_TIME)); assertEquals(12100, LocalTime.of(1, 21).get(PackedFields.PACKED_TIME)); } + @Test public void test_time_adjustInto() { assertEquals(LocalTime.of(11, 30, 52), LocalTime.MIDNIGHT.with(PackedFields.PACKED_TIME, 113052)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_time_adjustInto_value() { - LocalDate.MIN.with(PackedFields.PACKED_TIME, 127310); + assertThrows(DateTimeException.class, () -> LocalDate.MIN.with(PackedFields.PACKED_TIME, 127310)); } + @Test public void test_time_resolve() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_TIME).toFormatter(); assertEquals(LocalTime.of(11, 30, 52), LocalTime.parse("113052", f)); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_time_resolve_invalid_smart() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_TIME).toFormatter(); - LocalTime.parse("117361", f.withResolverStyle(ResolverStyle.SMART)); + assertThrows(DateTimeParseException.class, () -> LocalTime.parse("117361", f.withResolverStyle(ResolverStyle.SMART))); } + @Test public void test_time_resolve_invalid_lenient() { DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(PackedFields.PACKED_TIME).toFormatter(); assertEquals(LocalTime.of(12, 14, 1), LocalTime.parse("117361", f.withResolverStyle(ResolverStyle.LENIENT))); diff --git a/src/test/java/org/threeten/extra/TestPeriodDuration.java b/src/test/java/org/threeten/extra/TestPeriodDuration.java new file mode 100644 index 00000000..d1d04aa5 --- /dev/null +++ b/src/test/java/org/threeten/extra/TestPeriodDuration.java @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Period; +import java.time.format.DateTimeParseException; +import java.util.Arrays; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; + +/** + * Test class. + */ +public class TestPeriodDuration { + + private static final Period P1Y2M3D = Period.of(1, 2, 3); + private static final Duration DUR_5 = Duration.ofSeconds(5); + private static final Duration DUR_6 = Duration.ofSeconds(6); + + //----------------------------------------------------------------------- + @Test + public void test_isSerializable() { + assertTrue(Serializable.class.isAssignableFrom(PeriodDuration.class)); + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + PeriodDuration test = PeriodDuration.of(P1Y2M3D, DUR_5); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertEquals(test, ois.readObject()); + } + } + + //----------------------------------------------------------------------- + @Test + public void test_ZERO() { + assertEquals(PeriodDuration.ZERO, PeriodDuration.of(Period.ZERO, Duration.ZERO)); + assertEquals(PeriodDuration.ZERO, PeriodDuration.of(Period.ZERO)); + assertEquals(PeriodDuration.ZERO, PeriodDuration.of(Duration.ZERO)); + assertEquals(Period.ZERO, PeriodDuration.ZERO.getPeriod()); + assertEquals(Duration.ZERO, PeriodDuration.ZERO.getDuration()); + assertEquals(true, PeriodDuration.ZERO.isZero()); + assertEquals(Arrays.asList(YEARS, MONTHS, DAYS, SECONDS, NANOS), PeriodDuration.ZERO.getUnits()); + assertEquals(0, PeriodDuration.ZERO.get(YEARS)); + assertEquals(0, PeriodDuration.ZERO.get(MONTHS)); + assertEquals(0, PeriodDuration.ZERO.get(DAYS)); + assertEquals(0, PeriodDuration.ZERO.get(SECONDS)); + assertEquals(0, PeriodDuration.ZERO.get(NANOS)); + } + + @Test + public void test_ZERO_getEra() { + assertThrows(DateTimeException.class, () -> PeriodDuration.ZERO.get(ERAS)); + } + + //----------------------------------------------------------------------- + @Test + public void test_of_both() { + PeriodDuration test = PeriodDuration.of(P1Y2M3D, Duration.ofSeconds(4)); + assertEquals(P1Y2M3D, test.getPeriod()); + assertEquals(Duration.ofSeconds(4), test.getDuration()); + assertEquals(false, test.isZero()); + assertEquals(1, test.get(YEARS)); + assertEquals(2, test.get(MONTHS)); + assertEquals(3, test.get(DAYS)); + assertEquals(4, test.get(SECONDS)); + assertEquals(0, test.get(NANOS)); + } + + @Test + public void test_of_period() { + PeriodDuration test = PeriodDuration.of(P1Y2M3D); + assertEquals(P1Y2M3D, test.getPeriod()); + assertEquals(Duration.ZERO, test.getDuration()); + assertEquals(false, test.isZero()); + assertEquals(1, test.get(YEARS)); + assertEquals(2, test.get(MONTHS)); + assertEquals(3, test.get(DAYS)); + assertEquals(0, test.get(SECONDS)); + assertEquals(0, test.get(NANOS)); + } + + @Test + public void test_of_duration() { + PeriodDuration test = PeriodDuration.of(Duration.ofSeconds(4)); + assertEquals(Period.ZERO, test.getPeriod()); + assertEquals(Duration.ofSeconds(4), test.getDuration()); + assertEquals(false, test.isZero()); + assertEquals(0, test.get(YEARS)); + assertEquals(0, test.get(MONTHS)); + assertEquals(0, test.get(DAYS)); + assertEquals(4, test.get(SECONDS)); + assertEquals(0, test.get(NANOS)); + } + + //----------------------------------------------------------------------- + @Test + public void test_between_dates() { + PeriodDuration test = PeriodDuration.between(LocalDate.of(2012, 6, 20), LocalDate.of(2012, 8, 25)); + assertEquals(Period.between(LocalDate.of(2012, 6, 20), LocalDate.of(2012, 8, 25)), test.getPeriod()); + assertEquals(Duration.ZERO, test.getDuration()); + } + + @Test + public void test_between_times() { + PeriodDuration test = PeriodDuration.between(LocalTime.of(11, 20), LocalTime.of(12, 25)); + assertEquals(Period.ZERO, test.getPeriod()); + assertEquals(Duration.between(LocalTime.of(11, 20), LocalTime.of(12, 25)), test.getDuration()); + } + + @Test + public void test_between_mixed1() { + PeriodDuration test = PeriodDuration.between(LocalDate.of(2012, 6, 20), LocalTime.of(11, 25)); + assertEquals(Period.ZERO, test.getPeriod()); + assertEquals(Duration.ofHours(11).plusMinutes(25), test.getDuration()); + } + + @Test + public void test_between_mixed2() { + PeriodDuration test = PeriodDuration.between(LocalDate.of(2012, 6, 20), LocalDateTime.of(2012, 7, 22, 11, 25)); + assertEquals(Period.of(0, 1, 2), test.getPeriod()); + assertEquals(Duration.ofHours(11).plusMinutes(25), test.getDuration()); + } + + //----------------------------------------------------------------------- + @Test + public void test_from() { + assertEquals(PeriodDuration.from(PeriodDuration.of(P1Y2M3D)), PeriodDuration.from(PeriodDuration.of(P1Y2M3D))); + assertEquals(PeriodDuration.of(Period.ofYears(2)), PeriodDuration.from(Period.ofYears(2))); + assertEquals(PeriodDuration.of(Duration.ofSeconds(2)), PeriodDuration.from(Duration.ofSeconds(2))); + assertEquals(PeriodDuration.of(Period.ofYears(2)), PeriodDuration.from(Years.of(2))); + assertEquals(PeriodDuration.of(Period.ofMonths(2)), PeriodDuration.from(Months.of(2))); + assertEquals(PeriodDuration.of(Period.ofWeeks(2)), PeriodDuration.from(Weeks.of(2))); + assertEquals(PeriodDuration.of(Period.ofDays(2)), PeriodDuration.from(Days.of(2))); + assertEquals(PeriodDuration.of(Duration.ofHours(2)), PeriodDuration.from(Hours.of(2))); + } + + //----------------------------------------------------------------------- + public static Object[][] data_valid() { + return new Object[][] { + {"P1Y2M3W4DT5H6M7S", Period.of(1, 2, 3 * 7 + 4), Duration.ofHours(5).plusMinutes(6).plusSeconds(7)}, + {"P3Y", Period.ofYears(3), Duration.ZERO}, + {"P3M", Period.ofMonths(3), Duration.ZERO}, + {"P3W", Period.ofWeeks(3), Duration.ZERO}, + {"P3D", Period.ofDays(3), Duration.ZERO}, + + {"PT0S", Period.of(0, 0, 0), Duration.ofSeconds(0)}, + {"PT1S", Period.of(0, 0, 0), Duration.ofSeconds(1)}, + {"PT2S", Period.of(0, 0, 0), Duration.ofSeconds(2)}, + {"PT123456789S", Period.of(0, 0, 0), Duration.ofSeconds(123456789)}, + {"PT+0S", Period.of(0, 0, 0), Duration.ofSeconds(0)}, + {"PT+2S", Period.of(0, 0, 0), Duration.ofSeconds(2)}, + {"PT-0S", Period.of(0, 0, 0), Duration.ofSeconds(0)}, + {"PT-2S", Period.of(0, 0, 0), Duration.ofSeconds(-2)}, + + {"P+0M", Period.of(0, 0, 0), Duration.ZERO}, + {"P+2M", Period.of(0, 2, 0), Duration.ZERO}, + {"P-0M", Period.of(0, 0, 0), Duration.ZERO}, + {"P-2M", Period.of(0, -2, 0), Duration.ZERO}, + }; + } + + @ParameterizedTest + @MethodSource("data_valid") + public void test_parse_CharSequence_valid(String str, Period period, Duration duration) { + assertEquals(PeriodDuration.of(period, duration), PeriodDuration.parse(str)); + } + + @ParameterizedTest + @MethodSource("data_valid") + public void test_parse_CharSequence_valid_initialPlus(String str, Period period, Duration duration) { + assertEquals(PeriodDuration.of(period, duration), PeriodDuration.parse("+" + str)); + } + + @ParameterizedTest + @MethodSource("data_valid") + public void test_parse_CharSequence_valid_initialMinus(String str, Period period, Duration duration) { + assertEquals(PeriodDuration.of(period, duration).negated(), PeriodDuration.parse("-" + str)); + } + + public static Object[][] data_invalid() { + return new Object[][] { + {"P3Q"}, + {"P1M2Y"}, + + {"3"}, + {"-3"}, + {"3H"}, + {"-3H"}, + {"P3"}, + {"P-3"}, + {"PH"}, + {"T"}, + {"T3H"}, + }; + } + + @ParameterizedTest + @MethodSource("data_invalid") + public void test_parse_CharSequence_invalid(String str) { + assertThrows(DateTimeParseException.class, () -> PeriodDuration.parse(str)); + } + + @Test + public void test_parse_CharSequence_null() { + assertThrows(NullPointerException.class, () -> PeriodDuration.parse((CharSequence) null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_plus_TemporalAmount_PeriodDuration() { + PeriodDuration test = PeriodDuration.of(P1Y2M3D, DUR_5); + assertEquals(PeriodDuration.of(Period.of(4, 4, 4), DUR_5), test.plus(Period.of(3, 2, 1))); + assertEquals(PeriodDuration.of(P1Y2M3D, Duration.ofSeconds(9)), test.plus(Duration.ofSeconds(4))); + } + + @Test + public void test_plus_TemporalAmount_overflowTooBig() { + assertThrows(ArithmeticException.class, () -> PeriodDuration.of(Period.of(Integer.MAX_VALUE - 1, 0, 0)).plus(PeriodDuration.of(Period.ofYears(2)))); + } + + @Test + public void test_plus_TemporalAmount_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> PeriodDuration.of(Period.of(Integer.MIN_VALUE + 1, 0, 0)).plus(PeriodDuration.of(Period.ofYears(-2)))); + } + + @Test + public void test_plus_TemporalAmount_null() { + assertThrows(NullPointerException.class, () -> P1Y2M3D.plus(null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_minus_TemporalAmount_PeriodDuration() { + PeriodDuration test = PeriodDuration.of(P1Y2M3D, DUR_5); + assertEquals(PeriodDuration.of(Period.of(0, 1, 2), DUR_5), test.minus(Period.of(1, 1, 1))); + assertEquals(PeriodDuration.of(P1Y2M3D, Duration.ofSeconds(1)), test.minus(Duration.ofSeconds(4))); + } + + @Test + public void test_minus_TemporalAmount_overflowTooBig() { + assertThrows(ArithmeticException.class, () -> PeriodDuration.of(Period.of(Integer.MAX_VALUE - 1, 0, 0)).minus(PeriodDuration.of(Period.ofYears(-2)))); + } + + @Test + public void test_minus_TemporalAmount_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> PeriodDuration.of(Period.of(Integer.MIN_VALUE + 1, 0, 0)).minus(PeriodDuration.of(Period.ofYears(2)))); + } + + @Test + public void test_minus_TemporalAmount_null() { + assertThrows(NullPointerException.class, () -> P1Y2M3D.minus(null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_multipliedBy() { + PeriodDuration test = PeriodDuration.of(P1Y2M3D, DUR_5); + assertEquals(PeriodDuration.ZERO, test.multipliedBy(0)); + assertEquals(test, test.multipliedBy(1)); + assertEquals(PeriodDuration.of(Period.of(5, 10, 15), Duration.ofSeconds(25)), test.multipliedBy(5)); + assertEquals(PeriodDuration.of(Period.of(-3, -6, -9), Duration.ofSeconds(-15)), test.multipliedBy(-3)); + } + + @Test + public void test_multipliedBy_overflowTooBig() { + assertThrows(ArithmeticException.class, () -> PeriodDuration.of(Period.ofYears(Integer.MAX_VALUE / 2 + 1)).multipliedBy(2)); + } + + @Test + public void test_multipliedBy_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> PeriodDuration.of(Period.ofYears(Integer.MIN_VALUE / 2 - 1)).multipliedBy(2)); + } + + //----------------------------------------------------------------------- + @Test + public void test_negated() { + assertEquals(PeriodDuration.of(P1Y2M3D.negated(), DUR_5.negated()), PeriodDuration.of(P1Y2M3D, DUR_5).negated()); + } + + @Test + public void test_negated_overflow() { + assertThrows(ArithmeticException.class, () -> PeriodDuration.of(Duration.ofSeconds(Long.MIN_VALUE)).negated()); + } + + //----------------------------------------------------------------------- + @Test + public void test_normalizedYears() { + assertEquals(PeriodDuration.of(P1Y2M3D.normalized(), DUR_5), PeriodDuration.of(P1Y2M3D, DUR_5).normalizedYears()); + } + + //----------------------------------------------------------------------- + @Test + public void test_normalizedStandardDays() { + assertEquals( + PeriodDuration.of(P1Y2M3D, Duration.ofHours(5)), + PeriodDuration.of(P1Y2M3D, Duration.ofHours(5)).normalizedStandardDays()); + assertEquals( + PeriodDuration.of(P1Y2M3D.plusDays(1), Duration.ofHours(1)), + PeriodDuration.of(P1Y2M3D, Duration.ofHours(25)).normalizedStandardDays()); + assertEquals( + PeriodDuration.of(P1Y2M3D.plusDays(-3), Duration.ofHours(-1)), + PeriodDuration.of(P1Y2M3D, Duration.ofHours(-73)).normalizedStandardDays()); + } + + @Test + public void test_normalizedStandardDaysn_overflow() { + assertThrows(ArithmeticException.class, () -> PeriodDuration.of(Duration.ofSeconds(Long.MIN_VALUE)).normalizedStandardDays()); + } + + //----------------------------------------------------------------------- + @Test + public void test_addTo() { + LocalDateTime base = LocalDateTime.of(2012, 6, 20, 11, 30, 0); + assertEquals(LocalDateTime.of(2013, 8, 23, 11, 30, 5), PeriodDuration.of(P1Y2M3D, DUR_5).addTo(base)); + } + + //----------------------------------------------------------------------- + @Test + public void test_subtractFrom() { + LocalDateTime base = LocalDateTime.of(2012, 6, 20, 11, 30, 0); + assertEquals(LocalDateTime.of(2011, 4, 17, 11, 29, 55), PeriodDuration.of(P1Y2M3D, DUR_5).subtractFrom(base)); + } + + //----------------------------------------------------------------------- + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(PeriodDuration.of(P1Y2M3D, DUR_5), PeriodDuration.of(P1Y2M3D, DUR_5)) + .addEqualityGroup(PeriodDuration.of(P1Y2M3D, DUR_6), PeriodDuration.of(P1Y2M3D, DUR_6)) + .testEquals(); + } + + //----------------------------------------------------------------------- + @Test + public void test_toString() { + assertEquals("P1Y2M3DT5S", PeriodDuration.of(P1Y2M3D, DUR_5).toString()); + assertEquals("P1Y2M3D", PeriodDuration.of(P1Y2M3D, Duration.ZERO).toString()); + assertEquals("PT5S", PeriodDuration.of(Period.ZERO, DUR_5).toString()); + } + +} diff --git a/src/test/java/org/threeten/extra/TestQuarter.java b/src/test/java/org/threeten/extra/TestQuarter.java index dd6c6840..3b60be79 100644 --- a/src/test/java/org/threeten/extra/TestQuarter.java +++ b/src/test/java/org/threeten/extra/TestQuarter.java @@ -63,8 +63,11 @@ import static java.time.temporal.ChronoField.YEAR_OF_ERA; import static java.time.temporal.IsoFields.QUARTER_OF_YEAR; import static java.time.temporal.IsoFields.QUARTER_YEARS; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.threeten.extra.Quarter.Q3; import java.io.Serializable; import java.time.DateTimeException; @@ -73,26 +76,22 @@ import java.time.LocalTime; import java.time.Month; import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; import java.time.format.TextStyle; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQueries; import java.time.temporal.UnsupportedTemporalTypeException; import java.util.Locale; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Test Quarter. */ -@Test public class TestQuarter { - @BeforeMethod - public void setUp() { - } - //----------------------------------------------------------------------- @Test public void test_interfaces() { @@ -109,18 +108,18 @@ public void test_interfaces() { public void test_of_int_singleton() { for (int i = 1; i <= 4; i++) { Quarter test = Quarter.of(i); - assertEquals(test.getValue(), i); + assertEquals(i, test.getValue()); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_valueTooLow() { - Quarter.of(0); + assertThrows(DateTimeException.class, () -> Quarter.of(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_valueTooHigh() { - Quarter.of(5); + assertThrows(DateTimeException.class, () -> Quarter.of(5)); } //----------------------------------------------------------------------- @@ -128,28 +127,28 @@ public void test_of_int_valueTooHigh() { //----------------------------------------------------------------------- @Test public void test_ofMonth_int_singleton() { - assertEquals(Quarter.ofMonth(1), Quarter.Q1); - assertEquals(Quarter.ofMonth(2), Quarter.Q1); - assertEquals(Quarter.ofMonth(3), Quarter.Q1); - assertEquals(Quarter.ofMonth(4), Quarter.Q2); - assertEquals(Quarter.ofMonth(5), Quarter.Q2); - assertEquals(Quarter.ofMonth(6), Quarter.Q2); - assertEquals(Quarter.ofMonth(7), Quarter.Q3); - assertEquals(Quarter.ofMonth(8), Quarter.Q3); - assertEquals(Quarter.ofMonth(9), Quarter.Q3); - assertEquals(Quarter.ofMonth(10), Quarter.Q4); - assertEquals(Quarter.ofMonth(11), Quarter.Q4); - assertEquals(Quarter.ofMonth(12), Quarter.Q4); - } - - @Test(expectedExceptions = DateTimeException.class) + assertSame(Quarter.Q1, Quarter.ofMonth(1)); + assertSame(Quarter.Q1, Quarter.ofMonth(2)); + assertSame(Quarter.Q1, Quarter.ofMonth(3)); + assertSame(Quarter.Q2, Quarter.ofMonth(4)); + assertSame(Quarter.Q2, Quarter.ofMonth(5)); + assertSame(Quarter.Q2, Quarter.ofMonth(6)); + assertSame(Quarter.Q3, Quarter.ofMonth(7)); + assertSame(Quarter.Q3, Quarter.ofMonth(8)); + assertSame(Quarter.Q3, Quarter.ofMonth(9)); + assertSame(Quarter.Q4, Quarter.ofMonth(10)); + assertSame(Quarter.Q4, Quarter.ofMonth(11)); + assertSame(Quarter.Q4, Quarter.ofMonth(12)); + } + + @Test public void test_ofMonth_int_valueTooLow() { - Quarter.ofMonth(0); + assertThrows(DateTimeException.class, () -> Quarter.ofMonth(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_ofMonth_int_valueTooHigh() { - Quarter.ofMonth(13); + assertThrows(DateTimeException.class, () -> Quarter.ofMonth(13)); } //----------------------------------------------------------------------- @@ -157,34 +156,40 @@ public void test_ofMonth_int_valueTooHigh() { //----------------------------------------------------------------------- @Test public void test_from_TemporalAccessor() { - assertEquals(Quarter.from(LocalDate.of(2011, 6, 6)), Quarter.Q2); - assertEquals(Quarter.from(LocalDateTime.of(2012, 2, 3, 12, 30)), Quarter.Q1); + assertEquals(Quarter.Q2, Quarter.from(LocalDate.of(2011, 6, 6))); + assertEquals(Quarter.Q1, Quarter.from(LocalDateTime.of(2012, 2, 3, 12, 30))); } @Test public void test_from_TemporalAccessor_Month() { - assertEquals(Quarter.from(Month.JANUARY), Quarter.Q1); - assertEquals(Quarter.from(Month.FEBRUARY), Quarter.Q1); - assertEquals(Quarter.from(Month.MARCH), Quarter.Q1); - assertEquals(Quarter.from(Month.APRIL), Quarter.Q2); - assertEquals(Quarter.from(Month.MAY), Quarter.Q2); - assertEquals(Quarter.from(Month.JUNE), Quarter.Q2); - assertEquals(Quarter.from(Month.JULY), Quarter.Q3); - assertEquals(Quarter.from(Month.AUGUST), Quarter.Q3); - assertEquals(Quarter.from(Month.SEPTEMBER), Quarter.Q3); - assertEquals(Quarter.from(Month.OCTOBER), Quarter.Q4); - assertEquals(Quarter.from(Month.NOVEMBER), Quarter.Q4); - assertEquals(Quarter.from(Month.DECEMBER), Quarter.Q4); - } - - @Test(expectedExceptions = DateTimeException.class) + assertEquals(Quarter.Q1, Quarter.from(Month.JANUARY)); + assertEquals(Quarter.Q1, Quarter.from(Month.FEBRUARY)); + assertEquals(Quarter.Q1, Quarter.from(Month.MARCH)); + assertEquals(Quarter.Q2, Quarter.from(Month.APRIL)); + assertEquals(Quarter.Q2, Quarter.from(Month.MAY)); + assertEquals(Quarter.Q2, Quarter.from(Month.JUNE)); + assertEquals(Quarter.Q3, Quarter.from(Month.JULY)); + assertEquals(Quarter.Q3, Quarter.from(Month.AUGUST)); + assertEquals(Quarter.Q3, Quarter.from(Month.SEPTEMBER)); + assertEquals(Quarter.Q4, Quarter.from(Month.OCTOBER)); + assertEquals(Quarter.Q4, Quarter.from(Month.NOVEMBER)); + assertEquals(Quarter.Q4, Quarter.from(Month.DECEMBER)); + } + + @Test public void test_from_TemporalAccessorl_invalid_noDerive() { - Quarter.from(LocalTime.of(12, 30)); + assertThrows(DateTimeException.class, () -> Quarter.from(LocalTime.of(12, 30))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_TemporalAccessor_null() { - Quarter.from((TemporalAccessor) null); + assertThrows(NullPointerException.class, () -> Quarter.from((TemporalAccessor) null)); + } + + @Test + public void test_from_parse_CharSequence() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("'Q'Q"); + assertEquals(Q3, formatter.parse("Q3", Quarter::from)); } //----------------------------------------------------------------------- @@ -192,120 +197,123 @@ public void test_from_TemporalAccessor_null() { //----------------------------------------------------------------------- @Test public void test_getDisplayName() { - assertEquals(Quarter.Q1.getDisplayName(TextStyle.SHORT, Locale.US), "Q1"); + assertEquals("Q1", Quarter.Q1.getDisplayName(TextStyle.SHORT, Locale.US)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getDisplayName_nullStyle() { - Quarter.Q1.getDisplayName(null, Locale.US); + assertThrows(NullPointerException.class, () -> Quarter.Q1.getDisplayName(null, Locale.US)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getDisplayName_nullLocale() { - Quarter.Q1.getDisplayName(TextStyle.FULL, null); + assertThrows(NullPointerException.class, () -> Quarter.Q1.getDisplayName(TextStyle.FULL, null)); } //----------------------------------------------------------------------- // isSupported() //----------------------------------------------------------------------- + @Test public void test_isSupported() { Quarter test = Quarter.Q1; - assertEquals(test.isSupported(null), false); - assertEquals(test.isSupported(NANO_OF_SECOND), false); - assertEquals(test.isSupported(NANO_OF_DAY), false); - assertEquals(test.isSupported(MICRO_OF_SECOND), false); - assertEquals(test.isSupported(MICRO_OF_DAY), false); - assertEquals(test.isSupported(MILLI_OF_SECOND), false); - assertEquals(test.isSupported(MILLI_OF_DAY), false); - assertEquals(test.isSupported(SECOND_OF_MINUTE), false); - assertEquals(test.isSupported(SECOND_OF_DAY), false); - assertEquals(test.isSupported(MINUTE_OF_HOUR), false); - assertEquals(test.isSupported(MINUTE_OF_DAY), false); - assertEquals(test.isSupported(HOUR_OF_AMPM), false); - assertEquals(test.isSupported(CLOCK_HOUR_OF_AMPM), false); - assertEquals(test.isSupported(HOUR_OF_DAY), false); - assertEquals(test.isSupported(CLOCK_HOUR_OF_DAY), false); - assertEquals(test.isSupported(AMPM_OF_DAY), false); - assertEquals(test.isSupported(DAY_OF_WEEK), false); - assertEquals(test.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH), false); - assertEquals(test.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR), false); - assertEquals(test.isSupported(DAY_OF_MONTH), false); - assertEquals(test.isSupported(DAY_OF_YEAR), false); - assertEquals(test.isSupported(EPOCH_DAY), false); - assertEquals(test.isSupported(ALIGNED_WEEK_OF_MONTH), false); - assertEquals(test.isSupported(ALIGNED_WEEK_OF_YEAR), false); - assertEquals(test.isSupported(MONTH_OF_YEAR), false); - assertEquals(test.isSupported(PROLEPTIC_MONTH), false); - assertEquals(test.isSupported(YEAR_OF_ERA), false); - assertEquals(test.isSupported(YEAR), false); - assertEquals(test.isSupported(ERA), false); - assertEquals(test.isSupported(INSTANT_SECONDS), false); - assertEquals(test.isSupported(OFFSET_SECONDS), false); - assertEquals(test.isSupported(QUARTER_OF_YEAR), true); + assertEquals(false, test.isSupported(null)); + assertEquals(false, test.isSupported(NANO_OF_SECOND)); + assertEquals(false, test.isSupported(NANO_OF_DAY)); + assertEquals(false, test.isSupported(MICRO_OF_SECOND)); + assertEquals(false, test.isSupported(MICRO_OF_DAY)); + assertEquals(false, test.isSupported(MILLI_OF_SECOND)); + assertEquals(false, test.isSupported(MILLI_OF_DAY)); + assertEquals(false, test.isSupported(SECOND_OF_MINUTE)); + assertEquals(false, test.isSupported(SECOND_OF_DAY)); + assertEquals(false, test.isSupported(MINUTE_OF_HOUR)); + assertEquals(false, test.isSupported(MINUTE_OF_DAY)); + assertEquals(false, test.isSupported(HOUR_OF_AMPM)); + assertEquals(false, test.isSupported(CLOCK_HOUR_OF_AMPM)); + assertEquals(false, test.isSupported(HOUR_OF_DAY)); + assertEquals(false, test.isSupported(CLOCK_HOUR_OF_DAY)); + assertEquals(false, test.isSupported(AMPM_OF_DAY)); + assertEquals(false, test.isSupported(DAY_OF_WEEK)); + assertEquals(false, test.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(false, test.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(false, test.isSupported(DAY_OF_MONTH)); + assertEquals(false, test.isSupported(DAY_OF_YEAR)); + assertEquals(false, test.isSupported(EPOCH_DAY)); + assertEquals(false, test.isSupported(ALIGNED_WEEK_OF_MONTH)); + assertEquals(false, test.isSupported(ALIGNED_WEEK_OF_YEAR)); + assertEquals(false, test.isSupported(MONTH_OF_YEAR)); + assertEquals(false, test.isSupported(PROLEPTIC_MONTH)); + assertEquals(false, test.isSupported(YEAR_OF_ERA)); + assertEquals(false, test.isSupported(YEAR)); + assertEquals(false, test.isSupported(ERA)); + assertEquals(false, test.isSupported(INSTANT_SECONDS)); + assertEquals(false, test.isSupported(OFFSET_SECONDS)); + assertEquals(true, test.isSupported(QUARTER_OF_YEAR)); } //----------------------------------------------------------------------- // range() //----------------------------------------------------------------------- + @Test public void test_range() { - assertEquals(Quarter.Q1.range(QUARTER_OF_YEAR), QUARTER_OF_YEAR.range()); + assertEquals(QUARTER_OF_YEAR.range(), Quarter.Q1.range(QUARTER_OF_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_invalidField() { - Quarter.Q1.range(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> Quarter.Q1.range(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_range_null() { - Quarter.Q1.range(null); + assertThrows(NullPointerException.class, () -> Quarter.Q1.range(null)); } //----------------------------------------------------------------------- // get() //----------------------------------------------------------------------- + @Test public void test_get() { - assertEquals(Quarter.Q1.get(QUARTER_OF_YEAR), 1); - assertEquals(Quarter.Q2.get(QUARTER_OF_YEAR), 2); - assertEquals(Quarter.Q3.get(QUARTER_OF_YEAR), 3); - assertEquals(Quarter.Q4.get(QUARTER_OF_YEAR), 4); + assertEquals(1, Quarter.Q1.get(QUARTER_OF_YEAR)); + assertEquals(2, Quarter.Q2.get(QUARTER_OF_YEAR)); + assertEquals(3, Quarter.Q3.get(QUARTER_OF_YEAR)); + assertEquals(4, Quarter.Q4.get(QUARTER_OF_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_get_invalidField() { - Quarter.Q2.get(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> Quarter.Q2.get(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_get_null() { - Quarter.Q2.get(null); + assertThrows(NullPointerException.class, () -> Quarter.Q2.get(null)); } //----------------------------------------------------------------------- // getLong() //----------------------------------------------------------------------- + @Test public void test_getLong() { - assertEquals(Quarter.Q1.getLong(QUARTER_OF_YEAR), 1); - assertEquals(Quarter.Q2.getLong(QUARTER_OF_YEAR), 2); - assertEquals(Quarter.Q3.getLong(QUARTER_OF_YEAR), 3); - assertEquals(Quarter.Q4.getLong(QUARTER_OF_YEAR), 4); + assertEquals(1, Quarter.Q1.getLong(QUARTER_OF_YEAR)); + assertEquals(2, Quarter.Q2.getLong(QUARTER_OF_YEAR)); + assertEquals(3, Quarter.Q3.getLong(QUARTER_OF_YEAR)); + assertEquals(4, Quarter.Q4.getLong(QUARTER_OF_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_invalidField() { - Quarter.Q2.getLong(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> Quarter.Q2.getLong(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getLong_null() { - Quarter.Q2.getLong(null); + assertThrows(NullPointerException.class, () -> Quarter.Q2.getLong(null)); } //----------------------------------------------------------------------- // plus(long), plus(long,unit) //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {1, -5, 4}, {1, -4, 1}, @@ -321,16 +329,16 @@ Object[][] data_plus() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_long(int base, long amount, int expected) { - assertEquals(Quarter.of(base).plus(amount), Quarter.of(expected)); + assertEquals(Quarter.of(expected), Quarter.of(base).plus(amount)); } //----------------------------------------------------------------------- // minus(long), minus(long,unit) //----------------------------------------------------------------------- - @DataProvider(name = "minus") - Object[][] data_minus() { + public static Object[][] data_minus() { return new Object[][] { {1, -5, 2}, {1, -4, 1}, @@ -346,9 +354,10 @@ Object[][] data_minus() { }; } - @Test(dataProvider = "minus") + @ParameterizedTest + @MethodSource("data_minus") public void test_minus_long(int base, long amount, int expected) { - assertEquals(Quarter.of(base).minus(amount), Quarter.of(expected)); + assertEquals(Quarter.of(expected), Quarter.of(base).minus(amount)); } //----------------------------------------------------------------------- @@ -356,14 +365,14 @@ public void test_minus_long(int base, long amount, int expected) { //----------------------------------------------------------------------- @Test public void test_length_boolean() { - assertEquals(Quarter.Q1.length(true), 91); - assertEquals(Quarter.Q1.length(false), 90); - assertEquals(Quarter.Q2.length(true), 91); - assertEquals(Quarter.Q2.length(false), 91); - assertEquals(Quarter.Q3.length(true), 92); - assertEquals(Quarter.Q3.length(false), 92); - assertEquals(Quarter.Q4.length(true), 92); - assertEquals(Quarter.Q4.length(false), 92); + assertEquals(91, Quarter.Q1.length(true)); + assertEquals(90, Quarter.Q1.length(false)); + assertEquals(91, Quarter.Q2.length(true)); + assertEquals(91, Quarter.Q2.length(false)); + assertEquals(92, Quarter.Q3.length(true)); + assertEquals(92, Quarter.Q3.length(false)); + assertEquals(92, Quarter.Q4.length(true)); + assertEquals(92, Quarter.Q4.length(false)); } //----------------------------------------------------------------------- @@ -371,10 +380,10 @@ public void test_length_boolean() { //----------------------------------------------------------------------- @Test public void test_firstMonth() { - assertEquals(Quarter.Q1.firstMonth(), Month.JANUARY); - assertEquals(Quarter.Q2.firstMonth(), Month.APRIL); - assertEquals(Quarter.Q3.firstMonth(), Month.JULY); - assertEquals(Quarter.Q4.firstMonth(), Month.OCTOBER); + assertEquals(Month.JANUARY, Quarter.Q1.firstMonth()); + assertEquals(Month.APRIL, Quarter.Q2.firstMonth()); + assertEquals(Month.JULY, Quarter.Q3.firstMonth()); + assertEquals(Month.OCTOBER, Quarter.Q4.firstMonth()); } //----------------------------------------------------------------------- @@ -382,13 +391,13 @@ public void test_firstMonth() { //----------------------------------------------------------------------- @Test public void test_query() { - assertEquals(Quarter.Q1.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); - assertEquals(Quarter.Q1.query(TemporalQueries.localDate()), null); - assertEquals(Quarter.Q1.query(TemporalQueries.localTime()), null); - assertEquals(Quarter.Q1.query(TemporalQueries.offset()), null); - assertEquals(Quarter.Q1.query(TemporalQueries.precision()), QUARTER_YEARS); - assertEquals(Quarter.Q1.query(TemporalQueries.zone()), null); - assertEquals(Quarter.Q1.query(TemporalQueries.zoneId()), null); + assertEquals(IsoChronology.INSTANCE, Quarter.Q1.query(TemporalQueries.chronology())); + assertEquals(null, Quarter.Q1.query(TemporalQueries.localDate())); + assertEquals(null, Quarter.Q1.query(TemporalQueries.localTime())); + assertEquals(null, Quarter.Q1.query(TemporalQueries.offset())); + assertEquals(QUARTER_YEARS, Quarter.Q1.query(TemporalQueries.precision())); + assertEquals(null, Quarter.Q1.query(TemporalQueries.zone())); + assertEquals(null, Quarter.Q1.query(TemporalQueries.zoneId())); } //----------------------------------------------------------------------- @@ -396,10 +405,10 @@ public void test_query() { //----------------------------------------------------------------------- @Test public void test_toString() { - assertEquals(Quarter.Q1.toString(), "Q1"); - assertEquals(Quarter.Q2.toString(), "Q2"); - assertEquals(Quarter.Q3.toString(), "Q3"); - assertEquals(Quarter.Q4.toString(), "Q4"); + assertEquals("Q1", Quarter.Q1.toString()); + assertEquals("Q2", Quarter.Q2.toString()); + assertEquals("Q3", Quarter.Q3.toString()); + assertEquals("Q4", Quarter.Q4.toString()); } //----------------------------------------------------------------------- @@ -407,8 +416,8 @@ public void test_toString() { //----------------------------------------------------------------------- @Test public void test_enum() { - assertEquals(Quarter.valueOf("Q4"), Quarter.Q4); - assertEquals(Quarter.values()[0], Quarter.Q1); + assertEquals(Quarter.Q4, Quarter.valueOf("Q4")); + assertEquals(Quarter.Q1, Quarter.values()[0]); } } diff --git a/src/test/java/org/threeten/extra/TestSeconds.java b/src/test/java/org/threeten/extra/TestSeconds.java new file mode 100644 index 00000000..cec47027 --- /dev/null +++ b/src/test/java/org/threeten/extra/TestSeconds.java @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.time.Duration; +import java.time.LocalTime; +import java.time.format.DateTimeParseException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; + +/** + * Test class. + */ +public class TestSeconds { + + //----------------------------------------------------------------------- + @Test + public void test_isSerializable() { + assertTrue(Serializable.class.isAssignableFrom(Seconds.class)); + } + + //----------------------------------------------------------------------- + @Test + public void test_deserializationSingleton() throws Exception { + Seconds test = Seconds.ZERO; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } + } + + //----------------------------------------------------------------------- + @Test + public void test_ZERO() { + assertSame(Seconds.ZERO, Seconds.of(0)); + assertEquals(Seconds.ZERO, Seconds.of(0)); + assertEquals(0, Seconds.ZERO.getAmount()); + assertFalse(Seconds.ZERO.isNegative()); + assertTrue(Seconds.ZERO.isZero()); + assertFalse(Seconds.ZERO.isPositive()); + } + + //----------------------------------------------------------------------- + @Test + public void test_of() { + assertEquals(0, Seconds.of(0).getAmount()); + assertEquals(1, Seconds.of(1).getAmount()); + assertEquals(2, Seconds.of(2).getAmount()); + assertEquals(Integer.MAX_VALUE, Seconds.of(Integer.MAX_VALUE).getAmount()); + assertEquals(-1, Seconds.of(-1).getAmount()); + assertEquals(-2, Seconds.of(-2).getAmount()); + assertEquals(Integer.MIN_VALUE, Seconds.of(Integer.MIN_VALUE).getAmount()); + } + + @Test + public void test_ofMinusOne() { + assertEquals(-1, Seconds.of(-1).getAmount()); + assertTrue(Seconds.of(-1).isNegative()); + assertFalse(Seconds.of(-1).isZero()); + assertFalse(Seconds.of(-1).isPositive()); + } + + @Test + public void test_ofPlusOne() { + assertEquals(1, Seconds.of(1).getAmount()); + assertFalse(Seconds.of(1).isNegative()); + assertFalse(Seconds.of(1).isZero()); + assertTrue(Seconds.of(1).isPositive()); + } + + //----------------------------------------------------------------------- + @Test + public void test_ofHours() { + assertEquals(0, Seconds.ofHours(0).getAmount()); + assertEquals(3600, Seconds.ofHours(1).getAmount()); + assertEquals(7200, Seconds.ofHours(2).getAmount()); + assertEquals((Integer.MAX_VALUE / 3600) * 3600, Seconds.ofHours(Integer.MAX_VALUE / 3600).getAmount()); + assertEquals(-3600, Seconds.ofHours(-1).getAmount()); + assertEquals(-7200, Seconds.ofHours(-2).getAmount()); + assertEquals((Integer.MIN_VALUE / 3600) * 3600, Seconds.ofHours(Integer.MIN_VALUE / 3600).getAmount()); + } + + @Test + public void test_ofHours_overflow() { + assertThrows(ArithmeticException.class, () -> Seconds.ofHours((Integer.MAX_VALUE / 3600) + 3600)); + } + + //----------------------------------------------------------------------- + @Test + public void test_ofMinutes() { + assertEquals(0, Seconds.ofMinutes(0).getAmount()); + assertEquals(60, Seconds.ofMinutes(1).getAmount()); + assertEquals(120, Seconds.ofMinutes(2).getAmount()); + assertEquals((Integer.MAX_VALUE / 60) * 60, Seconds.ofMinutes(Integer.MAX_VALUE / 60).getAmount()); + assertEquals(-60, Seconds.ofMinutes(-1).getAmount()); + assertEquals(-120, Seconds.ofMinutes(-2).getAmount()); + assertEquals((Integer.MIN_VALUE / 60) * 60, Seconds.ofMinutes(Integer.MIN_VALUE / 60).getAmount()); + } + + @Test + public void test_ofMinutes_overflow() { + assertThrows(ArithmeticException.class, () -> Seconds.ofMinutes((Integer.MAX_VALUE / 60) + 60)); + } + + //----------------------------------------------------------------------- + public static Object[][] data_valid() { + return new Object[][] { + {"PT0S", 0}, + {"PT1S", 1}, + {"PT2S", 2}, + {"PT123456789S", 123456789}, + {"PT+0S", 0}, + {"PT+2S", 2}, + {"PT-0S", 0}, + {"PT-2S", -2}, + + {"PT0M", 0}, + {"PT1M", 60}, + {"PT2M", 120}, + {"PT1234M", 1234 * 60}, + {"PT+0M", 0}, + {"PT+2M", 120}, + {"PT-0M", 0}, + {"PT-2M", -120}, + + {"PT0H", 0}, + {"PT1H", 60 * 60}, + {"PT2H", 120 * 60}, + {"PT1234H", 1234 * 60 * 60}, + {"PT+0H", 0}, + {"PT+2H", 120 * 60}, + {"PT-0H", 0}, + {"PT-2H", -120 * 60}, + + {"P0D", 0}, + {"P1D", 60 * 60 * 24}, + {"P2D", 120 * 60 * 24}, + {"P1234D", 1234 * 60 * 60 * 24}, + {"P+0D", 0}, + {"P+2D", 120 * 60 * 24}, + {"P-0D", 0}, + {"P-2D", -120 * 60 * 24}, + + {"PT0M0S", 0}, + {"PT2M3S", 2 * 60 + 3}, + {"PT+2M3S", 2 * 60 + 3}, + {"PT2M+3S", 2 * 60 + 3}, + {"PT-2M3S", -2 * 60 + 3}, + {"PT2M-3S", 2 * 60 - 3}, + {"PT-2M-3S", -2 * 60 - 3}, + + {"PT0H0S", 0}, + {"PT2H3S", 2 * 3600 + 3}, + {"PT+2H3S", 2 * 3600 + 3}, + {"PT2H+3S", 2 * 3600 + 3}, + {"PT-2H3S", -2 * 3600 + 3}, + {"PT2H-3S", 2 * 3600 - 3}, + {"PT-2H-3S", -2 * 3600 - 3}, + + {"P0DT0H0M0S", 0}, + {"P5DT2H4M3S", 5 * 86400 + 2 * 3600 + 4 * 60 + 3}, + }; + } + + @ParameterizedTest + @MethodSource("data_valid") + public void test_parse_CharSequence_valid(String str, int expectedSeconds) { + assertEquals(Seconds.of(expectedSeconds), Seconds.parse(str)); + } + + @ParameterizedTest + @MethodSource("data_valid") + public void test_parse_CharSequence_valid_initialPlus(String str, int expectedSeconds) { + assertEquals(Seconds.of(expectedSeconds), Seconds.parse("+" + str)); + } + + @ParameterizedTest + @MethodSource("data_valid") + public void test_parse_CharSequence_valid_initialMinus(String str, int expectedSeconds) { + assertEquals(Seconds.of(-expectedSeconds), Seconds.parse("-" + str)); + } + + public static Object[][] data_invalid() { + return new Object[][] { + {"P3W"}, + {"P3Q"}, + {"P1M2Y"}, + + {"3"}, + {"-3"}, + {"3S"}, + {"-3S"}, + {"P3S"}, + {"P3"}, + {"P-3"}, + {"PS"}, + {"T3"}, + {"PT3"}, + }; + } + + @ParameterizedTest + @MethodSource("data_invalid") + public void test_parse_CharSequence_invalid(String str) { + assertThrows(DateTimeParseException.class, () -> Seconds.parse(str)); + } + + @Test + public void test_parse_CharSequence_null() { + assertThrows(NullPointerException.class, () -> Seconds.parse((CharSequence) null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_plus_TemporalAmount_Seconds() { + Seconds test5 = Seconds.of(5); + assertEquals(Seconds.of(5), test5.plus(Seconds.of(0))); + assertEquals(Seconds.of(7), test5.plus(Seconds.of(2))); + assertEquals(Seconds.of(3), test5.plus(Seconds.of(-2))); + assertEquals(Seconds.of(Integer.MAX_VALUE), Seconds.of(Integer.MAX_VALUE - 1).plus(Seconds.of(1))); + assertEquals(Seconds.of(Integer.MIN_VALUE), Seconds.of(Integer.MIN_VALUE + 1).plus(Seconds.of(-1))); + } + + @Test + public void test_plus_TemporalAmount_overflowTooBig() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MAX_VALUE - 1).plus(Seconds.of(2))); + } + + @Test + public void test_plus_TemporalAmount_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MIN_VALUE + 1).plus(Seconds.of(-2))); + } + + @Test + public void test_plus_TemporalAmount_null() { + assertThrows(NullPointerException.class, () -> Seconds.of(Integer.MIN_VALUE + 1).plus(null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_plus_int() { + Seconds test5 = Seconds.of(5); + assertEquals(Seconds.of(5), test5.plus(0)); + assertEquals(Seconds.of(7), test5.plus(2)); + assertEquals(Seconds.of(3), test5.plus(-2)); + assertEquals(Seconds.of(Integer.MAX_VALUE), Seconds.of(Integer.MAX_VALUE - 1).plus(1)); + assertEquals(Seconds.of(Integer.MIN_VALUE), Seconds.of(Integer.MIN_VALUE + 1).plus(-1)); + } + + @Test + public void test_plus_int_overflowTooBig() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MAX_VALUE - 1).plus(2)); + } + + @Test + public void test_plus_int_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MIN_VALUE + 1).plus(-2)); + } + + //----------------------------------------------------------------------- + @Test + public void test_minus_TemporalAmount_Seconds() { + Seconds test5 = Seconds.of(5); + assertEquals(Seconds.of(5), test5.minus(Seconds.of(0))); + assertEquals(Seconds.of(3), test5.minus(Seconds.of(2))); + assertEquals(Seconds.of(7), test5.minus(Seconds.of(-2))); + assertEquals(Seconds.of(Integer.MAX_VALUE), Seconds.of(Integer.MAX_VALUE - 1).minus(Seconds.of(-1))); + assertEquals(Seconds.of(Integer.MIN_VALUE), Seconds.of(Integer.MIN_VALUE + 1).minus(Seconds.of(1))); + } + + @Test + public void test_minus_TemporalAmount_overflowTooBig() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MAX_VALUE - 1).minus(Seconds.of(-2))); + } + + @Test + public void test_minus_TemporalAmount_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MIN_VALUE + 1).minus(Seconds.of(2))); + } + + @Test + public void test_minus_TemporalAmount_null() { + assertThrows(NullPointerException.class, () -> Seconds.of(Integer.MIN_VALUE + 1).minus(null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_minus_int() { + Seconds test5 = Seconds.of(5); + assertEquals(Seconds.of(5), test5.minus(0)); + assertEquals(Seconds.of(3), test5.minus(2)); + assertEquals(Seconds.of(7), test5.minus(-2)); + assertEquals(Seconds.of(Integer.MAX_VALUE), Seconds.of(Integer.MAX_VALUE - 1).minus(-1)); + assertEquals(Seconds.of(Integer.MIN_VALUE), Seconds.of(Integer.MIN_VALUE + 1).minus(1)); + } + + @Test + public void test_minus_int_overflowTooBig() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MAX_VALUE - 1).minus(-2)); + } + + @Test + public void test_minus_int_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MIN_VALUE + 1).minus(2)); + } + + //----------------------------------------------------------------------- + @Test + public void test_multipliedBy() { + Seconds test5 = Seconds.of(5); + assertEquals(Seconds.of(0), test5.multipliedBy(0)); + assertEquals(Seconds.of(5), test5.multipliedBy(1)); + assertEquals(Seconds.of(10), test5.multipliedBy(2)); + assertEquals(Seconds.of(15), test5.multipliedBy(3)); + assertEquals(Seconds.of(-15), test5.multipliedBy(-3)); + } + + @Test + public void test_multipliedBy_negate() { + Seconds test5 = Seconds.of(5); + assertEquals(Seconds.of(-15), test5.multipliedBy(-3)); + } + + @Test + public void test_multipliedBy_overflowTooBig() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2)); + } + + @Test + public void test_multipliedBy_overflowTooSmall() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2)); + } + + //----------------------------------------------------------------------- + @Test + public void test_dividedBy() { + Seconds test12 = Seconds.of(12); + assertEquals(Seconds.of(12), test12.dividedBy(1)); + assertEquals(Seconds.of(6), test12.dividedBy(2)); + assertEquals(Seconds.of(4), test12.dividedBy(3)); + assertEquals(Seconds.of(3), test12.dividedBy(4)); + assertEquals(Seconds.of(2), test12.dividedBy(5)); + assertEquals(Seconds.of(2), test12.dividedBy(6)); + assertEquals(Seconds.of(-4), test12.dividedBy(-3)); + } + + @Test + public void test_dividedBy_negate() { + Seconds test12 = Seconds.of(12); + assertEquals(Seconds.of(-4), test12.dividedBy(-3)); + } + + @Test + public void test_dividedBy_divideByZero() { + assertThrows(ArithmeticException.class, () -> Seconds.of(1).dividedBy(0)); + } + + //----------------------------------------------------------------------- + @Test + public void test_negated() { + assertEquals(Seconds.of(0), Seconds.of(0).negated()); + assertEquals(Seconds.of(-12), Seconds.of(12).negated()); + assertEquals(Seconds.of(12), Seconds.of(-12).negated()); + assertEquals(Seconds.of(-Integer.MAX_VALUE), Seconds.of(Integer.MAX_VALUE).negated()); + } + + @Test + public void test_negated_overflow() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MIN_VALUE).negated()); + } + + //----------------------------------------------------------------------- + @Test + public void test_abs() { + assertEquals(Seconds.of(0), Seconds.of(0).abs()); + assertEquals(Seconds.of(12), Seconds.of(12).abs()); + assertEquals(Seconds.of(12), Seconds.of(-12).abs()); + assertEquals(Seconds.of(Integer.MAX_VALUE), Seconds.of(Integer.MAX_VALUE).abs()); + assertEquals(Seconds.of(Integer.MAX_VALUE), Seconds.of(-Integer.MAX_VALUE).abs()); + } + + @Test + public void test_abs_overflow() { + assertThrows(ArithmeticException.class, () -> Seconds.of(Integer.MIN_VALUE).abs()); + } + + //----------------------------------------------------------------------- + @Test + public void test_addTo() { + LocalTime base = LocalTime.of(11, 30); + assertEquals(LocalTime.of(11, 30), Seconds.of(0).addTo(base)); + assertEquals(LocalTime.of(11, 30, 6), Seconds.of(6).addTo(base)); + } + + //----------------------------------------------------------------------- + @Test + public void test_subtractFrom() { + LocalTime base = LocalTime.of(11, 30); + assertEquals(LocalTime.of(11, 30), Seconds.of(0).subtractFrom(base)); + assertEquals(LocalTime.of(11, 29, 54), Seconds.of(6).subtractFrom(base)); + } + + //----------------------------------------------------------------------- + @Test + public void test_toDuration() { + for (int i = -20; i < 20; i++) { + assertEquals(Duration.ofSeconds(i), Seconds.of(i).toDuration()); + } + } + + //----------------------------------------------------------------------- + @Test + public void test_compareTo() { + Seconds test5 = Seconds.of(5); + Seconds test6 = Seconds.of(6); + assertEquals(0, test5.compareTo(test5)); + assertEquals(-1, test5.compareTo(test6)); + assertEquals(1, test6.compareTo(test5)); + } + + @Test + public void test_compareTo_null() { + Seconds test5 = Seconds.of(5); + assertThrows(NullPointerException.class, () -> test5.compareTo(null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Seconds.of(5), Seconds.of(5)) + .addEqualityGroup(Seconds.of(6), Seconds.of(6)) + .testEquals(); + } + + //----------------------------------------------------------------------- + @Test + public void test_toString() { + Seconds test5 = Seconds.of(5); + assertEquals("PT5S", test5.toString()); + Seconds testM1 = Seconds.of(-1); + assertEquals("PT-1S", testM1.toString()); + } + +} diff --git a/src/test/java/org/threeten/extra/TestTemporalFields.java b/src/test/java/org/threeten/extra/TestTemporalFields.java new file mode 100644 index 00000000..d74f8972 --- /dev/null +++ b/src/test/java/org/threeten/extra/TestTemporalFields.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.threeten.extra.TemporalFields.DAY_OF_HALF; +import static org.threeten.extra.TemporalFields.HALF_OF_YEAR; +import static org.threeten.extra.TemporalFields.HALF_YEARS; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.YearMonth; +import java.time.format.ResolverStyle; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.time.temporal.ValueRange; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +/** + * Test TemporalFields. + */ +public class TestTemporalFields { + + //----------------------------------------------------------------------- + // DAY_OF_HALF + //----------------------------------------------------------------------- + @Test + public void test_DAY_OF_HALF() { + assertEquals(DAYS, DAY_OF_HALF.getBaseUnit()); + assertEquals(HALF_YEARS, DAY_OF_HALF.getRangeUnit()); + assertEquals(true, DAY_OF_HALF.isDateBased()); + assertEquals(false, DAY_OF_HALF.isTimeBased()); + assertEquals("DayOfHalf", DAY_OF_HALF.toString()); + + assertEquals(true, DAY_OF_HALF.isSupportedBy(LocalDate.of(2023, 6, 30))); + assertEquals(false, DAY_OF_HALF.isSupportedBy(DayOfYear.of(32))); + assertEquals(false, DAY_OF_HALF.isSupportedBy(YearMonth.of(2023, 6))); + assertEquals(181, DAY_OF_HALF.getFrom(LocalDate.of(2023, 6, 30))); + assertEquals(184, DAY_OF_HALF.getFrom(LocalDate.of(2023, 12, 31))); + + assertEquals(ValueRange.of(1, 181, 184), DAY_OF_HALF.range()); + assertEquals(ValueRange.of(1, 181), DAY_OF_HALF.rangeRefinedBy(LocalDate.of(2023, 6, 30))); + assertEquals(ValueRange.of(1, 182), DAY_OF_HALF.rangeRefinedBy(LocalDate.of(2024, 6, 30))); + assertEquals(ValueRange.of(1, 184), DAY_OF_HALF.rangeRefinedBy(LocalDate.of(2023, 7, 30))); + + assertEquals(LocalDate.of(2023, 1, 20), DAY_OF_HALF.adjustInto(LocalDate.of(2023, 6, 30), 20)); + assertEquals(LocalDate.of(2023, 7, 20), DAY_OF_HALF.adjustInto(LocalDate.of(2023, 7, 1), 20)); + } + + //----------------------------------------------------------------------- + // HALF_OF_YEAR + //----------------------------------------------------------------------- + @Test + public void test_HALF_OF_YEAR() { + assertEquals(HALF_YEARS, HALF_OF_YEAR.getBaseUnit()); + assertEquals(YEARS, HALF_OF_YEAR.getRangeUnit()); + assertEquals(true, HALF_OF_YEAR.isDateBased()); + assertEquals(false, HALF_OF_YEAR.isTimeBased()); + assertEquals("HalfOfYear", HALF_OF_YEAR.toString()); + + assertEquals(true, HALF_OF_YEAR.isSupportedBy(LocalDate.of(2023, 6, 30))); + assertEquals(true, HALF_OF_YEAR.isSupportedBy(Quarter.Q2)); + assertEquals(false, HALF_OF_YEAR.isSupportedBy(DayOfYear.of(32))); + assertEquals(true, HALF_OF_YEAR.isSupportedBy(YearMonth.of(2023, 6))); + assertEquals(1, HALF_OF_YEAR.getFrom(LocalDate.of(2023, 6, 30))); + assertEquals(2, HALF_OF_YEAR.getFrom(LocalDate.of(2023, 12, 31))); + + assertEquals(ValueRange.of(1, 2), HALF_OF_YEAR.range()); + assertEquals(ValueRange.of(1, 2), HALF_OF_YEAR.rangeRefinedBy(LocalDate.of(2023, 6, 30))); + assertEquals(ValueRange.of(1, 2), HALF_OF_YEAR.rangeRefinedBy(LocalDate.of(2024, 6, 30))); + assertEquals(ValueRange.of(1, 2), HALF_OF_YEAR.rangeRefinedBy(LocalDate.of(2023, 7, 30))); + + assertEquals(LocalDate.of(2023, 12, 30), HALF_OF_YEAR.adjustInto(LocalDate.of(2023, 6, 30), 2)); + assertEquals(LocalDate.of(2023, 7, 1), HALF_OF_YEAR.adjustInto(LocalDate.of(2023, 7, 1), 2)); + + assertEquals(YearMonth.of(2023, 12), HALF_OF_YEAR.adjustInto(YearMonth.of(2023, 6), 2)); + } + + //----------------------------------------------------------------------- + // HALF_YEARS + //----------------------------------------------------------------------- + @Test + public void test_HALF_YEARS() { + assertEquals(true, HALF_YEARS.isDateBased()); + assertEquals(false, HALF_YEARS.isTimeBased()); + assertEquals("HalfYears", HALF_YEARS.toString()); + + assertEquals(true, HALF_YEARS.isSupportedBy(LocalDate.of(2023, 6, 30))); + assertEquals(true, HALF_YEARS.isSupportedBy(YearQuarter.of(2023, 2))); + assertEquals(true, HALF_YEARS.isSupportedBy(YearMonth.of(2023, 6))); + + assertEquals(LocalDate.of(2023, 12, 30), HALF_YEARS.addTo(LocalDate.of(2023, 6, 30), 1)); + assertEquals(YearQuarter.of(2023, 4), HALF_YEARS.addTo(YearQuarter.of(2023, 2), 1)); + assertEquals(YearMonth.of(2023, 12), HALF_YEARS.addTo(YearMonth.of(2023, 6), 1)); + + assertEquals(0, HALF_YEARS.between(LocalDate.of(2023, 6, 30), LocalDate.of(2023, 12, 29))); + assertEquals(1, HALF_YEARS.between(LocalDate.of(2023, 6, 30), LocalDate.of(2023, 12, 30))); + + assertEquals(0, HALF_YEARS.between(YearQuarter.of(2023, 2), YearQuarter.of(2023, 3))); + assertEquals(1, HALF_YEARS.between(YearQuarter.of(2023, 2), YearQuarter.of(2023, 4))); + + assertEquals(0, HALF_YEARS.between(YearMonth.of(2023, 2), YearMonth.of(2023, 7))); + assertEquals(1, HALF_YEARS.between(YearMonth.of(2023, 2), YearMonth.of(2023, 8))); + } + + //------------------------------------------------------------------------- + @Test + public void test_resolveStrict() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 20L); + values.put(HALF_OF_YEAR, 2L); + values.put(YEAR, 2023L); + TemporalAccessor resolved = DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.STRICT); + assertEquals(LocalDate.of(2023, 7, 20), resolved.query(LocalDate::from)); + } + + @Test + public void test_resolveStrict_noYear() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 20L); + values.put(HALF_OF_YEAR, 1L); + assertNull(DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.STRICT)); + } + + @Test + public void test_resolveStrict_halfOfYear() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 20L); + values.put(YEAR, 2023L); + assertNull(DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.STRICT)); + } + + @Test + public void test_resolveStrict_badHalfOfYear() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 20L); + values.put(HALF_OF_YEAR, 3L); + values.put(YEAR, 2023L); + assertThrows(DateTimeException.class, () -> DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.STRICT)); + } + + @Test + public void test_resolveStrict_day0() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 0L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2023L); + assertThrows(DateTimeException.class, () -> DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.STRICT)); + } + + @Test + public void test_resolveStrict_day182_notLeap() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 182L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2023L); + assertThrows(DateTimeException.class, () -> DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.STRICT)); + } + + @Test + public void test_resolveStrict_day182_leap() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 182L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2024L); + TemporalAccessor resolved = DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.STRICT); + assertEquals(LocalDate.of(2024, 6, 30), resolved.query(LocalDate::from)); + } + + //------------------------------------------------------------------------- + @Test + public void test_resolveSmart_day181_notLeap() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 181L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2023L); + TemporalAccessor resolved = DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.SMART); + assertEquals(LocalDate.of(2023, 6, 30), resolved.query(LocalDate::from)); + } + + @Test + public void test_resolveSmart_day184() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 184L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2023L); + TemporalAccessor resolved = DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.SMART); + assertEquals(LocalDate.of(2023, 7, 3), resolved.query(LocalDate::from)); + } + + @Test + public void test_resolve_day185() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 185L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2023L); + assertThrows(DateTimeException.class, () -> DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.STRICT)); + } + + //------------------------------------------------------------------------- + @Test + public void test_resolveLenient_day181_notLeap() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 181L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2023L); + TemporalAccessor resolved = DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.LENIENT); + assertEquals(LocalDate.of(2023, 6, 30), resolved.query(LocalDate::from)); + } + + @Test + public void test_resolveLenient_day0() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 0L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2023L); + TemporalAccessor resolved = DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.LENIENT); + assertEquals(LocalDate.of(2022, 12, 31), resolved.query(LocalDate::from)); + } + + @Test + public void test_resolveLenient_day185() { + Map values = new HashMap<>(); + values.put(DAY_OF_HALF, 185L); + values.put(HALF_OF_YEAR, 1L); + values.put(YEAR, 2023L); + TemporalAccessor resolved = DAY_OF_HALF.resolve(values, LocalDate.of(1, 1, 1), ResolverStyle.LENIENT); + assertEquals(LocalDate.of(2023, 7, 4), resolved.query(LocalDate::from)); + } + +} diff --git a/src/test/java/org/threeten/extra/TestTemporals.java b/src/test/java/org/threeten/extra/TestTemporals.java index c3a0ec36..7fb4744a 100644 --- a/src/test/java/org/threeten/extra/TestTemporals.java +++ b/src/test/java/org/threeten/extra/TestTemporals.java @@ -52,11 +52,12 @@ import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; import static java.time.temporal.IsoFields.QUARTER_YEARS; -import static org.testng.Assert.assertThrows; -import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertFalse; -import static org.testng.AssertJUnit.assertSame; -import static org.testng.AssertJUnit.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -64,7 +65,9 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.math.BigDecimal; import java.time.DateTimeException; +import java.time.Duration; import java.time.LocalDate; import java.time.Month; import java.time.format.DateTimeFormatter; @@ -76,13 +79,13 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.util.concurrent.TimeUnit; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Test Temporals. */ -@Test public class TestTemporals { //----------------------------------------------------------------------- @@ -90,16 +93,15 @@ public class TestTemporals { //----------------------------------------------------------------------- @Test public void test_nextWorkingDay_serialization() throws IOException, ClassNotFoundException { - TemporalAdjuster nextWorkingDay = Temporals.nextWorkingDay(); - assertTrue(nextWorkingDay instanceof Serializable); - + TemporalAdjuster test = Temporals.nextWorkingDay(); + assertInstanceOf(Serializable.class, test); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(nextWorkingDay); - oos.close(); - - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); - assertSame(ois.readObject(), nextWorkingDay); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } } @Test @@ -109,13 +111,13 @@ public void test_nextWorkingDay() { LocalDate date = LocalDate.of(2007, month, i); LocalDate test = (LocalDate) Temporals.nextWorkingDay().adjustInto(date); assertTrue(test.isAfter(date)); - assertFalse(test.getDayOfWeek().equals(SATURDAY)); - assertFalse(test.getDayOfWeek().equals(SUNDAY)); + assertNotEquals(SATURDAY, test.getDayOfWeek()); + assertNotEquals(SUNDAY, test.getDayOfWeek()); switch (date.getDayOfWeek()) { case FRIDAY: case SATURDAY: - assertEquals(test.getDayOfWeek(), MONDAY); + assertEquals(MONDAY, test.getDayOfWeek()); break; default: assertEquals(date.getDayOfWeek().plus(1), test.getDayOfWeek()); @@ -125,18 +127,18 @@ public void test_nextWorkingDay() { int dayDiff = test.getDayOfYear() - date.getDayOfYear(); switch (date.getDayOfWeek()) { case FRIDAY: - assertEquals(dayDiff, 3); + assertEquals(3, dayDiff); break; case SATURDAY: - assertEquals(dayDiff, 2); + assertEquals(2, dayDiff); break; default: - assertEquals(dayDiff, 1); + assertEquals(1, dayDiff); } } else { - assertEquals(test.getYear(), 2008); - assertEquals(test.getMonth(), JANUARY); - assertEquals(test.getDayOfMonth(), 1); + assertEquals(2008, test.getYear()); + assertEquals(JANUARY, test.getMonth()); + assertEquals(1, test.getDayOfMonth()); } } } @@ -153,21 +155,86 @@ public void test_nextWorkingDay_yearChange() { assertEquals(LocalDate.of(2012, JANUARY, 2), test); } + //----------------------------------------------------------------------- + // nextWorkingDayOrSame() + //----------------------------------------------------------------------- + @Test + public void test_nextWorkingDayOrSame_serialization() throws IOException, ClassNotFoundException { + TemporalAdjuster test = Temporals.nextWorkingDayOrSame(); + assertInstanceOf(Serializable.class, test); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } + } + + @Test + public void test_nextWorkingDayOrSame() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = LocalDate.of(2007, month, i); + LocalDate test = (LocalDate) Temporals.nextWorkingDayOrSame().adjustInto(date); + assertNotEquals(SATURDAY, test.getDayOfWeek()); + assertNotEquals(SUNDAY, test.getDayOfWeek()); + + switch (date.getDayOfWeek()) { + case SATURDAY: + case SUNDAY: + assertEquals(MONDAY, test.getDayOfWeek()); + break; + default: + assertEquals(date.getDayOfWeek(), test.getDayOfWeek()); + } + + if (test.getYear() == 2007) { + int dayDiff = test.getDayOfYear() - date.getDayOfYear(); + switch (date.getDayOfWeek()) { + case SATURDAY: + assertEquals(2, dayDiff); + break; + case SUNDAY: + assertEquals(1, dayDiff); + break; + default: + assertEquals(0, dayDiff); + } + } else { + assertEquals(2008, test.getYear()); + assertEquals(JANUARY, test.getMonth()); + assertEquals(1, test.getDayOfMonth()); + } + } + } + } + + @Test + public void test_nextWorkingDayOrSame_yearChange() { + LocalDate saturday = LocalDate.of(2016, DECEMBER, 31); + Temporal test = Temporals.nextWorkingDayOrSame().adjustInto(saturday); + assertEquals(LocalDate.of(2017, JANUARY, 2), test); + + LocalDate sunday = LocalDate.of(2017, DECEMBER, 31); + test = Temporals.nextWorkingDayOrSame().adjustInto(sunday); + assertEquals(LocalDate.of(2018, JANUARY, 1), test); + } + //----------------------------------------------------------------------- // previousWorkingDay() //----------------------------------------------------------------------- @Test public void test_previousWorkingDay_serialization() throws IOException, ClassNotFoundException { - TemporalAdjuster previousWorkingDay = Temporals.previousWorkingDay(); - assertTrue(previousWorkingDay instanceof Serializable); - + TemporalAdjuster test = Temporals.previousWorkingDay(); + assertInstanceOf(Serializable.class, test); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(previousWorkingDay); - oos.close(); - - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); - assertSame(ois.readObject(), previousWorkingDay); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } } @Test @@ -177,13 +244,13 @@ public void test_previousWorkingDay() { LocalDate date = LocalDate.of(2007, month, i); LocalDate test = (LocalDate) Temporals.previousWorkingDay().adjustInto(date); assertTrue(test.isBefore(date)); - assertFalse(test.getDayOfWeek().equals(SATURDAY)); - assertFalse(test.getDayOfWeek().equals(SUNDAY)); + assertNotEquals(SATURDAY, test.getDayOfWeek()); + assertNotEquals(SUNDAY, test.getDayOfWeek()); switch (date.getDayOfWeek()) { case MONDAY: case SUNDAY: - assertEquals(test.getDayOfWeek(), FRIDAY); + assertEquals(FRIDAY, test.getDayOfWeek()); break; default: assertEquals(date.getDayOfWeek().minus(1), test.getDayOfWeek()); @@ -193,18 +260,18 @@ public void test_previousWorkingDay() { int dayDiff = test.getDayOfYear() - date.getDayOfYear(); switch (date.getDayOfWeek()) { case MONDAY: - assertEquals(dayDiff, -3); + assertEquals(-3, dayDiff); break; case SUNDAY: - assertEquals(dayDiff, -2); + assertEquals(-2, dayDiff); break; default: - assertEquals(dayDiff, -1); + assertEquals(-1, dayDiff); } } else { - assertEquals(test.getYear(), 2006); - assertEquals(test.getMonth(), DECEMBER); - assertEquals(test.getDayOfMonth(), 29); + assertEquals(2006, test.getYear()); + assertEquals(DECEMBER, test.getMonth()); + assertEquals(29, test.getDayOfMonth()); } } } @@ -221,41 +288,108 @@ public void test_previousWorkingDay_yearChange() { assertEquals(LocalDate.of(2010, DECEMBER, 31), test); } + //----------------------------------------------------------------------- + // previousWorkingDayOrSame() + //----------------------------------------------------------------------- + @Test + public void test_previousWorkingDayOrSame_serialization() throws IOException, ClassNotFoundException { + TemporalAdjuster test = Temporals.previousWorkingDayOrSame(); + assertInstanceOf(Serializable.class, test); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } + } + + @Test + public void test_previousWorkingDayOrSame() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = LocalDate.of(2007, month, i); + LocalDate test = (LocalDate) Temporals.previousWorkingDayOrSame().adjustInto(date); + assertNotEquals(SATURDAY, test.getDayOfWeek()); + assertNotEquals(SUNDAY, test.getDayOfWeek()); + + switch (date.getDayOfWeek()) { + case SATURDAY: + case SUNDAY: + assertEquals(FRIDAY, test.getDayOfWeek()); + break; + default: + assertEquals(date.getDayOfWeek(), test.getDayOfWeek()); + } + + if (test.getYear() == 2007) { + int dayDiff = test.getDayOfYear() - date.getDayOfYear(); + switch (date.getDayOfWeek()) { + case SATURDAY: + assertEquals(-1, dayDiff); + break; + case SUNDAY: + assertEquals(-2, dayDiff); + break; + default: + assertEquals(0, dayDiff); + } + } else { + assertEquals(2006, test.getYear()); + assertEquals(DECEMBER, test.getMonth()); + assertEquals(29, test.getDayOfMonth()); + } + } + } + } + + @Test + public void test_previousWorkingDayOrSame_yearChange() { + + LocalDate sunday = LocalDate.of(2011, JANUARY, 2); + Temporal test = Temporals.previousWorkingDayOrSame().adjustInto(sunday); + assertEquals(LocalDate.of(2010, DECEMBER, 31), test); + + LocalDate saturday = LocalDate.of(2011, JANUARY, 1); + test = Temporals.previousWorkingDayOrSame().adjustInto(saturday); + assertEquals(LocalDate.of(2010, DECEMBER, 31), test); + } + //----------------------------------------------------------------------- // parseFirstMatching() //----------------------------------------------------------------------- - @DataProvider(name = "parseFirstMatching") - Object[][] data_parseFirstMatching() { + public static Object[][] data_parseFirstMatching() { return new Object[][] { {"2016-09-06", DateTimeFormatter.ISO_LOCAL_DATE, DateTimeFormatter.BASIC_ISO_DATE}, {"20160906", DateTimeFormatter.ISO_LOCAL_DATE, DateTimeFormatter.BASIC_ISO_DATE}, }; } - @Test(dataProvider = "parseFirstMatching") + @ParameterizedTest + @MethodSource("data_parseFirstMatching") public void test_parseFirstMatching(String text, DateTimeFormatter fmt1, DateTimeFormatter fmt2) { - assertEquals(Temporals.parseFirstMatching(text, LocalDate::from, fmt1, fmt2), LocalDate.of(2016, 9, 6)); + assertEquals(LocalDate.of(2016, 9, 6), Temporals.parseFirstMatching(text, LocalDate::from, fmt1, fmt2)); } + @Test public void test_parseFirstMatching_zero() { assertThrows(DateTimeParseException.class, () -> Temporals.parseFirstMatching("2016-09-06", LocalDate::from)); } + @Test public void test_parseFirstMatching_one() { - assertEquals(Temporals.parseFirstMatching("2016-09-06", LocalDate::from, DateTimeFormatter.ISO_LOCAL_DATE), LocalDate.of(2016, 9, 6)); + assertEquals(LocalDate.of(2016, 9, 6), Temporals.parseFirstMatching("2016-09-06", LocalDate::from, DateTimeFormatter.ISO_LOCAL_DATE)); } + @Test public void test_parseFirstMatching_twoNoMatch() { - assertThrows( - DateTimeParseException.class, - () -> Temporals.parseFirstMatching("2016", LocalDate::from, DateTimeFormatter.ISO_LOCAL_DATE, DateTimeFormatter.BASIC_ISO_DATE)); + assertThrows(DateTimeParseException.class, () -> Temporals.parseFirstMatching("2016", LocalDate::from, DateTimeFormatter.ISO_LOCAL_DATE, DateTimeFormatter.BASIC_ISO_DATE)); } //----------------------------------------------------------------------- // chronoUnit() / timeUnit() //----------------------------------------------------------------------- - @DataProvider(name = "timeUnitConversion") - Object[][] data_timeUnitConversion() { + public static Object[][] data_timeUnitConversion() { return new Object[][] { {ChronoUnit.NANOS, TimeUnit.NANOSECONDS}, {ChronoUnit.MICROS, TimeUnit.MICROSECONDS}, @@ -267,36 +401,37 @@ Object[][] data_timeUnitConversion() { }; } - @Test(dataProvider = "timeUnitConversion") + @ParameterizedTest + @MethodSource("data_timeUnitConversion") public void test_timeUnit(ChronoUnit chronoUnit, TimeUnit timeUnit) { - assertEquals(Temporals.timeUnit(chronoUnit), timeUnit); + assertEquals(timeUnit, Temporals.timeUnit(chronoUnit)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test_timeUnit_unknown() { - Temporals.timeUnit(ChronoUnit.MONTHS); + assertThrows(IllegalArgumentException.class, () -> Temporals.timeUnit(ChronoUnit.MONTHS)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_timeUnit_null() { - Temporals.timeUnit(null); + assertThrows(NullPointerException.class, () -> Temporals.timeUnit(null)); } - @Test(dataProvider = "timeUnitConversion") + @ParameterizedTest + @MethodSource("data_timeUnitConversion") public void test_chronoUnit(ChronoUnit chronoUnit, TimeUnit timeUnit) { - assertEquals(Temporals.chronoUnit(timeUnit), chronoUnit); + assertEquals(chronoUnit, Temporals.chronoUnit(timeUnit)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_chronoUnit_null() { - Temporals.chronoUnit(null); + assertThrows(NullPointerException.class, () -> Temporals.chronoUnit(null)); } //----------------------------------------------------------------------- // convertAmount() //------------------------------------------------------------------------- - @DataProvider(name = "convertAmount") - Object[][] data_convertAmount() { + public static Object[][] data_convertAmount() { return new Object[][] { {2L, NANOS, SECONDS, 0L, 2L}, {999_999_999L, NANOS, SECONDS, 0L, 999_999_999L}, @@ -442,22 +577,24 @@ Object[][] data_convertAmount() { }; } - @Test(dataProvider = "convertAmount") + @ParameterizedTest + @MethodSource("data_convertAmount") public void test_convertAmount( long fromAmount, TemporalUnit fromUnit, TemporalUnit resultUnit, long resultWhole, long resultRemainder) { long[] result = Temporals.convertAmount(fromAmount, fromUnit, resultUnit); - assertEquals(result[0], resultWhole); - assertEquals(result[1], resultRemainder); + assertEquals(resultWhole, result[0]); + assertEquals(resultRemainder, result[1]); } - @Test(dataProvider = "convertAmount") + @ParameterizedTest + @MethodSource("data_convertAmount") public void test_convertAmount_negative( long fromAmount, TemporalUnit fromUnit, TemporalUnit resultUnit, long resultWhole, long resultRemainder) { long[] result = Temporals.convertAmount(-fromAmount, fromUnit, resultUnit); - assertEquals(result[0], -resultWhole); - assertEquals(result[1], -resultRemainder); + assertEquals(-resultWhole, result[0]); + assertEquals(-resultRemainder, result[1]); } @Test @@ -465,8 +602,8 @@ public void test_convertAmountSameUnit_zero() { for (ChronoUnit unit : ChronoUnit.values()) { if (unit != ERAS && unit != FOREVER) { long[] result = Temporals.convertAmount(0, unit, unit); - assertEquals(result[0], 0); - assertEquals(result[1], 0); + assertEquals(0, result[0]); + assertEquals(0, result[1]); } } } @@ -476,14 +613,13 @@ public void test_convertAmountSameUnit_nonZero() { for (ChronoUnit unit : ChronoUnit.values()) { if (unit != ERAS && unit != FOREVER) { long[] result = Temporals.convertAmount(2, unit, unit); - assertEquals(result[0], 2); - assertEquals(result[1], 0); + assertEquals(2, result[0]); + assertEquals(0, result[1]); } } } - @DataProvider(name = "convertAmountInvalid") - Object[][] data_convertAmountInvalid() { + public static Object[][] data_convertAmountInvalid() { return new Object[][] { {SECONDS, MONTHS}, {SECONDS, QUARTER_YEARS}, @@ -501,13 +637,13 @@ Object[][] data_convertAmountInvalid() { }; } - @Test(dataProvider = "convertAmountInvalid", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_convertAmountInvalid") public void test_convertAmountInvalid(TemporalUnit fromUnit, TemporalUnit resultUnit) { - Temporals.convertAmount(1, fromUnit, resultUnit); + assertThrows(DateTimeException.class, () -> Temporals.convertAmount(1, fromUnit, resultUnit)); } - @DataProvider(name = "convertAmountInvalidUnsupported") - Object[][] data_convertAmountInvalidUnsupported() { + public static Object[][] data_convertAmountInvalidUnsupported() { return new Object[][] { {SECONDS, ERAS}, {ERAS, SECONDS}, @@ -524,9 +660,113 @@ Object[][] data_convertAmountInvalidUnsupported() { }; } - @Test(dataProvider = "convertAmountInvalidUnsupported", expectedExceptions = UnsupportedTemporalTypeException.class) + @ParameterizedTest + @MethodSource("data_convertAmountInvalidUnsupported") public void test_convertAmountInvalidUnsupported(TemporalUnit fromUnit, TemporalUnit resultUnit) { - Temporals.convertAmount(1, fromUnit, resultUnit); + assertThrows(UnsupportedTemporalTypeException.class, () -> Temporals.convertAmount(1, fromUnit, resultUnit)); + } + + //----------------------------------------------------------------------- + // duration to/from BigDecimal/double + //------------------------------------------------------------------------- + public static Object[][] data_durationConversions() { + return new Object[][] { + {Duration.ZERO, BigDecimal.valueOf(0, 9), 0d}, + {Duration.ofSeconds(1, 0), new BigDecimal("1.000000000"), 1d}, + {Duration.ofSeconds(1, 500_000_000), new BigDecimal("1.500000000"), 1.5d}, + {Duration.ofSeconds(0, -400_000_000), new BigDecimal("-0.400000000"), -0.4d}, + }; + } + + @ParameterizedTest + @MethodSource("data_durationConversions") + public void test_durationToBigDecimalSeconds(Duration input, BigDecimal expected, double ignored) { + BigDecimal test = Temporals.durationToBigDecimalSeconds(input); + assertEquals(expected, test); + } + + @ParameterizedTest + @MethodSource("data_durationConversions") + public void test_durationFromBigDecimalSeconds(Duration expected, BigDecimal input, double ignored) { + Duration test = Temporals.durationFromBigDecimalSeconds(input); + assertEquals(expected, test); + } + + @ParameterizedTest + @MethodSource("data_durationConversions") + public void test_durationToDoubleSeconds(Duration input, BigDecimal ignored, double expected) { + double test = Temporals.durationToDoubleSeconds(input); + assertEquals(expected, test, 0d); + } + + @ParameterizedTest + @MethodSource("data_durationConversions") + public void test_durationFromDoubleSeconds(Duration expected, BigDecimal ignored, double input) { + Duration test = Temporals.durationFromDoubleSeconds(input); + assertEquals(expected, test); + } + + @Test + public void test_durationFromBigDecimalSeconds_manyDecimals() { + Duration test = Temporals.durationFromBigDecimalSeconds(BigDecimal.valueOf(122233322251L, 11)); + assertEquals(Duration.ofSeconds(1, 222333223), test); + } + + @Test + public void test_durationFromDoubleSeconds_manyDecimals() { + Duration test = Temporals.durationFromDoubleSeconds(1.22233322251d); + assertEquals(Duration.ofSeconds(1, 222333223), test); + } + + @Test + public void test_durationFromBigDecimalSeconds_tooLargePositive() { + Duration test = Temporals.durationFromBigDecimalSeconds(BigDecimal.valueOf(122233322251L, -10)); + assertEquals(Duration.ofSeconds(Long.MAX_VALUE, 999_999_999), test); + } + + @Test + public void test_durationFromBigDecimalSeconds_tooLargeNegative() { + Duration test = Temporals.durationFromBigDecimalSeconds(BigDecimal.valueOf(-122233322251L, -10)); + assertEquals(Duration.ofSeconds(Long.MIN_VALUE), test); + } + + @Test + public void test_durationFromDoubleSeconds_tooLargePositive() { + Duration test = Temporals.durationFromDoubleSeconds(122233322251e10); + assertEquals(Duration.ofSeconds(Long.MAX_VALUE, 999_999_999), test); + } + + @Test + public void test_durationFromDoubleSeconds_tooLargeNegative() { + Duration test = Temporals.durationFromDoubleSeconds(-122233322251e10); + assertEquals(Duration.ofSeconds(Long.MIN_VALUE), test); + } + + //----------------------------------------------------------------------- + // duration multiply + //------------------------------------------------------------------------- + public static Object[][] data_durationMultiply() { + return new Object[][] { + {Duration.ZERO, 0d, Duration.ZERO}, + {Duration.ZERO, 1d, Duration.ZERO}, + {Duration.ZERO, 2d, Duration.ZERO}, + {Duration.ofSeconds(1, 0), 0d, Duration.ZERO}, + {Duration.ofSeconds(1, 0), -0d, Duration.ZERO}, + {Duration.ofSeconds(1, 0), 1d, Duration.ofSeconds(1, 0)}, + {Duration.ofSeconds(1, 0), 2d, Duration.ofSeconds(2, 0)}, + {Duration.ofSeconds(1, 500_000_000), 2d, Duration.ofSeconds(3, 0)}, + {Duration.ofSeconds(1, 0), 1e-12, Duration.ofNanos(1)}, + {Duration.ofNanos(1), 1e-12, Duration.ofNanos(1)}, + {Duration.ofSeconds(Long.MAX_VALUE - 1, 0), 1.1d, Duration.ofSeconds(Long.MAX_VALUE, 999_999_999)}, + {Duration.ofSeconds(Long.MAX_VALUE - 1, 0), -1.1d, Duration.ofSeconds(Long.MIN_VALUE, 0)}, + }; + } + + @ParameterizedTest + @MethodSource("data_durationMultiply") + public void test_durationMultiply(Duration input, double multiplicand, Duration expected) { + Duration test = Temporals.multiply(input, multiplicand); + assertEquals(expected, test); } } diff --git a/src/test/java/org/threeten/extra/TestWeeks.java b/src/test/java/org/threeten/extra/TestWeeks.java index 08d703fa..668d33c4 100644 --- a/src/test/java/org/threeten/extra/TestWeeks.java +++ b/src/test/java/org/threeten/extra/TestWeeks.java @@ -31,9 +31,11 @@ */ package org.threeten.extra; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -42,105 +44,133 @@ import java.io.Serializable; import java.time.DateTimeException; import java.time.Duration; +import java.time.LocalDate; import java.time.Period; import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAmount; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test class. */ -@Test public class TestWeeks { //----------------------------------------------------------------------- + @Test public void test_isSerializable() { assertTrue(Serializable.class.isAssignableFrom(Weeks.class)); } //----------------------------------------------------------------------- + @Test public void test_deserializationSingleton() throws Exception { - Weeks orginal = Weeks.ZERO; + Weeks test = Weeks.ZERO; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Weeks ser = (Weeks) in.readObject(); - assertSame(Weeks.ZERO, ser); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } } //----------------------------------------------------------------------- + @Test public void test_ZERO() { - assertSame(Weeks.of(0), Weeks.ZERO); - assertSame(Weeks.of(0), Weeks.ZERO); - assertEquals(Weeks.ZERO.getAmount(), 0); + assertSame(Weeks.ZERO, Weeks.of(0)); + assertEquals(Weeks.ZERO, Weeks.of(0)); + assertEquals(0, Weeks.ZERO.getAmount()); + assertFalse(Weeks.ZERO.isNegative()); + assertTrue(Weeks.ZERO.isZero()); + assertFalse(Weeks.ZERO.isPositive()); } + @Test public void test_ONE() { - assertSame(Weeks.of(1), Weeks.ONE); - assertSame(Weeks.of(1), Weeks.ONE); - assertEquals(Weeks.ONE.getAmount(), 1); + assertSame(Weeks.ONE, Weeks.of(1)); + assertEquals(Weeks.ONE, Weeks.of(1)); + assertEquals(1, Weeks.ONE.getAmount()); + assertFalse(Weeks.ONE.isNegative()); + assertFalse(Weeks.ONE.isZero()); + assertTrue(Weeks.ONE.isPositive()); } //----------------------------------------------------------------------- + @Test public void test_of() { - assertEquals(Weeks.of(1).getAmount(), 1); - assertEquals(Weeks.of(2).getAmount(), 2); - assertEquals(Weeks.of(Integer.MAX_VALUE).getAmount(), Integer.MAX_VALUE); - assertEquals(Weeks.of(-1).getAmount(), -1); - assertEquals(Weeks.of(-2).getAmount(), -2); - assertEquals(Weeks.of(Integer.MIN_VALUE).getAmount(), Integer.MIN_VALUE); + assertEquals(1, Weeks.of(1).getAmount()); + assertEquals(2, Weeks.of(2).getAmount()); + assertEquals(Integer.MAX_VALUE, Weeks.of(Integer.MAX_VALUE).getAmount()); + assertEquals(-1, Weeks.of(-1).getAmount()); + assertEquals(-2, Weeks.of(-2).getAmount()); + assertEquals(Integer.MIN_VALUE, Weeks.of(Integer.MIN_VALUE).getAmount()); + } + + @Test + public void test_ofMinusOne() { + assertEquals(-1, Weeks.of(-1).getAmount()); + assertTrue(Weeks.of(-1).isNegative()); + assertFalse(Weeks.of(-1).isZero()); + assertFalse(Weeks.of(-1).isPositive()); } //----------------------------------------------------------------------- + @Test public void test_from_P0W() { - assertEquals(Weeks.from(Period.ofWeeks(0)), Weeks.of(0)); + assertEquals(Weeks.of(0), Weeks.from(Period.ofWeeks(0))); } + @Test public void test_from_P2W() { - assertEquals(Weeks.from(Period.ofWeeks(2)), Weeks.of(2)); + assertEquals(Weeks.of(2), Weeks.from(Period.ofWeeks(2))); } + @Test public void test_from_P14D() { - assertEquals(Weeks.from(Period.ofDays(14)), Weeks.of(2)); + assertEquals(Weeks.of(2), Weeks.from(Period.ofDays(14))); } + @Test public void test_from_Duration() { - assertEquals(Weeks.from(Duration.ofDays(14)), Weeks.of(2)); + assertEquals(Weeks.of(2), Weeks.from(Duration.ofDays(14))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_wrongUnit_remainder() { - Weeks.from(Period.ofDays(3)); + assertThrows(DateTimeException.class, () -> Weeks.from(Period.ofDays(3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_wrongUnit_noConversion() { - Weeks.from(Period.ofMonths(2)); + assertThrows(DateTimeException.class, () -> Weeks.from(Period.ofMonths(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_null() { - Weeks.from((TemporalAmount) null); + assertThrows(NullPointerException.class, () -> Weeks.from((TemporalAmount) null)); } //----------------------------------------------------------------------- + @Test public void test_parse_CharSequence() { - assertEquals(Weeks.parse("P0W"), Weeks.of(0)); - assertEquals(Weeks.parse("P1W"), Weeks.of(1)); - assertEquals(Weeks.parse("P2W"), Weeks.of(2)); - assertEquals(Weeks.parse("P123456789W"), Weeks.of(123456789)); - assertEquals(Weeks.parse("P-2W"), Weeks.of(-2)); - assertEquals(Weeks.parse("-P2W"), Weeks.of(-2)); - assertEquals(Weeks.parse("-P-2W"), Weeks.of(2)); + assertEquals(Weeks.of(0), Weeks.parse("P0W")); + assertEquals(Weeks.of(1), Weeks.parse("P1W")); + assertEquals(Weeks.of(2), Weeks.parse("P2W")); + assertEquals(Weeks.of(123456789), Weeks.parse("P123456789W")); + assertEquals(Weeks.of(-2), Weeks.parse("P-2W")); + assertEquals(Weeks.of(-2), Weeks.parse("-P2W")); + assertEquals(Weeks.of(2), Weeks.parse("-P-2W")); } - @DataProvider(name = "parseInvalid") - Object[][] data_invalid() { + public static Object[][] data_invalid() { return new Object[][] { {"P3Y"}, {"P3M"}, @@ -156,17 +186,46 @@ Object[][] data_invalid() { }; } - @Test(expectedExceptions = DateTimeParseException.class, dataProvider = "parseInvalid") + @ParameterizedTest + @MethodSource("data_invalid") public void test_parse_CharSequence_invalid(String str) { - Weeks.parse(str); + assertThrows(DateTimeParseException.class, () -> Weeks.parse(str)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequence_null() { - Weeks.parse((CharSequence) null); + assertThrows(NullPointerException.class, () -> Weeks.parse((CharSequence) null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_between() { + assertEquals(Weeks.of(104), Weeks.between(LocalDate.of(2019, 1, 1), LocalDate.of(2021, 1, 1))); + } + + @Test + public void test_between_date_null() { + assertThrows(NullPointerException.class, () -> Weeks.between(LocalDate.now(), (Temporal) null)); + } + + @Test + public void test_between_null_date() { + assertThrows(NullPointerException.class, () -> Weeks.between((Temporal) null, LocalDate.now())); } //----------------------------------------------------------------------- + @Test + public void test_get() { + assertEquals(6, Weeks.of(6).get(ChronoUnit.WEEKS)); + } + + @Test + public void test_get_invalidType() { + assertThrows(DateTimeException.class, () -> Weeks.of(6).get(IsoFields.QUARTER_YEARS)); + } + + //----------------------------------------------------------------------- + @Test public void test_plus_TemporalAmount_Weeks() { Weeks test5 = Weeks.of(5); assertEquals(Weeks.of(5), test5.plus(Weeks.of(0))); @@ -176,6 +235,7 @@ public void test_plus_TemporalAmount_Weeks() { assertEquals(Weeks.of(Integer.MIN_VALUE), Weeks.of(Integer.MIN_VALUE + 1).plus(Weeks.of(-1))); } + @Test public void test_plus_TemporalAmount_Period() { Weeks test5 = Weeks.of(5); assertEquals(Weeks.of(5), test5.plus(Period.ofWeeks(0))); @@ -185,32 +245,33 @@ public void test_plus_TemporalAmount_Period() { assertEquals(Weeks.of(Integer.MIN_VALUE), Weeks.of(Integer.MIN_VALUE + 1).plus(Period.ofWeeks(-1))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_TemporalAmount_PeriodMonths() { - Weeks.of(1).plus(Period.ofMonths(2)); + assertThrows(DateTimeException.class, () -> Weeks.of(1).plus(Period.ofMonths(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_TemporalAmount_Duration() { - Weeks.of(1).plus(Duration.ofHours(2)); + assertThrows(DateTimeException.class, () -> Weeks.of(1).plus(Duration.ofHours(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooBig() { - Weeks.of(Integer.MAX_VALUE - 1).plus(Weeks.of(2)); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MAX_VALUE - 1).plus(Weeks.of(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooSmall() { - Weeks.of(Integer.MIN_VALUE + 1).plus(Weeks.of(-2)); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MIN_VALUE + 1).plus(Weeks.of(-2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_plus_TemporalAmount_null() { - Weeks.of(Integer.MIN_VALUE + 1).plus(null); + assertThrows(NullPointerException.class, () -> Weeks.of(Integer.MIN_VALUE + 1).plus(null)); } //----------------------------------------------------------------------- + @Test public void test_plus_int() { Weeks test5 = Weeks.of(5); assertEquals(Weeks.of(5), test5.plus(0)); @@ -220,17 +281,18 @@ public void test_plus_int() { assertEquals(Weeks.of(Integer.MIN_VALUE), Weeks.of(Integer.MIN_VALUE + 1).plus(-1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooBig() { - Weeks.of(Integer.MAX_VALUE - 1).plus(2); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MAX_VALUE - 1).plus(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooSmall() { - Weeks.of(Integer.MIN_VALUE + 1).plus(-2); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MIN_VALUE + 1).plus(-2)); } //----------------------------------------------------------------------- + @Test public void test_minus_TemporalAmount_Weeks() { Weeks test5 = Weeks.of(5); assertEquals(Weeks.of(5), test5.minus(Weeks.of(0))); @@ -240,6 +302,7 @@ public void test_minus_TemporalAmount_Weeks() { assertEquals(Weeks.of(Integer.MIN_VALUE), Weeks.of(Integer.MIN_VALUE + 1).minus(Weeks.of(1))); } + @Test public void test_minus_TemporalAmount_Period() { Weeks test5 = Weeks.of(5); assertEquals(Weeks.of(5), test5.minus(Period.ofWeeks(0))); @@ -249,32 +312,33 @@ public void test_minus_TemporalAmount_Period() { assertEquals(Weeks.of(Integer.MIN_VALUE), Weeks.of(Integer.MIN_VALUE + 1).minus(Period.ofWeeks(1))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_TemporalAmount_PeriodMonths() { - Weeks.of(1).minus(Period.ofMonths(2)); + assertThrows(DateTimeException.class, () -> Weeks.of(1).minus(Period.ofMonths(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_TemporalAmount_Duration() { - Weeks.of(1).minus(Duration.ofHours(2)); + assertThrows(DateTimeException.class, () -> Weeks.of(1).minus(Duration.ofHours(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooBig() { - Weeks.of(Integer.MAX_VALUE - 1).minus(Weeks.of(-2)); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MAX_VALUE - 1).minus(Weeks.of(-2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooSmall() { - Weeks.of(Integer.MIN_VALUE + 1).minus(Weeks.of(2)); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MIN_VALUE + 1).minus(Weeks.of(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_minus_TemporalAmount_null() { - Weeks.of(Integer.MIN_VALUE + 1).minus(null); + assertThrows(NullPointerException.class, () -> Weeks.of(Integer.MIN_VALUE + 1).minus(null)); } //----------------------------------------------------------------------- + @Test public void test_minus_int() { Weeks test5 = Weeks.of(5); assertEquals(Weeks.of(5), test5.minus(0)); @@ -284,17 +348,18 @@ public void test_minus_int() { assertEquals(Weeks.of(Integer.MIN_VALUE), Weeks.of(Integer.MIN_VALUE + 1).minus(1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooBig() { - Weeks.of(Integer.MAX_VALUE - 1).minus(-2); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MAX_VALUE - 1).minus(-2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooSmall() { - Weeks.of(Integer.MIN_VALUE + 1).minus(2); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MIN_VALUE + 1).minus(2)); } //----------------------------------------------------------------------- + @Test public void test_multipliedBy() { Weeks test5 = Weeks.of(5); assertEquals(Weeks.of(0), test5.multipliedBy(0)); @@ -304,22 +369,24 @@ public void test_multipliedBy() { assertEquals(Weeks.of(-15), test5.multipliedBy(-3)); } + @Test public void test_multipliedBy_negate() { Weeks test5 = Weeks.of(5); assertEquals(Weeks.of(-15), test5.multipliedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooBig() { - Weeks.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooSmall() { - Weeks.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2)); } //----------------------------------------------------------------------- + @Test public void test_dividedBy() { Weeks test12 = Weeks.of(12); assertEquals(Weeks.of(12), test12.dividedBy(1)); @@ -331,17 +398,19 @@ public void test_dividedBy() { assertEquals(Weeks.of(-4), test12.dividedBy(-3)); } + @Test public void test_dividedBy_negate() { Weeks test12 = Weeks.of(12); assertEquals(Weeks.of(-4), test12.dividedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_dividedBy_divideByZero() { - Weeks.of(1).dividedBy(0); + assertThrows(ArithmeticException.class, () -> Weeks.of(1).dividedBy(0)); } //----------------------------------------------------------------------- + @Test public void test_negated() { assertEquals(Weeks.of(0), Weeks.of(0).negated()); assertEquals(Weeks.of(-12), Weeks.of(12).negated()); @@ -349,12 +418,13 @@ public void test_negated() { assertEquals(Weeks.of(-Integer.MAX_VALUE), Weeks.of(Integer.MAX_VALUE).negated()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_negated_overflow() { - Weeks.of(Integer.MIN_VALUE).negated(); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MIN_VALUE).negated()); } //----------------------------------------------------------------------- + @Test public void test_abs() { assertEquals(Weeks.of(0), Weeks.of(0).abs()); assertEquals(Weeks.of(12), Weeks.of(12).abs()); @@ -363,19 +433,34 @@ public void test_abs() { assertEquals(Weeks.of(Integer.MAX_VALUE), Weeks.of(-Integer.MAX_VALUE).abs()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_abs_overflow() { - Weeks.of(Integer.MIN_VALUE).abs(); + assertThrows(ArithmeticException.class, () -> Weeks.of(Integer.MIN_VALUE).abs()); } //----------------------------------------------------------------------- + @Test + public void test_addTo() { + assertEquals(LocalDate.of(2019, 1, 10), Weeks.of(0).addTo(LocalDate.of(2019, 1, 10))); + assertEquals(LocalDate.of(2019, 2, 14), Weeks.of(5).addTo(LocalDate.of(2019, 1, 10))); + } + + @Test + public void test_subtractFrom() { + assertEquals(LocalDate.of(2019, 1, 10), Weeks.of(0).subtractFrom(LocalDate.of(2019, 1, 10))); + assertEquals(LocalDate.of(2018, 12, 6), Weeks.of(5).subtractFrom(LocalDate.of(2019, 1, 10))); + } + + //----------------------------------------------------------------------- + @Test public void test_toPeriod() { for (int i = -20; i < 20; i++) { - assertEquals(Weeks.of(i).toPeriod(), Period.ofWeeks(i)); + assertEquals(Period.ofWeeks(i), Weeks.of(i).toPeriod()); } } //----------------------------------------------------------------------- + @Test public void test_compareTo() { Weeks test5 = Weeks.of(5); Weeks test6 = Weeks.of(6); @@ -384,40 +469,23 @@ public void test_compareTo() { assertEquals(1, test6.compareTo(test5)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_null() { Weeks test5 = Weeks.of(5); - test5.compareTo(null); + assertThrows(NullPointerException.class, () -> test5.compareTo(null)); } //----------------------------------------------------------------------- - public void test_equals() { - Weeks test5 = Weeks.of(5); - Weeks test6 = Weeks.of(6); - assertEquals(true, test5.equals(test5)); - assertEquals(false, test5.equals(test6)); - assertEquals(false, test6.equals(test5)); - } - - public void test_equals_null() { - Weeks test5 = Weeks.of(5); - assertEquals(false, test5.equals(null)); - } - - public void test_equals_otherClass() { - Weeks test5 = Weeks.of(5); - assertEquals(false, test5.equals("")); - } - - //----------------------------------------------------------------------- - public void test_hashCode() { - Weeks test5 = Weeks.of(5); - Weeks test6 = Weeks.of(6); - assertEquals(true, test5.hashCode() == test5.hashCode()); - assertEquals(false, test5.hashCode() == test6.hashCode()); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Weeks.of(5), Weeks.of(5)) + .addEqualityGroup(Weeks.of(6), Weeks.of(6)) + .testEquals(); } //----------------------------------------------------------------------- + @Test public void test_toString() { Weeks test5 = Weeks.of(5); assertEquals("P5W", test5.toString()); diff --git a/src/test/java/org/threeten/extra/TestYearHalf.java b/src/test/java/org/threeten/extra/TestYearHalf.java new file mode 100644 index 00000000..dc99eb89 --- /dev/null +++ b/src/test/java/org/threeten/extra/TestYearHalf.java @@ -0,0 +1,985 @@ +/* + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.threeten.extra; + +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; +import static java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MICROS; +import static java.time.temporal.ChronoUnit.MILLENNIA; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; +import static java.time.temporal.IsoFields.DAY_OF_QUARTER; +import static java.time.temporal.IsoFields.QUARTER_OF_YEAR; +import static java.time.temporal.IsoFields.QUARTER_YEARS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.threeten.extra.Half.H1; +import static org.threeten.extra.Half.H2; +import static org.threeten.extra.TemporalFields.DAY_OF_HALF; +import static org.threeten.extra.TemporalFields.HALF_OF_YEAR; +import static org.threeten.extra.TemporalFields.HALF_YEARS; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Year; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import com.google.common.testing.EqualsTester; + +/** + * Test YearHalf. + */ +public class TestYearHalf { + + private static final YearHalf TEST = YearHalf.of(2012, H2); + private static final int STANDARD_YEAR_LENGTH = 365; + private static final int LEAP_YEAR_LENGTH = 366; + + //----------------------------------------------------------------------- + @Test + public void test_interfaces() { + assertTrue(Serializable.class.isAssignableFrom(YearHalf.class)); + assertTrue(Comparable.class.isAssignableFrom(YearHalf.class)); + assertTrue(TemporalAdjuster.class.isAssignableFrom(YearHalf.class)); + assertTrue(TemporalAccessor.class.isAssignableFrom(YearHalf.class)); + } + + @Test + public void test_serialization() throws IOException, ClassNotFoundException { + YearHalf test = YearHalf.of(2012, 1); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertEquals(test, ois.readObject()); + } + } + + //----------------------------------------------------------------------- + // of(Year,Half) + //----------------------------------------------------------------------- + @Test + public void test_of_Year_Half() { + for (int year = -100; year <= 100; year++) { + for (Half half : Half.values()) { + YearHalf test = YearHalf.of(Year.of(year), half); + assertEquals(year, test.getYear()); + assertEquals(half.getValue(), test.getHalfValue()); + assertEquals(half, test.getHalf()); + } + } + } + + @Test + public void test_of_Year_Half_nullHalf() { + assertThrows(NullPointerException.class, () -> YearHalf.of(Year.of(2012), (Half) null)); + } + + @Test + public void test_of_Year_Half_nullYear() { + assertThrows(NullPointerException.class, () -> YearHalf.of((Year) null, Half.H2)); + } + + @Test + public void test_of_Year_Half_nullBoth() { + assertThrows(NullPointerException.class, () -> YearHalf.of((Year) null, (Half) null)); + } + + //----------------------------------------------------------------------- + // of(Year,int) + //----------------------------------------------------------------------- + @Test + public void test_of_Year_int() { + for (int year = -100; year <= 100; year++) { + for (Half half : Half.values()) { + YearHalf test = YearHalf.of(Year.of(year), half.getValue()); + assertEquals(year, test.getYear()); + assertEquals(half.getValue(), test.getHalfValue()); + assertEquals(half, test.getHalf()); + } + } + } + + @Test + public void test_of_Year_int_null() { + assertThrows(NullPointerException.class, () -> YearHalf.of((Year) null, 2)); + } + + //----------------------------------------------------------------------- + // of(int,Half) + //----------------------------------------------------------------------- + @Test + public void test_of_int_Half() { + for (int year = -100; year <= 100; year++) { + for (Half half : Half.values()) { + YearHalf test = YearHalf.of(year, half); + assertEquals(year, test.getYear()); + assertEquals(half.getValue(), test.getHalfValue()); + assertEquals(half, test.getHalf()); + } + } + } + + @Test + public void test_of_int_Half_yearTooLow() { + assertThrows(DateTimeException.class, () -> YearHalf.of(Year.MIN_VALUE - 1, Half.H2)); + } + + @Test + public void test_of_int_Half_yearTooHigh() { + assertThrows(DateTimeException.class, () -> YearHalf.of(Year.MAX_VALUE + 1, Half.H2)); + } + + @Test + public void test_of_int_Half_null() { + assertThrows(NullPointerException.class, () -> YearHalf.of(2012, (Half) null)); + } + + //----------------------------------------------------------------------- + // of(int,int) + //----------------------------------------------------------------------- + @Test + public void test_of_int_int() { + for (int year = -100; year <= 100; year++) { + for (int half = 1; half <= 2; half++) { + YearHalf test = YearHalf.of(year, half); + assertEquals(year, test.getYear()); + assertEquals(half, test.getHalfValue()); + assertEquals(Half.of(half), test.getHalf()); + assertEquals(test, YearHalf.of(year, half)); + assertEquals(test.hashCode(), YearHalf.of(year, half).hashCode()); + } + } + } + + @Test + public void test_of_int_int_yearTooLow() { + assertThrows(DateTimeException.class, () -> YearHalf.of(Year.MIN_VALUE - 1, 1)); + } + + @Test + public void test_of_int_int_yearTooHigh() { + assertThrows(DateTimeException.class, () -> YearHalf.of(Year.MAX_VALUE + 1, 1)); + } + + @Test + public void test_of_int_int_halfTooLow() { + assertThrows(DateTimeException.class, () -> YearHalf.of(2012, 0)); + } + + @Test + public void test_of_int_int_halfTooHigh() { + assertThrows(DateTimeException.class, () -> YearHalf.of(2012, 3)); + } + + //----------------------------------------------------------------------- + // from(TemporalAccessor) + //----------------------------------------------------------------------- + @Test + public void test_from_TemporalAccessor_notLeapYear() { + LocalDate date = LocalDate.of(2007, 1, 1); + for (int i = 1; i <= STANDARD_YEAR_LENGTH; i++) { + YearHalf test = YearHalf.from(date); + int expected = ((date.getMonthValue() - 1) / 6) + 1; + assertEquals(YearHalf.of(2007, expected), test); + date = date.plusDays(1); + } + } + + @Test + public void test_from_TemporalAccessor_leapYear() { + LocalDate date = LocalDate.of(2008, 1, 1); + for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { + YearHalf test = YearHalf.from(date); + int expected = ((date.getMonthValue() - 1) / 6) + 1; + assertEquals(YearHalf.of(2008, expected), test); + date = date.plusDays(1); + } + } + + @Test + public void test_from_TemporalAccessor_noDerive() { + assertThrows(DateTimeException.class, () -> YearHalf.from(LocalTime.NOON)); + } + + @Test + public void test_from_TemporalAccessor_null() { + assertThrows(NullPointerException.class, () -> YearHalf.from((TemporalAccessor) null)); + } + + //----------------------------------------------------------------------- + // parse(CharSequence) + //----------------------------------------------------------------------- + @Test + public void test_parse_CharSequence() { + assertEquals(YearHalf.of(2012, H2), YearHalf.parse("2012-H2")); + } + + @Test + public void test_parse_CharSequence_caseInsensitive() { + assertEquals(YearHalf.of(2012, H1), YearHalf.parse("2012-h1")); + } + + @Test + public void test_parse_CharSequenceDate_invalidYear() { + assertThrows(DateTimeParseException.class, () -> YearHalf.parse("12345-H1")); + } + + @Test + public void test_parse_CharSequenceDate_invalidHalf() { + assertThrows(DateTimeParseException.class, () -> YearHalf.parse("2012-H0")); + } + + @Test + public void test_parse_CharSequenceDate_nullCharSequence() { + assertThrows(NullPointerException.class, () -> YearHalf.parse((CharSequence) null)); + } + + //----------------------------------------------------------------------- + // parse(CharSequence,DateTimeFormatter) + //----------------------------------------------------------------------- + @Test + public void test_parse_CharSequenceDateTimeFormatter() { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendLiteral('H') + .appendValue(HALF_OF_YEAR, 1) + .appendLiteral(' ') + .appendValue(YEAR) + .toFormatter(); + assertEquals(YearHalf.of(2012, H1), YearHalf.parse("H1 2012", f)); + } + + @Test + public void test_parse_CharSequenceDateDateTimeFormatter_invalidHalf() { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendLiteral('H') + .appendValue(HALF_OF_YEAR, 1) + .appendLiteral(' ') + .appendValue(YEAR) + .toFormatter(); + assertThrows(DateTimeParseException.class, () -> YearHalf.parse("H0 2012", f)); + } + + @Test + public void test_parse_CharSequenceDateTimeFormatter_nullCharSequence() { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendLiteral('H') + .appendValue(HALF_OF_YEAR, 1) + .appendLiteral(' ') + .appendValue(YEAR) + .toFormatter(); + assertThrows(NullPointerException.class, () -> YearHalf.parse((CharSequence) null, f)); + } + + @Test + public void test_parse_CharSequenceDateTimeFormatter_nullDateTimeFormatter() { + assertThrows(NullPointerException.class, () -> YearHalf.parse("", (DateTimeFormatter) null)); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(false, TEST.isSupported((TemporalField) null)); + assertEquals(false, TEST.isSupported(NANO_OF_SECOND)); + assertEquals(false, TEST.isSupported(NANO_OF_DAY)); + assertEquals(false, TEST.isSupported(MICRO_OF_SECOND)); + assertEquals(false, TEST.isSupported(MICRO_OF_DAY)); + assertEquals(false, TEST.isSupported(MILLI_OF_SECOND)); + assertEquals(false, TEST.isSupported(MILLI_OF_DAY)); + assertEquals(false, TEST.isSupported(SECOND_OF_MINUTE)); + assertEquals(false, TEST.isSupported(SECOND_OF_DAY)); + assertEquals(false, TEST.isSupported(MINUTE_OF_HOUR)); + assertEquals(false, TEST.isSupported(MINUTE_OF_DAY)); + assertEquals(false, TEST.isSupported(HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(AMPM_OF_DAY)); + assertEquals(false, TEST.isSupported(DAY_OF_WEEK)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(false, TEST.isSupported(DAY_OF_MONTH)); + assertEquals(false, TEST.isSupported(DAY_OF_YEAR)); + assertEquals(false, TEST.isSupported(EPOCH_DAY)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_YEAR)); + assertEquals(false, TEST.isSupported(MONTH_OF_YEAR)); + assertEquals(false, TEST.isSupported(PROLEPTIC_MONTH)); + assertEquals(true, TEST.isSupported(YEAR_OF_ERA)); + assertEquals(true, TEST.isSupported(YEAR)); + assertEquals(true, TEST.isSupported(ERA)); + assertEquals(false, TEST.isSupported(INSTANT_SECONDS)); + assertEquals(false, TEST.isSupported(OFFSET_SECONDS)); + assertEquals(false, TEST.isSupported(QUARTER_OF_YEAR)); + assertEquals(false, TEST.isSupported(DAY_OF_QUARTER)); + assertEquals(true, TEST.isSupported(HALF_OF_YEAR)); + assertEquals(false, TEST.isSupported(DAY_OF_HALF)); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(false, TEST.isSupported((TemporalUnit) null)); + assertEquals(false, TEST.isSupported(NANOS)); + assertEquals(false, TEST.isSupported(MICROS)); + assertEquals(false, TEST.isSupported(MILLIS)); + assertEquals(false, TEST.isSupported(SECONDS)); + assertEquals(false, TEST.isSupported(MINUTES)); + assertEquals(false, TEST.isSupported(HOURS)); + assertEquals(false, TEST.isSupported(DAYS)); + assertEquals(false, TEST.isSupported(WEEKS)); + assertEquals(false, TEST.isSupported(MONTHS)); + assertEquals(true, TEST.isSupported(YEARS)); + assertEquals(true, TEST.isSupported(DECADES)); + assertEquals(true, TEST.isSupported(CENTURIES)); + assertEquals(true, TEST.isSupported(MILLENNIA)); + assertEquals(true, TEST.isSupported(ERA)); + assertEquals(false, TEST.isSupported(FOREVER)); + assertEquals(false, TEST.isSupported(QUARTER_YEARS)); + assertEquals(true, TEST.isSupported(HALF_YEARS)); + } + + //----------------------------------------------------------------------- + // range(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_range() { + assertEquals(HALF_OF_YEAR.range(), TEST.range(HALF_OF_YEAR)); + assertEquals(YEAR.range(), TEST.range(YEAR)); + assertEquals(ValueRange.of(1, Year.MAX_VALUE), TEST.range(YEAR_OF_ERA)); + assertEquals(ERA.range(), TEST.range(ERA)); + } + + @Test + public void test_range_invalidField() { + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.range(MONTH_OF_YEAR)); + } + + @Test + public void test_range_null() { + assertThrows(NullPointerException.class, () -> TEST.range((TemporalField) null)); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get() { + assertEquals(2, TEST.get(HALF_OF_YEAR)); + assertEquals(2012, TEST.get(YEAR)); + assertEquals(2012, TEST.get(YEAR_OF_ERA)); + assertEquals(1, TEST.get(ERA)); + } + + @Test + public void test_get_invalidField() { + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.get(MONTH_OF_YEAR)); + } + + @Test + public void test_get_null() { + assertThrows(NullPointerException.class, () -> TEST.get((TemporalField) null)); + } + + //----------------------------------------------------------------------- + // getLong(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_getLong() { + assertEquals(2L, TEST.getLong(HALF_OF_YEAR)); + assertEquals(2012L, TEST.getLong(YEAR)); + assertEquals(2012L, TEST.getLong(YEAR_OF_ERA)); + assertEquals(1L, TEST.getLong(ERA)); + } + + @Test + public void test_getLong_invalidField() { + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.getLong(MONTH_OF_YEAR)); + } + + @Test + public void test_getLong_null() { + assertThrows(NullPointerException.class, () -> TEST.getLong((TemporalField) null)); + } + + //----------------------------------------------------------------------- + // isLeapYear(int) + //----------------------------------------------------------------------- + @Test + public void test_isLeapYear_int() { + for (int year = -500; year <= 500; year++) { + for (Half half : Half.values()) { + YearHalf test = YearHalf.of(year, half); + assertEquals(Year.isLeap(year), test.isLeapYear()); + } + } + } + + //----------------------------------------------------------------------- + // isValidDay(int) + //----------------------------------------------------------------------- + @Test + public void test_isValidDay_int_nonLeap() { + assertEquals(true, YearHalf.of(2011, H1).isValidDay(181)); + assertEquals(false, YearHalf.of(2011, H1).isValidDay(182)); + assertEquals(false, YearHalf.of(2011, H1).isValidDay(183)); + + assertEquals(true, YearHalf.of(2011, H2).isValidDay(183)); + assertEquals(true, YearHalf.of(2011, H2).isValidDay(184)); + assertEquals(false, YearHalf.of(2011, H2).isValidDay(185)); + } + + @Test + public void test_isValidDay_int_leap() { + assertEquals(true, YearHalf.of(2012, H1).isValidDay(181)); + assertEquals(true, YearHalf.of(2012, H1).isValidDay(182)); + assertEquals(false, YearHalf.of(2012, H1).isValidDay(183)); + + assertEquals(true, YearHalf.of(2012, H2).isValidDay(183)); + assertEquals(true, YearHalf.of(2012, H2).isValidDay(184)); + assertEquals(false, YearHalf.of(2012, H2).isValidDay(185)); + } + + @Test + public void test_isValidDay_int_outOfRange() { + assertEquals(false, YearHalf.of(2011, H1).isValidDay(185)); + assertEquals(false, YearHalf.of(2011, H2).isValidDay(185)); + + assertEquals(false, YearHalf.of(2011, H1).isValidDay(0)); + assertEquals(false, YearHalf.of(2011, H2).isValidDay(0)); + } + + //----------------------------------------------------------------------- + // lengthOfHalf() + //----------------------------------------------------------------------- + @Test + public void test_lengthOfHalf() { + for (int year = -500; year <= 500; year++) { + assertEquals(Year.isLeap(year) ? 182 : 181, YearHalf.of(year, H1).lengthOfHalf()); + assertEquals(184, YearHalf.of(year, H2).lengthOfHalf()); + } + } + + //----------------------------------------------------------------------- + // with(TemporalAdjuster) + //----------------------------------------------------------------------- + @Test + public void test_with_TemporalAdjuster_Half() { + assertEquals(YearHalf.of(2007, H1), YearHalf.of(2007, H2).with(H1)); + } + + @Test + public void test_with_TemporalAdjuster_Year() { + assertEquals(YearHalf.of(2012, H2), YearHalf.of(2007, H2).with(Year.of(2012))); + } + + @Test + public void test_with_TemporalAdjuster_YearHalf() { + assertEquals(YearHalf.of(2012, H1), YearHalf.of(2007, H2).with(YearHalf.of(2012, H1))); + } + + @Test + public void test_with_TemporalAdjuster_LocalDate() { + assertThrows(DateTimeException.class, () -> YearHalf.of(2007, H2).with(LocalDate.of(2012, 6, 30))); + } + + @Test + public void test_with_TemporalAdjuster_null() { + assertThrows(NullPointerException.class, () -> YearHalf.of(2007, H2).with((TemporalAdjuster) null)); + } + + //----------------------------------------------------------------------- + // withYear(int) + //----------------------------------------------------------------------- + @Test + public void test_withYear() { + assertEquals(YearHalf.of(2012, H2), YearHalf.of(2007, H2).withYear(2012)); + } + + @Test + public void test_withYear_int_halfTooLow() { + assertThrows(DateTimeException.class, () -> TEST.withYear(Year.MIN_VALUE - 1)); + } + + @Test + public void test_withYear_int_halfTooHigh() { + assertThrows(DateTimeException.class, () -> TEST.withYear(Year.MAX_VALUE + 1)); + } + + //----------------------------------------------------------------------- + // withHalf(int) + //----------------------------------------------------------------------- + @Test + public void test_withHalf_int() { + assertEquals(YearHalf.of(2007, H1), YearHalf.of(2007, H2).withHalf(1)); + } + + @Test + public void test_withHalf_int_halfTooLow() { + assertThrows(DateTimeException.class, () -> TEST.withHalf(0)); + } + + @Test + public void test_withHalf_int_halfTooHigh() { + assertThrows(DateTimeException.class, () -> TEST.withHalf(3)); + } + + //----------------------------------------------------------------------- + // plus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_plus_longTemporalUnit() { + assertEquals(YearHalf.of(2012, H2), YearHalf.of(2007, H2).plus(5, YEARS)); + assertEquals(YearHalf.of(2007, H2), YearHalf.of(2007, H2).plus(0, YEARS)); + assertEquals(YearHalf.of(2002, H2), YearHalf.of(2007, H2).plus(-5, YEARS)); + assertEquals(YearHalf.of(2010, H1), YearHalf.of(2007, H2).plus(5, HALF_YEARS)); + assertEquals(YearHalf.of(2007, H2), YearHalf.of(2007, H2).plus(0, HALF_YEARS)); + assertEquals(YearHalf.of(2005, H1), YearHalf.of(2007, H2).plus(-5, HALF_YEARS)); + } + + //----------------------------------------------------------------------- + // plusYears(int) + //----------------------------------------------------------------------- + @Test + public void test_plusYears() { + assertEquals(YearHalf.of(2012, H2), YearHalf.of(2007, H2).plusYears(5)); + assertEquals(YearHalf.of(2007, H2), YearHalf.of(2007, H2).plusYears(0)); + assertEquals(YearHalf.of(2002, H2), YearHalf.of(2007, H2).plusYears(-5)); + } + + //----------------------------------------------------------------------- + // plusHalves(int) + //----------------------------------------------------------------------- + @Test + public void test_plusHalves() { + assertEquals(YearHalf.of(2010, H1), YearHalf.of(2007, H2).plusHalves(5)); + assertEquals(YearHalf.of(2007, H2), YearHalf.of(2007, H2).plusHalves(0)); + assertEquals(YearHalf.of(2005, H1), YearHalf.of(2007, H2).plusHalves(-5)); + } + + //----------------------------------------------------------------------- + // minus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_minus_longTemporalUnit() { + assertEquals(YearHalf.of(2002, H2), YearHalf.of(2007, H2).minus(5, YEARS)); + assertEquals(YearHalf.of(2007, H2), YearHalf.of(2007, H2).minus(0, YEARS)); + assertEquals(YearHalf.of(2012, H2), YearHalf.of(2007, H2).minus(-5, YEARS)); + assertEquals(YearHalf.of(2005, H1), YearHalf.of(2007, H2).minus(5, HALF_YEARS)); + assertEquals(YearHalf.of(2007, H2), YearHalf.of(2007, H2).minus(0, HALF_YEARS)); + assertEquals(YearHalf.of(2010, H1), YearHalf.of(2007, H2).minus(-5, HALF_YEARS)); + } + + //----------------------------------------------------------------------- + // minusYears(int) + //----------------------------------------------------------------------- + @Test + public void test_minusYears() { + assertEquals(YearHalf.of(2002, H2), YearHalf.of(2007, H2).minusYears(5)); + assertEquals(YearHalf.of(2007, H2), YearHalf.of(2007, H2).minusYears(0)); + assertEquals(YearHalf.of(2012, H2), YearHalf.of(2007, H2).minusYears(-5)); + } + + //----------------------------------------------------------------------- + // minusHalves(int) + //----------------------------------------------------------------------- + @Test + public void test_minusHalves() { + assertEquals(YearHalf.of(2005, H1), YearHalf.of(2007, H2).minusHalves(5)); + assertEquals(YearHalf.of(2007, H2), YearHalf.of(2007, H2).minusHalves(0)); + assertEquals(YearHalf.of(2010, H1), YearHalf.of(2007, H2).minusHalves(-5)); + } + + //----------------------------------------------------------------------- + // lengthOfYear() + //----------------------------------------------------------------------- + @Test + public void test_lengthOfYear() { + for (int year = -500; year <= 500; year++) { + for (Half half : Half.values()) { + YearHalf test = YearHalf.of(year, half); + assertEquals(Year.isLeap(year) ? 366 : 365, test.lengthOfYear()); + } + } + } + + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @Test + public void test_query() { + assertEquals(IsoChronology.INSTANCE, TEST.query(TemporalQueries.chronology())); + assertEquals(null, TEST.query(TemporalQueries.localDate())); + assertEquals(null, TEST.query(TemporalQueries.localTime())); + assertEquals(null, TEST.query(TemporalQueries.offset())); + assertEquals(HALF_YEARS, TEST.query(TemporalQueries.precision())); + assertEquals(null, TEST.query(TemporalQueries.zone())); + assertEquals(null, TEST.query(TemporalQueries.zoneId())); + } + + //----------------------------------------------------------------------- + // adjustInto(Temporal) + //----------------------------------------------------------------------- + @Test + public void test_adjustInto_Temporal() { + for (int month = 1; month < 12; month++) { + for (int dom = 1; dom < 28; dom++) { + LocalDate base = LocalDate.of(2007, month, dom); + LocalDate expected = LocalDate.of(2012, 7 + ((month - 1) % 6), dom); + assertEquals(expected, YearHalf.of(2012, H2).adjustInto(base)); + } + } + } + + @Test + public void test_adjustInto_Temporal_lastValidDay_nonLeap() { + LocalDate base = LocalDate.of(2007, 8, 31); + LocalDate expected = LocalDate.of(2011, 2, 28); + assertEquals(expected, YearHalf.of(2011, H1).adjustInto(base)); + } + + @Test + public void test_adjustInto_Temporal_lastValidDay_leap() { + LocalDate base = LocalDate.of(2007, 8, 31); + LocalDate expected = LocalDate.of(2012, 2, 29); + assertEquals(expected, YearHalf.of(2012, H1).adjustInto(base)); + } + + @Test + public void test_adjustInto_Temporal_null() { + assertThrows(NullPointerException.class, () -> TEST.adjustInto((Temporal) null)); + } + + //----------------------------------------------------------------------- + // until(Temporal,TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_until_TemporalTemporalUnit_HALF_YEARS() { + assertEquals(-2, YearHalf.of(2012, H2).until(YearHalf.of(2011, H2), HALF_YEARS)); + assertEquals(-1, YearHalf.of(2012, H2).until(YearHalf.of(2012, H1), HALF_YEARS)); + assertEquals(0, YearHalf.of(2012, H2).until(YearHalf.of(2012, H2), HALF_YEARS)); + assertEquals(1, YearHalf.of(2012, H2).until(YearHalf.of(2013, H1), HALF_YEARS)); + assertEquals(2, YearHalf.of(2012, H2).until(YearHalf.of(2013, H2), HALF_YEARS)); + assertEquals(3, YearHalf.of(2012, H2).until(YearHalf.of(2014, H1), HALF_YEARS)); + } + + @Test + public void test_until_TemporalTemporalUnit_YEARS() { + assertEquals(-2, YearHalf.of(2012, H2).until(YearHalf.of(2010, H2), YEARS)); + assertEquals(-1, YearHalf.of(2012, H2).until(YearHalf.of(2011, H1), YEARS)); + assertEquals(-1, YearHalf.of(2012, H2).until(YearHalf.of(2011, H2), YEARS)); + assertEquals(0, YearHalf.of(2012, H2).until(YearHalf.of(2012, H1), YEARS)); + assertEquals(0, YearHalf.of(2012, H2).until(YearHalf.of(2012, H2), YEARS)); + assertEquals(0, YearHalf.of(2012, H2).until(YearHalf.of(2013, H1), YEARS)); + assertEquals(1, YearHalf.of(2012, H2).until(YearHalf.of(2013, H2), YEARS)); + assertEquals(1, YearHalf.of(2012, H2).until(YearHalf.of(2014, H1), YEARS)); + assertEquals(2, YearHalf.of(2012, H2).until(YearHalf.of(2014, H2), YEARS)); + } + + @Test + public void test_until_TemporalTemporalUnit_nullTemporal() { + assertThrows(NullPointerException.class, () -> YearHalf.of(2012, H2).until(null, HALF_YEARS)); + } + + @Test + public void test_until_TemporalTemporalUnit_nullTemporalUnit() { + assertThrows(NullPointerException.class, () -> YearHalf.of(2012, H2).until(YearHalf.of(2012, H1), null)); + } + + //----------------------------------------------------------------------- + // halvesUntil(YearHalf) + //----------------------------------------------------------------------- + @Test + public void test_halvesUntil_null() { + assertThrows(NullPointerException.class, () -> YearHalf.of(2012, H2).halvesUntil(null)); + } + + @Test + public void test_halvesUntil_IllegalArgument() { + assertThrows(IllegalArgumentException.class, () -> YearHalf.of(2012, H2).halvesUntil(YearHalf.of(2012, H1))); + } + + @Test + public void test_halvesUntil() { + assertEquals(1, YearHalf.of(2012, H1).halvesUntil(YearHalf.of(2012, H2)).count()); + assertEquals(4, YearHalf.of(2012, H2).halvesUntil(YearHalf.of(2014, H2)).count()); + + YearHalf start = YearHalf.of(2012, H1); + YearHalf end = YearHalf.of(2013, H2); + Stream stream = start.halvesUntil(end); + + List expects = Arrays.asList( + YearHalf.of(start.getYear(), H1), + YearHalf.of(start.getYear(), H2), + YearHalf.of(end.getYear(), H1)); + assertEquals(expects, stream.collect(Collectors.toList())); + } + + //----------------------------------------------------------------------- + // format(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test + public void test_format() { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendLiteral('H') + .appendValue(HALF_OF_YEAR, 1) + .appendLiteral(' ') + .appendValue(YEAR) + .toFormatter(); + assertEquals("H1 2012", YearHalf.of(2012, H1).format(f)); + } + + @Test + public void test_format_null() { + assertThrows(NullPointerException.class, () -> TEST.format((DateTimeFormatter) null)); + } + + //----------------------------------------------------------------------- + // atDay(int) + //----------------------------------------------------------------------- + @Test + public void test_atDay() { + for (int i = 1; i <= 182; i++) { + LocalDate expected = LocalDate.of(2012, 1, 1).plusDays(i - 1); + assertEquals(expected, YearHalf.of(2012, H1).atDay(i)); + } + for (int i = 1; i <= 184; i++) { + LocalDate expected = LocalDate.of(2012, 7, 1).plusDays(i - 1); + assertEquals(expected, YearHalf.of(2012, H2).atDay(i)); + } + } + + @Test + public void test_atDay_H1_181_leap() { + assertEquals(LocalDate.of(2012, 6, 30), YearHalf.of(2012, H1).atDay(182)); + } + + @Test + public void test_atDay_H1_182_notLeap() { + assertThrows(DateTimeException.class, () -> YearHalf.of(2011, H1).atDay(182)); + } + + @Test + public void test_atDay_H1_183() { + assertThrows(DateTimeException.class, () -> YearHalf.of(2012, H1).atDay(183)); + } + + @Test + public void test_atDay_tooLow() { + assertThrows(DateTimeException.class, () -> TEST.atDay(0)); + } + + @Test + public void test_atDay_tooHigh() { + assertThrows(DateTimeException.class, () -> TEST.atDay(185)); + } + + //----------------------------------------------------------------------- + // atEndOfHalf(int) + //----------------------------------------------------------------------- + @Test + public void test_atEndOfHalf() { + assertEquals(LocalDate.of(2011, 6, 30), YearHalf.of(2011, H1).atEndOfHalf()); + assertEquals(LocalDate.of(2011, 12, 31), YearHalf.of(2011, H2).atEndOfHalf()); + + assertEquals(LocalDate.of(2012, 6, 30), YearHalf.of(2012, H1).atEndOfHalf()); + assertEquals(LocalDate.of(2012, 12, 31), YearHalf.of(2012, H2).atEndOfHalf()); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test + public void test_compareTo() { + for (int year1 = -100; year1 < 100; year1++) { + for (Half half1 : Half.values()) { + YearHalf a = YearHalf.of(year1, half1); + for (int year2 = -100; year2 < 100; year2++) { + for (Half half2 : Half.values()) { + YearHalf b = YearHalf.of(year2, half2); + if (year1 < year2) { + assertEquals(true, a.compareTo(b) < 0); + assertEquals(true, b.compareTo(a) > 0); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(true, b.isAfter(a)); + assertEquals(true, a.isBefore(b)); + } else if (year1 > year2) { + assertEquals(true, a.compareTo(b) > 0); + assertEquals(true, b.compareTo(a) < 0); + assertEquals(true, a.isAfter(b)); + assertEquals(true, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); + } else { + if (half1.getValue() < half2.getValue()) { + assertEquals(true, a.compareTo(b) < 0); + assertEquals(true, b.compareTo(a) > 0); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(true, b.isAfter(a)); + assertEquals(true, a.isBefore(b)); + } else if (half1.getValue() > half2.getValue()) { + assertEquals(true, a.compareTo(b) > 0); + assertEquals(true, b.compareTo(a) < 0); + assertEquals(true, a.isAfter(b)); + assertEquals(true, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); + } else { + assertEquals(0, a.compareTo(b)); + assertEquals(0, b.compareTo(a)); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); + } + } + } + } + } + } + } + + @Test + public void test_compareTo_nullYearHalf() { + assertThrows(NullPointerException.class, () -> TEST.compareTo(null)); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test + public void test_equals_and_hashCode() { + EqualsTester tester = new EqualsTester(); + for (int year = -100; year <= 100; year++) { + for (Half half : Half.values()) { + YearHalf instance1 = YearHalf.of(year, half); + YearHalf instance2 = YearHalf.of(year, half); + tester.addEqualityGroup(instance1, instance2); + } + } + tester.testEquals(); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test + public void test_toString() { + assertEquals("2012-H2", YearHalf.of(2012, H2).toString()); + } + + @Test + public void test_toString_bigYear() { + assertEquals("+10000-H2", YearHalf.of(10000, H2).toString()); + } + + @Test + public void test_toString_negativeYear() { + assertEquals("-0001-H2", YearHalf.of(-1, H2).toString()); + } + + @Test + public void test_toString_negativeBigYear() { + assertEquals("-10000-H2", YearHalf.of(-10000, H2).toString()); + } + +} diff --git a/src/test/java/org/threeten/extra/TestYearQuarter.java b/src/test/java/org/threeten/extra/TestYearQuarter.java index 3239efea..c1e13544 100644 --- a/src/test/java/org/threeten/extra/TestYearQuarter.java +++ b/src/test/java/org/threeten/extra/TestYearQuarter.java @@ -78,8 +78,9 @@ import static java.time.temporal.IsoFields.DAY_OF_QUARTER; import static java.time.temporal.IsoFields.QUARTER_OF_YEAR; import static java.time.temporal.IsoFields.QUARTER_YEARS; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.threeten.extra.Quarter.Q1; import static org.threeten.extra.Quarter.Q2; import static org.threeten.extra.Quarter.Q3; @@ -106,25 +107,26 @@ import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; + +import com.google.common.testing.EqualsTester; /** * Test YearQuarter. */ -@Test public class TestYearQuarter { private static final YearQuarter TEST = YearQuarter.of(2012, Q2); private static final int STANDARD_YEAR_LENGTH = 365; private static final int LEAP_YEAR_LENGTH = 366; - @BeforeMethod - public void setUp() { - } - //----------------------------------------------------------------------- + @Test public void test_interfaces() { assertTrue(Serializable.class.isAssignableFrom(YearQuarter.class)); assertTrue(Comparable.class.isAssignableFrom(YearQuarter.class)); @@ -132,297 +134,360 @@ public void test_interfaces() { assertTrue(TemporalAccessor.class.isAssignableFrom(YearQuarter.class)); } + @Test public void test_serialization() throws IOException, ClassNotFoundException { YearQuarter test = YearQuarter.of(2012, 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(test); - oos.close(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertEquals(test, ois.readObject()); + } + } + + //----------------------------------------------------------------------- + // of(Year,Quarter) + //----------------------------------------------------------------------- + @Test + public void test_of_Year_Quarter() { + for (int year = -100; year <= 100; year++) { + for (Quarter quarter : Quarter.values()) { + YearQuarter test = YearQuarter.of(Year.of(year), quarter); + assertEquals(year, test.getYear()); + assertEquals(quarter.getValue(), test.getQuarterValue()); + assertEquals(quarter, test.getQuarter()); + } + } + } + + @Test + public void test_of_Year_Quarter_nullQuarter() { + assertThrows(NullPointerException.class, () -> YearQuarter.of(Year.of(2012), (Quarter) null)); + } + + @Test + public void test_of_Year_Quarter_nullYear() { + assertThrows(NullPointerException.class, () -> YearQuarter.of((Year) null, Quarter.Q2)); + } + + @Test + public void test_of_Year_Quarter_nullBoth() { + assertThrows(NullPointerException.class, () -> YearQuarter.of((Year) null, (Quarter) null)); + } + + //----------------------------------------------------------------------- + // of(Year,int) + //----------------------------------------------------------------------- + @Test + public void test_of_Year_int() { + for (int year = -100; year <= 100; year++) { + for (Quarter quarter : Quarter.values()) { + YearQuarter test = YearQuarter.of(Year.of(year), quarter.getValue()); + assertEquals(year, test.getYear()); + assertEquals(quarter.getValue(), test.getQuarterValue()); + assertEquals(quarter, test.getQuarter()); + } + } + } - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( - baos.toByteArray())); - assertEquals(ois.readObject(), test); + @Test + public void test_of_Year_int_null() { + assertThrows(NullPointerException.class, () -> YearQuarter.of((Year) null, 2)); } //----------------------------------------------------------------------- // of(int,Quarter) //----------------------------------------------------------------------- + @Test public void test_of_int_Quarter() { for (int year = -100; year <= 100; year++) { for (Quarter quarter : Quarter.values()) { YearQuarter test = YearQuarter.of(year, quarter); - assertEquals(test.getYear(), year); - assertEquals(test.getQuarterValue(), quarter.getValue()); - assertEquals(test.getQuarter(), quarter); + assertEquals(year, test.getYear()); + assertEquals(quarter.getValue(), test.getQuarterValue()); + assertEquals(quarter, test.getQuarter()); } } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_Quarter_yearTooLow() { - YearQuarter.of(Year.MIN_VALUE - 1, Quarter.Q2); + assertThrows(DateTimeException.class, () -> YearQuarter.of(Year.MIN_VALUE - 1, Quarter.Q2)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_Quarter_yearTooHigh() { - YearQuarter.of(Year.MAX_VALUE + 1, Quarter.Q2); + assertThrows(DateTimeException.class, () -> YearQuarter.of(Year.MAX_VALUE + 1, Quarter.Q2)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_of_int_Quarter_null() { - YearQuarter.of(2012, (Quarter) null); + assertThrows(NullPointerException.class, () -> YearQuarter.of(2012, (Quarter) null)); } //----------------------------------------------------------------------- // of(int,int) //----------------------------------------------------------------------- + @Test public void test_of_int_int() { for (int year = -100; year <= 100; year++) { for (int quarter = 1; quarter <= 4; quarter++) { YearQuarter test = YearQuarter.of(year, quarter); - assertEquals(test.getYear(), year); - assertEquals(test.getQuarterValue(), quarter); - assertEquals(test.getQuarter(), Quarter.of(quarter)); - assertEquals(YearQuarter.of(year, quarter), test); - assertEquals(YearQuarter.of(year, quarter).hashCode(), test.hashCode()); + assertEquals(year, test.getYear()); + assertEquals(quarter, test.getQuarterValue()); + assertEquals(Quarter.of(quarter), test.getQuarter()); + assertEquals(test, YearQuarter.of(year, quarter)); + assertEquals(test.hashCode(), YearQuarter.of(year, quarter).hashCode()); } } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_int_yearTooLow() { - YearQuarter.of(Year.MIN_VALUE - 1, 1); + assertThrows(DateTimeException.class, () -> YearQuarter.of(Year.MIN_VALUE - 1, 1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_int_yearTooHigh() { - YearQuarter.of(Year.MAX_VALUE + 1, 1); + assertThrows(DateTimeException.class, () -> YearQuarter.of(Year.MAX_VALUE + 1, 1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_int_quarterTooLow() { - YearQuarter.of(2012, 0); + assertThrows(DateTimeException.class, () -> YearQuarter.of(2012, 0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_int_int_quarterTooHigh() { - YearQuarter.of(2012, 5); + assertThrows(DateTimeException.class, () -> YearQuarter.of(2012, 5)); } //----------------------------------------------------------------------- // from(TemporalAccessor) //----------------------------------------------------------------------- + @Test public void test_from_TemporalAccessor_notLeapYear() { LocalDate date = LocalDate.of(2007, 1, 1); for (int i = 1; i <= STANDARD_YEAR_LENGTH; i++) { YearQuarter test = YearQuarter.from(date); int expected = ((date.getMonthValue() - 1) / 3) + 1; - assertEquals(test, YearQuarter.of(2007, expected)); + assertEquals(YearQuarter.of(2007, expected), test); date = date.plusDays(1); } } + @Test public void test_from_TemporalAccessor_leapYear() { LocalDate date = LocalDate.of(2008, 1, 1); for (int i = 1; i <= LEAP_YEAR_LENGTH; i++) { YearQuarter test = YearQuarter.from(date); int expected = ((date.getMonthValue() - 1) / 3) + 1; - assertEquals(test, YearQuarter.of(2008, expected)); + assertEquals(YearQuarter.of(2008, expected), test); date = date.plusDays(1); } } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_TemporalAccessor_noDerive() { - YearQuarter.from(LocalTime.NOON); + assertThrows(DateTimeException.class, () -> YearQuarter.from(LocalTime.NOON)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_TemporalAccessor_null() { - YearQuarter.from((TemporalAccessor) null); + assertThrows(NullPointerException.class, () -> YearQuarter.from((TemporalAccessor) null)); } //----------------------------------------------------------------------- // parse(CharSequence) //----------------------------------------------------------------------- + @Test public void test_parse_CharSequence() { - assertEquals(YearQuarter.parse("2012-Q3"), YearQuarter.of(2012, Q3)); + assertEquals(YearQuarter.of(2012, Q3), YearQuarter.parse("2012-Q3")); } + @Test public void test_parse_CharSequence_caseInsensitive() { - assertEquals(YearQuarter.parse("2012-q3"), YearQuarter.of(2012, Q3)); + assertEquals(YearQuarter.of(2012, Q3), YearQuarter.parse("2012-q3")); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_parse_CharSequenceDate_invalidYear() { - YearQuarter.parse("12345-Q3"); + assertThrows(DateTimeParseException.class, () -> YearQuarter.parse("12345-Q3")); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_parse_CharSequenceDate_invalidQuarter() { - YearQuarter.parse("2012-Q0"); + assertThrows(DateTimeParseException.class, () -> YearQuarter.parse("2012-Q0")); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequenceDate_nullCharSequence() { - YearQuarter.parse((CharSequence) null); + assertThrows(NullPointerException.class, () -> YearQuarter.parse((CharSequence) null)); } //----------------------------------------------------------------------- // parse(CharSequence,DateTimeFormatter) //----------------------------------------------------------------------- + @Test public void test_parse_CharSequenceDateTimeFormatter() { DateTimeFormatter f = DateTimeFormatter.ofPattern("'Q'Q uuuu"); - assertEquals(YearQuarter.parse("Q3 2012", f), YearQuarter.of(2012, Q3)); + assertEquals(YearQuarter.of(2012, Q3), YearQuarter.parse("Q3 2012", f)); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_parse_CharSequenceDateDateTimeFormatter_invalidQuarter() { DateTimeFormatter f = DateTimeFormatter.ofPattern("'Q'Q uuuu"); - YearQuarter.parse("Q0 2012", f); + assertThrows(DateTimeParseException.class, () -> YearQuarter.parse("Q0 2012", f)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequenceDateTimeFormatter_nullCharSequence() { DateTimeFormatter f = DateTimeFormatter.ofPattern("'Q'Q uuuu"); - YearQuarter.parse((CharSequence) null, f); + assertThrows(NullPointerException.class, () -> YearQuarter.parse((CharSequence) null, f)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequenceDateTimeFormatter_nullDateTimeFormatter() { - YearQuarter.parse("", (DateTimeFormatter) null); + assertThrows(NullPointerException.class, () -> YearQuarter.parse("", (DateTimeFormatter) null)); } //----------------------------------------------------------------------- // isSupported(TemporalField) //----------------------------------------------------------------------- + @Test public void test_isSupported_TemporalField() { - assertEquals(TEST.isSupported((TemporalField) null), false); - assertEquals(TEST.isSupported(NANO_OF_SECOND), false); - assertEquals(TEST.isSupported(NANO_OF_DAY), false); - assertEquals(TEST.isSupported(MICRO_OF_SECOND), false); - assertEquals(TEST.isSupported(MICRO_OF_DAY), false); - assertEquals(TEST.isSupported(MILLI_OF_SECOND), false); - assertEquals(TEST.isSupported(MILLI_OF_DAY), false); - assertEquals(TEST.isSupported(SECOND_OF_MINUTE), false); - assertEquals(TEST.isSupported(SECOND_OF_DAY), false); - assertEquals(TEST.isSupported(MINUTE_OF_HOUR), false); - assertEquals(TEST.isSupported(MINUTE_OF_DAY), false); - assertEquals(TEST.isSupported(HOUR_OF_AMPM), false); - assertEquals(TEST.isSupported(CLOCK_HOUR_OF_AMPM), false); - assertEquals(TEST.isSupported(HOUR_OF_DAY), false); - assertEquals(TEST.isSupported(CLOCK_HOUR_OF_DAY), false); - assertEquals(TEST.isSupported(AMPM_OF_DAY), false); - assertEquals(TEST.isSupported(DAY_OF_WEEK), false); - assertEquals(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH), false); - assertEquals(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR), false); - assertEquals(TEST.isSupported(DAY_OF_MONTH), false); - assertEquals(TEST.isSupported(DAY_OF_YEAR), false); - assertEquals(TEST.isSupported(EPOCH_DAY), false); - assertEquals(TEST.isSupported(ALIGNED_WEEK_OF_MONTH), false); - assertEquals(TEST.isSupported(ALIGNED_WEEK_OF_YEAR), false); - assertEquals(TEST.isSupported(MONTH_OF_YEAR), false); - assertEquals(TEST.isSupported(PROLEPTIC_MONTH), false); - assertEquals(TEST.isSupported(YEAR_OF_ERA), true); - assertEquals(TEST.isSupported(YEAR), true); - assertEquals(TEST.isSupported(ERA), true); - assertEquals(TEST.isSupported(INSTANT_SECONDS), false); - assertEquals(TEST.isSupported(OFFSET_SECONDS), false); - assertEquals(TEST.isSupported(QUARTER_OF_YEAR), true); - assertEquals(TEST.isSupported(DAY_OF_QUARTER), false); + assertEquals(false, TEST.isSupported((TemporalField) null)); + assertEquals(false, TEST.isSupported(NANO_OF_SECOND)); + assertEquals(false, TEST.isSupported(NANO_OF_DAY)); + assertEquals(false, TEST.isSupported(MICRO_OF_SECOND)); + assertEquals(false, TEST.isSupported(MICRO_OF_DAY)); + assertEquals(false, TEST.isSupported(MILLI_OF_SECOND)); + assertEquals(false, TEST.isSupported(MILLI_OF_DAY)); + assertEquals(false, TEST.isSupported(SECOND_OF_MINUTE)); + assertEquals(false, TEST.isSupported(SECOND_OF_DAY)); + assertEquals(false, TEST.isSupported(MINUTE_OF_HOUR)); + assertEquals(false, TEST.isSupported(MINUTE_OF_DAY)); + assertEquals(false, TEST.isSupported(HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(AMPM_OF_DAY)); + assertEquals(false, TEST.isSupported(DAY_OF_WEEK)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(false, TEST.isSupported(DAY_OF_MONTH)); + assertEquals(false, TEST.isSupported(DAY_OF_YEAR)); + assertEquals(false, TEST.isSupported(EPOCH_DAY)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_YEAR)); + assertEquals(false, TEST.isSupported(MONTH_OF_YEAR)); + assertEquals(false, TEST.isSupported(PROLEPTIC_MONTH)); + assertEquals(true, TEST.isSupported(YEAR_OF_ERA)); + assertEquals(true, TEST.isSupported(YEAR)); + assertEquals(true, TEST.isSupported(ERA)); + assertEquals(false, TEST.isSupported(INSTANT_SECONDS)); + assertEquals(false, TEST.isSupported(OFFSET_SECONDS)); + assertEquals(true, TEST.isSupported(QUARTER_OF_YEAR)); + assertEquals(false, TEST.isSupported(DAY_OF_QUARTER)); } //----------------------------------------------------------------------- // isSupported(TemporalUnit) //----------------------------------------------------------------------- + @Test public void test_isSupported_TemporalUnit() { - assertEquals(TEST.isSupported((TemporalUnit) null), false); - assertEquals(TEST.isSupported(NANOS), false); - assertEquals(TEST.isSupported(MICROS), false); - assertEquals(TEST.isSupported(MILLIS), false); - assertEquals(TEST.isSupported(SECONDS), false); - assertEquals(TEST.isSupported(MINUTES), false); - assertEquals(TEST.isSupported(HOURS), false); - assertEquals(TEST.isSupported(DAYS), false); - assertEquals(TEST.isSupported(WEEKS), false); - assertEquals(TEST.isSupported(MONTHS), false); - assertEquals(TEST.isSupported(YEARS), true); - assertEquals(TEST.isSupported(DECADES), true); - assertEquals(TEST.isSupported(CENTURIES), true); - assertEquals(TEST.isSupported(MILLENNIA), true); - assertEquals(TEST.isSupported(ERA), true); - assertEquals(TEST.isSupported(FOREVER), false); - assertEquals(TEST.isSupported(QUARTER_YEARS), true); + assertEquals(false, TEST.isSupported((TemporalUnit) null)); + assertEquals(false, TEST.isSupported(NANOS)); + assertEquals(false, TEST.isSupported(MICROS)); + assertEquals(false, TEST.isSupported(MILLIS)); + assertEquals(false, TEST.isSupported(SECONDS)); + assertEquals(false, TEST.isSupported(MINUTES)); + assertEquals(false, TEST.isSupported(HOURS)); + assertEquals(false, TEST.isSupported(DAYS)); + assertEquals(false, TEST.isSupported(WEEKS)); + assertEquals(false, TEST.isSupported(MONTHS)); + assertEquals(true, TEST.isSupported(YEARS)); + assertEquals(true, TEST.isSupported(DECADES)); + assertEquals(true, TEST.isSupported(CENTURIES)); + assertEquals(true, TEST.isSupported(MILLENNIA)); + assertEquals(true, TEST.isSupported(ERA)); + assertEquals(false, TEST.isSupported(FOREVER)); + assertEquals(true, TEST.isSupported(QUARTER_YEARS)); } //----------------------------------------------------------------------- // range(TemporalField) //----------------------------------------------------------------------- + @Test public void test_range() { - assertEquals(TEST.range(QUARTER_OF_YEAR), QUARTER_OF_YEAR.range()); - assertEquals(TEST.range(YEAR), YEAR.range()); - assertEquals(TEST.range(YEAR_OF_ERA), ValueRange.of(1, Year.MAX_VALUE)); - assertEquals(TEST.range(ERA), ERA.range()); + assertEquals(QUARTER_OF_YEAR.range(), TEST.range(QUARTER_OF_YEAR)); + assertEquals(YEAR.range(), TEST.range(YEAR)); + assertEquals(ValueRange.of(1, Year.MAX_VALUE), TEST.range(YEAR_OF_ERA)); + assertEquals(ERA.range(), TEST.range(ERA)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_invalidField() { - TEST.range(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.range(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_range_null() { - TEST.range((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.range((TemporalField) null)); } //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- + @Test public void test_get() { - assertEquals(TEST.get(QUARTER_OF_YEAR), 2); - assertEquals(TEST.get(YEAR), 2012); - assertEquals(TEST.get(YEAR_OF_ERA), 2012); - assertEquals(TEST.get(ERA), 1); + assertEquals(2, TEST.get(QUARTER_OF_YEAR)); + assertEquals(2012, TEST.get(YEAR)); + assertEquals(2012, TEST.get(YEAR_OF_ERA)); + assertEquals(1, TEST.get(ERA)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_get_invalidField() { - TEST.get(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.get(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_get_null() { - TEST.get((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.get((TemporalField) null)); } //----------------------------------------------------------------------- // getLong(TemporalField) //----------------------------------------------------------------------- + @Test public void test_getLong() { - assertEquals(TEST.getLong(QUARTER_OF_YEAR), 2L); - assertEquals(TEST.getLong(YEAR), 2012L); - assertEquals(TEST.getLong(YEAR_OF_ERA), 2012L); - assertEquals(TEST.getLong(ERA), 1L); + assertEquals(2L, TEST.getLong(QUARTER_OF_YEAR)); + assertEquals(2012L, TEST.getLong(YEAR)); + assertEquals(2012L, TEST.getLong(YEAR_OF_ERA)); + assertEquals(1L, TEST.getLong(ERA)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_invalidField() { - TEST.getLong(MONTH_OF_YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.getLong(MONTH_OF_YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getLong_null() { - TEST.getLong((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.getLong((TemporalField) null)); } //----------------------------------------------------------------------- // isLeapYear(int) //----------------------------------------------------------------------- + @Test public void test_isLeapYear_int() { for (int year = -500; year <= 500; year++) { for (Quarter quarter : Quarter.values()) { YearQuarter test = YearQuarter.of(year, quarter); - assertEquals(test.isLeapYear(), Year.isLeap(year)); + assertEquals(Year.isLeap(year), test.isLeapYear()); } } } @@ -432,194 +497,207 @@ public void test_isLeapYear_int() { //----------------------------------------------------------------------- @Test public void test_isValidDay_int_nonLeap() { - assertEquals(YearQuarter.of(2011, Q1).isValidDay(90), true); - assertEquals(YearQuarter.of(2011, Q1).isValidDay(91), false); - assertEquals(YearQuarter.of(2011, Q1).isValidDay(92), false); + assertEquals(true, YearQuarter.of(2011, Q1).isValidDay(90)); + assertEquals(false, YearQuarter.of(2011, Q1).isValidDay(91)); + assertEquals(false, YearQuarter.of(2011, Q1).isValidDay(92)); - assertEquals(YearQuarter.of(2011, Q2).isValidDay(90), true); - assertEquals(YearQuarter.of(2011, Q2).isValidDay(91), true); - assertEquals(YearQuarter.of(2011, Q2).isValidDay(92), false); + assertEquals(true, YearQuarter.of(2011, Q2).isValidDay(90)); + assertEquals(true, YearQuarter.of(2011, Q2).isValidDay(91)); + assertEquals(false, YearQuarter.of(2011, Q2).isValidDay(92)); - assertEquals(YearQuarter.of(2011, Q3).isValidDay(90), true); - assertEquals(YearQuarter.of(2011, Q3).isValidDay(91), true); - assertEquals(YearQuarter.of(2011, Q4).isValidDay(90), true); + assertEquals(true, YearQuarter.of(2011, Q3).isValidDay(90)); + assertEquals(true, YearQuarter.of(2011, Q3).isValidDay(91)); + assertEquals(true, YearQuarter.of(2011, Q4).isValidDay(90)); - assertEquals(YearQuarter.of(2011, Q3).isValidDay(92), true); - assertEquals(YearQuarter.of(2011, Q4).isValidDay(91), true); - assertEquals(YearQuarter.of(2011, Q4).isValidDay(92), true); + assertEquals(true, YearQuarter.of(2011, Q3).isValidDay(92)); + assertEquals(true, YearQuarter.of(2011, Q4).isValidDay(91)); + assertEquals(true, YearQuarter.of(2011, Q4).isValidDay(92)); } @Test public void test_isValidDay_int_leap() { - assertEquals(YearQuarter.of(2012, Q1).isValidDay(90), true); - assertEquals(YearQuarter.of(2012, Q1).isValidDay(91), true); - assertEquals(YearQuarter.of(2012, Q1).isValidDay(92), false); + assertEquals(true, YearQuarter.of(2012, Q1).isValidDay(90)); + assertEquals(true, YearQuarter.of(2012, Q1).isValidDay(91)); + assertEquals(false, YearQuarter.of(2012, Q1).isValidDay(92)); - assertEquals(YearQuarter.of(2012, Q2).isValidDay(90), true); - assertEquals(YearQuarter.of(2012, Q2).isValidDay(91), true); - assertEquals(YearQuarter.of(2012, Q2).isValidDay(92), false); + assertEquals(true, YearQuarter.of(2012, Q2).isValidDay(90)); + assertEquals(true, YearQuarter.of(2012, Q2).isValidDay(91)); + assertEquals(false, YearQuarter.of(2012, Q2).isValidDay(92)); - assertEquals(YearQuarter.of(2012, Q3).isValidDay(90), true); - assertEquals(YearQuarter.of(2012, Q3).isValidDay(91), true); - assertEquals(YearQuarter.of(2012, Q3).isValidDay(92), true); + assertEquals(true, YearQuarter.of(2012, Q3).isValidDay(90)); + assertEquals(true, YearQuarter.of(2012, Q3).isValidDay(91)); + assertEquals(true, YearQuarter.of(2012, Q3).isValidDay(92)); - assertEquals(YearQuarter.of(2012, Q4).isValidDay(90), true); - assertEquals(YearQuarter.of(2012, Q4).isValidDay(91), true); - assertEquals(YearQuarter.of(2012, Q4).isValidDay(92), true); + assertEquals(true, YearQuarter.of(2012, Q4).isValidDay(90)); + assertEquals(true, YearQuarter.of(2012, Q4).isValidDay(91)); + assertEquals(true, YearQuarter.of(2012, Q4).isValidDay(92)); } @Test public void test_isValidDay_int_outOfRange() { - assertEquals(YearQuarter.of(2011, Q1).isValidDay(93), false); - assertEquals(YearQuarter.of(2011, Q2).isValidDay(93), false); - assertEquals(YearQuarter.of(2011, Q3).isValidDay(93), false); - assertEquals(YearQuarter.of(2011, Q4).isValidDay(93), false); + assertEquals(false, YearQuarter.of(2011, Q1).isValidDay(93)); + assertEquals(false, YearQuarter.of(2011, Q2).isValidDay(93)); + assertEquals(false, YearQuarter.of(2011, Q3).isValidDay(93)); + assertEquals(false, YearQuarter.of(2011, Q4).isValidDay(93)); - assertEquals(YearQuarter.of(2011, Q1).isValidDay(0), false); - assertEquals(YearQuarter.of(2011, Q2).isValidDay(0), false); - assertEquals(YearQuarter.of(2011, Q3).isValidDay(0), false); - assertEquals(YearQuarter.of(2011, Q4).isValidDay(0), false); + assertEquals(false, YearQuarter.of(2011, Q1).isValidDay(0)); + assertEquals(false, YearQuarter.of(2011, Q2).isValidDay(0)); + assertEquals(false, YearQuarter.of(2011, Q3).isValidDay(0)); + assertEquals(false, YearQuarter.of(2011, Q4).isValidDay(0)); } //----------------------------------------------------------------------- // lengthOfQuarter() //----------------------------------------------------------------------- + @Test public void test_lengthOfQuarter() { for (int year = -500; year <= 500; year++) { - assertEquals(YearQuarter.of(year, Q1).lengthOfQuarter(), Year.isLeap(year) ? 91 : 90); - assertEquals(YearQuarter.of(year, Q2).lengthOfQuarter(), 91); - assertEquals(YearQuarter.of(year, Q3).lengthOfQuarter(), 92); - assertEquals(YearQuarter.of(year, Q4).lengthOfQuarter(), 92); + assertEquals(Year.isLeap(year) ? 91 : 90, YearQuarter.of(year, Q1).lengthOfQuarter()); + assertEquals(91, YearQuarter.of(year, Q2).lengthOfQuarter()); + assertEquals(92, YearQuarter.of(year, Q3).lengthOfQuarter()); + assertEquals(92, YearQuarter.of(year, Q4).lengthOfQuarter()); } } //----------------------------------------------------------------------- // with(TemporalAdjuster) //----------------------------------------------------------------------- + @Test public void test_with_TemporalAdjuster_Quarter() { - assertEquals(YearQuarter.of(2007, Q2).with(Q1), YearQuarter.of(2007, Q1)); + assertEquals(YearQuarter.of(2007, Q1), YearQuarter.of(2007, Q2).with(Q1)); } + @Test public void test_with_TemporalAdjuster_Year() { - assertEquals(YearQuarter.of(2007, Q2).with(Year.of(2012)), YearQuarter.of(2012, Q2)); + assertEquals(YearQuarter.of(2012, Q2), YearQuarter.of(2007, Q2).with(Year.of(2012))); } + @Test public void test_with_TemporalAdjuster_YearQuarter() { - assertEquals(YearQuarter.of(2007, Q2).with(YearQuarter.of(2012, Q3)), YearQuarter.of(2012, Q3)); + assertEquals(YearQuarter.of(2012, Q3), YearQuarter.of(2007, Q2).with(YearQuarter.of(2012, Q3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_with_TemporalAdjuster_LocalDate() { - YearQuarter.of(2007, Q2).with(LocalDate.of(2012, 6, 30)); + assertThrows(DateTimeException.class, () -> YearQuarter.of(2007, Q2).with(LocalDate.of(2012, 6, 30))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_with_TemporalAdjuster_null() { - YearQuarter.of(2007, Q2).with((TemporalAdjuster) null); + assertThrows(NullPointerException.class, () -> YearQuarter.of(2007, Q2).with((TemporalAdjuster) null)); } //----------------------------------------------------------------------- // withYear(int) //----------------------------------------------------------------------- + @Test public void test_withYear() { - assertEquals(YearQuarter.of(2007, Q2).withYear(2012), YearQuarter.of(2012, Q2)); + assertEquals(YearQuarter.of(2012, Q2), YearQuarter.of(2007, Q2).withYear(2012)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withYear_int_quarterTooLow() { - TEST.withYear(Year.MIN_VALUE - 1); + assertThrows(DateTimeException.class, () -> TEST.withYear(Year.MIN_VALUE - 1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withYear_int_quarterTooHigh() { - TEST.withYear(Year.MAX_VALUE + 1); + assertThrows(DateTimeException.class, () -> TEST.withYear(Year.MAX_VALUE + 1)); } //----------------------------------------------------------------------- // withQuarter(int) //----------------------------------------------------------------------- + @Test public void test_withQuarter_int() { - assertEquals(YearQuarter.of(2007, Q2).withQuarter(1), YearQuarter.of(2007, Q1)); + assertEquals(YearQuarter.of(2007, Q1), YearQuarter.of(2007, Q2).withQuarter(1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withQuarter_int_quarterTooLow() { - TEST.withQuarter(0); + assertThrows(DateTimeException.class, () -> TEST.withQuarter(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withQuarter_int_quarterTooHigh() { - TEST.withQuarter(5); + assertThrows(DateTimeException.class, () -> TEST.withQuarter(5)); } //----------------------------------------------------------------------- // plus(long,TemporalUnit) //----------------------------------------------------------------------- + @Test public void test_plus_longTemporalUnit() { - assertEquals(YearQuarter.of(2007, Q2).plus(5, YEARS), YearQuarter.of(2012, Q2)); - assertEquals(YearQuarter.of(2007, Q2).plus(0, YEARS), YearQuarter.of(2007, Q2)); - assertEquals(YearQuarter.of(2007, Q2).plus(-5, YEARS), YearQuarter.of(2002, Q2)); - assertEquals(YearQuarter.of(2007, Q2).plus(5, QUARTER_YEARS), YearQuarter.of(2008, Q3)); - assertEquals(YearQuarter.of(2007, Q2).plus(0, QUARTER_YEARS), YearQuarter.of(2007, Q2)); - assertEquals(YearQuarter.of(2007, Q2).plus(-5, QUARTER_YEARS), YearQuarter.of(2006, Q1)); + assertEquals(YearQuarter.of(2012, Q2), YearQuarter.of(2007, Q2).plus(5, YEARS)); + assertEquals(YearQuarter.of(2007, Q2), YearQuarter.of(2007, Q2).plus(0, YEARS)); + assertEquals(YearQuarter.of(2002, Q2), YearQuarter.of(2007, Q2).plus(-5, YEARS)); + assertEquals(YearQuarter.of(2008, Q3), YearQuarter.of(2007, Q2).plus(5, QUARTER_YEARS)); + assertEquals(YearQuarter.of(2007, Q2), YearQuarter.of(2007, Q2).plus(0, QUARTER_YEARS)); + assertEquals(YearQuarter.of(2006, Q1), YearQuarter.of(2007, Q2).plus(-5, QUARTER_YEARS)); } //----------------------------------------------------------------------- // plusYears(int) //----------------------------------------------------------------------- + @Test public void test_plusYears() { - assertEquals(YearQuarter.of(2007, Q2).plusYears(5), YearQuarter.of(2012, Q2)); - assertEquals(YearQuarter.of(2007, Q2).plusYears(0), YearQuarter.of(2007, Q2)); - assertEquals(YearQuarter.of(2007, Q2).plusYears(-5), YearQuarter.of(2002, Q2)); + assertEquals(YearQuarter.of(2012, Q2), YearQuarter.of(2007, Q2).plusYears(5)); + assertEquals(YearQuarter.of(2007, Q2), YearQuarter.of(2007, Q2).plusYears(0)); + assertEquals(YearQuarter.of(2002, Q2), YearQuarter.of(2007, Q2).plusYears(-5)); } //----------------------------------------------------------------------- // plusQuarters(int) //----------------------------------------------------------------------- + @Test public void test_plusQuarters() { - assertEquals(YearQuarter.of(2007, Q2).plusQuarters(5), YearQuarter.of(2008, Q3)); - assertEquals(YearQuarter.of(2007, Q2).plusQuarters(0), YearQuarter.of(2007, Q2)); - assertEquals(YearQuarter.of(2007, Q2).plusQuarters(-5), YearQuarter.of(2006, Q1)); + assertEquals(YearQuarter.of(2008, Q3), YearQuarter.of(2007, Q2).plusQuarters(5)); + assertEquals(YearQuarter.of(2007, Q2), YearQuarter.of(2007, Q2).plusQuarters(0)); + assertEquals(YearQuarter.of(2006, Q1), YearQuarter.of(2007, Q2).plusQuarters(-5)); } //----------------------------------------------------------------------- // minus(long,TemporalUnit) //----------------------------------------------------------------------- + @Test public void test_minus_longTemporalUnit() { - assertEquals(YearQuarter.of(2007, Q2).minus(5, YEARS), YearQuarter.of(2002, Q2)); - assertEquals(YearQuarter.of(2007, Q2).minus(0, YEARS), YearQuarter.of(2007, Q2)); - assertEquals(YearQuarter.of(2007, Q2).minus(-5, YEARS), YearQuarter.of(2012, Q2)); - assertEquals(YearQuarter.of(2007, Q2).minus(5, QUARTER_YEARS), YearQuarter.of(2006, Q1)); - assertEquals(YearQuarter.of(2007, Q2).minus(0, QUARTER_YEARS), YearQuarter.of(2007, Q2)); - assertEquals(YearQuarter.of(2007, Q2).minus(-5, QUARTER_YEARS), YearQuarter.of(2008, Q3)); + assertEquals(YearQuarter.of(2002, Q2), YearQuarter.of(2007, Q2).minus(5, YEARS)); + assertEquals(YearQuarter.of(2007, Q2), YearQuarter.of(2007, Q2).minus(0, YEARS)); + assertEquals(YearQuarter.of(2012, Q2), YearQuarter.of(2007, Q2).minus(-5, YEARS)); + assertEquals(YearQuarter.of(2006, Q1), YearQuarter.of(2007, Q2).minus(5, QUARTER_YEARS)); + assertEquals(YearQuarter.of(2007, Q2), YearQuarter.of(2007, Q2).minus(0, QUARTER_YEARS)); + assertEquals(YearQuarter.of(2008, Q3), YearQuarter.of(2007, Q2).minus(-5, QUARTER_YEARS)); } //----------------------------------------------------------------------- // minusYears(int) //----------------------------------------------------------------------- + @Test public void test_minusYears() { - assertEquals(YearQuarter.of(2007, Q2).minusYears(5), YearQuarter.of(2002, Q2)); - assertEquals(YearQuarter.of(2007, Q2).minusYears(0), YearQuarter.of(2007, Q2)); - assertEquals(YearQuarter.of(2007, Q2).minusYears(-5), YearQuarter.of(2012, Q2)); + assertEquals(YearQuarter.of(2002, Q2), YearQuarter.of(2007, Q2).minusYears(5)); + assertEquals(YearQuarter.of(2007, Q2), YearQuarter.of(2007, Q2).minusYears(0)); + assertEquals(YearQuarter.of(2012, Q2), YearQuarter.of(2007, Q2).minusYears(-5)); } //----------------------------------------------------------------------- // minusQuarters(int) //----------------------------------------------------------------------- + @Test public void test_minusQuarters() { - assertEquals(YearQuarter.of(2007, Q2).minusQuarters(5), YearQuarter.of(2006, Q1)); - assertEquals(YearQuarter.of(2007, Q2).minusQuarters(0), YearQuarter.of(2007, Q2)); - assertEquals(YearQuarter.of(2007, Q2).minusQuarters(-5), YearQuarter.of(2008, Q3)); + assertEquals(YearQuarter.of(2006, Q1), YearQuarter.of(2007, Q2).minusQuarters(5)); + assertEquals(YearQuarter.of(2007, Q2), YearQuarter.of(2007, Q2).minusQuarters(0)); + assertEquals(YearQuarter.of(2008, Q3), YearQuarter.of(2007, Q2).minusQuarters(-5)); } //----------------------------------------------------------------------- // lengthOfYear() //----------------------------------------------------------------------- + @Test public void test_lengthOfYear() { for (int year = -500; year <= 500; year++) { for (Quarter quarter : Quarter.values()) { YearQuarter test = YearQuarter.of(year, quarter); - assertEquals(test.lengthOfYear(), Year.isLeap(year) ? 366 : 365); + assertEquals(Year.isLeap(year) ? 366 : 365, test.lengthOfYear()); } } } @@ -629,171 +707,213 @@ public void test_lengthOfYear() { //----------------------------------------------------------------------- @Test public void test_query() { - assertEquals(TEST.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); - assertEquals(TEST.query(TemporalQueries.localDate()), null); - assertEquals(TEST.query(TemporalQueries.localTime()), null); - assertEquals(TEST.query(TemporalQueries.offset()), null); - assertEquals(TEST.query(TemporalQueries.precision()), QUARTER_YEARS); - assertEquals(TEST.query(TemporalQueries.zone()), null); - assertEquals(TEST.query(TemporalQueries.zoneId()), null); + assertEquals(IsoChronology.INSTANCE, TEST.query(TemporalQueries.chronology())); + assertEquals(null, TEST.query(TemporalQueries.localDate())); + assertEquals(null, TEST.query(TemporalQueries.localTime())); + assertEquals(null, TEST.query(TemporalQueries.offset())); + assertEquals(QUARTER_YEARS, TEST.query(TemporalQueries.precision())); + assertEquals(null, TEST.query(TemporalQueries.zone())); + assertEquals(null, TEST.query(TemporalQueries.zoneId())); } //----------------------------------------------------------------------- // adjustInto(Temporal) //----------------------------------------------------------------------- + @Test public void test_adjustInto_Temporal() { for (int month = 1; month < 12; month++) { for (int dom = 1; dom < 28; dom++) { LocalDate base = LocalDate.of(2007, month, dom); LocalDate expected = LocalDate.of(2012, 4 + ((month - 1) % 3), dom); - assertEquals(YearQuarter.of(2012, Q2).adjustInto(base), expected); + assertEquals(expected, YearQuarter.of(2012, Q2).adjustInto(base)); } } } + @Test public void test_adjustInto_Temporal_lastValidDay_nonLeap() { LocalDate base = LocalDate.of(2007, 5, 31); LocalDate expected = LocalDate.of(2011, 2, 28); - assertEquals(YearQuarter.of(2011, Q1).adjustInto(base), expected); + assertEquals(expected, YearQuarter.of(2011, Q1).adjustInto(base)); } + @Test public void test_adjustInto_Temporal_lastValidDay_leap() { LocalDate base = LocalDate.of(2007, 5, 31); LocalDate expected = LocalDate.of(2012, 2, 29); - assertEquals(YearQuarter.of(2012, Q1).adjustInto(base), expected); + assertEquals(expected, YearQuarter.of(2012, Q1).adjustInto(base)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_adjustInto_Temporal_null() { - TEST.adjustInto((Temporal) null); + assertThrows(NullPointerException.class, () -> TEST.adjustInto((Temporal) null)); } //----------------------------------------------------------------------- // until(Temporal,TemporalUnit) //----------------------------------------------------------------------- + @Test public void test_until_TemporalTemporalUnit_QUARTER_YEARS() { - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q4), QUARTER_YEARS), -2); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q1), QUARTER_YEARS), -1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q2), QUARTER_YEARS), 0); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q3), QUARTER_YEARS), 1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q4), QUARTER_YEARS), 2); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q1), QUARTER_YEARS), 3); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q2), QUARTER_YEARS), 4); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q3), QUARTER_YEARS), 5); + assertEquals(-2, YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q4), QUARTER_YEARS)); + assertEquals(-1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q1), QUARTER_YEARS)); + assertEquals(0, YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q2), QUARTER_YEARS)); + assertEquals(1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q3), QUARTER_YEARS)); + assertEquals(2, YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q4), QUARTER_YEARS)); + assertEquals(3, YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q1), QUARTER_YEARS)); + assertEquals(4, YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q2), QUARTER_YEARS)); + assertEquals(5, YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q3), QUARTER_YEARS)); } + @Test public void test_until_TemporalTemporalUnit_YEARS() { - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2010, Q2), YEARS), -2); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2010, Q3), YEARS), -1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2010, Q4), YEARS), -1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q1), YEARS), -1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q2), YEARS), -1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q3), YEARS), 0); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q4), YEARS), 0); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q1), YEARS), 0); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q2), YEARS), 0); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q3), YEARS), 0); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q4), YEARS), 0); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q1), YEARS), 0); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q2), YEARS), 1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q3), YEARS), 1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q4), YEARS), 1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2014, Q1), YEARS), 1); - assertEquals(YearQuarter.of(2012, Q2).until(YearQuarter.of(2014, Q2), YEARS), 2); - } - - @Test(expectedExceptions = NullPointerException.class) + assertEquals(-2, YearQuarter.of(2012, Q2).until(YearQuarter.of(2010, Q2), YEARS)); + assertEquals(-1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2010, Q3), YEARS)); + assertEquals(-1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2010, Q4), YEARS)); + assertEquals(-1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q1), YEARS)); + assertEquals(-1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q2), YEARS)); + assertEquals(0, YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q3), YEARS)); + assertEquals(0, YearQuarter.of(2012, Q2).until(YearQuarter.of(2011, Q4), YEARS)); + assertEquals(0, YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q1), YEARS)); + assertEquals(0, YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q2), YEARS)); + assertEquals(0, YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q3), YEARS)); + assertEquals(0, YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q4), YEARS)); + assertEquals(0, YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q1), YEARS)); + assertEquals(1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q2), YEARS)); + assertEquals(1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q3), YEARS)); + assertEquals(1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2013, Q4), YEARS)); + assertEquals(1, YearQuarter.of(2012, Q2).until(YearQuarter.of(2014, Q1), YEARS)); + assertEquals(2, YearQuarter.of(2012, Q2).until(YearQuarter.of(2014, Q2), YEARS)); + } + + @Test public void test_until_TemporalTemporalUnit_nullTemporal() { - YearQuarter.of(2012, Q2).until(null, QUARTER_YEARS); + assertThrows(NullPointerException.class, () -> YearQuarter.of(2012, Q2).until(null, QUARTER_YEARS)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_until_TemporalTemporalUnit_nullTemporalUnit() { - YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q3), null); + assertThrows(NullPointerException.class, () -> YearQuarter.of(2012, Q2).until(YearQuarter.of(2012, Q3), null)); + } + + //----------------------------------------------------------------------- + // quartersUntil(YearQuarter) + //----------------------------------------------------------------------- + @Test + public void test_quartersUntil_null() { + assertThrows(NullPointerException.class, () -> YearQuarter.of(2012, Q2).quartersUntil(null)); + } + + @Test + public void test_quartersUntil_IllegalArgument() { + assertThrows(IllegalArgumentException.class, () -> YearQuarter.of(2012, Q2).quartersUntil(YearQuarter.of(2012, Q1))); + } + + @Test + public void test_quartersUntil() { + assertEquals(2, YearQuarter.of(2012, Q2).quartersUntil(YearQuarter.of(2012, Q4)).count()); + assertEquals(10, YearQuarter.of(2012, Q2).quartersUntil(YearQuarter.of(2014, Q4)).count()); + + YearQuarter start = YearQuarter.of(2012, Q1); + YearQuarter end = YearQuarter.of(2013, Q3); + Stream stream = start.quartersUntil(end); + + List expects = Arrays.asList( + YearQuarter.of(start.getYear(), Q1), + YearQuarter.of(start.getYear(), Q2), + YearQuarter.of(start.getYear(), Q3), + YearQuarter.of(start.getYear(), Q4), + YearQuarter.of(end.getYear(), Q1), + YearQuarter.of(end.getYear(), Q2)); + assertEquals(expects, stream.collect(Collectors.toList())); } //----------------------------------------------------------------------- // format(DateTimeFormatter) //----------------------------------------------------------------------- + @Test public void test_format() { DateTimeFormatter f = DateTimeFormatter.ofPattern("'Q'Q uuuu"); - assertEquals(YearQuarter.of(2012, Q1).format(f), "Q1 2012"); + assertEquals("Q1 2012", YearQuarter.of(2012, Q1).format(f)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_format_null() { - TEST.format((DateTimeFormatter) null); + assertThrows(NullPointerException.class, () -> TEST.format((DateTimeFormatter) null)); } //----------------------------------------------------------------------- // atDay(int) //----------------------------------------------------------------------- + @Test public void test_atDay() { for (int i = 1; i <= 90; i++) { LocalDate expected = LocalDate.of(2012, 1, 1).plusDays(i - 1); - assertEquals(YearQuarter.of(2012, Q1).atDay(i), expected); + assertEquals(expected, YearQuarter.of(2012, Q1).atDay(i)); } for (int i = 1; i <= 91; i++) { LocalDate expected = LocalDate.of(2012, 4, 1).plusDays(i - 1); - assertEquals(YearQuarter.of(2012, Q2).atDay(i), expected); + assertEquals(expected, YearQuarter.of(2012, Q2).atDay(i)); } for (int i = 1; i <= 92; i++) { LocalDate expected = LocalDate.of(2012, 7, 1).plusDays(i - 1); - assertEquals(YearQuarter.of(2012, Q3).atDay(i), expected); + assertEquals(expected, YearQuarter.of(2012, Q3).atDay(i)); } for (int i = 1; i <= 92; i++) { LocalDate expected = LocalDate.of(2012, 10, 1).plusDays(i - 1); - assertEquals(YearQuarter.of(2012, Q4).atDay(i), expected); + assertEquals(expected, YearQuarter.of(2012, Q4).atDay(i)); } } + @Test public void test_atDay_Q1_91_leap() { - assertEquals(YearQuarter.of(2012, Q1).atDay(91), LocalDate.of(2012, 3, 31)); + assertEquals(LocalDate.of(2012, 3, 31), YearQuarter.of(2012, Q1).atDay(91)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atDay_Q1_91_notLeap() { - YearQuarter.of(2011, Q1).atDay(91); + assertThrows(DateTimeException.class, () -> YearQuarter.of(2011, Q1).atDay(91)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atDay_Q1_92() { - YearQuarter.of(2012, Q1).atDay(92); + assertThrows(DateTimeException.class, () -> YearQuarter.of(2012, Q1).atDay(92)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atDay_Q2_92() { - YearQuarter.of(2012, Q2).atDay(92); + assertThrows(DateTimeException.class, () -> YearQuarter.of(2012, Q2).atDay(92)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atDay_tooLow() { - TEST.atDay(0); + assertThrows(DateTimeException.class, () -> TEST.atDay(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_atDay_tooHigh() { - TEST.atDay(93); + assertThrows(DateTimeException.class, () -> TEST.atDay(93)); } //----------------------------------------------------------------------- // atEndOfQuarter(int) //----------------------------------------------------------------------- + @Test public void test_atEndOfQuarter() { - assertEquals(YearQuarter.of(2011, Q1).atEndOfQuarter(), LocalDate.of(2011, 3, 31)); - assertEquals(YearQuarter.of(2011, Q2).atEndOfQuarter(), LocalDate.of(2011, 6, 30)); - assertEquals(YearQuarter.of(2011, Q3).atEndOfQuarter(), LocalDate.of(2011, 9, 30)); - assertEquals(YearQuarter.of(2011, Q4).atEndOfQuarter(), LocalDate.of(2011, 12, 31)); + assertEquals(LocalDate.of(2011, 3, 31), YearQuarter.of(2011, Q1).atEndOfQuarter()); + assertEquals(LocalDate.of(2011, 6, 30), YearQuarter.of(2011, Q2).atEndOfQuarter()); + assertEquals(LocalDate.of(2011, 9, 30), YearQuarter.of(2011, Q3).atEndOfQuarter()); + assertEquals(LocalDate.of(2011, 12, 31), YearQuarter.of(2011, Q4).atEndOfQuarter()); - assertEquals(YearQuarter.of(2012, Q1).atEndOfQuarter(), LocalDate.of(2012, 3, 31)); - assertEquals(YearQuarter.of(2012, Q2).atEndOfQuarter(), LocalDate.of(2012, 6, 30)); - assertEquals(YearQuarter.of(2012, Q3).atEndOfQuarter(), LocalDate.of(2012, 9, 30)); - assertEquals(YearQuarter.of(2012, Q4).atEndOfQuarter(), LocalDate.of(2012, 12, 31)); + assertEquals(LocalDate.of(2012, 3, 31), YearQuarter.of(2012, Q1).atEndOfQuarter()); + assertEquals(LocalDate.of(2012, 6, 30), YearQuarter.of(2012, Q2).atEndOfQuarter()); + assertEquals(LocalDate.of(2012, 9, 30), YearQuarter.of(2012, Q3).atEndOfQuarter()); + assertEquals(LocalDate.of(2012, 12, 31), YearQuarter.of(2012, Q4).atEndOfQuarter()); } //----------------------------------------------------------------------- // compareTo() //----------------------------------------------------------------------- + @Test public void test_compareTo() { for (int year1 = -100; year1 < 100; year1++) { for (Quarter quarter1 : Quarter.values()) { @@ -802,41 +922,41 @@ public void test_compareTo() { for (Quarter quarter2 : Quarter.values()) { YearQuarter b = YearQuarter.of(year2, quarter2); if (year1 < year2) { - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); - assertEquals(a.isAfter(b), false); - assertEquals(b.isBefore(a), false); - assertEquals(b.isAfter(a), true); - assertEquals(a.isBefore(b), true); + assertEquals(true, a.compareTo(b) < 0); + assertEquals(true, b.compareTo(a) > 0); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(true, b.isAfter(a)); + assertEquals(true, a.isBefore(b)); } else if (year1 > year2) { - assertEquals(a.compareTo(b) > 0, true); - assertEquals(b.compareTo(a) < 0, true); - assertEquals(a.isAfter(b), true); - assertEquals(b.isBefore(a), true); - assertEquals(b.isAfter(a), false); - assertEquals(a.isBefore(b), false); + assertEquals(true, a.compareTo(b) > 0); + assertEquals(true, b.compareTo(a) < 0); + assertEquals(true, a.isAfter(b)); + assertEquals(true, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); } else { if (quarter1.getValue() < quarter2.getValue()) { - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); - assertEquals(a.isAfter(b), false); - assertEquals(b.isBefore(a), false); - assertEquals(b.isAfter(a), true); - assertEquals(a.isBefore(b), true); + assertEquals(true, a.compareTo(b) < 0); + assertEquals(true, b.compareTo(a) > 0); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(true, b.isAfter(a)); + assertEquals(true, a.isBefore(b)); } else if (quarter1.getValue() > quarter2.getValue()) { - assertEquals(a.compareTo(b) > 0, true); - assertEquals(b.compareTo(a) < 0, true); - assertEquals(a.isAfter(b), true); - assertEquals(b.isBefore(a), true); - assertEquals(b.isAfter(a), false); - assertEquals(a.isBefore(b), false); + assertEquals(true, a.compareTo(b) > 0); + assertEquals(true, b.compareTo(a) < 0); + assertEquals(true, a.isAfter(b)); + assertEquals(true, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); } else { - assertEquals(a.compareTo(b), 0); - assertEquals(b.compareTo(a), 0); - assertEquals(a.isAfter(b), false); - assertEquals(b.isBefore(a), false); - assertEquals(b.isAfter(a), false); - assertEquals(a.isBefore(b), false); + assertEquals(0, a.compareTo(b)); + assertEquals(0, b.compareTo(a)); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); } } } @@ -845,56 +965,48 @@ public void test_compareTo() { } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_nullYearQuarter() { - TEST.compareTo(null); + assertThrows(NullPointerException.class, () -> TEST.compareTo(null)); } //----------------------------------------------------------------------- // equals() / hashCode() //----------------------------------------------------------------------- - public void test_equals() { - for (int year1 = -100; year1 < 100; year1++) { - for (Quarter quarter1 : Quarter.values()) { - YearQuarter a = YearQuarter.of(year1, quarter1); - for (int year2 = -100; year2 < 100; year2++) { - for (Quarter quarter2 : Quarter.values()) { - YearQuarter b = YearQuarter.of(year2, quarter2); - if (year1 == year2 && quarter1 == quarter2) { - assertEquals(a, b); - assertEquals(a.hashCode(), b.hashCode()); - } - } - } + @Test + public void test_equals_and_hashCode() { + EqualsTester tester = new EqualsTester(); + for (int year = -100; year <= 100; year++) { + for (Quarter quarter : Quarter.values()) { + YearQuarter instance1 = YearQuarter.of(year, quarter); + YearQuarter instance2 = YearQuarter.of(year, quarter); + tester.addEqualityGroup(instance1, instance2); } } - } - - public void test_equals_nullYearQuarter() { - assertEquals(TEST.equals(null), false); - } - - public void test_equals_incorrectType() { - assertEquals(TEST.equals("Incorrect type"), false); + tester.testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- + @Test public void test_toString() { - assertEquals(YearQuarter.of(2012, Q2).toString(), "2012-Q2"); + assertEquals("2012-Q2", YearQuarter.of(2012, Q2).toString()); } + @Test public void test_toString_bigYear() { - assertEquals(YearQuarter.of(10000, Q2).toString(), "+10000-Q2"); + assertEquals("+10000-Q2", YearQuarter.of(10000, Q2).toString()); } + @Test public void test_toString_negativeYear() { - assertEquals(YearQuarter.of(-1, Q2).toString(), "-0001-Q2"); + assertEquals("-0001-Q2", YearQuarter.of(-1, Q2).toString()); } + @Test public void test_toString_negativeBigYear() { - assertEquals(YearQuarter.of(-10000, Q2).toString(), "-10000-Q2"); + assertEquals("-10000-Q2", YearQuarter.of(-10000, Q2).toString()); } } diff --git a/src/test/java/org/threeten/extra/TestYearWeek.java b/src/test/java/org/threeten/extra/TestYearWeek.java index 443b8764..77a21d39 100644 --- a/src/test/java/org/threeten/extra/TestYearWeek.java +++ b/src/test/java/org/threeten/extra/TestYearWeek.java @@ -68,13 +68,26 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MICROS; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; import static java.time.temporal.IsoFields.DAY_OF_QUARTER; import static java.time.temporal.IsoFields.QUARTER_OF_YEAR; +import static java.time.temporal.IsoFields.QUARTER_YEARS; import static java.time.temporal.IsoFields.WEEK_BASED_YEAR; +import static java.time.temporal.IsoFields.WEEK_BASED_YEARS; import static java.time.temporal.IsoFields.WEEK_OF_WEEK_BASED_YEAR; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -89,6 +102,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.chrono.IsoChronology; @@ -96,25 +110,32 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQueries; +import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junitpioneer.jupiter.RetryingTest; + +import com.google.common.testing.EqualsTester; -@Test public class TestYearWeek { private static final YearWeek TEST_NON_LEAP = YearWeek.of(2014, 1); private static final YearWeek TEST = YearWeek.of(2015, 1); - @DataProvider(name = "sampleYearWeeks") - Object[][] provider_sampleYearWeeks() { + public static Object[][] data_sampleYearWeeks() { return new Object[][]{ {2015, 1}, {2015, 2}, @@ -175,8 +196,7 @@ Object[][] provider_sampleYearWeeks() { }; } - @DataProvider(name = "53WeekYear") - Object[][] provider_53WeekYear() { + public static Object[][] data_53WeekYear() { return new Object[][]{ {4}, {9}, @@ -252,35 +272,49 @@ Object[][] provider_53WeekYear() { }; } - @DataProvider(name = "sampleAtDay") - Object[][] provider_sampleAtDay() { + public static Object[][] data_sampleAtDay() { return new Object[][]{ - {2014, 52, MONDAY, 2014, 12, 22}, - {2014, 52, TUESDAY, 2014, 12, 23}, + {2014, 52, MONDAY, 2014, 12, 22}, + {2014, 52, TUESDAY, 2014, 12, 23}, {2014, 52, WEDNESDAY, 2014, 12, 24}, - {2014, 52, THURSDAY, 2014, 12, 25}, - {2014, 52, FRIDAY, 2014, 12, 26}, - {2014, 52, SATURDAY, 2014, 12, 27}, - {2014, 52, SUNDAY, 2014, 12, 28}, - {2015, 1, MONDAY, 2014, 12, 29}, - {2015, 1, TUESDAY, 2014, 12, 30}, + {2014, 52, THURSDAY, 2014, 12, 25}, + {2014, 52, FRIDAY, 2014, 12, 26}, + {2014, 52, SATURDAY, 2014, 12, 27}, + {2014, 52, SUNDAY, 2014, 12, 28}, + {2015, 1, MONDAY, 2014, 12, 29}, + {2015, 1, TUESDAY, 2014, 12, 30}, {2015, 1, WEDNESDAY, 2014, 12, 31}, - {2015, 1, THURSDAY, 2015, 1, 1}, - {2015, 1, FRIDAY, 2015, 1, 2}, - {2015, 1, SATURDAY, 2015, 1, 3}, - {2015, 1, SUNDAY, 2015, 1, 4}, - {2017, 1, MONDAY, 2017, 1, 2}, - {2017, 1, TUESDAY, 2017, 1, 3}, - {2017, 1, WEDNESDAY, 2017, 1, 4}, - {2017, 1, THURSDAY, 2017, 1, 5}, - {2017, 1, FRIDAY, 2017, 1, 6}, - {2017, 1, SATURDAY, 2017, 1, 7}, - {2017, 1, SUNDAY, 2017, 1, 8}, - {2025, 1, MONDAY, 2024, 12, 30} + {2015, 1, THURSDAY, 2015, 1, 1}, + {2015, 1, FRIDAY, 2015, 1, 2}, + {2015, 1, SATURDAY, 2015, 1, 3}, + {2015, 1, SUNDAY, 2015, 1, 4}, + {2015, 53, FRIDAY, 2016, 1, 1}, + {2015, 53, SATURDAY, 2016, 1, 2}, + {2015, 53, SUNDAY, 2016, 1, 3}, + {2016, 1, MONDAY, 2016, 1, 4}, + {2016, 52, SUNDAY, 2017, 1, 1}, + {2017, 1, MONDAY, 2017, 1, 2}, + {2017, 1, TUESDAY, 2017, 1, 3}, + {2017, 1, WEDNESDAY, 2017, 1, 4}, + {2017, 1, THURSDAY, 2017, 1, 5}, + {2017, 1, FRIDAY, 2017, 1, 6}, + {2017, 1, SATURDAY, 2017, 1, 7}, + {2017, 1, SUNDAY, 2017, 1, 8}, + {2025, 1, MONDAY, 2024, 12, 30}, }; } + public static Object[][] data_outOfBounds() { + return new Object[][] { + {IsoFields.WEEK_OF_WEEK_BASED_YEAR, 54}, + {IsoFields.WEEK_OF_WEEK_BASED_YEAR, 0}, + {IsoFields.WEEK_BASED_YEAR, 1000000000}, + {IsoFields.WEEK_BASED_YEAR, -1000000000}, + }; + } + //----------------------------------------------------------------------- + @Test public void test_interfaces() { assertTrue(Serializable.class.isAssignableFrom(YearWeek.class)); assertTrue(Comparable.class.isAssignableFrom(YearWeek.class)); @@ -288,6 +322,7 @@ public void test_interfaces() { assertTrue(TemporalAccessor.class.isAssignableFrom(YearWeek.class)); } + @Test public void test_serialization() throws IOException, ClassNotFoundException { YearWeek test = YearWeek.of(2015, 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -296,47 +331,29 @@ public void test_serialization() throws IOException, ClassNotFoundException { } ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( baos.toByteArray())); - assertEquals(ois.readObject(), test); + assertEquals(test, ois.readObject()); } //----------------------------------------------------------------------- // now() //----------------------------------------------------------------------- - @Test + @RetryingTest(100) public void test_now() { - YearWeek expected = YearWeek.now(Clock.systemDefaultZone()); - YearWeek test = YearWeek.now(); - for (int i = 0; i < 100; i++) { - if (expected.equals(test)) { - return; - } - expected = YearWeek.now(Clock.systemDefaultZone()); - test = YearWeek.now(); - } - assertEquals(test, expected); + assertEquals(YearWeek.now(Clock.systemDefaultZone()), YearWeek.now()); } //----------------------------------------------------------------------- // now(ZoneId) //----------------------------------------------------------------------- - @Test(expectedExceptions = NullPointerException.class) + @Test public void now_ZoneId_nullZoneId() { - YearWeek.now((ZoneId) null); + assertThrows(NullPointerException.class, () -> YearWeek.now((ZoneId) null)); } - @Test + @RetryingTest(100) public void now_ZoneId() { ZoneId zone = ZoneId.of("UTC+01:02:03"); - YearWeek expected = YearWeek.now(Clock.system(zone)); - YearWeek test = YearWeek.now(zone); - for (int i = 0; i < 100; i++) { - if (expected.equals(test)) { - return; - } - expected = YearWeek.now(Clock.system(zone)); - test = YearWeek.now(zone); - } - assertEquals(test, expected); + assertEquals(YearWeek.now(Clock.system(zone)), YearWeek.now(zone)); } //----------------------------------------------------------------------- @@ -347,110 +364,167 @@ public void now_Clock() { Instant instant = LocalDateTime.of(2010, 12, 31, 0, 0).toInstant(ZoneOffset.UTC); Clock clock = Clock.fixed(instant, ZoneOffset.UTC); YearWeek test = YearWeek.now(clock); - assertEquals(test.getYear(), 2010); - assertEquals(test.getWeek(), 52); + assertEquals(2010, test.getYear()); + assertEquals(52, test.getWeek()); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void now_Clock_nullClock() { - YearWeek.now((Clock) null); + assertThrows(NullPointerException.class, () -> YearWeek.now((Clock) null)); + } + + //----------------------------------------------------------------------- + // of(Year, int) + //----------------------------------------------------------------------- + @ParameterizedTest + @MethodSource("data_sampleYearWeeks") + public void test_of_Year_int(int year, int week) { + YearWeek yearWeek = YearWeek.of(Year.of(year), week); + assertEquals(year, yearWeek.getYear()); + assertEquals(week, yearWeek.getWeek()); + } + + @Test + public void test_carry_Year_int() { + assertTrue(YearWeek.of(Year.of(2014), 53).equals(TEST)); } //----------------------------------------------------------------------- // of(int, int) //----------------------------------------------------------------------- - @Test(dataProvider = "sampleYearWeeks") + @ParameterizedTest + @MethodSource("data_sampleYearWeeks") public void test_of(int year, int week) { YearWeek yearWeek = YearWeek.of(year, week); - assertEquals(yearWeek.getYear(), year); - assertEquals(yearWeek.getWeek(), week); + assertEquals(year, yearWeek.getYear()); + assertEquals(week, yearWeek.getWeek()); } + @Test public void test_carry() { assertTrue(YearWeek.of(2014, 53).equals(TEST)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_year_tooLow() { - YearWeek.of(Integer.MIN_VALUE, 1); + assertThrows(DateTimeException.class, () -> YearWeek.of(Integer.MIN_VALUE, 1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_year_tooHigh() { - YearWeek.of(Integer.MAX_VALUE, 1); + assertThrows(DateTimeException.class, () -> YearWeek.of(Integer.MAX_VALUE, 1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_invalidWeekValue() { - YearWeek.of(2015, 54); + assertThrows(DateTimeException.class, () -> YearWeek.of(2015, 54)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_of_invalidWeekValueZero() { - YearWeek.of(2015, 0); + assertThrows(DateTimeException.class, () -> YearWeek.of(2015, 0)); } //----------------------------------------------------------------------- // isSupported(TemporalField) //----------------------------------------------------------------------- + @Test public void test_isSupported_TemporalField() { - assertEquals(TEST.isSupported((TemporalField) null), false); - assertEquals(TEST.isSupported(NANO_OF_SECOND), false); - assertEquals(TEST.isSupported(NANO_OF_DAY), false); - assertEquals(TEST.isSupported(MICRO_OF_SECOND), false); - assertEquals(TEST.isSupported(MICRO_OF_DAY), false); - assertEquals(TEST.isSupported(MILLI_OF_SECOND), false); - assertEquals(TEST.isSupported(MILLI_OF_DAY), false); - assertEquals(TEST.isSupported(SECOND_OF_MINUTE), false); - assertEquals(TEST.isSupported(SECOND_OF_DAY), false); - assertEquals(TEST.isSupported(MINUTE_OF_HOUR), false); - assertEquals(TEST.isSupported(MINUTE_OF_DAY), false); - assertEquals(TEST.isSupported(HOUR_OF_AMPM), false); - assertEquals(TEST.isSupported(CLOCK_HOUR_OF_AMPM), false); - assertEquals(TEST.isSupported(HOUR_OF_DAY), false); - assertEquals(TEST.isSupported(CLOCK_HOUR_OF_DAY), false); - assertEquals(TEST.isSupported(AMPM_OF_DAY), false); - assertEquals(TEST.isSupported(DAY_OF_WEEK), false); - assertEquals(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH), false); - assertEquals(TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR), false); - assertEquals(TEST.isSupported(DAY_OF_MONTH), false); - assertEquals(TEST.isSupported(DAY_OF_YEAR), false); - assertEquals(TEST.isSupported(EPOCH_DAY), false); - assertEquals(TEST.isSupported(ALIGNED_WEEK_OF_MONTH), false); - assertEquals(TEST.isSupported(ALIGNED_WEEK_OF_YEAR), false); - assertEquals(TEST.isSupported(MONTH_OF_YEAR), false); - assertEquals(TEST.isSupported(PROLEPTIC_MONTH), false); - assertEquals(TEST.isSupported(YEAR_OF_ERA), false); - assertEquals(TEST.isSupported(YEAR), false); - assertEquals(TEST.isSupported(ERA), false); - assertEquals(TEST.isSupported(INSTANT_SECONDS), false); - assertEquals(TEST.isSupported(OFFSET_SECONDS), false); - assertEquals(TEST.isSupported(QUARTER_OF_YEAR), false); - assertEquals(TEST.isSupported(DAY_OF_QUARTER), false); - assertEquals(TEST.isSupported(WEEK_BASED_YEAR), true); - assertEquals(TEST.isSupported(WEEK_OF_WEEK_BASED_YEAR), true); + assertEquals(false, TEST.isSupported((TemporalField) null)); + assertEquals(false, TEST.isSupported(NANO_OF_SECOND)); + assertEquals(false, TEST.isSupported(NANO_OF_DAY)); + assertEquals(false, TEST.isSupported(MICRO_OF_SECOND)); + assertEquals(false, TEST.isSupported(MICRO_OF_DAY)); + assertEquals(false, TEST.isSupported(MILLI_OF_SECOND)); + assertEquals(false, TEST.isSupported(MILLI_OF_DAY)); + assertEquals(false, TEST.isSupported(SECOND_OF_MINUTE)); + assertEquals(false, TEST.isSupported(SECOND_OF_DAY)); + assertEquals(false, TEST.isSupported(MINUTE_OF_HOUR)); + assertEquals(false, TEST.isSupported(MINUTE_OF_DAY)); + assertEquals(false, TEST.isSupported(HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_AMPM)); + assertEquals(false, TEST.isSupported(HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(CLOCK_HOUR_OF_DAY)); + assertEquals(false, TEST.isSupported(AMPM_OF_DAY)); + assertEquals(false, TEST.isSupported(DAY_OF_WEEK)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(false, TEST.isSupported(DAY_OF_MONTH)); + assertEquals(false, TEST.isSupported(DAY_OF_YEAR)); + assertEquals(false, TEST.isSupported(EPOCH_DAY)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_MONTH)); + assertEquals(false, TEST.isSupported(ALIGNED_WEEK_OF_YEAR)); + assertEquals(false, TEST.isSupported(MONTH_OF_YEAR)); + assertEquals(false, TEST.isSupported(PROLEPTIC_MONTH)); + assertEquals(false, TEST.isSupported(YEAR_OF_ERA)); + assertEquals(false, TEST.isSupported(YEAR)); + assertEquals(false, TEST.isSupported(ERA)); + assertEquals(false, TEST.isSupported(INSTANT_SECONDS)); + assertEquals(false, TEST.isSupported(OFFSET_SECONDS)); + assertEquals(false, TEST.isSupported(QUARTER_OF_YEAR)); + assertEquals(false, TEST.isSupported(DAY_OF_QUARTER)); + assertEquals(true, TEST.isSupported(WEEK_BASED_YEAR)); + assertEquals(true, TEST.isSupported(WEEK_OF_WEEK_BASED_YEAR)); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(false, TEST.isSupported((TemporalUnit) null)); + assertEquals(false, TEST.isSupported(NANOS)); + assertEquals(false, TEST.isSupported(MICROS)); + assertEquals(false, TEST.isSupported(MILLIS)); + assertEquals(false, TEST.isSupported(SECONDS)); + assertEquals(false, TEST.isSupported(MINUTES)); + assertEquals(false, TEST.isSupported(HOURS)); + assertEquals(false, TEST.isSupported(DAYS)); + assertEquals(true, TEST.isSupported(WEEKS)); + assertEquals(false, TEST.isSupported(MONTHS)); + assertEquals(false, TEST.isSupported(YEARS)); + assertEquals(false, TEST.isSupported(CENTURIES)); + assertEquals(true, TEST.isSupported(WEEK_BASED_YEARS)); + assertEquals(false, TEST.isSupported(QUARTER_YEARS)); } //----------------------------------------------------------------------- // atDay(DayOfWeek) //----------------------------------------------------------------------- - @Test(dataProvider = "sampleAtDay") + @ParameterizedTest + @MethodSource("data_sampleAtDay") public void test_atDay(int weekBasedYear, int weekOfWeekBasedYear, DayOfWeek dayOfWeek, int year, int month, int dayOfMonth) { YearWeek yearWeek = YearWeek.of(weekBasedYear, weekOfWeekBasedYear); LocalDate expected = LocalDate.of(year, month, dayOfMonth); LocalDate actual = yearWeek.atDay(dayOfWeek); - assertEquals(actual, expected); + assertEquals(expected, actual); } - @Test(expectedExceptions = NullPointerException.class) + @Test + public void test_atDay_loop20years() { + YearWeek yearWeek = YearWeek.of(1998, 51); + LocalDate expected = LocalDate.of(1998, 12, 14); + for (int i = 0; i < (20 * 53); i++) { + for (int j = 1; j <= 7; j++) { + DayOfWeek dow = DayOfWeek.of(j); + LocalDate actual = yearWeek.atDay(dow); + assertEquals(expected, actual); + expected = expected.plusDays(1); + } + yearWeek = yearWeek.plusWeeks(1); + } + } + + @Test public void test_atDay_null() { - TEST.atDay(null); + assertThrows(NullPointerException.class, () -> TEST.atDay(null)); } //----------------------------------------------------------------------- // is53WeekYear() //----------------------------------------------------------------------- - @Test(dataProvider = "53WeekYear") + @ParameterizedTest + @MethodSource("data_53WeekYear") public void test_is53WeekYear(int year) { YearWeek yearWeek = YearWeek.of(year, 1); assertTrue(yearWeek.is53WeekYear()); @@ -459,6 +533,7 @@ public void test_is53WeekYear(int year) { //----------------------------------------------------------------------- // compareTo() //----------------------------------------------------------------------- + @Test public void test_compareTo() { for (int year1 = -100; year1 < 100; year1++) { for (int week1 = 1; week1 < 53; week1++) { @@ -467,41 +542,41 @@ public void test_compareTo() { for (int week2 = 1; week2 < 53; week2++) { YearWeek b = YearWeek.of(year2, week2); if (year1 < year2) { - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); - assertEquals(a.isAfter(b), false); - assertEquals(b.isBefore(a), false); - assertEquals(b.isAfter(a), true); - assertEquals(a.isBefore(b), true); + assertEquals(true, a.compareTo(b) < 0); + assertEquals(true, b.compareTo(a) > 0); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(true, b.isAfter(a)); + assertEquals(true, a.isBefore(b)); } else if (year1 > year2) { - assertEquals(a.compareTo(b) > 0, true); - assertEquals(b.compareTo(a) < 0, true); - assertEquals(a.isAfter(b), true); - assertEquals(b.isBefore(a), true); - assertEquals(b.isAfter(a), false); - assertEquals(a.isBefore(b), false); + assertEquals(true, a.compareTo(b) > 0); + assertEquals(true, b.compareTo(a) < 0); + assertEquals(true, a.isAfter(b)); + assertEquals(true, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); } else { if (week1 < week2) { - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); - assertEquals(a.isAfter(b), false); - assertEquals(b.isBefore(a), false); - assertEquals(b.isAfter(a), true); - assertEquals(a.isBefore(b), true); + assertEquals(true, a.compareTo(b) < 0); + assertEquals(true, b.compareTo(a) > 0); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(true, b.isAfter(a)); + assertEquals(true, a.isBefore(b)); } else if (week1 > week2) { - assertEquals(a.compareTo(b) > 0, true); - assertEquals(b.compareTo(a) < 0, true); - assertEquals(a.isAfter(b), true); - assertEquals(b.isBefore(a), true); - assertEquals(b.isAfter(a), false); - assertEquals(a.isBefore(b), false); + assertEquals(true, a.compareTo(b) > 0); + assertEquals(true, b.compareTo(a) < 0); + assertEquals(true, a.isAfter(b)); + assertEquals(true, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); } else { - assertEquals(a.compareTo(b), 0); - assertEquals(b.compareTo(a), 0); - assertEquals(a.isAfter(b), false); - assertEquals(b.isBefore(a), false); - assertEquals(b.isAfter(a), false); - assertEquals(a.isBefore(b), false); + assertEquals(0, a.compareTo(b)); + assertEquals(0, b.compareTo(a)); + assertEquals(false, a.isAfter(b)); + assertEquals(false, b.isBefore(a)); + assertEquals(false, b.isAfter(a)); + assertEquals(false, a.isBefore(b)); } } } @@ -510,276 +585,501 @@ public void test_compareTo() { } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_nullYearWeek() { - TEST.compareTo(null); + assertThrows(NullPointerException.class, () -> TEST.compareTo(null)); } //----------------------------------------------------------------------- // from(TemporalAccessor) //----------------------------------------------------------------------- - @Test(dataProvider = "sampleAtDay") + @ParameterizedTest + @MethodSource("data_sampleAtDay") public void test_from(int weekBasedYear, int weekOfWeekBasedYear, DayOfWeek dayOfWeek, int year, int month, int dayOfMonth) { YearWeek expected = YearWeek.of(weekBasedYear, weekOfWeekBasedYear); LocalDate ld = LocalDate.of(year, month, dayOfMonth); - assertEquals(YearWeek.from(ld), expected); - assertEquals(YearWeek.from(ThaiBuddhistDate.from(ld)), expected); - assertEquals(YearWeek.from(expected), expected); + assertEquals(expected, YearWeek.from(ld)); + assertEquals(expected, YearWeek.from(ThaiBuddhistDate.from(ld))); + assertEquals(expected, YearWeek.from(expected)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_TemporalAccessor_noDerive() { - YearWeek.from(LocalTime.NOON); + assertThrows(DateTimeException.class, () -> YearWeek.from(LocalTime.NOON)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_TemporalAccessor_null() { - YearWeek.from((TemporalAccessor) null); + assertThrows(NullPointerException.class, () -> YearWeek.from((TemporalAccessor) null)); } //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- + @Test public void test_get() { - assertEquals(TEST.get(WEEK_BASED_YEAR), 2015); - assertEquals(TEST.get(WEEK_OF_WEEK_BASED_YEAR), 1); + assertEquals(2015, TEST.get(WEEK_BASED_YEAR)); + assertEquals(1, TEST.get(WEEK_OF_WEEK_BASED_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_get_invalidField() { - TEST.get(YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.get(YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_get_null() { - TEST.get((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.get((TemporalField) null)); } //----------------------------------------------------------------------- // getLong(TemporalField) //----------------------------------------------------------------------- + @Test public void test_getLong() { - assertEquals(TEST.getLong(WEEK_BASED_YEAR), 2015L); - assertEquals(TEST.getLong(WEEK_OF_WEEK_BASED_YEAR), 1L); + assertEquals(2015L, TEST.getLong(WEEK_BASED_YEAR)); + assertEquals(1L, TEST.getLong(WEEK_OF_WEEK_BASED_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_invalidField() { - TEST.getLong(YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.getLong(YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_getLong_null() { - TEST.getLong((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.getLong((TemporalField) null)); } //----------------------------------------------------------------------- // lengthOfYear() //----------------------------------------------------------------------- + @Test public void test_lengthOfYear() { - assertEquals(YearWeek.of(2014, 1).lengthOfYear(), 364); - assertEquals(YearWeek.of(2015, 1).lengthOfYear(), 371); + assertEquals(364, YearWeek.of(2014, 1).lengthOfYear()); + assertEquals(371, YearWeek.of(2015, 1).lengthOfYear()); + } + + //----------------------------------------------------------------------- + // with(TemporalField, long) + //----------------------------------------------------------------------- + @Test() + public void test_with() { + assertEquals(YearWeek.of(2015, 10), TEST.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 10)); + assertEquals(YearWeek.of(2016, 1), TEST.with(IsoFields.WEEK_BASED_YEAR, 2016)); + } + + @ParameterizedTest + @MethodSource("data_outOfBounds") + public void test_with_outOfBounds(TemporalField field, long newValue) { + assertThrows(DateTimeException.class, () -> TEST.with(field, newValue)); + } + + @Test + public void test_with_TemporalAdjuster_unsupportedType() { + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.with(ChronoField.MONTH_OF_YEAR, 5)); + } + + //----------------------------------------------------------------------- + // with(TemporalAdjuster) + //----------------------------------------------------------------------- + @Test + public void test_with_unsupportedType() { + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.with(TemporalAdjusters.firstDayOfMonth())); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- + @Test public void test_toString() { - assertEquals(TEST.toString(), "2015-W01"); + assertEquals("2015-W01", TEST.toString()); } //----------------------------------------------------------------------- // parse(CharSequence) //----------------------------------------------------------------------- + @Test public void test_parse_CharSequence() { - assertEquals(YearWeek.parse("2015-W01"), TEST); + assertEquals(TEST, YearWeek.parse("2015-W01")); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_parse_CharSequenceDate_invalidYear() { - YearWeek.parse("12345-W7"); + assertThrows(DateTimeParseException.class, () -> YearWeek.parse("12345-W7")); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_parse_CharSequenceDate_invalidWeek() { - YearWeek.parse("2015-W54"); + assertThrows(DateTimeParseException.class, () -> YearWeek.parse("2015-W54")); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequenceDate_nullCharSequence() { - YearWeek.parse((CharSequence) null); + assertThrows(NullPointerException.class, () -> YearWeek.parse((CharSequence) null)); } //----------------------------------------------------------------------- // parse(CharSequence,DateTimeFormatter) //----------------------------------------------------------------------- + @Test public void test_parse_CharSequenceDateTimeFormatter() { DateTimeFormatter f = DateTimeFormatter.ofPattern("E 'W'w YYYY").withLocale(Locale.ENGLISH); - assertEquals(YearWeek.parse("Mon W1 2015", f), TEST); + assertEquals(TEST, YearWeek.parse("Mon W1 2015", f)); } - @Test(expectedExceptions = DateTimeParseException.class) + @Test public void test_parse_CharSequenceDateDateTimeFormatter_invalidWeek() { DateTimeFormatter f = DateTimeFormatter.ofPattern("E 'W'w YYYY").withLocale(Locale.ENGLISH); - YearWeek.parse("Mon W99 2015", f); + assertThrows(DateTimeParseException.class, () -> YearWeek.parse("Mon W99 2015", f)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequenceDateTimeFormatter_nullCharSequence() { DateTimeFormatter f = DateTimeFormatter.ofPattern("E 'W'w YYYY").withLocale(Locale.ENGLISH); - YearWeek.parse((CharSequence) null, f); + assertThrows(NullPointerException.class, () -> YearWeek.parse((CharSequence) null, f)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequenceDateTimeFormatter_nullDateTimeFormatter() { - YearWeek.parse("", (DateTimeFormatter) null); + assertThrows(NullPointerException.class, () -> YearWeek.parse("", (DateTimeFormatter) null)); } //----------------------------------------------------------------------- // format() //----------------------------------------------------------------------- + @Test public void test_format() { DateTimeFormatter f = new DateTimeFormatterBuilder() - .appendValue(WEEK_BASED_YEAR, 4) - .appendLiteral('-') - .appendValue(WEEK_OF_WEEK_BASED_YEAR, 2) - .toFormatter(); - assertEquals(TEST.format(f), "2015-01"); + .appendValue(WEEK_BASED_YEAR, 4) + .appendLiteral('-') + .appendValue(WEEK_OF_WEEK_BASED_YEAR, 2) + .toFormatter(); + assertEquals("2015-01", TEST.format(f)); } //----------------------------------------------------------------------- // adjustInto() //----------------------------------------------------------------------- + @Test public void test_adjustInto() { YearWeek yw = YearWeek.of(2016, 1); LocalDate date = LocalDate.of(2015, 6, 20); - assertEquals(yw.adjustInto(date), LocalDate.of(2016, 1, 9)); + assertEquals(LocalDate.of(2016, 1, 9), yw.adjustInto(date)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjustInto_badChronology() { YearWeek yw = YearWeek.of(2016, 1); ThaiBuddhistDate date = ThaiBuddhistDate.from(LocalDate.of(2015, 6, 20)); - yw.adjustInto(date); + assertThrows(DateTimeException.class, () -> yw.adjustInto(date)); + } + + //----------------------------------------------------------------------- + // until(Temporal, TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_until_weeks() { + assertEquals(1, TEST.until(YearWeek.of(2015, 2), ChronoUnit.WEEKS)); + assertEquals(2, TEST.until(YearWeek.of(2015, 3), ChronoUnit.WEEKS)); + assertEquals(52, TEST_NON_LEAP.until(TEST, ChronoUnit.WEEKS)); + assertEquals(53, TEST.until(YearWeek.of(2016, 1), ChronoUnit.WEEKS)); + } + + @Test + public void test_until_years() { + assertEquals(1, TEST.until(YearWeek.of(2016, 1), IsoFields.WEEK_BASED_YEARS)); + assertEquals(-1, TEST.until(YearWeek.of(2014, 1), IsoFields.WEEK_BASED_YEARS)); + assertEquals(0, TEST.until(YearWeek.of(2015, 53), IsoFields.WEEK_BASED_YEARS)); + assertEquals(0, YearWeek.of(2015, 10).until(YearWeek.of(2015, 5), IsoFields.WEEK_BASED_YEARS)); + assertEquals(0, YearWeek.of(2015, 10).until(YearWeek.of(2016, 5), IsoFields.WEEK_BASED_YEARS)); + assertEquals(0, TEST.until(YearWeek.of(2014, 2), IsoFields.WEEK_BASED_YEARS)); + assertEquals(-1, TEST.until(YearWeek.of(2013, 2), IsoFields.WEEK_BASED_YEARS)); + } + + @Test + public void test_until_unsupportedType() { + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.until(YearWeek.of(2016, 1), ChronoUnit.MONTHS)); } //----------------------------------------------------------------------- // range(TemporalField) //----------------------------------------------------------------------- + @Test public void test_range() { - assertEquals(TEST_NON_LEAP.range(WEEK_BASED_YEAR), WEEK_BASED_YEAR.range()); - assertEquals(TEST.range(WEEK_BASED_YEAR), WEEK_BASED_YEAR.range()); + assertEquals(WEEK_BASED_YEAR.range(), TEST_NON_LEAP.range(WEEK_BASED_YEAR)); + assertEquals(WEEK_BASED_YEAR.range(), TEST.range(WEEK_BASED_YEAR)); - assertEquals(TEST_NON_LEAP.range(WEEK_OF_WEEK_BASED_YEAR), ValueRange.of(1, 52)); - assertEquals(TEST.range(WEEK_OF_WEEK_BASED_YEAR), ValueRange.of(1, 53)); + assertEquals(ValueRange.of(1, 52), TEST_NON_LEAP.range(WEEK_OF_WEEK_BASED_YEAR)); + assertEquals(ValueRange.of(1, 53), TEST.range(WEEK_OF_WEEK_BASED_YEAR)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_invalidField() { - TEST.range(YEAR); + assertThrows(UnsupportedTemporalTypeException.class, () -> TEST.range(YEAR)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_range_null() { - TEST.range((TemporalField) null); + assertThrows(NullPointerException.class, () -> TEST.range((TemporalField) null)); } //----------------------------------------------------------------------- // withYear(int) //----------------------------------------------------------------------- + @Test public void test_withYear() { - assertEquals(YearWeek.of(2015, 1).withYear(2014), YearWeek.of(2014, 1)); - assertEquals(YearWeek.of(2015, 53).withYear(2009), YearWeek.of(2009, 53)); + assertEquals(YearWeek.of(2014, 1), YearWeek.of(2015, 1).withYear(2014)); + assertEquals(YearWeek.of(2009, 53), YearWeek.of(2015, 53).withYear(2009)); } + @Test public void test_withYear_sameYear() { - assertEquals(YearWeek.of(2015, 1).withYear(2015), YearWeek.of(2015, 1)); + assertEquals(YearWeek.of(2015, 1), YearWeek.of(2015, 1).withYear(2015)); } + @Test public void test_withYear_resolve() { - assertEquals(YearWeek.of(2015, 53).withYear(2014), YearWeek.of(2014, 52)); + assertEquals(YearWeek.of(2014, 52), YearWeek.of(2015, 53).withYear(2014)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withYear_int_max() { - TEST.withYear(Integer.MAX_VALUE); + assertThrows(DateTimeException.class, () -> TEST.withYear(Integer.MAX_VALUE)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withYear_int_min() { - TEST.withYear(Integer.MIN_VALUE); + assertThrows(DateTimeException.class, () -> TEST.withYear(Integer.MIN_VALUE)); + } + + //----------------------------------------------------------------------- + // plus(int, TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_plus() { + assertEquals(YearWeek.of(2015, 2), TEST.plus(1, ChronoUnit.WEEKS)); + assertEquals(YearWeek.of(2016, 1), TEST.plus(1, IsoFields.WEEK_BASED_YEARS)); + } + + @Test + public void test_plus_unsupportedType() { + assertThrows(UnsupportedTemporalTypeException.class, () -> YearWeek.of(2014, 1).plus(1, ChronoUnit.DAYS)); + } + + //----------------------------------------------------------------------- + // plus(TemporalAmount) + //----------------------------------------------------------------------- + @Test + public void test_plus_TemporalAmount() { + assertEquals(YearWeek.of(2015, 2), TEST.plus(Weeks.of(1))); } //----------------------------------------------------------------------- // withWeek(int) //----------------------------------------------------------------------- + @Test public void test_withWeek() { - assertEquals(TEST.withWeek(52), YearWeek.of(2015, 52)); - assertEquals(YearWeek.of(2014, 1).withWeek(53), TEST); + assertEquals(YearWeek.of(2015, 52), TEST.withWeek(52)); + assertEquals(TEST, YearWeek.of(2014, 1).withWeek(53)); } + @Test public void test_withWeek_sameWeek() { - assertEquals(YearWeek.of(2014, 2).withWeek(2), YearWeek.of(2014, 2)); + assertEquals(YearWeek.of(2014, 2), YearWeek.of(2014, 2).withWeek(2)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withWeek_int_max() { - TEST.withWeek(Integer.MAX_VALUE); + assertThrows(DateTimeException.class, () -> TEST.withWeek(Integer.MAX_VALUE)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_withWeek_int_min() { - TEST.withWeek(Integer.MIN_VALUE); + assertThrows(DateTimeException.class, () -> TEST.withWeek(Integer.MIN_VALUE)); } //----------------------------------------------------------------------- - // query(TemporalQuery) + // plusYears(long) //----------------------------------------------------------------------- @Test - public void test_query() { - assertEquals(TEST.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); - assertEquals(TEST.query(TemporalQueries.localDate()), null); - assertEquals(TEST.query(TemporalQueries.localTime()), null); - assertEquals(TEST.query(TemporalQueries.offset()), null); - assertEquals(TEST.query(TemporalQueries.precision()), null); - assertEquals(TEST.query(TemporalQueries.zone()), null); - assertEquals(TEST.query(TemporalQueries.zoneId()), null); + public void test_plusYears() { + assertEquals(YearWeek.of(2013, 1), TEST.plusYears(-2)); + assertEquals(YearWeek.of(2014, 1), TEST.plusYears(-1)); + assertEquals(TEST, TEST.plusYears(0)); + assertEquals(YearWeek.of(2016, 1), TEST.plusYears(1)); + assertEquals(YearWeek.of(2017, 1), TEST.plusYears(2)); + } + + @Test + public void test_plusYears_changeWeek() { + assertEquals(YearWeek.of(2014, 52), YearWeek.of(2015, 53).plusYears(-1)); + assertEquals(YearWeek.of(2015, 53), YearWeek.of(2015, 53).plusYears(0)); + assertEquals(YearWeek.of(2016, 52), YearWeek.of(2015, 53).plusYears(1)); + assertEquals(YearWeek.of(2020, 53), YearWeek.of(2015, 53).plusYears(5)); + } + + @Test + public void test_plusYears_max_long() { + assertThrows(ArithmeticException.class, () -> TEST.plusYears(Long.MAX_VALUE)); + } + + @Test + public void test_plusYears_min_long() { + assertThrows(ArithmeticException.class, () -> TEST.plusYears(Long.MIN_VALUE)); } //----------------------------------------------------------------------- - // equals() / hashCode() + // plusWeeks(long) //----------------------------------------------------------------------- - @Test(dataProvider = "sampleYearWeeks") - public void test_equalsAndHashCodeContract(int year, int week) { - YearWeek a = YearWeek.of(year, week); - YearWeek b = YearWeek.of(year, week); - assertTrue(a.equals(b)); - assertTrue(b.equals(a)); - assertTrue(a.hashCode() == b.hashCode()); + @Test + public void test_plusWeeks() { + assertEquals(TEST, TEST.plusWeeks(0)); + assertEquals(YearWeek.of(2015, 2), TEST.plusWeeks(1)); + assertEquals(YearWeek.of(2015, 3), TEST.plusWeeks(2)); + assertEquals(YearWeek.of(2015, 52), TEST.plusWeeks(51)); + assertEquals(YearWeek.of(2015, 53), TEST.plusWeeks(52)); + assertEquals(YearWeek.of(2016, 1), TEST.plusWeeks(53)); + assertEquals(YearWeek.of(2021, 1), TEST.plusWeeks(314)); } - public void test_equals() { - YearWeek a = YearWeek.of(2015, 4); - YearWeek b = YearWeek.of(2015, 6); - YearWeek c = YearWeek.of(2016, 6); - assertFalse(a.equals(b)); - assertFalse(a.equals(c)); - assertFalse(b.equals(a)); - assertFalse(b.equals(c)); - assertFalse(c.equals(a)); - assertFalse(c.equals(b)); + @Test + public void test_plusWeeks_negative() { + assertEquals(TEST, TEST.plusWeeks(0)); + assertEquals(YearWeek.of(2014, 52), TEST.plusWeeks(-1)); + assertEquals(YearWeek.of(2014, 51), TEST.plusWeeks(-2)); + assertEquals(YearWeek.of(2014, 2), TEST.plusWeeks(-51)); + assertEquals(YearWeek.of(2014, 1), TEST.plusWeeks(-52)); + assertEquals(YearWeek.of(2013, 52), TEST.plusWeeks(-53)); + assertEquals(YearWeek.of(2009, 53), TEST.plusWeeks(-261)); } - public void test_equals_incorrectType() { - assertTrue(TEST.equals(null) == false); - assertEquals(TEST.equals("Incorrect type"), false); + @Test + public void test_plusWeeks_max_long() { + assertThrows(ArithmeticException.class, () -> TEST.plusWeeks(Long.MAX_VALUE)); + } + + @Test + public void test_plusWeeks_min_long() { + assertThrows(ArithmeticException.class, () -> TEST.plusWeeks(Long.MIN_VALUE)); + } + + //----------------------------------------------------------------------- + // minus(int, TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_minus() { + assertEquals(YearWeek.of(2014, 1), YearWeek.of(2014, 2).minus(1, ChronoUnit.WEEKS)); + } + + @Test + public void test_minus_overflow() { + assertThrows(ArithmeticException.class, () -> TEST.minus(Long.MIN_VALUE, ChronoUnit.WEEKS)); + } + + //----------------------------------------------------------------------- + // minus(TemporalAmount) + //----------------------------------------------------------------------- + @Test + public void test_minus_TemporalAmount() { + assertEquals(YearWeek.of(2014, 1), YearWeek.of(2014, 2).minus(Weeks.of(1))); + } + + //----------------------------------------------------------------------- + // minusYears(long) + //----------------------------------------------------------------------- + @Test + public void test_minusYears() { + assertEquals(YearWeek.of(2017, 1), TEST.minusYears(-2)); + assertEquals(YearWeek.of(2016, 1), TEST.minusYears(-1)); + assertEquals(TEST, TEST.minusYears(0)); + assertEquals(YearWeek.of(2014, 1), TEST.minusYears(1)); + assertEquals(YearWeek.of(2013, 1), TEST.minusYears(2)); + } + + @Test + public void test_minusYears_changeWeek() { + assertEquals(YearWeek.of(2020, 53), YearWeek.of(2015, 53).minusYears(-5)); + assertEquals(YearWeek.of(2016, 52), YearWeek.of(2015, 53).minusYears(-1)); + assertEquals(YearWeek.of(2015, 53), YearWeek.of(2015, 53).minusYears(0)); + assertEquals(YearWeek.of(2014, 52), YearWeek.of(2015, 53).minusYears(1)); + } + + @Test + public void test_minusYears_max_long() { + assertThrows(ArithmeticException.class, () -> TEST.minusYears(Long.MAX_VALUE)); + } + + @Test + public void test_minusYears_min_long() { + assertThrows(ArithmeticException.class, () -> TEST.minusYears(Long.MIN_VALUE)); + } + + //----------------------------------------------------------------------- + // minusWeeks(long) + //----------------------------------------------------------------------- + @Test + public void test_minusWeeks() { + assertEquals(TEST, TEST.minusWeeks(0)); + assertEquals(YearWeek.of(2014, 52), TEST.minusWeeks(1)); + assertEquals(YearWeek.of(2014, 51), TEST.minusWeeks(2)); + assertEquals(YearWeek.of(2014, 2), TEST.minusWeeks(51)); + assertEquals(YearWeek.of(2014, 1), TEST.minusWeeks(52)); + assertEquals(YearWeek.of(2013, 52), TEST.minusWeeks(53)); + assertEquals(YearWeek.of(2009, 53), TEST.minusWeeks(261)); + } + + @Test + public void test_minusWeeks_negative() { + assertEquals(TEST, TEST.minusWeeks(0)); + assertEquals(YearWeek.of(2015, 2), TEST.minusWeeks(-1)); + assertEquals(YearWeek.of(2015, 3), TEST.minusWeeks(-2)); + assertEquals(YearWeek.of(2015, 52), TEST.minusWeeks(-51)); + assertEquals(YearWeek.of(2015, 53), TEST.minusWeeks(-52)); + assertEquals(YearWeek.of(2016, 1), TEST.minusWeeks(-53)); + assertEquals(YearWeek.of(2021, 1), TEST.minusWeeks(-314)); + } + + @Test + public void test_minWeeks_max_long() { + assertThrows(ArithmeticException.class, () -> TEST.plusWeeks(Long.MAX_VALUE)); + } + + @Test + public void test_minWeeks_min_long() { + assertThrows(ArithmeticException.class, () -> TEST.plusWeeks(Long.MIN_VALUE)); + } + + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @Test + public void test_query() { + assertEquals(IsoChronology.INSTANCE, TEST.query(TemporalQueries.chronology())); + assertEquals(null, TEST.query(TemporalQueries.localDate())); + assertEquals(null, TEST.query(TemporalQueries.localTime())); + assertEquals(null, TEST.query(TemporalQueries.offset())); + assertEquals(null, TEST.query(TemporalQueries.precision())); + assertEquals(null, TEST.query(TemporalQueries.zone())); + assertEquals(null, TEST.query(TemporalQueries.zoneId())); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(YearWeek.of(2015, 4), YearWeek.of(2015, 4)) + .addEqualityGroup(YearWeek.of(2015, 6), YearWeek.of(2015, 6)) + .addEqualityGroup(YearWeek.of(2016, 6), YearWeek.of(2016, 6)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "sampleToString") - Object[][] provider_sampleToString() { + public static Object[][] data_sampleToString() { return new Object[][]{ {2015, 1, "2015-W01"}, {2015, 10, "2015-W10"}, @@ -789,11 +1089,12 @@ Object[][] provider_sampleToString() { {-10000, 1, "-10000-W01"},}; } - @Test(dataProvider = "sampleToString") + @ParameterizedTest + @MethodSource("data_sampleToString") public void test_toString(int year, int week, String expected) { YearWeek yearWeek = YearWeek.of(year, week); String s = yearWeek.toString(); - assertEquals(s, expected); + assertEquals(expected, s); } } diff --git a/src/test/java/org/threeten/extra/TestYears.java b/src/test/java/org/threeten/extra/TestYears.java index 6d57d6b9..5a324447 100644 --- a/src/test/java/org/threeten/extra/TestYears.java +++ b/src/test/java/org/threeten/extra/TestYears.java @@ -31,9 +31,11 @@ */ package org.threeten.extra; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -42,109 +44,138 @@ import java.io.Serializable; import java.time.DateTimeException; import java.time.Duration; +import java.time.LocalDate; import java.time.Period; import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAmount; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test class. */ -@Test public class TestYears { //----------------------------------------------------------------------- + @Test public void test_isSerializable() { assertTrue(Serializable.class.isAssignableFrom(Years.class)); } //----------------------------------------------------------------------- + @Test public void test_deserializationSingleton() throws Exception { - Years orginal = Years.ZERO; + Years test = Years.ZERO; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Years ser = (Years) in.readObject(); - assertSame(Years.ZERO, ser); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } } //----------------------------------------------------------------------- + @Test public void test_ZERO() { - assertSame(Years.of(0), Years.ZERO); - assertSame(Years.of(0), Years.ZERO); - assertEquals(Years.ZERO.getAmount(), 0); + assertSame(Years.ZERO, Years.of(0)); + assertEquals(Years.ZERO, Years.of(0)); + assertEquals(0, Years.ZERO.getAmount()); + assertFalse(Years.ZERO.isNegative()); + assertTrue(Years.ZERO.isZero()); + assertFalse(Years.ZERO.isPositive()); } + @Test public void test_ONE() { - assertSame(Years.of(1), Years.ONE); - assertSame(Years.of(1), Years.ONE); - assertEquals(Years.ONE.getAmount(), 1); + assertSame(Years.ONE, Years.of(1)); + assertEquals(Years.ONE, Years.of(1)); + assertEquals(1, Years.ONE.getAmount()); + assertFalse(Years.ONE.isNegative()); + assertFalse(Years.ONE.isZero()); + assertTrue(Years.ONE.isPositive()); } //----------------------------------------------------------------------- + @Test public void test_of() { - assertEquals(Years.of(1).getAmount(), 1); - assertEquals(Years.of(2).getAmount(), 2); - assertEquals(Years.of(Integer.MAX_VALUE).getAmount(), Integer.MAX_VALUE); - assertEquals(Years.of(-1).getAmount(), -1); - assertEquals(Years.of(-2).getAmount(), -2); - assertEquals(Years.of(Integer.MIN_VALUE).getAmount(), Integer.MIN_VALUE); + assertEquals(1, Years.of(1).getAmount()); + assertEquals(2, Years.of(2).getAmount()); + assertEquals(Integer.MAX_VALUE, Years.of(Integer.MAX_VALUE).getAmount()); + assertEquals(-1, Years.of(-1).getAmount()); + assertEquals(-2, Years.of(-2).getAmount()); + assertEquals(Integer.MIN_VALUE, Years.of(Integer.MIN_VALUE).getAmount()); + } + + @Test + public void test_ofMinusOne() { + assertEquals(-1, Years.of(-1).getAmount()); + assertTrue(Years.of(-1).isNegative()); + assertFalse(Years.of(-1).isZero()); + assertFalse(Years.of(-1).isPositive()); } //----------------------------------------------------------------------- + @Test public void test_from_P0Y() { - assertEquals(Years.from(Period.ofYears(0)), Years.of(0)); + assertEquals(Years.of(0), Years.from(Period.ofYears(0))); } + @Test public void test_from_P2Y() { - assertEquals(Years.from(Period.ofYears(2)), Years.of(2)); + assertEquals(Years.of(2), Years.from(Period.ofYears(2))); } + @Test public void test_from_P24M() { - assertEquals(Years.from(Period.ofMonths(24)), Years.of(2)); + assertEquals(Years.of(2), Years.from(Period.ofMonths(24))); } + @Test public void test_from_yearsAndMonths() { - assertEquals(Years.from(Period.of(3, 24, 0)), Years.of(5)); + assertEquals(Years.of(5), Years.from(Period.of(3, 24, 0))); } + @Test public void test_from_decadesAndMonths() { - assertEquals(Years.from(new MockDecadesMonths(2, -12)), Years.of(19)); + assertEquals(Years.of(19), Years.from(new MockDecadesMonths(2, -12))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_wrongUnit_remainder() { - Years.from(Period.ofMonths(3)); + assertThrows(DateTimeException.class, () -> Years.from(Period.ofMonths(3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_from_wrongUnit_noConversion() { - Years.from(Period.ofDays(2)); + assertThrows(DateTimeException.class, () -> Years.from(Period.ofDays(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_from_null() { - Years.from((TemporalAmount) null); + assertThrows(NullPointerException.class, () -> Years.from((TemporalAmount) null)); } //----------------------------------------------------------------------- + @Test public void test_parse_CharSequence() { - assertEquals(Years.parse("P0Y"), Years.of(0)); - assertEquals(Years.parse("P1Y"), Years.of(1)); - assertEquals(Years.parse("P2Y"), Years.of(2)); - assertEquals(Years.parse("P123456789Y"), Years.of(123456789)); - assertEquals(Years.parse("P-2Y"), Years.of(-2)); - assertEquals(Years.parse("-P2Y"), Years.of(-2)); - assertEquals(Years.parse("-P-2Y"), Years.of(2)); + assertEquals(Years.of(0), Years.parse("P0Y")); + assertEquals(Years.of(1), Years.parse("P1Y")); + assertEquals(Years.of(2), Years.parse("P2Y")); + assertEquals(Years.of(123456789), Years.parse("P123456789Y")); + assertEquals(Years.of(-2), Years.parse("P-2Y")); + assertEquals(Years.of(-2), Years.parse("-P2Y")); + assertEquals(Years.of(2), Years.parse("-P-2Y")); } - @DataProvider(name = "parseInvalid") - Object[][] data_invalid() { + public static Object[][] data_invalid() { return new Object[][] { {"P3M"}, {"P3W"}, @@ -160,17 +191,46 @@ Object[][] data_invalid() { }; } - @Test(expectedExceptions = DateTimeParseException.class, dataProvider = "parseInvalid") + @ParameterizedTest + @MethodSource("data_invalid") public void test_parse_CharSequence_invalid(String str) { - Years.parse(str); + assertThrows(DateTimeParseException.class, () -> Years.parse(str)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_parse_CharSequence_null() { - Years.parse((CharSequence) null); + assertThrows(NullPointerException.class, () -> Years.parse((CharSequence) null)); + } + + //----------------------------------------------------------------------- + @Test + public void test_between() { + assertEquals(Years.of(2), Years.between(LocalDate.of(2019, 1, 1), LocalDate.of(2021, 1, 1))); + } + + @Test + public void test_between_date_null() { + assertThrows(NullPointerException.class, () -> Years.between(LocalDate.now(), (Temporal) null)); + } + + @Test + public void test_between_null_date() { + assertThrows(NullPointerException.class, () -> Years.between((Temporal) null, LocalDate.now())); } //----------------------------------------------------------------------- + @Test + public void test_get() { + assertEquals(6, Years.of(6).get(ChronoUnit.YEARS)); + } + + @Test + public void test_get_invalidType() { + assertThrows(DateTimeException.class, () -> Years.of(6).get(IsoFields.QUARTER_YEARS)); + } + + //----------------------------------------------------------------------- + @Test public void test_plus_TemporalAmount_Years() { Years test5 = Years.of(5); assertEquals(Years.of(5), test5.plus(Years.of(0))); @@ -180,6 +240,7 @@ public void test_plus_TemporalAmount_Years() { assertEquals(Years.of(Integer.MIN_VALUE), Years.of(Integer.MIN_VALUE + 1).plus(Years.of(-1))); } + @Test public void test_plus_TemporalAmount_Period() { Years test5 = Years.of(5); assertEquals(Years.of(5), test5.plus(Period.ofYears(0))); @@ -189,32 +250,33 @@ public void test_plus_TemporalAmount_Period() { assertEquals(Years.of(Integer.MIN_VALUE), Years.of(Integer.MIN_VALUE + 1).plus(Period.ofYears(-1))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_TemporalAmount_PeriodMonths() { - Years.of(1).plus(Period.ofMonths(2)); + assertThrows(DateTimeException.class, () -> Years.of(1).plus(Period.ofMonths(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_TemporalAmount_Duration() { - Years.of(1).plus(Duration.ofHours(2)); + assertThrows(DateTimeException.class, () -> Years.of(1).plus(Duration.ofHours(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooBig() { - Years.of(Integer.MAX_VALUE - 1).plus(Years.of(2)); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MAX_VALUE - 1).plus(Years.of(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_TemporalAmount_overflowTooSmall() { - Years.of(Integer.MIN_VALUE + 1).plus(Years.of(-2)); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MIN_VALUE + 1).plus(Years.of(-2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_plus_TemporalAmount_null() { - Years.of(Integer.MIN_VALUE + 1).plus(null); + assertThrows(NullPointerException.class, () -> Years.of(Integer.MIN_VALUE + 1).plus(null)); } //----------------------------------------------------------------------- + @Test public void test_plus_int() { Years test5 = Years.of(5); assertEquals(Years.of(5), test5.plus(0)); @@ -224,17 +286,18 @@ public void test_plus_int() { assertEquals(Years.of(Integer.MIN_VALUE), Years.of(Integer.MIN_VALUE + 1).plus(-1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooBig() { - Years.of(Integer.MAX_VALUE - 1).plus(2); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MAX_VALUE - 1).plus(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_int_overflowTooSmall() { - Years.of(Integer.MIN_VALUE + 1).plus(-2); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MIN_VALUE + 1).plus(-2)); } //----------------------------------------------------------------------- + @Test public void test_minus_TemporalAmount_Years() { Years test5 = Years.of(5); assertEquals(Years.of(5), test5.minus(Years.of(0))); @@ -244,6 +307,7 @@ public void test_minus_TemporalAmount_Years() { assertEquals(Years.of(Integer.MIN_VALUE), Years.of(Integer.MIN_VALUE + 1).minus(Years.of(1))); } + @Test public void test_minus_TemporalAmount_Period() { Years test5 = Years.of(5); assertEquals(Years.of(5), test5.minus(Period.ofYears(0))); @@ -253,32 +317,33 @@ public void test_minus_TemporalAmount_Period() { assertEquals(Years.of(Integer.MIN_VALUE), Years.of(Integer.MIN_VALUE + 1).minus(Period.ofYears(1))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_TemporalAmount_PeriodMonths() { - Years.of(1).minus(Period.ofMonths(2)); + assertThrows(DateTimeException.class, () -> Years.of(1).minus(Period.ofMonths(2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_TemporalAmount_Duration() { - Years.of(1).minus(Duration.ofHours(2)); + assertThrows(DateTimeException.class, () -> Years.of(1).minus(Duration.ofHours(2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooBig() { - Years.of(Integer.MAX_VALUE - 1).minus(Years.of(-2)); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MAX_VALUE - 1).minus(Years.of(-2))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_TemporalAmount_overflowTooSmall() { - Years.of(Integer.MIN_VALUE + 1).minus(Years.of(2)); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MIN_VALUE + 1).minus(Years.of(2))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_minus_TemporalAmount_null() { - Years.of(Integer.MIN_VALUE + 1).minus(null); + assertThrows(NullPointerException.class, () -> Years.of(Integer.MIN_VALUE + 1).minus(null)); } //----------------------------------------------------------------------- + @Test public void test_minus_int() { Years test5 = Years.of(5); assertEquals(Years.of(5), test5.minus(0)); @@ -288,17 +353,18 @@ public void test_minus_int() { assertEquals(Years.of(Integer.MIN_VALUE), Years.of(Integer.MIN_VALUE + 1).minus(1)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooBig() { - Years.of(Integer.MAX_VALUE - 1).minus(-2); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MAX_VALUE - 1).minus(-2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_int_overflowTooSmall() { - Years.of(Integer.MIN_VALUE + 1).minus(2); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MIN_VALUE + 1).minus(2)); } //----------------------------------------------------------------------- + @Test public void test_multipliedBy() { Years test5 = Years.of(5); assertEquals(Years.of(0), test5.multipliedBy(0)); @@ -308,22 +374,24 @@ public void test_multipliedBy() { assertEquals(Years.of(-15), test5.multipliedBy(-3)); } + @Test public void test_multipliedBy_negate() { Years test5 = Years.of(5); assertEquals(Years.of(-15), test5.multipliedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooBig() { - Years.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MAX_VALUE / 2 + 1).multipliedBy(2)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_multipliedBy_overflowTooSmall() { - Years.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MIN_VALUE / 2 - 1).multipliedBy(2)); } //----------------------------------------------------------------------- + @Test public void test_dividedBy() { Years test12 = Years.of(12); assertEquals(Years.of(12), test12.dividedBy(1)); @@ -335,17 +403,19 @@ public void test_dividedBy() { assertEquals(Years.of(-4), test12.dividedBy(-3)); } + @Test public void test_dividedBy_negate() { Years test12 = Years.of(12); assertEquals(Years.of(-4), test12.dividedBy(-3)); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_dividedBy_divideByZero() { - Years.of(1).dividedBy(0); + assertThrows(ArithmeticException.class, () -> Years.of(1).dividedBy(0)); } //----------------------------------------------------------------------- + @Test public void test_negated() { assertEquals(Years.of(0), Years.of(0).negated()); assertEquals(Years.of(-12), Years.of(12).negated()); @@ -353,12 +423,13 @@ public void test_negated() { assertEquals(Years.of(-Integer.MAX_VALUE), Years.of(Integer.MAX_VALUE).negated()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_negated_overflow() { - Years.of(Integer.MIN_VALUE).negated(); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MIN_VALUE).negated()); } //----------------------------------------------------------------------- + @Test public void test_abs() { assertEquals(Years.of(0), Years.of(0).abs()); assertEquals(Years.of(12), Years.of(12).abs()); @@ -367,19 +438,34 @@ public void test_abs() { assertEquals(Years.of(Integer.MAX_VALUE), Years.of(-Integer.MAX_VALUE).abs()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_abs_overflow() { - Years.of(Integer.MIN_VALUE).abs(); + assertThrows(ArithmeticException.class, () -> Years.of(Integer.MIN_VALUE).abs()); } //----------------------------------------------------------------------- + @Test + public void test_addTo() { + assertEquals(LocalDate.of(2019, 1, 10), Years.of(0).addTo(LocalDate.of(2019, 1, 10))); + assertEquals(LocalDate.of(2024, 1, 10), Years.of(5).addTo(LocalDate.of(2019, 1, 10))); + } + + @Test + public void test_subtractFrom() { + assertEquals(LocalDate.of(2019, 1, 10), Years.of(0).subtractFrom(LocalDate.of(2019, 1, 10))); + assertEquals(LocalDate.of(2014, 1, 10), Years.of(5).subtractFrom(LocalDate.of(2019, 1, 10))); + } + + //----------------------------------------------------------------------- + @Test public void test_toPeriod() { for (int i = -20; i < 20; i++) { - assertEquals(Years.of(i).toPeriod(), Period.ofYears(i)); + assertEquals(Period.ofYears(i), Years.of(i).toPeriod()); } } //----------------------------------------------------------------------- + @Test public void test_compareTo() { Years test5 = Years.of(5); Years test6 = Years.of(6); @@ -388,40 +474,23 @@ public void test_compareTo() { assertEquals(1, test6.compareTo(test5)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_null() { Years test5 = Years.of(5); - test5.compareTo(null); + assertThrows(NullPointerException.class, () -> test5.compareTo(null)); } //----------------------------------------------------------------------- - public void test_equals() { - Years test5 = Years.of(5); - Years test6 = Years.of(6); - assertEquals(true, test5.equals(test5)); - assertEquals(false, test5.equals(test6)); - assertEquals(false, test6.equals(test5)); - } - - public void test_equals_null() { - Years test5 = Years.of(5); - assertEquals(false, test5.equals(null)); - } - - public void test_equals_otherClass() { - Years test5 = Years.of(5); - assertEquals(false, test5.equals("")); - } - - //----------------------------------------------------------------------- - public void test_hashCode() { - Years test5 = Years.of(5); - Years test6 = Years.of(6); - assertEquals(true, test5.hashCode() == test5.hashCode()); - assertEquals(false, test5.hashCode() == test6.hashCode()); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Years.of(0), Years.of(0)) + .addEqualityGroup(Years.of(1), Years.of(1)) + .testEquals(); } //----------------------------------------------------------------------- + @Test public void test_toString() { Years test5 = Years.of(5); assertEquals("P5Y", test5.toString()); diff --git a/src/test/java/org/threeten/extra/chrono/TestAccountingChronology.java b/src/test/java/org/threeten/extra/chrono/TestAccountingChronology.java index df613bf1..6fb07d47 100644 --- a/src/test/java/org/threeten/extra/chrono/TestAccountingChronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestAccountingChronology.java @@ -53,7 +53,8 @@ import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.time.DateTimeException; import java.time.DayOfWeek; @@ -63,7 +64,6 @@ import java.time.Period; import java.time.chrono.Era; import java.time.chrono.IsoEra; -import java.time.temporal.IsoFields; import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; @@ -71,16 +71,17 @@ import java.time.temporal.ValueRange; import java.time.temporal.WeekFields; import java.util.List; -import java.util.function.Predicate; +import java.util.function.IntPredicate; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test public class TestAccountingChronology { private static AccountingChronology INSTANCE = new AccountingChronologyBuilder().endsOn(DayOfWeek.SUNDAY).nearestEndOf(Month.AUGUST). @@ -91,19 +92,18 @@ public class TestAccountingChronology { //----------------------------------------------------------------------- @Test public void test_chronology_of_name() { - Assert.assertEquals(INSTANCE.getId(), "Accounting"); + assertEquals("Accounting", INSTANCE.getId()); } @Test public void test_chronology_of_name_id() { - Assert.assertEquals(INSTANCE.getCalendarType(), null); + assertEquals(null, INSTANCE.getCalendarType()); } //----------------------------------------------------------------------- // creation, toLocalDate() //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { {INSTANCE.date(1, 1, 1), LocalDate.of(0, 9, 4)}, {INSTANCE.date(1, 1, 2), LocalDate.of(0, 9, 5)}, @@ -138,74 +138,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_AccountingDate(AccountingDate accounting, LocalDate iso) { - assertEquals(LocalDate.from(accounting), iso); + assertEquals(iso, LocalDate.from(accounting)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_AccountingDate_from_LocalDate(AccountingDate accounting, LocalDate iso) { - assertEquals(AccountingDate.from(INSTANCE, iso), accounting); + assertEquals(accounting, AccountingDate.from(INSTANCE, iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_AccountingDate_chronology_dateEpochDay(AccountingDate accounting, LocalDate iso) { - assertEquals(INSTANCE.dateEpochDay(iso.toEpochDay()), accounting); + assertEquals(accounting, INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_AccountingDate_toEpochDay(AccountingDate accounting, LocalDate iso) { - assertEquals(accounting.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), accounting.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_AccountingDate_until_CoptiDate(AccountingDate accounting, LocalDate iso) { - assertEquals(accounting.until(accounting), INSTANCE.period(0, 0, 0)); + assertEquals(INSTANCE.period(0, 0, 0), accounting.until(accounting)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_AccountingDate_until_LocalDate(AccountingDate accounting, LocalDate iso) { - assertEquals(accounting.until(iso), INSTANCE.period(0, 0, 0)); + assertEquals(INSTANCE.period(0, 0, 0), accounting.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_CoptiDate(AccountingDate accounting, LocalDate iso) { - assertEquals(iso.until(accounting), Period.ZERO); + assertEquals(Period.ZERO, iso.until(accounting)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(AccountingDate accounting, LocalDate iso) { - assertEquals(INSTANCE.date(iso), accounting); + assertEquals(accounting, INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(AccountingDate accounting, LocalDate iso) { - assertEquals(LocalDate.from(accounting.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(accounting.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(accounting.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(accounting.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(accounting.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(accounting.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(accounting.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(accounting.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(accounting.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(accounting.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(AccountingDate accounting, LocalDate iso) { - assertEquals(LocalDate.from(accounting.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(accounting.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(accounting.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(accounting.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(accounting.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(accounting.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(accounting.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(accounting.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(accounting.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(accounting.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(AccountingDate accounting, LocalDate iso) { - assertEquals(accounting.until(iso.plusDays(0), DAYS), 0); - assertEquals(accounting.until(iso.plusDays(1), DAYS), 1); - assertEquals(accounting.until(iso.plusDays(35), DAYS), 35); - assertEquals(accounting.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, accounting.until(iso.plusDays(0), DAYS)); + assertEquals(1, accounting.until(iso.plusDays(1), DAYS)); + assertEquals(35, accounting.until(iso.plusDays(35), DAYS)); + assertEquals(-40, accounting.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {2012, 0, 0}, @@ -247,44 +257,45 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - INSTANCE.date(year, month, dom); + assertThrows(DateTimeException.class, () -> INSTANCE.date(year, month, dom)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_chronology_dateYearDay_badDate() { - INSTANCE.dateYearDay(2001, 366); + assertThrows(DateTimeException.class, () -> INSTANCE.dateYearDay(2001, 366)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_date_create_no_chronology() { - AccountingDate.create(null, 2012, 1, 1); + assertThrows(NullPointerException.class, () -> AccountingDate.create(null, 2012, 1, 1)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_date_from_no_chronology() { - AccountingDate.from(null, LocalDate.of(2012, 1, 1)); + assertThrows(NullPointerException.class, () -> AccountingDate.from(null, LocalDate.of(2012, 1, 1))); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_date_now_no_chronology() { - AccountingDate.now(null); + assertThrows(NullPointerException.class, () -> AccountingDate.now(null)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_date_of_no_chronology() { - AccountingDate.of(null, 2012, 1, 1); + assertThrows(NullPointerException.class, () -> AccountingDate.of(null, 2012, 1, 1)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_date_ofEpochDay_no_chronology() { - AccountingDate.ofEpochDay(null, 0); + assertThrows(NullPointerException.class, () -> AccountingDate.ofEpochDay(null, 0)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_date_ofYearDay_no_chronology() { - AccountingDate.ofYearDay(null, 0, 1); + assertThrows(NullPointerException.class, () -> AccountingDate.ofYearDay(null, 0, 1)); } //----------------------------------------------------------------------- @@ -292,39 +303,38 @@ public void test_date_ofYearDay_no_chronology() { //----------------------------------------------------------------------- @Test public void test_isLeapYear_loop() { - Predicate isLeapYear = year -> { + IntPredicate isLeapYear = year -> { LocalDate currentYearEnd = LocalDate.of(year, 9, 3).with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY)); LocalDate prevYearEnd = LocalDate.of(year - 1, 9, 3).with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY)); return prevYearEnd.until(currentYearEnd, DAYS) == 371; }; for (int year = -200; year < 200; year++) { AccountingDate base = INSTANCE.date(year, 1, 1); - assertEquals(base.isLeapYear(), isLeapYear.test(year)); - assertEquals(INSTANCE.isLeapYear(year), isLeapYear.test(year)); + assertEquals(isLeapYear.test(year), base.isLeapYear()); + assertEquals(isLeapYear.test(year), INSTANCE.isLeapYear(year)); } } @Test public void test_isLeapYear_specific() { - assertEquals(INSTANCE.isLeapYear(8), false); - assertEquals(INSTANCE.isLeapYear(7), false); - assertEquals(INSTANCE.isLeapYear(6), true); - assertEquals(INSTANCE.isLeapYear(5), false); - assertEquals(INSTANCE.isLeapYear(4), false); - assertEquals(INSTANCE.isLeapYear(3), false); - assertEquals(INSTANCE.isLeapYear(2), false); - assertEquals(INSTANCE.isLeapYear(1), false); - assertEquals(INSTANCE.isLeapYear(0), true); - assertEquals(INSTANCE.isLeapYear(-1), false); - assertEquals(INSTANCE.isLeapYear(-2), false); - assertEquals(INSTANCE.isLeapYear(-3), false); - assertEquals(INSTANCE.isLeapYear(-4), false); - assertEquals(INSTANCE.isLeapYear(-5), true); - assertEquals(INSTANCE.isLeapYear(-6), false); - } - - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + assertEquals(false, INSTANCE.isLeapYear(8)); + assertEquals(false, INSTANCE.isLeapYear(7)); + assertEquals(true, INSTANCE.isLeapYear(6)); + assertEquals(false, INSTANCE.isLeapYear(5)); + assertEquals(false, INSTANCE.isLeapYear(4)); + assertEquals(false, INSTANCE.isLeapYear(3)); + assertEquals(false, INSTANCE.isLeapYear(2)); + assertEquals(false, INSTANCE.isLeapYear(1)); + assertEquals(true, INSTANCE.isLeapYear(0)); + assertEquals(false, INSTANCE.isLeapYear(-1)); + assertEquals(false, INSTANCE.isLeapYear(-2)); + assertEquals(false, INSTANCE.isLeapYear(-3)); + assertEquals(false, INSTANCE.isLeapYear(-4)); + assertEquals(true, INSTANCE.isLeapYear(-5)); + assertEquals(false, INSTANCE.isLeapYear(-6)); + } + + public static Object[][] data_lengthOfMonth() { return new Object[][] { {2012, 1, 28}, {2012, 2, 28}, @@ -347,9 +357,10 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int length) { - assertEquals(INSTANCE.date(year, month, 1).lengthOfMonth(), length); + assertEquals(length, INSTANCE.date(year, month, 1).lengthOfMonth()); } //----------------------------------------------------------------------- @@ -365,7 +376,7 @@ public void test_era_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); AccountingDate eraBased = INSTANCE.date(era, yoe, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -379,44 +390,44 @@ public void test_era_yearDay_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); AccountingDate eraBased = INSTANCE.dateYearDay(era, yoe, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(INSTANCE.prolepticYear(AccountingEra.CE, 4), 4); - assertEquals(INSTANCE.prolepticYear(AccountingEra.CE, 3), 3); - assertEquals(INSTANCE.prolepticYear(AccountingEra.CE, 2), 2); - assertEquals(INSTANCE.prolepticYear(AccountingEra.CE, 1), 1); - assertEquals(INSTANCE.prolepticYear(AccountingEra.BCE, 1), 0); - assertEquals(INSTANCE.prolepticYear(AccountingEra.BCE, 2), -1); - assertEquals(INSTANCE.prolepticYear(AccountingEra.BCE, 3), -2); - assertEquals(INSTANCE.prolepticYear(AccountingEra.BCE, 4), -3); + assertEquals(4, INSTANCE.prolepticYear(AccountingEra.CE, 4)); + assertEquals(3, INSTANCE.prolepticYear(AccountingEra.CE, 3)); + assertEquals(2, INSTANCE.prolepticYear(AccountingEra.CE, 2)); + assertEquals(1, INSTANCE.prolepticYear(AccountingEra.CE, 1)); + assertEquals(0, INSTANCE.prolepticYear(AccountingEra.BCE, 1)); + assertEquals(-1, INSTANCE.prolepticYear(AccountingEra.BCE, 2)); + assertEquals(-2, INSTANCE.prolepticYear(AccountingEra.BCE, 3)); + assertEquals(-3, INSTANCE.prolepticYear(AccountingEra.BCE, 4)); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void test_prolepticYear_badEra() { - INSTANCE.prolepticYear(IsoEra.CE, 4); + assertThrows(ClassCastException.class, () -> INSTANCE.prolepticYear(IsoEra.CE, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(INSTANCE.eraOf(1), AccountingEra.CE); - assertEquals(INSTANCE.eraOf(0), AccountingEra.BCE); + assertEquals(AccountingEra.CE, INSTANCE.eraOf(1)); + assertEquals(AccountingEra.BCE, INSTANCE.eraOf(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - INSTANCE.eraOf(2); + assertThrows(DateTimeException.class, () -> INSTANCE.eraOf(2)); } @Test public void test_Chronology_eras() { List eras = INSTANCE.eras(); - assertEquals(eras.size(), 2); - assertEquals(eras.contains(AccountingEra.BCE), true); - assertEquals(eras.contains(AccountingEra.CE), true); + assertEquals(2, eras.size()); + assertEquals(true, eras.contains(AccountingEra.BCE)); + assertEquals(true, eras.contains(AccountingEra.CE)); } //----------------------------------------------------------------------- @@ -424,18 +435,17 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(INSTANCE.range(DAY_OF_WEEK), ValueRange.of(1, 7)); - assertEquals(INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 28, 35)); - assertEquals(INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 364, 371)); - assertEquals(INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 13)); - assertEquals(INSTANCE.range(ALIGNED_WEEK_OF_YEAR), ValueRange.of(1, 52, 53)); + assertEquals(ValueRange.of(1, 7), INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 28, 35), INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 364, 371), INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(1, 13), INSTANCE.range(MONTH_OF_YEAR)); + assertEquals(ValueRange.of(1, 52, 53), INSTANCE.range(ALIGNED_WEEK_OF_YEAR)); } //----------------------------------------------------------------------- // AccountingDate.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { {2012, 1, 23, DAY_OF_MONTH, 1, 28}, {2012, 2, 23, DAY_OF_MONTH, 1, 28}, @@ -458,26 +468,24 @@ Object[][] data_ranges() { {2011, 13, 23, DAY_OF_MONTH, 1, 28}, {2011, 13, 23, DAY_OF_YEAR, 1, 364}, {2011, 13, 23, ALIGNED_WEEK_OF_MONTH, 1, 4}, - - {2011, 2, 23, IsoFields.QUARTER_OF_YEAR, 1, 4}, }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, int expectedMin, int expectedMax) { - assertEquals(INSTANCE.date(year, month, dom).range(field), ValueRange.of(expectedMin, expectedMax)); + assertEquals(ValueRange.of(expectedMin, expectedMax), INSTANCE.date(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - INSTANCE.date(2012, 6, 28).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> INSTANCE.date(2012, 6, 28).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // AccountingDate.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 5}, {2014, 5, 26, DAY_OF_MONTH, 26}, @@ -497,21 +505,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(INSTANCE.date(year, month, dom).getLong(field), expected); + assertEquals(expected, INSTANCE.date(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - INSTANCE.date(2012, 6, 28).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> INSTANCE.date(2012, 6, 28).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // AccountingDate.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 3, 2014, 5, 24}, {2014, 5, 26, DAY_OF_WEEK, 5, 2014, 5, 26}, @@ -548,16 +556,17 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(INSTANCE.date(year, month, dom).with(field, value), INSTANCE.date(expectedYear, expectedMonth, expectedDom)); + assertEquals(INSTANCE.date(expectedYear, expectedMonth, expectedDom), INSTANCE.date(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - INSTANCE.date(2012, 6, 28).with(MINUTE_OF_DAY, 0); + assertThrows(UnsupportedTemporalTypeException.class, () -> INSTANCE.date(2012, 6, 28).with(MINUTE_OF_DAY, 0)); } //----------------------------------------------------------------------- @@ -567,14 +576,14 @@ public void test_with_TemporalField_unsupported() { public void test_adjust1() { AccountingDate base = INSTANCE.date(2012, 6, 23); AccountingDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, INSTANCE.date(2012, 6, 28)); + assertEquals(INSTANCE.date(2012, 6, 28), test); } @Test public void test_adjust2() { AccountingDate base = INSTANCE.date(2012, 13, 23); AccountingDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, INSTANCE.date(2012, 13, 35)); + assertEquals(INSTANCE.date(2012, 13, 35), test); } //----------------------------------------------------------------------- @@ -584,13 +593,13 @@ public void test_adjust2() { public void test_adjust_toLocalDate() { AccountingDate accounting = INSTANCE.date(2000, 1, 4); AccountingDate test = accounting.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, INSTANCE.date(2012, 12, 5)); + assertEquals(INSTANCE.date(2012, 12, 5), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { AccountingDate accounting = INSTANCE.date(2000, 1, 4); - accounting.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> accounting.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -600,21 +609,20 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToAccountingDate() { AccountingDate accounting = INSTANCE.date(2012, 6, 23); LocalDate test = LocalDate.MIN.with(accounting); - assertEquals(test, LocalDate.of(2012, 2, 7)); + assertEquals(LocalDate.of(2012, 2, 7), test); } @Test public void test_LocalDateTime_adjustToAccountingDate() { AccountingDate accounting = INSTANCE.date(2012, 6, 23); LocalDateTime test = LocalDateTime.MIN.with(accounting); - assertEquals(test, LocalDateTime.of(2012, 2, 7, 0, 0)); + assertEquals(LocalDateTime.of(2012, 2, 7, 0, 0), test); } //----------------------------------------------------------------------- // AccountingDate.plus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {2014, 5, 26, 0, DAYS, 2014, 5, 26}, {2014, 5, 26, 8, DAYS, 2014, 6, 6}, @@ -641,31 +649,32 @@ Object[][] data_plus() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(INSTANCE.date(year, month, dom).plus(amount, unit), INSTANCE.date(expectedYear, expectedMonth, expectedDom)); + assertEquals(INSTANCE.date(expectedYear, expectedMonth, expectedDom), INSTANCE.date(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(INSTANCE.date(year, month, dom).minus(amount, unit), INSTANCE.date(expectedYear, expectedMonth, expectedDom)); + assertEquals(INSTANCE.date(expectedYear, expectedMonth, expectedDom), INSTANCE.date(year, month, dom).minus(amount, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - INSTANCE.date(2012, 6, 28).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> INSTANCE.date(2012, 6, 28).plus(0, MINUTES)); } //----------------------------------------------------------------------- // AccountingDate.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, DAYS, 0}, {2014, 5, 26, 2014, 6, 4, DAYS, 6}, @@ -693,88 +702,89 @@ Object[][] data_until() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { AccountingDate start = INSTANCE.date(year1, month1, dom1); AccountingDate end = INSTANCE.date(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { AccountingDate start = INSTANCE.date(2012, 6, 28); AccountingDate end = INSTANCE.date(2012, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(INSTANCE.date(2014, 5, 26).plus(INSTANCE.period(0, 2, 3)), INSTANCE.date(2014, 8, 1)); + assertEquals(INSTANCE.date(2014, 8, 1), INSTANCE.date(2014, 5, 26).plus(INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(INSTANCE.date(2014, 5, 26).plus(Period.ofMonths(2)), INSTANCE.date(2014, 7, 26)); + assertThrows(DateTimeException.class, () -> INSTANCE.date(2014, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(INSTANCE.date(2014, 5, 26).minus(INSTANCE.period(0, 2, 3)), INSTANCE.date(2014, 3, 23)); + assertEquals(INSTANCE.date(2014, 3, 23), INSTANCE.date(2014, 5, 26).minus(INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(INSTANCE.date(2014, 5, 26).minus(Period.ofMonths(2)), INSTANCE.date(2014, 3, 26)); + assertThrows(DateTimeException.class, () -> INSTANCE.date(2014, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - void test_equals() { - AccountingDate a1 = INSTANCE.date(2000, 1, 3); - AccountingDate a2 = INSTANCE.date(2000, 1, 3); - AccountingDate b = INSTANCE.date(2000, 1, 4); - AccountingDate c = INSTANCE.date(2000, 2, 3); - AccountingDate d = INSTANCE.date(2001, 1, 3); - - AccountingDate other = new AccountingChronologyBuilder().endsOn(DayOfWeek.WEDNESDAY) - .nearestEndOf(Month.AUGUST).leapWeekInMonth(13) - .withDivision(AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS) - .toChronology().date(2000, 1, 3); - - assertEquals(a1.equals(a1), true); - assertEquals(a1.equals(a2), true); - assertEquals(a1.equals(b), false); - assertEquals(a1.equals(c), false); - assertEquals(a1.equals(d), false); - - assertEquals(a1.equals(null), false); - assertEquals(a1.equals(""), false); - assertEquals(a1.getChronology().equals(other.getChronology()), false); - assertEquals(a1.equals(other), false); - - assertEquals(a1.hashCode(), a2.hashCode()); + public void test_equals_and_hashCode() { + AccountingChronology other = new AccountingChronologyBuilder() + .endsOn(DayOfWeek.WEDNESDAY) + .nearestEndOf(Month.AUGUST) + .leapWeekInMonth(13) + .withDivision(AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS) + .accountingYearEndsInIsoYear() + .toChronology(); + new EqualsTester() + .addEqualityGroup(INSTANCE.date(2000, 1, 3), INSTANCE.date(2000, 1, 3)) + .addEqualityGroup(INSTANCE.date(2000, 1, 4), INSTANCE.date(2000, 1, 4)) + .addEqualityGroup(INSTANCE.date(2000, 2, 3), INSTANCE.date(2000, 2, 3)) + .addEqualityGroup(INSTANCE.date(2001, 1, 3), INSTANCE.date(2001, 1, 3)) + .addEqualityGroup(other.date(2000, 1, 3), other.date(2000, 1, 3)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { + AccountingChronology other = new AccountingChronologyBuilder().endsOn(DayOfWeek.SUNDAY).nearestEndOf(Month.AUGUST). + withDivision(AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS).leapWeekInMonth(13).accountingYearStartsInIsoYear().toChronology(); + return new Object[][] { - {INSTANCE.date(1, 1, 1), "Accounting calendar ends on SUNDAY nearest end of AUGUST, year divided in THIRTEEN_EVEN_MONTHS_OF_4_WEEKS with leap-week in month 13 CE 1-01-01"}, - {INSTANCE.date(2012, 6, 23), "Accounting calendar ends on SUNDAY nearest end of AUGUST, year divided in THIRTEEN_EVEN_MONTHS_OF_4_WEEKS with leap-week in month 13 CE 2012-06-23"}, + { INSTANCE.date(1, 1, 1), + "Accounting calendar ends on SUNDAY nearest end of AUGUST, year divided in THIRTEEN_EVEN_MONTHS_OF_4_WEEKS with leap-week in month 13 ending in the given ISO year CE 1-01-01" }, + { INSTANCE.date(2012, 6, 23), + "Accounting calendar ends on SUNDAY nearest end of AUGUST, year divided in THIRTEEN_EVEN_MONTHS_OF_4_WEEKS with leap-week in month 13 ending in the given ISO year CE 2012-06-23" }, + { other.date(1, 1, 1), + "Accounting calendar ends on SUNDAY nearest end of AUGUST, year divided in THIRTEEN_EVEN_MONTHS_OF_4_WEEKS with leap-week in month 13 starting in the given ISO year CE 1-01-01" }, + { other.date(2012, 6, 23), + "Accounting calendar ends on SUNDAY nearest end of AUGUST, year divided in THIRTEEN_EVEN_MONTHS_OF_4_WEEKS with leap-week in month 13 starting in the given ISO year CE 2012-06-23" }, }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(AccountingDate accounting, String expected) { - assertEquals(accounting.toString(), expected); + assertEquals(expected, accounting.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestAccountingChronologyBuilder.java b/src/test/java/org/threeten/extra/chrono/TestAccountingChronologyBuilder.java index 586cd081..ffe08ce9 100644 --- a/src/test/java/org/threeten/extra/chrono/TestAccountingChronologyBuilder.java +++ b/src/test/java/org/threeten/extra/chrono/TestAccountingChronologyBuilder.java @@ -32,7 +32,10 @@ package org.threeten.extra.chrono; import static java.time.temporal.ChronoUnit.DAYS; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.params.provider.Arguments.arguments; import java.time.DateTimeException; import java.time.DayOfWeek; @@ -41,422 +44,422 @@ import java.time.temporal.ChronoField; import java.time.temporal.TemporalAdjusters; import java.time.temporal.ValueRange; +import java.util.Arrays; +import java.util.function.BiFunction; +import java.util.function.IntBinaryOperator; import java.util.function.IntFunction; -import java.util.function.Predicate; +import java.util.function.IntPredicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.collect.Lists; +import com.google.common.collect.Streams; /** * Test. */ -@Test public class TestAccountingChronologyBuilder { - - //----------------------------------------------------------------------- - // isLeapYear(), date(int, int, int) - //----------------------------------------------------------------------- - @DataProvider(name = "yearEnding") - Object[][] data_yearEnding() { - return new Object[][] { - {DayOfWeek.MONDAY, Month.JANUARY}, - {DayOfWeek.TUESDAY, Month.MARCH}, - {DayOfWeek.WEDNESDAY, Month.APRIL}, - {DayOfWeek.THURSDAY, Month.MAY}, - {DayOfWeek.FRIDAY, Month.JUNE}, - {DayOfWeek.SATURDAY, Month.JULY}, - {DayOfWeek.SUNDAY, Month.AUGUST}, - {DayOfWeek.MONDAY, Month.SEPTEMBER}, - {DayOfWeek.TUESDAY, Month.OCTOBER}, - {DayOfWeek.WEDNESDAY, Month.NOVEMBER}, - {DayOfWeek.THURSDAY, Month.DECEMBER}, - - {DayOfWeek.MONDAY, Month.FEBRUARY}, - {DayOfWeek.TUESDAY, Month.FEBRUARY}, - {DayOfWeek.WEDNESDAY, Month.FEBRUARY}, - {DayOfWeek.THURSDAY, Month.FEBRUARY}, - {DayOfWeek.FRIDAY, Month.FEBRUARY}, - {DayOfWeek.SATURDAY, Month.FEBRUARY}, - {DayOfWeek.SUNDAY, Month.FEBRUARY}, - }; + @FunctionalInterface + private interface GetYearEnd { + LocalDate apply(int year, Month ending, DayOfWeek dayOfWeek); } - @Test(dataProvider = "yearEnding") - public void test_isLeapYear_inLastWeekOf(DayOfWeek dayOfWeek, Month ending) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(dayOfWeek).inLastWeekOf(ending) - .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS).leapWeekInMonth(12) - .toChronology(); - - IntFunction getYearEnd = year -> { - return LocalDate.of(year, ending, 1).with(TemporalAdjusters.lastDayOfMonth()).with(TemporalAdjusters.previousOrSame(dayOfWeek)); - }; - Predicate isLeapYear = year -> { - LocalDate currentYearEnd = getYearEnd.apply(year); - LocalDate prevYearEnd = getYearEnd.apply(year - 1); - return prevYearEnd.until(currentYearEnd, DAYS) == 371; - }; - - for (int year = -200; year < 600; year++) { - assertEquals(chronology.isLeapYear(year), isLeapYear.test(year), "Fails on " + year); - } + // ----------------------------------------------------------------------- + // isLeapYear(), date(int, int, int) + // ----------------------------------------------------------------------- + public static Stream data_yearEnding() { + return Lists.cartesianProduct( + Lists.newArrayList(DayOfWeek.values()), + Lists.newArrayList(Month.values()), + Lists.newArrayList(new Object[] { + (BiFunction) AccountingChronologyBuilder::inLastWeekOf, + (GetYearEnd) ((year, ending, dayOfWeek) -> LocalDate.of(year, ending, 1) + .with(TemporalAdjusters.lastDayOfMonth()) + .with(TemporalAdjusters.previousOrSame(dayOfWeek))) + }, new Object[] { + (BiFunction) AccountingChronologyBuilder::nearestEndOf, + (GetYearEnd) ((year, ending, dayOfWeek) -> LocalDate.of(year, ending, 3).plusMonths(1) + .with(TemporalAdjusters.previousOrSame(dayOfWeek))) + }), + Lists.newArrayList( + (Object) new Object[] { (UnaryOperator) AccountingChronologyBuilder::accountingYearEndsInIsoYear, 0}, + (Object) new Object[] { (UnaryOperator) AccountingChronologyBuilder::accountingYearStartsInIsoYear, 1} + )) + .stream().map( + (args) -> { + DayOfWeek dayOfWeek = (DayOfWeek) args.get(0); + Month ending = (Month) args.get(1); + BiFunction endingType = + (BiFunction) ((Object[]) args.get(2))[0]; + GetYearEnd getYearEnd = (GetYearEnd) ((Object[]) args.get(2))[1]; + UnaryOperator startOrEnd = (UnaryOperator) ((Object[]) args.get(3))[0]; + int offset = (int) ((Object[]) args.get(3))[1]; + + AccountingChronology chrono = endingType.andThen(startOrEnd).apply(new AccountingChronologyBuilder(), ending) + .endsOn(dayOfWeek) + .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS) + .leapWeekInMonth(12) + .toChronology(); + + IntFunction offsetYearEnd = (int year) -> getYearEnd.apply(year + offset, ending, dayOfWeek); + + IntPredicate isLeapYear = year -> { + LocalDate currentYearEnd = offsetYearEnd.apply(year); + LocalDate prevYearEnd = offsetYearEnd.apply(year - 1); + return prevYearEnd.until(currentYearEnd, DAYS) == 371; + }; + + return arguments(chrono, offsetYearEnd, isLeapYear); + + }); } - @Test(dataProvider = "yearEnding") - public void test_isLeapYear_nearestEndOf(DayOfWeek dayOfWeek, Month ending) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(dayOfWeek).nearestEndOf(ending) - .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS).leapWeekInMonth(12) - .toChronology(); - - IntFunction getYearEnd = year -> { - return LocalDate.of(year, ending, 3).plusMonths(1).with(TemporalAdjusters.previousOrSame(dayOfWeek)); - }; - Predicate isLeapYear = year -> { - LocalDate currentYearEnd = getYearEnd.apply(year); - LocalDate prevYearEnd = getYearEnd.apply(year - 1); - return prevYearEnd.until(currentYearEnd, DAYS) == 371; - }; - - for (int year = -200; year < 600; year++) { - assertEquals(chronology.isLeapYear(year), isLeapYear.test(year), "Fails on " + year); - } + @ParameterizedTest + @MethodSource("data_yearEnding") + public void test_isLeapYear(AccountingChronology chronology, IntFunction _getYearEnd, IntPredicate isLeapYear) { + assertAll(IntStream.range(-200, 600).mapToObj( + year -> () -> assertEquals(isLeapYear.test(year), chronology.isLeapYear(year), + () -> String.format("for year %d ", year)))); } - @Test(dataProvider = "yearEnding") - public void test_previousLeapYears_inLastWeekOf(DayOfWeek dayOfWeek, Month ending) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(dayOfWeek).inLastWeekOf(ending) - .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS).leapWeekInMonth(12) - .toChronology(); - - IntFunction getYearEnd = year -> { - return LocalDate.of(year, ending, 1).with(TemporalAdjusters.lastDayOfMonth()).with(TemporalAdjusters.previousOrSame(dayOfWeek)); - }; - Predicate isLeapYear = year -> { - LocalDate currentYearEnd = getYearEnd.apply(year); - LocalDate prevYearEnd = getYearEnd.apply(year - 1); - return prevYearEnd.until(currentYearEnd, DAYS) == 371; - }; - + @ParameterizedTest + @MethodSource("data_yearEnding") + public void test_previousLeapYears(AccountingChronology chronology, IntFunction _getYearEnd, IntPredicate isLeapYear) { for (int year = 1, leapYears = 0; year < 600; year++) { if (year != 1 && isLeapYear.test(year - 1)) { leapYears++; } - assertEquals(chronology.previousLeapYears(year), leapYears, "Fails on " + year); + final int loopYear = year; + assertEquals(leapYears, chronology.previousLeapYears(year), () -> String.format("for year %d ", loopYear)); } for (int year = 1, leapYears = 0; year >= -200; year--) { if (year != 1 && isLeapYear.test(year)) { leapYears--; } - assertEquals(chronology.previousLeapYears(year), leapYears, "Fails on " + year); + final int loopYear = year; + assertEquals(leapYears, chronology.previousLeapYears(year), () -> String.format("for year %d ", loopYear)); } } - @Test(dataProvider = "yearEnding") - public void test_previousLeapYears_nearestEndOf(DayOfWeek dayOfWeek, Month ending) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(dayOfWeek).nearestEndOf(ending) - .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS).leapWeekInMonth(12) - .toChronology(); - - IntFunction getYearEnd = year -> { - return LocalDate.of(year, ending, 3).plusMonths(1).with(TemporalAdjusters.previousOrSame(dayOfWeek)); - }; - Predicate isLeapYear = year -> { - LocalDate currentYearEnd = getYearEnd.apply(year); - LocalDate prevYearEnd = getYearEnd.apply(year - 1); - return prevYearEnd.until(currentYearEnd, DAYS) == 371; - }; - - for (int year = 1, leapYears = 0; year < 600; year++) { - if (year != 1 && isLeapYear.test(year - 1)) { - leapYears++; - } - assertEquals(chronology.previousLeapYears(year), leapYears, "Fails on " + year); - } - for (int year = 1, leapYears = 0; year >= -200; year--) { - if (year != 1 && isLeapYear.test(year)) { - leapYears--; - } - assertEquals(chronology.previousLeapYears(year), leapYears, "Fails on " + year); - } + @ParameterizedTest + @MethodSource("data_yearEnding") + public void test_date_int_int_int(AccountingChronology chronology, IntFunction getYearEnd, IntPredicate isLeapYear) { + assertAll(IntStream.range(-200, 600).mapToObj( + year -> () -> assertEquals(getYearEnd.apply(year - 1).plusDays(1).toEpochDay(), + chronology.date(year, 1, 1).toEpochDay(), + () -> String.format("for year %d ", year)))); } - @Test(dataProvider = "yearEnding") - public void test_date_int_int_int_inLastWeekOf(DayOfWeek dayOfWeek, Month ending) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(dayOfWeek).inLastWeekOf(ending) - .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS).leapWeekInMonth(12) - .toChronology(); - - IntFunction getYearEnd = year -> { - return LocalDate.of(year, ending, 1).with(TemporalAdjusters.lastDayOfMonth()).with(TemporalAdjusters.previousOrSame(dayOfWeek)); - }; - - for (int year = -200; year < 600; year++) { - assertEquals(chronology.date(year, 1, 1).toEpochDay(), getYearEnd.apply(year - 1).plusDays(1).toEpochDay()); - } + // ----------------------------------------------------------------------- + // range(MONTH_OF_YEAR), range(DAY_OF_MONTH) + // ----------------------------------------------------------------------- + public static Stream data_range() { + IntBinaryOperator weeksInMonth = (leapWeekInMonth, offset) -> (leapWeekInMonth + offset) % 3 == 0 ? 6 : 5; + + Stream pattern_4_4_5 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> new Object[] { + AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, + leapWeekInMonth, + ValueRange.of(1, 4, weeksInMonth.applyAsInt(leapWeekInMonth, 0)), + ValueRange.of(1, 7 * 4, 7 * weeksInMonth.applyAsInt(leapWeekInMonth, 0)), + ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11) }); + + Stream pattern_4_5_4 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> new Object[] { + AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, + leapWeekInMonth, + ValueRange.of(1, 4, weeksInMonth.applyAsInt(leapWeekInMonth, 1)), + ValueRange.of(1, 7 * 4, 7 * weeksInMonth.applyAsInt(leapWeekInMonth, 1)), + ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11) }); + + Stream pattern_5_4_4 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> new Object[] { + AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, + leapWeekInMonth, + ValueRange.of(1, 4, weeksInMonth.applyAsInt(leapWeekInMonth, 2)), + ValueRange.of(1, 7 * 4, 7 * weeksInMonth.applyAsInt(leapWeekInMonth, 2)), + ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11) }); + + Stream pattern_even_13 = IntStream.range(1, 14) + .mapToObj((leapWeekInMonth) -> new Object[] { + AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, + leapWeekInMonth, + ValueRange.of(1, 4, 5), + ValueRange.of(1, 7 * 4, 7 * 5), + ValueRange.of(1, 13), ValueRange.of(-999_999 * 13L, 999_999 * 13L + 12) }); + + return Lists.cartesianProduct( + Streams.concat(pattern_4_4_5, pattern_4_5_4, pattern_5_4_4, pattern_even_13) + .collect(Collectors.toList()), + Lists.newArrayList( + (UnaryOperator) AccountingChronologyBuilder::accountingYearEndsInIsoYear, + (UnaryOperator) AccountingChronologyBuilder::accountingYearStartsInIsoYear + )) + .stream().map(args -> { + AccountingYearDivision division = (AccountingYearDivision) ((Object[]) args.get(0))[0]; + int leapWeekInMonth = (int) ((Object[]) args.get(0))[1]; + ValueRange expectedWeekOfMonthRange = (ValueRange) ((Object[]) args.get(0))[2]; + ValueRange expectedDayOfMonthRange = (ValueRange) ((Object[]) args.get(0))[3]; + ValueRange expectedMonthRange = (ValueRange) ((Object[]) args.get(0))[4]; + ValueRange expectedProlepticMonthRange = (ValueRange) ((Object[]) args.get(0))[5]; + UnaryOperator startOrEnd = (UnaryOperator) args.get(1); + + AccountingChronologyBuilder builder = startOrEnd.apply(new AccountingChronologyBuilder()) + .nearestEndOf(Month.AUGUST).endsOn(DayOfWeek.SUNDAY) + .withDivision(division).leapWeekInMonth(leapWeekInMonth); + + return arguments(builder.toChronology(), expectedWeekOfMonthRange, expectedDayOfMonthRange, + expectedMonthRange, expectedProlepticMonthRange); + }); } - @Test(dataProvider = "yearEnding") - public void test_date_int_int_int_nearestEndOf(DayOfWeek dayOfWeek, Month ending) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(dayOfWeek).nearestEndOf(ending) - .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS).leapWeekInMonth(12) - .toChronology(); - - IntFunction getYearEnd = year -> { - return LocalDate.of(year, ending, 3).plusMonths(1).with(TemporalAdjusters.previousOrSame(dayOfWeek)); - }; + @ParameterizedTest + @MethodSource("data_range") + public void test_range(AccountingChronology chronology, ValueRange expectedWeekOfMonthRange, + ValueRange expectedDayOfMonthRange, ValueRange expectedMonthRange, ValueRange expectedProlepticMonthRange) { + assertAll( + () -> assertEquals(expectedWeekOfMonthRange, chronology.range(ChronoField.ALIGNED_WEEK_OF_MONTH)), + () -> assertEquals(expectedDayOfMonthRange, chronology.range(ChronoField.DAY_OF_MONTH)), + () -> assertEquals(ValueRange.of(1, 364, 371), chronology.range(ChronoField.DAY_OF_YEAR)), + () -> assertEquals(expectedMonthRange, chronology.range(ChronoField.MONTH_OF_YEAR)), + () -> assertEquals(expectedProlepticMonthRange, chronology.range(ChronoField.PROLEPTIC_MONTH))); + } - for (int year = -200; year < 600; year++) { - assertEquals(chronology.date(year, 1, 1).toEpochDay(), getYearEnd.apply(year - 1).plusDays(1).toEpochDay()); - } + @ParameterizedTest + @MethodSource("data_weeksInMonth") + public void test_date_dayOfMonth_range(AccountingChronology chronology, int[] weeksInMonth, int[] _elapsedWeeksInMonth, int leapWeekInMonth, int yearOffset) { + assertAll(IntStream.range(1, weeksInMonth.length).mapToObj( + month -> () -> assertAll( + () -> assertEquals(ValueRange.of(1, weeksInMonth[month - 1] * 7), + AccountingDate.of(chronology, 2011 - yearOffset, month, 15).range(ChronoField.DAY_OF_MONTH), + () -> String.format("day of month for month %d ", month)), + () -> assertEquals( + ValueRange.of(1, weeksInMonth[month - 1] * 7 + (month == leapWeekInMonth ? 7 : 0)), + AccountingDate.of(chronology, 2012 - yearOffset, month, 15).range(ChronoField.DAY_OF_MONTH), + () -> String.format("leap year day of month for month %d ", month)), + () -> assertEquals(ValueRange.of(1, weeksInMonth[month - 1]), + AccountingDate.of(chronology, 2011 - yearOffset, month, 15) + .range(ChronoField.ALIGNED_WEEK_OF_MONTH), + () -> String.format("week of month for month %d ", month)), + () -> assertEquals( + ValueRange.of(1, weeksInMonth[month - 1] + (month == leapWeekInMonth ? 1 : 0)), + AccountingDate.of(chronology, 2012 - yearOffset, month, 15) + .range(ChronoField.ALIGNED_WEEK_OF_MONTH)), + () -> String.format("leap year week of month for month %d ", month)))); } - //----------------------------------------------------------------------- - // range(MONTH_OF_YEAR), range(DAY_OF_MONTH) - //----------------------------------------------------------------------- - @DataProvider(name = "range") - Object[][] data_range() { - return new Object[][] { - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 1, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 2, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 3, - ValueRange.of(1, 4, 6), ValueRange.of(1, 28, 42), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 4, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 5, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 6, - ValueRange.of(1, 4, 6), ValueRange.of(1, 28, 42), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 7, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 8, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 9, - ValueRange.of(1, 4, 6), ValueRange.of(1, 28, 42), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 10, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 11, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 12, - ValueRange.of(1, 4, 6), ValueRange.of(1, 28, 42), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, 1, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, 2, - ValueRange.of(1, 4, 6), ValueRange.of(1, 28, 42), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, 3, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - - {AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, 1, - ValueRange.of(1, 4, 6), ValueRange.of(1, 28, 42), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, 2, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, 3, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 12), ValueRange.of(-999_999 * 12L, 999_999 * 12L + 11)}, - - {AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 1, - ValueRange.of(1, 4, 5), ValueRange.of(1, 28, 35), ValueRange.of(1, 13), ValueRange.of(-999_999 * 13L, 999_999 * 13L + 12)}, - }; + @ParameterizedTest + @MethodSource("data_yearEnding") + public void test_date_dayOfYear_range(AccountingChronology chronology, IntFunction _getYearEnd, IntPredicate isLeapYear) { + assertAll(IntStream.range(2007, 2015).mapToObj( + year -> () -> assertEquals(ValueRange.of(1, isLeapYear.test(year) ? 371 : 364), + AccountingDate.of(chronology, year, 3, 5).range(ChronoField.DAY_OF_YEAR), + () -> String.format("for year %d ", year)))); } - @Test(dataProvider = "range") - public void test_range(AccountingYearDivision division, int leapWeekInMonth, - ValueRange expectedWeekOfMonthRange, ValueRange expectedDayOfMonthRange, ValueRange expectedMonthRange, ValueRange expectedProlepticMonthRange) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(DayOfWeek.SUNDAY).nearestEndOf(Month.AUGUST) - .withDivision(division).leapWeekInMonth(leapWeekInMonth) - .toChronology(); - - assertEquals(chronology.range(ChronoField.ALIGNED_WEEK_OF_MONTH), expectedWeekOfMonthRange); - assertEquals(chronology.range(ChronoField.DAY_OF_MONTH), expectedDayOfMonthRange); - assertEquals(chronology.range(ChronoField.DAY_OF_YEAR), ValueRange.of(1, 364, 371)); - assertEquals(chronology.range(ChronoField.MONTH_OF_YEAR), expectedMonthRange); - assertEquals(chronology.range(ChronoField.PROLEPTIC_MONTH), expectedProlepticMonthRange); + // ----------------------------------------------------------------------- + // getWeeksInMonth(month), + // getWeeksAtStartOfMonth(weeks), getMonthFromElapsedWeeks(weeks) + // ----------------------------------------------------------------------- + public static Stream data_weeksInMonth() { + Stream pattern_4_4_5 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> new Object[] { AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, + new int[] { 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5 }, leapWeekInMonth }); + + Stream pattern_4_5_4 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> new Object[] { AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, + new int[] { 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4 }, leapWeekInMonth }); + + Stream pattern_5_4_4 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> new Object[] { AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, + new int[] { 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4 }, leapWeekInMonth }); + + Stream pattern_even_13 = IntStream.range(1, 14) + .mapToObj((leapWeekInMonth) -> new Object[] { AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, + new int[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, leapWeekInMonth }); + + return Lists.cartesianProduct( + Streams.concat(pattern_4_4_5, pattern_4_5_4, pattern_5_4_4, pattern_even_13).collect(Collectors.toList()), + Lists.newArrayList((Object) new Object[] { + (UnaryOperator) AccountingChronologyBuilder::accountingYearEndsInIsoYear, 0 + })) + .stream().map(args -> { + AccountingYearDivision division = (AccountingYearDivision) ((Object[]) args.get(0))[0]; + int[] expectedWeeksInMonth = (int[]) ((Object[]) args.get(0))[1]; + int leapWeekInMonth = (int) ((Object[]) args.get(0))[2]; + UnaryOperator startOrEnd = (UnaryOperator) ((Object[]) args.get(1))[0]; + int offset = (int) ((Object[]) args.get(1))[1]; + + AccountingChronologyBuilder builder = startOrEnd.apply(new AccountingChronologyBuilder()) + .endsOn(DayOfWeek.SUNDAY) + .nearestEndOf(Month.AUGUST) + .withDivision(division).leapWeekInMonth(leapWeekInMonth); + + int[] elapsedWeeksInMonth = new int[expectedWeeksInMonth.length]; + for (int month = 1, elapsedWeeks = 0; month <= elapsedWeeksInMonth.length; elapsedWeeks += expectedWeeksInMonth[month - 1], month++) { + elapsedWeeksInMonth[month - 1] = elapsedWeeks; + } + + return arguments(builder.toChronology(), expectedWeeksInMonth, elapsedWeeksInMonth, leapWeekInMonth, offset); + }); } - @Test(dataProvider = "weeksInMonth") - public void test_date_dayOfMonth_range(AccountingYearDivision division, int[] weeksInMonth, int leapWeekInMonth) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(DayOfWeek.SUNDAY).nearestEndOf(Month.AUGUST) - .withDivision(division).leapWeekInMonth(leapWeekInMonth) - .toChronology(); - - for (int month = 1; month <= weeksInMonth.length; month++) { - assertEquals(AccountingDate.of(chronology, 2011, month, 15).range(ChronoField.DAY_OF_MONTH), ValueRange.of(1, weeksInMonth[month - 1] * 7)); - assertEquals(AccountingDate.of(chronology, 2012, month, 15).range(ChronoField.DAY_OF_MONTH), ValueRange.of(1, weeksInMonth[month - 1] * 7 + (month == leapWeekInMonth ? 7 : 0))); - assertEquals(AccountingDate.of(chronology, 2011, month, 15).range(ChronoField.ALIGNED_WEEK_OF_MONTH), ValueRange.of(1, weeksInMonth[month - 1])); - assertEquals(AccountingDate.of(chronology, 2012, month, 15).range(ChronoField.ALIGNED_WEEK_OF_MONTH), ValueRange.of(1, weeksInMonth[month - 1] + (month == leapWeekInMonth ? 1 : 0))); - } + @ParameterizedTest + @MethodSource("data_weeksInMonth") + public void test_getWeeksInMonth(AccountingChronology chronology, int[] weeksInMonth, int[] _elapsedWeeksInMonth, int leapWeekInMonth, int _yearOffset) { + assertAll( + IntStream.range(1, weeksInMonth.length) + .mapToObj(month -> () -> assertAll( + () -> assertEquals(weeksInMonth[month - 1], + chronology.getDivision().getWeeksInMonth(month), + () -> String.format("weeks in month mismatch for month %d ", month)), + () -> assertEquals(weeksInMonth[month - 1] + (month == leapWeekInMonth ? 1 : 0), + chronology.getDivision().getWeeksInMonth(month, leapWeekInMonth), + () -> String.format("weeks in month mismatch with leap week for month %d ", + month))))); } - @Test(dataProvider = "yearEnding") - public void test_date_dayOfYear_inLastWeekOf_range(DayOfWeek dayOfWeek, Month ending) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(dayOfWeek).inLastWeekOf(ending) - .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS).leapWeekInMonth(12) - .toChronology(); - - IntFunction getYearEnd = year -> { - return LocalDate.of(year, ending, 1).with(TemporalAdjusters.lastDayOfMonth()).with(TemporalAdjusters.previousOrSame(dayOfWeek)); - }; - Predicate isLeapYear = year -> { - LocalDate currentYearEnd = getYearEnd.apply(year); - LocalDate prevYearEnd = getYearEnd.apply(year - 1); - return prevYearEnd.until(currentYearEnd, DAYS) == 371; - }; - - for (int year = 2007; year < 2015; year++) { - assertEquals(AccountingDate.of(chronology, year, 3, 5).range(ChronoField.DAY_OF_YEAR), ValueRange.of(1, isLeapYear.test(year) ? 371 : 364)); - } + @ParameterizedTest + @MethodSource("data_weeksInMonth") + public void test_getWeeksAtStartOf(AccountingChronology chronology, int[] weeksInMonth, int[] elapsedWeeksInMonth, int leapWeekInMonth, int _yearOffset) { + assertAll( + IntStream.range(1, weeksInMonth.length) + .mapToObj(month -> () -> assertAll( + () -> assertEquals(elapsedWeeksInMonth[month - 1], + chronology.getDivision().getWeeksAtStartOfMonth(month), + () -> String.format("weeks in month mismatch for month %d ", month)), + () -> assertEquals(elapsedWeeksInMonth[month - 1] + (month > leapWeekInMonth ? 1 : 0), + chronology.getDivision().getWeeksAtStartOfMonth(month, leapWeekInMonth), + () -> String.format("weeks in month mismatch with leap week for month %d ", month))))); } - @Test(dataProvider = "yearEnding") - public void test_date_dayOfYear_nearestEndOf_range(DayOfWeek dayOfWeek, Month ending) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(dayOfWeek).nearestEndOf(ending) - .withDivision(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS).leapWeekInMonth(12) - .toChronology(); - - IntFunction getYearEnd = year -> { - return LocalDate.of(year, ending, 3).plusMonths(1).with(TemporalAdjusters.previousOrSame(dayOfWeek)); - }; - Predicate isLeapYear = year -> { - LocalDate currentYearEnd = getYearEnd.apply(year); - LocalDate prevYearEnd = getYearEnd.apply(year - 1); - return prevYearEnd.until(currentYearEnd, DAYS) == 371; - }; - - for (int year = 2007; year < 2015; year++) { - assertEquals(AccountingDate.of(chronology, year, 3, 5).range(ChronoField.DAY_OF_YEAR), ValueRange.of(1, isLeapYear.test(year) ? 371 : 364)); - } + @ParameterizedTest + @MethodSource("data_weeksInMonth") + public void test_getMonthFromElapsedWeeks(AccountingChronology chronology, int[] weeksInMonth, int[] elapsedWeeksInMonths, int leapWeekInMonth, int _yearOffset) { + assertAll( + IntStream.range(0, weeksInMonth.length).boxed() + .flatMap(i -> IntStream.range(elapsedWeeksInMonths[i], elapsedWeeksInMonths[i] + weeksInMonth[i]).mapToObj(week -> new int[] { i + 1, week })) + .map(args -> { + int month = args[0]; + int week = args[1]; + + return () -> assertAll( + () -> assertEquals(month, chronology.getDivision().getMonthFromElapsedWeeks(week), + () -> String.format("weeks in month mismatch for month %d ", month)), + () -> assertEquals(month, + chronology.getDivision().getMonthFromElapsedWeeks(week + (month > leapWeekInMonth ? 1 : 0), leapWeekInMonth), + () -> String.format("weeks in month mismatch with leap week for month %d ",month)), + month == leapWeekInMonth && week == weeksInMonth[month - 1] - 1 + ? () -> assertEquals(month, + chronology.getDivision().getMonthFromElapsedWeeks(week + 1, leapWeekInMonth), + () -> String.format("leap week in month for month %d ", month)) + : () -> {}); + })); } - //----------------------------------------------------------------------- - // getWeeksInMonth(month), - // getWeeksAtStartOfMonth(weeks), getMonthFromElapsedWeeks(weeks) - //----------------------------------------------------------------------- - @DataProvider(name = "weeksInMonth") - Object[][] data_weeksInMonth() { - return new Object[][] { - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 1}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 2}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 3}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 4}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 5}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 6}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 7}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 8}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 9}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 10}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 11}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, new int[] {4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5}, 12}, - - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, new int[] {4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4}, 1}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, new int[] {4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4}, 2}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, new int[] {4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4}, 3}, - - {AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, new int[] {5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4}, 1}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, new int[] {5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4}, 2}, - {AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, new int[] {5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4}, 3}, - - {AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, new int[] {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, 13}, - }; + @ParameterizedTest + @EnumSource + public void test_negativeWeeks_getMonthFromElapsedWeekspublic(AccountingYearDivision division) { + assertAll( + () -> assertEquals(1, division.getMonthFromElapsedWeeks(0)), + () -> assertThrows(DateTimeException.class, () -> division.getMonthFromElapsedWeeks(-1))); } - @Test(dataProvider = "weeksInMonth") - public void test_getWeeksInMonth(AccountingYearDivision division, int[] weeksInMonth, int leapWeekInMonth) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(DayOfWeek.SUNDAY).nearestEndOf(Month.AUGUST) - .withDivision(division).leapWeekInMonth(leapWeekInMonth) - .toChronology(); + public static Stream data_weeksInMonth_noChronology() { + return Stream.of( + arguments(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, + new int[] { 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5 }), + arguments(AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, + new int[] { 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4 }), + arguments(AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, + new int[] { 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4 }), + arguments(AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, + new int[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 })); + } - for (int month = 1; month <= weeksInMonth.length; month++) { - assertEquals(chronology.getDivision().getWeeksInMonth(month), weeksInMonth[month - 1]); - assertEquals(chronology.getDivision().getWeeksInMonth(month, leapWeekInMonth), weeksInMonth[month - 1] + (month == leapWeekInMonth ? 1 : 0)); - } + @ParameterizedTest + @MethodSource("data_weeksInMonth_noChronology") + public void test_extraWeeks_getMonthFromElapsedWeekspublic(AccountingYearDivision division, int[] weeksInMonth) { + final int elapsedWeeks = Arrays.stream(weeksInMonth).sum(); + assertAll( + () -> assertThrows(DateTimeException.class, () -> division.getMonthFromElapsedWeeks(elapsedWeeks), + "For elapsed weeks on border"), + () -> assertThrows(DateTimeException.class, () -> division.getMonthFromElapsedWeeks(elapsedWeeks + 1), + "For elapsed weeks beyond border")); } - @Test(dataProvider = "weeksInMonth") - public void test_getWeeksAtStartOf(AccountingYearDivision division, int[] weeksInMonth, int leapWeekInMonth) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(DayOfWeek.SUNDAY).nearestEndOf(Month.AUGUST) - .withDivision(division).leapWeekInMonth(leapWeekInMonth) - .toChronology(); + public static Stream data_weeksInMonth_weekInMonth_noChronology() { + Stream pattern_4_4_5 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> arguments(AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, + new int[] { 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5 }, leapWeekInMonth)); - for (int month = 1, elapsedWeeks = 0; month <= weeksInMonth.length; elapsedWeeks += weeksInMonth[month - 1], month++) { - assertEquals(chronology.getDivision().getWeeksAtStartOfMonth(month), elapsedWeeks); - assertEquals(chronology.getDivision().getWeeksAtStartOfMonth(month, leapWeekInMonth), elapsedWeeks + (month > leapWeekInMonth ? 1 : 0)); - } - } + Stream pattern_4_5_4 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> arguments(AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, + new int[] { 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4 }, leapWeekInMonth)); - @Test(dataProvider = "weeksInMonth") - public void test_getMonthFromElapsedWeeks(AccountingYearDivision division, int[] weeksInMonth, int leapWeekInMonth) { - AccountingChronology chronology = new AccountingChronologyBuilder().endsOn(DayOfWeek.SUNDAY).nearestEndOf(Month.AUGUST) - .withDivision(division).leapWeekInMonth(leapWeekInMonth) - .toChronology(); - - for (int month = 1, elapsedWeeks = 0; month <= weeksInMonth.length; elapsedWeeks += weeksInMonth[month - 1], month++) { - for (int i = 0; i < weeksInMonth[month - 1]; i++) { - assertEquals(chronology.getDivision().getMonthFromElapsedWeeks(elapsedWeeks + i), month); - assertEquals(chronology.getDivision().getMonthFromElapsedWeeks(elapsedWeeks + i + (month > leapWeekInMonth ? 1 : 0), leapWeekInMonth), month); - if (month == leapWeekInMonth && i == weeksInMonth[month - 1] - 1) { - assertEquals(chronology.getDivision().getMonthFromElapsedWeeks(elapsedWeeks + i + 1, leapWeekInMonth), month); - } - } - } - } + Stream pattern_5_4_4 = IntStream.range(1, 13) + .mapToObj((leapWeekInMonth) -> arguments(AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, + new int[] { 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4 }, leapWeekInMonth)); - @Test(dataProvider = "weeksInMonth", expectedExceptions = DateTimeException.class) - public void test_negativeWeeks_getMonthFromElapsedWeekspublic(AccountingYearDivision division, int[] weeksInMonth, int leapWeekInMonth) { - assertEquals(division.getMonthFromElapsedWeeks(0), 1); - division.getMonthFromElapsedWeeks(-1); - } + Stream pattern_even_13 = IntStream.range(1, 14) + .mapToObj((leapWeekInMonth) -> arguments(AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, + new int[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, leapWeekInMonth)); - @Test(dataProvider = "weeksInMonth", expectedExceptions = DateTimeException.class) - public void test_extraWeeks_getMonthFromElapsedWeekspublic(AccountingYearDivision division, int[] weeksInMonth, int leapWeekInMonth) { - int elapsedWeeks = 0; - for (int month = 1; month <= weeksInMonth.length; month++) { - elapsedWeeks += weeksInMonth[month - 1]; - } - assertEquals(division.getMonthFromElapsedWeeks(elapsedWeeks), weeksInMonth.length); - division.getMonthFromElapsedWeeks(elapsedWeeks + 1); + return Streams.concat(pattern_4_4_5, pattern_4_5_4, pattern_5_4_4, pattern_even_13); } - @Test(dataProvider = "weeksInMonth", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_weeksInMonth_weekInMonth_noChronology") public void test_extraWeeksLeap_getMonthFromElapsedWeekspublic(AccountingYearDivision division, int[] weeksInMonth, int leapWeekInMonth) { - int elapsedWeeks = 1; - for (int month = 1; month <= weeksInMonth.length; month++) { - elapsedWeeks += weeksInMonth[month - 1]; - } - assertEquals(division.getMonthFromElapsedWeeks(elapsedWeeks, leapWeekInMonth), weeksInMonth.length); - division.getMonthFromElapsedWeeks(elapsedWeeks + 1, leapWeekInMonth); + final int elapsedWeeks = Arrays.stream(weeksInMonth).sum() + 1; + assertAll( + () -> assertThrows(DateTimeException.class, + () -> division.getMonthFromElapsedWeeks(elapsedWeeks, leapWeekInMonth), + "For elapsed weeks on border"), + () -> assertThrows(DateTimeException.class, + () -> division.getMonthFromElapsedWeeks(elapsedWeeks + 1, leapWeekInMonth), + "For elapsed weeks beyond border")); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- // toChronology() failures. - //----------------------------------------------------------------------- - @DataProvider(name = "badChronology") - Object[][] data_badChronology() { - return new Object[][] { - {DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 0}, - {DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, -1}, - {DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 14}, - {DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 13}, - {DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, 13}, - {DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, 13}, - {DayOfWeek.MONDAY, Month.JANUARY, null, 13}, - {DayOfWeek.MONDAY, null, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 13}, - {null, Month.JANUARY, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 13}, - - }; + // ----------------------------------------------------------------------- + public static Stream data_badChronology() { + return Stream.of( + arguments(DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 0), + arguments(DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, -1), + arguments(DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 14), + arguments(DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.QUARTERS_OF_PATTERN_4_4_5_WEEKS, 13), + arguments(DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.QUARTERS_OF_PATTERN_4_5_4_WEEKS, 13), + arguments(DayOfWeek.MONDAY, Month.JANUARY, AccountingYearDivision.QUARTERS_OF_PATTERN_5_4_4_WEEKS, 13), + arguments(DayOfWeek.MONDAY, Month.JANUARY, null, 13), + arguments(DayOfWeek.MONDAY, null, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 13), + arguments(null, Month.JANUARY, AccountingYearDivision.THIRTEEN_EVEN_MONTHS_OF_4_WEEKS, 13)); } - @Test(dataProvider = "badChronology", expectedExceptions = IllegalStateException.class) + @ParameterizedTest + @MethodSource("data_badChronology") public void test_badChronology_nearestEndOf(DayOfWeek dayOfWeek, Month ending, AccountingYearDivision division, int leapWeekInMonth) { - new AccountingChronologyBuilder().endsOn(dayOfWeek).nearestEndOf(ending) - .withDivision(division).leapWeekInMonth(leapWeekInMonth) - .toChronology(); + assertThrows(IllegalStateException.class, + () -> new AccountingChronologyBuilder().endsOn(dayOfWeek).nearestEndOf(ending) + .withDivision(division).leapWeekInMonth(leapWeekInMonth) + .toChronology()); } - @Test(dataProvider = "badChronology", expectedExceptions = IllegalStateException.class) + @ParameterizedTest + @MethodSource("data_badChronology") public void test_badChronology_inLastWeekOf(DayOfWeek dayOfWeek, Month ending, AccountingYearDivision division, int leapWeekInMonth) { - new AccountingChronologyBuilder().endsOn(dayOfWeek).inLastWeekOf(ending) - .withDivision(division).leapWeekInMonth(leapWeekInMonth) - .toChronology(); + assertThrows(IllegalStateException.class, + () -> new AccountingChronologyBuilder().endsOn(dayOfWeek).inLastWeekOf(ending) + .withDivision(division).leapWeekInMonth(leapWeekInMonth) + .toChronology()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestBritishCutoverChronology.java b/src/test/java/org/threeten/extra/chrono/TestBritishCutoverChronology.java index 66d0f8c3..dd6fe3b4 100644 --- a/src/test/java/org/threeten/extra/chrono/TestBritishCutoverChronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestBritishCutoverChronology.java @@ -53,7 +53,9 @@ import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.time.DateTimeException; import java.time.Instant; @@ -81,14 +83,15 @@ import java.util.List; import java.util.TimeZone; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test public class TestBritishCutoverChronology { //----------------------------------------------------------------------- @@ -97,17 +100,16 @@ public class TestBritishCutoverChronology { @Test public void test_chronology_of_name() { Chronology chrono = Chronology.of("BritishCutover"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, BritishCutoverChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "BritishCutover"); - Assert.assertEquals(chrono.getCalendarType(), null); + assertNotNull(chrono); + assertEquals(BritishCutoverChronology.INSTANCE, chrono); + assertEquals("BritishCutover", chrono.getId()); + assertEquals(null, chrono.getCalendarType()); } //----------------------------------------------------------------------- // creation, toLocalDate() //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { {BritishCutoverDate.of(1, 1, 1), LocalDate.of(0, 12, 30)}, {BritishCutoverDate.of(1, 1, 2), LocalDate.of(0, 12, 31)}, @@ -151,74 +153,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_BritishCutoverDate(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(LocalDate.from(cutover), iso); + assertEquals(iso, LocalDate.from(cutover)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_BritishCutoverDate_from_LocalDate(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(BritishCutoverDate.from(iso), cutover); + assertEquals(cutover, BritishCutoverDate.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_BritishCutoverDate_chronology_dateEpochDay(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(BritishCutoverChronology.INSTANCE.dateEpochDay(iso.toEpochDay()), cutover); + assertEquals(cutover, BritishCutoverChronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_BritishCutoverDate_toEpochDay(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(cutover.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), cutover.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_BritishCutoverDate_until_BritishCutoverDate(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(cutover.until(cutover), BritishCutoverChronology.INSTANCE.period(0, 0, 0)); + assertEquals(BritishCutoverChronology.INSTANCE.period(0, 0, 0), cutover.until(cutover)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_BritishCutoverDate_until_LocalDate(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(cutover.until(iso), BritishCutoverChronology.INSTANCE.period(0, 0, 0)); + assertEquals(BritishCutoverChronology.INSTANCE.period(0, 0, 0), cutover.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_BritishCutoverDate(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(iso.until(cutover), Period.ZERO); + assertEquals(Period.ZERO, iso.until(cutover)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(BritishCutoverChronology.INSTANCE.date(iso), cutover); + assertEquals(cutover, BritishCutoverChronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(LocalDate.from(cutover.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(cutover.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(cutover.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(cutover.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(cutover.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(cutover.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(cutover.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(cutover.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(cutover.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(cutover.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(LocalDate.from(cutover.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(cutover.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(cutover.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(cutover.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(cutover.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(cutover.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(cutover.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(cutover.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(cutover.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(cutover.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(BritishCutoverDate cutover, LocalDate iso) { - assertEquals(cutover.until(iso.plusDays(0), DAYS), 0); - assertEquals(cutover.until(iso.plusDays(1), DAYS), 1); - assertEquals(cutover.until(iso.plusDays(35), DAYS), 35); - assertEquals(cutover.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, cutover.until(iso.plusDays(0), DAYS)); + assertEquals(1, cutover.until(iso.plusDays(1), DAYS)); + assertEquals(35, cutover.until(iso.plusDays(35), DAYS)); + assertEquals(-40, cutover.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {1900, 0, 0}, @@ -260,14 +272,15 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - BritishCutoverDate.of(year, month, dom); + assertThrows(DateTimeException.class, () -> BritishCutoverDate.of(year, month, dom)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_dateYearDay_badDate() { - BritishCutoverChronology.INSTANCE.dateYearDay(2001, 366); + assertThrows(DateTimeException.class, () -> BritishCutoverChronology.INSTANCE.dateYearDay(2001, 366)); } //----------------------------------------------------------------------- @@ -277,28 +290,28 @@ public void test_Chronology_dateYearDay_badDate() { public void test_Chronology_isLeapYear_loop() { for (int year = -200; year < 200; year++) { BritishCutoverDate base = BritishCutoverDate.of(year, 1, 1); - assertEquals(base.isLeapYear(), (year % 4) == 0); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(year), (year % 4) == 0); + assertEquals((year % 4) == 0, base.isLeapYear()); + assertEquals((year % 4) == 0, BritishCutoverChronology.INSTANCE.isLeapYear(year)); } } @Test public void test_Chronology_isLeapYear_specific() { - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(8), true); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(7), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(6), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(5), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(4), true); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(3), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(2), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(1), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(0), true); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(-1), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(-2), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(-3), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(-4), true); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(-5), false); - assertEquals(BritishCutoverChronology.INSTANCE.isLeapYear(-6), false); + assertEquals(true, BritishCutoverChronology.INSTANCE.isLeapYear(8)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(7)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(6)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(5)); + assertEquals(true, BritishCutoverChronology.INSTANCE.isLeapYear(4)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(3)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(2)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(1)); + assertEquals(true, BritishCutoverChronology.INSTANCE.isLeapYear(0)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(-1)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(-2)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(-3)); + assertEquals(true, BritishCutoverChronology.INSTANCE.isLeapYear(-4)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(-5)); + assertEquals(false, BritishCutoverChronology.INSTANCE.isLeapYear(-6)); } //----------------------------------------------------------------------- @@ -306,14 +319,13 @@ public void test_Chronology_isLeapYear_specific() { //----------------------------------------------------------------------- @Test public void test_Chronology_getCutover() { - assertEquals(BritishCutoverChronology.INSTANCE.getCutover(), LocalDate.of(1752, 9, 14)); + assertEquals(LocalDate.of(1752, 9, 14), BritishCutoverChronology.INSTANCE.getCutover()); } //----------------------------------------------------------------------- // lengthOfMonth() //----------------------------------------------------------------------- - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + public static Object[][] data_lengthOfMonth() { return new Object[][] { {1700, 1, 31}, {1700, 2, 29}, @@ -381,16 +393,16 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int length) { - assertEquals(BritishCutoverDate.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, BritishCutoverDate.of(year, month, 1).lengthOfMonth()); } //----------------------------------------------------------------------- // lengthOfYear() //----------------------------------------------------------------------- - @DataProvider(name = "lengthOfYear") - Object[][] data_lengthOfYear() { + public static Object[][] data_lengthOfYear() { return new Object[][] { {-101, 365}, {-100, 366}, @@ -421,14 +433,16 @@ Object[][] data_lengthOfYear() { }; } - @Test(dataProvider = "lengthOfYear") + @ParameterizedTest + @MethodSource("data_lengthOfYear") public void test_lengthOfYear_atStart(int year, int length) { - assertEquals(BritishCutoverDate.of(year, 1, 1).lengthOfYear(), length); + assertEquals(length, BritishCutoverDate.of(year, 1, 1).lengthOfYear()); } - @Test(dataProvider = "lengthOfYear") + @ParameterizedTest + @MethodSource("data_lengthOfYear") public void test_lengthOfYear_atEnd(int year, int length) { - assertEquals(BritishCutoverDate.of(year, 12, 31).lengthOfYear(), length); + assertEquals(length, BritishCutoverDate.of(year, 12, 31).lengthOfYear()); } //----------------------------------------------------------------------- @@ -444,7 +458,7 @@ public void test_era_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); BritishCutoverDate eraBased = BritishCutoverChronology.INSTANCE.date(era, yoe, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -458,56 +472,56 @@ public void test_era_yearDay_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); BritishCutoverDate eraBased = BritishCutoverChronology.INSTANCE.dateYearDay(era, yoe, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_era_yearDay() { - assertEquals(BritishCutoverChronology.INSTANCE.dateYearDay(1752, 1), BritishCutoverDate.of(1752, 1, 1)); - assertEquals(BritishCutoverChronology.INSTANCE.dateYearDay(1752, 244), BritishCutoverDate.of(1752, 8, 31)); - assertEquals(BritishCutoverChronology.INSTANCE.dateYearDay(1752, 246), BritishCutoverDate.of(1752, 9, 2)); - assertEquals(BritishCutoverChronology.INSTANCE.dateYearDay(1752, 247), BritishCutoverDate.of(1752, 9, 14)); - assertEquals(BritishCutoverChronology.INSTANCE.dateYearDay(1752, 257), BritishCutoverDate.of(1752, 9, 24)); - assertEquals(BritishCutoverChronology.INSTANCE.dateYearDay(1752, 258), BritishCutoverDate.of(1752, 9, 25)); - assertEquals(BritishCutoverChronology.INSTANCE.dateYearDay(1752, 355), BritishCutoverDate.of(1752, 12, 31)); - assertEquals(BritishCutoverChronology.INSTANCE.dateYearDay(2014, 1), BritishCutoverDate.of(2014, 1, 1)); + assertEquals(BritishCutoverDate.of(1752, 1, 1), BritishCutoverChronology.INSTANCE.dateYearDay(1752, 1)); + assertEquals(BritishCutoverDate.of(1752, 8, 31), BritishCutoverChronology.INSTANCE.dateYearDay(1752, 244)); + assertEquals(BritishCutoverDate.of(1752, 9, 2), BritishCutoverChronology.INSTANCE.dateYearDay(1752, 246)); + assertEquals(BritishCutoverDate.of(1752, 9, 14), BritishCutoverChronology.INSTANCE.dateYearDay(1752, 247)); + assertEquals(BritishCutoverDate.of(1752, 9, 24), BritishCutoverChronology.INSTANCE.dateYearDay(1752, 257)); + assertEquals(BritishCutoverDate.of(1752, 9, 25), BritishCutoverChronology.INSTANCE.dateYearDay(1752, 258)); + assertEquals(BritishCutoverDate.of(1752, 12, 31), BritishCutoverChronology.INSTANCE.dateYearDay(1752, 355)); + assertEquals(BritishCutoverDate.of(2014, 1, 1), BritishCutoverChronology.INSTANCE.dateYearDay(2014, 1)); } @Test public void test_prolepticYear_specific() { - assertEquals(BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.AD, 4), 4); - assertEquals(BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.AD, 3), 3); - assertEquals(BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.AD, 2), 2); - assertEquals(BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.AD, 1), 1); - assertEquals(BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.BC, 1), 0); - assertEquals(BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.BC, 2), -1); - assertEquals(BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.BC, 3), -2); - assertEquals(BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.BC, 4), -3); + assertEquals(4, BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.AD, 4)); + assertEquals(3, BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.AD, 3)); + assertEquals(2, BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.AD, 2)); + assertEquals(1, BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.AD, 1)); + assertEquals(0, BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.BC, 1)); + assertEquals(-1, BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.BC, 2)); + assertEquals(-2, BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.BC, 3)); + assertEquals(-3, BritishCutoverChronology.INSTANCE.prolepticYear(JulianEra.BC, 4)); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void test_prolepticYear_badEra() { - BritishCutoverChronology.INSTANCE.prolepticYear(IsoEra.CE, 4); + assertThrows(ClassCastException.class, () -> BritishCutoverChronology.INSTANCE.prolepticYear(IsoEra.CE, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(BritishCutoverChronology.INSTANCE.eraOf(1), JulianEra.AD); - assertEquals(BritishCutoverChronology.INSTANCE.eraOf(0), JulianEra.BC); + assertEquals(JulianEra.AD, BritishCutoverChronology.INSTANCE.eraOf(1)); + assertEquals(JulianEra.BC, BritishCutoverChronology.INSTANCE.eraOf(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - BritishCutoverChronology.INSTANCE.eraOf(2); + assertThrows(DateTimeException.class, () -> BritishCutoverChronology.INSTANCE.eraOf(2)); } @Test public void test_Chronology_eras() { List eras = BritishCutoverChronology.INSTANCE.eras(); - assertEquals(eras.size(), 2); - assertEquals(eras.contains(JulianEra.BC), true); - assertEquals(eras.contains(JulianEra.AD), true); + assertEquals(2, eras.size()); + assertEquals(true, eras.contains(JulianEra.BC)); + assertEquals(true, eras.contains(JulianEra.AD)); } //----------------------------------------------------------------------- @@ -515,19 +529,18 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(BritishCutoverChronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(1, 7)); - assertEquals(BritishCutoverChronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 28, 31)); - assertEquals(BritishCutoverChronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 355, 366)); - assertEquals(BritishCutoverChronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 12)); - assertEquals(BritishCutoverChronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH), ValueRange.of(1, 3, 5)); - assertEquals(BritishCutoverChronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR), ValueRange.of(1, 51, 53)); + assertEquals(ValueRange.of(1, 7), BritishCutoverChronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 28, 31), BritishCutoverChronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 355, 366), BritishCutoverChronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(1, 12), BritishCutoverChronology.INSTANCE.range(MONTH_OF_YEAR)); + assertEquals(ValueRange.of(1, 3, 5), BritishCutoverChronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH)); + assertEquals(ValueRange.of(1, 51, 53), BritishCutoverChronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR)); } //----------------------------------------------------------------------- // BritishCutoverDate.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { {1700, 1, 23, DAY_OF_MONTH, 1, 31}, {1700, 2, 23, DAY_OF_MONTH, 1, 29}, @@ -612,21 +625,21 @@ Object[][] data_ranges() { }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, int expectedMin, int expectedMax) { - assertEquals(BritishCutoverDate.of(year, month, dom).range(field), ValueRange.of(expectedMin, expectedMax)); + assertEquals(ValueRange.of(expectedMin, expectedMax), BritishCutoverDate.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - BritishCutoverDate.of(2012, 6, 30).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> BritishCutoverDate.of(2012, 6, 30).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // BritishCutoverDate.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {1752, 5, 26, DAY_OF_WEEK, 2}, {1752, 5, 26, DAY_OF_MONTH, 26}, @@ -673,21 +686,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(BritishCutoverDate.of(year, month, dom).getLong(field), expected); + assertEquals(expected, BritishCutoverDate.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - BritishCutoverDate.of(2012, 6, 30).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> BritishCutoverDate.of(2012, 6, 30).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // BritishCutoverDate.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {1752, 9, 2, DAY_OF_WEEK, 1, 1752, 8, 31}, {1752, 9, 2, DAY_OF_WEEK, 4, 1752, 9, 14}, @@ -784,23 +797,23 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(BritishCutoverDate.of(year, month, dom).with(field, value), BritishCutoverDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(BritishCutoverDate.of(expectedYear, expectedMonth, expectedDom), BritishCutoverDate.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - BritishCutoverDate.of(2012, 6, 30).with(MINUTE_OF_DAY, 0); + assertThrows(UnsupportedTemporalTypeException.class, () -> BritishCutoverDate.of(2012, 6, 30).with(MINUTE_OF_DAY, 0)); } //----------------------------------------------------------------------- // BritishCutoverDate.with(TemporalAdjuster) //----------------------------------------------------------------------- - @DataProvider(name = "withLastDayOfMonth") - Object[][] data_lastDayOfMonth() { + public static Object[][] data_lastDayOfMonth() { return new Object[][] { {BritishCutoverDate.of(1752, 2, 23), BritishCutoverDate.of(1752, 2, 29)}, {BritishCutoverDate.of(1752, 6, 23), BritishCutoverDate.of(1752, 6, 30)}, @@ -811,17 +824,17 @@ Object[][] data_lastDayOfMonth() { }; } - @Test(dataProvider = "withLastDayOfMonth") + @ParameterizedTest + @MethodSource("data_lastDayOfMonth") public void test_adjust_lastDayOfMonth(BritishCutoverDate input, BritishCutoverDate expected) { BritishCutoverDate test = input.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, expected); + assertEquals(expected, test); } //----------------------------------------------------------------------- // BritishCutoverDate.with(Local*) //----------------------------------------------------------------------- - @DataProvider(name = "withLocalDate") - Object[][] data_withLocalDate() { + public static Object[][] data_withLocalDate() { return new Object[][] { {BritishCutoverDate.of(1752, 9, 2), LocalDate.of(1752, 9, 12), BritishCutoverDate.of(1752, 9, 1)}, {BritishCutoverDate.of(1752, 9, 14), LocalDate.of(1752, 9, 12), BritishCutoverDate.of(1752, 9, 1)}, @@ -831,16 +844,17 @@ Object[][] data_withLocalDate() { }; } - @Test(dataProvider = "withLocalDate") + @ParameterizedTest + @MethodSource("data_withLocalDate") public void test_adjust_LocalDate(BritishCutoverDate input, LocalDate local, BritishCutoverDate expected) { BritishCutoverDate test = input.with(local); - assertEquals(test, expected); + assertEquals(expected, test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { BritishCutoverDate cutover = BritishCutoverDate.of(2000, 1, 4); - cutover.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> cutover.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -850,21 +864,20 @@ public void test_adjust_toMonth() { public void test_LocalDate_withBritishCutoverDate() { BritishCutoverDate cutover = BritishCutoverDate.of(2012, 6, 23); LocalDate test = LocalDate.MIN.with(cutover); - assertEquals(test, LocalDate.of(2012, 6, 23)); + assertEquals(LocalDate.of(2012, 6, 23), test); } @Test public void test_LocalDateTime_withBritishCutoverDate() { BritishCutoverDate cutover = BritishCutoverDate.of(2012, 6, 23); LocalDateTime test = LocalDateTime.MIN.with(cutover); - assertEquals(test, LocalDateTime.of(2012, 6, 23, 0, 0)); + assertEquals(LocalDateTime.of(2012, 6, 23, 0, 0), test); } //----------------------------------------------------------------------- // BritishCutoverDate.plus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {1752, 9, 2, -1, DAYS, 1752, 9, 1, true}, {1752, 9, 2, 0, DAYS, 1752, 9, 2, true}, @@ -915,33 +928,34 @@ Object[][] data_plus() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom, boolean bidi) { - assertEquals(BritishCutoverDate.of(year, month, dom).plus(amount, unit), BritishCutoverDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(BritishCutoverDate.of(expectedYear, expectedMonth, expectedDom), BritishCutoverDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom, boolean bidi) { if (bidi) { - assertEquals(BritishCutoverDate.of(year, month, dom).minus(amount, unit), BritishCutoverDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(BritishCutoverDate.of(expectedYear, expectedMonth, expectedDom), BritishCutoverDate.of(year, month, dom).minus(amount, unit)); } } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - BritishCutoverDate.of(2012, 6, 30).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> BritishCutoverDate.of(2012, 6, 30).plus(0, MINUTES)); } //----------------------------------------------------------------------- // BritishCutoverDate.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {1752, 9, 1, 1752, 9, 2, DAYS, 1}, {1752, 9, 1, 1752, 9, 14, DAYS, 2}, @@ -993,64 +1007,60 @@ Object[][] data_until() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { BritishCutoverDate start = BritishCutoverDate.of(year1, month1, dom1); BritishCutoverDate end = BritishCutoverDate.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { BritishCutoverDate start = BritishCutoverDate.of(2012, 6, 30); BritishCutoverDate end = BritishCutoverDate.of(2012, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- @Test public void test_plus_Period() { assertEquals( - BritishCutoverDate.of(1752, 9, 2).plus(BritishCutoverChronology.INSTANCE.period(0, 1, 3)), - BritishCutoverDate.of(1752, 10, 5)); + BritishCutoverDate.of(1752, 10, 5), + BritishCutoverDate.of(1752, 9, 2).plus(BritishCutoverChronology.INSTANCE.period(0, 1, 3))); assertEquals( - BritishCutoverDate.of(1752, 8, 12).plus(BritishCutoverChronology.INSTANCE.period(0, 1, 0)), - BritishCutoverDate.of(1752, 9, 23)); + BritishCutoverDate.of(1752, 9, 23), + BritishCutoverDate.of(1752, 8, 12).plus(BritishCutoverChronology.INSTANCE.period(0, 1, 0))); assertEquals( - BritishCutoverDate.of(2014, 5, 26).plus(BritishCutoverChronology.INSTANCE.period(0, 2, 3)), - BritishCutoverDate.of(2014, 7, 29)); + BritishCutoverDate.of(2014, 7, 29), + BritishCutoverDate.of(2014, 5, 26).plus(BritishCutoverChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals( - BritishCutoverDate.of(2014, 5, 26).plus(Period.ofMonths(2)), - BritishCutoverDate.of(2014, 7, 26)); + assertThrows(DateTimeException.class, () -> BritishCutoverDate.of(2014, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { assertEquals( - BritishCutoverDate.of(1752, 10, 12).minus(BritishCutoverChronology.INSTANCE.period(0, 1, 0)), - BritishCutoverDate.of(1752, 9, 23)); + BritishCutoverDate.of(1752, 9, 23), + BritishCutoverDate.of(1752, 10, 12).minus(BritishCutoverChronology.INSTANCE.period(0, 1, 0))); assertEquals( - BritishCutoverDate.of(2014, 5, 26).minus(BritishCutoverChronology.INSTANCE.period(0, 2, 3)), - BritishCutoverDate.of(2014, 3, 23)); + BritishCutoverDate.of(2014, 3, 23), + BritishCutoverDate.of(2014, 5, 26).minus(BritishCutoverChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals( - BritishCutoverDate.of(2014, 5, 26).minus(Period.ofMonths(2)), - BritishCutoverDate.of(2014, 3, 26)); + assertThrows(DateTimeException.class, () -> BritishCutoverDate.of(2014, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- - @DataProvider(name = "untilCLD") - Object[][] data_untilCLD() { + public static Object[][] data_untilCLD() { return new Object[][] { {1752, 7, 2, 1752, 7, 1, 0, 0, -1}, {1752, 7, 2, 1752, 7, 2, 0, 0, 0}, @@ -1151,7 +1161,7 @@ Object[][] data_untilCLD() { {1752, 9, 14, 1752, 10, 13, 0, 0, 29}, {1752, 9, 14, 1752, 10, 14, 0, 1, 0}, {1752, 9, 14, 1752, 10, 15, 0, 1, 1}, - + {1752, 9, 24, 1752, 7, 23, 0, -2, -1}, {1752, 9, 24, 1752, 7, 24, 0, -2, 0}, {1752, 9, 24, 1752, 8, 23, 0, -1, -1}, @@ -1168,7 +1178,7 @@ Object[][] data_untilCLD() { {1752, 9, 24, 1752, 10, 23, 0, 0, 29}, {1752, 9, 24, 1752, 10, 24, 0, 1, 0}, {1752, 9, 24, 1752, 10, 25, 0, 1, 1}, - + {1752, 10, 3, 1752, 10, 1, 0, 0, -2}, {1752, 10, 3, 1752, 9, 30, 0, 0, -3}, {1752, 10, 3, 1752, 9, 16, 0, 0, -17}, @@ -1180,7 +1190,7 @@ Object[][] data_untilCLD() { {1752, 10, 3, 1752, 8, 4, 0, -1, -30}, {1752, 10, 3, 1752, 8, 3, 0, -2, 0}, {1752, 10, 3, 1752, 8, 2, 0, -2, -1}, - + {1752, 10, 4, 1752, 10, 1, 0, 0, -3}, {1752, 10, 4, 1752, 9, 30, 0, 0, -4}, {1752, 10, 4, 1752, 9, 16, 0, 0, -18}, @@ -1195,7 +1205,8 @@ Object[][] data_untilCLD() { }; } - @Test(dataProvider = "untilCLD") + @ParameterizedTest + @MethodSource("data_untilCLD") public void test_until_CLD( int year1, int month1, int dom1, int year2, int month2, int dom2, @@ -1204,11 +1215,12 @@ public void test_until_CLD( BritishCutoverDate b = BritishCutoverDate.of(year2, month2, dom2); ChronoPeriod c = a.until(b); assertEquals( - c, - BritishCutoverChronology.INSTANCE.period(expectedYears, expectedMonths, expectedDays)); + BritishCutoverChronology.INSTANCE.period(expectedYears, expectedMonths, expectedDays), + c); } - @Test(dataProvider = "untilCLD") + @ParameterizedTest + @MethodSource("data_untilCLD") public void test_until_CLD_plus( int year1, int month1, int dom1, int year2, int month2, int dom2, @@ -1216,7 +1228,7 @@ public void test_until_CLD_plus( BritishCutoverDate a = BritishCutoverDate.of(year1, month1, dom1); BritishCutoverDate b = BritishCutoverDate.of(year2, month2, dom2); ChronoPeriod c = a.until(b); - assertEquals(a.plus(c), b); + assertEquals(b, a.plus(c)); } //------------------------------------------------------------------------- @@ -1226,23 +1238,23 @@ public void test_until_CLD_plus( public void test_atTime() { BritishCutoverDate date = BritishCutoverDate.of(2014, 10, 12); ChronoLocalDateTime test = date.atTime(LocalTime.of(12, 30)); - assertEquals(test.toLocalDate(), date); - assertEquals(test.toLocalTime(), LocalTime.of(12, 30)); + assertEquals(date, test.toLocalDate()); + assertEquals(LocalTime.of(12, 30), test.toLocalTime()); ChronoLocalDateTime test2 = BritishCutoverChronology.INSTANCE.localDateTime(LocalDateTime.from(test)); - assertEquals(test2, test); + assertEquals(test, test2); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_atTime_null() { - BritishCutoverDate.of(2014, 5, 26).atTime(null); + assertThrows(NullPointerException.class, () -> BritishCutoverDate.of(2014, 5, 26).atTime(null)); } //----------------------------------------------------------------------- // check against GregorianCalendar //----------------------------------------------------------------------- @Test - void test_crossCheck() { + public void test_crossCheck() { BritishCutoverDate test = BritishCutoverDate.of(1700, 1, 1); BritishCutoverDate end = BritishCutoverDate.of(1800, 1, 1); Instant cutover = ZonedDateTime.of(1752, 9, 14, 0, 0, 0, 0, ZoneOffset.UTC).toInstant(); @@ -1251,52 +1263,42 @@ void test_crossCheck() { gcal.clear(); gcal.set(1700, Calendar.JANUARY, 1); while (test.isBefore(end)) { - assertEquals(test.get(YEAR_OF_ERA), gcal.get(Calendar.YEAR)); - assertEquals(test.get(MONTH_OF_YEAR), gcal.get(Calendar.MONTH) + 1); - assertEquals(test.get(DAY_OF_MONTH), gcal.get(Calendar.DAY_OF_MONTH)); - assertEquals(LocalDate.from(test), gcal.toZonedDateTime().toLocalDate()); + assertEquals(gcal.get(Calendar.YEAR), test.get(YEAR_OF_ERA)); + assertEquals(gcal.get(Calendar.MONTH) + 1, test.get(MONTH_OF_YEAR)); + assertEquals(gcal.get(Calendar.DAY_OF_MONTH), test.get(DAY_OF_MONTH)); + assertEquals(gcal.toZonedDateTime().toLocalDate(), LocalDate.from(test)); gcal.add(Calendar.DAY_OF_MONTH, 1); test = test.plus(1, DAYS); } } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - void test_equals() { - BritishCutoverDate a1 = BritishCutoverDate.of(2000, 1, 3); - BritishCutoverDate a2 = BritishCutoverDate.of(2000, 1, 3); - BritishCutoverDate b = BritishCutoverDate.of(2000, 1, 4); - BritishCutoverDate c = BritishCutoverDate.of(2000, 2, 3); - BritishCutoverDate d = BritishCutoverDate.of(2001, 1, 3); - - assertEquals(a1.equals(a1), true); - assertEquals(a1.equals(a2), true); - assertEquals(a1.equals(b), false); - assertEquals(a1.equals(c), false); - assertEquals(a1.equals(d), false); - - assertEquals(a1.equals(null), false); - assertEquals(a1.equals(""), false); - - assertEquals(a1.hashCode(), a2.hashCode()); + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(BritishCutoverDate.of(2000, 1, 3), BritishCutoverDate.of(2000, 1, 3)) + .addEqualityGroup(BritishCutoverDate.of(2000, 1, 4), BritishCutoverDate.of(2000, 1, 4)) + .addEqualityGroup(BritishCutoverDate.of(2000, 2, 3), BritishCutoverDate.of(2000, 2, 3)) + .addEqualityGroup(BritishCutoverDate.of(2001, 1, 3), BritishCutoverDate.of(2001, 1, 3)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {BritishCutoverDate.of(1, 1, 1), "BritishCutover AD 1-01-01"}, {BritishCutoverDate.of(2012, 6, 23), "BritishCutover AD 2012-06-23"}, }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(BritishCutoverDate cutover, String expected) { - assertEquals(cutover.toString(), expected); + assertEquals(expected, cutover.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestCopticChronology.java b/src/test/java/org/threeten/extra/chrono/TestCopticChronology.java index 20c7ca13..edaa6507 100644 --- a/src/test/java/org/threeten/extra/chrono/TestCopticChronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestCopticChronology.java @@ -53,7 +53,9 @@ import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.time.DateTimeException; import java.time.LocalDate; @@ -70,14 +72,15 @@ import java.time.temporal.WeekFields; import java.util.List; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test public class TestCopticChronology { //----------------------------------------------------------------------- @@ -86,26 +89,25 @@ public class TestCopticChronology { @Test public void test_chronology_of_name() { Chronology chrono = Chronology.of("Coptic"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, CopticChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Coptic"); - Assert.assertEquals(chrono.getCalendarType(), "coptic"); + assertNotNull(chrono); + assertEquals(CopticChronology.INSTANCE, chrono); + assertEquals("Coptic", chrono.getId()); + assertEquals("coptic", chrono.getCalendarType()); } @Test public void test_chronology_of_name_id() { Chronology chrono = Chronology.of("coptic"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, CopticChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Coptic"); - Assert.assertEquals(chrono.getCalendarType(), "coptic"); + assertNotNull(chrono); + assertEquals(CopticChronology.INSTANCE, chrono); + assertEquals("Coptic", chrono.getId()); + assertEquals("coptic", chrono.getCalendarType()); } //----------------------------------------------------------------------- // creation, toLocalDate() //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { {CopticDate.of(-1, 13, 6), LocalDate.of(283, 8, 29)}, {CopticDate.of(0, 1, 1), LocalDate.of(283, 8, 30)}, @@ -132,74 +134,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_CopticDate(CopticDate coptic, LocalDate iso) { - assertEquals(LocalDate.from(coptic), iso); + assertEquals(iso, LocalDate.from(coptic)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_CopticDate_from_LocalDate(CopticDate coptic, LocalDate iso) { - assertEquals(CopticDate.from(iso), coptic); + assertEquals(coptic, CopticDate.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_CopticDate_chronology_dateEpochDay(CopticDate coptic, LocalDate iso) { - assertEquals(CopticChronology.INSTANCE.dateEpochDay(iso.toEpochDay()), coptic); + assertEquals(coptic, CopticChronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_CopticDate_toEpochDay(CopticDate coptic, LocalDate iso) { - assertEquals(coptic.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), coptic.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_CopticDate_until_CopticDate(CopticDate coptic, LocalDate iso) { - assertEquals(coptic.until(coptic), CopticChronology.INSTANCE.period(0, 0, 0)); + assertEquals(CopticChronology.INSTANCE.period(0, 0, 0), coptic.until(coptic)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_CopticDate_until_LocalDate(CopticDate coptic, LocalDate iso) { - assertEquals(coptic.until(iso), CopticChronology.INSTANCE.period(0, 0, 0)); + assertEquals(CopticChronology.INSTANCE.period(0, 0, 0), coptic.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_CopticDate(CopticDate coptic, LocalDate iso) { - assertEquals(iso.until(coptic), Period.ZERO); + assertEquals(Period.ZERO, iso.until(coptic)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(CopticDate coptic, LocalDate iso) { - assertEquals(CopticChronology.INSTANCE.date(iso), coptic); + assertEquals(coptic, CopticChronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(CopticDate coptic, LocalDate iso) { - assertEquals(LocalDate.from(coptic.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(coptic.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(coptic.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(coptic.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(coptic.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(coptic.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(coptic.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(coptic.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(coptic.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(coptic.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(CopticDate coptic, LocalDate iso) { - assertEquals(LocalDate.from(coptic.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(coptic.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(coptic.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(coptic.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(coptic.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(coptic.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(coptic.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(coptic.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(coptic.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(coptic.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(CopticDate coptic, LocalDate iso) { - assertEquals(coptic.until(iso.plusDays(0), DAYS), 0); - assertEquals(coptic.until(iso.plusDays(1), DAYS), 1); - assertEquals(coptic.until(iso.plusDays(35), DAYS), 35); - assertEquals(coptic.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, coptic.until(iso.plusDays(0), DAYS)); + assertEquals(1, coptic.until(iso.plusDays(1), DAYS)); + assertEquals(35, coptic.until(iso.plusDays(35), DAYS)); + assertEquals(-40, coptic.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {1728, 0, 0}, @@ -230,14 +242,15 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - CopticDate.of(year, month, dom); + assertThrows(DateTimeException.class, () -> CopticDate.of(year, month, dom)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_chronology_dateYearDay_badDate() { - CopticChronology.INSTANCE.dateYearDay(1728, 366); + assertThrows(DateTimeException.class, () -> CopticChronology.INSTANCE.dateYearDay(1728, 366)); } //----------------------------------------------------------------------- @@ -247,32 +260,31 @@ public void test_chronology_dateYearDay_badDate() { public void test_isLeapYear_loop() { for (int year = -200; year < 200; year++) { CopticDate base = CopticDate.of(year, 1, 1); - assertEquals(base.isLeapYear(), ((year - 3) % 4) == 0); - assertEquals(CopticChronology.INSTANCE.isLeapYear(year), ((year + 400 - 3) % 4) == 0); + assertEquals(((year - 3) % 4) == 0, base.isLeapYear()); + assertEquals(((year + 400 - 3) % 4) == 0, CopticChronology.INSTANCE.isLeapYear(year)); } } @Test public void test_isLeapYear_specific() { - assertEquals(CopticChronology.INSTANCE.isLeapYear(8), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(7), true); - assertEquals(CopticChronology.INSTANCE.isLeapYear(6), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(5), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(4), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(3), true); - assertEquals(CopticChronology.INSTANCE.isLeapYear(2), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(1), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(0), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(-1), true); - assertEquals(CopticChronology.INSTANCE.isLeapYear(-2), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(-3), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(-4), false); - assertEquals(CopticChronology.INSTANCE.isLeapYear(-5), true); - assertEquals(CopticChronology.INSTANCE.isLeapYear(-6), false); - } - - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(8)); + assertEquals(true, CopticChronology.INSTANCE.isLeapYear(7)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(6)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(5)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(4)); + assertEquals(true, CopticChronology.INSTANCE.isLeapYear(3)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(2)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(1)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(0)); + assertEquals(true, CopticChronology.INSTANCE.isLeapYear(-1)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(-2)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(-3)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(-4)); + assertEquals(true, CopticChronology.INSTANCE.isLeapYear(-5)); + assertEquals(false, CopticChronology.INSTANCE.isLeapYear(-6)); + } + + public static Object[][] data_lengthOfMonth() { return new Object[][] { {1726, 1, 30}, {1726, 2, 30}, @@ -291,9 +303,10 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int length) { - assertEquals(CopticDate.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, CopticDate.of(year, month, 1).lengthOfMonth()); } //----------------------------------------------------------------------- @@ -309,7 +322,7 @@ public void test_era_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); CopticDate eraBased = CopticChronology.INSTANCE.date(era, yoe, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -323,39 +336,39 @@ public void test_era_yearDay_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); CopticDate eraBased = CopticChronology.INSTANCE.dateYearDay(era, yoe, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(CopticChronology.INSTANCE.prolepticYear(CopticEra.AM, 4), 4); - assertEquals(CopticChronology.INSTANCE.prolepticYear(CopticEra.AM, 3), 3); - assertEquals(CopticChronology.INSTANCE.prolepticYear(CopticEra.AM, 2), 2); - assertEquals(CopticChronology.INSTANCE.prolepticYear(CopticEra.AM, 1), 1); - assertEquals(CopticChronology.INSTANCE.prolepticYear(CopticEra.BEFORE_AM, 1), 0); - assertEquals(CopticChronology.INSTANCE.prolepticYear(CopticEra.BEFORE_AM, 2), -1); - assertEquals(CopticChronology.INSTANCE.prolepticYear(CopticEra.BEFORE_AM, 3), -2); - assertEquals(CopticChronology.INSTANCE.prolepticYear(CopticEra.BEFORE_AM, 4), -3); + assertEquals(4, CopticChronology.INSTANCE.prolepticYear(CopticEra.AM, 4)); + assertEquals(3, CopticChronology.INSTANCE.prolepticYear(CopticEra.AM, 3)); + assertEquals(2, CopticChronology.INSTANCE.prolepticYear(CopticEra.AM, 2)); + assertEquals(1, CopticChronology.INSTANCE.prolepticYear(CopticEra.AM, 1)); + assertEquals(0, CopticChronology.INSTANCE.prolepticYear(CopticEra.BEFORE_AM, 1)); + assertEquals(-1, CopticChronology.INSTANCE.prolepticYear(CopticEra.BEFORE_AM, 2)); + assertEquals(-2, CopticChronology.INSTANCE.prolepticYear(CopticEra.BEFORE_AM, 3)); + assertEquals(-3, CopticChronology.INSTANCE.prolepticYear(CopticEra.BEFORE_AM, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(CopticChronology.INSTANCE.eraOf(1), CopticEra.AM); - assertEquals(CopticChronology.INSTANCE.eraOf(0), CopticEra.BEFORE_AM); + assertEquals(CopticEra.AM, CopticChronology.INSTANCE.eraOf(1)); + assertEquals(CopticEra.BEFORE_AM, CopticChronology.INSTANCE.eraOf(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - CopticChronology.INSTANCE.eraOf(2); + assertThrows(DateTimeException.class, () -> CopticChronology.INSTANCE.eraOf(2)); } @Test public void test_Chronology_eras() { List eras = CopticChronology.INSTANCE.eras(); - assertEquals(eras.size(), 2); - assertEquals(eras.contains(CopticEra.BEFORE_AM), true); - assertEquals(eras.contains(CopticEra.AM), true); + assertEquals(2, eras.size()); + assertEquals(true, eras.contains(CopticEra.BEFORE_AM)); + assertEquals(true, eras.contains(CopticEra.AM)); } //----------------------------------------------------------------------- @@ -363,17 +376,16 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(CopticChronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(1, 7)); - assertEquals(CopticChronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 5, 30)); - assertEquals(CopticChronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 365, 366)); - assertEquals(CopticChronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 13)); + assertEquals(ValueRange.of(1, 7), CopticChronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 5, 30), CopticChronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 365, 366), CopticChronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(1, 13), CopticChronology.INSTANCE.range(MONTH_OF_YEAR)); } //----------------------------------------------------------------------- // CopticDate.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { {1727, 1, 23, DAY_OF_MONTH, 1, 30}, {1727, 2, 23, DAY_OF_MONTH, 1, 30}, @@ -401,21 +413,21 @@ Object[][] data_ranges() { }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, int expectedMin, int expectedMax) { - assertEquals(CopticDate.of(year, month, dom).range(field), ValueRange.of(expectedMin, expectedMax)); + assertEquals(ValueRange.of(expectedMin, expectedMax), CopticDate.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - CopticDate.of(1727, 6, 30).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> CopticDate.of(1727, 6, 30).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // CopticDate.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {1727, 6, 8, DAY_OF_WEEK, 2}, {1727, 6, 8, DAY_OF_MONTH, 8}, @@ -435,21 +447,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(CopticDate.of(year, month, dom).getLong(field), expected); + assertEquals(expected, CopticDate.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - CopticDate.of(1727, 6, 30).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> CopticDate.of(1727, 6, 30).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // CopticDate.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {1727, 6, 8, DAY_OF_WEEK, 4, 1727, 6, 10}, {1727, 6, 8, DAY_OF_WEEK, 2, 1727, 6, 8}, @@ -484,16 +496,17 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(CopticDate.of(year, month, dom).with(field, value), CopticDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(CopticDate.of(expectedYear, expectedMonth, expectedDom), CopticDate.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - CopticDate.of(1727, 6, 30).with(MINUTE_OF_DAY, 0); + assertThrows(UnsupportedTemporalTypeException.class, () -> CopticDate.of(1727, 6, 30).with(MINUTE_OF_DAY, 0)); } //----------------------------------------------------------------------- @@ -503,14 +516,14 @@ public void test_with_TemporalField_unsupported() { public void test_adjust1() { CopticDate base = CopticDate.of(1728, 10, 29); CopticDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, CopticDate.of(1728, 10, 30)); + assertEquals(CopticDate.of(1728, 10, 30), test); } @Test public void test_adjust2() { CopticDate base = CopticDate.of(1728, 13, 2); CopticDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, CopticDate.of(1728, 13, 5)); + assertEquals(CopticDate.of(1728, 13, 5), test); } //----------------------------------------------------------------------- @@ -520,13 +533,13 @@ public void test_adjust2() { public void test_adjust_toLocalDate() { CopticDate coptic = CopticDate.of(1726, 1, 4); CopticDate test = coptic.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, CopticDate.of(1728, 10, 29)); + assertEquals(CopticDate.of(1728, 10, 29), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { CopticDate coptic = CopticDate.of(1726, 1, 4); - coptic.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> coptic.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -536,21 +549,20 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToCopticDate() { CopticDate coptic = CopticDate.of(1728, 10, 29); LocalDate test = LocalDate.MIN.with(coptic); - assertEquals(test, LocalDate.of(2012, 7, 6)); + assertEquals(LocalDate.of(2012, 7, 6), test); } @Test public void test_LocalDateTime_adjustToCopticDate() { CopticDate coptic = CopticDate.of(1728, 10, 29); LocalDateTime test = LocalDateTime.MIN.with(coptic); - assertEquals(test, LocalDateTime.of(2012, 7, 6, 0, 0)); + assertEquals(LocalDateTime.of(2012, 7, 6, 0, 0), test); } //----------------------------------------------------------------------- // CopticDate.plus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {1726, 5, 26, 0, DAYS, 1726, 5, 26}, {1726, 5, 26, 8, DAYS, 1726, 6, 4}, @@ -577,52 +589,53 @@ Object[][] data_plus() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(CopticDate.of(year, month, dom).plus(amount, unit), CopticDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(CopticDate.of(expectedYear, expectedMonth, expectedDom), CopticDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(CopticDate.of(year, month, dom).minus(amount, unit), CopticDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(CopticDate.of(expectedYear, expectedMonth, expectedDom), CopticDate.of(year, month, dom).minus(amount, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - CopticDate.of(1727, 6, 30).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> CopticDate.of(1727, 6, 30).plus(0, MINUTES)); } //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(CopticDate.of(1727, 5, 26).plus(CopticChronology.INSTANCE.period(0, 2, 3)), CopticDate.of(1727, 7, 29)); + assertEquals(CopticDate.of(1727, 7, 29), CopticDate.of(1727, 5, 26).plus(CopticChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(CopticDate.of(1727, 5, 26).plus(Period.ofMonths(2)), CopticDate.of(1727, 7, 26)); + assertThrows(DateTimeException.class, () -> CopticDate.of(1727, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(CopticDate.of(1727, 5, 26).minus(CopticChronology.INSTANCE.period(0, 2, 3)), CopticDate.of(1727, 3, 23)); + assertEquals(CopticDate.of(1727, 3, 23), CopticDate.of(1727, 5, 26).minus(CopticChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(CopticDate.of(1727, 5, 26).minus(Period.ofMonths(2)), CopticDate.of(1727, 3, 26)); + assertThrows(DateTimeException.class, () -> CopticDate.of(1727, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- // CopticDate.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {1726, 5, 26, 1726, 5, 26, DAYS, 0}, {1726, 5, 26, 1726, 6, 1, DAYS, 5}, @@ -648,51 +661,41 @@ Object[][] data_until() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { CopticDate start = CopticDate.of(year1, month1, dom1); CopticDate end = CopticDate.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { CopticDate start = CopticDate.of(1726, 6, 30); CopticDate end = CopticDate.of(1726, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - void test_equals() { - CopticDate a1 = CopticDate.of(1728, 1, 3); - CopticDate a2 = CopticDate.of(1728, 1, 3); - CopticDate b = CopticDate.of(1728, 1, 4); - CopticDate c = CopticDate.of(1728, 2, 3); - CopticDate d = CopticDate.of(1729, 1, 3); - - assertEquals(a1.equals(a1), true); - assertEquals(a1.equals(a2), true); - assertEquals(a1.equals(b), false); - assertEquals(a1.equals(c), false); - assertEquals(a1.equals(d), false); - - assertEquals(a1.equals(null), false); - assertEquals(a1.equals(""), false); - - assertEquals(a1.hashCode(), a2.hashCode()); + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(CopticDate.of(1728, 1, 3), CopticDate.of(1728, 1, 3)) + .addEqualityGroup(CopticDate.of(1728, 1, 4), CopticDate.of(1728, 1, 4)) + .addEqualityGroup(CopticDate.of(1728, 2, 3), CopticDate.of(1728, 2, 3)) + .addEqualityGroup(CopticDate.of(1729, 1, 3), CopticDate.of(1729, 1, 3)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {CopticDate.of(1, 1, 1), "Coptic AM 1-01-01"}, {CopticDate.of(1728, 10, 28), "Coptic AM 1728-10-28"}, @@ -702,9 +705,10 @@ Object[][] data_toString() { }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(CopticDate coptic, String expected) { - assertEquals(coptic.toString(), expected); + assertEquals(expected, coptic.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestDiscordianChronology.java b/src/test/java/org/threeten/extra/chrono/TestDiscordianChronology.java index 915e3bb8..ab5763ea 100644 --- a/src/test/java/org/threeten/extra/chrono/TestDiscordianChronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestDiscordianChronology.java @@ -54,7 +54,9 @@ import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.time.DateTimeException; import java.time.LocalDate; @@ -71,16 +73,17 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.List; -import java.util.function.Predicate; +import java.util.function.IntPredicate; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test public class TestDiscordianChronology { //----------------------------------------------------------------------- @@ -89,26 +92,25 @@ public class TestDiscordianChronology { @Test public void test_chronology_of_name() { Chronology chrono = Chronology.of("Discordian"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, DiscordianChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Discordian"); - Assert.assertEquals(chrono.getCalendarType(), "discordian"); + assertNotNull(chrono); + assertEquals(DiscordianChronology.INSTANCE, chrono); + assertEquals("Discordian", chrono.getId()); + assertEquals("discordian", chrono.getCalendarType()); } @Test public void test_chronology_of_name_id() { Chronology chrono = Chronology.of("discordian"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, DiscordianChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Discordian"); - Assert.assertEquals(chrono.getCalendarType(), "discordian"); + assertNotNull(chrono); + assertEquals(DiscordianChronology.INSTANCE, chrono); + assertEquals("Discordian", chrono.getId()); + assertEquals("discordian", chrono.getCalendarType()); } //----------------------------------------------------------------------- // creation, toLocalDate() //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { {DiscordianDate.of(2, 1, 1), LocalDate.of(-1164, 1, 1)}, {DiscordianDate.of(166, 1, 1), LocalDate.of(-1000, 1, 1)}, @@ -148,74 +150,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_DiscordianDate(DiscordianDate discordian, LocalDate iso) { - assertEquals(LocalDate.from(discordian), iso); + assertEquals(iso, LocalDate.from(discordian)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_DiscordianDate_from_LocalDate(DiscordianDate discordian, LocalDate iso) { - assertEquals(DiscordianDate.from(iso), discordian); + assertEquals(discordian, DiscordianDate.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_DiscordianDate_chronology_dateEpochDay(DiscordianDate discordian, LocalDate iso) { - assertEquals(DiscordianChronology.INSTANCE.dateEpochDay(iso.toEpochDay()), discordian); + assertEquals(discordian, DiscordianChronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_DiscordianDate_toEpochDay(DiscordianDate discordian, LocalDate iso) { - assertEquals(discordian.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), discordian.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_DiscordianDate_until_DiscordianDate(DiscordianDate discordian, LocalDate iso) { - assertEquals(discordian.until(discordian), DiscordianChronology.INSTANCE.period(0, 0, 0)); + assertEquals(DiscordianChronology.INSTANCE.period(0, 0, 0), discordian.until(discordian)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_DiscordianDate_until_LocalDate(DiscordianDate discordian, LocalDate iso) { - assertEquals(discordian.until(iso), DiscordianChronology.INSTANCE.period(0, 0, 0)); + assertEquals(DiscordianChronology.INSTANCE.period(0, 0, 0), discordian.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_DiscordianDate(DiscordianDate discordian, LocalDate iso) { - assertEquals(iso.until(discordian), Period.ZERO); + assertEquals(Period.ZERO, iso.until(discordian)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(DiscordianDate discordian, LocalDate iso) { - assertEquals(DiscordianChronology.INSTANCE.date(iso), discordian); + assertEquals(discordian, DiscordianChronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(DiscordianDate discordian, LocalDate iso) { - assertEquals(LocalDate.from(discordian.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(discordian.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(discordian.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(discordian.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(discordian.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(discordian.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(discordian.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(discordian.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(discordian.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(discordian.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(DiscordianDate discordian, LocalDate iso) { - assertEquals(LocalDate.from(discordian.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(discordian.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(discordian.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(discordian.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(discordian.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(discordian.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(discordian.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(discordian.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(discordian.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(discordian.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(DiscordianDate discordian, LocalDate iso) { - assertEquals(discordian.until(iso.plusDays(0), DAYS), 0); - assertEquals(discordian.until(iso.plusDays(1), DAYS), 1); - assertEquals(discordian.until(iso.plusDays(35), DAYS), 35); - assertEquals(discordian.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, discordian.until(iso.plusDays(0), DAYS)); + assertEquals(1, discordian.until(iso.plusDays(1), DAYS)); + assertEquals(35, discordian.until(iso.plusDays(35), DAYS)); + assertEquals(-40, discordian.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {1900, 0, 0}, @@ -240,14 +252,15 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - DiscordianDate.of(year, month, dom); + assertThrows(DateTimeException.class, () -> DiscordianDate.of(year, month, dom)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_chronology_dateYearDay_badDate() { - DiscordianChronology.INSTANCE.dateYearDay(2001, 366); + assertThrows(DateTimeException.class, () -> DiscordianChronology.INSTANCE.dateYearDay(2001, 366)); } //----------------------------------------------------------------------- @@ -255,38 +268,37 @@ public void test_chronology_dateYearDay_badDate() { //----------------------------------------------------------------------- @Test public void test_isLeapYear_loop() { - Predicate isLeapYear = year -> { + IntPredicate isLeapYear = year -> { int offsetYear = year - 1166; return offsetYear % 4 == 0 && (offsetYear % 400 == 0 || offsetYear % 100 != 0); }; for (int year = 1066; year < 1567; year++) { DiscordianDate base = DiscordianDate.of(year, 1, 1); - assertEquals(base.isLeapYear(), isLeapYear.test(year), "Mismatch on " + year); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(year), isLeapYear.test(year), "Mismatch on " + year); + assertEquals(isLeapYear.test(year), base.isLeapYear()); + assertEquals(isLeapYear.test(year), DiscordianChronology.INSTANCE.isLeapYear(year)); } } @Test public void test_isLeapYear_specific() { - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1174), true); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1173), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1172), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1171), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1170), true); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1169), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1168), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1167), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1166), true); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1165), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1164), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1163), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1162), true); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1161), false); - assertEquals(DiscordianChronology.INSTANCE.isLeapYear(1160), false); - } - - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + assertEquals(true, DiscordianChronology.INSTANCE.isLeapYear(1174)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1173)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1172)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1171)); + assertEquals(true, DiscordianChronology.INSTANCE.isLeapYear(1170)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1169)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1168)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1167)); + assertEquals(true, DiscordianChronology.INSTANCE.isLeapYear(1166)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1165)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1164)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1163)); + assertEquals(true, DiscordianChronology.INSTANCE.isLeapYear(1162)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1161)); + assertEquals(false, DiscordianChronology.INSTANCE.isLeapYear(1160)); + } + + public static Object[][] data_lengthOfMonth() { return new Object[][] { {1900, 1, 73}, {1900, 2, 73}, @@ -303,16 +315,17 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int length) { - assertEquals(DiscordianDate.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, DiscordianDate.of(year, month, 1).lengthOfMonth()); } @Test public void test_lengthOfMonth_specific() { - assertEquals(DiscordianDate.of(3178, 0, 0).lengthOfMonth(), 1); - assertEquals(DiscordianDate.of(3178, 1, 1).lengthOfMonth(), 73); - assertEquals(DiscordianDate.of(3178, 1, 73).lengthOfMonth(), 73); + assertEquals(1, DiscordianDate.of(3178, 0, 0).lengthOfMonth()); + assertEquals(73, DiscordianDate.of(3178, 1, 1).lengthOfMonth()); + assertEquals(73, DiscordianDate.of(3178, 1, 73).lengthOfMonth()); } //----------------------------------------------------------------------- @@ -326,7 +339,7 @@ public void test_era_loop() { assertEquals(DiscordianEra.YOLD, base.getEra()); assertEquals(year, base.get(YEAR_OF_ERA)); DiscordianDate eraBased = DiscordianChronology.INSTANCE.date(DiscordianEra.YOLD, year, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -338,39 +351,39 @@ public void test_era_yearDay_loop() { assertEquals(DiscordianEra.YOLD, base.getEra()); assertEquals(year, base.get(YEAR_OF_ERA)); DiscordianDate eraBased = DiscordianChronology.INSTANCE.dateYearDay(DiscordianEra.YOLD, year, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(DiscordianChronology.INSTANCE.prolepticYear(DiscordianEra.YOLD, 4), 4); - assertEquals(DiscordianChronology.INSTANCE.prolepticYear(DiscordianEra.YOLD, 3), 3); - assertEquals(DiscordianChronology.INSTANCE.prolepticYear(DiscordianEra.YOLD, 2), 2); - assertEquals(DiscordianChronology.INSTANCE.prolepticYear(DiscordianEra.YOLD, 1), 1); + assertEquals(4, DiscordianChronology.INSTANCE.prolepticYear(DiscordianEra.YOLD, 4)); + assertEquals(3, DiscordianChronology.INSTANCE.prolepticYear(DiscordianEra.YOLD, 3)); + assertEquals(2, DiscordianChronology.INSTANCE.prolepticYear(DiscordianEra.YOLD, 2)); + assertEquals(1, DiscordianChronology.INSTANCE.prolepticYear(DiscordianEra.YOLD, 1)); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void test_prolepticYear_badEra() { - DiscordianChronology.INSTANCE.prolepticYear(IsoEra.CE, 4); + assertThrows(ClassCastException.class, () -> DiscordianChronology.INSTANCE.prolepticYear(IsoEra.CE, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(DiscordianChronology.INSTANCE.eraOf(1), DiscordianEra.YOLD); + assertEquals(DiscordianEra.YOLD, DiscordianChronology.INSTANCE.eraOf(1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - DiscordianChronology.INSTANCE.eraOf(2); - DiscordianChronology.INSTANCE.eraOf(0); + assertThrows(DateTimeException.class, () -> DiscordianChronology.INSTANCE.eraOf(2)); + assertThrows(DateTimeException.class, () -> DiscordianChronology.INSTANCE.eraOf(0)); } @Test public void test_Chronology_eras() { List eras = DiscordianChronology.INSTANCE.eras(); - assertEquals(eras.size(), 1); - assertEquals(eras.contains(DiscordianEra.YOLD), true); + assertEquals(1, eras.size()); + assertEquals(true, eras.contains(DiscordianEra.YOLD)); } //----------------------------------------------------------------------- @@ -378,26 +391,25 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(DiscordianChronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_MONTH), ValueRange.of(0, 1, 0, 5)); - assertEquals(DiscordianChronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_YEAR), ValueRange.of(0, 1, 5, 5)); - assertEquals(DiscordianChronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH), ValueRange.of(0, 1, 0, 15)); - assertEquals(DiscordianChronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR), ValueRange.of(0, 1, 73, 73)); - assertEquals(DiscordianChronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(0, 1, 0, 5)); - assertEquals(DiscordianChronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(0, 1, 0, 73)); - assertEquals(DiscordianChronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 365, 366)); - assertEquals(DiscordianChronology.INSTANCE.range(EPOCH_DAY), ValueRange.of(-1_145_400, 999_999 * 365L + 242_499)); - assertEquals(DiscordianChronology.INSTANCE.range(ERA), ValueRange.of(1, 1)); - assertEquals(DiscordianChronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(0, 1, 5, 5)); - assertEquals(DiscordianChronology.INSTANCE.range(PROLEPTIC_MONTH), ValueRange.of(0, 999_999 * 5L + 5 - 1)); - assertEquals(DiscordianChronology.INSTANCE.range(YEAR), ValueRange.of(1, 999_999)); - assertEquals(DiscordianChronology.INSTANCE.range(YEAR_OF_ERA), ValueRange.of(1, 999_999)); + assertEquals(ValueRange.of(0, 1, 0, 5), DiscordianChronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(ValueRange.of(0, 1, 5, 5), DiscordianChronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(ValueRange.of(0, 1, 0, 15), DiscordianChronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH)); + assertEquals(ValueRange.of(0, 1, 73, 73), DiscordianChronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR)); + assertEquals(ValueRange.of(0, 1, 0, 5), DiscordianChronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(0, 1, 0, 73), DiscordianChronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 365, 366), DiscordianChronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(-1_145_400, 999_999 * 365L + 242_499), DiscordianChronology.INSTANCE.range(EPOCH_DAY)); + assertEquals(ValueRange.of(1, 1), DiscordianChronology.INSTANCE.range(ERA)); + assertEquals(ValueRange.of(0, 1, 5, 5), DiscordianChronology.INSTANCE.range(MONTH_OF_YEAR)); + assertEquals(ValueRange.of(0, 999_999 * 5L + 5 - 1), DiscordianChronology.INSTANCE.range(PROLEPTIC_MONTH)); + assertEquals(ValueRange.of(1, 999_999), DiscordianChronology.INSTANCE.range(YEAR)); + assertEquals(ValueRange.of(1, 999_999), DiscordianChronology.INSTANCE.range(YEAR_OF_ERA)); } //----------------------------------------------------------------------- // DiscordianDate.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { // St Tibs is in its own month, so (0 to 0) or (1 to 73) {2010, 0, 0, DAY_OF_MONTH, 0, 0}, @@ -438,21 +450,21 @@ Object[][] data_ranges() { }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, int expectedMin, int expectedMax) { - assertEquals(DiscordianDate.of(year, month, dom).range(field), ValueRange.of(expectedMin, expectedMax)); + assertEquals(ValueRange.of(expectedMin, expectedMax), DiscordianDate.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - DiscordianDate.of(2012, 5, 30).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> DiscordianDate.of(2012, 5, 30).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // DiscordianDate.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {2014, 1, 26, DAY_OF_WEEK, 1}, {2014, 1, 26, DAY_OF_MONTH, 26}, @@ -491,21 +503,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(DiscordianDate.of(year, month, dom).getLong(field), expected); + assertEquals(expected, DiscordianDate.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - DiscordianDate.of(2012, 1, 30).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> DiscordianDate.of(2012, 1, 30).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // DiscordianDate.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 1, 2014, 5, 24}, {2014, 5, 26, DAY_OF_WEEK, 3, 2014, 5, 26}, @@ -579,15 +591,15 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(DiscordianDate.of(year, month, dom).with(field, value), DiscordianDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(DiscordianDate.of(expectedYear, expectedMonth, expectedDom), DiscordianDate.of(year, month, dom).with(field, value)); } - @DataProvider(name = "withBad") - Object[][] data_with_bad() { + public static Object[][] data_with_bad() { return new Object[][] { {2013, 1, 1, DAY_OF_WEEK, 0}, {2013, 1, 1, DAY_OF_WEEK, 6}, @@ -611,14 +623,15 @@ Object[][] data_with_bad() { }; } - @Test(dataProvider = "withBad", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_with_bad") public void test_with_TemporalField_badValue(int year, int month, int dom, TemporalField field, long value) { - DiscordianDate.of(year, month, dom).with(field, value); + assertThrows(DateTimeException.class, () -> DiscordianDate.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - DiscordianDate.of(2012, 5, 30).with(MINUTE_OF_DAY, 0); + assertThrows(UnsupportedTemporalTypeException.class, () -> DiscordianDate.of(2012, 5, 30).with(MINUTE_OF_DAY, 0)); } //----------------------------------------------------------------------- @@ -628,14 +641,14 @@ public void test_with_TemporalField_unsupported() { public void test_adjust1() { DiscordianDate base = DiscordianDate.of(2014, 0, 0); DiscordianDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, DiscordianDate.of(2014, 0, 0)); + assertEquals(DiscordianDate.of(2014, 0, 0), test); } @Test public void test_adjust2() { DiscordianDate base = DiscordianDate.of(2012, 2, 23); DiscordianDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, DiscordianDate.of(2012, 2, 73)); + assertEquals(DiscordianDate.of(2012, 2, 73), test); } //----------------------------------------------------------------------- @@ -645,13 +658,13 @@ public void test_adjust2() { public void test_adjust_toLocalDate() { DiscordianDate discordian = DiscordianDate.of(2000, 1, 4); DiscordianDate test = discordian.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, DiscordianDate.of(3178, 3, 41)); + assertEquals(DiscordianDate.of(3178, 3, 41), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { DiscordianDate discordian = DiscordianDate.of(2000, 1, 4); - discordian.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> discordian.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -661,21 +674,20 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToDiscordianDate() { DiscordianDate discordian = DiscordianDate.of(3178, 3, 41); LocalDate test = LocalDate.MIN.with(discordian); - assertEquals(test, LocalDate.of(2012, 7, 6)); + assertEquals(LocalDate.of(2012, 7, 6), test); } @Test public void test_LocalDateTime_adjustToDiscordianDate() { DiscordianDate discordian = DiscordianDate.of(3178, 3, 41); LocalDateTime test = LocalDateTime.MIN.with(discordian); - assertEquals(test, LocalDateTime.of(2012, 7, 6, 0, 0)); + assertEquals(LocalDateTime.of(2012, 7, 6, 0, 0), test); } //----------------------------------------------------------------------- // DiscordianDate.plus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {2014, 5, 26, 0, DAYS, 2014, 5, 26}, {2014, 5, 26, 8, DAYS, 2014, 5, 34}, @@ -701,8 +713,7 @@ Object[][] data_plus() { }; } - @DataProvider(name = "plus_leap") - Object[][] data_plus_leap() { + public static Object[][] data_plus_leap() { return new Object[][] { {2014, 0, 0, 0, DAYS, 2014, 0, 0}, {2014, 0, 0, 8, DAYS, 2014, 1, 67}, @@ -722,8 +733,7 @@ Object[][] data_plus_leap() { }; } - @DataProvider(name = "minus_leap") - Object[][] data_minus_leap() { + public static Object[][] data_minus_leap() { return new Object[][] { {2014, 0, 0, 0, DAYS, 2014, 0, 0}, {2014, 1, 52, 8, DAYS, 2014, 0, 0}, @@ -743,46 +753,49 @@ Object[][] data_minus_leap() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(DiscordianDate.of(year, month, dom).plus(amount, unit), DiscordianDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(DiscordianDate.of(expectedYear, expectedMonth, expectedDom), DiscordianDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus_leap") + @ParameterizedTest + @MethodSource("data_plus_leap") public void test_plus_leap_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(DiscordianDate.of(year, month, dom).plus(amount, unit), DiscordianDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(DiscordianDate.of(expectedYear, expectedMonth, expectedDom), DiscordianDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(DiscordianDate.of(year, month, dom).minus(amount, unit), DiscordianDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(DiscordianDate.of(expectedYear, expectedMonth, expectedDom), DiscordianDate.of(year, month, dom).minus(amount, unit)); } - @Test(dataProvider = "minus_leap") + @ParameterizedTest + @MethodSource("data_minus_leap") public void test_minus_leap_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(DiscordianDate.of(year, month, dom).minus(amount, unit), DiscordianDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(DiscordianDate.of(expectedYear, expectedMonth, expectedDom), DiscordianDate.of(year, month, dom).minus(amount, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - DiscordianDate.of(2012, 5, 30).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> DiscordianDate.of(2012, 5, 30).plus(0, MINUTES)); } //----------------------------------------------------------------------- // DiscordianDate.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, DAYS, 0}, {2014, 5, 26, 2014, 5, 32, DAYS, 6}, @@ -847,8 +860,7 @@ Object[][] data_until() { }; } - @DataProvider(name = "until_period") - Object[][] data_until_period() { + public static Object[][] data_until_period() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, 0, 0, 0}, {2014, 5, 26, 2014, 5, 32, 0, 0, 6}, @@ -893,17 +905,19 @@ Object[][] data_until_period() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { DiscordianDate start = DiscordianDate.of(year1, month1, dom1); DiscordianDate end = DiscordianDate.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(dataProvider = "until_period") + @ParameterizedTest + @MethodSource("data_until_period") public void test_until_end( int year1, int month1, int dom1, int year2, int month2, int dom2, @@ -911,65 +925,54 @@ public void test_until_end( DiscordianDate start = DiscordianDate.of(year1, month1, dom1); DiscordianDate end = DiscordianDate.of(year2, month2, dom2); ChronoPeriod period = DiscordianChronology.INSTANCE.period(yearPeriod, monthPeriod, domPeriod); - assertEquals(start.until(end), period); + assertEquals(period, start.until(end)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { DiscordianDate start = DiscordianDate.of(2012, 1, 30); DiscordianDate end = DiscordianDate.of(2012, 2, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(DiscordianDate.of(2014, 5, 26).plus(DiscordianChronology.INSTANCE.period(0, 2, 3)), DiscordianDate.of(2015, 2, 29)); + assertEquals(DiscordianDate.of(2015, 2, 29), DiscordianDate.of(2014, 5, 26).plus(DiscordianChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(DiscordianDate.of(2014, 5, 26).plus(Period.ofMonths(2)), DiscordianDate.of(2015, 2, 26)); + assertThrows(DateTimeException.class, () -> DiscordianDate.of(2014, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(DiscordianDate.of(2014, 5, 26).minus(DiscordianChronology.INSTANCE.period(0, 2, 3)), DiscordianDate.of(2014, 3, 23)); + assertEquals(DiscordianDate.of(2014, 3, 23), DiscordianDate.of(2014, 5, 26).minus(DiscordianChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(DiscordianDate.of(2014, 5, 26).minus(Period.ofMonths(2)), DiscordianDate.of(2014, 3, 26)); + assertThrows(DateTimeException.class, () -> DiscordianDate.of(2014, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - void test_equals() { - DiscordianDate a1 = DiscordianDate.of(2000, 1, 3); - DiscordianDate a2 = DiscordianDate.of(2000, 1, 3); - DiscordianDate b = DiscordianDate.of(2000, 1, 4); - DiscordianDate c = DiscordianDate.of(2000, 2, 3); - DiscordianDate d = DiscordianDate.of(2001, 1, 3); - - assertEquals(a1.equals(a1), true); - assertEquals(a1.equals(a2), true); - assertEquals(a1.equals(b), false); - assertEquals(a1.equals(c), false); - assertEquals(a1.equals(d), false); - - assertEquals(a1.equals(null), false); - assertEquals(a1.equals(""), false); - - assertEquals(a1.hashCode(), a2.hashCode()); + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(DiscordianDate.of(2000, 1, 3), DiscordianDate.of(2000, 1, 3)) + .addEqualityGroup(DiscordianDate.of(2000, 1, 4), DiscordianDate.of(2000, 1, 4)) + .addEqualityGroup(DiscordianDate.of(2000, 2, 3), DiscordianDate.of(2000, 2, 3)) + .addEqualityGroup(DiscordianDate.of(2001, 1, 3), DiscordianDate.of(2001, 1, 3)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {DiscordianDate.of(1, 1, 1), "Discordian YOLD 1-1-01"}, {DiscordianDate.of(2012, 5, 23), "Discordian YOLD 2012-5-23"}, @@ -977,9 +980,10 @@ Object[][] data_toString() { }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(DiscordianDate discordian, String expected) { - assertEquals(discordian.toString(), expected); + assertEquals(expected, discordian.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestEthiopicChronology.java b/src/test/java/org/threeten/extra/chrono/TestEthiopicChronology.java index e93d3822..6be2f05a 100644 --- a/src/test/java/org/threeten/extra/chrono/TestEthiopicChronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestEthiopicChronology.java @@ -53,7 +53,9 @@ import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.time.DateTimeException; import java.time.LocalDate; @@ -70,14 +72,15 @@ import java.time.temporal.WeekFields; import java.util.List; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test public class TestEthiopicChronology { //----------------------------------------------------------------------- @@ -86,26 +89,25 @@ public class TestEthiopicChronology { @Test public void test_chronology_of_name() { Chronology chrono = Chronology.of("Ethiopic"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, EthiopicChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Ethiopic"); - Assert.assertEquals(chrono.getCalendarType(), "ethiopic"); + assertNotNull(chrono); + assertEquals(EthiopicChronology.INSTANCE, chrono); + assertEquals("Ethiopic", chrono.getId()); + assertEquals("ethiopic", chrono.getCalendarType()); } @Test public void test_chronology_of_name_id() { Chronology chrono = Chronology.of("ethiopic"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, EthiopicChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Ethiopic"); - Assert.assertEquals(chrono.getCalendarType(), "ethiopic"); + assertNotNull(chrono); + assertEquals(EthiopicChronology.INSTANCE, chrono); + assertEquals("Ethiopic", chrono.getId()); + assertEquals("ethiopic", chrono.getCalendarType()); } //----------------------------------------------------------------------- // creation, toLocalDate() //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { {EthiopicDate.of(-1, 13, 6), LocalDate.of(7, 8, 27)}, {EthiopicDate.of(0, 1, 1), LocalDate.of(7, 8, 28)}, @@ -133,74 +135,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_EthiopicDate(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(LocalDate.from(ethiopic), iso); + assertEquals(iso, LocalDate.from(ethiopic)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_EthiopicDate_from_LocalDate(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(EthiopicDate.from(iso), ethiopic); + assertEquals(ethiopic, EthiopicDate.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_EthiopicDate_chronology_dateEpochDay(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(EthiopicChronology.INSTANCE.dateEpochDay(iso.toEpochDay()), ethiopic); + assertEquals(ethiopic, EthiopicChronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_EthiopicDate_toEpochDay(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(ethiopic.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), ethiopic.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_EthiopicDate_until_EthiopicDate(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(ethiopic.until(ethiopic), EthiopicChronology.INSTANCE.period(0, 0, 0)); + assertEquals(EthiopicChronology.INSTANCE.period(0, 0, 0), ethiopic.until(ethiopic)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_EthiopicDate_until_LocalDate(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(ethiopic.until(iso), EthiopicChronology.INSTANCE.period(0, 0, 0)); + assertEquals(EthiopicChronology.INSTANCE.period(0, 0, 0), ethiopic.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_EthiopicDate(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(iso.until(ethiopic), Period.ZERO); + assertEquals(Period.ZERO, iso.until(ethiopic)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(EthiopicChronology.INSTANCE.date(iso), ethiopic); + assertEquals(ethiopic, EthiopicChronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(LocalDate.from(ethiopic.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(ethiopic.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(ethiopic.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(ethiopic.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(ethiopic.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(ethiopic.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(ethiopic.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(ethiopic.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(ethiopic.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(ethiopic.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(LocalDate.from(ethiopic.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(ethiopic.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(ethiopic.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(ethiopic.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(ethiopic.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(ethiopic.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(ethiopic.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(ethiopic.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(ethiopic.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(ethiopic.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(EthiopicDate ethiopic, LocalDate iso) { - assertEquals(ethiopic.until(iso.plusDays(0), DAYS), 0); - assertEquals(ethiopic.until(iso.plusDays(1), DAYS), 1); - assertEquals(ethiopic.until(iso.plusDays(35), DAYS), 35); - assertEquals(ethiopic.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, ethiopic.until(iso.plusDays(0), DAYS)); + assertEquals(1, ethiopic.until(iso.plusDays(1), DAYS)); + assertEquals(35, ethiopic.until(iso.plusDays(35), DAYS)); + assertEquals(-40, ethiopic.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {2008, 0, 0}, @@ -231,14 +243,15 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - EthiopicDate.of(year, month, dom); + assertThrows(DateTimeException.class, () -> EthiopicDate.of(year, month, dom)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_chronology_dateYearDay_badDate() { - EthiopicChronology.INSTANCE.dateYearDay(2008, 366); + assertThrows(DateTimeException.class, () -> EthiopicChronology.INSTANCE.dateYearDay(2008, 366)); } //----------------------------------------------------------------------- @@ -248,32 +261,31 @@ public void test_chronology_dateYearDay_badDate() { public void test_isLeapYear_loop() { for (int year = -200; year < 200; year++) { EthiopicDate base = EthiopicDate.of(year, 1, 1); - assertEquals(base.isLeapYear(), ((year - 3) % 4) == 0); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(year), ((year + 400 - 3) % 4) == 0); + assertEquals(((year - 3) % 4) == 0, base.isLeapYear()); + assertEquals(((year + 400 - 3) % 4) == 0, EthiopicChronology.INSTANCE.isLeapYear(year)); } } @Test public void test_isLeapYear_specific() { - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(8), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(7), true); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(6), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(5), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(4), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(3), true); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(2), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(1), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(0), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(-1), true); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(-2), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(-3), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(-4), false); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(-5), true); - assertEquals(EthiopicChronology.INSTANCE.isLeapYear(-6), false); - } - - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(8)); + assertEquals(true, EthiopicChronology.INSTANCE.isLeapYear(7)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(6)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(5)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(4)); + assertEquals(true, EthiopicChronology.INSTANCE.isLeapYear(3)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(2)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(1)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(0)); + assertEquals(true, EthiopicChronology.INSTANCE.isLeapYear(-1)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(-2)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(-3)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(-4)); + assertEquals(true, EthiopicChronology.INSTANCE.isLeapYear(-5)); + assertEquals(false, EthiopicChronology.INSTANCE.isLeapYear(-6)); + } + + public static Object[][] data_lengthOfMonth() { return new Object[][] { {2006, 1, 30}, {2006, 2, 30}, @@ -292,9 +304,10 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int length) { - assertEquals(EthiopicDate.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, EthiopicDate.of(year, month, 1).lengthOfMonth()); } //----------------------------------------------------------------------- @@ -310,7 +323,7 @@ public void test_era_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); EthiopicDate eraBased = EthiopicChronology.INSTANCE.date(era, yoe, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -324,39 +337,39 @@ public void test_era_yearDay_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); EthiopicDate eraBased = EthiopicChronology.INSTANCE.dateYearDay(era, yoe, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.INCARNATION, 4), 4); - assertEquals(EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.INCARNATION, 3), 3); - assertEquals(EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.INCARNATION, 2), 2); - assertEquals(EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.INCARNATION, 1), 1); - assertEquals(EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.BEFORE_INCARNATION, 1), 0); - assertEquals(EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.BEFORE_INCARNATION, 2), -1); - assertEquals(EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.BEFORE_INCARNATION, 3), -2); - assertEquals(EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.BEFORE_INCARNATION, 4), -3); + assertEquals(4, EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.INCARNATION, 4)); + assertEquals(3, EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.INCARNATION, 3)); + assertEquals(2, EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.INCARNATION, 2)); + assertEquals(1, EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.INCARNATION, 1)); + assertEquals(0, EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.BEFORE_INCARNATION, 1)); + assertEquals(-1, EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.BEFORE_INCARNATION, 2)); + assertEquals(-2, EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.BEFORE_INCARNATION, 3)); + assertEquals(-3, EthiopicChronology.INSTANCE.prolepticYear(EthiopicEra.BEFORE_INCARNATION, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(EthiopicChronology.INSTANCE.eraOf(1), EthiopicEra.INCARNATION); - assertEquals(EthiopicChronology.INSTANCE.eraOf(0), EthiopicEra.BEFORE_INCARNATION); + assertEquals(EthiopicEra.INCARNATION, EthiopicChronology.INSTANCE.eraOf(1)); + assertEquals(EthiopicEra.BEFORE_INCARNATION, EthiopicChronology.INSTANCE.eraOf(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - EthiopicChronology.INSTANCE.eraOf(2); + assertThrows(DateTimeException.class, () -> EthiopicChronology.INSTANCE.eraOf(2)); } @Test public void test_Chronology_eras() { List eras = EthiopicChronology.INSTANCE.eras(); - assertEquals(eras.size(), 2); - assertEquals(eras.contains(EthiopicEra.BEFORE_INCARNATION), true); - assertEquals(eras.contains(EthiopicEra.INCARNATION), true); + assertEquals(2, eras.size()); + assertEquals(true, eras.contains(EthiopicEra.BEFORE_INCARNATION)); + assertEquals(true, eras.contains(EthiopicEra.INCARNATION)); } //----------------------------------------------------------------------- @@ -364,17 +377,16 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(EthiopicChronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(1, 7)); - assertEquals(EthiopicChronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 5, 30)); - assertEquals(EthiopicChronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 365, 366)); - assertEquals(EthiopicChronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 13)); + assertEquals(ValueRange.of(1, 7), EthiopicChronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 5, 30), EthiopicChronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 365, 366), EthiopicChronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(1, 13), EthiopicChronology.INSTANCE.range(MONTH_OF_YEAR)); } //----------------------------------------------------------------------- // EthiopicDate.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { {2007, 1, 23, DAY_OF_MONTH, 1, 30}, {2007, 2, 23, DAY_OF_MONTH, 1, 30}, @@ -402,21 +414,21 @@ Object[][] data_ranges() { }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, int expectedMin, int expectedMax) { - assertEquals(EthiopicDate.of(year, month, dom).range(field), ValueRange.of(expectedMin, expectedMax)); + assertEquals(ValueRange.of(expectedMin, expectedMax), EthiopicDate.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - EthiopicDate.of(2007, 6, 30).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> EthiopicDate.of(2007, 6, 30).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // EthiopicDate.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {2007, 6, 8, DAY_OF_WEEK, 7}, {2007, 6, 8, DAY_OF_MONTH, 8}, @@ -436,21 +448,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(EthiopicDate.of(year, month, dom).getLong(field), expected); + assertEquals(expected, EthiopicDate.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - EthiopicDate.of(2007, 6, 30).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> EthiopicDate.of(2007, 6, 30).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // EthiopicDate.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {2007, 6, 8, DAY_OF_WEEK, 3, 2007, 6, 4}, {2007, 6, 8, DAY_OF_WEEK, 7, 2007, 6, 8}, @@ -488,15 +500,15 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(EthiopicDate.of(year, month, dom).with(field, value), EthiopicDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(EthiopicDate.of(expectedYear, expectedMonth, expectedDom), EthiopicDate.of(year, month, dom).with(field, value)); } - @DataProvider(name = "withBad") - Object[][] data_with_bad() { + public static Object[][] data_with_bad() { return new Object[][] { {2007, 6, 8, DAY_OF_WEEK, 0}, {2007, 6, 8, DAY_OF_WEEK, 8}, @@ -510,14 +522,15 @@ Object[][] data_with_bad() { }; } - @Test(dataProvider = "withBad", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_with_bad") public void test_with_TemporalField_badValue(int year, int month, int dom, TemporalField field, long value) { - EthiopicDate.of(year, month, dom).with(field, value); + assertThrows(DateTimeException.class, () -> EthiopicDate.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - EthiopicDate.of(2006, 6, 30).with(MINUTE_OF_DAY, 0); + assertThrows(UnsupportedTemporalTypeException.class, () -> EthiopicDate.of(2006, 6, 30).with(MINUTE_OF_DAY, 0)); } //----------------------------------------------------------------------- @@ -527,14 +540,14 @@ public void test_with_TemporalField_unsupported() { public void test_adjust1() { EthiopicDate base = EthiopicDate.of(2005, 10, 29); EthiopicDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, EthiopicDate.of(2005, 10, 30)); + assertEquals(EthiopicDate.of(2005, 10, 30), test); } @Test public void test_adjust2() { EthiopicDate base = EthiopicDate.of(2005, 13, 2); EthiopicDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, EthiopicDate.of(2005, 13, 5)); + assertEquals(EthiopicDate.of(2005, 13, 5), test); } //----------------------------------------------------------------------- @@ -544,13 +557,13 @@ public void test_adjust2() { public void test_adjust_toLocalDate() { EthiopicDate ethiopic = EthiopicDate.of(2001, 1, 4); EthiopicDate test = ethiopic.with(LocalDate.of(2011, 10, 16)); - assertEquals(test, EthiopicDate.of(2004, 2, 5)); + assertEquals(EthiopicDate.of(2004, 2, 5), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { EthiopicDate ethiopic = EthiopicDate.of(2004, 1, 4); - ethiopic.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> ethiopic.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -560,21 +573,20 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToEthiopicDate() { EthiopicDate ethiopic = EthiopicDate.of(2004, 2, 5); LocalDate test = LocalDate.MIN.with(ethiopic); - assertEquals(test, LocalDate.of(2011, 10, 16)); + assertEquals(LocalDate.of(2011, 10, 16), test); } @Test public void test_LocalDateTime_adjustToEthiopicDate() { EthiopicDate ethiopic = EthiopicDate.of(2004, 2, 5); LocalDateTime test = LocalDateTime.MIN.with(ethiopic); - assertEquals(test, LocalDateTime.of(2011, 10, 16, 0, 0)); + assertEquals(LocalDateTime.of(2011, 10, 16, 0, 0), test); } //----------------------------------------------------------------------- // EthiopicDate.plus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {2006, 5, 26, 0, DAYS, 2006, 5, 26}, {2006, 5, 26, 8, DAYS, 2006, 6, 4}, @@ -601,52 +613,53 @@ Object[][] data_plus() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(EthiopicDate.of(year, month, dom).plus(amount, unit), EthiopicDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(EthiopicDate.of(expectedYear, expectedMonth, expectedDom), EthiopicDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(EthiopicDate.of(year, month, dom).minus(amount, unit), EthiopicDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(EthiopicDate.of(expectedYear, expectedMonth, expectedDom), EthiopicDate.of(year, month, dom).minus(amount, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - EthiopicDate.of(2006, 6, 30).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> EthiopicDate.of(2006, 6, 30).plus(0, MINUTES)); } //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(EthiopicDate.of(2006, 5, 26).plus(EthiopicChronology.INSTANCE.period(0, 2, 3)), EthiopicDate.of(2006, 7, 29)); + assertEquals(EthiopicDate.of(2006, 7, 29), EthiopicDate.of(2006, 5, 26).plus(EthiopicChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(EthiopicDate.of(2006, 5, 26).plus(Period.ofMonths(2)), EthiopicDate.of(2006, 7, 26)); + assertThrows(DateTimeException.class, () -> EthiopicDate.of(2006, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(EthiopicDate.of(2006, 5, 26).minus(EthiopicChronology.INSTANCE.period(0, 2, 3)), EthiopicDate.of(2006, 3, 23)); + assertEquals(EthiopicDate.of(2006, 3, 23), EthiopicDate.of(2006, 5, 26).minus(EthiopicChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(EthiopicDate.of(2006, 5, 26).minus(Period.ofMonths(2)), EthiopicDate.of(2006, 3, 26)); + assertThrows(DateTimeException.class, () -> EthiopicDate.of(2006, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- // EthiopicDate.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {2006, 5, 26, 2006, 5, 26, DAYS, 0}, {2006, 5, 26, 2006, 6, 1, DAYS, 5}, @@ -672,51 +685,41 @@ Object[][] data_until() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { EthiopicDate start = EthiopicDate.of(year1, month1, dom1); EthiopicDate end = EthiopicDate.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { EthiopicDate start = EthiopicDate.of(2006, 6, 30); EthiopicDate end = EthiopicDate.of(2006, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - void test_equals() { - EthiopicDate a1 = EthiopicDate.of(2004, 1, 3); - EthiopicDate a2 = EthiopicDate.of(2004, 1, 3); - EthiopicDate b = EthiopicDate.of(2004, 1, 4); - EthiopicDate c = EthiopicDate.of(2004, 2, 3); - EthiopicDate d = EthiopicDate.of(2005, 1, 3); - - assertEquals(a1.equals(a1), true); - assertEquals(a1.equals(a2), true); - assertEquals(a1.equals(b), false); - assertEquals(a1.equals(c), false); - assertEquals(a1.equals(d), false); - - assertEquals(a1.equals(null), false); - assertEquals(a1.equals(""), false); - - assertEquals(a1.hashCode(), a2.hashCode()); + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(EthiopicDate.of(2004, 1, 3), EthiopicDate.of(2004, 1, 3)) + .addEqualityGroup(EthiopicDate.of(2004, 1, 4), EthiopicDate.of(2004, 1, 4)) + .addEqualityGroup(EthiopicDate.of(2004, 2, 3), EthiopicDate.of(2004, 2, 3)) + .addEqualityGroup(EthiopicDate.of(2005, 1, 3), EthiopicDate.of(2005, 1, 3)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {EthiopicDate.of(1, 1, 1), "Ethiopic INCARNATION 1-01-01"}, {EthiopicDate.of(2007, 10, 28), "Ethiopic INCARNATION 2007-10-28"}, @@ -726,9 +729,10 @@ Object[][] data_toString() { }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(EthiopicDate ethiopic, String expected) { - assertEquals(ethiopic.toString(), expected); + assertEquals(expected, ethiopic.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestInternationalFixedChronology.java b/src/test/java/org/threeten/extra/chrono/TestInternationalFixedChronology.java index aaf70c91..92d8f33b 100644 --- a/src/test/java/org/threeten/extra/chrono/TestInternationalFixedChronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestInternationalFixedChronology.java @@ -54,39 +54,38 @@ import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; import java.time.Period; - -import java.time.chrono.Chronology; import java.time.chrono.ChronoPeriod; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.IsoEra; - import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; - import java.util.List; -import java.util.function.Predicate; +import java.util.function.IntPredicate; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test @SuppressWarnings({"static-method", "javadoc"}) public class TestInternationalFixedChronology { @@ -97,16 +96,15 @@ public class TestInternationalFixedChronology { public void test_chronology() { Chronology chrono = Chronology.of("Ifc"); assertNotNull(chrono); - assertEquals(chrono, InternationalFixedChronology.INSTANCE); - assertEquals(chrono.getId(), "Ifc"); - assertEquals(chrono.getCalendarType(), null); + assertEquals(InternationalFixedChronology.INSTANCE, chrono); + assertEquals("Ifc", chrono.getId()); + assertEquals(null, chrono.getCalendarType()); } //----------------------------------------------------------------------- // creation, toLocalDate() //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { {InternationalFixedDate.of(1, 1, 1), LocalDate.of(1, 1, 1)}, {InternationalFixedDate.of(1, 1, 2), LocalDate.of(1, 1, 2)}, @@ -152,81 +150,91 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_InternationalFixedDate(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(LocalDate.from(fixed), iso); + assertEquals(iso, LocalDate.from(fixed)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_InternationalFixedDate_from_LocalDate(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(InternationalFixedDate.from(iso), fixed); + assertEquals(fixed, InternationalFixedDate.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_InternationalFixedDate_chronology_dateEpochDay(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(InternationalFixedChronology.INSTANCE.dateEpochDay(iso.toEpochDay()), fixed); + assertEquals(fixed, InternationalFixedChronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_InternationalFixedDate_toEpochDay(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(fixed.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), fixed.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_InternationalFixedDate_until_InternationalFixedDate(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(fixed.until(fixed), InternationalFixedChronology.INSTANCE.period(0, 0, 0)); + assertEquals(InternationalFixedChronology.INSTANCE.period(0, 0, 0), fixed.until(fixed)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_InternationalFixedDate_until_LocalDate(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(fixed.until(iso), InternationalFixedChronology.INSTANCE.period(0, 0, 0)); + assertEquals(InternationalFixedChronology.INSTANCE.period(0, 0, 0), fixed.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_InternationalFixedDate(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(iso.until(fixed), Period.ZERO); + assertEquals(Period.ZERO, iso.until(fixed)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(InternationalFixedChronology.INSTANCE.date(iso), fixed); + assertEquals(fixed, InternationalFixedChronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(LocalDate.from(fixed.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(fixed.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(fixed.plus(35, DAYS)), iso.plusDays(35)); + assertEquals(iso, LocalDate.from(fixed.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(fixed.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(fixed.plus(35, DAYS))); if (LocalDate.ofYearDay(1, 60).isBefore(iso)) { - assertEquals(LocalDate.from(fixed.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(fixed.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso.plusDays(-1), LocalDate.from(fixed.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(fixed.plus(-60, DAYS))); } } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(LocalDate.from(fixed.minus(0, DAYS)), iso); + assertEquals(iso, LocalDate.from(fixed.minus(0, DAYS))); if (LocalDate.ofYearDay(1, 35).isBefore(iso)) { - assertEquals(LocalDate.from(fixed.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(fixed.minus(35, DAYS)), iso.minusDays(35)); + assertEquals(iso.minusDays(1), LocalDate.from(fixed.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(fixed.minus(35, DAYS))); } - assertEquals(LocalDate.from(fixed.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(fixed.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso.minusDays(-1), LocalDate.from(fixed.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(fixed.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(InternationalFixedDate fixed, LocalDate iso) { - assertEquals(fixed.until(iso.plusDays(0), DAYS), 0); - assertEquals(fixed.until(iso.plusDays(1), DAYS), 1); - assertEquals(fixed.until(iso.plusDays(35), DAYS), 35); + assertEquals(0, fixed.until(iso.plusDays(0), DAYS)); + assertEquals(1, fixed.until(iso.plusDays(1), DAYS)); + assertEquals(35, fixed.until(iso.plusDays(35), DAYS)); if (LocalDate.ofYearDay(1, 40).isBefore(iso)) { - assertEquals(fixed.until(iso.minusDays(40), DAYS), -40); + assertEquals(-40, fixed.until(iso.minusDays(40), DAYS)); } } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {-1, 13, 28}, {-1, 13, 29}, @@ -266,13 +274,13 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - InternationalFixedDate.of(year, month, dom); + assertThrows(DateTimeException.class, () -> InternationalFixedDate.of(year, month, dom)); } - @DataProvider(name = "badLeapDates") - Object[][] data_badLeapDates() { + public static Object[][] data_badLeapDates() { return new Object[][] { {1}, {100}, @@ -282,14 +290,15 @@ Object[][] data_badLeapDates() { }; } - @Test(dataProvider = "badLeapDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badLeapDates") public void badLeapDayDates(int year) { - InternationalFixedDate.of(year, 6, 29); + assertThrows(DateTimeException.class, () -> InternationalFixedDate.of(year, 6, 29)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_chronology_dateYearDay_badDate() { - InternationalFixedChronology.INSTANCE.dateYearDay(2001, 366); + assertThrows(DateTimeException.class, () -> InternationalFixedChronology.INSTANCE.dateYearDay(2001, 366)); } //----------------------------------------------------------------------- @@ -297,15 +306,15 @@ public void test_chronology_dateYearDay_badDate() { //----------------------------------------------------------------------- @Test public void test_isLeapYear_loop() { - Predicate isLeapYear = year -> { + IntPredicate isLeapYear = year -> { return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0); }; for (int year = 1; year < 500; year++) { InternationalFixedDate base = InternationalFixedDate.of(year, 1, 1); - assertEquals(base.isLeapYear(), isLeapYear.test(year), "Year " + year + " is failing"); - assertEquals(base.lengthOfYear(), isLeapYear.test(year) ? 366 : 365); - assertEquals(InternationalFixedChronology.INSTANCE.isLeapYear(year), isLeapYear.test(year), "Year " + year + " is failing leap-year test"); + assertEquals(isLeapYear.test(year), base.isLeapYear()); + assertEquals(isLeapYear.test(year) ? 366 : 365, base.lengthOfYear()); + assertEquals(isLeapYear.test(year), InternationalFixedChronology.INSTANCE.isLeapYear(year)); } } @@ -322,8 +331,7 @@ public void test_isLeapYear_specific() { //----------------------------------------------------------------------- // lengthOfMonth() //----------------------------------------------------------------------- - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + public static Object[][] data_lengthOfMonth() { return new Object[][] { {1900, 1, 28, 28}, {1900, 2, 28, 28}, @@ -342,21 +350,47 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int day, int length) { - assertEquals(InternationalFixedDate.of(year, month, day).lengthOfMonth(), length); + assertEquals(length, InternationalFixedDate.of(year, month, day).lengthOfMonth()); } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonthFirst(int year, int month, int day, int length) { - assertEquals(InternationalFixedDate.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, InternationalFixedDate.of(year, month, 1).lengthOfMonth()); } @Test public void test_lengthOfMonth_specific() { - assertEquals(InternationalFixedDate.of(1900, 13, 29).lengthOfMonth(), 29); - assertEquals(InternationalFixedDate.of(2000, 13, 29).lengthOfMonth(), 29); - assertEquals(InternationalFixedDate.of(2000, 6, 29).lengthOfMonth(), 29); + assertEquals(29, InternationalFixedDate.of(1900, 13, 29).lengthOfMonth()); + assertEquals(29, InternationalFixedDate.of(2000, 13, 29).lengthOfMonth()); + assertEquals(29, InternationalFixedDate.of(2000, 6, 29).lengthOfMonth()); + } + + @Test + public void test_era_valid() { + Era era = InternationalFixedChronology.INSTANCE.eraOf(1); + assertNotNull(era); + assertEquals(1, era.getValue()); + } + + //----------------------------------------------------------------------- + // data_invalidEraValues() + //----------------------------------------------------------------------- + public static Object[][] data_invalidEraValues() { + return new Object[][] { + {-1}, + {0}, + {2}, + }; + } + + @ParameterizedTest + @MethodSource("data_invalidEraValues") + public void test_era_invalid(int eraValue) { + assertThrows(DateTimeException.class, () -> InternationalFixedChronology.INSTANCE.eraOf(eraValue)); } //----------------------------------------------------------------------- @@ -371,7 +405,7 @@ public void test_era_loop() { assertEquals(era, base.getEra()); assertEquals(year, base.get(YEAR_OF_ERA)); InternationalFixedDate eraBased = InternationalFixedChronology.INSTANCE.date(era, year, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -384,22 +418,21 @@ public void test_era_yearDay_loop() { assertEquals(era, base.getEra()); assertEquals(year, base.get(YEAR_OF_ERA)); InternationalFixedDate eraBased = InternationalFixedChronology.INSTANCE.dateYearDay(era, year, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 4), 4); - assertEquals(InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 3), 3); - assertEquals(InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 2), 2); - assertEquals(InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 1), 1); - assertEquals(InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 2000), 2000); - assertEquals(InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 1582), 1582); + assertEquals(4, InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 4)); + assertEquals(3, InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 3)); + assertEquals(2, InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 2)); + assertEquals(1, InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 1)); + assertEquals(2000, InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 2000)); + assertEquals(1582, InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, 1582)); } - @DataProvider(name = "prolepticYearBad") - Object[][] data_prolepticYear_bad() { + public static Object[][] data_prolepticYear_bad() { return new Object[][] { {-10}, {-1}, @@ -407,30 +440,31 @@ Object[][] data_prolepticYear_bad() { }; } - @Test(dataProvider = "prolepticYearBad", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_prolepticYear_bad") public void test_prolepticYearBad(int year) { - InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, year); + assertThrows(DateTimeException.class, () -> InternationalFixedChronology.INSTANCE.prolepticYear(InternationalFixedEra.CE, year)); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void test_prolepticYear_badEra() { - InternationalFixedChronology.INSTANCE.prolepticYear(IsoEra.CE, 4); + assertThrows(ClassCastException.class, () -> InternationalFixedChronology.INSTANCE.prolepticYear(IsoEra.CE, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(InternationalFixedChronology.INSTANCE.eraOf(1), InternationalFixedEra.CE); + assertEquals(InternationalFixedEra.CE, InternationalFixedChronology.INSTANCE.eraOf(1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - InternationalFixedChronology.INSTANCE.eraOf(0); + assertThrows(DateTimeException.class, () -> InternationalFixedChronology.INSTANCE.eraOf(0)); } @Test public void test_Chronology_eras() { List eras = InternationalFixedChronology.INSTANCE.eras(); - assertEquals(eras.size(), 1); + assertEquals(1, eras.size()); assertTrue(eras.contains(InternationalFixedEra.CE)); } @@ -439,26 +473,25 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(InternationalFixedChronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_MONTH), ValueRange.of(0, 1, 0, 7)); - assertEquals(InternationalFixedChronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_YEAR), ValueRange.of(0, 1, 0, 7)); - assertEquals(InternationalFixedChronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH), ValueRange.of(0, 1, 0, 4)); - assertEquals(InternationalFixedChronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR), ValueRange.of(0, 1, 0, 52)); - assertEquals(InternationalFixedChronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(0, 1, 0, 7)); - assertEquals(InternationalFixedChronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 29)); - assertEquals(InternationalFixedChronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 365, 366)); - assertEquals(InternationalFixedChronology.INSTANCE.range(ERA), ValueRange.of(1, 1)); - assertEquals(InternationalFixedChronology.INSTANCE.range(EPOCH_DAY), ValueRange.of(-719_528, 1_000_000 * 365L + 242_499 - 719_528)); - assertEquals(InternationalFixedChronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 13)); - assertEquals(InternationalFixedChronology.INSTANCE.range(PROLEPTIC_MONTH), ValueRange.of(13, 1_000_000 * 13L - 1)); - assertEquals(InternationalFixedChronology.INSTANCE.range(YEAR), ValueRange.of(1, 1_000_000)); - assertEquals(InternationalFixedChronology.INSTANCE.range(YEAR_OF_ERA), ValueRange.of(1, 1_000_000)); + assertEquals(ValueRange.of(0, 1, 0, 7), InternationalFixedChronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(ValueRange.of(0, 1, 0, 7), InternationalFixedChronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(ValueRange.of(0, 1, 0, 4), InternationalFixedChronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH)); + assertEquals(ValueRange.of(0, 1, 0, 52), InternationalFixedChronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR)); + assertEquals(ValueRange.of(0, 1, 0, 7), InternationalFixedChronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 29), InternationalFixedChronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 365, 366), InternationalFixedChronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(1, 1), InternationalFixedChronology.INSTANCE.range(ERA)); + assertEquals(ValueRange.of(-719_528, 1_000_000 * 365L + 242_499 - 719_528), InternationalFixedChronology.INSTANCE.range(EPOCH_DAY)); + assertEquals(ValueRange.of(1, 13), InternationalFixedChronology.INSTANCE.range(MONTH_OF_YEAR)); + assertEquals(ValueRange.of(13, 1_000_000 * 13L - 1), InternationalFixedChronology.INSTANCE.range(PROLEPTIC_MONTH)); + assertEquals(ValueRange.of(1, 1_000_000), InternationalFixedChronology.INSTANCE.range(YEAR)); + assertEquals(ValueRange.of(1, 1_000_000), InternationalFixedChronology.INSTANCE.range(YEAR_OF_ERA)); } //----------------------------------------------------------------------- // InternationalFixedDate.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { // Leap Day and Year Day are members of months {2012, 6, 29, DAY_OF_MONTH, ValueRange.of(1, 29)}, @@ -517,21 +550,21 @@ Object[][] data_ranges() { }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, ValueRange range) { - assertEquals(InternationalFixedDate.of(year, month, dom).range(field), range); + assertEquals(range, InternationalFixedDate.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - InternationalFixedDate.of(2012, 6, 28).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> InternationalFixedDate.of(2012, 6, 28).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // InternationalFixedDate.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 5}, {2014, 5, 26, DAY_OF_MONTH, 26}, @@ -598,21 +631,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(InternationalFixedDate.of(year, month, dom).getLong(field), expected); + assertEquals(expected, InternationalFixedDate.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - InternationalFixedDate.of(2012, 6, 28).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> InternationalFixedDate.of(2012, 6, 28).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // InternationalFixedDate.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 1, 2014, 5, 22}, {2014, 5, 26, DAY_OF_WEEK, 5, 2014, 5, 26}, @@ -745,15 +778,15 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(InternationalFixedDate.of(year, month, dom).with(field, value), InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom), InternationalFixedDate.of(year, month, dom).with(field, value)); } - @DataProvider(name = "with_bad") - Object[][] data_with_bad() { + public static Object[][] data_with_bad() { return new Object[][] { {2013, 1, 1, ALIGNED_DAY_OF_WEEK_IN_MONTH, 0}, {2013, 1, 1, ALIGNED_DAY_OF_WEEK_IN_MONTH, 8}, @@ -811,21 +844,21 @@ Object[][] data_with_bad() { }; } - @Test(dataProvider = "with_bad", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_with_bad") public void test_with_TemporalField_badValue(int year, int month, int dom, TemporalField field, long value) { - InternationalFixedDate.of(year, month, dom).with(field, value); + assertThrows(DateTimeException.class, () -> InternationalFixedDate.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - InternationalFixedDate.of(2012, 6, 28).with(MINUTE_OF_DAY, 0); + assertThrows(UnsupportedTemporalTypeException.class, () -> InternationalFixedDate.of(2012, 6, 28).with(MINUTE_OF_DAY, 0)); } //----------------------------------------------------------------------- // InternationalFixedDate.with(TemporalAdjuster) //----------------------------------------------------------------------- - @DataProvider(name = "temporalAdjusters_lastDayOfMonth") - Object[][] data_temporalAdjusters_lastDayOfMonth() { + public static Object[][] data_temporalAdjusters_lastDayOfMonth() { return new Object[][] { {2012, 6, 23, 2012, 6, 29}, {2012, 6, 29, 2012, 6, 29}, @@ -835,12 +868,13 @@ Object[][] data_temporalAdjusters_lastDayOfMonth() { }; } - @Test(dataProvider = "temporalAdjusters_lastDayOfMonth") + @ParameterizedTest + @MethodSource("data_temporalAdjusters_lastDayOfMonth") public void test_temporalAdjusters_LastDayOfMonth(int year, int month, int day, int expectedYear, int expectedMonth, int expectedDay) { InternationalFixedDate base = InternationalFixedDate.of(year, month, day); InternationalFixedDate expected = InternationalFixedDate.of(expectedYear, expectedMonth, expectedDay); InternationalFixedDate actual = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(actual, expected); + assertEquals(expected, actual); } //----------------------------------------------------------------------- @@ -850,13 +884,13 @@ public void test_temporalAdjusters_LastDayOfMonth(int year, int month, int day, public void test_adjust_toLocalDate() { InternationalFixedDate fixed = InternationalFixedDate.of(2000, 1, 4); InternationalFixedDate test = fixed.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, InternationalFixedDate.of(2012, 7, 19)); + assertEquals(InternationalFixedDate.of(2012, 7, 19), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { InternationalFixedDate fixed = InternationalFixedDate.of(2000, 1, 4); - fixed.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> fixed.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -866,22 +900,21 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToInternationalFixedDate() { InternationalFixedDate fixed = InternationalFixedDate.of(2012, 7, 19); LocalDate test = LocalDate.MIN.with(fixed); - assertEquals(test, LocalDate.of(2012, 7, 6)); + assertEquals(LocalDate.of(2012, 7, 6), test); } @Test public void test_LocalDateTime_adjustToInternationalFixedDate() { InternationalFixedDate fixed = InternationalFixedDate.of(2012, 7, 19); LocalDateTime test = LocalDateTime.MIN.with(fixed); - assertEquals(test, LocalDateTime.of(2012, 7, 6, 0, 0)); + assertEquals(LocalDateTime.of(2012, 7, 6, 0, 0), test); } //----------------------------------------------------------------------- // InternationalFixedDate.plus // InternationalFixedDate.minus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {2014, 5, 26, 0, DAYS, 2014, 5, 26}, {2014, 5, 26, 8, DAYS, 2014, 6, 6}, @@ -916,8 +949,7 @@ Object[][] data_plus() { }; } - @DataProvider(name = "plus_leap_and_year_day") - Object[][] data_plus_leap_and_year_day() { + public static Object[][] data_plus_leap_and_year_day() { return new Object[][] { {2014, 13, 29, 0, DAYS, 2014, 13, 29}, {2014, 13, 29, 8, DAYS, 2015, 1, 8}, @@ -958,8 +990,7 @@ Object[][] data_plus_leap_and_year_day() { }; } - @DataProvider(name = "minus_leap_and_year_day") - Object[][] data_minus_leap_and_year_day() { + public static Object[][] data_minus_leap_and_year_day() { return new Object[][] { {2014, 13, 29, 0, DAYS, 2014, 13, 29}, {2014, 13, 21, 8, DAYS, 2014, 13, 29}, @@ -1001,46 +1032,49 @@ Object[][] data_minus_leap_and_year_day() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(InternationalFixedDate.of(year, month, dom).plus(amount, unit), InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom), InternationalFixedDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus_leap_and_year_day") + @ParameterizedTest + @MethodSource("data_plus_leap_and_year_day") public void test_plus_leap_and_year_day_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(InternationalFixedDate.of(year, month, dom).plus(amount, unit), InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom), InternationalFixedDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(InternationalFixedDate.of(year, month, dom).minus(amount, unit), InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom), InternationalFixedDate.of(year, month, dom).minus(amount, unit)); } - @Test(dataProvider = "minus_leap_and_year_day") + @ParameterizedTest + @MethodSource("data_minus_leap_and_year_day") public void test_minus_leap_and_year_day_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(InternationalFixedDate.of(year, month, dom).minus(amount, unit), InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(InternationalFixedDate.of(expectedYear, expectedMonth, expectedDom), InternationalFixedDate.of(year, month, dom).minus(amount, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - InternationalFixedDate.of(2012, 6, 28).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> InternationalFixedDate.of(2012, 6, 28).plus(0, MINUTES)); } //----------------------------------------------------------------------- // InternationalFixedDate.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, DAYS, 0}, {2014, 5, 26, 2014, 6, 4, DAYS, 6}, @@ -1171,8 +1205,7 @@ Object[][] data_until() { }; } - @DataProvider(name = "until_period") - Object[][] data_until_period() { + public static Object[][] data_until_period() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, 0, 0, 0}, {2014, 5, 26, 2014, 6, 4, 0, 0, 6}, @@ -1247,17 +1280,19 @@ Object[][] data_until_period() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { InternationalFixedDate start = InternationalFixedDate.of(year1, month1, dom1); InternationalFixedDate end = InternationalFixedDate.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(dataProvider = "until_period") + @ParameterizedTest + @MethodSource("data_until_period") public void test_until_end( int year1, int month1, int dom1, int year2, int month2, int dom2, @@ -1265,14 +1300,14 @@ public void test_until_end( InternationalFixedDate start = InternationalFixedDate.of(year1, month1, dom1); InternationalFixedDate end = InternationalFixedDate.of(year2, month2, dom2); ChronoPeriod period = InternationalFixedChronology.INSTANCE.period(yearPeriod, monthPeriod, dayPeriod); - assertEquals(start.until(end), period); + assertEquals(period, start.until(end)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { InternationalFixedDate start = InternationalFixedDate.of(2012, 6, 28); InternationalFixedDate end = InternationalFixedDate.of(2012, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- @@ -1280,55 +1315,46 @@ public void test_until_TemporalUnit_unsupported() { //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(InternationalFixedDate.of(2014, 5, 26).plus(InternationalFixedChronology.INSTANCE.period(0, 2, 3)), InternationalFixedDate.of(2014, 8, 1)); + assertEquals(InternationalFixedDate.of(2014, 8, 1), InternationalFixedDate.of(2014, 5, 26).plus(InternationalFixedChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(InternationalFixedDate.of(2014, 5, 26).plus(Period.ofMonths(2)), InternationalFixedDate.of(2014, 7, 26)); + assertThrows(DateTimeException.class, () -> InternationalFixedDate.of(2014, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(InternationalFixedDate.of(2014, 5, 26).minus(InternationalFixedChronology.INSTANCE.period(0, 2, 3)), InternationalFixedDate.of(2014, 3, 23)); + assertEquals(InternationalFixedDate.of(2014, 3, 23), InternationalFixedDate.of(2014, 5, 26).minus(InternationalFixedChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(InternationalFixedDate.of(2014, 5, 26).minus(Period.ofMonths(2)), InternationalFixedDate.of(2014, 3, 26)); + assertThrows(DateTimeException.class, () -> InternationalFixedDate.of(2014, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- - @DataProvider(name = "equals") - Object[][] data_equals() { - return new Object[][] { - {InternationalFixedDate.of(2000, 1, 3), - InternationalFixedDate.of(2000, 1, 4), InternationalFixedDate.of(2000, 2, 3), InternationalFixedDate.of(2001, 1, 3)}, - {InternationalFixedDate.of(2000, 13, 29), - InternationalFixedDate.of(2000, 13, 28), InternationalFixedDate.of(2001, 1, 1), InternationalFixedDate.of(2001, 13, 29)}, - {InternationalFixedDate.of(2000, 6, 29), - InternationalFixedDate.of(2000, 6, 28), InternationalFixedDate.of(2000, 7, 1), InternationalFixedDate.of(2004, 6, 29)}, - }; - } - - @Test(dataProvider = "equals") - void test_equals(InternationalFixedDate a1, InternationalFixedDate b, InternationalFixedDate c, InternationalFixedDate d) { - assertTrue(a1.equals(a1)); - assertFalse(a1.equals(b)); - assertFalse(a1.equals(c)); - assertFalse(a1.equals(d)); - - assertFalse(a1.equals(null)); - assertFalse("".equals(a1)); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(InternationalFixedDate.of(2000, 1, 3), InternationalFixedDate.of(2000, 1, 3)) + .addEqualityGroup(InternationalFixedDate.of(2000, 1, 4), InternationalFixedDate.of(2000, 1, 4)) + .addEqualityGroup(InternationalFixedDate.of(2000, 2, 3), InternationalFixedDate.of(2000, 2, 3)) + .addEqualityGroup(InternationalFixedDate.of(2000, 6, 28), InternationalFixedDate.of(2000, 6, 28)) + .addEqualityGroup(InternationalFixedDate.of(2000, 6, 29), InternationalFixedDate.of(2000, 6, 29)) + .addEqualityGroup(InternationalFixedDate.of(2000, 13, 28), InternationalFixedDate.of(2000, 13, 28)) + .addEqualityGroup(InternationalFixedDate.of(2001, 1, 1), InternationalFixedDate.of(2001, 1, 1)) + .addEqualityGroup(InternationalFixedDate.of(2001, 13, 29), InternationalFixedDate.of(2001, 13, 29)) + .addEqualityGroup(InternationalFixedDate.of(2004, 6, 29), InternationalFixedDate.of(2004, 6, 29)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {InternationalFixedDate.of(1, 1, 1), "Ifc CE 1/01/01"}, {InternationalFixedDate.of(2012, 6, 23), "Ifc CE 2012/06/23"}, @@ -1339,8 +1365,9 @@ Object[][] data_toString() { }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(InternationalFixedDate date, String expected) { - assertEquals(date.toString(), expected); + assertEquals(expected, date.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestJulianChronology.java b/src/test/java/org/threeten/extra/chrono/TestJulianChronology.java index 23e1b8da..599b3482 100644 --- a/src/test/java/org/threeten/extra/chrono/TestJulianChronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestJulianChronology.java @@ -53,7 +53,9 @@ import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.time.DateTimeException; import java.time.LocalDate; @@ -63,7 +65,6 @@ import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.IsoEra; -import java.time.temporal.IsoFields; import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; @@ -72,14 +73,15 @@ import java.time.temporal.WeekFields; import java.util.List; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test public class TestJulianChronology { //----------------------------------------------------------------------- @@ -88,26 +90,25 @@ public class TestJulianChronology { @Test public void test_chronology_of_name() { Chronology chrono = Chronology.of("Julian"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, JulianChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Julian"); - Assert.assertEquals(chrono.getCalendarType(), "julian"); + assertNotNull(chrono); + assertEquals(JulianChronology.INSTANCE, chrono); + assertEquals("Julian", chrono.getId()); + assertEquals("julian", chrono.getCalendarType()); } @Test public void test_chronology_of_name_id() { Chronology chrono = Chronology.of("julian"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, JulianChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Julian"); - Assert.assertEquals(chrono.getCalendarType(), "julian"); + assertNotNull(chrono); + assertEquals(JulianChronology.INSTANCE, chrono); + assertEquals("Julian", chrono.getId()); + assertEquals("julian", chrono.getCalendarType()); } //----------------------------------------------------------------------- // creation, toLocalDate() //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { {JulianDate.of(1, 1, 1), LocalDate.of(0, 12, 30)}, {JulianDate.of(1, 1, 2), LocalDate.of(0, 12, 31)}, @@ -142,74 +143,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_JulianDate(JulianDate julian, LocalDate iso) { - assertEquals(LocalDate.from(julian), iso); + assertEquals(iso, LocalDate.from(julian)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_JulianDate_from_LocalDate(JulianDate julian, LocalDate iso) { - assertEquals(JulianDate.from(iso), julian); + assertEquals(julian, JulianDate.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_JulianDate_chronology_dateEpochDay(JulianDate julian, LocalDate iso) { - assertEquals(JulianChronology.INSTANCE.dateEpochDay(iso.toEpochDay()), julian); + assertEquals(julian, JulianChronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_JulianDate_toEpochDay(JulianDate julian, LocalDate iso) { - assertEquals(julian.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), julian.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_JulianDate_until_JulianDate(JulianDate julian, LocalDate iso) { - assertEquals(julian.until(julian), JulianChronology.INSTANCE.period(0, 0, 0)); + assertEquals(JulianChronology.INSTANCE.period(0, 0, 0), julian.until(julian)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_JulianDate_until_LocalDate(JulianDate julian, LocalDate iso) { - assertEquals(julian.until(iso), JulianChronology.INSTANCE.period(0, 0, 0)); + assertEquals(JulianChronology.INSTANCE.period(0, 0, 0), julian.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_JulianDate(JulianDate julian, LocalDate iso) { - assertEquals(iso.until(julian), Period.ZERO); + assertEquals(Period.ZERO, iso.until(julian)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(JulianDate julian, LocalDate iso) { - assertEquals(JulianChronology.INSTANCE.date(iso), julian); + assertEquals(julian, JulianChronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(JulianDate julian, LocalDate iso) { - assertEquals(LocalDate.from(julian.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(julian.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(julian.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(julian.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(julian.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(julian.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(julian.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(julian.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(julian.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(julian.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(JulianDate julian, LocalDate iso) { - assertEquals(LocalDate.from(julian.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(julian.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(julian.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(julian.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(julian.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(julian.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(julian.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(julian.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(julian.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(julian.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(JulianDate julian, LocalDate iso) { - assertEquals(julian.until(iso.plusDays(0), DAYS), 0); - assertEquals(julian.until(iso.plusDays(1), DAYS), 1); - assertEquals(julian.until(iso.plusDays(35), DAYS), 35); - assertEquals(julian.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, julian.until(iso.plusDays(0), DAYS)); + assertEquals(1, julian.until(iso.plusDays(1), DAYS)); + assertEquals(35, julian.until(iso.plusDays(35), DAYS)); + assertEquals(-40, julian.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {1900, 0, 0}, @@ -251,14 +262,15 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - JulianDate.of(year, month, dom); + assertThrows(DateTimeException.class, () -> JulianDate.of(year, month, dom)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_chronology_dateYearDay_badDate() { - JulianChronology.INSTANCE.dateYearDay(2001, 366); + assertThrows(DateTimeException.class, () -> JulianChronology.INSTANCE.dateYearDay(2001, 366)); } //----------------------------------------------------------------------- @@ -268,32 +280,31 @@ public void test_chronology_dateYearDay_badDate() { public void test_isLeapYear_loop() { for (int year = -200; year < 200; year++) { JulianDate base = JulianDate.of(year, 1, 1); - assertEquals(base.isLeapYear(), (year % 4) == 0); - assertEquals(JulianChronology.INSTANCE.isLeapYear(year), (year % 4) == 0); + assertEquals((year % 4) == 0, base.isLeapYear()); + assertEquals((year % 4) == 0, JulianChronology.INSTANCE.isLeapYear(year)); } } @Test public void test_isLeapYear_specific() { - assertEquals(JulianChronology.INSTANCE.isLeapYear(8), true); - assertEquals(JulianChronology.INSTANCE.isLeapYear(7), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(6), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(5), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(4), true); - assertEquals(JulianChronology.INSTANCE.isLeapYear(3), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(2), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(1), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(0), true); - assertEquals(JulianChronology.INSTANCE.isLeapYear(-1), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(-2), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(-3), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(-4), true); - assertEquals(JulianChronology.INSTANCE.isLeapYear(-5), false); - assertEquals(JulianChronology.INSTANCE.isLeapYear(-6), false); - } - - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + assertEquals(true, JulianChronology.INSTANCE.isLeapYear(8)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(7)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(6)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(5)); + assertEquals(true, JulianChronology.INSTANCE.isLeapYear(4)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(3)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(2)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(1)); + assertEquals(true, JulianChronology.INSTANCE.isLeapYear(0)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(-1)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(-2)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(-3)); + assertEquals(true, JulianChronology.INSTANCE.isLeapYear(-4)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(-5)); + assertEquals(false, JulianChronology.INSTANCE.isLeapYear(-6)); + } + + public static Object[][] data_lengthOfMonth() { return new Object[][] { {1900, 1, 31}, {1900, 2, 29}, @@ -317,9 +328,10 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int length) { - assertEquals(JulianDate.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, JulianDate.of(year, month, 1).lengthOfMonth()); } //----------------------------------------------------------------------- @@ -335,7 +347,7 @@ public void test_era_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); JulianDate eraBased = JulianChronology.INSTANCE.date(era, yoe, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -349,44 +361,44 @@ public void test_era_yearDay_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); JulianDate eraBased = JulianChronology.INSTANCE.dateYearDay(era, yoe, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(JulianChronology.INSTANCE.prolepticYear(JulianEra.AD, 4), 4); - assertEquals(JulianChronology.INSTANCE.prolepticYear(JulianEra.AD, 3), 3); - assertEquals(JulianChronology.INSTANCE.prolepticYear(JulianEra.AD, 2), 2); - assertEquals(JulianChronology.INSTANCE.prolepticYear(JulianEra.AD, 1), 1); - assertEquals(JulianChronology.INSTANCE.prolepticYear(JulianEra.BC, 1), 0); - assertEquals(JulianChronology.INSTANCE.prolepticYear(JulianEra.BC, 2), -1); - assertEquals(JulianChronology.INSTANCE.prolepticYear(JulianEra.BC, 3), -2); - assertEquals(JulianChronology.INSTANCE.prolepticYear(JulianEra.BC, 4), -3); + assertEquals(4, JulianChronology.INSTANCE.prolepticYear(JulianEra.AD, 4)); + assertEquals(3, JulianChronology.INSTANCE.prolepticYear(JulianEra.AD, 3)); + assertEquals(2, JulianChronology.INSTANCE.prolepticYear(JulianEra.AD, 2)); + assertEquals(1, JulianChronology.INSTANCE.prolepticYear(JulianEra.AD, 1)); + assertEquals(0, JulianChronology.INSTANCE.prolepticYear(JulianEra.BC, 1)); + assertEquals(-1, JulianChronology.INSTANCE.prolepticYear(JulianEra.BC, 2)); + assertEquals(-2, JulianChronology.INSTANCE.prolepticYear(JulianEra.BC, 3)); + assertEquals(-3, JulianChronology.INSTANCE.prolepticYear(JulianEra.BC, 4)); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void test_prolepticYear_badEra() { - JulianChronology.INSTANCE.prolepticYear(IsoEra.CE, 4); + assertThrows(ClassCastException.class, () -> JulianChronology.INSTANCE.prolepticYear(IsoEra.CE, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(JulianChronology.INSTANCE.eraOf(1), JulianEra.AD); - assertEquals(JulianChronology.INSTANCE.eraOf(0), JulianEra.BC); + assertEquals(JulianEra.AD, JulianChronology.INSTANCE.eraOf(1)); + assertEquals(JulianEra.BC, JulianChronology.INSTANCE.eraOf(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - JulianChronology.INSTANCE.eraOf(2); + assertThrows(DateTimeException.class, () -> JulianChronology.INSTANCE.eraOf(2)); } @Test public void test_Chronology_eras() { List eras = JulianChronology.INSTANCE.eras(); - assertEquals(eras.size(), 2); - assertEquals(eras.contains(JulianEra.BC), true); - assertEquals(eras.contains(JulianEra.AD), true); + assertEquals(2, eras.size()); + assertEquals(true, eras.contains(JulianEra.BC)); + assertEquals(true, eras.contains(JulianEra.AD)); } //----------------------------------------------------------------------- @@ -394,17 +406,16 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(JulianChronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(1, 7)); - assertEquals(JulianChronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 28, 31)); - assertEquals(JulianChronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 365, 366)); - assertEquals(JulianChronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 12)); + assertEquals(ValueRange.of(1, 7), JulianChronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 28, 31), JulianChronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 365, 366), JulianChronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(1, 12), JulianChronology.INSTANCE.range(MONTH_OF_YEAR)); } //----------------------------------------------------------------------- // JulianDate.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { {2012, 1, 23, DAY_OF_MONTH, 1, 31}, {2012, 2, 23, DAY_OF_MONTH, 1, 29}, @@ -426,26 +437,24 @@ Object[][] data_ranges() { {2011, 2, 23, DAY_OF_MONTH, 1, 28}, {2011, 2, 23, DAY_OF_YEAR, 1, 365}, {2011, 2, 23, ALIGNED_WEEK_OF_MONTH, 1, 4}, - - {2011, 2, 23, IsoFields.QUARTER_OF_YEAR, 1, 4}, }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, int expectedMin, int expectedMax) { - assertEquals(JulianDate.of(year, month, dom).range(field), ValueRange.of(expectedMin, expectedMax)); + assertEquals(ValueRange.of(expectedMin, expectedMax), JulianDate.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - JulianDate.of(2012, 6, 30).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> JulianDate.of(2012, 6, 30).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // JulianDate.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 7}, {2014, 5, 26, DAY_OF_MONTH, 26}, @@ -465,21 +474,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(JulianDate.of(year, month, dom).getLong(field), expected); + assertEquals(expected, JulianDate.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - JulianDate.of(2012, 6, 30).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> JulianDate.of(2012, 6, 30).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // JulianDate.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 3, 2014, 5, 22}, {2014, 5, 26, DAY_OF_WEEK, 7, 2014, 5, 26}, @@ -515,16 +524,17 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(JulianDate.of(year, month, dom).with(field, value), JulianDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(JulianDate.of(expectedYear, expectedMonth, expectedDom), JulianDate.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - JulianDate.of(2012, 6, 30).with(MINUTE_OF_DAY, 0); + assertThrows(UnsupportedTemporalTypeException.class, () -> JulianDate.of(2012, 6, 30).with(MINUTE_OF_DAY, 0)); } //----------------------------------------------------------------------- @@ -534,14 +544,14 @@ public void test_with_TemporalField_unsupported() { public void test_adjust1() { JulianDate base = JulianDate.of(2012, 6, 23); JulianDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, JulianDate.of(2012, 6, 30)); + assertEquals(JulianDate.of(2012, 6, 30), test); } @Test public void test_adjust2() { JulianDate base = JulianDate.of(2012, 2, 23); JulianDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, JulianDate.of(2012, 2, 29)); + assertEquals(JulianDate.of(2012, 2, 29), test); } //----------------------------------------------------------------------- @@ -551,13 +561,13 @@ public void test_adjust2() { public void test_adjust_toLocalDate() { JulianDate julian = JulianDate.of(2000, 1, 4); JulianDate test = julian.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, JulianDate.of(2012, 6, 23)); + assertEquals(JulianDate.of(2012, 6, 23), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { JulianDate julian = JulianDate.of(2000, 1, 4); - julian.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> julian.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -567,21 +577,20 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToJulianDate() { JulianDate julian = JulianDate.of(2012, 6, 23); LocalDate test = LocalDate.MIN.with(julian); - assertEquals(test, LocalDate.of(2012, 7, 6)); + assertEquals(LocalDate.of(2012, 7, 6), test); } @Test public void test_LocalDateTime_adjustToJulianDate() { JulianDate julian = JulianDate.of(2012, 6, 23); LocalDateTime test = LocalDateTime.MIN.with(julian); - assertEquals(test, LocalDateTime.of(2012, 7, 6, 0, 0)); + assertEquals(LocalDateTime.of(2012, 7, 6, 0, 0), test); } //----------------------------------------------------------------------- // JulianDate.plus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {2014, 5, 26, 0, DAYS, 2014, 5, 26}, {2014, 5, 26, 8, DAYS, 2014, 6, 3}, @@ -608,31 +617,32 @@ Object[][] data_plus() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(JulianDate.of(year, month, dom).plus(amount, unit), JulianDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(JulianDate.of(expectedYear, expectedMonth, expectedDom), JulianDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(JulianDate.of(year, month, dom).minus(amount, unit), JulianDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(JulianDate.of(expectedYear, expectedMonth, expectedDom), JulianDate.of(year, month, dom).minus(amount, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - JulianDate.of(2012, 6, 30).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> JulianDate.of(2012, 6, 30).plus(0, MINUTES)); } //----------------------------------------------------------------------- // JulianDate.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, DAYS, 0}, {2014, 5, 26, 2014, 6, 1, DAYS, 6}, @@ -660,81 +670,72 @@ Object[][] data_until() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { JulianDate start = JulianDate.of(year1, month1, dom1); JulianDate end = JulianDate.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { JulianDate start = JulianDate.of(2012, 6, 30); JulianDate end = JulianDate.of(2012, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(JulianDate.of(2014, 5, 26).plus(JulianChronology.INSTANCE.period(0, 2, 3)), JulianDate.of(2014, 7, 29)); + assertEquals(JulianDate.of(2014, 7, 29), JulianDate.of(2014, 5, 26).plus(JulianChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(JulianDate.of(2014, 5, 26).plus(Period.ofMonths(2)), JulianDate.of(2014, 7, 26)); + assertThrows(DateTimeException.class, () -> JulianDate.of(2014, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(JulianDate.of(2014, 5, 26).minus(JulianChronology.INSTANCE.period(0, 2, 3)), JulianDate.of(2014, 3, 23)); + assertEquals(JulianDate.of(2014, 3, 23), JulianDate.of(2014, 5, 26).minus(JulianChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(JulianDate.of(2014, 5, 26).minus(Period.ofMonths(2)), JulianDate.of(2014, 3, 26)); + assertThrows(DateTimeException.class, () -> JulianDate.of(2014, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - void test_equals() { - JulianDate a1 = JulianDate.of(2000, 1, 3); - JulianDate a2 = JulianDate.of(2000, 1, 3); - JulianDate b = JulianDate.of(2000, 1, 4); - JulianDate c = JulianDate.of(2000, 2, 3); - JulianDate d = JulianDate.of(2001, 1, 3); - - assertEquals(a1.equals(a1), true); - assertEquals(a1.equals(a2), true); - assertEquals(a1.equals(b), false); - assertEquals(a1.equals(c), false); - assertEquals(a1.equals(d), false); - - assertEquals(a1.equals(null), false); - assertEquals(a1.equals(""), false); - - assertEquals(a1.hashCode(), a2.hashCode()); + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(JulianDate.of(2000, 1, 3), JulianDate.of(2000, 1, 3)) + .addEqualityGroup(JulianDate.of(2000, 1, 4), JulianDate.of(2000, 1, 4)) + .addEqualityGroup(JulianDate.of(2000, 2, 3), JulianDate.of(2000, 2, 3)) + .addEqualityGroup(JulianDate.of(2001, 1, 3), JulianDate.of(2001, 1, 3)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {JulianDate.of(1, 1, 1), "Julian AD 1-01-01"}, {JulianDate.of(2012, 6, 23), "Julian AD 2012-06-23"}, }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(JulianDate julian, String expected) { - assertEquals(julian.toString(), expected); + assertEquals(expected, julian.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestPaxChronology.java b/src/test/java/org/threeten/extra/chrono/TestPaxChronology.java index d15a4cdf..3f474cbf 100644 --- a/src/test/java/org/threeten/extra/chrono/TestPaxChronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestPaxChronology.java @@ -53,7 +53,9 @@ import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.time.DateTimeException; import java.time.LocalDate; @@ -71,16 +73,17 @@ import java.time.temporal.ValueRange; import java.time.temporal.WeekFields; import java.util.List; -import java.util.function.Predicate; +import java.util.function.IntPredicate; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test @SuppressWarnings({"static-method", "javadoc"}) public class TestPaxChronology { @@ -90,26 +93,25 @@ public class TestPaxChronology { @Test public void test_chronology_of_name() { Chronology chrono = Chronology.of("Pax"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, PaxChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Pax"); - Assert.assertEquals(chrono.getCalendarType(), "pax"); + assertNotNull(chrono); + assertEquals(PaxChronology.INSTANCE, chrono); + assertEquals("Pax", chrono.getId()); + assertEquals("pax", chrono.getCalendarType()); } @Test public void test_chronology_of_name_id() { Chronology chrono = Chronology.of("pax"); - Assert.assertNotNull(chrono); - Assert.assertEquals(chrono, PaxChronology.INSTANCE); - Assert.assertEquals(chrono.getId(), "Pax"); - Assert.assertEquals(chrono.getCalendarType(), "pax"); + assertNotNull(chrono); + assertEquals(PaxChronology.INSTANCE, chrono); + assertEquals("Pax", chrono.getId()); + assertEquals("pax", chrono.getCalendarType()); } //----------------------------------------------------------------------- // creation, toLocalDate() //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { {PaxDate.of(1, 1, 1), LocalDate.of(0, 12, 31)}, {PaxDate.of(1, 1, 2), LocalDate.of(1, 1, 1)}, @@ -173,74 +175,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_PaxDate(PaxDate pax, LocalDate iso) { - assertEquals(LocalDate.from(pax), iso); + assertEquals(iso, LocalDate.from(pax)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_PaxDate_from_LocalDate(PaxDate pax, LocalDate iso) { - assertEquals(PaxDate.from(iso), pax); + assertEquals(pax, PaxDate.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_PaxDate_chronology_dateEpochDay(PaxDate pax, LocalDate iso) { - assertEquals(PaxChronology.INSTANCE.dateEpochDay(iso.toEpochDay()), pax); + assertEquals(pax, PaxChronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_PaxDate_toEpochDay(PaxDate pax, LocalDate iso) { - assertEquals(pax.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), pax.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_PaxDate_until_PaxDate(PaxDate pax, LocalDate iso) { - assertEquals(pax.until(pax), PaxChronology.INSTANCE.period(0, 0, 0)); + assertEquals(PaxChronology.INSTANCE.period(0, 0, 0), pax.until(pax)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_PaxDate_until_LocalDate(PaxDate pax, LocalDate iso) { - assertEquals(pax.until(iso), PaxChronology.INSTANCE.period(0, 0, 0)); + assertEquals(PaxChronology.INSTANCE.period(0, 0, 0), pax.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_PaxDate(PaxDate pax, LocalDate iso) { - assertEquals(iso.until(pax), Period.ZERO); + assertEquals(Period.ZERO, iso.until(pax)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(PaxDate pax, LocalDate iso) { - assertEquals(PaxChronology.INSTANCE.date(iso), pax); + assertEquals(pax, PaxChronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(PaxDate pax, LocalDate iso) { - assertEquals(LocalDate.from(pax.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(pax.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(pax.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(pax.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(pax.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(pax.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(pax.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(pax.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(pax.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(pax.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(PaxDate pax, LocalDate iso) { - assertEquals(LocalDate.from(pax.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(pax.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(pax.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(pax.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(pax.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(pax.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(pax.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(pax.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(pax.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(pax.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(PaxDate pax, LocalDate iso) { - assertEquals(pax.until(iso.plusDays(0), DAYS), 0); - assertEquals(pax.until(iso.plusDays(1), DAYS), 1); - assertEquals(pax.until(iso.plusDays(35), DAYS), 35); - assertEquals(pax.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, pax.until(iso.plusDays(0), DAYS)); + assertEquals(1, pax.until(iso.plusDays(1), DAYS)); + assertEquals(35, pax.until(iso.plusDays(35), DAYS)); + assertEquals(-40, pax.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {1900, 0, 0}, @@ -286,14 +298,15 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - PaxDate.of(year, month, dom); + assertThrows(DateTimeException.class, () -> PaxDate.of(year, month, dom)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_chronology_dateYearDay_badDate() { - PaxChronology.INSTANCE.dateYearDay(2001, 365); + assertThrows(DateTimeException.class, () -> PaxChronology.INSTANCE.dateYearDay(2001, 365)); } //----------------------------------------------------------------------- @@ -301,43 +314,42 @@ public void test_chronology_dateYearDay_badDate() { //----------------------------------------------------------------------- @Test public void test_isLeapYear_loop() { - Predicate isLeapYear = year -> { + IntPredicate isLeapYear = year -> { int lastTwoDigits = Math.abs(year % 100); return (year % 400 != 0 && (lastTwoDigits == 0 || lastTwoDigits % 6 == 0)) || lastTwoDigits == 99; }; for (int year = -500; year < 500; year++) { PaxDate base = PaxDate.of(year, 1, 1); - assertEquals(base.isLeapYear(), isLeapYear.test(year), "Year " + year + " is failing"); - assertEquals(PaxChronology.INSTANCE.isLeapYear(year), isLeapYear.test(year), "Year " + year + " is failing"); + assertEquals(isLeapYear.test(year), base.isLeapYear()); + assertEquals(isLeapYear.test(year), PaxChronology.INSTANCE.isLeapYear(year)); } } @Test public void test_isLeapYear_specific() { - assertEquals(PaxChronology.INSTANCE.isLeapYear(400), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(100), true); - assertEquals(PaxChronology.INSTANCE.isLeapYear(99), true); - assertEquals(PaxChronology.INSTANCE.isLeapYear(7), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(6), true); - assertEquals(PaxChronology.INSTANCE.isLeapYear(5), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(4), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(3), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(2), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(1), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(0), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-1), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-2), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-3), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-4), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-5), false); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-6), true); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-99), true); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-100), true); - assertEquals(PaxChronology.INSTANCE.isLeapYear(-400), false); - } - - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(400)); + assertEquals(true, PaxChronology.INSTANCE.isLeapYear(100)); + assertEquals(true, PaxChronology.INSTANCE.isLeapYear(99)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(7)); + assertEquals(true, PaxChronology.INSTANCE.isLeapYear(6)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(5)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(4)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(3)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(2)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(1)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(0)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(-1)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(-2)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(-3)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(-4)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(-5)); + assertEquals(true, PaxChronology.INSTANCE.isLeapYear(-6)); + assertEquals(true, PaxChronology.INSTANCE.isLeapYear(-99)); + assertEquals(true, PaxChronology.INSTANCE.isLeapYear(-100)); + assertEquals(false, PaxChronology.INSTANCE.isLeapYear(-400)); + } + + public static Object[][] data_lengthOfMonth() { return new Object[][] { {1900, 1, 28}, {1900, 2, 28}, @@ -365,9 +377,10 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int length) { - assertEquals(PaxDate.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, PaxDate.of(year, month, 1).lengthOfMonth()); } //----------------------------------------------------------------------- @@ -383,7 +396,7 @@ public void test_era_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); PaxDate eraBased = PaxChronology.INSTANCE.date(era, yoe, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -397,44 +410,44 @@ public void test_era_yearDay_loop() { int yoe = (year <= 0 ? 1 - year : year); assertEquals(yoe, base.get(YEAR_OF_ERA)); PaxDate eraBased = PaxChronology.INSTANCE.dateYearDay(era, yoe, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(PaxChronology.INSTANCE.prolepticYear(PaxEra.CE, 4), 4); - assertEquals(PaxChronology.INSTANCE.prolepticYear(PaxEra.CE, 3), 3); - assertEquals(PaxChronology.INSTANCE.prolepticYear(PaxEra.CE, 2), 2); - assertEquals(PaxChronology.INSTANCE.prolepticYear(PaxEra.CE, 1), 1); - assertEquals(PaxChronology.INSTANCE.prolepticYear(PaxEra.BCE, 1), 0); - assertEquals(PaxChronology.INSTANCE.prolepticYear(PaxEra.BCE, 2), -1); - assertEquals(PaxChronology.INSTANCE.prolepticYear(PaxEra.BCE, 3), -2); - assertEquals(PaxChronology.INSTANCE.prolepticYear(PaxEra.BCE, 4), -3); + assertEquals(4, PaxChronology.INSTANCE.prolepticYear(PaxEra.CE, 4)); + assertEquals(3, PaxChronology.INSTANCE.prolepticYear(PaxEra.CE, 3)); + assertEquals(2, PaxChronology.INSTANCE.prolepticYear(PaxEra.CE, 2)); + assertEquals(1, PaxChronology.INSTANCE.prolepticYear(PaxEra.CE, 1)); + assertEquals(0, PaxChronology.INSTANCE.prolepticYear(PaxEra.BCE, 1)); + assertEquals(-1, PaxChronology.INSTANCE.prolepticYear(PaxEra.BCE, 2)); + assertEquals(-2, PaxChronology.INSTANCE.prolepticYear(PaxEra.BCE, 3)); + assertEquals(-3, PaxChronology.INSTANCE.prolepticYear(PaxEra.BCE, 4)); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void test_prolepticYear_badEra() { - PaxChronology.INSTANCE.prolepticYear(IsoEra.CE, 4); + assertThrows(ClassCastException.class, () -> PaxChronology.INSTANCE.prolepticYear(IsoEra.CE, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(PaxChronology.INSTANCE.eraOf(1), PaxEra.CE); - assertEquals(PaxChronology.INSTANCE.eraOf(0), PaxEra.BCE); + assertEquals(PaxEra.CE, PaxChronology.INSTANCE.eraOf(1)); + assertEquals(PaxEra.BCE, PaxChronology.INSTANCE.eraOf(0)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - PaxChronology.INSTANCE.eraOf(2); + assertThrows(DateTimeException.class, () -> PaxChronology.INSTANCE.eraOf(2)); } @Test public void test_Chronology_eras() { List eras = PaxChronology.INSTANCE.eras(); - assertEquals(eras.size(), 2); - assertEquals(eras.contains(PaxEra.BCE), true); - assertEquals(eras.contains(PaxEra.CE), true); + assertEquals(2, eras.size()); + assertEquals(true, eras.contains(PaxEra.BCE)); + assertEquals(true, eras.contains(PaxEra.CE)); } //----------------------------------------------------------------------- @@ -442,17 +455,16 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(PaxChronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(1, 7)); - assertEquals(PaxChronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 7, 28)); - assertEquals(PaxChronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 364, 371)); - assertEquals(PaxChronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 13, 14)); + assertEquals(ValueRange.of(1, 7), PaxChronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 7, 28), PaxChronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 364, 371), PaxChronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(1, 13, 14), PaxChronology.INSTANCE.range(MONTH_OF_YEAR)); } //----------------------------------------------------------------------- // PaxDate.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { {2012, 1, 23, DAY_OF_MONTH, 1, 28}, {2012, 2, 23, DAY_OF_MONTH, 1, 28}, @@ -483,21 +495,21 @@ Object[][] data_ranges() { }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, int expectedMin, int expectedMax) { - assertEquals(PaxDate.of(year, month, dom).range(field), ValueRange.of(expectedMin, expectedMax)); + assertEquals(ValueRange.of(expectedMin, expectedMax), PaxDate.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - PaxDate.of(2012, 6, 28).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> PaxDate.of(2012, 6, 28).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // PaxDate.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 4}, {2014, 5, 26, DAY_OF_MONTH, 26}, @@ -517,21 +529,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(PaxDate.of(year, month, dom).getLong(field), expected); + assertEquals(expected, PaxDate.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - PaxDate.of(2012, 6, 28).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> PaxDate.of(2012, 6, 28).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // PaxDate.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 3, 2014, 5, 25}, {2014, 5, 26, DAY_OF_WEEK, 4, 2014, 5, 26}, @@ -567,16 +579,17 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(PaxDate.of(year, month, dom).with(field, value), PaxDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(PaxDate.of(expectedYear, expectedMonth, expectedDom), PaxDate.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - PaxDate.of(2012, 6, 28).with(MINUTE_OF_DAY, 0); + assertThrows(UnsupportedTemporalTypeException.class, () -> PaxDate.of(2012, 6, 28).with(MINUTE_OF_DAY, 0)); } //----------------------------------------------------------------------- @@ -586,14 +599,14 @@ public void test_with_TemporalField_unsupported() { public void test_adjust1() { PaxDate base = PaxDate.of(2012, 6, 23); PaxDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, PaxDate.of(2012, 6, 28)); + assertEquals(PaxDate.of(2012, 6, 28), test); } @Test public void test_adjust2() { PaxDate base = PaxDate.of(2012, 13, 2); PaxDate test = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(test, PaxDate.of(2012, 13, 7)); + assertEquals(PaxDate.of(2012, 13, 7), test); } //----------------------------------------------------------------------- @@ -603,13 +616,13 @@ public void test_adjust2() { public void test_adjust_toLocalDate() { PaxDate pax = PaxDate.of(2000, 1, 4); PaxDate test = pax.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, PaxDate.of(2012, 7, 27)); + assertEquals(PaxDate.of(2012, 7, 27), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { PaxDate pax = PaxDate.of(2000, 1, 4); - pax.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> pax.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -619,21 +632,20 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToPaxDate() { PaxDate pax = PaxDate.of(2012, 6, 23); LocalDate test = LocalDate.MIN.with(pax); - assertEquals(test, LocalDate.of(2012, 6, 4)); + assertEquals(LocalDate.of(2012, 6, 4), test); } @Test public void test_LocalDateTime_adjustToPaxDate() { PaxDate pax = PaxDate.of(2012, 6, 23); LocalDateTime test = LocalDateTime.MIN.with(pax); - assertEquals(test, LocalDateTime.of(2012, 6, 4, 0, 0)); + assertEquals(LocalDateTime.of(2012, 6, 4, 0, 0), test); } //----------------------------------------------------------------------- // PaxDate.plus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {2014, 5, 26, 0, DAYS, 2014, 5, 26}, {2014, 5, 26, 8, DAYS, 2014, 6, 6}, @@ -670,8 +682,7 @@ Object[][] data_plus() { }; } - @DataProvider(name = "plusLeap") - Object[][] data_plus_leap() { + public static Object[][] data_plus_leap() { return new Object[][] { {2012, 12, 26, 1, MONTHS, 2012, 13, 7}, {2012, 14, 26, -1, MONTHS, 2012, 13, 7}, @@ -679,8 +690,7 @@ Object[][] data_plus_leap() { }; } - @DataProvider(name = "minusLeap") - Object[][] data_minus_leap() { + public static Object[][] data_minus_leap() { return new Object[][] { {2012, 13, 7, -1, MONTHS, 2012, 12, 26}, {2012, 13, 7, 1, MONTHS, 2012, 14, 26}, @@ -688,45 +698,48 @@ Object[][] data_minus_leap() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(PaxDate.of(year, month, dom).plus(amount, unit), PaxDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(PaxDate.of(expectedYear, expectedMonth, expectedDom), PaxDate.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plusLeap") + @ParameterizedTest + @MethodSource("data_plus_leap") public void test_plus_leap_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { test_plus_TemporalUnit(year, month, dom, amount, unit, expectedYear, expectedMonth, expectedDom); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(PaxDate.of(year, month, dom).minus(amount, unit), PaxDate.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(PaxDate.of(expectedYear, expectedMonth, expectedDom), PaxDate.of(year, month, dom).minus(amount, unit)); } - @Test(dataProvider = "minusLeap") + @ParameterizedTest + @MethodSource("data_minus_leap") public void test_minus_leap_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { test_minus_TemporalUnit(year, month, dom, amount, unit, expectedYear, expectedMonth, expectedDom); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - PaxDate.of(2012, 6, 10).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> PaxDate.of(2012, 6, 10).plus(0, MINUTES)); } //----------------------------------------------------------------------- // PaxDate.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, DAYS, 0}, {2014, 5, 26, 2014, 6, 4, DAYS, 6}, @@ -767,8 +780,7 @@ Object[][] data_until() { }; } - @DataProvider(name = "until_period") - Object[][] data_until_period() { + public static Object[][] data_until_period() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, 0, 0, 0}, {2014, 5, 26, 2014, 6, 4, 0, 0, 6}, @@ -795,17 +807,19 @@ Object[][] data_until_period() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { PaxDate start = PaxDate.of(year1, month1, dom1); PaxDate end = PaxDate.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(dataProvider = "until_period") + @ParameterizedTest + @MethodSource("data_until_period") public void test_until_end( int year1, int month1, int dom1, int year2, int month2, int dom2, @@ -813,74 +827,64 @@ public void test_until_end( PaxDate start = PaxDate.of(year1, month1, dom1); PaxDate end = PaxDate.of(year2, month2, dom2); ChronoPeriod period = PaxChronology.INSTANCE.period(yearPeriod, monthPeriod, dayPeriod); - assertEquals(start.until(end), period); + assertEquals(period, start.until(end)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { PaxDate start = PaxDate.of(2012, 6, 28); PaxDate end = PaxDate.of(2012, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(PaxDate.of(2014, 5, 26).plus(PaxChronology.INSTANCE.period(0, 2, 2)), PaxDate.of(2014, 7, 28)); + assertEquals(PaxDate.of(2014, 7, 28), PaxDate.of(2014, 5, 26).plus(PaxChronology.INSTANCE.period(0, 2, 2))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(PaxDate.of(2014, 5, 26).plus(Period.ofMonths(2)), PaxDate.of(2014, 7, 26)); + assertThrows(DateTimeException.class, () -> PaxDate.of(2014, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(PaxDate.of(2014, 5, 26).minus(PaxChronology.INSTANCE.period(0, 2, 3)), PaxDate.of(2014, 3, 23)); + assertEquals(PaxDate.of(2014, 3, 23), PaxDate.of(2014, 5, 26).minus(PaxChronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(PaxDate.of(2014, 5, 26).minus(Period.ofMonths(2)), PaxDate.of(2014, 3, 26)); + assertThrows(DateTimeException.class, () -> PaxDate.of(2014, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - void test_equals() { - PaxDate a1 = PaxDate.of(2000, 1, 3); - PaxDate a2 = PaxDate.of(2000, 1, 3); - PaxDate b = PaxDate.of(2000, 1, 4); - PaxDate c = PaxDate.of(2000, 2, 3); - PaxDate d = PaxDate.of(2001, 1, 3); - - assertEquals(a1.equals(a1), true); - assertEquals(a1.equals(a2), true); - assertEquals(a1.equals(b), false); - assertEquals(a1.equals(c), false); - assertEquals(a1.equals(d), false); - - assertEquals(a1.equals(null), false); - assertEquals(a1.equals(""), false); - - assertEquals(a1.hashCode(), a2.hashCode()); + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(PaxDate.of(2000, 1, 3), PaxDate.of(2000, 1, 3)) + .addEqualityGroup(PaxDate.of(2000, 1, 4), PaxDate.of(2000, 1, 4)) + .addEqualityGroup(PaxDate.of(2000, 2, 3), PaxDate.of(2000, 2, 3)) + .addEqualityGroup(PaxDate.of(2001, 1, 3), PaxDate.of(2001, 1, 3)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {PaxDate.of(1, 1, 1), "Pax CE 1-01-01"}, {PaxDate.of(2012, 6, 23), "Pax CE 2012-06-23"}, }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(PaxDate pax, String expected) { - assertEquals(pax.toString(), expected); + assertEquals(expected, pax.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestSymmetry010Chronology.java b/src/test/java/org/threeten/extra/chrono/TestSymmetry010Chronology.java index fda786b1..97921a58 100644 --- a/src/test/java/org/threeten/extra/chrono/TestSymmetry010Chronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestSymmetry010Chronology.java @@ -31,66 +31,65 @@ */ package org.threeten.extra.chrono; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.MILLENNIA; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; import java.time.Period; - -import java.time.chrono.Chronology; import java.time.chrono.ChronoPeriod; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.HijrahEra; import java.time.chrono.IsoEra; import java.time.chrono.JapaneseEra; import java.time.chrono.MinguoEra; import java.time.chrono.ThaiBuddhistEra; - import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; -import java.time.temporal.ValueRange; import java.time.temporal.UnsupportedTemporalTypeException; - +import java.time.temporal.ValueRange; import java.util.List; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; -import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.DAY_OF_WEEK; -import static java.time.temporal.ChronoField.DAY_OF_YEAR; -import static java.time.temporal.ChronoField.EPOCH_DAY; -import static java.time.temporal.ChronoField.ERA; -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; -import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; -import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static java.time.temporal.ChronoField.YEAR; -import static java.time.temporal.ChronoField.MINUTE_OF_DAY; - -import static java.time.temporal.ChronoUnit.DAYS; -import static java.time.temporal.ChronoUnit.ERAS; -import static java.time.temporal.ChronoUnit.MONTHS; -import static java.time.temporal.ChronoUnit.WEEKS; -import static java.time.temporal.ChronoUnit.YEARS; -import static java.time.temporal.ChronoUnit.DECADES; -import static java.time.temporal.ChronoUnit.CENTURIES; -import static java.time.temporal.ChronoUnit.MILLENNIA; -import static java.time.temporal.ChronoUnit.MINUTES; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test @SuppressWarnings({"static-method", "javadoc"}) public class TestSymmetry010Chronology { @@ -101,16 +100,15 @@ public class TestSymmetry010Chronology { public void test_chronology() { Chronology chrono = Chronology.of("Sym010"); assertNotNull(chrono); - assertEquals(chrono, Symmetry010Chronology.INSTANCE); - assertEquals(chrono.getId(), "Sym010"); - assertEquals(chrono.getCalendarType(), null); + assertEquals(Symmetry010Chronology.INSTANCE, chrono); + assertEquals("Sym010", chrono.getId()); + assertEquals(null, chrono.getCalendarType()); } //----------------------------------------------------------------------- // Symmetry010Date.of //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { { Symmetry010Date.of( 1, 1, 1), LocalDate.of( 1, 1, 1) }, { Symmetry010Date.of( 272, 2, 28), LocalDate.of( 272, 2, 27) }, // Constantine the Great, Roman emperor (d. 337) @@ -146,74 +144,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_Symmetry010Date(Symmetry010Date sym010, LocalDate iso) { - assertEquals(LocalDate.from(sym010), iso); + assertEquals(iso, LocalDate.from(sym010)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry010Date_from_LocalDate(Symmetry010Date sym010, LocalDate iso) { - assertEquals(Symmetry010Date.from(iso), sym010); + assertEquals(sym010, Symmetry010Date.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry010Date_chronology_dateEpochDay(Symmetry010Date sym010, LocalDate iso) { - assertEquals(Symmetry010Chronology.INSTANCE.dateEpochDay(iso.toEpochDay()), sym010); + assertEquals(sym010, Symmetry010Chronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry010Date_toEpochDay(Symmetry010Date sym010, LocalDate iso) { - assertEquals(sym010.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), sym010.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry010Date_until_Symmetry010Date(Symmetry010Date sym010, LocalDate iso) { - assertEquals(sym010.until(sym010), Symmetry010Chronology.INSTANCE.period(0, 0, 0)); + assertEquals(Symmetry010Chronology.INSTANCE.period(0, 0, 0), sym010.until(sym010)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry010Date_until_LocalDate(Symmetry010Date sym010, LocalDate iso) { - assertEquals(sym010.until(iso), Symmetry010Chronology.INSTANCE.period(0, 0, 0)); + assertEquals(Symmetry010Chronology.INSTANCE.period(0, 0, 0), sym010.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(Symmetry010Date sym010, LocalDate iso) { - assertEquals(Symmetry010Chronology.INSTANCE.date(iso), sym010); + assertEquals(sym010, Symmetry010Chronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_Symmetry010Date(Symmetry010Date sym010, LocalDate iso) { - assertEquals(iso.until(sym010), Period.ZERO); + assertEquals(Period.ZERO, iso.until(sym010)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(Symmetry010Date sym010, LocalDate iso) { - assertEquals(LocalDate.from(sym010.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(sym010.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(sym010.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(sym010.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(sym010.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(sym010.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(sym010.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(sym010.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(sym010.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(sym010.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(Symmetry010Date sym010, LocalDate iso) { - assertEquals(LocalDate.from(sym010.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(sym010.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(sym010.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(sym010.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(sym010.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(sym010.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(sym010.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(sym010.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(sym010.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(sym010.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(Symmetry010Date sym010, LocalDate iso) { - assertEquals(sym010.until(iso.plusDays(0), DAYS), 0); - assertEquals(sym010.until(iso.plusDays(1), DAYS), 1); - assertEquals(sym010.until(iso.plusDays(35), DAYS), 35); - assertEquals(sym010.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, sym010.until(iso.plusDays(0), DAYS)); + assertEquals(1, sym010.until(iso.plusDays(1), DAYS)); + assertEquals(35, sym010.until(iso.plusDays(35), DAYS)); + assertEquals(-40, sym010.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {-1, 13, 28}, {-1, 13, 29}, @@ -245,13 +253,13 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - Symmetry010Date.of(year, month, dom); + assertThrows(DateTimeException.class, () -> Symmetry010Date.of(year, month, dom)); } - @DataProvider(name = "badLeapDates") - Object[][] data_badLeapDates() { + public static Object[][] data_badLeapDates() { return new Object[][] { {1}, {100}, @@ -260,9 +268,10 @@ Object[][] data_badLeapDates() { }; } - @Test(dataProvider = "badLeapDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badLeapDates") public void badLeapDayDates(int year) { - Symmetry010Date.of(year, 12, 37); + assertThrows(DateTimeException.class, () -> Symmetry010Date.of(year, 12, 37)); } //----------------------------------------------------------------------- @@ -281,7 +290,7 @@ public void test_isLeapYear_specific() { // Symmetry010Date.isLeapWeek //----------------------------------------------------------------------- @Test - void test_leapWeek() { + public void test_leapWeek() { assertTrue(Symmetry010Date.of (2015, 12, 31).isLeapWeek()); assertTrue(Symmetry010Date.of (2015, 12, 32).isLeapWeek()); assertTrue(Symmetry010Date.of (2015, 12, 33).isLeapWeek()); @@ -294,8 +303,7 @@ void test_leapWeek() { //----------------------------------------------------------------------- // Symmetry010Date.lengthOfMonth //----------------------------------------------------------------------- - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + public static Object[][] data_lengthOfMonth() { return new Object[][] { {2000, 1, 28, 30}, {2000, 2, 28, 31}, @@ -313,20 +321,22 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int day, int length) { - assertEquals(Symmetry010Date.of(year, month, day).lengthOfMonth(), length); + assertEquals(length, Symmetry010Date.of(year, month, day).lengthOfMonth()); } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonthFirst(int year, int month, int day, int length) { - assertEquals(Symmetry010Date.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, Symmetry010Date.of(year, month, 1).lengthOfMonth()); } @Test public void test_lengthOfMonth_specific() { - assertEquals(Symmetry010Date.of(2000, 12, 1).lengthOfMonth(), 30); - assertEquals(Symmetry010Date.of(2004, 12, 1).lengthOfMonth(), 37); + assertEquals(30, Symmetry010Date.of(2000, 12, 1).lengthOfMonth()); + assertEquals(37, Symmetry010Date.of(2004, 12, 1).lengthOfMonth()); } //----------------------------------------------------------------------- @@ -343,7 +353,7 @@ public void test_era_loop() { assertEquals(era, base.getEra()); assertEquals(year, base.get(YEAR_OF_ERA)); Symmetry010Date eraBased = Symmetry010Chronology.INSTANCE.date(era, year, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } for (int year = -200; year < 0; year++) { @@ -353,7 +363,7 @@ public void test_era_loop() { assertEquals(era, base.getEra()); assertEquals(1 - year, base.get(YEAR_OF_ERA)); Symmetry010Date eraBased = Symmetry010Chronology.INSTANCE.date(era, year, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -366,22 +376,21 @@ public void test_era_yearDay_loop() { assertEquals(era, base.getEra()); assertEquals(year, base.get(YEAR_OF_ERA)); Symmetry010Date eraBased = Symmetry010Chronology.INSTANCE.dateYearDay(era, year, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 4), 4); - assertEquals(Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 3), 3); - assertEquals(Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 2), 2); - assertEquals(Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 1), 1); - assertEquals(Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 2000), 2000); - assertEquals(Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 1582), 1582); + assertEquals(4, Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 4)); + assertEquals(3, Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 3)); + assertEquals(2, Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 2)); + assertEquals(1, Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 1)); + assertEquals(2000, Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 2000)); + assertEquals(1582, Symmetry010Chronology.INSTANCE.prolepticYear(IsoEra.CE, 1582)); } - @DataProvider(name = "prolepticYearBadEra") - Object[][] data_prolepticYear_badEra() { + public static Object[][] data_prolepticYear_badEra() { return new Era[][] { { AccountingEra.BCE }, { AccountingEra.CE }, @@ -407,26 +416,27 @@ Object[][] data_prolepticYear_badEra() { }; } - @Test(dataProvider = "prolepticYearBadEra", expectedExceptions = ClassCastException.class) + @ParameterizedTest + @MethodSource("data_prolepticYear_badEra") public void test_prolepticYear_badEra(Era era) { - Symmetry010Chronology.INSTANCE.prolepticYear(era, 4); + assertThrows(ClassCastException.class, () -> Symmetry010Chronology.INSTANCE.prolepticYear(era, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(Symmetry010Chronology.INSTANCE.eraOf(0), IsoEra.BCE); - assertEquals(Symmetry010Chronology.INSTANCE.eraOf(1), IsoEra.CE); + assertEquals(IsoEra.BCE, Symmetry010Chronology.INSTANCE.eraOf(0)); + assertEquals(IsoEra.CE, Symmetry010Chronology.INSTANCE.eraOf(1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - Symmetry010Chronology.INSTANCE.eraOf(2); + assertThrows(DateTimeException.class, () -> Symmetry010Chronology.INSTANCE.eraOf(2)); } @Test public void test_Chronology_eras() { List eras = Symmetry010Chronology.INSTANCE.eras(); - assertEquals(eras.size(), 2); + assertEquals(2, eras.size()); assertTrue(eras.contains(IsoEra.BCE)); assertTrue(eras.contains(IsoEra.CE)); } @@ -436,26 +446,25 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(Symmetry010Chronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_MONTH), ValueRange.of(1, 7)); - assertEquals(Symmetry010Chronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_YEAR), ValueRange.of(1, 7)); - assertEquals(Symmetry010Chronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH), ValueRange.of(1, 4, 5)); - assertEquals(Symmetry010Chronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR), ValueRange.of(1, 52, 53)); - assertEquals(Symmetry010Chronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(1, 7)); - assertEquals(Symmetry010Chronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 30, 37)); - assertEquals(Symmetry010Chronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 364, 371)); - assertEquals(Symmetry010Chronology.INSTANCE.range(ERA), ValueRange.of(0, 1)); - assertEquals(Symmetry010Chronology.INSTANCE.range(EPOCH_DAY), ValueRange.of(-1_000_000 * 364L - 177_474 * 7 - 719_162, 1_000_000 * 364L + 177_474 * 7 - 719_162)); - assertEquals(Symmetry010Chronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 12)); - assertEquals(Symmetry010Chronology.INSTANCE.range(PROLEPTIC_MONTH), ValueRange.of(-12_000_000L, 11_999_999L)); - assertEquals(Symmetry010Chronology.INSTANCE.range(YEAR), ValueRange.of(-1_000_000L, 1_000_000)); - assertEquals(Symmetry010Chronology.INSTANCE.range(YEAR_OF_ERA), ValueRange.of(-1_000_000, 1_000_000)); + assertEquals(ValueRange.of(1, 7), Symmetry010Chronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(ValueRange.of(1, 7), Symmetry010Chronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(ValueRange.of(1, 4, 5), Symmetry010Chronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH)); + assertEquals(ValueRange.of(1, 52, 53), Symmetry010Chronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR)); + assertEquals(ValueRange.of(1, 7), Symmetry010Chronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 30, 37), Symmetry010Chronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 364, 371), Symmetry010Chronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(0, 1), Symmetry010Chronology.INSTANCE.range(ERA)); + assertEquals(ValueRange.of(-1_000_000 * 364L - 177_474 * 7 - 719_162, 1_000_000 * 364L + 177_474 * 7 - 719_162), Symmetry010Chronology.INSTANCE.range(EPOCH_DAY)); + assertEquals(ValueRange.of(1, 12), Symmetry010Chronology.INSTANCE.range(MONTH_OF_YEAR)); + assertEquals(ValueRange.of(-12_000_000L, 11_999_999L), Symmetry010Chronology.INSTANCE.range(PROLEPTIC_MONTH)); + assertEquals(ValueRange.of(-1_000_000L, 1_000_000), Symmetry010Chronology.INSTANCE.range(YEAR)); + assertEquals(ValueRange.of(-1_000_000, 1_000_000), Symmetry010Chronology.INSTANCE.range(YEAR_OF_ERA)); } //----------------------------------------------------------------------- // Symmetry010Date.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { // Leap Day and Year Day are members of months {2012, 1, 23, DAY_OF_MONTH, ValueRange.of(1, 30)}, @@ -500,21 +509,21 @@ Object[][] data_ranges() { }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, ValueRange range) { - assertEquals(Symmetry010Date.of(year, month, dom).range(field), range); + assertEquals(range, Symmetry010Date.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - Symmetry010Date.of(2012, 6, 28).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> Symmetry010Date.of(2012, 6, 28).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // Symmetry010Date.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 2}, {2014, 5, 26, DAY_OF_MONTH, 26}, @@ -548,21 +557,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(Symmetry010Date.of(year, month, dom).getLong(field), expected); + assertEquals(expected, Symmetry010Date.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - Symmetry010Date.of(2012, 6, 28).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> Symmetry010Date.of(2012, 6, 28).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // Symmetry010Date.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 1, 2014, 5, 20}, {2014, 5, 26, DAY_OF_WEEK, 5, 2014, 5, 24}, @@ -637,15 +646,15 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(Symmetry010Date.of(year, month, dom).with(field, value), Symmetry010Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry010Date.of(expectedYear, expectedMonth, expectedDom), Symmetry010Date.of(year, month, dom).with(field, value)); } - @DataProvider(name = "with_bad") - Object[][] data_with_bad() { + public static Object[][] data_with_bad() { return new Object[][] { {2013, 1, 1, ALIGNED_DAY_OF_WEEK_IN_MONTH, -1}, {2013, 1, 1, ALIGNED_DAY_OF_WEEK_IN_MONTH, 8}, @@ -683,21 +692,21 @@ Object[][] data_with_bad() { }; } - @Test(dataProvider = "with_bad", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_with_bad") public void test_with_TemporalField_badValue(int year, int month, int dom, TemporalField field, long value) { - Symmetry010Date.of(year, month, dom).with(field, value); + assertThrows(DateTimeException.class, () -> Symmetry010Date.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - Symmetry010Date.of(2012, 6, 28).with(MINUTE_OF_DAY, 10); + assertThrows(UnsupportedTemporalTypeException.class, () -> Symmetry010Date.of(2012, 6, 28).with(MINUTE_OF_DAY, 10)); } //----------------------------------------------------------------------- // Symmetry010Date.with(TemporalAdjuster) //----------------------------------------------------------------------- - @DataProvider(name = "temporalAdjusters_lastDayOfMonth") - Object[][] data_temporalAdjusters_lastDayOfMonth() { + public static Object[][] data_temporalAdjusters_lastDayOfMonth() { return new Object[][] { {2012, 1, 23, 2012, 1, 30}, {2012, 2, 23, 2012, 2, 31}, @@ -715,12 +724,13 @@ Object[][] data_temporalAdjusters_lastDayOfMonth() { }; } - @Test(dataProvider = "temporalAdjusters_lastDayOfMonth") + @ParameterizedTest + @MethodSource("data_temporalAdjusters_lastDayOfMonth") public void test_temporalAdjusters_LastDayOfMonth(int year, int month, int day, int expectedYear, int expectedMonth, int expectedDay) { Symmetry010Date base = Symmetry010Date.of(year, month, day); Symmetry010Date expected = Symmetry010Date.of(expectedYear, expectedMonth, expectedDay); Symmetry010Date actual = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(actual, expected); + assertEquals(expected, actual); } //----------------------------------------------------------------------- @@ -730,13 +740,13 @@ public void test_temporalAdjusters_LastDayOfMonth(int year, int month, int day, public void test_adjust_toLocalDate() { Symmetry010Date sym010 = Symmetry010Date.of(2000, 1, 4); Symmetry010Date test = sym010.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, Symmetry010Date.of(2012, 7, 5)); + assertEquals(Symmetry010Date.of(2012, 7, 5), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { Symmetry010Date sym010 = Symmetry010Date.of(2000, 1, 4); - sym010.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> sym010.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -746,22 +756,21 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToSymmetry010Date() { Symmetry010Date sym010 = Symmetry010Date.of(2012, 7, 19); LocalDate test = LocalDate.MIN.with(sym010); - assertEquals(test, LocalDate.of(2012, 7, 20)); + assertEquals(LocalDate.of(2012, 7, 20), test); } @Test public void test_LocalDateTime_adjustToSymmetry010Date() { Symmetry010Date sym010 = Symmetry010Date.of(2012, 7, 19); LocalDateTime test = LocalDateTime.MIN.with(sym010); - assertEquals(test, LocalDateTime.of(2012, 7, 20, 0, 0)); + assertEquals(LocalDateTime.of(2012, 7, 20, 0, 0), test); } //----------------------------------------------------------------------- // Symmetry010Date.plus // Symmetry010Date.minus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {2014, 5, 26, 0, DAYS, 2014, 5, 26}, {2014, 5, 26, 8, DAYS, 2014, 6, 3}, @@ -796,8 +805,7 @@ Object[][] data_plus() { }; } - @DataProvider(name = "plus_leapWeek") - Object[][] data_plus_leapWeek() { + public static Object[][] data_plus_leapWeek() { return new Object[][] { {2015, 12, 28, 0, DAYS, 2015, 12, 28}, {2015, 12, 28, 8, DAYS, 2015, 12, 36}, @@ -816,46 +824,49 @@ Object[][] data_plus_leapWeek() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(Symmetry010Date.of(year, month, dom).plus(amount, unit), Symmetry010Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry010Date.of(expectedYear, expectedMonth, expectedDom), Symmetry010Date.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus_leapWeek") + @ParameterizedTest + @MethodSource("data_plus_leapWeek") public void test_plus_leapWeek_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(Symmetry010Date.of(year, month, dom).plus(amount, unit), Symmetry010Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry010Date.of(expectedYear, expectedMonth, expectedDom), Symmetry010Date.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(Symmetry010Date.of(year, month, dom).minus(amount, unit), Symmetry010Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry010Date.of(expectedYear, expectedMonth, expectedDom), Symmetry010Date.of(year, month, dom).minus(amount, unit)); } - @Test(dataProvider = "plus_leapWeek") + @ParameterizedTest + @MethodSource("data_plus_leapWeek") public void test_minus_leapWeek_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(Symmetry010Date.of(year, month, dom).minus(amount, unit), Symmetry010Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry010Date.of(expectedYear, expectedMonth, expectedDom), Symmetry010Date.of(year, month, dom).minus(amount, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - Symmetry010Date.of(2012, 6, 28).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> Symmetry010Date.of(2012, 6, 28).plus(0, MINUTES)); } //----------------------------------------------------------------------- // Symmetry010Date.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, DAYS, 0}, {2014, 5, 26, 2014, 6, 4, DAYS, 9}, @@ -882,8 +893,7 @@ Object[][] data_until() { }; } - @DataProvider(name = "until_period") - Object[][] data_until_period() { + public static Object[][] data_until_period() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, 0, 0, 0}, {2014, 5, 26, 2014, 6, 4, 0, 0, 9}, @@ -897,17 +907,19 @@ Object[][] data_until_period() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { Symmetry010Date start = Symmetry010Date.of(year1, month1, dom1); Symmetry010Date end = Symmetry010Date.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(dataProvider = "until_period") + @ParameterizedTest + @MethodSource("data_until_period") public void test_until_end( int year1, int month1, int dom1, int year2, int month2, int dom2, @@ -915,14 +927,14 @@ public void test_until_end( Symmetry010Date start = Symmetry010Date.of(year1, month1, dom1); Symmetry010Date end = Symmetry010Date.of(year2, month2, dom2); ChronoPeriod period = Symmetry010Chronology.INSTANCE.period(yearPeriod, monthPeriod, dayPeriod); - assertEquals(start.until(end), period); + assertEquals(period, start.until(end)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { Symmetry010Date start = Symmetry010Date.of(2012, 6, 28); Symmetry010Date end = Symmetry010Date.of(2012, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- @@ -930,55 +942,51 @@ public void test_until_TemporalUnit_unsupported() { //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(Symmetry010Date.of(2014, 5, 21).plus(Symmetry010Chronology.INSTANCE.period(0, 2, 8)), - Symmetry010Date.of(2014, 7, 29)); + assertEquals(Symmetry010Date.of(2014, 7, 29), + Symmetry010Date.of(2014, 5, 21).plus(Symmetry010Chronology.INSTANCE.period(0, 2, 8))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(Symmetry010Date.of(2014, 5, 26).plus(Period.ofMonths(2)), - Symmetry010Date.of(2014, 7, 26)); + assertThrows(DateTimeException.class, () -> Symmetry010Date.of(2014, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(Symmetry010Date.of(2014, 5, 26).minus(Symmetry010Chronology.INSTANCE.period(0, 2, 3)), - Symmetry010Date.of(2014, 3, 23)); + assertEquals(Symmetry010Date.of(2014, 3, 23), + Symmetry010Date.of(2014, 5, 26).minus(Symmetry010Chronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(Symmetry010Date.of(2014, 5, 26).minus(Period.ofMonths(2)), Symmetry010Date.of(2014, 3, 26)); + assertThrows(DateTimeException.class, () -> Symmetry010Date.of(2014, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- - // Symmetry010Date.equals + // equals() / hashCode() //----------------------------------------------------------------------- - @DataProvider(name = "equals") - Object[][] data_equals() { - return new Object[][] { - {Symmetry010Date.of(2000, 1, 3), Symmetry010Date.of(2000, 1, 4), Symmetry010Date.of(2000, 2, 3), Symmetry010Date.of(2001, 1, 3)}, - {Symmetry010Date.of(2000, 12, 28), Symmetry010Date.of(2000, 12, 25), Symmetry010Date.of(2001, 1, 1), Symmetry010Date.of(2001, 12, 28)}, - {Symmetry010Date.of(2000, 6, 28), Symmetry010Date.of(2000, 6, 23), Symmetry010Date.of(2000, 7, 1), Symmetry010Date.of(2004, 6, 28)}, - }; - } - - @Test(dataProvider = "equals") - void test_equals(Symmetry010Date a1, Symmetry010Date b, Symmetry010Date c, Symmetry010Date d) { - assertTrue(a1.equals(a1)); - assertFalse(a1.equals(b)); - assertFalse(a1.equals(c)); - assertFalse(a1.equals(d)); - - assertFalse(a1.equals(null)); - assertFalse("".equals(a1)); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Symmetry010Date.of(2000, 1, 3), Symmetry010Date.of(2000, 1, 3)) + .addEqualityGroup(Symmetry010Date.of(2000, 1, 4), Symmetry010Date.of(2000, 1, 4)) + .addEqualityGroup(Symmetry010Date.of(2000, 2, 3), Symmetry010Date.of(2000, 2, 3)) + .addEqualityGroup(Symmetry010Date.of(2000, 6, 23), Symmetry010Date.of(2000, 6, 23)) + .addEqualityGroup(Symmetry010Date.of(2000, 6, 28), Symmetry010Date.of(2000, 6, 28)) + .addEqualityGroup(Symmetry010Date.of(2000, 7, 1), Symmetry010Date.of(2000, 7, 1)) + .addEqualityGroup(Symmetry010Date.of(2000, 12, 25), Symmetry010Date.of(2000, 12, 25)) + .addEqualityGroup(Symmetry010Date.of(2000, 12, 28), Symmetry010Date.of(2000, 12, 28)) + .addEqualityGroup(Symmetry010Date.of(2001, 1, 1), Symmetry010Date.of(2001, 1, 1)) + .addEqualityGroup(Symmetry010Date.of(2001, 1, 3), Symmetry010Date.of(2001, 1, 3)) + .addEqualityGroup(Symmetry010Date.of(2001, 12, 28), Symmetry010Date.of(2001, 12, 28)) + .addEqualityGroup(Symmetry010Date.of(2004, 6, 28), Symmetry010Date.of(2004, 6, 28)) + .testEquals(); } //----------------------------------------------------------------------- // Symmetry010Date.toString //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {Symmetry010Date.of( 1, 1, 1), "Sym010 CE 1/01/01"}, {Symmetry010Date.of(1970, 2, 31), "Sym010 CE 1970/02/31"}, @@ -987,8 +995,9 @@ Object[][] data_toString() { }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(Symmetry010Date date, String expected) { - assertEquals(date.toString(), expected); + assertEquals(expected, date.toString()); } } diff --git a/src/test/java/org/threeten/extra/chrono/TestSymmetry454Chronology.java b/src/test/java/org/threeten/extra/chrono/TestSymmetry454Chronology.java index bac82cf1..34cdcf45 100644 --- a/src/test/java/org/threeten/extra/chrono/TestSymmetry454Chronology.java +++ b/src/test/java/org/threeten/extra/chrono/TestSymmetry454Chronology.java @@ -31,66 +31,65 @@ */ package org.threeten.extra.chrono; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.MILLENNIA; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; import java.time.Period; - -import java.time.chrono.Chronology; import java.time.chrono.ChronoPeriod; +import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.HijrahEra; import java.time.chrono.IsoEra; import java.time.chrono.JapaneseEra; import java.time.chrono.MinguoEra; import java.time.chrono.ThaiBuddhistEra; - import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; -import java.time.temporal.ValueRange; import java.time.temporal.UnsupportedTemporalTypeException; - +import java.time.temporal.ValueRange; import java.util.List; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; -import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.DAY_OF_WEEK; -import static java.time.temporal.ChronoField.DAY_OF_YEAR; -import static java.time.temporal.ChronoField.EPOCH_DAY; -import static java.time.temporal.ChronoField.ERA; -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; -import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; -import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static java.time.temporal.ChronoField.YEAR; -import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import static java.time.temporal.ChronoUnit.DAYS; -import static java.time.temporal.ChronoUnit.ERAS; -import static java.time.temporal.ChronoUnit.MONTHS; -import static java.time.temporal.ChronoUnit.WEEKS; -import static java.time.temporal.ChronoUnit.YEARS; -import static java.time.temporal.ChronoUnit.DECADES; -import static java.time.temporal.ChronoUnit.CENTURIES; -import static java.time.temporal.ChronoUnit.MILLENNIA; -import static java.time.temporal.ChronoUnit.MINUTES; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; +import com.google.common.testing.EqualsTester; /** * Test. */ -@Test @SuppressWarnings({"static-method", "javadoc"}) public class TestSymmetry454Chronology { @@ -101,16 +100,15 @@ public class TestSymmetry454Chronology { public void test_chronology() { Chronology chrono = Chronology.of("Sym454"); assertNotNull(chrono); - assertEquals(chrono, Symmetry454Chronology.INSTANCE); - assertEquals(chrono.getId(), "Sym454"); - assertEquals(chrono.getCalendarType(), null); + assertEquals(Symmetry454Chronology.INSTANCE, chrono); + assertEquals("Sym454", chrono.getId()); + assertEquals(null, chrono.getCalendarType()); } //----------------------------------------------------------------------- // Symmetry454Date.of //----------------------------------------------------------------------- - @DataProvider(name = "samples") - Object[][] data_samples() { + public static Object[][] data_samples() { return new Object[][] { { Symmetry454Date.of( 1, 1, 1), LocalDate.of( 1, 1, 1) }, { Symmetry454Date.of( 272, 2, 30), LocalDate.of( 272, 2, 27) }, // Constantine the Great, Roman emperor (d. 337) @@ -146,74 +144,84 @@ Object[][] data_samples() { }; } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_from_Symmetry454Date(Symmetry454Date sym454, LocalDate iso) { - assertEquals(LocalDate.from(sym454), iso); + assertEquals(iso, LocalDate.from(sym454)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry454Date_from_LocalDate(Symmetry454Date sym454, LocalDate iso) { - assertEquals(Symmetry454Date.from(iso), sym454); + assertEquals(sym454, Symmetry454Date.from(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry454Date_chronology_dateEpochDay(Symmetry454Date sym454, LocalDate iso) { - assertEquals(Symmetry454Chronology.INSTANCE.dateEpochDay(iso.toEpochDay()), sym454); + assertEquals(sym454, Symmetry454Chronology.INSTANCE.dateEpochDay(iso.toEpochDay())); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry454Date_toEpochDay(Symmetry454Date sym454, LocalDate iso) { - assertEquals(sym454.toEpochDay(), iso.toEpochDay()); + assertEquals(iso.toEpochDay(), sym454.toEpochDay()); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry454Date_until_Symmetry454Date(Symmetry454Date sym454, LocalDate iso) { - assertEquals(sym454.until(sym454), Symmetry454Chronology.INSTANCE.period(0, 0, 0)); + assertEquals(Symmetry454Chronology.INSTANCE.period(0, 0, 0), sym454.until(sym454)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Symmetry454Date_until_LocalDate(Symmetry454Date sym454, LocalDate iso) { - assertEquals(sym454.until(iso), Symmetry454Chronology.INSTANCE.period(0, 0, 0)); + assertEquals(Symmetry454Chronology.INSTANCE.period(0, 0, 0), sym454.until(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_Chronology_date_Temporal(Symmetry454Date sym454, LocalDate iso) { - assertEquals(Symmetry454Chronology.INSTANCE.date(iso), sym454); + assertEquals(sym454, Symmetry454Chronology.INSTANCE.date(iso)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_LocalDate_until_Symmetry454Date(Symmetry454Date sym454, LocalDate iso) { - assertEquals(iso.until(sym454), Period.ZERO); + assertEquals(Period.ZERO, iso.until(sym454)); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_plusDays(Symmetry454Date sym454, LocalDate iso) { - assertEquals(LocalDate.from(sym454.plus(0, DAYS)), iso); - assertEquals(LocalDate.from(sym454.plus(1, DAYS)), iso.plusDays(1)); - assertEquals(LocalDate.from(sym454.plus(35, DAYS)), iso.plusDays(35)); - assertEquals(LocalDate.from(sym454.plus(-1, DAYS)), iso.plusDays(-1)); - assertEquals(LocalDate.from(sym454.plus(-60, DAYS)), iso.plusDays(-60)); + assertEquals(iso, LocalDate.from(sym454.plus(0, DAYS))); + assertEquals(iso.plusDays(1), LocalDate.from(sym454.plus(1, DAYS))); + assertEquals(iso.plusDays(35), LocalDate.from(sym454.plus(35, DAYS))); + assertEquals(iso.plusDays(-1), LocalDate.from(sym454.plus(-1, DAYS))); + assertEquals(iso.plusDays(-60), LocalDate.from(sym454.plus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_minusDays(Symmetry454Date sym454, LocalDate iso) { - assertEquals(LocalDate.from(sym454.minus(0, DAYS)), iso); - assertEquals(LocalDate.from(sym454.minus(1, DAYS)), iso.minusDays(1)); - assertEquals(LocalDate.from(sym454.minus(35, DAYS)), iso.minusDays(35)); - assertEquals(LocalDate.from(sym454.minus(-1, DAYS)), iso.minusDays(-1)); - assertEquals(LocalDate.from(sym454.minus(-60, DAYS)), iso.minusDays(-60)); + assertEquals(iso, LocalDate.from(sym454.minus(0, DAYS))); + assertEquals(iso.minusDays(1), LocalDate.from(sym454.minus(1, DAYS))); + assertEquals(iso.minusDays(35), LocalDate.from(sym454.minus(35, DAYS))); + assertEquals(iso.minusDays(-1), LocalDate.from(sym454.minus(-1, DAYS))); + assertEquals(iso.minusDays(-60), LocalDate.from(sym454.minus(-60, DAYS))); } - @Test(dataProvider = "samples") + @ParameterizedTest + @MethodSource("data_samples") public void test_until_DAYS(Symmetry454Date sym454, LocalDate iso) { - assertEquals(sym454.until(iso.plusDays(0), DAYS), 0); - assertEquals(sym454.until(iso.plusDays(1), DAYS), 1); - assertEquals(sym454.until(iso.plusDays(35), DAYS), 35); - assertEquals(sym454.until(iso.minusDays(40), DAYS), -40); + assertEquals(0, sym454.until(iso.plusDays(0), DAYS)); + assertEquals(1, sym454.until(iso.plusDays(1), DAYS)); + assertEquals(35, sym454.until(iso.plusDays(35), DAYS)); + assertEquals(-40, sym454.until(iso.minusDays(40), DAYS)); } - @DataProvider(name = "badDates") - Object[][] data_badDates() { + public static Object[][] data_badDates() { return new Object[][] { {-1, 13, 28}, {-1, 13, 29}, @@ -245,13 +253,13 @@ Object[][] data_badDates() { }; } - @Test(dataProvider = "badDates", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_badDates") public void test_badDates(int year, int month, int dom) { - Symmetry454Date.of(year, month, dom); + assertThrows(DateTimeException.class, () -> Symmetry454Date.of(year, month, dom)); } - @DataProvider(name = "badLeapDates") - Object[][] data_badLeapDates() { + public static Object[][] data_badLeapDates() { return new Object[][] { {1}, {100}, @@ -260,14 +268,15 @@ Object[][] data_badLeapDates() { }; } - @Test(dataProvider = "badLeapDates", expectedExceptions = DateTimeException.class) - public void badLeapDayDates(int year) { - Symmetry454Date.of(year, 12, 29); + @ParameterizedTest + @MethodSource("data_badLeapDates") + public void test_badLeapDayDates(int year) { + assertThrows(DateTimeException.class, () -> Symmetry454Date.of(year, 12, 29)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_chronology_dateYearDay_badDate() { - Symmetry454Chronology.INSTANCE.dateYearDay(2000, 365); + assertThrows(DateTimeException.class, () -> Symmetry454Chronology.INSTANCE.dateYearDay(2000, 365)); } //----------------------------------------------------------------------- @@ -286,7 +295,7 @@ public void test_isLeapYear_specific() { // Symmetry454Date.isLeapWeek //----------------------------------------------------------------------- @Test - void test_leapWeek() { + public void test_leapWeek() { assertTrue(Symmetry454Date.of (2015, 12, 29).isLeapWeek()); assertTrue(Symmetry454Date.of (2015, 12, 30).isLeapWeek()); assertTrue(Symmetry454Date.of (2015, 12, 31).isLeapWeek()); @@ -299,8 +308,7 @@ void test_leapWeek() { //----------------------------------------------------------------------- // Symmetry454Date.lengthOfMonth //----------------------------------------------------------------------- - @DataProvider(name = "lengthOfMonth") - Object[][] data_lengthOfMonth() { + public static Object[][] data_lengthOfMonth() { return new Object[][] { {2000, 1, 28, 28}, {2000, 2, 28, 35}, @@ -318,20 +326,22 @@ Object[][] data_lengthOfMonth() { }; } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonth(int year, int month, int day, int length) { - assertEquals(Symmetry454Date.of(year, month, day).lengthOfMonth(), length); + assertEquals(length, Symmetry454Date.of(year, month, day).lengthOfMonth()); } - @Test(dataProvider = "lengthOfMonth") + @ParameterizedTest + @MethodSource("data_lengthOfMonth") public void test_lengthOfMonthFirst(int year, int month, int day, int length) { - assertEquals(Symmetry454Date.of(year, month, 1).lengthOfMonth(), length); + assertEquals(length, Symmetry454Date.of(year, month, 1).lengthOfMonth()); } @Test public void test_lengthOfMonth_specific() { - assertEquals(Symmetry454Date.of(2000, 12, 28).lengthOfMonth(), 28); - assertEquals(Symmetry454Date.of(2004, 12, 28).lengthOfMonth(), 35); + assertEquals(28, Symmetry454Date.of(2000, 12, 28).lengthOfMonth()); + assertEquals(35, Symmetry454Date.of(2004, 12, 28).lengthOfMonth()); } //----------------------------------------------------------------------- @@ -348,7 +358,7 @@ public void test_era_loop() { assertEquals(era, base.getEra()); assertEquals(year, base.get(YEAR_OF_ERA)); Symmetry454Date eraBased = Symmetry454Chronology.INSTANCE.date(era, year, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } @@ -359,7 +369,7 @@ public void test_era_loop() { assertEquals(era, base.getEra()); assertEquals(1 - year, base.get(YEAR_OF_ERA)); Symmetry454Date eraBased = Symmetry454Chronology.INSTANCE.date(era, year, 1, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @@ -372,22 +382,21 @@ public void test_era_yearDay_loop() { assertEquals(era, base.getEra()); assertEquals(year, base.get(YEAR_OF_ERA)); Symmetry454Date eraBased = Symmetry454Chronology.INSTANCE.dateYearDay(era, year, 1); - assertEquals(eraBased, base); + assertEquals(base, eraBased); } } @Test public void test_prolepticYear_specific() { - assertEquals(Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 4), 4); - assertEquals(Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 3), 3); - assertEquals(Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 2), 2); - assertEquals(Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 1), 1); - assertEquals(Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 2000), 2000); - assertEquals(Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 1582), 1582); + assertEquals(4, Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 4)); + assertEquals(3, Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 3)); + assertEquals(2, Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 2)); + assertEquals(1, Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 1)); + assertEquals(2000, Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 2000)); + assertEquals(1582, Symmetry454Chronology.INSTANCE.prolepticYear(IsoEra.CE, 1582)); } - @DataProvider(name = "prolepticYearBadEra") - Object[][] data_prolepticYear_badEra() { + public static Object[][] data_prolepticYear_badEra() { return new Era[][] { { AccountingEra.BCE }, { AccountingEra.CE }, @@ -413,26 +422,27 @@ Object[][] data_prolepticYear_badEra() { }; } - @Test(dataProvider = "prolepticYearBadEra", expectedExceptions = ClassCastException.class) + @ParameterizedTest + @MethodSource("data_prolepticYear_badEra") public void test_prolepticYear_badEra(Era era) { - Symmetry454Chronology.INSTANCE.prolepticYear(era, 4); + assertThrows(ClassCastException.class, () -> Symmetry454Chronology.INSTANCE.prolepticYear(era, 4)); } @Test public void test_Chronology_eraOf() { - assertEquals(Symmetry454Chronology.INSTANCE.eraOf(0), IsoEra.BCE); - assertEquals(Symmetry454Chronology.INSTANCE.eraOf(1), IsoEra.CE); + assertEquals(IsoEra.BCE, Symmetry454Chronology.INSTANCE.eraOf(0)); + assertEquals(IsoEra.CE, Symmetry454Chronology.INSTANCE.eraOf(1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_Chronology_eraOf_invalid() { - Symmetry454Chronology.INSTANCE.eraOf(2); + assertThrows(DateTimeException.class, () -> Symmetry454Chronology.INSTANCE.eraOf(2)); } @Test public void test_Chronology_eras() { List eras = Symmetry454Chronology.INSTANCE.eras(); - assertEquals(eras.size(), 2); + assertEquals(2, eras.size()); assertTrue(eras.contains(IsoEra.BCE)); assertTrue(eras.contains(IsoEra.CE)); } @@ -442,26 +452,25 @@ public void test_Chronology_eras() { //----------------------------------------------------------------------- @Test public void test_Chronology_range() { - assertEquals(Symmetry454Chronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_MONTH), ValueRange.of(1, 7)); - assertEquals(Symmetry454Chronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_YEAR), ValueRange.of(1, 7)); - assertEquals(Symmetry454Chronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH), ValueRange.of(1, 4, 5)); - assertEquals(Symmetry454Chronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR), ValueRange.of(1, 52, 53)); - assertEquals(Symmetry454Chronology.INSTANCE.range(DAY_OF_WEEK), ValueRange.of(1, 7)); - assertEquals(Symmetry454Chronology.INSTANCE.range(DAY_OF_MONTH), ValueRange.of(1, 28, 35)); - assertEquals(Symmetry454Chronology.INSTANCE.range(DAY_OF_YEAR), ValueRange.of(1, 364, 371)); - assertEquals(Symmetry454Chronology.INSTANCE.range(ERA), ValueRange.of(0, 1)); - assertEquals(Symmetry454Chronology.INSTANCE.range(EPOCH_DAY), ValueRange.of(-1_000_000 * 364L - 177_474 * 7 - 719_162, 1_000_000 * 364L + 177_474 * 7 - 719_162)); - assertEquals(Symmetry454Chronology.INSTANCE.range(MONTH_OF_YEAR), ValueRange.of(1, 12)); - assertEquals(Symmetry454Chronology.INSTANCE.range(PROLEPTIC_MONTH), ValueRange.of(-12_000_000L, 11_999_999L)); - assertEquals(Symmetry454Chronology.INSTANCE.range(YEAR), ValueRange.of(-1_000_000L, 1_000_000)); - assertEquals(Symmetry454Chronology.INSTANCE.range(YEAR_OF_ERA), ValueRange.of(-1_000_000, 1_000_000)); + assertEquals(ValueRange.of(1, 7), Symmetry454Chronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + assertEquals(ValueRange.of(1, 7), Symmetry454Chronology.INSTANCE.range(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + assertEquals(ValueRange.of(1, 4, 5), Symmetry454Chronology.INSTANCE.range(ALIGNED_WEEK_OF_MONTH)); + assertEquals(ValueRange.of(1, 52, 53), Symmetry454Chronology.INSTANCE.range(ALIGNED_WEEK_OF_YEAR)); + assertEquals(ValueRange.of(1, 7), Symmetry454Chronology.INSTANCE.range(DAY_OF_WEEK)); + assertEquals(ValueRange.of(1, 28, 35), Symmetry454Chronology.INSTANCE.range(DAY_OF_MONTH)); + assertEquals(ValueRange.of(1, 364, 371), Symmetry454Chronology.INSTANCE.range(DAY_OF_YEAR)); + assertEquals(ValueRange.of(0, 1), Symmetry454Chronology.INSTANCE.range(ERA)); + assertEquals(ValueRange.of(-1_000_000 * 364L - 177_474 * 7 - 719_162, 1_000_000 * 364L + 177_474 * 7 - 719_162), Symmetry454Chronology.INSTANCE.range(EPOCH_DAY)); + assertEquals(ValueRange.of(1, 12), Symmetry454Chronology.INSTANCE.range(MONTH_OF_YEAR)); + assertEquals(ValueRange.of(-12_000_000L, 11_999_999L), Symmetry454Chronology.INSTANCE.range(PROLEPTIC_MONTH)); + assertEquals(ValueRange.of(-1_000_000L, 1_000_000), Symmetry454Chronology.INSTANCE.range(YEAR)); + assertEquals(ValueRange.of(-1_000_000, 1_000_000), Symmetry454Chronology.INSTANCE.range(YEAR_OF_ERA)); } //----------------------------------------------------------------------- // Symmetry454Date.range //----------------------------------------------------------------------- - @DataProvider(name = "ranges") - Object[][] data_ranges() { + public static Object[][] data_ranges() { return new Object[][] { // Leap Day and Year Day are members of months {2012, 1, 23, DAY_OF_MONTH, ValueRange.of(1, 28)}, @@ -506,21 +515,21 @@ Object[][] data_ranges() { }; } - @Test(dataProvider = "ranges") + @ParameterizedTest + @MethodSource("data_ranges") public void test_range(int year, int month, int dom, TemporalField field, ValueRange range) { - assertEquals(Symmetry454Date.of(year, month, dom).range(field), range); + assertEquals(range, Symmetry454Date.of(year, month, dom).range(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_range_unsupported() { - Symmetry454Date.of(2012, 6, 28).range(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> Symmetry454Date.of(2012, 6, 28).range(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // Symmetry454Date.getLong //----------------------------------------------------------------------- - @DataProvider(name = "getLong") - Object[][] data_getLong() { + public static Object[][] data_getLong() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 5}, {2014, 5, 26, DAY_OF_MONTH, 26}, @@ -554,21 +563,21 @@ Object[][] data_getLong() { }; } - @Test(dataProvider = "getLong") + @ParameterizedTest + @MethodSource("data_getLong") public void test_getLong(int year, int month, int dom, TemporalField field, long expected) { - assertEquals(Symmetry454Date.of(year, month, dom).getLong(field), expected); + assertEquals(expected, Symmetry454Date.of(year, month, dom).getLong(field)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_getLong_unsupported() { - Symmetry454Date.of(2012, 6, 28).getLong(MINUTE_OF_DAY); + assertThrows(UnsupportedTemporalTypeException.class, () -> Symmetry454Date.of(2012, 6, 28).getLong(MINUTE_OF_DAY)); } //----------------------------------------------------------------------- // Symmetry454Date.with //----------------------------------------------------------------------- - @DataProvider(name = "with") - Object[][] data_with() { + public static Object[][] data_with() { return new Object[][] { {2014, 5, 26, DAY_OF_WEEK, 1, 2014, 5, 22}, {2014, 5, 26, DAY_OF_WEEK, 5, 2014, 5, 26}, @@ -643,15 +652,15 @@ Object[][] data_with() { }; } - @Test(dataProvider = "with") + @ParameterizedTest + @MethodSource("data_with") public void test_with_TemporalField(int year, int month, int dom, TemporalField field, long value, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(Symmetry454Date.of(year, month, dom).with(field, value), Symmetry454Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry454Date.of(expectedYear, expectedMonth, expectedDom), Symmetry454Date.of(year, month, dom).with(field, value)); } - @DataProvider(name = "with_bad") - Object[][] data_with_bad() { + public static Object[][] data_with_bad() { return new Object[][] { {2013, 1, 1, ALIGNED_DAY_OF_WEEK_IN_MONTH, -1}, {2013, 1, 1, ALIGNED_DAY_OF_WEEK_IN_MONTH, 8}, @@ -691,21 +700,21 @@ Object[][] data_with_bad() { }; } - @Test(dataProvider = "with_bad", expectedExceptions = DateTimeException.class) + @ParameterizedTest + @MethodSource("data_with_bad") public void test_with_TemporalField_badValue(int year, int month, int dom, TemporalField field, long value) { - Symmetry454Date.of(year, month, dom).with(field, value); + assertThrows(DateTimeException.class, () -> Symmetry454Date.of(year, month, dom).with(field, value)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_with_TemporalField_unsupported() { - Symmetry454Date.of(2012, 6, 28).with(MINUTE_OF_DAY, 10); + assertThrows(UnsupportedTemporalTypeException.class, () -> Symmetry454Date.of(2012, 6, 28).with(MINUTE_OF_DAY, 10)); } //----------------------------------------------------------------------- // Symmetry454Date.with(TemporalAdjuster) //----------------------------------------------------------------------- - @DataProvider(name = "temporalAdjusters_lastDayOfMonth") - Object[][] data_temporalAdjusters_lastDayOfMonth() { + public static Object[][] data_temporalAdjusters_lastDayOfMonth() { return new Object[][] { {2012, 1, 23, 2012, 1, 28}, {2012, 2, 23, 2012, 2, 35}, @@ -723,12 +732,13 @@ Object[][] data_temporalAdjusters_lastDayOfMonth() { }; } - @Test(dataProvider = "temporalAdjusters_lastDayOfMonth") + @ParameterizedTest + @MethodSource("data_temporalAdjusters_lastDayOfMonth") public void test_temporalAdjusters_LastDayOfMonth(int year, int month, int day, int expectedYear, int expectedMonth, int expectedDay) { Symmetry454Date base = Symmetry454Date.of(year, month, day); Symmetry454Date expected = Symmetry454Date.of(expectedYear, expectedMonth, expectedDay); Symmetry454Date actual = base.with(TemporalAdjusters.lastDayOfMonth()); - assertEquals(actual, expected); + assertEquals(expected, actual); } //----------------------------------------------------------------------- @@ -738,13 +748,13 @@ public void test_temporalAdjusters_LastDayOfMonth(int year, int month, int day, public void test_adjust_toLocalDate() { Symmetry454Date sym454 = Symmetry454Date.of(2000, 1, 4); Symmetry454Date test = sym454.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, Symmetry454Date.of(2012, 7, 5)); + assertEquals(Symmetry454Date.of(2012, 7, 5), test); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_adjust_toMonth() { Symmetry454Date sym454 = Symmetry454Date.of(2000, 1, 4); - sym454.with(Month.APRIL); + assertThrows(DateTimeException.class, () -> sym454.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -754,22 +764,21 @@ public void test_adjust_toMonth() { public void test_LocalDate_adjustToSymmetry454Date() { Symmetry454Date sym454 = Symmetry454Date.of(2012, 7, 19); LocalDate test = LocalDate.MIN.with(sym454); - assertEquals(test, LocalDate.of(2012, 7, 20)); + assertEquals(LocalDate.of(2012, 7, 20), test); } @Test public void test_LocalDateTime_adjustToSymmetry454Date() { Symmetry454Date sym454 = Symmetry454Date.of(2012, 7, 19); LocalDateTime test = LocalDateTime.MIN.with(sym454); - assertEquals(test, LocalDateTime.of(2012, 7, 20, 0, 0)); + assertEquals(LocalDateTime.of(2012, 7, 20, 0, 0), test); } //----------------------------------------------------------------------- // Symmetry454Date.plus // Symmetry454Date.minus //----------------------------------------------------------------------- - @DataProvider(name = "plus") - Object[][] data_plus() { + public static Object[][] data_plus() { return new Object[][] { {2014, 5, 26, 0, DAYS, 2014, 5, 26}, {2014, 5, 26, 8, DAYS, 2014, 5, 34}, @@ -804,8 +813,7 @@ Object[][] data_plus() { }; } - @DataProvider(name = "plus_leapWeek") - Object[][] data_plus_leapWeek() { + public static Object[][] data_plus_leapWeek() { return new Object[][] { {2015, 12, 28, 0, DAYS, 2015, 12, 28}, {2015, 12, 28, 8, DAYS, 2016, 1, 1}, @@ -824,46 +832,49 @@ Object[][] data_plus_leapWeek() { }; } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(Symmetry454Date.of(year, month, dom).plus(amount, unit), Symmetry454Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry454Date.of(expectedYear, expectedMonth, expectedDom), Symmetry454Date.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus_leapWeek") + @ParameterizedTest + @MethodSource("data_plus_leapWeek") public void test_plus_leapWeek_TemporalUnit(int year, int month, int dom, long amount, TemporalUnit unit, int expectedYear, int expectedMonth, int expectedDom) { - assertEquals(Symmetry454Date.of(year, month, dom).plus(amount, unit), Symmetry454Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry454Date.of(expectedYear, expectedMonth, expectedDom), Symmetry454Date.of(year, month, dom).plus(amount, unit)); } - @Test(dataProvider = "plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_minus_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(Symmetry454Date.of(year, month, dom).minus(amount, unit), Symmetry454Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry454Date.of(expectedYear, expectedMonth, expectedDom), Symmetry454Date.of(year, month, dom).minus(amount, unit)); } - @Test(dataProvider = "plus_leapWeek") + @ParameterizedTest + @MethodSource("data_plus_leapWeek") public void test_minus_leapWeek_TemporalUnit( int expectedYear, int expectedMonth, int expectedDom, long amount, TemporalUnit unit, int year, int month, int dom) { - assertEquals(Symmetry454Date.of(year, month, dom).minus(amount, unit), Symmetry454Date.of(expectedYear, expectedMonth, expectedDom)); + assertEquals(Symmetry454Date.of(expectedYear, expectedMonth, expectedDom), Symmetry454Date.of(year, month, dom).minus(amount, unit)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_plus_TemporalUnit_unsupported() { - Symmetry454Date.of(2012, 6, 28).plus(0, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> Symmetry454Date.of(2012, 6, 28).plus(0, MINUTES)); } //----------------------------------------------------------------------- // Symmetry454Date.until //----------------------------------------------------------------------- - @DataProvider(name = "until") - Object[][] data_until() { + public static Object[][] data_until() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, DAYS, 0}, {2014, 5, 26, 2014, 6, 4, DAYS, 13}, @@ -890,8 +901,7 @@ Object[][] data_until() { }; } - @DataProvider(name = "until_period") - Object[][] data_until_period() { + public static Object[][] data_until_period() { return new Object[][] { {2014, 5, 26, 2014, 5, 26, 0, 0, 0}, {2014, 5, 26, 2014, 6, 4, 0, 0, 13}, @@ -905,17 +915,19 @@ Object[][] data_until_period() { }; } - @Test(dataProvider = "until") + @ParameterizedTest + @MethodSource("data_until") public void test_until_TemporalUnit( int year1, int month1, int dom1, int year2, int month2, int dom2, TemporalUnit unit, long expected) { Symmetry454Date start = Symmetry454Date.of(year1, month1, dom1); Symmetry454Date end = Symmetry454Date.of(year2, month2, dom2); - assertEquals(start.until(end, unit), expected); + assertEquals(expected, start.until(end, unit)); } - @Test(dataProvider = "until_period") + @ParameterizedTest + @MethodSource("data_until_period") public void test_until_end( int year1, int month1, int dom1, int year2, int month2, int dom2, @@ -923,14 +935,14 @@ public void test_until_end( Symmetry454Date start = Symmetry454Date.of(year1, month1, dom1); Symmetry454Date end = Symmetry454Date.of(year2, month2, dom2); ChronoPeriod period = Symmetry454Chronology.INSTANCE.period(yearPeriod, monthPeriod, dayPeriod); - assertEquals(start.until(end), period); + assertEquals(period, start.until(end)); } - @Test(expectedExceptions = UnsupportedTemporalTypeException.class) + @Test public void test_until_TemporalUnit_unsupported() { Symmetry454Date start = Symmetry454Date.of(2012, 6, 28); Symmetry454Date end = Symmetry454Date.of(2012, 7, 1); - start.until(end, MINUTES); + assertThrows(UnsupportedTemporalTypeException.class, () -> start.until(end, MINUTES)); } //----------------------------------------------------------------------- @@ -938,55 +950,51 @@ public void test_until_TemporalUnit_unsupported() { //----------------------------------------------------------------------- @Test public void test_plus_Period() { - assertEquals(Symmetry454Date.of(2014, 5, 21).plus(Symmetry454Chronology.INSTANCE.period(0, 2, 8)), - Symmetry454Date.of(2014, 8, 1)); + assertEquals(Symmetry454Date.of(2014, 8, 1), + Symmetry454Date.of(2014, 5, 21).plus(Symmetry454Chronology.INSTANCE.period(0, 2, 8))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_plus_Period_ISO() { - assertEquals(Symmetry454Date.of(2014, 5, 26).plus(Period.ofMonths(2)), - Symmetry454Date.of(2014, 7, 26)); + assertThrows(DateTimeException.class, () -> Symmetry454Date.of(2014, 5, 26).plus(Period.ofMonths(2))); } @Test public void test_minus_Period() { - assertEquals(Symmetry454Date.of(2014, 5, 26).minus(Symmetry454Chronology.INSTANCE.period(0, 2, 3)), - Symmetry454Date.of(2014, 3, 23)); + assertEquals(Symmetry454Date.of(2014, 3, 23), + Symmetry454Date.of(2014, 5, 26).minus(Symmetry454Chronology.INSTANCE.period(0, 2, 3))); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void test_minus_Period_ISO() { - assertEquals(Symmetry454Date.of(2014, 5, 26).minus(Period.ofMonths(2)), Symmetry454Date.of(2014, 3, 26)); + assertThrows(DateTimeException.class, () -> Symmetry454Date.of(2014, 5, 26).minus(Period.ofMonths(2))); } //----------------------------------------------------------------------- - // Symmetry454Date.equals + // equals() / hashCode() //----------------------------------------------------------------------- - @DataProvider(name = "equals") - Object[][] data_equals() { - return new Object[][] { - {Symmetry454Date.of(2000, 1, 3), Symmetry454Date.of(2000, 1, 4), Symmetry454Date.of(2000, 2, 3), Symmetry454Date.of(2001, 1, 3)}, - {Symmetry454Date.of(2000, 12, 28), Symmetry454Date.of(2000, 12, 25), Symmetry454Date.of(2001, 1, 1), Symmetry454Date.of(2001, 12, 28)}, - {Symmetry454Date.of(2000, 6, 28), Symmetry454Date.of(2000, 6, 23), Symmetry454Date.of(2000, 7, 1), Symmetry454Date.of(2004, 6, 28)}, - }; - } - - @Test(dataProvider = "equals") - void test_equals(Symmetry454Date a1, Symmetry454Date b, Symmetry454Date c, Symmetry454Date d) { - assertTrue(a1.equals(a1)); - assertFalse(a1.equals(b)); - assertFalse(a1.equals(c)); - assertFalse(a1.equals(d)); - - assertFalse(a1.equals(null)); - assertFalse("".equals(a1)); + @Test + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(Symmetry454Date.of(2000, 1, 3), Symmetry454Date.of(2000, 1, 3)) + .addEqualityGroup(Symmetry454Date.of(2000, 1, 4), Symmetry454Date.of(2000, 1, 4)) + .addEqualityGroup(Symmetry454Date.of(2000, 2, 3), Symmetry454Date.of(2000, 2, 3)) + .addEqualityGroup(Symmetry454Date.of(2001, 1, 3), Symmetry454Date.of(2001, 1, 3)) + .addEqualityGroup(Symmetry454Date.of(2000, 12, 28), Symmetry454Date.of(2000, 12, 28)) + .addEqualityGroup(Symmetry454Date.of(2000, 12, 25), Symmetry454Date.of(2000, 12, 25)) + .addEqualityGroup(Symmetry454Date.of(2001, 1, 1), Symmetry454Date.of(2001, 1, 1)) + .addEqualityGroup(Symmetry454Date.of(2001, 12, 28), Symmetry454Date.of(2001, 12, 28)) + .addEqualityGroup(Symmetry454Date.of(2000, 6, 28), Symmetry454Date.of(2000, 6, 28)) + .addEqualityGroup(Symmetry454Date.of(2000, 6, 23), Symmetry454Date.of(2000, 6, 23)) + .addEqualityGroup(Symmetry454Date.of(2000, 7, 1), Symmetry454Date.of(2000, 7, 1)) + .addEqualityGroup(Symmetry454Date.of(2004, 6, 28), Symmetry454Date.of(2004, 6, 28)) + .testEquals(); } //----------------------------------------------------------------------- // Symmetry454Date.toString //----------------------------------------------------------------------- - @DataProvider(name = "toString") - Object[][] data_toString() { + public static Object[][] data_toString() { return new Object[][] { {Symmetry454Date.of(1, 1, 1), "Sym454 CE 1/01/01"}, {Symmetry454Date.of(1970, 2, 35), "Sym454 CE 1970/02/35"}, @@ -995,8 +1003,9 @@ Object[][] data_toString() { }; } - @Test(dataProvider = "toString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(Symmetry454Date date, String expected) { - assertEquals(date.toString(), expected); + assertEquals(expected, date.toString()); } } diff --git a/src/test/java/org/threeten/extra/scale/TestTaiInstant.java b/src/test/java/org/threeten/extra/scale/TestTaiInstant.java index d17557c4..be2b2ccb 100644 --- a/src/test/java/org/threeten/extra/scale/TestTaiInstant.java +++ b/src/test/java/org/threeten/extra/scale/TestTaiInstant.java @@ -31,9 +31,10 @@ */ package org.threeten.extra.scale; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -44,13 +45,15 @@ import java.time.Instant; import java.time.format.DateTimeParseException; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test TaiInstant. */ -@Test public class TestTaiInstant { //----------------------------------------------------------------------- @@ -64,16 +67,15 @@ public void test_interfaces() { // serialization //----------------------------------------------------------------------- @Test - public void test_deserialization() throws Exception { - TaiInstant orginal = TaiInstant.ofTaiSeconds(2, 3); + public void test_serialization() throws Exception { + TaiInstant test = TaiInstant.ofTaiSeconds(2, 3); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - TaiInstant ser = (TaiInstant) in.readObject(); - assertEquals(TaiInstant.ofTaiSeconds(2, 3), ser); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertEquals(test, ois.readObject()); + } } //----------------------------------------------------------------------- @@ -84,18 +86,18 @@ public void factory_ofTaiSecondslong_long() { for (long i = -2; i <= 2; i++) { for (int j = 0; j < 10; j++) { TaiInstant t = TaiInstant.ofTaiSeconds(i, j); - assertEquals(t.getTaiSeconds(), i); - assertEquals(t.getNano(), j); + assertEquals(i, t.getTaiSeconds()); + assertEquals(j, t.getNano()); } for (int j = -10; j < 0; j++) { TaiInstant t = TaiInstant.ofTaiSeconds(i, j); - assertEquals(t.getTaiSeconds(), i - 1); - assertEquals(t.getNano(), j + 1000000000); + assertEquals(i - 1, t.getTaiSeconds()); + assertEquals(j + 1000000000, t.getNano()); } for (int j = 999999990; j < 1000000000; j++) { TaiInstant t = TaiInstant.ofTaiSeconds(i, j); - assertEquals(t.getTaiSeconds(), i); - assertEquals(t.getNano(), j); + assertEquals(i, t.getTaiSeconds()); + assertEquals(j, t.getNano()); } } } @@ -103,13 +105,13 @@ public void factory_ofTaiSecondslong_long() { @Test public void factory_ofTaiSeconds_long_long_nanosNegativeAdjusted() { TaiInstant test = TaiInstant.ofTaiSeconds(2L, -1); - assertEquals(test.getTaiSeconds(), 1); - assertEquals(test.getNano(), 999999999); + assertEquals(1, test.getTaiSeconds()); + assertEquals(999999999, test.getNano()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void factory_ofTaiSeconds_long_long_tooBig() { - TaiInstant.ofTaiSeconds(Long.MAX_VALUE, 1000000000); + assertThrows(ArithmeticException.class, () -> TaiInstant.ofTaiSeconds(Long.MAX_VALUE, 1000000000)); } //----------------------------------------------------------------------- @@ -118,13 +120,13 @@ public void factory_ofTaiSeconds_long_long_tooBig() { @Test public void factory_of_Instant() { TaiInstant test = TaiInstant.of(Instant.ofEpochSecond(0, 2)); - assertEquals(test.getTaiSeconds(), (40587L - 36204) * 24 * 60 * 60 + 10); //((1970 - 1958) * 365 + 3) * 24 * 60 * 60 + 10); - assertEquals(test.getNano(), 2); + assertEquals((40587L - 36204) * 24 * 60 * 60 + 10, test.getTaiSeconds()); //((1970 - 1958) * 365 + 3) * 24 * 60 * 60 + 10); + assertEquals(2, test.getNano()); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void factory_of_Instant_null() { - TaiInstant.of((Instant) null); + assertThrows(NullPointerException.class, () -> TaiInstant.of((Instant) null)); } //----------------------------------------------------------------------- @@ -135,15 +137,15 @@ public void factory_of_UtcInstant() { for (int i = -1000; i < 1000; i++) { for (int j = 0; j < 10; j++) { TaiInstant test = TaiInstant.of(UtcInstant.ofModifiedJulianDay(36204 + i, j * 1000000000L + 2L)); - assertEquals(test.getTaiSeconds(), i * 24 * 60 * 60 + j + 10); - assertEquals(test.getNano(), 2); + assertEquals(i * 24 * 60 * 60 + j + 10, test.getTaiSeconds()); + assertEquals(2, test.getNano()); } } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void factory_of_UtcInstant_null() { - TaiInstant.of((UtcInstant) null); + assertThrows(NullPointerException.class, () -> TaiInstant.of((UtcInstant) null)); } //----------------------------------------------------------------------- @@ -155,14 +157,13 @@ public void factory_parse_CharSequence() { for (int j = 900000000; j < 990000000; j += 10000000) { String str = i + "." + j + "s(TAI)"; TaiInstant test = TaiInstant.parse(str); - assertEquals(test.getTaiSeconds(), i); - assertEquals(test.getNano(), j); + assertEquals(i, test.getTaiSeconds()); + assertEquals(j, test.getNano()); } } } - @DataProvider(name = "BadParse") - Object[][] provider_badParse() { + public static Object[][] data_badParse() { return new Object[][] { {"A.123456789s(TAI)"}, {"123.12345678As(TAI)"}, @@ -173,21 +174,21 @@ Object[][] provider_badParse() { }; } - @Test(dataProvider = "BadParse", expectedExceptions = DateTimeParseException.class) + @ParameterizedTest + @MethodSource("data_badParse") public void factory_parse_CharSequence_invalid(String str) { - TaiInstant.parse(str); + assertThrows(DateTimeParseException.class, () -> TaiInstant.parse(str)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void factory_parse_CharSequence_null() { - TaiInstant.parse((String) null); + assertThrows(NullPointerException.class, () -> TaiInstant.parse((String) null)); } //----------------------------------------------------------------------- // withTAISeconds() //----------------------------------------------------------------------- - @DataProvider(name = "withTAISeconds") - Object[][] provider_withTAISeconds() { + public static Object[][] data_withTAISeconds() { return new Object[][] { {0L, 12345L, 1L, 1L, 12345L}, {0L, 12345L, -1L, -1L, 12345L}, @@ -198,18 +199,18 @@ Object[][] provider_withTAISeconds() { }; } - @Test(dataProvider = "withTAISeconds") + @ParameterizedTest + @MethodSource("data_withTAISeconds") public void test_withTAISeconds(long tai, long nanos, long newTai, Long expectedTai, Long expectedNanos) { TaiInstant i = TaiInstant.ofTaiSeconds(tai, nanos).withTaiSeconds(newTai); - assertEquals(i.getTaiSeconds(), expectedTai.longValue()); - assertEquals(i.getNano(), expectedNanos.longValue()); + assertEquals(expectedTai.longValue(), i.getTaiSeconds()); + assertEquals(expectedNanos.longValue(), i.getNano()); } //----------------------------------------------------------------------- // withNano() //----------------------------------------------------------------------- - @DataProvider(name = "withNanoOfSecond") - Object[][] provider_withNano() { + public static Object[][] data_withNano() { return new Object[][] { {0L, 12345L, 1, 0L, 1L}, {7L, 12345L, 2, 7L, 2L}, @@ -220,28 +221,23 @@ Object[][] provider_withNano() { }; } - @Test(dataProvider = "withNanoOfSecond") + @ParameterizedTest + @MethodSource("data_withNano") public void test_withNano(long tai, long nanos, int newNano, Long expectedTai, Long expectedNanos) { TaiInstant i = TaiInstant.ofTaiSeconds(tai, nanos); if (expectedTai != null) { - i = i.withNano(newNano); - assertEquals(i.getTaiSeconds(), expectedTai.longValue()); - assertEquals(i.getNano(), expectedNanos.longValue()); + TaiInstant withNano = i.withNano(newNano); + assertEquals(expectedTai.longValue(), withNano.getTaiSeconds()); + assertEquals(expectedNanos.longValue(), withNano.getNano()); } else { - try { - i = i.withNano(newNano); - fail(); - } catch (IllegalArgumentException ex) { - // expected - } + assertThrows(IllegalArgumentException.class, () -> i.withNano(newNano)); } } //----------------------------------------------------------------------- // plus(Duration) //----------------------------------------------------------------------- - @DataProvider(name = "Plus") - Object[][] provider_plus() { + public static Object[][] data_plus() { return new Object[][] { {Long.MIN_VALUE, 0, Long.MAX_VALUE, 0, -1, 0}, @@ -425,30 +421,30 @@ Object[][] provider_plus() { }; } - @Test(dataProvider = "Plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus(long seconds, int nanos, long plusSeconds, int plusNanos, long expectedSeconds, int expectedNanoOfSecond) { TaiInstant i = TaiInstant.ofTaiSeconds(seconds, nanos).plus(Duration.ofSeconds(plusSeconds, plusNanos)); - assertEquals(i.getTaiSeconds(), expectedSeconds); - assertEquals(i.getNano(), expectedNanoOfSecond); + assertEquals(expectedSeconds, i.getTaiSeconds()); + assertEquals(expectedNanoOfSecond, i.getNano()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_overflowTooBig() { TaiInstant i = TaiInstant.ofTaiSeconds(Long.MAX_VALUE, 999999999); - i.plus(Duration.ofSeconds(0, 1)); + assertThrows(ArithmeticException.class, () -> i.plus(Duration.ofSeconds(0, 1))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_overflowTooSmall() { TaiInstant i = TaiInstant.ofTaiSeconds(Long.MIN_VALUE, 0); - i.plus(Duration.ofSeconds(-1, 999999999)); + assertThrows(ArithmeticException.class, () -> i.plus(Duration.ofSeconds(-1, 999999999))); } //----------------------------------------------------------------------- // minus(Duration) //----------------------------------------------------------------------- - @DataProvider(name = "Minus") - Object[][] provider_minus() { + public static Object[][] data_minus() { return new Object[][] { {Long.MIN_VALUE, 0, Long.MIN_VALUE + 1, 0, -1, 0}, @@ -632,23 +628,24 @@ Object[][] provider_minus() { }; } - @Test(dataProvider = "Minus") + @ParameterizedTest + @MethodSource("data_minus") public void test_minus(long seconds, int nanos, long minusSeconds, int minusNanos, long expectedSeconds, int expectedNanoOfSecond) { TaiInstant i = TaiInstant.ofTaiSeconds(seconds, nanos).minus(Duration.ofSeconds(minusSeconds, minusNanos)); - assertEquals(i.getTaiSeconds(), expectedSeconds); - assertEquals(i.getNano(), expectedNanoOfSecond); + assertEquals(expectedSeconds, i.getTaiSeconds()); + assertEquals(expectedNanoOfSecond, i.getNano()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_overflowTooSmall() { TaiInstant i = TaiInstant.ofTaiSeconds(Long.MIN_VALUE, 0); - i.minus(Duration.ofSeconds(0, 1)); + assertThrows(ArithmeticException.class, () -> i.minus(Duration.ofSeconds(0, 1))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_overflowTooBig() { TaiInstant i = TaiInstant.ofTaiSeconds(Long.MAX_VALUE, 999999999); - i.minus(Duration.ofSeconds(-1, 999999999)); + assertThrows(ArithmeticException.class, () -> i.minus(Duration.ofSeconds(-1, 999999999))); } //----------------------------------------------------------------------- @@ -659,8 +656,8 @@ public void test_durationUntil_fifteenSeconds() { TaiInstant tai1 = TaiInstant.ofTaiSeconds(10, 0); TaiInstant tai2 = TaiInstant.ofTaiSeconds(25, 0); Duration test = tai1.durationUntil(tai2); - assertEquals(test.getSeconds(), 15); - assertEquals(test.getNano(), 0); + assertEquals(15, test.getSeconds()); + assertEquals(0, test.getNano()); } @Test @@ -668,8 +665,8 @@ public void test_durationUntil_twoNanos() { TaiInstant tai1 = TaiInstant.ofTaiSeconds(4, 5); TaiInstant tai2 = TaiInstant.ofTaiSeconds(4, 7); Duration test = tai1.durationUntil(tai2); - assertEquals(test.getSeconds(), 0); - assertEquals(test.getNano(), 2); + assertEquals(0, test.getSeconds()); + assertEquals(2, test.getNano()); } @Test @@ -677,8 +674,8 @@ public void test_durationUntil_twoNanosNegative() { TaiInstant tai1 = TaiInstant.ofTaiSeconds(4, 9); TaiInstant tai2 = TaiInstant.ofTaiSeconds(4, 7); Duration test = tai1.durationUntil(tai2); - assertEquals(test.getSeconds(), -1); - assertEquals(test.getNano(), 999999998); + assertEquals(-1, test.getSeconds()); + assertEquals(999999998, test.getNano()); } //----------------------------------------------------------------------- @@ -690,7 +687,7 @@ public void test_toUtcInstant() { for (int j = 0; j < 10; j++) { UtcInstant expected = UtcInstant.ofModifiedJulianDay(36204 + i, j * 1000000000L + 2L); TaiInstant test = TaiInstant.ofTaiSeconds(i * 24 * 60 * 60 + j + 10, 2); - assertEquals(test.toUtcInstant(), expected); + assertEquals(expected, test.toUtcInstant()); } } } @@ -704,7 +701,7 @@ public void test_toInstant() { for (int j = 0; j < 10; j++) { Instant expected = Instant.ofEpochSecond(-378691200L + i * 24 * 60 * 60 + j).plusNanos(2); TaiInstant test = TaiInstant.ofTaiSeconds(i * 24 * 60 * 60 + j + 10, 2); - assertEquals(test.toInstant(), expected, "Loop " + i + " " + j); + assertEquals(expected, test.toInstant()); } } } @@ -737,91 +734,48 @@ void doTest_comparisons_TaiInstant(TaiInstant... instants) { for (int j = 0; j < instants.length; j++) { TaiInstant b = instants[j]; if (i < j) { - assertEquals(a.compareTo(b) < 0, true, a + " <=> " + b); - assertEquals(a.equals(b), false, a + " <=> " + b); + assertTrue(a.compareTo(b) < 0); + assertFalse(a.equals(b)); + assertTrue(a.isBefore(b)); + assertFalse(a.isAfter(b)); } else if (i > j) { - assertEquals(a.compareTo(b) > 0, true, a + " <=> " + b); - assertEquals(a.equals(b), false, a + " <=> " + b); + assertTrue(a.compareTo(b) > 0); + assertFalse(a.equals(b)); + assertFalse(a.isBefore(b)); + assertTrue(a.isAfter(b)); } else { - assertEquals(a.compareTo(b), 0, a + " <=> " + b); - assertEquals(a.equals(b), true, a + " <=> " + b); + assertEquals(0, a.compareTo(b)); + assertTrue(a.equals(b)); + assertFalse(a.isBefore(b)); + assertFalse(a.isAfter(b)); } } } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_ObjectNull() { TaiInstant a = TaiInstant.ofTaiSeconds(0L, 0); - a.compareTo(null); + assertThrows(NullPointerException.class, () -> a.compareTo(null)); } - @Test(expectedExceptions = ClassCastException.class) + @Test @SuppressWarnings({"unchecked", "rawtypes"}) public void test_compareToNonTaiInstant() { Comparable c = TaiInstant.ofTaiSeconds(0L, 2); - c.compareTo(new Object()); + assertThrows(ClassCastException.class, () -> c.compareTo(new Object())); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - public void test_equals() { - TaiInstant test5a = TaiInstant.ofTaiSeconds(5L, 20); - TaiInstant test5b = TaiInstant.ofTaiSeconds(5L, 20); - TaiInstant test5n = TaiInstant.ofTaiSeconds(5L, 30); - TaiInstant test6 = TaiInstant.ofTaiSeconds(6L, 20); - - assertEquals(test5a.equals(test5a), true); - assertEquals(test5a.equals(test5b), true); - assertEquals(test5a.equals(test5n), false); - assertEquals(test5a.equals(test6), false); - - assertEquals(test5b.equals(test5a), true); - assertEquals(test5b.equals(test5b), true); - assertEquals(test5b.equals(test5n), false); - assertEquals(test5b.equals(test6), false); - - assertEquals(test5n.equals(test5a), false); - assertEquals(test5n.equals(test5b), false); - assertEquals(test5n.equals(test5n), true); - assertEquals(test5n.equals(test6), false); - - assertEquals(test6.equals(test5a), false); - assertEquals(test6.equals(test5b), false); - assertEquals(test6.equals(test5n), false); - assertEquals(test6.equals(test6), true); - } - - @Test - public void test_equals_null() { - TaiInstant test5 = TaiInstant.ofTaiSeconds(5L, 20); - assertEquals(test5.equals(null), false); - } - - @Test - public void test_equals_otherClass() { - TaiInstant test5 = TaiInstant.ofTaiSeconds(5L, 20); - assertEquals(test5.equals(""), false); - } - - //----------------------------------------------------------------------- - // hashCode() - //----------------------------------------------------------------------- - @Test - public void test_hashCode() { - TaiInstant test5a = TaiInstant.ofTaiSeconds(5L, 20); - TaiInstant test5b = TaiInstant.ofTaiSeconds(5L, 20); - TaiInstant test5n = TaiInstant.ofTaiSeconds(5L, 30); - TaiInstant test6 = TaiInstant.ofTaiSeconds(6L, 20); - - assertEquals(test5a.hashCode() == test5a.hashCode(), true); - assertEquals(test5a.hashCode() == test5b.hashCode(), true); - assertEquals(test5b.hashCode() == test5b.hashCode(), true); - - assertEquals(test5a.hashCode() == test5n.hashCode(), false); - assertEquals(test5a.hashCode() == test6.hashCode(), false); + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(TaiInstant.ofTaiSeconds(5L, 20), TaiInstant.ofTaiSeconds(5L, 20)) + .addEqualityGroup(TaiInstant.ofTaiSeconds(5L, 30), TaiInstant.ofTaiSeconds(5L, 30)) + .addEqualityGroup(TaiInstant.ofTaiSeconds(6L, 20), TaiInstant.ofTaiSeconds(6L, 20)) + .testEquals(); } //----------------------------------------------------------------------- @@ -830,19 +784,19 @@ public void test_hashCode() { @Test public void test_toString_standard() { TaiInstant t = TaiInstant.ofTaiSeconds(123L, 123456789); - assertEquals(t.toString(), "123.123456789s(TAI)"); + assertEquals("123.123456789s(TAI)", t.toString()); } @Test public void test_toString_negative() { TaiInstant t = TaiInstant.ofTaiSeconds(-123L, 123456789); - assertEquals(t.toString(), "-123.123456789s(TAI)"); + assertEquals("-123.123456789s(TAI)", t.toString()); } @Test public void test_toString_zeroDecimal() { TaiInstant t = TaiInstant.ofTaiSeconds(0L, 567); - assertEquals(t.toString(), "0.000000567s(TAI)"); + assertEquals("0.000000567s(TAI)", t.toString()); } } diff --git a/src/test/java/org/threeten/extra/scale/TestUtcInstant.java b/src/test/java/org/threeten/extra/scale/TestUtcInstant.java index bee05847..5757e1cf 100644 --- a/src/test/java/org/threeten/extra/scale/TestUtcInstant.java +++ b/src/test/java/org/threeten/extra/scale/TestUtcInstant.java @@ -31,9 +31,10 @@ */ package org.threeten.extra.scale; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -43,15 +44,16 @@ import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; -import java.time.format.DateTimeParseException; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.google.common.testing.EqualsTester; /** * Test UtcInstant. */ -@Test public class TestUtcInstant { private static final long MJD_1972_12_30 = 41681; @@ -74,16 +76,15 @@ public void test_interfaces() { // serialization //----------------------------------------------------------------------- @Test - public void test_deserialization() throws Exception { - UtcInstant orginal = UtcInstant.ofModifiedJulianDay(2, 3); + public void test_serialization() throws Exception { + UtcInstant test = UtcInstant.ofModifiedJulianDay(2, 3); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - UtcInstant ser = (UtcInstant) in.readObject(); - assertEquals(UtcInstant.ofModifiedJulianDay(2, 3), ser); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertEquals(test, ois.readObject()); + } } //----------------------------------------------------------------------- @@ -94,40 +95,53 @@ public void factory_ofModifiedJulianDay_long_long() { for (long i = -2; i <= 2; i++) { for (int j = 0; j < 10; j++) { UtcInstant t = UtcInstant.ofModifiedJulianDay(i, j); - assertEquals(t.getModifiedJulianDay(), i); - assertEquals(t.getNanoOfDay(), j); - assertEquals(t.isLeapSecond(), false); + assertEquals(i, t.getModifiedJulianDay()); + assertEquals(j, t.getNanoOfDay()); + assertEquals(false, t.isLeapSecond()); } } } + @Test + public void factory_ofModifiedJulianDay_long_long_endNormal() { + UtcInstant t = UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_DAY - 1); + assertEquals(MJD_1972_12_31_LEAP, t.getModifiedJulianDay()); + assertEquals(NANOS_PER_DAY - 1, t.getNanoOfDay()); + assertFalse(t.isLeapSecond()); + assertEquals("1972-12-31T23:59:59.999999999Z", t.toString()); + } + @Test public void factory_ofModifiedJulianDay_long_long_startLeap() { UtcInstant t = UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_DAY); - assertEquals(t.getModifiedJulianDay(), MJD_1972_12_31_LEAP); - assertEquals(t.getNanoOfDay(), NANOS_PER_DAY); + assertEquals(MJD_1972_12_31_LEAP, t.getModifiedJulianDay()); + assertEquals(NANOS_PER_DAY, t.getNanoOfDay()); + assertTrue(t.isLeapSecond()); + assertEquals("1972-12-31T23:59:60Z", t.toString()); } @Test public void factory_ofModifiedJulianDay_long_long_endLeap() { UtcInstant t = UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_LEAP_DAY - 1); - assertEquals(t.getModifiedJulianDay(), MJD_1972_12_31_LEAP); - assertEquals(t.getNanoOfDay(), NANOS_PER_LEAP_DAY - 1); + assertEquals(MJD_1972_12_31_LEAP, t.getModifiedJulianDay()); + assertEquals(NANOS_PER_LEAP_DAY - 1, t.getNanoOfDay()); + assertTrue(t.isLeapSecond()); + assertEquals("1972-12-31T23:59:60.999999999Z", t.toString()); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void factory_ofModifiedJulianDay_long_long_nanosNegative() { - UtcInstant.ofModifiedJulianDay(MJD_1973_01_01, -1); + assertThrows(DateTimeException.class, () -> UtcInstant.ofModifiedJulianDay(MJD_1973_01_01, -1)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void factory_ofModifiedJulianDay_long_long_nanosTooBig_notLeap() { - UtcInstant.ofModifiedJulianDay(MJD_1973_01_01, NANOS_PER_DAY); + assertThrows(DateTimeException.class, () -> UtcInstant.ofModifiedJulianDay(MJD_1973_01_01, NANOS_PER_DAY)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void factory_ofModifiedJulianDay_long_long_nanosTooBig_leap() { - UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_LEAP_DAY); + assertThrows(DateTimeException.class, () -> UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_LEAP_DAY)); } //----------------------------------------------------------------------- @@ -136,13 +150,13 @@ public void factory_ofModifiedJulianDay_long_long_nanosTooBig_leap() { @Test public void factory_of_Instant() { UtcInstant test = UtcInstant.of(Instant.ofEpochSecond(0, 2)); // 1970-01-01 - assertEquals(test.getModifiedJulianDay(), 40587); - assertEquals(test.getNanoOfDay(), 2); + assertEquals(40587, test.getModifiedJulianDay()); + assertEquals(2, test.getNanoOfDay()); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void factory_of_Instant_null() { - UtcInstant.of((Instant) null); + assertThrows(NullPointerException.class, () -> UtcInstant.of((Instant) null)); } //----------------------------------------------------------------------- @@ -154,14 +168,14 @@ public void factory_of_TaiInstant() { for (int j = 0; j < 10; j++) { UtcInstant expected = UtcInstant.ofModifiedJulianDay(36204 + i, j * NANOS_PER_SEC + 2L); TaiInstant tai = TaiInstant.ofTaiSeconds(i * SECS_PER_DAY + j + 10, 2); - assertEquals(UtcInstant.of(tai), expected); + assertEquals(expected, UtcInstant.of(tai)); } } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void factory_of_TaiInstant_null() { - UtcInstant.of((TaiInstant) null); + assertThrows(NullPointerException.class, () -> UtcInstant.of((TaiInstant) null)); } //----------------------------------------------------------------------- @@ -169,12 +183,11 @@ public void factory_of_TaiInstant_null() { //----------------------------------------------------------------------- @Test public void factory_parse_CharSequence() { - assertEquals(UtcInstant.parse("1972-12-31T23:59:59Z"), UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_DAY - NANOS_PER_SEC)); - assertEquals(UtcInstant.parse("1972-12-31T23:59:60Z"), UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_DAY)); + assertEquals(UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_DAY - NANOS_PER_SEC), UtcInstant.parse("1972-12-31T23:59:59Z")); + assertEquals(UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, NANOS_PER_DAY), UtcInstant.parse("1972-12-31T23:59:60Z")); } - @DataProvider(name = "BadParse") - Object[][] provider_badParse() { + public static Object[][] data_badParse() { return new Object[][] { {""}, {"A"}, @@ -182,26 +195,26 @@ Object[][] provider_badParse() { }; } - @Test(dataProvider = "BadParse", expectedExceptions = DateTimeParseException.class) + @ParameterizedTest + @MethodSource("data_badParse") public void factory_parse_CharSequence_invalid(String str) { - UtcInstant.parse(str); + assertThrows(DateTimeException.class, () -> UtcInstant.parse(str)); } - @Test(expectedExceptions = DateTimeException.class) + @Test public void factory_parse_CharSequence_invalidLeapSecond() { - UtcInstant.parse("1972-11-11T23:59:60Z"); // leap second but not leap day + assertThrows(DateTimeException.class, () -> UtcInstant.parse("1972-11-11T23:59:60Z")); // leap second but not leap day } - @Test(expectedExceptions = NullPointerException.class) + @Test public void factory_parse_CharSequence_null() { - UtcInstant.parse((String) null); + assertThrows(NullPointerException.class, () -> UtcInstant.parse((String) null)); } //----------------------------------------------------------------------- // withModifiedJulianDay() //----------------------------------------------------------------------- - @DataProvider(name = "WithModifiedJulianDay") - Object[][] provider_withModifiedJulianDay() { + public static Object[][] data_withModifiedJulianDay() { return new Object[][] { {0L, 12345L, 1L, 1L, 12345L}, {0L, 12345L, -1L, -1L, 12345L}, @@ -216,28 +229,23 @@ Object[][] provider_withModifiedJulianDay() { }; } - @Test(dataProvider = "WithModifiedJulianDay") + @ParameterizedTest + @MethodSource("data_withModifiedJulianDay") public void test_withModifiedJulianDay(long mjd, long nanos, long newMjd, Long expectedMjd, Long expectedNanos) { UtcInstant i = UtcInstant.ofModifiedJulianDay(mjd, nanos); if (expectedMjd != null) { - i = i.withModifiedJulianDay(newMjd); - assertEquals(i.getModifiedJulianDay(), expectedMjd.longValue()); - assertEquals(i.getNanoOfDay(), expectedNanos.longValue()); + UtcInstant withModifiedJulianDay = i.withModifiedJulianDay(newMjd); + assertEquals(expectedMjd.longValue(), withModifiedJulianDay.getModifiedJulianDay()); + assertEquals(expectedNanos.longValue(), withModifiedJulianDay.getNanoOfDay()); } else { - try { - i = i.withModifiedJulianDay(newMjd); - fail(); - } catch (DateTimeException ex) { - // expected - } + assertThrows(DateTimeException.class, () -> i.withModifiedJulianDay(newMjd)); } } //----------------------------------------------------------------------- // withNanoOfDay() //----------------------------------------------------------------------- - @DataProvider(name = "WithNanoOfDay") - Object[][] provider_withNanoOfDay() { + public static Object[][] data_withNanoOfDay() { return new Object[][] { {0L, 12345L, 1L, 0L, 1L}, {0L, 12345L, -1L, null, null}, @@ -258,28 +266,23 @@ Object[][] provider_withNanoOfDay() { }; } - @Test(dataProvider = "WithNanoOfDay") + @ParameterizedTest + @MethodSource("data_withNanoOfDay") public void test_withNanoOfDay(long mjd, long nanos, long newNanoOfDay, Long expectedMjd, Long expectedNanos) { UtcInstant i = UtcInstant.ofModifiedJulianDay(mjd, nanos); if (expectedMjd != null) { - i = i.withNanoOfDay(newNanoOfDay); - assertEquals(i.getModifiedJulianDay(), expectedMjd.longValue()); - assertEquals(i.getNanoOfDay(), expectedNanos.longValue()); + UtcInstant withNanoOfDay = i.withNanoOfDay(newNanoOfDay); + assertEquals(expectedMjd.longValue(), withNanoOfDay.getModifiedJulianDay()); + assertEquals(expectedNanos.longValue(), withNanoOfDay.getNanoOfDay()); } else { - try { - i = i.withNanoOfDay(newNanoOfDay); - fail(); - } catch (DateTimeException ex) { - // expected - } + assertThrows(DateTimeException.class, () -> i.withNanoOfDay(newNanoOfDay)); } } //----------------------------------------------------------------------- // plus(Duration) //----------------------------------------------------------------------- - @DataProvider(name = "Plus") - Object[][] provider_plus() { + public static Object[][] data_plus() { return new Object[][] { {0, 0, -2 * SECS_PER_DAY, 5, -2, 5}, {0, 0, -1 * SECS_PER_DAY, 1, -1, 1}, @@ -313,30 +316,30 @@ Object[][] provider_plus() { }; } - @Test(dataProvider = "Plus") + @ParameterizedTest + @MethodSource("data_plus") public void test_plus(long mjd, long nanos, long plusSeconds, int plusNanos, long expectedMjd, long expectedNanos) { UtcInstant i = UtcInstant.ofModifiedJulianDay(mjd, nanos).plus(Duration.ofSeconds(plusSeconds, plusNanos)); - assertEquals(i.getModifiedJulianDay(), expectedMjd); - assertEquals(i.getNanoOfDay(), expectedNanos); + assertEquals(expectedMjd, i.getModifiedJulianDay()); + assertEquals(expectedNanos, i.getNanoOfDay()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_overflowTooBig() { UtcInstant i = UtcInstant.ofModifiedJulianDay(Long.MAX_VALUE, NANOS_PER_DAY - 1); - i.plus(Duration.ofNanos(1)); + assertThrows(ArithmeticException.class, () -> i.plus(Duration.ofNanos(1))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_plus_overflowTooSmall() { UtcInstant i = UtcInstant.ofModifiedJulianDay(Long.MIN_VALUE, 0); - i.plus(Duration.ofNanos(-1)); + assertThrows(ArithmeticException.class, () -> i.plus(Duration.ofNanos(-1))); } //----------------------------------------------------------------------- // minus(Duration) //----------------------------------------------------------------------- - @DataProvider(name = "Minus") - Object[][] provider_minus() { + public static Object[][] data_minus() { return new Object[][] { {0, 0, 2 * SECS_PER_DAY, -5, -2, 5}, {0, 0, 1 * SECS_PER_DAY, -1, -1, 1}, @@ -370,23 +373,24 @@ Object[][] provider_minus() { }; } - @Test(dataProvider = "Minus") + @ParameterizedTest + @MethodSource("data_minus") public void test_minus(long mjd, long nanos, long minusSeconds, int minusNanos, long expectedMjd, long expectedNanos) { UtcInstant i = UtcInstant.ofModifiedJulianDay(mjd, nanos).minus(Duration.ofSeconds(minusSeconds, minusNanos)); - assertEquals(i.getModifiedJulianDay(), expectedMjd); - assertEquals(i.getNanoOfDay(), expectedNanos); + assertEquals(expectedMjd, i.getModifiedJulianDay()); + assertEquals(expectedNanos, i.getNanoOfDay()); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_overflowTooSmall() { UtcInstant i = UtcInstant.ofModifiedJulianDay(Long.MIN_VALUE, 0); - i.minus(Duration.ofNanos(1)); + assertThrows(ArithmeticException.class, () -> i.minus(Duration.ofNanos(1))); } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_minus_overflowTooBig() { UtcInstant i = UtcInstant.ofModifiedJulianDay(Long.MAX_VALUE, NANOS_PER_DAY - 1); - i.minus(Duration.ofNanos(-1)); + assertThrows(ArithmeticException.class, () -> i.minus(Duration.ofNanos(-1))); } //----------------------------------------------------------------------- @@ -397,8 +401,8 @@ public void test_durationUntil_oneDayNoLeap() { UtcInstant utc1 = UtcInstant.ofModifiedJulianDay(MJD_1972_12_30, 0); UtcInstant utc2 = UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, 0); Duration test = utc1.durationUntil(utc2); - assertEquals(test.getSeconds(), 86400); - assertEquals(test.getNano(), 0); + assertEquals(86400, test.getSeconds()); + assertEquals(0, test.getNano()); } @Test @@ -406,8 +410,8 @@ public void test_durationUntil_oneDayLeap() { UtcInstant utc1 = UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, 0); UtcInstant utc2 = UtcInstant.ofModifiedJulianDay(MJD_1973_01_01, 0); Duration test = utc1.durationUntil(utc2); - assertEquals(test.getSeconds(), 86401); - assertEquals(test.getNano(), 0); + assertEquals(86401, test.getSeconds()); + assertEquals(0, test.getNano()); } @Test @@ -415,8 +419,8 @@ public void test_durationUntil_oneDayLeapNegative() { UtcInstant utc1 = UtcInstant.ofModifiedJulianDay(MJD_1973_01_01, 0); UtcInstant utc2 = UtcInstant.ofModifiedJulianDay(MJD_1972_12_31_LEAP, 0); Duration test = utc1.durationUntil(utc2); - assertEquals(test.getSeconds(), -86401); - assertEquals(test.getNano(), 0); + assertEquals(-86401, test.getSeconds()); + assertEquals(0, test.getNano()); } //----------------------------------------------------------------------- @@ -428,16 +432,16 @@ public void test_toTaiInstant() { for (int j = 0; j < 10; j++) { UtcInstant utc = UtcInstant.ofModifiedJulianDay(36204 + i, j * NANOS_PER_SEC + 2L); TaiInstant test = utc.toTaiInstant(); - assertEquals(test.getTaiSeconds(), i * SECS_PER_DAY + j + 10); - assertEquals(test.getNano(), 2); + assertEquals(i * SECS_PER_DAY + j + 10, test.getTaiSeconds()); + assertEquals(2, test.getNano()); } } } - @Test(expectedExceptions = ArithmeticException.class) + @Test public void test_toTaiInstant_maxInvalid() { UtcInstant utc = UtcInstant.ofModifiedJulianDay(Long.MAX_VALUE, 0); - utc.toTaiInstant(); + assertThrows(ArithmeticException.class, () -> utc.toTaiInstant()); } //----------------------------------------------------------------------- @@ -449,7 +453,7 @@ public void test_toInstant() { for (int j = 0; j < 10; j++) { Instant expected = Instant.ofEpochSecond(315532800 + i * SECS_PER_DAY + j).plusNanos(2); UtcInstant test = UtcInstant.ofModifiedJulianDay(44239 + i, j * NANOS_PER_SEC + 2); - assertEquals(test.toInstant(), expected, "Loop " + i + " " + j); + assertEquals(expected, test.toInstant()); } } } @@ -482,98 +486,54 @@ void doTest_comparisons_UtcInstant(UtcInstant... instants) { for (int j = 0; j < instants.length; j++) { UtcInstant b = instants[j]; if (i < j) { - assertEquals(a.compareTo(b), -1, a + " <=> " + b); - assertEquals(a.equals(b), false, a + " <=> " + b); + assertEquals(-1, a.compareTo(b)); + assertEquals(false, a.equals(b)); + assertTrue(a.isBefore(b)); + assertFalse(a.isAfter(b)); } else if (i > j) { - assertEquals(a.compareTo(b), 1, a + " <=> " + b); - assertEquals(a.equals(b), false, a + " <=> " + b); + assertEquals(1, a.compareTo(b)); + assertEquals(false, a.equals(b)); + assertFalse(a.isBefore(b)); + assertTrue(a.isAfter(b)); } else { - assertEquals(a.compareTo(b), 0, a + " <=> " + b); - assertEquals(a.equals(b), true, a + " <=> " + b); + assertEquals(0, a.compareTo(b)); + assertEquals(true, a.equals(b)); + assertFalse(a.isBefore(b)); + assertFalse(a.isAfter(b)); } } } } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_compareTo_ObjectNull() { UtcInstant a = UtcInstant.ofModifiedJulianDay(0L, 0); - a.compareTo(null); + assertThrows(NullPointerException.class, () -> a.compareTo(null)); } - @Test(expectedExceptions = ClassCastException.class) + @Test @SuppressWarnings({"unchecked", "rawtypes"}) public void test_compareToNonUtcInstant() { Comparable c = UtcInstant.ofModifiedJulianDay(0L, 2); - c.compareTo(new Object()); + assertThrows(ClassCastException.class, () -> c.compareTo(new Object())); } //----------------------------------------------------------------------- - // equals() + // equals() / hashCode() //----------------------------------------------------------------------- @Test - public void test_equals() { - UtcInstant test5a = UtcInstant.ofModifiedJulianDay(5L, 20); - UtcInstant test5b = UtcInstant.ofModifiedJulianDay(5L, 20); - UtcInstant test5n = UtcInstant.ofModifiedJulianDay(5L, 30); - UtcInstant test6 = UtcInstant.ofModifiedJulianDay(6L, 20); - - assertEquals(test5a.equals(test5a), true); - assertEquals(test5a.equals(test5b), true); - assertEquals(test5a.equals(test5n), false); - assertEquals(test5a.equals(test6), false); - - assertEquals(test5b.equals(test5a), true); - assertEquals(test5b.equals(test5b), true); - assertEquals(test5b.equals(test5n), false); - assertEquals(test5b.equals(test6), false); - - assertEquals(test5n.equals(test5a), false); - assertEquals(test5n.equals(test5b), false); - assertEquals(test5n.equals(test5n), true); - assertEquals(test5n.equals(test6), false); - - assertEquals(test6.equals(test5a), false); - assertEquals(test6.equals(test5b), false); - assertEquals(test6.equals(test5n), false); - assertEquals(test6.equals(test6), true); - } - - @Test - public void test_equals_null() { - UtcInstant test5 = UtcInstant.ofModifiedJulianDay(5L, 20); - assertEquals(test5.equals(null), false); - } - - @Test - public void test_equals_otherClass() { - UtcInstant test5 = UtcInstant.ofModifiedJulianDay(5L, 20); - assertEquals(test5.equals(""), false); - } - - //----------------------------------------------------------------------- - // hashCode() - //----------------------------------------------------------------------- - @Test - public void test_hashCode() { - UtcInstant test5a = UtcInstant.ofModifiedJulianDay(5L, 20); - UtcInstant test5b = UtcInstant.ofModifiedJulianDay(5L, 20); - UtcInstant test5n = UtcInstant.ofModifiedJulianDay(5L, 30); - UtcInstant test6 = UtcInstant.ofModifiedJulianDay(6L, 20); - - assertEquals(test5a.hashCode() == test5a.hashCode(), true); - assertEquals(test5a.hashCode() == test5b.hashCode(), true); - assertEquals(test5b.hashCode() == test5b.hashCode(), true); - - assertEquals(test5a.hashCode() == test5n.hashCode(), false); - assertEquals(test5a.hashCode() == test6.hashCode(), false); + public void test_equals_and_hashCode() { + new EqualsTester() + .addEqualityGroup(UtcInstant.ofModifiedJulianDay(5L, 20), UtcInstant.ofModifiedJulianDay(5L, 20)) + .addEqualityGroup(UtcInstant.ofModifiedJulianDay(5L, 30), UtcInstant.ofModifiedJulianDay(5L, 30)) + .addEqualityGroup(UtcInstant.ofModifiedJulianDay(6L, 20), UtcInstant.ofModifiedJulianDay(6L, 20)) + .testEquals(); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name = "ToString") - Object[][] provider_toString() { + public static Object[][] data_toString() { return new Object[][] { {40587, 0, "1970-01-01T00:00:00Z"}, {40588, 1, "1970-01-02T00:00:00.000000001Z"}, @@ -591,14 +551,16 @@ Object[][] provider_toString() { }; } - @Test(dataProvider = "ToString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString(long mjd, long nod, String expected) { - assertEquals(UtcInstant.ofModifiedJulianDay(mjd, nod).toString(), expected); + assertEquals(expected, UtcInstant.ofModifiedJulianDay(mjd, nod).toString()); } - @Test(dataProvider = "ToString") + @ParameterizedTest + @MethodSource("data_toString") public void test_toString_parse(long mjd, long nod, String str) { - assertEquals(UtcInstant.parse(str), UtcInstant.ofModifiedJulianDay(mjd, nod)); + assertEquals(UtcInstant.ofModifiedJulianDay(mjd, nod), UtcInstant.parse(str)); } } diff --git a/src/test/java/org/threeten/extra/scale/TestUtcRules.java b/src/test/java/org/threeten/extra/scale/TestUtcRules.java index f0b3012c..4eab852e 100644 --- a/src/test/java/org/threeten/extra/scale/TestUtcRules.java +++ b/src/test/java/org/threeten/extra/scale/TestUtcRules.java @@ -31,9 +31,10 @@ */ package org.threeten.extra.scale; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -49,19 +50,19 @@ import java.time.temporal.JulianFields; import java.util.Arrays; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Test SystemLeapSecondRules. */ -@Test public class TestUtcRules { SystemUtcRules rules; - @BeforeMethod + @BeforeEach public void setUp() throws Exception { Constructor con = SystemUtcRules.class.getDeclaredConstructor(); con.setAccessible(true); @@ -69,6 +70,7 @@ public void setUp() throws Exception { } //----------------------------------------------------------------------- + @Test public void test_interfaces() { assertTrue(Serializable.class.isAssignableFrom(Duration.class)); } @@ -76,28 +78,30 @@ public void test_interfaces() { //----------------------------------------------------------------------- // serialize //----------------------------------------------------------------------- - public void test_serialize() throws Exception { + @Test + public void test_serialization() throws Exception { SystemUtcRules test = SystemUtcRules.INSTANCE; // use real rules, not our hacked copy ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(test); - oos.close(); - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); - assertSame(ois.readObject(), test); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(test); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + assertSame(test, ois.readObject()); + } } //----------------------------------------------------------------------- // getName() //----------------------------------------------------------------------- + @Test public void test_getName() { - assertEquals(rules.getName(), "System"); + assertEquals("System", rules.getName()); } //----------------------------------------------------------------------- // getLeapSecond() //----------------------------------------------------------------------- - @DataProvider(name = "LeapSeconds") - Object[][] leapSeconds() { + public static Object[][] data_leapSeconds() { return new Object[][] { {-1, 0, 10, "1858-11-16"}, {0, 0, 10, "1858-11-17"}, @@ -229,16 +233,17 @@ Object[][] leapSeconds() { }; } - @Test(dataProvider = "LeapSeconds") + @ParameterizedTest + @MethodSource("data_leapSeconds") public void test_leapSeconds(long mjd, int adjust, int offset, String checkDate) { - assertEquals(mjd, LocalDate.parse(checkDate).getLong(JulianFields.MODIFIED_JULIAN_DAY), "Invalid test"); + assertEquals(LocalDate.parse(checkDate).getLong(JulianFields.MODIFIED_JULIAN_DAY), mjd); - assertEquals(rules.getLeapSecondAdjustment(mjd), adjust); - assertEquals(rules.getTaiOffset(mjd), offset); + assertEquals(adjust, rules.getLeapSecondAdjustment(mjd)); + assertEquals(offset, rules.getTaiOffset(mjd)); if (adjust != 0) { long[] leaps = rules.getLeapSecondDates(); Arrays.sort(leaps); - assertEquals(Arrays.binarySearch(leaps, mjd) >= 0, true); + assertEquals(true, Arrays.binarySearch(leaps, mjd) >= 0); } } @@ -260,115 +265,128 @@ public void test_leapSeconds(long mjd, int adjust, int offset, String checkDate) private static final long TAI_SECS_UTC2100 = (MJD_2100 - MJD_1958) * SECS_PER_DAY + CURRENT_TAI_OFFSET; private static final long TAI_SECS_UTC2100_EXTRA_NEGATIVE_LEAP = (MJD_2100 - MJD_1958) * SECS_PER_DAY + CURRENT_TAI_OFFSET - 1; + @Test public void test_convertToUtc_TaiInstant_startUtcPeriod() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC1980, 0); // 1980-01-01 (19 leap secs added) UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_1980, 0); for (int i = -10; i < 10; i++) { Duration duration = Duration.ofNanos(i); - assertEquals(rules.convertToUtc(tai.plus(duration)), expected.plus(duration)); - assertEquals(rules.convertToTai(expected.plus(duration)), tai.plus(duration)); // check reverse + assertEquals(expected.plus(duration), rules.convertToUtc(tai.plus(duration))); + assertEquals(tai.plus(duration), rules.convertToTai(expected.plus(duration))); // check reverse } for (int i = -10; i < 10; i++) { Duration duration = Duration.ofSeconds(i); - assertEquals(rules.convertToUtc(tai.plus(duration)), expected.plus(duration)); - assertEquals(rules.convertToTai(expected.plus(duration)), tai.plus(duration)); // check reverse + assertEquals(expected.plus(duration), rules.convertToUtc(tai.plus(duration))); + assertEquals(tai.plus(duration), rules.convertToTai(expected.plus(duration))); // check reverse } } + @Test public void test_convertToUtc_TaiInstant_furtherAfterLeap() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC1980 + 1, 0); // 1980-01-01 (19 leap secs added) UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_1980, NANOS_PER_SEC); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } + @Test public void test_convertToUtc_TaiInstant_justAfterLeap() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC1980, 0); // 1980-01-01 (19 leap secs added) UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_1980, 0); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } + @Test public void test_convertToUtc_TaiInstant_inLeap() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC1980 - 1, 0); // 1980-01-01 (1 second before 1980) UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_1980 - 1, SECS_PER_DAY * NANOS_PER_SEC); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } + @Test public void test_convertToUtc_TaiInstant_justBeforeLeap() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC1980 - 2, 0); // 1980-01-01 (2 seconds before 1980) UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_1980 - 1, (SECS_PER_DAY - 1) * NANOS_PER_SEC); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } + @Test public void test_convertToUtc_TaiInstant_1800() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC1800, 0); // 1800-01-01 UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_1800, 0); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } + @Test public void test_convertToUtc_TaiInstant_1900() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC1900, 0); // 1900-01-01 UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_1900, 0); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } + @Test public void test_convertToUtc_TaiInstant_1958() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC1958, 0); // 1958-01-01 UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_1958, 0); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } + @Test public void test_convertToUtc_TaiInstant_2100() { TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC2100, 0); // 2100-01-01 UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_2100, 0); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_convertToUtc_TaiInstant_null() { - rules.convertToUtc((TaiInstant) null); + assertThrows(NullPointerException.class, () -> rules.convertToUtc((TaiInstant) null)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_convertToTai_UtcInstant_null() { - rules.convertToTai((UtcInstant) null); + assertThrows(NullPointerException.class, () -> rules.convertToTai((UtcInstant) null)); } //------------------------------------------------------------------------- + @Test public void test_negativeLeap_justBeforeLeap() { rules.register(MJD_2100 - 1, -1); TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC2100_EXTRA_NEGATIVE_LEAP - 1, 0); // 2100-01-01 (1 second before 2100) UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_2100 - 1, (SECS_PER_DAY - 2) * NANOS_PER_SEC); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } + @Test public void test_negativeLeap_justAfterLeap() { rules.register(MJD_2100 - 1, -1); TaiInstant tai = TaiInstant.ofTaiSeconds(TAI_SECS_UTC2100_EXTRA_NEGATIVE_LEAP, 0); // 2100-01-01 UtcInstant expected = UtcInstant.ofModifiedJulianDay(MJD_2100, 0); - assertEquals(rules.convertToUtc(tai), expected); - assertEquals(rules.convertToTai(expected), tai); // check reverse + assertEquals(expected, rules.convertToUtc(tai)); + assertEquals(tai, rules.convertToTai(expected)); // check reverse } //----------------------------------------------------------------------- // convertToUtc(Instant)/convertToInstant(UtcInstant) //----------------------------------------------------------------------- + @Test public void test_convertToInstant_justBeforeLeap() { OffsetDateTime odt = OffsetDateTime.of(1979, 12, 31, 23, 43, 21, 0, ZoneOffset.UTC); Instant instant = odt.toInstant(); UtcInstant utc = UtcInstant.ofModifiedJulianDay(MJD_1980 - 1, (SECS_PER_DAY + 1 - 1000) * NANOS_PER_SEC); - assertEquals(rules.convertToInstant(utc), instant); - assertEquals(rules.convertToUtc(instant), utc); + assertEquals(instant, rules.convertToInstant(utc)); + assertEquals(utc, rules.convertToUtc(instant)); } + @Test public void test_convertToInstant_sls() { for (int i = 1; i < 1000; i++) { long utcNanos = (SECS_PER_DAY + 1 - 1000) * NANOS_PER_SEC + i * 1000000000L; @@ -380,11 +398,12 @@ public void test_convertToInstant_sls() { Instant instant = odt.toInstant(); UtcInstant utc = UtcInstant.ofModifiedJulianDay( MJD_1980 - 1, (SECS_PER_DAY + 1 - 1000) * NANOS_PER_SEC + i * NANOS_PER_SEC); - assertEquals(rules.convertToInstant(utc), instant); - assertEquals(rules.convertToUtc(instant), utc); + assertEquals(instant, rules.convertToInstant(utc)); + assertEquals(utc, rules.convertToUtc(instant)); } } + @Test public void test_convertToInstant_slsMillis() { for (int i = 1; i < 1000; i++) { long utcNanos = (SECS_PER_DAY + 1 - 1000) * NANOS_PER_SEC + i * 1000000; @@ -394,11 +413,12 @@ public void test_convertToInstant_slsMillis() { Instant instant = odt.toInstant(); UtcInstant utc = UtcInstant.ofModifiedJulianDay( MJD_1980 - 1, (SECS_PER_DAY + 1 - 1000) * NANOS_PER_SEC + i * 1000000); - assertEquals(rules.convertToInstant(utc), instant); - assertEquals(rules.convertToUtc(instant), utc); + assertEquals(instant, rules.convertToInstant(utc)); + assertEquals(utc, rules.convertToUtc(instant)); } } + @Test public void test_convertToInstant_slsMicros() { for (int i = 1; i < 1000; i++) { long utcNanos = (SECS_PER_DAY + 1 - 1000) * NANOS_PER_SEC + i * 1000; @@ -408,11 +428,12 @@ public void test_convertToInstant_slsMicros() { Instant instant = odt.toInstant(); UtcInstant utc = UtcInstant.ofModifiedJulianDay( MJD_1980 - 1, (SECS_PER_DAY + 1 - 1000) * NANOS_PER_SEC + i * 1000); - assertEquals(rules.convertToInstant(utc), instant); - assertEquals(rules.convertToUtc(instant), utc); + assertEquals(instant, rules.convertToInstant(utc)); + assertEquals(utc, rules.convertToUtc(instant)); } } + @Test public void test_convertToInstant_slsNanos() { for (int i = 1; i < 5005; i++) { long utcNanos = (SECS_PER_DAY + 1 - 1000) * NANOS_PER_SEC + i; @@ -421,115 +442,122 @@ public void test_convertToInstant_slsNanos() { OffsetDateTime odt = OffsetDateTime.of(1979, 12, 31, 23, 43, 21, (int) (slsNanos % NANOS_PER_SEC), ZoneOffset.UTC); Instant instant = odt.toInstant(); UtcInstant utc = UtcInstant.ofModifiedJulianDay(MJD_1980 - 1, utcNanos); - assertEquals(rules.convertToInstant(utc), instant); + assertEquals(instant, rules.convertToInstant(utc)); // not all instants can map back to the correct UTC value long reverseUtcNanos = startSls + ((slsNanos - startSls) * 1000L) / (1000L - 1); - assertEquals(rules.convertToUtc(instant), UtcInstant.ofModifiedJulianDay(MJD_1980 - 1, reverseUtcNanos)); + assertEquals(UtcInstant.ofModifiedJulianDay(MJD_1980 - 1, reverseUtcNanos), rules.convertToUtc(instant)); } } + @Test public void test_convertToInstant_justAfterLeap() { OffsetDateTime odt = OffsetDateTime.of(1980, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); Instant instant = odt.toInstant(); UtcInstant utc = UtcInstant.ofModifiedJulianDay(MJD_1980, 0); - assertEquals(rules.convertToInstant(utc), instant); - assertEquals(rules.convertToUtc(instant), utc); + assertEquals(instant, rules.convertToInstant(utc)); + assertEquals(utc, rules.convertToUtc(instant)); } + @Test public void test_convertToInstant_furtherAfterLeap() { OffsetDateTime odt = OffsetDateTime.of(1980, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC); Instant instant = odt.toInstant(); UtcInstant utc = UtcInstant.ofModifiedJulianDay(MJD_1980, NANOS_PER_SEC); - assertEquals(rules.convertToInstant(utc), instant); - assertEquals(rules.convertToUtc(instant), utc); + assertEquals(instant, rules.convertToInstant(utc)); + assertEquals(utc, rules.convertToUtc(instant)); } //----------------------------------------------------------------------- // registerLeapSecond() //----------------------------------------------------------------------- + @Test public void test_registerLeapSecond_justAfterLastDate_plusOne() { long[] dates = rules.getLeapSecondDates(); long mjd = dates[dates.length - 1] + 1; rules.register(mjd, 1); long[] test = rules.getLeapSecondDates(); - assertEquals(test.length, dates.length + 1); - assertEquals(test[test.length - 1], mjd); - assertEquals(rules.getLeapSecondAdjustment(mjd), 1); + assertEquals(dates.length + 1, test.length); + assertEquals(mjd, test[test.length - 1]); + assertEquals(1, rules.getLeapSecondAdjustment(mjd)); } + @Test public void test_registerLeapSecond_justAfterLastDate_minusOne() { long[] dates = rules.getLeapSecondDates(); long mjd = dates[dates.length - 1] + 1; rules.register(mjd, -1); long[] test = rules.getLeapSecondDates(); - assertEquals(test.length, dates.length + 1); - assertEquals(test[test.length - 1], mjd); - assertEquals(rules.getLeapSecondAdjustment(mjd), -1); + assertEquals(dates.length + 1, test.length); + assertEquals(mjd, test[test.length - 1]); + assertEquals(-1, rules.getLeapSecondAdjustment(mjd)); } + @Test public void test_registerLeapSecond_equalLastDate_sameLeap() { long[] dates = rules.getLeapSecondDates(); long mjd = dates[dates.length - 1]; int adj = rules.getLeapSecondAdjustment(mjd); rules.register(mjd, adj); long[] test = rules.getLeapSecondDates(); - assertEquals(Arrays.equals(test, dates), true); - assertEquals(rules.getLeapSecondAdjustment(mjd), adj); + assertEquals(true, Arrays.equals(test, dates)); + assertEquals(adj, rules.getLeapSecondAdjustment(mjd)); } + @Test public void test_registerLeapSecond_equalEarlierDate_sameLeap() { long[] dates = rules.getLeapSecondDates(); long mjd = dates[dates.length - 2]; int adj = rules.getLeapSecondAdjustment(mjd); rules.register(mjd, adj); long[] test = rules.getLeapSecondDates(); - assertEquals(Arrays.equals(test, dates), true); - assertEquals(rules.getLeapSecondAdjustment(mjd), adj); + assertEquals(true, Arrays.equals(test, dates)); + assertEquals(adj, rules.getLeapSecondAdjustment(mjd)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test_registerLeapSecond_equalLastDate_differentLeap() { long[] dates = rules.getLeapSecondDates(); long mjd = dates[dates.length - 1]; int adj = rules.getLeapSecondAdjustment(mjd); - rules.register(mjd, -adj); + assertThrows(IllegalArgumentException.class, () -> rules.register(mjd, -adj)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test_registerLeapSecond_equalEarlierDate_differentLeap() { long[] dates = rules.getLeapSecondDates(); long mjd = dates[dates.length - 2]; int adj = rules.getLeapSecondAdjustment(mjd); - rules.register(mjd, -adj); + assertThrows(IllegalArgumentException.class, () -> rules.register(mjd, -adj)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test_registerLeapSecond_beforeLastDate() { long[] dates = rules.getLeapSecondDates(); long mjd = dates[dates.length - 1] - 1; - rules.register(mjd, 1); + assertThrows(IllegalArgumentException.class, () -> rules.register(mjd, 1)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test_registerLeapSecond_invalidAdjustment_zero() { - rules.register(MJD_2100, 0); + assertThrows(IllegalArgumentException.class, () -> rules.register(MJD_2100, 0)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test_registerLeapSecond_invalidAdjustment_minusTwo() { - rules.register(MJD_2100, -2); + assertThrows(IllegalArgumentException.class, () -> rules.register(MJD_2100, -2)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test_registerLeapSecond_invalidAdjustment_three() { - rules.register(MJD_2100, 3); + assertThrows(IllegalArgumentException.class, () -> rules.register(MJD_2100, 3)); } //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- + @Test public void test_toString() { - assertEquals(rules.toString(), "UtcRules[System]"); + assertEquals("UtcRules[System]", rules.toString()); } }