diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 94673dce139..2982bf6dc76 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,14 +3,15 @@ # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. +# name: "CodeQL" on: push: - branches: [main] + branches: [ main ] pull_request: # The branches below must be a subset of the branches above - branches: [main] + branches: [ main ] schedule: - cron: '0 8 * * 0' @@ -18,59 +19,48 @@ jobs: analyze: name: Analyze runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write strategy: fail-fast: false matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['java'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + language: [ 'java' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - - name: Setup Java - uses: actions/setup-java@v1 - with: - java-version: 11 + - name: Checkout repository + uses: actions/checkout@v2 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/cross-version.yml b/.github/workflows/cross-version.yml index da01957fd88..d6dfa72a8f6 100644 --- a/.github/workflows/cross-version.yml +++ b/.github/workflows/cross-version.yml @@ -9,13 +9,14 @@ jobs: strategy: fail-fast: false matrix: - java: [14, 15, 16-ea, 17-ea] + java: [16, 17-ea] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: + distribution: 'zulu' java-version: ${{ matrix.java }} - name: Cache Maven Repository uses: actions/cache@v2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dcd10b03be1..9ba9388574b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,8 +14,9 @@ jobs: steps: - uses: actions/checkout@v2 - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: + distribution: 'zulu' java-version: 11 - name: Cache Maven Repository uses: actions/cache@v2 @@ -35,8 +36,9 @@ jobs: with: fetch-depth: 0 - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: + distribution: 'zulu' java-version: 11 - name: Cache Maven Repository uses: actions/cache@v2 @@ -46,8 +48,7 @@ jobs: restore-keys: ${{ runner.os }}-maven - name: Test with Sonar run: > - ./mvnw -V --no-transfer-progress -e clean verify javadoc:javadoc - org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar + ./mvnw -V --no-transfer-progress -e clean verify javadoc:javadoc sonar:sonar -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=assertj -Dsonar.projectKey=joel-costigliola_assertj-core diff --git a/.github/workflows/pitest-receive-pr.yml b/.github/workflows/pitest-receive-pr.yml new file mode 100644 index 00000000000..a4ac9fee377 --- /dev/null +++ b/.github/workflows/pitest-receive-pr.yml @@ -0,0 +1,53 @@ +# +# Part one of two stage process to update PRs with pitest data when accepting PRs from untrusted forks. +# +# The jobs will run the mutation analysis, but the token supplied by gtihub does not have write access. +# The results are therefore stored as an artifact which will be used to update the PR in the second stage. +# +# Projects where PRs come from the same repo can use a simpler single stage process. +# +# see https://blog.pitest.org/pitest-pr-setup/ +# +name: Receive + +# read-only repo token +# no access to secrets +on: + pull_request: + +jobs: + store-pitest-feedback: + # Only run on forked repos. + if: github.event.pull_request.head.repo.full_name != github.repository + runs-on: ubuntu-latest + + steps: + - name: Checkout project + uses: actions/checkout@v2 + with: + # important to set a fetch depth of 2. By default the checkout action make no history available + fetch-depth: 2 + + - name: Cache local Maven repository + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-maven- + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: 11 + - name: run pitest + # pitest has been bound to a profile called pitest for normal running + # we add config to analyse only changes made within a PR and treat surviving mutants as check errors + # failWhenNoMutations is unset in the pom, as otherwise PRs that do not affect java code would fail + run: mvn -e -B -Ppitest -Dfeatures="+GIT(from[HEAD~1]), +gitci" test + - name: aggregate files + run: mvn -e -B -Ppitest pitest-git:aggregate + - name: upload results + uses: actions/upload-artifact@v2 + with: + name: pitest + path: target/pit-reports-ci/ diff --git a/.github/workflows/pitest-updated-pr.yml b/.github/workflows/pitest-updated-pr.yml new file mode 100644 index 00000000000..68168a6e6f4 --- /dev/null +++ b/.github/workflows/pitest-updated-pr.yml @@ -0,0 +1,45 @@ +# +# Part two of two stage process for updating PRs with pitest results when accepting PRs from untrusted forks. +# +# The version of this file that runs is the version in the main/master branch, NOT the version in the PR. It must therefore +# be committed to main/master before the process can run for the first time. +# +# This workflow takes an artifact containing pitest results generated in part one, and updated the PR. It runs with +# write access. +# +# See https://blog.pitest.org/oss-pitest-pr/ + +name: Comment on the pull request + +# read-write repo token +# access to secrets +on: + workflow_run: + workflows: ["Receive"] + types: + - completed + +jobs: + pitest-update-pr: + if: ${{ github.event.workflow_run.conclusion == 'success' }} + runs-on: ubuntu-latest + steps: + - name: debug + uses: hmarr/debug-action@v2 + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: 11 + - name: Download artifact + uses: dawidd6/action-download-artifact@v2 + with: + workflow: ${{ github.event.workflow_run.workflow_id }} + name: pitest + path: target/pit-reports-ci + workflow_conclusion: success + - name: update pull request + # The updatePR maven goal is used here with an explicit version. This allows us to upload without checking out + # the code, but does mean the version here must be maintained. An alternative would be to checkout the code and use + # the github goal. This will work as long as the artifact is extracted to the maven target directory + run: mvn -Ppitest -DrepoToken=${{ secrets.GITHUB_TOKEN }} com.groupcdg:pitest-github-maven-plugin:0.0.10:updatePR diff --git a/.gitignore b/.gitignore index f64944915f3..bc6eab1bfd3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,8 @@ out /expected.txt #jEnv configuration .java-version -/bin/ /dependency-reduced-pom.xml /bin/ .mvn/wrapper/maven-wrapper.jar +# macOS specific files +.DS_Store diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java old mode 100755 new mode 100644 diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties old mode 100755 new mode 100644 index 642d572ce90..ffdc10e59f8 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,2 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 12512a2e4ac..75e3ae94ad6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,6 +5,7 @@ Thank you for your interest in contributing to AssertJ! We appreciate your effort and to make sure that your pull request is easy to review, we ask you to note the following guidelines including legal contributor agreement: +* Use JDK 11 or newer to build the project * Use **[AssertJ code Eclipse formatting preferences](src/ide-support/assertj-eclipse-formatter.xml)** (for IntelliJ IDEA users, you can import it with the 'Eclipse Code Formatter' Plugin) * Write complete Javadocs for each assertion method and include a code example (succeeding and failing assertion(s)). * As we use JUnit 5, favor `package-private` visibility for both test classes and test methods. @@ -12,15 +13,14 @@ We appreciate your effort and to make sure that your pull request is easy to rev * Use `@DisplayName` on the test class - see `OptionalAssert_containsInstanceOf_Test` as an example. * Write unit test assertions with AssertJ! Let's eat our own dog food. * Unit tests method naming convention is underscore-based (like python) and not camel-case, we find it is much readable for long test names! -* Successful assertion unit test method names should start with: `should_pass_...`. -* Failing assertion unit test method names should start with: `should_fail_...`. - -* Put GIVEN WHEN THEN steps in each test, favoring `BDDAssertions.then` instead of `Assertions.assertThat` for assertions in the THEN step. Steps can be combined or omitted if a separate step does not provide much benefit to test readability, just ensure that the WHEN step (either single or combined) contains the test target. -* Use `AssertionUtil.expectAssertionError` for tests expecting to get an `AssertionError` - see `OptionalAssert_containsInstanceOf_Test` as an example.. +* Successful assertion unit test method names should start with: `should_pass_xxx` (if you find a better test name, use your best judgment and go for it!) +* Failing assertion unit test method names should start with: `should_fail_xxx`. (if you find a better test name, use your best judgment and go for it!) +* Put `GIVEN` `WHEN` `THEN` steps in each test, prefer `BDDAssertions.then` over `Assertions.assertThat` for assertions in the `THEN` step. Steps can be combined or omitted if a separate step does not provide much benefit to test readability, just ensure that the WHEN step (either single or combined) contains the test target. +* Use `AssertionUtil.expectAssertionError` for tests expecting to get an `AssertionError` - see `OptionalAssert_containsInstanceOf_Test` below for an example. * Use static import when it makes the code more readable. * If possible, add a (fun) code example in [assertj-examples](https://github.com/assertj/assertj-examples) and use it in the javadoc. -A good unit test to use as a reference is `OptionalAssert_containsInstanceOf_Test`. Here's a sample below: +A good unit test to use as a reference is `OptionalAssert_containsInstanceOf_Test`, here's a sample below: ```java import static org.assertj.core.api.BDDAssertions.then; @@ -51,13 +51,13 @@ class OptionalAssert_containsInstanceOf_Test extends BaseTest { } ``` -It's ok not to follow some of the rules described above if you have a good reason not to (use your best judgement) +It's ok not to follow some rules described above if you have a good reason not to (use your best judgement) -[assertj-examples](https://github.com/assertj/assertj-examples) shows how to efficiently use AssertJ through fun unit test examples, it can be seen as AssertJs living documentation. +[assertj-examples](https://github.com/assertj/assertj-examples) shows how to efficiently use AssertJ through fun unit test examples, it is a kind of living documentation. ## Rebase your PR on main (no merge!) -We prefer integrating PR by squashing all the commits and rebase it to main, if you PR has diverged and needs to integrate with main, please rebase on main but do not merge as it will prevent rebasing later on. +We prefer integrating PR by squashing all the commits and rebase it to `main`, if your PR has diverged and needs to get the newer `main` commits, please rebase on `main` but **do not merge `main` in your PR branch** as it will prevent rebasing later on. ## Naming conventions with some examples: @@ -102,6 +102,26 @@ A good javadoc example taken from [`AbstractCharSequenceAssert.containsSequence` */ ``` +Note that to get a good HTML rendering for the code examples, the code should start at the same line and one space after `
`.
+
+Good:
+```text
+ * String book = "{ 'title':'A Game of Thrones', 'author':'George Martin'}";
+```
+
+BAD! (missing space)
+```text
+ * String book = "{ 'title':'A Game of Thrones', 'author':'George Martin'}";
+```
+
+BAD! (not in the same line)
+```text
+ *
+ * String book = "{ 'title':'A Game of Thrones', 'author':'George Martin'}";
+```
+
+To be sure of what the javadoc actually looks, simply generate it and read it in your browser.
+
## Legal stuff:
Project license(s): Apache License Version 2.0
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
index bfa9253c0e7..8862e1eec97 100644
--- a/PULL_REQUEST_TEMPLATE.md
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -1,6 +1,7 @@
#### Check List:
-* Fixes #???
+* Fixes #??? (ignore if not applicable)
* Unit tests : YES / NO / NA
* Javadoc with a code example (on API only) : YES / NO / NA
+* PR meets the [contributing guidelines](https://github.com/assertj/assertj-core/blob/main/CONTRIBUTING.md)
-
+Following the [contributing guidelines](https://github.com/assertj/assertj-core/blob/main/CONTRIBUTING.md) will make it easier for us to review and accept your PR.
diff --git a/README.md b/README.md
index 5987fa00850..a3739095b67 100644
--- a/README.md
+++ b/README.md
@@ -9,63 +9,36 @@
AssertJ provides a rich and intuitive set of strongly-typed assertions to use for unit testing (with JUnit, TestNG or any other test framework).
* [AssertJ's goals](#goals)
-* [Quick start](#quickstart)
-* [Latest News](#news)
-* AssertJ web site contains the [**AssertJ Core documentation**](https://assertj.github.io/doc/#assertj-core-assertions-guide).
-* [Assertions for custom types](http://joel-costigliola.github.io/assertj/assertj-core-custom-assertions.html) (still in the old site but will soon be available in the [new site](https://assertj.github.io/doc/#overview))
-* [Replacing JUnit assertions with AssertJ Assertions](#junit-to-assertj-assertions)
+* [Quick start](https://assertj.github.io/doc/#assertj-core-quick-start)
+* [Latest releases](https://assertj.github.io/doc/#assertj-core-release-notes)
+* [Documentation](https://assertj.github.io/doc/#assertj-core)
* [Contributing](#contributing)
-
You can ask questions in [**stackoverflow (assertj tag)**](https://stackoverflow.com/questions/tagged/assertj?mixed=1) and make suggestions by simply creating an issue.
-## AssertJ's goals
+## AssertJ's goals
AssertJ's ambition is to provide a rich and intuitive set of strongly-typed assertions for unit testing.
-The idea is that disposal assertions should be specific to the type of the objects we are checking when writing unit tests. If you're checking the value of a `String`, you use String-specific assertions. Checking the value of
-a `Map`? Use Map-specific assertions to easily check the contents of the map.
+The idea is that disposal assertions should be specific to the type of the objects we are checking when writing unit tests. If you're checking the value of a `String`, you use String-specific assertions. Checking the value of a `Map`? Use Map-specific assertions to easily check the contents of the map.
+
+AssertJ's assertions are super easy to use: just type **`assertThat(underTest).`** and use code completion to show you all assertions available.
+
+Assertion missing? Please [create an issue](https://github.com/assertj/assertj-core/issues) to discuss it and even better [contribute to the project](https://github.com/assertj/assertj-core/blob/main/CONTRIBUTING.md)!
+
AssertJ is composed of several modules:
* A core module (this one) to provide assertions for JDK types (`String`, `Iterable`, `Stream`, `Path`, `File`, `Map`...) - see [AssertJ Core documentation](https://assertj.github.io/doc/#assertj-core-assertions-guide) and [javadoc](https://www.javadoc.io/doc/org.assertj/assertj-core/latest/index.html).
-* A **[Guava module](https://github.com/assertj/assertj-guava#readme)** to provide assertions for Guava types (`Multimap`, `Optional`...) - see [AssertJ Guava documentation](https://assertj.github.io/doc/#assertj-guava) and [javadoc](https://www.javadoc.io/doc/org.assertj/assertj-guava/latest/index.html).
+* A **[Guava module](https://github.com/assertj/assertj-guava#readme)** to provide assertions for Guava types (`Multimap`, `Optional`...) - see [AssertJ Guava documentation](https://assertj.github.io/doc/#assertj-guava) and [javadoc](https://www.javadoc.io/doc/org.assertj/assertj-guava/latest/index.html).
* A **[Joda Time module](https://github.com/assertj/assertj-joda-time#readme)** to provide assertions for Joda Time types (`DateTime`, `LocalDateTime`) - see [AssertJ Joda Time documentation](http://joel-costigliola.github.io/assertj/assertj-joda-time.html) and [javadoc](https://www.javadoc.io/doc/org.assertj/assertj-joda-time/latest/index.html).
* A **[Neo4J module](https://github.com/assertj/assertj-neo4j#readme)** to provide assertions for Neo4J types (`Path`, `Node`, `Relationship`...) - see [AssertJ Neo4J documentation](http://joel-costigliola.github.io/assertj/assertj-neo4j.html) and [javadoc](https://www.javadoc.io/doc/org.assertj/assertj-neo4j/latest/index.html).
* A **[DB module](https://github.com/assertj/assertj-db#readme)** to provide assertions for relational database types (`Table`, `Row`, `Column`...) - see [AssertJ DB documentation](https://assertj.github.io/doc/#assertj-db) and [javadoc](https://www.javadoc.io/doc/org.assertj/assertj-db/latest/index.html).
* A **[Swing module](https://github.com/assertj/assertj-swing#readme)** provides a simple and intuitive API for functional testing of Swing user interfaces - see [AssertJ Swing documentation](http://joel-costigliola.github.io/assertj/assertj-swing.html) and [javadoc](https://www.javadoc.io/doc/org.assertj/assertj-swing/latest/index.html).
-Assertion missing? Please [create an issue](https://github.com/assertj/assertj-core/issues)!
-
-AssertJ's assertions are super easy to use: just type **```assertThat```** followed by the actual value in parentheses and a dot,
-then any Java IDE will show you all assertions available for the type of the object. No more confusion about the
-order of "expected" and "actual" value.
-
-AssertJ's assertions are very close to plain English.
-
-A lot of effort has been spent to provide intuitive failure messages showing clearly why the assertion failed.
-
-Note that AssertJ 3.x requires at least Java 8 and AssertJ 2.x requires at least Java 7.
-
-## Quickstart
-
-It is easy to start using AssertJ, just follow the [**one minute starting guide**](https://assertj.github.io/doc/#assertj-core-quick-start).
-
-## Latest News
-
-To read details on the latest releases, please go to [**AssertJ Core latest news**](https://assertj.github.io/doc/#assertj-core).
-
-## Assertions for custom types
-
-Having assertions for common types like `List` is great, but you might want some assertions specific to your own types. It is simple to [write assertions for your custom types](http://joel-costigliola.github.io/assertj/assertj-core-custom-assertions.html) with AssertJ because it is easily extensible.
-
-Moreover, to ease your work, we provide assertions generator that can take a set of custom types and create specific assertions. The tools provided are:
-* A **[CLI assertions generator](http://joel-costigliola.github.io/assertj/assertj-assertions-generator.html)**
-* A **[Maven plugin assertions generator](http://joel-costigliola.github.io/assertj/assertj-assertions-generator-maven-plugin.html)**
-## Replacing JUnit assertions with AssertJ Assertions
-To help you [**replace JUnit assertions**](https://assertj.github.io/doc/#assertj-migration) with AssertJ ones, you can use a [**script**](https://assertj.github.io/doc/#assertj-migration-using-scripts) or do regexp search and replace manually as described [**here**](https://assertj.github.io/doc/#assertj-migration-using-regexes).
+## Want to contribute?
-## Want to contribute?
+You are encouraged to contribute any missing useful assertions.
-You are encouraged to contribute any missing, useful assertions. To do so, please read the [contributing section](https://github.com/assertj/assertj-core/blob/main/CONTRIBUTING.md).
+Please read the [contributing section](https://github.com/assertj/assertj-core/blob/main/CONTRIBUTING.md) and raise a PR!
diff --git a/cdg-pitest-licence.txt b/cdg-pitest-licence.txt
new file mode 100644
index 00000000000..b78b9a825c6
--- /dev/null
+++ b/cdg-pitest-licence.txt
@@ -0,0 +1,7 @@
+#Licence file for pitest git plugin
+#Tue May 04 09:26:47 BST 2021
+expires=04/05/2023
+keyVersion=1
+signature=D1RXTdu1ITmJhlRqssvVts6xi5xeyobnq4QCOeLHRuggH1sk4FECLCMPXPtAe0mkUPFI3kuioxmQcnGpm4Xol/Q3YnhI3bKZWjNNgl1XdW3SiGzKqYg/mzwXZeWPPSBQ5pl3Bf0SvcvcZaQaLzAWtgRtjRWqyuBGegASqDOqwGc\=
+packages=org.assertj.*
+type=OSSS
diff --git a/mvnw.cmd b/mvnw.cmd
old mode 100755
new mode 100644
diff --git a/pom.xml b/pom.xml
index 447916d84ca..3a958507fbb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
assertj-core
- 3.19.0
+ 3.20.0
jar
AssertJ fluent assertions
Rich and fluent assertions for testing for Java
@@ -16,7 +16,7 @@
scm:git:git@github.com:assertj/assertj-core.git
scm:git:git@github.com:assertj/assertj-core.git
git@github.com:assertj/assertj-core
- assertj-core-3.19.0
+ assertj-core-3.20.0
github
@@ -25,15 +25,16 @@
-html5 --allow-script-in-comments --no-module-directories
- 1.10.19
+ 1.11.2
1.2.0
- 5.2.0
+ 5.3.0
- 4.13.1
- 5.6.3
- 3.7.7
+ 4.13.2
+ 5.7.2
+ 3.11.1
- 0.8.6
+ 0.8.7
+ 0.0.10
@@ -132,7 +133,7 @@
com.fasterxml.jackson.core
jackson-databind
- 2.12.1
+ 2.12.3
test
@@ -233,6 +262,7 @@
+ bytebuddy
package
shade
@@ -559,7 +589,7 @@
org.apache.maven.plugins
maven-invoker-plugin
- 3.2.1
+ 3.2.2
${project.build.directory}/it
src/it/settings.xml
@@ -579,9 +609,36 @@
+
+ org.pitest
+ pitest-maven
+ 1.6.7
+
+
+ org.pitest
+ pitest-junit5-plugin
+ 0.14
+
+
+ com.groupcdg
+ pitest-git-plugin
+ ${cdg.pitest.version}
+
+
+
+ 3
+ false
+ false
+
+
+
+ org.sonarsource.scanner.maven
+ sonar-maven-plugin
+ 3.9.0.2155
+
net.alchim31.maven
yuicompressor-maven-plugin
@@ -617,43 +674,6 @@
-
- java9+
-
- [9,)
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
-
- jdk9
-
- compile
-
-
- 9
-
- ${project.basedir}/src/main/java9
-
- ${project.build.outputDirectory}/META-INF/versions/9
-
- --patch-module
- org.assertj.core=${project.build.outputDirectory}
- --module-version
- ${project.version}
-
-
-
-
-
-
-
-
-
java13+
@@ -669,9 +689,39 @@
[16,)
- -Dnet.bytebuddy.experimental=true --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.math=ALL-UNNAMED --add-opens=java.base/sun.nio.fs=ALL-UNNAMED
+ -Dnet.bytebuddy.experimental=true --add-opens=java.base/java.lang=ALL-UNNAMED
+ --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.math=ALL-UNNAMED
+ --add-opens=java.base/sun.nio.fs=ALL-UNNAMED
+
+ pitest
+
+
+
+ org.pitest
+ pitest-maven
+
+
+ pitest
+ test-compile
+
+ mutationCoverage
+
+
+
+
+
+
+ com.groupcdg
+ pitest-git-maven-plugin
+ ${cdg.pitest.version}
+
+
+
+
diff --git a/src/main/java/org/assertj/core/api/AbstractArrayAssert.java b/src/main/java/org/assertj/core/api/AbstractArrayAssert.java
index c07d99d3a0f..d22927240cd 100644
--- a/src/main/java/org/assertj/core/api/AbstractArrayAssert.java
+++ b/src/main/java/org/assertj/core/api/AbstractArrayAssert.java
@@ -32,7 +32,7 @@ protected AbstractArrayAssert(final ACTUAL actual, final Class> selfType) {
}
static void requireNonNullParameter(Object parameter, String parameterName) {
- requireNonNull(parameter, shouldNotBeNull(parameterName).create());
+ requireNonNull(parameter, shouldNotBeNull(parameterName)::create);
}
}
diff --git a/src/main/java/org/assertj/core/api/AbstractAssert.java b/src/main/java/org/assertj/core/api/AbstractAssert.java
index c133a6180f6..dfa42db1708 100644
--- a/src/main/java/org/assertj/core/api/AbstractAssert.java
+++ b/src/main/java/org/assertj/core/api/AbstractAssert.java
@@ -82,13 +82,15 @@ public abstract class AbstractAssert,
protected final ACTUAL actual;
protected final SELF myself;
+ @VisibleForTesting
// = ConfigurationProvider.CONFIGURATION_PROVIDER.representation(); ?
- private static Representation customRepresentation = null;
+ static Representation customRepresentation = null;
@VisibleForTesting
AssertionErrorCreator assertionErrorCreator;
- private static boolean printAssertionsDescription;
+ @VisibleForTesting
+ static boolean printAssertionsDescription;
private static Consumer descriptionConsumer;
@@ -462,7 +464,7 @@ public SELF satisfies(Condition super ACTUAL> condition) {
@Override
@CheckReturnValue
public > ASSERT asInstanceOf(InstanceOfAssertFactory, ASSERT> instanceOfAssertFactory) {
- requireNonNull(instanceOfAssertFactory, shouldNotBeNull("instanceOfAssertFactory").create());
+ requireNonNull(instanceOfAssertFactory, shouldNotBeNull("instanceOfAssertFactory")::create);
objects.assertIsInstanceOf(info, actual, instanceOfAssertFactory.getType());
return (ASSERT) instanceOfAssertFactory.createAssert(actual).withAssertionState(myself);
}
@@ -834,107 +836,30 @@ public SELF satisfies(Consumer requirements) {
*
* Consumer<TolkienCharacter> isHobbit = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(HOBBIT);
* Consumer<TolkienCharacter> isElf = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(ELF);
+ * Consumer<TolkienCharacter> isDwarf = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(DWARF);
*
* // assertion succeeds:
- * assertThat(frodo).satisfiesAnyOf(isElf, isHobbit);
- *
- * // assertion fails:
- * TolkienCharacter boromir = new TolkienCharacter("Boromir", MAN);
- * assertThat(boromir).satisfiesAnyOf(isHobbit, isElf);
- *
- * @param assertions1 the first group of assertions to run against the object under test - must not be null.
- * @param assertions2 the second group of assertions to run against the object under test - must not be null.
- * @return this assertion object.
- *
- * @throws IllegalArgumentException if any given assertions group is null
- * @since 3.12.0
- */
- // Does not take a Consumer... to avoid to use @SafeVarargs to suppress the generic array type safety warning.
- // @SafeVarargs requires methods to be final which breaks the proxying mechanism used by soft assertions and assumptions
- public SELF satisfiesAnyOf(Consumer assertions1, Consumer assertions2) {
- return satisfiesAnyOfAssertionsGroups(assertions1, assertions2);
- }
-
- /**
- * Verifies that the actual object under test satisfies at least one of the given assertions group expressed as {@link Consumer}s.
- *
- * This allows users to perform OR like assertions since only one the assertions group has to be met.
- *
- * {@link #overridingErrorMessage(String, Object...) Overriding error message} is not supported as it would prevent from
- * getting the error messages of the failing assertions, these are valuable to figure out what went wrong.
- * Describing the assertion is supported (for example with {@link #as(String, Object...)}).
- *
- * Example:
- *
TolkienCharacter frodo = new TolkienCharacter("Frodo", HOBBIT);
- *
- * Consumer<TolkienCharacter> isHobbit = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(HOBBIT);
- * Consumer<TolkienCharacter> isElf = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(ELF);
- * Consumer<TolkienCharacter> isOrc = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(ORC);
- *
- * // assertion succeeds:
- * assertThat(frodo).satisfiesAnyOf(isElf, isHobbit, isOrc);
+ * assertThat(frodo).satisfiesAnyOf(isElf, isHobbit, isDwarf);
*
* // assertion fails:
* TolkienCharacter boromir = new TolkienCharacter("Boromir", MAN);
- * assertThat(boromir).satisfiesAnyOf(isHobbit, isElf, isOrc);
+ * assertThat(boromir).satisfiesAnyOf(isHobbit, isElf, isDwarf);
*
- * @param assertions1 the first group of assertions to run against the object under test - must not be null.
- * @param assertions2 the second group of assertions to run against the object under test - must not be null.
- * @param assertions3 the third group of assertions to run against the object under test - must not be null.
+ * @param assertions the group of assertions to run against the object under test - must not be null.
* @return this assertion object.
*
* @throws IllegalArgumentException if any given assertions group is null
* @since 3.12.0
*/
- // Does not take a Consumer... to avoid to use @SafeVarargs to suppress the generic array type safety warning.
- // @SafeVarargs requires methods to be final which breaks the proxying mechanism used by soft assertions and assumptions
- public SELF satisfiesAnyOf(Consumer assertions1, Consumer assertions2, Consumer assertions3) {
- return satisfiesAnyOfAssertionsGroups(assertions1, assertions2, assertions3);
- }
-
- /**
- * Verifies that the actual object under test satisfies at least one of the given assertions group expressed as {@link Consumer}s.
- *
- * This allows users to perform OR like assertions since only one the assertions group has to be met.
- *
- * {@link #overridingErrorMessage(String, Object...) Overriding error message} is not supported as it would prevent from
- * getting the error messages of the failing assertions, these are valuable to figure out what went wrong.
- * Describing the assertion is supported (for example with {@link #as(String, Object...)}).
- *
- * Example:
- *
TolkienCharacter smaug = new TolkienCharacter("Smaug", DRAGON);
- *
- * Consumer<TolkienCharacter> isHobbit = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(HOBBIT);
- * Consumer<TolkienCharacter> isElf = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(ELF);
- * Consumer<TolkienCharacter> isOrc = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(ORC);
- * Consumer<TolkienCharacter> isDragon = tolkienCharacter -> assertThat(tolkienCharacter.getRace()).isEqualTo(DRAGON);
- *
- * // assertion succeeds:
- * assertThat(smaug).satisfiesAnyOf(isElf, isHobbit, isOrc, isDragon);
- *
- * // assertion fails:
- * TolkienCharacter boromir = new TolkienCharacter("Boromir", MAN);
- * assertThat(boromir).satisfiesAnyOf(isHobbit, isElf, isOrc, isDragon);
- *
- * @param assertions1 the first group of assertions to run against the object under test - must not be null.
- * @param assertions2 the second group of assertions to run against the object under test - must not be null.
- * @param assertions3 the third group of assertions to run against the object under test - must not be null.
- * @param assertions4 the third group of assertions to run against the object under test - must not be null.
- * @return this assertion object.
- *
- * @throws IllegalArgumentException if any given assertions group is null
- * @since 3.16.0
- */
- // Does not take a Consumer... to avoid to use @SafeVarargs to suppress the generic array type safety warning.
- // @SafeVarargs requires methods to be final which breaks the proxying mechanism used by soft assertions and assumptions
- public SELF satisfiesAnyOf(Consumer assertions1, Consumer assertions2, Consumer assertions3,
- Consumer assertions4) {
- return satisfiesAnyOfAssertionsGroups(assertions1, assertions2, assertions3, assertions4);
+ @SafeVarargs
+ public final SELF satisfiesAnyOf(Consumer... assertions) {
+ return satisfiesAnyOfForProxy(assertions);
}
- // can be final as it is not proxied
- @SafeVarargs
- private final SELF satisfiesAnyOfAssertionsGroups(Consumer... assertionsGroups) throws AssertionError {
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF satisfiesAnyOfForProxy(Consumer[] assertionsGroups) throws AssertionError {
checkArgument(stream(assertionsGroups).allMatch(java.util.Objects::nonNull), "No assertions group should be null");
if (stream(assertionsGroups).anyMatch(this::satisfiesAssertions)) return myself;
// none of the assertions group was met! let's report all the errors
@@ -950,7 +875,7 @@ private AssertionError multipleAssertionsError(List assertionErr
private boolean satisfiesAssertions(Consumer assertions) {
try {
assertions.accept(actual);
- } catch (AssertionError e) {
+ } catch (@SuppressWarnings("unused") AssertionError e) {
return false;
}
return true;
@@ -1000,15 +925,12 @@ public SELF doesNotHaveSameHashCodeAs(Object other) {
}
/**
- * Create a {@link AbstractListAssert}.
- *
- * Implementations need to redefine either to be proxy friendly (i.e. no final assertion methods like {@link ProxyableListAssert})
- * or generic vararg friendly (to use {@link SafeVarargs} annotation which requires final method)like {@link ListAssert}.
+ * Create a {@link AbstractListAssert} from the given list.
*
- * The default implementation will assume that this concrete implementation is NOT a soft assertion.
+ * this method avoids code duplication when features like extracting/asList need to create a new list assertions.
*
* @param the type of elements.
- * @param newActual new value
+ * @param newActual new list under test
* @return a new {@link AbstractListAssert}.
*/
protected AbstractListAssert, List extends E>, E, ObjectAssert> newListAssertInstance(List extends E> newActual) {
@@ -1063,8 +985,8 @@ protected RecursiveComparisonAssert> usingRecursiveComparison() {
@CheckReturnValue
protected > ASSERT extracting(String propertyOrField,
AssertFactory
*
* @return this assertion object.
- * @throws AssertionError if the actual value doesn't represent the positive infinity nor negative infinity.
+ * @throws AssertionError if the actual value represents neither positive infinity nor negative infinity.
* @throws AssertionError if the actual value is null.
+ * @see #isNotInfinite()
+ * @see #isFinite()
+ * @see #isNaN()
+ * @see java.lang.Float#isInfinite(float)
* @since 3.19.0
*/
@Override
@@ -919,4 +955,31 @@ public SELF isInfinite() {
floats.assertIsInfinite(info, actual);
return myself;
}
+
+ /**
+ * Verifies that the float value represents neither positive infinity nor negative infinity.
+ *
+ * Examples:
+ *
// assertions succeed
+ * assertThat(1.0f).isNotInfinite();
+ * assertThat(Float.NaN).isNotInfinite();
+ *
+ * // assertions fail
+ * assertThat(Float.POSITIVE_INFINITY).isNotInfinite();
+ * assertThat(Float.NEGATIVE_INFINITY).isNotInfinite();
+ *
+ * @return this assertion object.
+ * @throws AssertionError if the actual value represents positive infinity or negative infinity.
+ * @throws AssertionError if the actual value is null.
+ * @see #isInfinite()
+ * @see #isFinite()
+ * @see #isNaN()
+ * @see java.lang.Float#isInfinite(float)
+ * @since 3.20.0
+ */
+ @Override
+ public SELF isNotInfinite() {
+ floats.assertIsNotInfinite(info, actual);
+ return myself;
+ }
}
diff --git a/src/main/java/org/assertj/core/api/AbstractInputStreamAssert.java b/src/main/java/org/assertj/core/api/AbstractInputStreamAssert.java
index 207eb715532..295c29cd32e 100644
--- a/src/main/java/org/assertj/core/api/AbstractInputStreamAssert.java
+++ b/src/main/java/org/assertj/core/api/AbstractInputStreamAssert.java
@@ -12,11 +12,18 @@
*/
package org.assertj.core.api;
+import static java.util.Objects.requireNonNull;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.InputStream;
+import java.nio.charset.Charset;
import java.security.MessageDigest;
import org.assertj.core.internal.InputStreams;
import org.assertj.core.internal.InputStreamsException;
+import org.assertj.core.util.CheckReturnValue;
import org.assertj.core.util.VisibleForTesting;
/**
@@ -28,6 +35,7 @@
*
* @author Matthieu Baechler
* @author Mikhail Mazursky
+ * @author Stefan Birkner
*/
public abstract class AbstractInputStreamAssert, ACTUAL extends InputStream>
extends AbstractAssert {
@@ -39,6 +47,36 @@ protected AbstractInputStreamAssert(ACTUAL actual, Class> selfType) {
super(actual, selfType);
}
+ /**
+ * Converts the content of the actual {@link InputStream} to a {@link String} by decoding its bytes using the given charset
+ * and returns assertions for the computed String allowing String specific assertions from this call.
+ *
+ * Example :
+ *
InputStream abcInputStream = new ByteArrayInputStream("abc".getBytes());
+ *
+ * // assertion succeeds
+ * assertThat(abcInputStream).asString(UTF_8)
+ * .startsWith("a");
+ *
+ * // assertion fails
+ * assertThat(abcInputStream).asString(UTF_8)
+ * .startsWith("e");
+ *
+ * @param charset the {@link Charset} to interpret the {@code InputStream}'s content to a String
+ * @return a string assertion object.
+ * @throws NullPointerException if the given {@code Charset} is {@code null}.
+ * @throws AssertionError if the actual {@code InputStream} is {@code null}.
+ * @throws InputStreamsException if an I/O error occurs.
+ * @since 3.20.0
+ */
+ @CheckReturnValue
+ public AbstractStringAssert> asString(Charset charset) {
+ requireNonNull(charset, "The charset for converting to a String must not be null");
+ objects.assertNotNull(info, actual);
+ String actualAsString = readString(charset);
+ return assertThat(actualAsString);
+ }
+
/**
* Verifies that the content of the actual {@code InputStream} is equal to the content of the given one.
*
@@ -298,4 +336,19 @@ public SELF hasDigest(String algorithm, String expected) {
inputStreams.assertHasDigest(info, actual, algorithm, expected);
return myself;
}
+
+ private String readString(Charset charset) {
+ try {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ int read;
+ byte[] data = new byte[1024];
+ while ((read = actual.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, read);
+ }
+ buffer.flush();
+ return new String(buffer.toByteArray(), charset);
+ } catch (IOException e) {
+ throw new InputStreamsException("Unable to read contents of InputStreams actual", e);
+ }
+ }
}
diff --git a/src/main/java/org/assertj/core/api/AbstractIterableAssert.java b/src/main/java/org/assertj/core/api/AbstractIterableAssert.java
index 61851834e7e..0e92b8c8887 100644
--- a/src/main/java/org/assertj/core/api/AbstractIterableAssert.java
+++ b/src/main/java/org/assertj/core/api/AbstractIterableAssert.java
@@ -69,7 +69,6 @@
import org.assertj.core.internal.ObjectArrays;
import org.assertj.core.internal.Objects;
import org.assertj.core.internal.OnFieldsComparator;
-import org.assertj.core.internal.RecursiveFieldByFieldComparator;
import org.assertj.core.internal.TypeComparators;
import org.assertj.core.presentation.PredicateDescription;
import org.assertj.core.util.CheckReturnValue;
@@ -100,6 +99,8 @@
* @author Marko Bekhta
*/
//@format:off
+// suppression of deprecation works in Eclipse to hide warning for the deprecated classes in the imports
+@SuppressWarnings("deprecation")
public abstract class AbstractIterableAssert,
ACTUAL extends Iterable extends ELEMENT>,
ELEMENT,
@@ -345,7 +346,15 @@ public SELF hasSameSizeAs(Iterable> other) {
* {@inheritDoc}
*/
@Override
- public SELF contains(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF contains(ELEMENT... values) {
+ return containsForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsForProxy(ELEMENT[] values) {
iterables.assertContains(info, actual, values);
return myself;
}
@@ -354,7 +363,15 @@ public SELF contains(@SuppressWarnings("unchecked") ELEMENT... values) {
* {@inheritDoc}
*/
@Override
- public SELF containsOnly(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF containsOnly(ELEMENT... values) {
+ return containsOnlyForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsOnlyForProxy(ELEMENT[] values) {
iterables.assertContainsOnly(info, actual, values);
return myself;
}
@@ -363,7 +380,15 @@ public SELF containsOnly(@SuppressWarnings("unchecked") ELEMENT... values) {
* {@inheritDoc}
*/
@Override
- public SELF containsOnlyOnce(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF containsOnlyOnce(ELEMENT... values) {
+ return containsOnlyOnceForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsOnlyOnceForProxy(ELEMENT[] values) {
iterables.assertContainsOnlyOnce(info, actual, values);
return myself;
}
@@ -381,14 +406,30 @@ public SELF containsOnlyNulls() {
* {@inheritDoc}
*/
@Override
- public SELF containsExactly(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF containsExactly(ELEMENT... values) {
+ return containsExactlyForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsExactlyForProxy(ELEMENT[] values) {
iterables.assertContainsExactly(info, actual, values);
return myself;
}
/** {@inheritDoc} */
@Override
- public SELF containsExactlyInAnyOrder(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF containsExactlyInAnyOrder(ELEMENT... values) {
+ return containsExactlyInAnyOrderForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsExactlyInAnyOrderForProxy(ELEMENT[] values) {
iterables.assertContainsExactlyInAnyOrder(info, actual, values);
return myself;
}
@@ -414,7 +455,15 @@ public SELF isSubsetOf(Iterable extends ELEMENT> values) {
* {@inheritDoc}
*/
@Override
- public SELF isSubsetOf(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF isSubsetOf(ELEMENT... values) {
+ return isSubsetOfForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF isSubsetOfForProxy(ELEMENT[] values) {
iterables.assertIsSubsetOf(info, actual, Arrays.asList(values));
return myself;
}
@@ -423,7 +472,15 @@ public SELF isSubsetOf(@SuppressWarnings("unchecked") ELEMENT... values) {
* {@inheritDoc}
*/
@Override
- public SELF containsSequence(@SuppressWarnings("unchecked") ELEMENT... sequence) {
+ @SafeVarargs
+ public final SELF containsSequence(ELEMENT... sequence) {
+ return containsSequenceForProxy(sequence);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsSequenceForProxy(ELEMENT[] sequence) {
iterables.assertContainsSequence(info, actual, sequence);
return myself;
}
@@ -442,7 +499,15 @@ public SELF containsSequence(Iterable extends ELEMENT> sequence) {
* {@inheritDoc}
*/
@Override
- public SELF doesNotContainSequence(@SuppressWarnings("unchecked") ELEMENT... sequence) {
+ @SafeVarargs
+ public final SELF doesNotContainSequence(ELEMENT... sequence) {
+ return doesNotContainSequenceForProxy(sequence);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF doesNotContainSequenceForProxy(ELEMENT[] sequence) {
iterables.assertDoesNotContainSequence(info, actual, sequence);
return myself;
}
@@ -461,7 +526,15 @@ public SELF doesNotContainSequence(Iterable extends ELEMENT> sequence) {
* {@inheritDoc}
*/
@Override
- public SELF containsSubsequence(@SuppressWarnings("unchecked") ELEMENT... subsequence) {
+ @SafeVarargs
+ public final SELF containsSubsequence(ELEMENT... subsequence) {
+ return containsSubsequenceForProxy(subsequence);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsSubsequenceForProxy(ELEMENT[] subsequence) {
iterables.assertContainsSubsequence(info, actual, subsequence);
return myself;
}
@@ -480,7 +553,15 @@ public SELF containsSubsequence(Iterable extends ELEMENT> subsequence) {
* {@inheritDoc}
*/
@Override
- public SELF doesNotContainSubsequence(@SuppressWarnings("unchecked") ELEMENT... subsequence) {
+ @SafeVarargs
+ public final SELF doesNotContainSubsequence(ELEMENT... subsequence) {
+ return doesNotContainSubsequenceForProxy(subsequence);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF doesNotContainSubsequenceForProxy(ELEMENT[] subsequence) {
iterables.assertDoesNotContainSubsequence(info, actual, subsequence);
return myself;
}
@@ -496,7 +577,15 @@ public SELF doesNotContainSubsequence(Iterable extends ELEMENT> subsequence) {
}
@Override
- public SELF doesNotContain(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF doesNotContain(ELEMENT... values) {
+ return doesNotContainForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF doesNotContainForProxy(ELEMENT[] values) {
iterables.assertDoesNotContain(info, actual, values);
return myself;
}
@@ -520,7 +609,15 @@ public SELF doesNotHaveDuplicates() {
* {@inheritDoc}
*/
@Override
- public SELF startsWith(@SuppressWarnings("unchecked") ELEMENT... sequence) {
+ @SafeVarargs
+ public final SELF startsWith(ELEMENT... sequence) {
+ return startsWithForProxy(sequence);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF startsWithForProxy(ELEMENT[] sequence) {
iterables.assertStartsWith(info, actual, sequence);
return myself;
}
@@ -529,7 +626,15 @@ public SELF startsWith(@SuppressWarnings("unchecked") ELEMENT... sequence) {
* {@inheritDoc}
*/
@Override
- public SELF endsWith(ELEMENT first, @SuppressWarnings("unchecked") ELEMENT... rest) {
+ @SafeVarargs
+ public final SELF endsWith(ELEMENT first, ELEMENT... rest) {
+ return endsWithForProxy(first, rest);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF endsWithForProxy(ELEMENT first, ELEMENT[] rest) {
iterables.assertEndsWith(info, actual, first, rest);
return myself;
}
@@ -758,6 +863,13 @@ public SELF hasOnlyElementsOfTypes(Class>... types) {
return myself;
}
+ /** {@inheritDoc} */
+ @Override
+ public SELF hasExactlyElementsOfTypes(Class>... types) {
+ ObjectArrays.instance().assertHasExactlyElementsOfTypes(info, toArray(actual), types);
+ return myself;
+ }
+
/**
* {@inheritDoc}
*/
@@ -821,7 +933,15 @@ public SELF usingDefaultElementComparator() {
* @since 2.9.0 / 3.9.0
*/
@Override
- public SELF containsAnyOf(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF containsAnyOf(ELEMENT... values) {
+ return containsAnyOfForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsAnyOfForProxy(ELEMENT[] values) {
iterables.assertContainsAnyOf(info, actual, values);
return myself;
}
@@ -1391,8 +1511,7 @@ public AbstractListAssert, List extends V>,
/*
* Should be used after any methods changing the elements type like {@link #extracting(Function)} as it will propagate the
- * correct
- * assertions state, that is everything but the element comparator (since the element type has changed).
+ * correct assertions state, that is everything but the element comparator (since the element type has changed).
*/
private AbstractListAssert, List extends V>, V, ObjectAssert> newListAssertInstanceForMethodsChangingElementType(List values) {
if (actual instanceof SortedSet) {
@@ -1582,8 +1701,9 @@ private AbstractListAssert, List extends V>, V, ObjectAssert> doFlatE
* @return a new assertion object whose object under test is a flattened list of all extracted values.
*/
@CheckReturnValue
- public AbstractListAssert, List extends Object>, Object, ObjectAssert
*
* @return {@code this} assertion object.
+ * @deprecated This method is deprecated because it performs a shallow field by field comparison, i.e. elements are compared
+ * field by field but the fields are compared with equals, use {@link #usingRecursiveFieldByFieldElementComparator()}
+ * or {@link #usingRecursiveComparison()} instead to perform a true recursive comparison.
+ * equals method to compare group elements for incoming
- * assertion checks. This can be useful if actual's {@code equals} implementation does not suit you.
+ * Enable using a recursive field by field comparison strategy similar to {@link #usingRecursiveComparison()} but contrary to the latter you can chain any iterable assertions after this method (this is why this method exists).
* - * The recursive property/field comparison is not applied on fields having a custom {@code equals} - * implementation, i.e. the overridden {@code equals} method will be used instead of a field/property by field/property - * comparison. + * This method uses the default {@link RecursiveComparisonConfiguration}, if you need to customize it use {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)} instead. *
- * The recursive comparison handles cycles. + * Breaking change: since 3.20.0 the comparison won't use any comparators set with: + *
- * You can specify a custom comparator per (nested) name or type of element field with - * {@link #usingComparatorForElementFieldsWithNames(Comparator, String...) usingComparatorForElementFieldsWithNames} - * and {@link #usingComparatorForElementFieldsWithType(Comparator, Class) usingComparatorForElementFieldsWithType}. + * These features (and many more) are provided through {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)} with a customized {@link RecursiveComparisonConfiguration} where there methods are called: + *
- * The objects to compare can be of different types but must have the same properties/fields. For example if actual - * object has a {@code name} String field, the other object must also have one. + * There are differences between this approach and {@link #usingRecursiveComparison()}: + *
- * If an object has a field and a property with the same name, the property value will be used over the field. + * This last point makes sense, take the {@link #contains(Object...)} assertion, it would not be relevant to report the differences of all the iterable's elements differing from the values to look for. *
* Example: - *
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
- * TolkienCharacter pippin = new TolkienCharacter("Pippin", 28, HOBBIT);
- * frodo.setFriend(pippin);
- * pippin.setFriend(frodo);
+ * public class Person {
+ * String name;
+ * boolean hasPhd;
+ * }
*
- * TolkienCharacter frodoClone = new TolkienCharacter("Frodo", 33, HOBBIT);
- * TolkienCharacter pippinClone = new TolkienCharacter("Pippin", 28, HOBBIT);
- * frodoClone.setFriend(pippinClone);
- * pippinClone.setFriend(frodoClone);
+ * public class Doctor {
+ * String name;
+ * boolean hasPhd;
+ * }
+ *
+ * Doctor drSheldon = new Doctor("Sheldon Cooper", true);
+ * Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
+ * Doctor drRaj = new Doctor("Raj Koothrappali", true);
+ *
+ * Person sheldon = new Person("Sheldon Cooper", true);
+ * Person leonard = new Person("Leonard Hofstadter", true);
+ * Person raj = new Person("Raj Koothrappali", true);
+ * Person howard = new Person("Howard Wolowitz", true);
*
- * List<TolkienCharacter> hobbits = Arrays.asList(frodo, pippin);
+ * List<Doctor> doctors = list(drSheldon, drLeonard, drRaj);
+ * List<Person> people = list(sheldon, leonard, raj);
*
- * // fails if equals has not been overridden in TolkienCharacter as it would compares object references
- * assertThat(hobbits).contains(frodoClone, pippinClone);
+ * // assertion succeeds as both lists contains equivalent items in order.
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(sheldon);
*
- * // frodo/frodoClone and pippin/pippinClone are equals when doing a recursive property/field by property/field comparison
- * assertThat(hobbits).usingRecursiveFieldByFieldElementComparator()
- * .contains(frodoClone, pippinClone);
- *
+ * // assertion fails because leonard names are different.
+ * leonard.setName("Leonard Ofstater");
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(leonard);
+ *
+ * // assertion fails because howard is missing and leonard is not expected.
+ * people = list(howard, sheldon, raj)
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(howard);
+ *
+ * Another point worth mentioning: elements order does matter if the expected iterable is ordered, for example comparing a {@code Set
* Use field/property by field/property comparison on the given fields/properties only (including inherited
* fields/properties) instead of relying on actual type A
+ * Nested fields are supported and are expressed like: {@code name.first}
+ *
+ * The comparison is recursive: elements are compared field by field, if a field type has fields they are also compared
+ * field by field (and so on).
+ *
+ * Example:
+ *
+ * This method is actually a shortcut of {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)}
+ * with a configuration comparing only the given fields, the previous example can be written as:
+ *
+ * @param fields the field names to exclude in the elements comparison.
+ * @return {@code this} assertion object.
+ * @since 3.20.0
+ * @see #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
+ * @see https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ */
+ @CheckReturnValue
+ public SELF usingRecursiveFieldByFieldElementComparatorOnFields(String... fields) {
+ RecursiveComparisonConfiguration recursiveComparisonConfiguration = RecursiveComparisonConfiguration.builder()
+ .withComparedFields(fields)
+ .build();
+ return usingRecursiveFieldByFieldElementComparator(recursiveComparisonConfiguration);
+ }
+
protected SELF usingComparisonStrategy(ComparisonStrategy comparisonStrategy) {
iterables = new Iterables(comparisonStrategy);
return myself;
}
/**
+ * Deprecated javadoc
+ *
* Use field/property by field/property comparison on all fields/properties except the given ones (including inherited
* fields/properties) instead of relying on actual type A
+ * Nested fields are supported and are expressed like: {@code name.first}
+ *
+ * The comparison is recursive: elements are compared field by field, if a field type has fields they are also compared
+ * field by field (and so on).
+ *
+ * Example:
+ *
+ * This method is actually a shortcut of {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)}
+ * with a configuration ignoring the given fields, the previous example can be written as:
+ *
+ * @param fields the field names to exclude in the elements comparison.
+ * @return {@code this} assertion object.
+ * @since 3.20.0
+ * @see #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
+ * @see https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ */
+ @CheckReturnValue
+ public SELF usingRecursiveFieldByFieldElementComparatorIgnoringFields(String... fields) {
+ RecursiveComparisonConfiguration recursiveComparisonConfiguration = RecursiveComparisonConfiguration.builder()
+ .withIgnoredFields(fields)
+ .build();
+ return usingRecursiveFieldByFieldElementComparator(recursiveComparisonConfiguration);
+ }
+
/**
* Enable hexadecimal representation of Iterable elements instead of standard representation in error messages.
*
@@ -3068,6 +3377,68 @@ public ELEMENT_ASSERT element(int index) {
return internalElement(index);
}
+ /**
+ * Allow to perform assertions on the elements corresponding to the given indices
+ * (the iterable {@link Iterable} under test is changed to an iterable with the selected elements).
+ *
+ * Example:
+ *
+ *
+ * @param indices the elements indices
+ * @return the assertion on the given elements
+ * @throws IllegalArgumentException if indices array is null or empty
+ * @throws AssertionError if one of the given indices is out of bound or if the actual is empty
+ * @since 3.20
+ */
+ @CheckReturnValue
+ public SELF elements(int... indices) {
+ isNotEmpty();
+ assertIndicesIsNotNull(indices);
+ assertIndicesIsNotEmpty(indices);
+
+ List
@@ -3370,13 +3741,29 @@ public SELF noneSatisfy(Consumer super ELEMENT> restrictions) {
}
@Override
- public SELF satisfiesExactly(@SuppressWarnings("unchecked") Consumer super ELEMENT>... requirements) {
+ @SafeVarargs
+ public final SELF satisfiesExactly(Consumer super ELEMENT>... requirements) {
+ return satisfiesExactlyForProxy(requirements);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF satisfiesExactlyForProxy(Consumer super ELEMENT>[] requirements) {
iterables.assertSatisfiesExactly(info, actual, requirements);
return myself;
}
@Override
- public SELF satisfiesExactlyInAnyOrder(@SuppressWarnings("unchecked") Consumer super ELEMENT>... requirements) {
+ @SafeVarargs
+ public final SELF satisfiesExactlyInAnyOrder(Consumer super ELEMENT>... requirements) {
+ return satisfiesExactlyInAnyOrderForProxy(requirements);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF satisfiesExactlyInAnyOrderForProxy(Consumer super ELEMENT>[] requirements) {
iterables.assertSatisfiesExactlyInAnyOrder(info, actual, requirements);
return myself;
}
diff --git a/src/main/java/org/assertj/core/api/AbstractMapAssert.java b/src/main/java/org/assertj/core/api/AbstractMapAssert.java
index c426c2c073f..5250ef0b442 100644
--- a/src/main/java/org/assertj/core/api/AbstractMapAssert.java
+++ b/src/main/java/org/assertj/core/api/AbstractMapAssert.java
@@ -12,6 +12,7 @@
*/
package org.assertj.core.api;
+import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.entry;
@@ -455,23 +456,24 @@ public SELF hasSameSizeAs(Iterable> other) {
* Verifies that the actual map has the same size as the given {@link Map}.
*
* Examples:
- *
+ * The verification tries to honor the key comparison semantic of the underlying map implementation.
+ * The map under test has to be cloned to identify unexpected elements, but depending on the map implementation
+ * this may not always be possible. In case it is not possible, a regular map is used and the key comparison strategy
+ * may not be the same as the map under test.
*
* Examples :
*
+ * The verification tries to honor the key comparison semantic of the underlying map implementation.
+ * The map under test has to be cloned to identify unexpected elements, but depending on the map implementation
+ * this may not always be possible. In case it is not possible, a regular map is used and the key comparison strategy
+ * may not be the same as the map under test.
*
* Examples :
*
+ * The verification tries to honor the key comparison semantic of the underlying map implementation.
+ * The map under test has to be cloned to identify unexpected elements, but depending on the map implementation
+ * this may not always be possible. In case it is not possible, a regular map is used and the key comparison strategy
+ * may not be the same as the map under test.
*
* Examples :
*
+ * Example:
+ *
@@ -963,7 +1068,15 @@ public SELF doesNotContain(ELEMENT value, Index index) {
* @throws AssertionError if the actual array contains any of the given values.
*/
@Override
- public SELF doesNotContain(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF doesNotContain(ELEMENT... values) {
+ return doesNotContainForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF doesNotContainForProxy(ELEMENT[] values) {
arrays.assertDoesNotContain(info, actual, values);
return myself;
}
@@ -1039,7 +1152,15 @@ public SELF doesNotHaveDuplicates() {
* @throws AssertionError if the actual array does not start with the given sequence of objects.
*/
@Override
- public SELF startsWith(@SuppressWarnings("unchecked") ELEMENT... sequence) {
+ @SafeVarargs
+ public final SELF startsWith(ELEMENT... sequence) {
+ return startsWithForProxy(sequence);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF startsWithForProxy(ELEMENT[] sequence) {
arrays.assertStartsWith(info, actual, sequence);
return myself;
}
@@ -1093,7 +1214,15 @@ public SELF endsWith(ELEMENT[] sequence) {
* @throws AssertionError if the actual array does not end with the given sequence of objects.
*/
@Override
- public SELF endsWith(ELEMENT first, @SuppressWarnings("unchecked") ELEMENT... sequence) {
+ @SafeVarargs
+ public final SELF endsWith(ELEMENT first, ELEMENT... sequence) {
+ return endsWithForProxy(first, sequence);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF endsWithForProxy(ELEMENT first, ELEMENT[] sequence) {
arrays.assertEndsWith(info, actual, first, sequence);
return myself;
}
@@ -1143,7 +1272,15 @@ public SELF isSubsetOf(Iterable extends ELEMENT> values) {
* @throws AssertionError if the actual {@code Iterable} is not subset of the given values.
*/
@Override
- public SELF isSubsetOf(@SuppressWarnings("unchecked") ELEMENT... values) {
+ @SafeVarargs
+ public final SELF isSubsetOf(ELEMENT... values) {
+ return isSubsetOfForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF isSubsetOfForProxy(ELEMENT[] values) {
arrays.assertIsSubsetOf(info, actual, Arrays.asList(values));
return myself;
}
@@ -1606,6 +1743,8 @@ public SELF usingDefaultElementComparator() {
}
/**
+ * Deprecated javadoc
+ *
* Allows to set a comparator to compare properties or fields of elements with the given names.
* A typical usage is for comparing fields of numeric type at a given precision.
*
@@ -1667,7 +1806,22 @@ public SELF usingDefaultElementComparator() {
* @param elementPropertyOrFieldNames the names of the properties and/or fields of the elements the comparator should be used for
* @return {@code this} assertions object
* @since 2.5.0 / 3.5.0
+ * @deprecated This method is used with {@link #usingFieldByFieldElementComparator()} which is deprecated in favor of
+ * {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)} or {@link #usingRecursiveComparison()}.
+ *
+ * When using {@link #usingRecursiveComparison()} the equivalent is:
+ *
+ * and when using {@link RecursiveComparisonConfiguration}:
+ *
* Allows to set a specific comparator to compare properties or fields of elements with the given type.
* A typical usage is for comparing fields of numeric type at a given precision.
*
* To be used, comparators need to be specified by this method before calling any of:
*
* Comparators specified by {@link #usingComparatorForElementFieldsWithNames(Comparator, String...) usingComparatorForElementFieldsWithNames}
@@ -1746,7 +1901,22 @@ public
+ * When using {@link #usingRecursiveComparison()} the equivalent is:
+ *
+ * and when using {@link RecursiveComparisonConfiguration}:
+ *
* Usage of this method affects comparators set by the following methods:
*
* Example:
@@ -1792,6 +1961,8 @@ public
* Use field/property by field/property comparison (including inherited fields/properties) instead of relying on
* actual type A
- * The recursive property/field comparison is not applied on fields having a custom {@code equals}
- * implementation, i.e. the overridden {@code equals} method will be used instead of a field/property by field/property comparison.
+ * This method uses the default {@link RecursiveComparisonConfiguration}, if you need to customize it use {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)} instead.
*
- * You can specify a custom comparator per (nested) name or type of element field with
- * {@link #usingComparatorForElementFieldsWithNames(Comparator, String...) usingComparatorForElementFieldsWithNames}
- * and {@link #usingComparatorForElementFieldsWithType(Comparator, Class) usingComparatorForElementFieldsWithType}.
+ * Breaking change: since 3.20.0 the comparison won't use any comparators set with:
+ *
- * The recursive comparison handles cycles.
+ * These features (and many more) are provided through {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)} with a customized {@link RecursiveComparisonConfiguration} where there methods are called:
+ *
- * The objects to compare can be of different types but must have the same properties/fields. For example if actual object has a
- * {@code name} String field, the other object must also have one.
+ * There are differences between this approach and {@link #usingRecursiveComparison()}:
+ *
- * If an object has a field and a property with the same name, the property value will be used over the field.
+ * This last point makes sense, take the {@link #contains(Object...)} assertion, it would not be relevant to report the differences of all the iterable's elements differing from the values to look for.
*
* Example:
+ *
+ * Another point worth mentioning: elements order does matter if the expected iterable is ordered, for example comparing a {@code Set
+ * The given {@link RecursiveComparisonConfiguration} is used to tweak the comparison behavior, for example by {@link RecursiveComparisonConfiguration#ignoreCollectionOrder(boolean) ignoring collection order}.
+ *
+ * Warning: the comparison won't use any comparators set with:
+ *
+ * These features (and many more) are provided through {@link RecursiveComparisonConfiguration} with:
+ *
+ * RecursiveComparisonConfiguration exposes a {@link RecursiveComparisonConfiguration.Builder builder} to ease setting the comparison behaviour,
+ * call {@link RecursiveComparisonConfiguration#builder() RecursiveComparisonConfiguration.builder()} to start building your configuration.
+ *
+ * There are differences between this approach and {@link #usingRecursiveComparison()}:
+ *
+ * This last point makes sense, take the {@link #contains(Object...)} assertion, it would not be relevant to report the differences of all the iterable's elements differing from the values to look for.
+ *
+ * Example:
+ *
+ * A point worth mentioning: elements order does matter if the expected iterable is ordered, for example comparing a {@code Set
* Use field/property by field/property comparison on the given fields/properties only (including inherited
* fields/properties) instead of relying on actual type A
+ * Nested fields are supported and are expressed like: {@code name.first}
+ *
+ * The comparison is recursive: elements are compared field by field, if a field type has fields they are also compared
+ * field by field (and so on).
+ *
+ * Example:
+ *
+ * This method is actually a shortcut of {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)}
+ * with a configuration comparing only the given fields, the previous example can be written as:
+ *
+ * @param fields the field names to exclude in the elements comparison.
+ * @return {@code this} assertion object.
+ * @since 3.20.0
+ * @see #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
+ * @see https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ */
+ @CheckReturnValue
+ public SELF usingRecursiveFieldByFieldElementComparatorOnFields(String... fields) {
+ RecursiveComparisonConfiguration recursiveComparisonConfiguration = RecursiveComparisonConfiguration.builder()
+ .withComparedFields(fields)
+ .build();
+ return usingRecursiveFieldByFieldElementComparator(recursiveComparisonConfiguration);
+ }
+
+ /**
+ * Deprecated javadoc
+ *
* Use field/property by field/property on all fields/properties except the given ones (including inherited
* fields/properties) instead of relying on actual type A
+ * Nested fields are supported and are expressed like: {@code name.first}
+ *
+ * The comparison is recursive: elements are compared field by field, if a field type has fields they are also compared
+ * field by field (and so on).
+ *
+ * Example:
+ *
+ * This method is actually a shortcut of {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)}
+ * with a configuration ignoring the given fields, the previous example can be written as:
+ *
+ * @param fields the field names to exclude in the elements comparison.
+ * @return {@code this} assertion object.
+ * @since 3.20.0
+ * @see #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
+ * @see https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ */
+ @CheckReturnValue
+ public SELF usingRecursiveFieldByFieldElementComparatorIgnoringFields(String... fields) {
+ RecursiveComparisonConfiguration recursiveComparisonConfiguration = RecursiveComparisonConfiguration.builder()
+ .withIgnoredFields(fields)
+ .build();
+ return usingRecursiveFieldByFieldElementComparator(recursiveComparisonConfiguration);
+ }
+
/**
* Extract the values of given field or property from the array's elements under test into a new list, this new list
* becoming the object under test.
@@ -2234,7 +2649,15 @@ public
- * Implementations need to redefine it so that some methods, such as {@link #extracting(Function)}, are able
- * to build the appropriate list assert (eg: {@link ListAssert} versus {@link ProxyableListAssert}).
+ * Implementations need to redefine either to be proxy friendly (i.e. no final assertion methods)
+ * or generic vararg friendly (to use {@link SafeVarargs} annotation which requires final method).
*
* The default implementation will assume that this concrete implementation is NOT a soft assertion.
*
@@ -3127,6 +3574,7 @@ public RecursiveComparisonAssert> usingRecursiveComparison() {
* @return a new {@link RecursiveComparisonAssert} instance built with the given {@link RecursiveComparisonConfiguration}.
*/
@Override
+ @Beta
public RecursiveComparisonAssert> usingRecursiveComparison(RecursiveComparisonConfiguration recursiveComparisonConfiguration) {
return super.usingRecursiveComparison(recursiveComparisonConfiguration).withTypeComparators(comparatorsByType);
}
diff --git a/src/main/java/org/assertj/core/api/AbstractObjectAssert.java b/src/main/java/org/assertj/core/api/AbstractObjectAssert.java
index 9a360b1822b..7f325deec3f 100644
--- a/src/main/java/org/assertj/core/api/AbstractObjectAssert.java
+++ b/src/main/java/org/assertj/core/api/AbstractObjectAssert.java
@@ -49,6 +49,8 @@
* @author Joel Costigliola
* @author Libor Ondrusek
*/
+// suppression of deprecation works in Eclipse to hide warning for the deprecated classes in the imports
+@SuppressWarnings("deprecation")
public abstract class AbstractObjectAssert
* This can be handy if
* Navigational methods provided:
* The available assertions after navigating to an element depend on the {@code ELEMENT_ASSERT} parameter of the given
@@ -655,9 +655,10 @@ FactoryBasedNavigableIterableAssert, ACTUAL, ELEMENT, ELEMENT_ASSERT> assertTh
* in order to perform assertions on it.
*
* Navigational methods provided:
* The available assertions after navigating to an element depend on the given {@code assertClass}
@@ -690,9 +691,10 @@ ClassBasedNavigableIterableAssert, ACTUAL, ELEMENT, ELEMENT_ASSERT> assertThat
* in order to perform assertions on it.
*
* Navigational methods provided:
* The available assertions after navigating to an element depend on the {@code ELEMENT_ASSERT} parameter of the given
@@ -733,9 +735,10 @@ FactoryBasedNavigableListAssert, ACTUAL, ELEMENT, ELEMENT_ASSERT> assertThat(L
* in order to perform assertions on it.
*
* Navigational methods provided:
* The available assertions after navigating to an element depend on the given {@code assertClass}
@@ -771,7 +774,7 @@ ClassBasedNavigableListAssert, ACTUAL, ELEMENT, ELEMENT_ASSERT> assertThat(Lis
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractLongAssert> assertThat(long actual) {
+ public static LongAssert assertThat(long actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -781,7 +784,7 @@ public static AbstractLongAssert> assertThat(long actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractLongAssert> assertThat(Long actual) {
+ public static LongAssert assertThat(Long actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -791,7 +794,7 @@ public static AbstractLongAssert> assertThat(Long actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractLongArrayAssert> assertThat(long[] actual) {
+ public static LongArrayAssert assertThat(long[] actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -846,7 +849,7 @@ public static
+ * This is useful to avoid repeating getting the instance to test, a bit like a with block which turns the target into
+ * the equivalent of {@code this} (as in Groovy for example).
+ *
+ * Example:
+ *
+ * {@code assertWith} is variation of {@link AbstractAssert#satisfies(Consumer)} hopefully easier to find for some users.
+ *
+ * @param
@@ -1493,7 +1523,6 @@ public static
@@ -1496,7 +1496,7 @@ public static InFilter in(Object... values) {
}
/**
- * Create a {@link FilterOperator} to use in {@link AbstractIterableAssert#filteredOn(String, FilterOperator)
+ * Create a {@link FilterOperator} to use in {@link IterableAssert#filteredOn(String, FilterOperator)
* filteredOn(String, FilterOperation)} to express a filter keeping all Iterable elements whose property/field
* value matches does not match any of the given values.
*
@@ -1520,7 +1520,7 @@ public static NotInFilter notIn(Object... valuesNotToMatch) {
}
/**
- * Create a {@link FilterOperator} to use in {@link AbstractIterableAssert#filteredOn(String, FilterOperator)
+ * Create a {@link FilterOperator} to use in {@link IterableAssert#filteredOn(String, FilterOperator)
* filteredOn(String, FilterOperation)} to express a filter keeping all Iterable elements whose property/field
* value matches does not match the given value.
*
@@ -1774,7 +1774,7 @@ public static void setLenientDateParsing(boolean value) {
/**
* Add the given date format to the ones used to parse date String in String based Date assertions like
- * {@link org.assertj.core.api.AbstractDateAssert#isEqualTo(String)}.
+ * {@link org.assertj.core.api.DateAssert#isEqualTo(String)}.
*
* User date formats are used before default ones in the order they have been registered (first registered, first
* used).
@@ -1790,7 +1790,7 @@ public static void setLenientDateParsing(boolean value) {
* Beware that AssertJ will use the newly registered format for all remaining Date assertions in the test suite
*
* To revert to default formats only, call {@link #useDefaultDateFormatsOnly()} or
- * {@link org.assertj.core.api.AbstractDateAssert#withDefaultDateFormatsOnly()}.
+ * {@link org.assertj.core.api.DateAssert#withDefaultDateFormatsOnly()}.
*
* Code examples:
*
@@ -1820,7 +1820,7 @@ public static void registerCustomDateFormat(DateFormat userCustomDateFormat) {
/**
* Add the given date format to the ones used to parse date String in String based Date assertions like
- * {@link org.assertj.core.api.AbstractDateAssert#isEqualTo(String)}.
+ * {@link org.assertj.core.api.DateAssert#isEqualTo(String)}.
*
* User date formats are used before default ones in the order they have been registered (first registered, first
* used).
diff --git a/src/main/java/org/assertj/core/api/AssertionsForInterfaceTypes.java b/src/main/java/org/assertj/core/api/AssertionsForInterfaceTypes.java
index 2bde801dae0..7be900c9d86 100644
--- a/src/main/java/org/assertj/core/api/AssertionsForInterfaceTypes.java
+++ b/src/main/java/org/assertj/core/api/AssertionsForInterfaceTypes.java
@@ -92,7 +92,7 @@ protected AssertionsForInterfaceTypes() {}
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractCharSequenceAssert, ? extends CharSequence> assertThat(CharSequence actual) {
+ public static CharSequenceAssert assertThat(CharSequence actual) {
return new CharSequenceAssert(actual);
}
@@ -296,7 +296,7 @@ ClassBasedNavigableListAssert, ACTUAL, ELEMENT, ELEMENT_ASSERT> assertThat(Lis
* @param actual the path to test
* @return the created assertion object
*/
- public static AbstractPathAssert> assertThat(Path actual) {
+ public static PathAssert assertThat(Path actual) {
return new PathAssert(actual);
}
@@ -323,7 +323,7 @@ public static
- * Breaking change in version 3.12.0: this method does not return anymore an {@link ProxyableIterableAssert} but an {@link IteratorAssert}.
+ * Example:
+ *
@@ -1040,7 +1147,15 @@ public AtomicReferenceArrayAssert
* Allows to set a comparator to compare properties or fields of elements with the given names.
* A typical usage is for comparing fields of numeric type at a given precision.
*
* To be used, comparators need to be specified by this method before calling any of:
*
* Comparators specified by this method have precedence over comparators specified by
@@ -1794,7 +1934,22 @@ public AtomicReferenceArrayAssert
+ * When using {@link #usingRecursiveComparison()} the equivalent is:
+ *
+ * and when using {@link RecursiveComparisonConfiguration}:
+ *
* Allows to set a specific comparator to compare properties or fields of elements with the given type.
* A typical usage is for comparing fields of numeric type at a given precision.
*
* To be used, comparators need to be specified by this method before calling any of:
*
* Comparators specified by {@link #usingComparatorForElementFieldsWithNames(Comparator, String...) usingComparatorForElementFieldsWithNames}
@@ -1873,7 +2029,22 @@ public
+ * When using {@link #usingRecursiveComparison()} the equivalent is:
+ *
+ * and when using {@link RecursiveComparisonConfiguration}:
+ *
* Usage of this method affects comparators set by next methods:
*
* Example:
@@ -1920,6 +2090,8 @@ public
* Use field/property by field/property comparison (including inherited fields/properties) instead of relying on
* actual type A
- * The recursive property/field comparison is not applied on fields having a custom {@code equals}
- * implementation, i.e. the overridden {@code equals} method will be used instead of a field/property by field/property comparison.
+ * This method uses the default {@link RecursiveComparisonConfiguration}, if you need to customize it use {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)} instead.
*
- * You can specify a custom comparator per (nested) name or type of element field with
- * {@link #usingComparatorForElementFieldsWithNames(Comparator, String...) usingComparatorForElementFieldsWithNames}
- * and {@link #usingComparatorForElementFieldsWithType(Comparator, Class) usingComparatorForElementFieldsWithType}.
+ * Breaking change: since 3.20.0 the comparison won't use any comparators set with:
+ *
- * The recursive comparison handles cycles.
+ * These features (and many more) are provided through {@link #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)} with a customized {@link RecursiveComparisonConfiguration} where there methods are called:
+ *
- * The objects to compare can be of different types but must have the same properties/fields. For example if actual object has a
- * {@code name} String field, the other object must also have one.
+ * There are differences between this approach and {@link #usingRecursiveComparison()}:
+ *
- * If an object has a field and a property with the same name, the property value will be used over the field.
+ * This last point makes sense, take the {@link #contains(Object...)} assertion, it would not be relevant to report the differences of all the iterable's elements differing from the values to look for.
*
* Example:
+ *
+ * Another point worth mentioning: elements order does matter if the expected iterable is ordered, for example comparing a {@code Set
+ * The given {@link RecursiveComparisonConfiguration} is used to tweak the comparison behavior, for example by {@link RecursiveComparisonConfiguration#ignoreCollectionOrder(boolean) ignoring collection order}.
+ *
+ * Warning: the comparison won't use any comparators set with:
+ *
+ * These features (and many more) are provided through {@link RecursiveComparisonConfiguration} with:
+ *
+ * RecursiveComparisonConfiguration exposes a {@link RecursiveComparisonConfiguration.Builder builder} to ease setting the comparison behaviour,
+ * call {@link RecursiveComparisonConfiguration#builder() RecursiveComparisonConfiguration.builder()} to start building your configuration.
+ *
+ * There are differences between this approach and {@link #usingRecursiveComparison()}:
+ *
+ * This last point makes sense, take the {@link #contains(Object...)} assertion, it would not be relevant to report the differences of all the iterable's elements differing from the values to look for.
+ *
+ * Example:
+ *
+ * A point worth mentioning: elements order does matter if the expected iterable is ordered, for example comparing a {@code Set
* Use field/property by field/property comparison on the given fields/properties only (including inherited
* fields/properties) instead of relying on actual type A
+ * The ordering can be ignored by calling {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} allowing ordered/unordered iterable comparison, note that {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} is applied recursively on any nested iterable fields, if this behavior is too generic,
+ * use the more fine grained {@link RecursiveComparisonAssert#ignoringCollectionOrderInFields(String...) ignoringCollectionOrderInFields} or
+ * {@link RecursiveComparisonAssert#ignoringCollectionOrderInFieldsMatchingRegexes(String...) ignoringCollectionOrderInFieldsMatchingRegexes}.
*
* @return {@code this} assertion object.
- * @since 2.5.0 / 3.5.0
+ * @since 2.5.0 / 3.5.0 - breaking change in 3.20.0
+ * @see RecursiveComparisonConfiguration
+ * @see usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
*/
@CheckReturnValue
public SELF usingRecursiveFieldByFieldElementComparator() {
- return usingExtendedByTypesElementComparator(new RecursiveFieldByFieldComparator(comparatorsForElementPropertyOrFieldNames,
- getComparatorsForElementPropertyOrFieldTypes()));
+ return usingRecursiveFieldByFieldElementComparator(new RecursiveComparisonConfiguration());
}
/**
@@ -2384,9 +2576,10 @@ public SELF usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfi
*
* @return a new {@link RecursiveComparisonAssert} instance
* @see RecursiveComparisonConfiguration RecursiveComparisonConfiguration
+ * @since 3.15.0
*/
- @Override
@Beta
+ @Override
public RecursiveComparisonAssert> usingRecursiveComparison() {
// overridden for javadoc and to make this method public
return super.usingRecursiveComparison();
@@ -2400,13 +2593,17 @@ public RecursiveComparisonAssert> usingRecursiveComparison() {
* @param recursiveComparisonConfiguration the {@link RecursiveComparisonConfiguration} used in the chained {@link RecursiveComparisonAssert#isEqualTo(Object) isEqualTo} assertion.
*
* @return a new {@link RecursiveComparisonAssert} instance built with the given {@link RecursiveComparisonConfiguration}.
+ * @since 3.15.0
*/
+ @Beta
@Override
public RecursiveComparisonAssert> usingRecursiveComparison(RecursiveComparisonConfiguration recursiveComparisonConfiguration) {
return super.usingRecursiveComparison(recursiveComparisonConfiguration).withTypeComparators(comparatorsByType);
}
/**
+ * Deprecated javadoc
+ * equals method to compare group elements for
* incoming assertion checks. Private fields are included but this can be disabled using
@@ -2433,7 +2630,13 @@ public RecursiveComparisonAssert> usingRecursiveComparison(RecursiveComparison
*
* @param fields the fields/properties to compare using element comparators
* @return {@code this} assertion object.
+ * @see #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
+ * @see https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ * @deprecated This method is deprecated because it performs a shallow field by field comparison, i.e. elements are
+ * compared field by field but the fields are compared with equals, use {@link #usingRecursiveFieldByFieldElementComparatorOnFields(String...)} instead.
+ *
See https://assertj.github.io/doc/#assertj-core-recursive-comparison
*/
+ @Deprecated
@CheckReturnValue
public SELF usingElementComparatorOnFields(String... fields) {
return usingExtendedByTypesElementComparator(new OnFieldsComparator(comparatorsForElementPropertyOrFieldNames,
@@ -2441,12 +2644,63 @@ public SELF usingElementComparatorOnFields(String... fields) {
fields));
}
+ /**
+ * The assertions chained after this method will use a recursive field by field comparison on the given fields (including
+ * inherited fields) instead of relying on the element equals method.
+ * This is handy when the element equals method is not overridden or implemented as you expect.
+ *
+ * Player derrickRose = new Player(new Name("Derrick", "Rose"), "Chicago Bulls");
+ * derrickRose.nickname = new Name("Crazy", "Dunks");
+ *
+ * Player jalenRose = new Player(new Name("Jalen", "Rose"), "Chicago Bulls");
+ * jalenRose.nickname = new Name("Crazy", "Defense");
+ *
+ * // assertion succeeds as all compared fields match
+ * assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorOnFields("name.last", "team", "nickname.first")
+ * .contains(jalenRose);
+ *
+ * // assertion fails, name.first values differ
+ * assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorOnFields("name")
+ * .contains(jalenRose);
+ * The recursive comparison is documented here: https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ * RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
+ * .withComparedFields("name.last", "team", "nickname.first")
+ * .build();
+ *
+ * assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(jalenRose);equals method to compare group elements for
* incoming assertion checks. Private fields are included but this can be disabled using
@@ -2471,9 +2725,15 @@ protected SELF usingComparisonStrategy(ComparisonStrategy comparisonStrategy) {
* // ... but not when comparing both name and race
* assertThat(newArrayList(frodo)).usingElementComparatorIgnoringFields("age").contains(sam); // FAIL
*
- * @param fields the fields/properties to compare using element comparators
+ * @param fields the field names to exclude in the elements comparison.
* @return {@code this} assertion object.
+ * @see #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
+ * @see https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ * @deprecated This method is deprecated because it performs a shallow field by field comparison, i.e. elements are
+ * compared field by field but the fields are compared with equals, use {@link #usingRecursiveFieldByFieldElementComparatorIgnoringFields(String...)} instead.
+ *
See https://assertj.github.io/doc/#assertj-core-recursive-comparison
*/
+ @Deprecated
@CheckReturnValue
public SELF usingElementComparatorIgnoringFields(String... fields) {
return usingExtendedByTypesElementComparator(new IgnoringFieldsComparator(comparatorsForElementPropertyOrFieldNames,
@@ -2481,6 +2741,55 @@ public SELF usingElementComparatorIgnoringFields(String... fields) {
fields));
}
+ /**
+ * The assertions chained after this method will use a recursive field by field comparison on all fields (including inherited
+ * fields) except the given ones instead of relying on the element equals method.
+ * This is handy when the element equals method is not overridden or implemented as you expect.
+ *
+ * Player derrickRose = new Player(new Name("Derrick", "Rose"), "Chicago Bulls");
+ * derrickRose.nickname = new Name("Crazy", "Dunks");
+ *
+ * Player jalenRose = new Player(new Name("Jalen", "Rose"), "Chicago Bulls");
+ * jalenRose.nickname = new Name("Crazy", "Defense");
+ *
+ * // assertion succeeds
+ * assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorIgnoringFields("name.first", "nickname.last")
+ * .contains(jalenRose);
+ *
+ * // assertion fails, names are ignored but nicknames are not and nickname.last values differ
+ * assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorIgnoringFields("name")
+ * .contains(jalenRose);
+ * The recursive comparison is documented here: https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ * RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
+ * .withIgnoredFields("name.first", "nickname.last")
+ * .build();
+ *
+ * assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(jalenRose);
+ * Iterable<TolkienCharacter> hobbits = newArrayList(frodo, sam, pippin);
+ *
+ * // assertion succeeds
+ * assertThat(hobbits).elements(1, 2)
+ * .hasSize(2)
+ * .containsExactly(sam, pippin);
+ *
+ * // assertion fails
+ * assertThat(hobbits).element(1, 2)
+ * .containsExactly(frodo, pippin);
*
* @param other the {@code Map} to compare size with actual map
* @return {@code this} assertion object
@@ -512,7 +514,15 @@ public SELF hasSameSizeAs(Map, ?> other) {
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map does not contain the given entries.
*/
- public SELF contains(@SuppressWarnings("unchecked") Map.Entry extends K, ? extends V>... entries) {
+ @SafeVarargs
+ public final SELF contains(Map.Entry extends K, ? extends V>... entries) {
+ return containsForProxy(entries);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsForProxy(Map.Entry extends K, ? extends V>[] entries) {
maps.assertContains(info, actual, entries);
return myself;
}
@@ -543,7 +553,15 @@ public SELF contains(@SuppressWarnings("unchecked") Map.Entry extends K, ? ext
* @throws AssertionError if the actual map does not contain any of the given entries.
* @since 3.6.0
*/
- public SELF containsAnyOf(@SuppressWarnings("unchecked") Map.Entry extends K, ? extends V>... entries) {
+ @SafeVarargs
+ public final SELF containsAnyOf(Map.Entry extends K, ? extends V>... entries) {
+ return containsAnyOfForProxy(entries);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsAnyOfForProxy(Map.Entry extends K, ? extends V>[] entries) {
maps.assertContainsAnyOf(info, actual, entries);
return myself;
}
@@ -563,10 +581,11 @@ public SELF containsAnyOf(@SuppressWarnings("unchecked") Map.Entry extends K,
* elvesRingBearers.put(narya, gandalf);
* elvesRingBearers.put(vilya, elrond);
*
- * // assertion will succeed
+ * // assertions succeed
* assertThat(ringBearers).containsAllEntriesOf(elvesRingBearers);
+ * assertThat(ringBearers).containsAllEntriesOf(emptyMap);
*
- * // assertion will fail
+ * // assertion fails
* assertThat(elvesRingBearers).containsAllEntriesOf(ringBearers);
*
* @param other the map with the given entries.
@@ -577,7 +596,7 @@ public SELF containsAnyOf(@SuppressWarnings("unchecked") Map.Entry extends K,
* @throws AssertionError if the actual map does not contain the given entries.
*/
public SELF containsAllEntriesOf(Map extends K, ? extends V> other) {
- maps.assertContains(info, actual, toEntries(other));
+ maps.assertContainsAllEntriesOf(info, actual, other);
return myself;
}
@@ -956,7 +975,15 @@ public SELF hasValueSatisfying(Condition super V> valueCondition) {
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map contains any of the given entries.
*/
- public SELF doesNotContain(@SuppressWarnings("unchecked") Map.Entry extends K, ? extends V>... entries) {
+ @SafeVarargs
+ public final SELF doesNotContain(Map.Entry extends K, ? extends V>... entries) {
+ return doesNotContainForProxy(entries);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF doesNotContainForProxy(Map.Entry extends K, ? extends V>[] entries) {
maps.assertDoesNotContain(info, actual, entries);
return myself;
}
@@ -1010,7 +1037,6 @@ public SELF doesNotContainEntry(K key, V value) {
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map does not contain the given key.
*/
- @SuppressWarnings("unchecked")
public SELF containsKey(K key) {
return containsKeys(key);
}
@@ -1037,7 +1063,15 @@ public SELF containsKey(K key) {
* @throws AssertionError if the actual map does not contain the given key.
* @throws IllegalArgumentException if the given argument is an empty array.
*/
- public SELF containsKeys(@SuppressWarnings("unchecked") K... keys) {
+ @SafeVarargs
+ public final SELF containsKeys(K... keys) {
+ return containsKeysForProxy(keys);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsKeysForProxy(K[] keys) {
maps.assertContainsKeys(info, actual, keys);
return myself;
}
@@ -1062,7 +1096,6 @@ public SELF containsKeys(@SuppressWarnings("unchecked") K... keys) {
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map contains the given key.
*/
- @SuppressWarnings("unchecked")
public SELF doesNotContainKey(K key) {
return doesNotContainKeys(key);
}
@@ -1088,14 +1121,26 @@ public SELF doesNotContainKey(K key) {
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map contains the given key.
*/
- public SELF doesNotContainKeys(@SuppressWarnings("unchecked") K... keys) {
+ @SafeVarargs
+ public final SELF doesNotContainKeys(K... keys) {
+ return doesNotContainKeysForProxy(keys);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF doesNotContainKeysForProxy(K[] keys) {
maps.assertDoesNotContainKeys(info, actual, keys);
return myself;
}
/**
* Verifies that the actual map contains only the given keys and nothing else, in any order.
- *
+ * Map<Ring, TolkienCharacter> ringBearers = new HashMap<>();
- * ringBearers.put(nenya, galadriel);
- * ringBearers.put(narya, gandalf);
- * ringBearers.put(vilya, elrond);
- * ringBearers.put(oneRing, frodo);
+ *
+ * // assertion succeeds:
+ * assertThat(ringBearers).hasSameSizeAs(ImmutableMap.of(oneRing, frodo,
+ * narya, gandalf,
+ * nenya, galadriel,
+ * vilya, elrond));
+ *
+ * // assertions fails:
+ * assertThat(ringBearers).hasSameSizeAs(Collections.emptyMap());
+ * assertThat(ringBearers).hasSameSizeAs(ImmutableMap.of(nenya, galadriel,
+ * narya, gandalf,
+ * vilya, elrond)); import static com.google.common.collect.ImmutableMap.of;
*
- * // assertion will pass
- * assertThat(ringBearers).hasSameSizeAs(mapOf(entry(oneRing, frodo),
- * entry(narya, gandalf),
- * entry(nenya, galadriel),
- * entry(vilya, elrond)));
+ * Map<Ring, TolkienCharacter> ringBearers = ImmutableMap.of(nenya, galadriel,
+ * narya, gandalf,
+ * vilya, elrond,
+ * oneRing, frodo);
*
- * // assertions will fail
- * assertThat(elvesRingBearers).hasSameSizeAs(new HashMap());
- * Map<String, String> keyToValue = new HashMap();
- * keyToValue.put("key", "value");
- * assertThat(keyToValue).hasSameSizeAs(keyToValue);
*
* @return {@code this} assertion object.
+ * @deprecated This method is deprecated because it performs a shallow field by field comparison, i.e. elements are compared
+ * field by field but the fields are compared with equals, use {@link #get()} chained with {@link AbstractObjectAssert#usingRecursiveComparison()} instead.
+ * Map<Ring, TolkienCharacter> ringBearers = new HashMap<>();
@@ -1117,15 +1162,26 @@ public SELF doesNotContainKeys(@SuppressWarnings("unchecked") K... keys) {
* of the given keys, or the actual map contains more entries than the given ones.
* @throws IllegalArgumentException if the given argument is an empty array.
*/
+ @SafeVarargs
+ public final SELF containsOnlyKeys(K... keys) {
+ return containsOnlyKeysForProxy(keys);
+ }
- public SELF containsOnlyKeys(@SuppressWarnings("unchecked") K... keys) {
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsOnlyKeysForProxy(K[] keys) {
maps.assertContainsOnlyKeys(info, actual, keys);
return myself;
}
/**
* Verifies that the actual map contains only the given keys and nothing else, in any order.
- *
+ *
*
* @return {@code this} assertion object.
+ * @deprecated This method is deprecated because it performs a shallow field by field comparison, i.e. elements are compared
+ * field by field but the fields are compared with equals, use {@link #usingRecursiveFieldByFieldElementComparator()}
+ * or {@link #usingRecursiveComparison()} instead to perform a true recursive comparison.
+ * Map<Ring, TolkienCharacter> ringBearers = new HashMap<>();
@@ -1154,7 +1210,7 @@ public SELF containsOnlyKeys(Iterable extends K> keys) {
if (keys instanceof Path) {
// do not treat Path as an Iterable
K path = (K) keys;
- maps.assertContainsOnlyKeys(info, actual, path);
+ maps.assertContainsOnlyKeys(info, actual, singleton(path));
} else {
maps.assertContainsOnlyKeys(info, actual, keys);
}
@@ -1209,7 +1265,15 @@ public SELF containsValue(V value) {
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map does not contain the given values.
*/
- public SELF containsValues(@SuppressWarnings("unchecked") V... values) {
+ @SafeVarargs
+ public final SELF containsValues(V... values) {
+ return containsValuesForProxy(values);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsValuesForProxy(V[] values) {
maps.assertContainsValues(info, actual, values);
return myself;
}
@@ -1242,7 +1306,11 @@ public SELF doesNotContainValue(V value) {
/**
* Verifies that the actual map contains only the given entries and nothing else, in any order.
- *
+ *
@@ -1265,7 +1338,15 @@ public SELF doesNotContainValue(V value) {
* @throws AssertionError if the actual map does not contain the given entries, i.e. the actual map contains some or
* none of the given entries, or the actual map contains more entries than the given ones.
*/
- public SELF containsOnly(@SuppressWarnings("unchecked") Map.Entry extends K, ? extends V>... entries) {
+ @SafeVarargs
+ public final SELF containsOnly(Map.Entry extends K, ? extends V>... entries) {
+ return containsOnlyForProxy(entries);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsOnlyForProxy(Map.Entry extends K, ? extends V>[] entries) {
maps.assertContainsOnly(info, actual, entries);
return myself;
}
@@ -1280,11 +1361,13 @@ public SELF containsOnly(@SuppressWarnings("unchecked") Map.Entry extends K, ?
* Map<Ring, TolkienCharacter> ringBearers = newLinkedHashMap(entry(oneRing, frodo),
* entry(nenya, galadriel),
* entry(narya, gandalf));
- * // assertion will pass
+ * // assertions will pass
* assertThat(ringBearers).containsExactly(entry(oneRing, frodo),
* entry(nenya, galadriel),
* entry(narya, gandalf));
*
+ * assertThat(Collections.emptyMap()).containsExactly();
+ *
* // assertion will fail as actual and expected order differ
* assertThat(ringBearers).containsExactly(entry(nenya, galadriel),
* entry(narya, gandalf),
@@ -1299,7 +1382,15 @@ public SELF containsOnly(@SuppressWarnings("unchecked") Map.Entry extends K, ?
* contains some or none of the given entries, or the actual map contains more entries than the given ones
* or entries are the same but the order is not.
*/
- public SELF containsExactly(@SuppressWarnings("unchecked") Map.Entry extends K, ? extends V>... entries) {
+ @SafeVarargs
+ public final SELF containsExactly(Map.Entry extends K, ? extends V>... entries) {
+ return containsExactlyForProxy(entries);
+ }
+
+ // This method is protected in order to be proxied for SoftAssertions / Assumptions.
+ // The public method for it (the one not ending with "ForProxy") is marked as final and annotated with @SafeVarargs
+ // in order to avoid compiler warning in user code
+ protected SELF containsExactlyForProxy(Map.Entry extends K, ? extends V>[] entries) {
maps.assertContainsExactly(info, actual, entries);
return myself;
}
@@ -1607,7 +1698,15 @@ public AbstractListAssert, List>, Object, ObjectAssert Map<Ring, TolkienCharacter> ringBearers = new HashMap<>();
@@ -1251,8 +1319,13 @@ public SELF doesNotContainValue(V value) {
* ringBearers.put(vilya, elrond);
* ringBearers.put(oneRing, frodo);
*
- * // assertion will pass
- * assertThat(ringBearers).containsOnly(entry(oneRing, frodo), entry(nenya, galadriel), entry(narya, gandalf), entry(vilya, elrond));
+ * // assertions will pass
+ * assertThat(ringBearers).containsOnly(entry(oneRing, frodo),
+ * entry(nenya, galadriel),
+ * entry(narya, gandalf),
+ * entry(vilya, elrond));
+ *
+ * assertThat(Collections.emptyMap()).containsOnly();
*
* // assertion will fail
* assertThat(ringBearers).containsOnly(entry(oneRing, frodo), entry(nenya, galadriel));
+ *
+ * @param expectedTypes the expected types
+ * @return {@code this} assertion object.
+ * @throws NullPointerException if the given type array is {@code null}.
+ * @throws AssertionError if actual is {@code null}.
+ * @throws AssertionError if the actual elements types don't exactly match the given ones (in the given order).
+ */
+ @Override
+ public SELF hasExactlyElementsOfTypes(Class>... expectedTypes) {
+ arrays.assertHasExactlyElementsOfTypes(info, actual, expectedTypes);
+ return myself;
+ }
+
/**
* Verifies that the actual array does not contain the given object at the given index.
* Object[] objects = { 1, "a", "b", 1.00 };
+ *
+ * // assertion succeeds
+ * assertThat(objects).hasExactlyElementsOfTypes(Integer.class, String.class, String.class, Double.class);
+ *
+ * // assertions fail
+ * // missing second String type
+ * assertThat(objects).hasExactlyElementsOfTypes(Integer.class, String.class, Double.class);
+ * // no Float type in actual
+ * assertThat(objects).hasExactlyElementsOfTypes(Float.class, String.class, String.class, Double.class);
+ * // correct types but wrong order
+ * assertThat(objects).hasExactlyElementsOfTypes(String.class, Integer.class, String.class, Double.class);
+ * // actual has more elements than the specified expected types
+ * assertThat(objects).hasExactlyElementsOfTypes(String.class);
+ *
+ *
+ *
*/
+ @Deprecated
@CheckReturnValue
public
- *
*
+ *
+ *
+ *
*/
+ @Deprecated
@CheckReturnValue
public
- *
* equals method to compare group elements for incoming assertion checks. Private fields
* are included but this can be disabled using {@link Assertions#setAllowExtractingPrivateFields(boolean)}.
@@ -1816,7 +1987,12 @@ public
See https://assertj.github.io/doc/#assertj-core-recursive-comparison
*/
+ @Deprecated
@CheckReturnValue
public SELF usingFieldByFieldElementComparator() {
return usingExtendedByTypesElementComparator(new FieldByFieldComparator(comparatorsForElementPropertyOrFieldNames,
@@ -1824,55 +2000,182 @@ public SELF usingFieldByFieldElementComparator() {
}
/**
- * Use a recursive field/property by field/property comparison (including inherited fields/properties)
- * instead of relying on actual type A equals method to compare group elements for incoming
- * assertion checks. This can be useful if actual's {@code equals} implementation does not suit you.
+ * Enable using a recursive field by field comparison strategy similar to {@link #usingRecursiveComparison()} but contrary to the latter you can chain any iterable assertions after this method (this is why this method exists).
*
+ *
*
+ *
*
+ *
*
+ * public class Person {
+ * String name;
+ * boolean hasPhd;
+ * }
*
- *
+ * // assertion fails because leonard names are different.
+ * leonard.setName("Leonard Ofstater");
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(leonard);
+ *
+ * // assertion fails because howard is missing and leonard is not expected.
+ * people = list(howard, sheldon, raj)
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(howard); TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
- * TolkienCharacter pippin = new TolkienCharacter("Pippin", 28, HOBBIT);
- * frodo.setFriend(pippin);
- * pippin.setFriend(frodo);
+ * public class Doctor {
+ * String name;
+ * boolean hasPhd;
+ * }
*
- * TolkienCharacter frodoClone = new TolkienCharacter("Frodo", 33, HOBBIT);
- * TolkienCharacter pippinClone = new TolkienCharacter("Pippin", 28, HOBBIT);
- * frodoClone.setFriend(pippinClone);
- * pippinClone.setFriend(frodoClone);
+ * Doctor drSheldon = new Doctor("Sheldon Cooper", true);
+ * Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
+ * Doctor drRaj = new Doctor("Raj Koothrappali", true);
+ *
+ * Person sheldon = new Person("Sheldon Cooper", true);
+ * Person leonard = new Person("Leonard Hofstadter", true);
+ * Person raj = new Person("Raj Koothrappali", true);
+ * Person howard = new Person("Howard Wolowitz", true);
*
- * TolkienCharacter[] hobbits = new TolkienCharacter[] {frodo, pippin};
+ * Doctor[] doctors = array(drSheldon, drLeonard, drRaj);
+ * Person[] people = array(sheldon, leonard, raj);
*
- * // fails if equals has not been overridden in TolkienCharacter as it would compares object references
- * assertThat(hobbits).contains(frodoClone, pippinClone);
+ * // assertion succeeds as both lists contains equivalent items in order.
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(sheldon);
*
- * // frodo/frodoClone and pippin/pippinClone are equals when doing a recursive property/field by property/field comparison
- * assertThat(hobbits).usingRecursiveFieldByFieldElementComparator()
- * .contains(frodoClone, pippinClone);
+ * The ordering can be ignored by calling {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} allowing ordered/unordered iterable comparison, note that {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} is applied recursively on any nested iterable fields, if this behavior is too generic,
+ * use the more fine grained {@link RecursiveComparisonAssert#ignoringCollectionOrderInFields(String...) ignoringCollectionOrderInFields} or
+ * {@link RecursiveComparisonAssert#ignoringCollectionOrderInFieldsMatchingRegexes(String...) ignoringCollectionOrderInFieldsMatchingRegexes}.
*
* @return {@code this} assertion object.
- * @since 2.5.0 / 3.5.0
+ * @since 2.5.0 / 3.5.0 - breaking change in 3.20.0
+ * @see RecursiveComparisonConfiguration
+ * @see usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
*/
@CheckReturnValue
public SELF usingRecursiveFieldByFieldElementComparator() {
- return usingExtendedByTypesElementComparator(new RecursiveFieldByFieldComparator(comparatorsForElementPropertyOrFieldNames,
- getComparatorsForElementPropertyOrFieldTypes()));
+ return usingRecursiveFieldByFieldElementComparator(new RecursiveComparisonConfiguration());
}
/**
+ * Enable using a recursive field by field comparison strategy similar to {@link #usingRecursiveComparison()} but contrary to the latter you can chain any iterable assertions after this method (this is why this method exists).
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * A detailed documentation for the recursive comparison is available here: https://assertj.github.io/doc/#assertj-core-recursive-comparison.
+ * public class Person {
+ * String name;
+ * boolean hasPhd;
+ * }
+ *
+ * public class Doctor {
+ * String name;
+ * boolean hasPhd;
+ * }
+ *
+ * Doctor drSheldon = new Doctor("Sheldon Cooper", true);
+ * Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
+ * Doctor drRaj = new Doctor("Raj Koothrappali", true);
+ *
+ * Person sheldon = new Person("Sheldon Cooper", false);
+ * Person leonard = new Person("Leonard Hofstadter", false);
+ * Person raj = new Person("Raj Koothrappali", false);
+ * Person howard = new Person("Howard Wolowitz", false);
+ *
+ * Doctor[] doctors = array(drSheldon, drLeonard, drRaj);
+ * Person[] people = array(sheldon, leonard, raj);
+ *
+ * RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
+ * .withIgnoredFields("hasPhd");
+ *
+ * // assertion succeeds as both lists contains equivalent items in order.
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(sheldon);
+ *
+ * // assertion fails because leonard names are different.
+ * leonard.setName("Leonard Ofstater");
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(leonard);
+ *
+ * // assertion fails because howard is missing and leonard is not expected.
+ * people = list(howard, sheldon, raj)
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(howard);
+ * The ordering can be ignored by calling {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} allowing ordered/unordered iterable comparison, note that {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} is applied recursively on any nested iterable fields, if this behavior is too generic,
+ * use the more fine grained {@link RecursiveComparisonAssert#ignoringCollectionOrderInFields(String...) ignoringCollectionOrderInFields} or
+ * {@link RecursiveComparisonAssert#ignoringCollectionOrderInFieldsMatchingRegexes(String...) ignoringCollectionOrderInFieldsMatchingRegexes}.
+ *
+ * @param configuration the recursive comparison configuration.
+ *
+ * @return {@code this} assertion object.
+ * @since 3.20.0
+ * @see RecursiveComparisonConfiguration
+ */
+ public SELF usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration configuration) {
+ return usingElementComparator(new ConfigurableRecursiveFieldByFieldComparator(configuration));
+ }
+
+ /**
+ * Deprecated javadoc
+ * equals method to compare group elements for
* incoming assertion checks. Private fields are included but this can be disabled using
@@ -1899,7 +2202,13 @@ public SELF usingRecursiveFieldByFieldElementComparator() {
*
* @param fields the name of the fields to use the element comparator on
* @return {@code this} assertion object.
+ * @see #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
+ * @see https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ * @deprecated This method is deprecated because it performs a shallow field by field comparison, i.e. elements are
+ * compared field by field but the fields are compared with equals, use {@link #usingRecursiveFieldByFieldElementComparatorOnFields(String...)} instead.
+ *
See https://assertj.github.io/doc/#assertj-core-recursive-comparison
*/
+ @Deprecated
@CheckReturnValue
public SELF usingElementComparatorOnFields(String... fields) {
return usingExtendedByTypesElementComparator(new OnFieldsComparator(comparatorsForElementPropertyOrFieldNames,
@@ -1908,6 +2217,57 @@ public SELF usingElementComparatorOnFields(String... fields) {
}
/**
+ * The assertions chained after this method will use a recursive field by field comparison on the given fields (including
+ * inherited fields) instead of relying on the element equals method.
+ * This is handy when the element equals method is not overridden or implemented as you expect.
+ *
+ * Player derrickRose = new Player(new Name("Derrick", "Rose"), "Chicago Bulls");
+ * derrickRose.nickname = new Name("Crazy", "Dunks");
+ *
+ * Player jalenRose = new Player(new Name("Jalen", "Rose"), "Chicago Bulls");
+ * jalenRose.nickname = new Name("Crazy", "Defense");
+ *
+ * // assertion succeeds as all compared fields match
+ * assertThat(array(derrickRose)).usingRecursiveFieldByFieldElementComparatorOnFields("name.last", "team", "nickname.first")
+ * .contains(jalenRose);
+ *
+ * // assertion fails, name.first values differ
+ * assertThat(array(derrickRose)).usingRecursiveFieldByFieldElementComparatorOnFields("name")
+ * .contains(jalenRose);
+ * The recursive comparison is documented here: https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ * RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
+ * .withComparedFields("name.last", "team", "nickname.first")
+ * .build();
+ *
+ * assertThat(array(derrickRose)).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(jalenRose);equals method to compare group elements for
* incoming assertion checks. Private fields are included but this can be disabled using
@@ -1934,7 +2294,13 @@ public SELF usingElementComparatorOnFields(String... fields) {
*
* @param fields the name of the fields to ignore
* @return {@code this} assertion object.
+ * @see #usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
+ * @see https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ * @deprecated This method is deprecated because it performs a shallow field by field comparison, i.e. elements are
+ * compared field by field but the fields are compared with equals, use {@link #usingRecursiveFieldByFieldElementComparatorIgnoringFields(String...)} instead.
+ *
See https://assertj.github.io/doc/#assertj-core-recursive-comparison
*/
+ @Deprecated
@CheckReturnValue
public SELF usingElementComparatorIgnoringFields(String... fields) {
return usingExtendedByTypesElementComparator(new IgnoringFieldsComparator(comparatorsForElementPropertyOrFieldNames,
@@ -1942,6 +2308,55 @@ public SELF usingElementComparatorIgnoringFields(String... fields) {
fields));
}
+ /**
+ * The assertions chained after this method will use a recursive field by field comparison on all fields (including inherited
+ * fields) except the given ones instead of relying on the element equals method.
+ * This is handy when the element equals method is not overridden or implemented as you expect.
+ *
+ * Player derrickRose = new Player(new Name("Derrick", "Rose"), "Chicago Bulls");
+ * derrickRose.nickname = new Name("Crazy", "Dunks");
+ *
+ * Player jalenRose = new Player(new Name("Jalen", "Rose"), "Chicago Bulls");
+ * jalenRose.nickname = new Name("Crazy", "Defense");
+ *
+ * // assertion succeeds
+ * assertThat(array(derrickRose)).usingRecursiveFieldByFieldElementComparatorIgnoringFields("name.first", "nickname.last")
+ * .contains(jalenRose);
+ *
+ * // assertion fails, names are ignored but nicknames are not and nickname.last values differ
+ * assertThat(array(derrickRose)).usingRecursiveFieldByFieldElementComparatorIgnoringFields("name")
+ * .contains(jalenRose);
+ * The recursive comparison is documented here: https://assertj.github.io/doc/#assertj-core-recursive-comparison
+ * RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
+ * .withIgnoredFields("name.first", "nickname.last")
+ * .build();
+ *
+ * assertThat(array(derrickRose)).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(jalenRose);equals method to compare the {@link Optional} value's object for incoming assertion
- * checks. Private fields are included but this can be disabled using
- * {@link Assertions#setAllowExtractingPrivateFields(boolean)}.
+ * checks. Private fields are included but this can be disabled using {@link Assertions#setAllowExtractingPrivateFields(boolean)}.
* equals method of the {@link Optional} value's object to compare does not suit
* you.
@@ -266,7 +266,17 @@ public SELF containsInstanceOf(Class> clazz) {
* assertThat(Optional.of(frodo)).usingFieldByFieldValueComparator().contains(frodoClone);
+ * TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
+ * TolkienCharacter frodoClone = new TolkienCharacter("Frodo", 33, HOBBIT);
+ *
+ * // frodo and frodoClone are equals when doing a field by field comparison.
+ * assertThat(Optional.of(frodo)).get().usingRecursiveComparison()
+ * .isEqualTo(frodoClone);
See https://assertj.github.io/doc/#assertj-core-recursive-comparison
*/
+ @Deprecated
@CheckReturnValue
public SELF usingFieldByFieldValueComparator() {
return usingValueComparator(new FieldByFieldComparator());
diff --git a/src/main/java/org/assertj/core/api/AbstractPathAssert.java b/src/main/java/org/assertj/core/api/AbstractPathAssert.java
index 1445063358e..68fca97f816 100644
--- a/src/main/java/org/assertj/core/api/AbstractPathAssert.java
+++ b/src/main/java/org/assertj/core/api/AbstractPathAssert.java
@@ -1761,14 +1761,14 @@ public SELF isNotEmptyDirectory() {
* /root/sub-dir-1/file-2.ext (content)
*
* Here are some assertions examples:
- *
*
* @return {@code this} assertion object.
* @throws AssertionError if actual is {@code null}.
@@ -1792,14 +1792,14 @@ public SELF isEmptyFile() {
* /root/sub-dir-1/file-2.ext (content)
*
* Here are some assertions examples:
- * Path noContentPath = Paths.get("/root/sub-dir-1/file-1.ext");
- * Path contentPath = Paths.get("/root/sub-dir-1/file-2.ext");
+ *
+ * assertThat(withContent).isEmptyFile(); Path withoutContent = Paths.get("/root/sub-dir-1/file-1.ext");
+ * Path withContent = Paths.get("/root/sub-dir-1/file-2.ext");
*
* // The following assertion succeeds:
- * assertThat(noContentPath).isEmptyFile();
+ * assertThat(withoutContent).isEmptyFile();
*
* // The following assertion fails:
- * assertThat(contentPath).isEmptyFile();
*
* @return {@code this} assertion object.
* @throws AssertionError if actual is {@code null}.
diff --git a/src/main/java/org/assertj/core/api/AbstractPredicateAssert.java b/src/main/java/org/assertj/core/api/AbstractPredicateAssert.java
index bb447968172..80d8879618a 100644
--- a/src/main/java/org/assertj/core/api/AbstractPredicateAssert.java
+++ b/src/main/java/org/assertj/core/api/AbstractPredicateAssert.java
@@ -57,7 +57,15 @@ protected AbstractPredicateAssert(Predicate Path noContentPath = Paths.get("/root/sub-dir-1/file-1.ext");
- * Path contentPath = Paths.get("/root/sub-dir-1/file-2.ext");
+ *
+ * assertThat(withoutContent).isNotEmptyFile(); Path withoutContent = Paths.get("/root/sub-dir-1/file-1.ext");
+ * Path withContent = Paths.get("/root/sub-dir-1/file-2.ext");
*
* // The following assertion succeeds:
- * assertThat(contentPath).isNotEmptyFile();
+ * assertThat(withContent).isNotEmptyFile();
*
* // The following assertion fails:
- * assertThat(noContentPath).isNotEmptyFile(); // assertions succeed
* assertThat(42L).doesNotHaveSameHashCodeAs(2501L);
- * assertThat("The Force").doesNotHaveSameHashCodeAs(null);
+ * assertThat("The Force").doesNotHaveSameHashCodeAs("Awakens");
*
* // assertions fail
* assertThat(42L).doesNotHaveSameHashCodeAs(42L);
diff --git a/src/main/java/org/assertj/core/api/Assertions.java b/src/main/java/org/assertj/core/api/Assertions.java
index 6a9417dc212..545b2468d41 100644
--- a/src/main/java/org/assertj/core/api/Assertions.java
+++ b/src/main/java/org/assertj/core/api/Assertions.java
@@ -282,7 +282,7 @@ public static OptionalLongAssert assertThat(OptionalLong actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractBigDecimalAssert> assertThat(BigDecimal actual) {
+ public static BigDecimalAssert assertThat(BigDecimal actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -293,7 +293,7 @@ public static AbstractBigDecimalAssert> assertThat(BigDecimal actual) {
* @return the created assertion object.
* @since 2.7.0 / 3.7.0
*/
- public static AbstractBigIntegerAssert> assertThat(BigInteger actual) {
+ public static BigIntegerAssert assertThat(BigInteger actual) {
return new BigIntegerAssert(actual);
}
@@ -303,7 +303,7 @@ public static AbstractBigIntegerAssert> assertThat(BigInteger actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractUriAssert> assertThat(URI actual) {
+ public static UriAssert assertThat(URI actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -313,7 +313,7 @@ public static AbstractUriAssert> assertThat(URI actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractUrlAssert> assertThat(URL actual) {
+ public static UrlAssert assertThat(URL actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -323,7 +323,7 @@ public static AbstractUrlAssert> assertThat(URL actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractBooleanAssert> assertThat(boolean actual) {
+ public static BooleanAssert assertThat(boolean actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -333,7 +333,7 @@ public static AbstractBooleanAssert> assertThat(boolean actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractBooleanAssert> assertThat(Boolean actual) {
+ public static BooleanAssert assertThat(Boolean actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -343,7 +343,7 @@ public static AbstractBooleanAssert> assertThat(Boolean actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractBooleanArrayAssert> assertThat(boolean[] actual) {
+ public static BooleanArrayAssert assertThat(boolean[] actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -364,7 +364,7 @@ public static Boolean2DArrayAssert assertThat(boolean[][] actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractByteAssert> assertThat(byte actual) {
+ public static ByteAssert assertThat(byte actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -374,7 +374,7 @@ public static AbstractByteAssert> assertThat(byte actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractByteAssert> assertThat(Byte actual) {
+ public static ByteAssert assertThat(Byte actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -384,7 +384,7 @@ public static AbstractByteAssert> assertThat(Byte actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractByteArrayAssert> assertThat(byte[] actual) {
+ public static ByteArrayAssert assertThat(byte[] actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -405,7 +405,7 @@ public static Byte2DArrayAssert assertThat(byte[][] actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractCharacterAssert> assertThat(char actual) {
+ public static CharacterAssert assertThat(char actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -415,7 +415,7 @@ public static AbstractCharacterAssert> assertThat(char actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractCharArrayAssert> assertThat(char[] actual) {
+ public static CharArrayAssert assertThat(char[] actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -436,7 +436,7 @@ public static Char2DArrayAssert assertThat(char[][] actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractCharacterAssert> assertThat(Character actual) {
+ public static CharacterAssert assertThat(Character actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -456,7 +456,7 @@ public static ClassAssert assertThat(Class> actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractDoubleAssert> assertThat(double actual) {
+ public static DoubleAssert assertThat(double actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -466,7 +466,7 @@ public static AbstractDoubleAssert> assertThat(double actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractDoubleAssert> assertThat(Double actual) {
+ public static DoubleAssert assertThat(Double actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -476,7 +476,7 @@ public static AbstractDoubleAssert> assertThat(Double actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractDoubleArrayAssert> assertThat(double[] actual) {
+ public static DoubleArrayAssert assertThat(double[] actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -497,7 +497,7 @@ public static Double2DArrayAssert assertThat(double[][] actual) {
* @param actual the actual value.
* @return the created assertion object.
*/
- public static AbstractFileAssert> assertThat(File actual) {
+ public static FileAssert assertThat(File actual) {
return AssertionsForClassTypes.assertThat(actual);
}
@@ -520,7 +520,7 @@ public static
- *
*
- *
*
- *
*
- *
*
+ * assertWith(team.getPlayers().get(0).getStats(),
+ * stats -> {
+ * assertThat(stats.pointPerGame).isGreaterThan(25.7);
+ * assertThat(stats.assistsPerGame).isGreaterThan(7.2);
+ * assertThat(stats.reboundsPerGame).isBetween(9, 12);
+ * });null if none was raised by the callable.
* @since 3.7.0
*/
- public static AbstractThrowableAssert, ? extends Throwable> assertThatCode(ThrowingCallable shouldRaiseOrNotThrowable) {
+ public static ThrowableAssert assertThatCode(ThrowingCallable shouldRaiseOrNotThrowable) {
return assertThat(catchThrowable(shouldRaiseOrNotThrowable));
}
@@ -1088,9 +1088,9 @@ public static Tuple tuple(Object... values) {
/**
* Globally sets whether
- * {@link org.assertj.core.api.AbstractIterableAssert#extracting(String) IterableAssert#extracting(String)}
+ * {@link org.assertj.core.api.IterableAssert#extracting(String) IterableAssert#extracting(String)}
* and
- * {@link org.assertj.core.api.AbstractObjectArrayAssert#extracting(String) ObjectArrayAssert#extracting(String)}
+ * {@link org.assertj.core.api.ObjectArrayAssert#extracting(String) ObjectArrayAssert#extracting(String)}
* should be allowed to extract private fields, if not and they try it fails with exception.
*
* @param allowExtractingPrivateFields allow private fields extraction. Default {@code true}.
@@ -1103,8 +1103,8 @@ public static void setAllowExtractingPrivateFields(boolean allowExtractingPrivat
* Globally sets whether the use of private fields is allowed for comparison.
* The following (incomplete) list of methods will be impacted by this change :
*
- *
*
* If the value is {@link org.assertj.core.api.AbstractIterableAssert#usingElementComparatorOnFields(java.lang.String...)}{@link org.assertj.core.api.AbstractObjectAssert#isEqualToComparingFieldByField(Object)}{@link org.assertj.core.api.IterableAssert#usingElementComparatorOnFields(java.lang.String...)}{@link org.assertj.core.api.ObjectAssert#isEqualToComparingFieldByField(Object)}false and these methods try to compare private fields, it will fail with an exception.
@@ -1472,7 +1472,7 @@ public static {@link IteratorAssert} assumption.
- *
*
* @param
+ *
+ * @param expectedTypes the expected types
+ * @return {@code this} assertion object.
+ * @throws NullPointerException if the given type array is {@code null}.
+ * @throws AssertionError if actual is {@code null}.
+ * @throws AssertionError if the actual elements types don't exactly match the given ones (in the given order).
+ */
+ @Override
+ public AtomicReferenceArrayAssert AtomicReferenceArray<Object> objects = new AtomicReferenceArray<>(new Object[] { 1, "a", 1.00 });
+ *
+ * // assertion succeeds
+ * assertThat(objects).hasExactlyElementsOfTypes(Integer.class, String.class, String.class, Double.class);
+ *
+ * // assertions fail
+ * // missing second String type
+ * assertThat(objects).hasExactlyElementsOfTypes(Integer.class, String.class, Double.class);
+ * // no Float type in actual
+ * assertThat(objects).hasExactlyElementsOfTypes(Float.class, String.class, String.class, Double.class);
+ * // correct types but wrong order
+ * assertThat(objects).hasExactlyElementsOfTypes(String.class, Integer.class, String.class, Double.class);
+ * // actual has more elements than the specified expected types
+ * assertThat(objects).hasExactlyElementsOfTypes(String.class);
- *
*
+ *
+ *
+ *
*/
+ @Deprecated
@CheckReturnValue
public
- *
*
+ *
+ *
+ *
*/
+ @Deprecated
@CheckReturnValue
public
- *
* equals method to compare AtomicReferenceArray elements for incoming assertion checks. Private fields
* are included but this can be disabled using {@link Assertions#setAllowExtractingPrivateFields(boolean)}.
@@ -1945,7 +2117,12 @@ public
See https://assertj.github.io/doc/#assertj-core-recursive-comparison
*/
+ @Deprecated
@CheckReturnValue
public AtomicReferenceArrayAssertequals method to compare AtomicReferenceArray elements for incoming
- * assertion checks. This can be useful if actual's {@code equals} implementation does not suit you.
+ * Enable using a recursive field by field comparison strategy similar to {@link #usingRecursiveComparison()} but contrary to the latter you can chain any iterable assertions after this method (this is why this method exists).
*
+ *
*
+ *
*
+ *
*
+ * public class Person {
+ * String name;
+ * boolean hasPhd;
+ * }
*
- *
+ * // assertion succeeds as both lists contains equivalent items in order.
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(sheldon);
+ *
+ * // assertion fails because leonard names are different.
+ * leonard.setName("Leonard Ofstater");
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(leonard);
+ *
+ * // assertion fails because howard is missing and leonard is not expected.
+ * people = list(howard, sheldon, raj)
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator()
+ * .contains(howard); TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
- * TolkienCharacter pippin = new TolkienCharacter("Pippin", 28, HOBBIT);
- * frodo.setFriend(pippin);
- * pippin.setFriend(frodo);
+ * public class Doctor {
+ * String name;
+ * boolean hasPhd;
+ * }
*
- * TolkienCharacter frodoClone = new TolkienCharacter("Frodo", 33, HOBBIT);
- * TolkienCharacter pippinClone = new TolkienCharacter("Pippin", 28, HOBBIT);
- * frodoClone.setFriend(pippinClone);
- * pippinClone.setFriend(frodoClone);
+ * Doctor drSheldon = new Doctor("Sheldon Cooper", true);
+ * Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
+ * Doctor drRaj = new Doctor("Raj Koothrappali", true);
*
- * AtomicReferenceArray<TolkienCharacter> hobbits = new AtomicReferenceArray<>(new TolkienCharacter[] {frodo, pippin});
+ * Person sheldon = new Person("Sheldon Cooper", true);
+ * Person leonard = new Person("Leonard Hofstadter", true);
+ * Person raj = new Person("Raj Koothrappali", true);
+ * Person howard = new Person("Howard Wolowitz", true);
*
- * // fails if equals has not been overridden in TolkienCharacter as it would compares object references
- * assertThat(hobbits).contains(frodoClone, pippinClone);
+ * AtomicReferenceArray<Doctor> doctors = new AtomicReferenceArray<>(array(drSheldon, drLeonard, drRaj));
+ * AtomicReferenceArray<Person> persons = new AtomicReferenceArray<>(array(sheldon, leonard, raj));
*
- * // frodo/frodoClone and pippin/pippinClone are equals when doing a recursive property/field by property/field comparison
- * assertThat(hobbits).usingRecursiveFieldByFieldElementComparator()
- * .contains(frodoClone, pippinClone);
+ * The ordering can be ignored by calling {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} allowing ordered/unordered iterable comparison, note that {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} is applied recursively on any nested iterable fields, if this behavior is too generic,
+ * use the more fine grained {@link RecursiveComparisonAssert#ignoringCollectionOrderInFields(String...) ignoringCollectionOrderInFields} or
+ * {@link RecursiveComparisonAssert#ignoringCollectionOrderInFieldsMatchingRegexes(String...) ignoringCollectionOrderInFieldsMatchingRegexes}.
*
* @return {@code this} assertion object.
- * @since 2.7.0 / 3.7.0
+ * @since 2.7.0 / 3.7.0 - breaking change in 3.20.0
+ * @see RecursiveComparisonConfiguration
+ * @see usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)
*/
@CheckReturnValue
public AtomicReferenceArrayAssert
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * A detailed documentation for the recursive comparison is available here: https://assertj.github.io/doc/#assertj-core-recursive-comparison.
+ * public class Person {
+ * String name;
+ * boolean hasPhd;
+ * }
+ *
+ * public class Doctor {
+ * String name;
+ * boolean hasPhd;
+ * }
+ *
+ * Doctor drSheldon = new Doctor("Sheldon Cooper", true);
+ * Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
+ * Doctor drRaj = new Doctor("Raj Koothrappali", true);
+ *
+ * Person sheldon = new Person("Sheldon Cooper", false);
+ * Person leonard = new Person("Leonard Hofstadter", false);
+ * Person raj = new Person("Raj Koothrappali", false);
+ * Person howard = new Person("Howard Wolowitz", false);
+ *
+ * AtomicReferenceArray<Doctor> doctors = new AtomicReferenceArray<>(array(drSheldon, drLeonard, drRaj));
+ * AtomicReferenceArray<Person> persons = new AtomicReferenceArray<>(array(sheldon, leonard, raj));
+ *
+ * RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
+ * .withIgnoredFields("hasPhd");
+ *
+ * // assertion succeeds as both lists contains equivalent items in order.
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(sheldon);
+ *
+ * // assertion fails because leonard names are different.
+ * leonard.setName("Leonard Ofstater");
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(leonard);
+ *
+ * // assertion fails because howard is missing and leonard is not expected.
+ * people = list(howard, sheldon, raj)
+ * assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
+ * .contains(howard);
+ * The ordering can be ignored by calling {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} allowing ordered/unordered iterable comparison, note that {@link RecursiveComparisonAssert#ignoringCollectionOrder ignoringCollectionOrder} is applied recursively on any nested iterable fields, if this behavior is too generic,
+ * use the more fine grained {@link RecursiveComparisonAssert#ignoringCollectionOrderInFields(String...) ignoringCollectionOrderInFields} or
+ * {@link RecursiveComparisonAssert#ignoringCollectionOrderInFieldsMatchingRegexes(String...) ignoringCollectionOrderInFieldsMatchingRegexes}.
+ *
+ * @param configuration the recursive comparison configuration.
+ *
+ * @return {@code this} assertion object.
+ * @since 3.20.0
+ * @see RecursiveComparisonConfiguration
+ */
+ public AtomicReferenceArrayAssertequals method to compare AtomicReferenceArray elements for
* incoming assertion checks. Private fields are included but this can be disabled using
@@ -2029,7 +2327,13 @@ public AtomicReferenceArrayAssert