mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
216 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53152499d6 | ||
|
|
61d92fb33f | ||
|
|
8690f49c35 | ||
|
|
d808f664ec | ||
|
|
7f5f4820e9 | ||
|
|
f7a4427852 | ||
|
|
0e956bcd44 | ||
|
|
5395fc60e1 | ||
|
|
d8cae04a98 | ||
|
|
7b14711ecf | ||
|
|
c3351b9ee1 | ||
|
|
40b3c87b72 | ||
|
|
726db5ce5b | ||
|
|
99d359c548 | ||
|
|
4744113411 | ||
|
|
ae8f940f55 | ||
|
|
8d7633df2d | ||
|
|
4a351cfbe3 | ||
|
|
bb01447760 | ||
|
|
f12ed17b96 | ||
|
|
854e05f044 | ||
|
|
82c22682c0 | ||
|
|
25b3817876 | ||
|
|
e2a2b086ad | ||
|
|
5f9a0c5e17 | ||
|
|
2a0ae0af13 | ||
|
|
7a051146b6 | ||
|
|
d9398001cb | ||
|
|
0be99cb12a | ||
|
|
70e2d3d43f | ||
|
|
441258f9f2 | ||
|
|
b96efb533c | ||
|
|
5af067cc23 | ||
|
|
0c84665e38 | ||
|
|
9316d81fe3 | ||
|
|
ec96c044d5 | ||
|
|
ae4ed9273f | ||
|
|
0ec882e62e | ||
|
|
fef9ba23f4 | ||
|
|
3bd415b910 | ||
|
|
2128624261 | ||
|
|
c53fcace76 | ||
|
|
ff3759984c | ||
|
|
6358d1e2e1 | ||
|
|
db53631e76 | ||
|
|
86b2d929ab | ||
|
|
0db4462a64 | ||
|
|
f8667fc655 | ||
|
|
d91f94e879 | ||
|
|
ad6c8593f2 | ||
|
|
873ee47e8d | ||
|
|
fed281dc2b | ||
|
|
277d30467d | ||
|
|
064e0bbc8c | ||
|
|
3beadeec50 | ||
|
|
c2a26ed12f | ||
|
|
2419dad433 | ||
|
|
900d6eaf78 | ||
|
|
33d205e11f | ||
|
|
ee0651d9d3 | ||
|
|
fb22039fd3 | ||
|
|
cf294b8964 | ||
|
|
0004c8bc44 | ||
|
|
aedeeb0943 | ||
|
|
a68e5ae150 | ||
|
|
6a6354eb55 | ||
|
|
ab0a844f26 | ||
|
|
5105cb684f | ||
|
|
f128a7975f | ||
|
|
e572a3641d | ||
|
|
2b467832fb | ||
|
|
77557c80b1 | ||
|
|
9088369f89 | ||
|
|
36ef967f0e | ||
|
|
dd190ee056 | ||
|
|
4c32d3ce7a | ||
|
|
4608c00140 | ||
|
|
708317f314 | ||
|
|
636c1993d5 | ||
|
|
895875c849 | ||
|
|
1aea710c53 | ||
|
|
5085eb2f25 | ||
|
|
ad5b1c9917 | ||
|
|
34cab33b76 | ||
|
|
c836f1147f | ||
|
|
f43921f344 | ||
|
|
811e70ae3a | ||
|
|
5fd50e6181 | ||
|
|
3767341605 | ||
|
|
9f83eec36b | ||
|
|
126159878c | ||
|
|
78141b2528 | ||
|
|
56db8adb5a | ||
|
|
90b4baba12 | ||
|
|
54c56a4cc8 | ||
|
|
b123282778 | ||
|
|
f4562c7106 | ||
|
|
6211e7e651 | ||
|
|
3e4a01a673 | ||
|
|
a42353b41a | ||
|
|
d2ce18e33e | ||
|
|
7b81dc44e5 | ||
|
|
5e81719cea | ||
|
|
2f3788fc63 | ||
|
|
a98780cef2 | ||
|
|
ff0e30c885 | ||
|
|
4aacc58382 | ||
|
|
dec22b8633 | ||
|
|
37d8ea92c6 | ||
|
|
7eb46dd218 | ||
|
|
623bdd7344 | ||
|
|
c3ae1b5b92 | ||
|
|
19d3ba0505 | ||
|
|
9493f2d59a | ||
|
|
68ecd652f7 | ||
|
|
e67800e4e2 | ||
|
|
7f90f26830 | ||
|
|
6477c1899d | ||
|
|
03514f9f6a | ||
|
|
d11ac09bda | ||
|
|
667f83fd2f | ||
|
|
15ba59a9aa | ||
|
|
a46d6dc146 | ||
|
|
cf523bc811 | ||
|
|
9bd8095e0b | ||
|
|
6cfa9a0dfe | ||
|
|
7daa39a0b5 | ||
|
|
5fc7bc29ee | ||
|
|
83f3f8bedc | ||
|
|
12585a8969 | ||
|
|
72b701cae3 | ||
|
|
24e3251eb0 | ||
|
|
f124749a4f | ||
|
|
2a3d9c8dd5 | ||
|
|
0fa59a5cec | ||
|
|
d316e8ac70 | ||
|
|
53fe15c356 | ||
|
|
acb8b651b7 | ||
|
|
ace6bc2813 | ||
|
|
f69fef2f52 | ||
|
|
d033b84b5b | ||
|
|
3e702733bc | ||
|
|
f212e9476d | ||
|
|
da00863e34 | ||
|
|
476916f381 | ||
|
|
67bf5b98a8 | ||
|
|
db7757c556 | ||
|
|
bfd309800b | ||
|
|
0121f7b33c | ||
|
|
8dbff50a8b | ||
|
|
aec56ce025 | ||
|
|
1b8ffd86b9 | ||
|
|
ee7be7e3b2 | ||
|
|
57825decf0 | ||
|
|
2b3e11bd24 | ||
|
|
23cb29b6fc | ||
|
|
ba1dd2cd08 | ||
|
|
75a9786f8f | ||
|
|
0b4fd8ddd1 | ||
|
|
2eda393c03 | ||
|
|
512a3bebad | ||
|
|
db18d6a1fc | ||
|
|
75ca3030f7 | ||
|
|
f484c3f10b | ||
|
|
0753de05d1 | ||
|
|
ab0847e49f | ||
|
|
f9383e4e94 | ||
|
|
50b6c31675 | ||
|
|
63e78933ac | ||
|
|
cd0e962ef7 | ||
|
|
107d135894 | ||
|
|
0bc43a32b9 | ||
|
|
1024f0e671 | ||
|
|
3eb7cf740f | ||
|
|
2713a7ed67 | ||
|
|
8ba75245b4 | ||
|
|
b3d391c80d | ||
|
|
43a1ea1d6c | ||
|
|
c4fd4871fc | ||
|
|
23bbb34fb7 | ||
|
|
56a82e56c0 | ||
|
|
8f0d870fff | ||
|
|
d531ceb9c6 | ||
|
|
dc87aeda6c | ||
|
|
1668546450 | ||
|
|
fc9c20062a | ||
|
|
27e9fe79a5 | ||
|
|
e37280b752 | ||
|
|
fff368c80a | ||
|
|
37cbee0f0a | ||
|
|
141822b614 | ||
|
|
b1bfc1fd36 | ||
|
|
13684ec59d | ||
|
|
a51ff4de4e | ||
|
|
da9b313ff7 | ||
|
|
6a50fe2d9c | ||
|
|
ed32cbae06 | ||
|
|
00549a3ba6 | ||
|
|
13f1fa3167 | ||
|
|
6396def588 | ||
|
|
7599b0f22f | ||
|
|
08eb7e7699 | ||
|
|
89f918c23e | ||
|
|
f08fc344f5 | ||
|
|
99aa656a1e | ||
|
|
86fbaf7403 | ||
|
|
563012549a | ||
|
|
4f46eb30d2 | ||
|
|
2f30082127 | ||
|
|
548506fbbb | ||
|
|
bdef83bce5 | ||
|
|
f7f665681d | ||
|
|
7c0d544cf8 | ||
|
|
9390b6f571 | ||
|
|
176a833d89 | ||
|
|
3cacd27248 |
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@@ -9,16 +9,16 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-22.04 ]
|
||||
os: [ ubuntu-24.04 ]
|
||||
jdk: [ 17.0.13, 21.0.5, 23.0.1 ]
|
||||
distribution: [ temurin ]
|
||||
experimental: [ false ]
|
||||
include:
|
||||
- os: macos-14
|
||||
- os: macos-15
|
||||
jdk: 17.0.13
|
||||
distribution: temurin
|
||||
experimental: false
|
||||
- os: windows-2022
|
||||
- os: windows-2025
|
||||
jdk: 17.0.13
|
||||
distribution: temurin
|
||||
experimental: false
|
||||
@@ -26,14 +26,16 @@ jobs:
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
github.com:443
|
||||
github-registry-files.githubusercontent.com:443
|
||||
jitpack.io:443
|
||||
maven.pkg.github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
# We run the build twice for each supported JDK: once against the
|
||||
@@ -42,7 +44,7 @@ jobs:
|
||||
# additionally enabling all checks defined in this project and any Error
|
||||
# Prone checks available only from other artifact repositories.
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
java-distribution: ${{ matrix.distribution }}
|
||||
@@ -53,7 +55,9 @@ jobs:
|
||||
run: mvn -T1C install javadoc:jar
|
||||
- name: Build project with self-check against Error Prone fork
|
||||
run: mvn -T1C clean verify -Perror-prone-fork -Pnon-maven-central -Pself-check -s settings.xml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Remove installed project artifacts
|
||||
run: mvn build-helper:remove-project-artifact
|
||||
run: mvn dependency:purge-local-repository -DmanualInclude='${project.groupId}' -DresolutionFuzziness=groupId
|
||||
|
||||
# XXX: Enable Codecov once we "go public".
|
||||
|
||||
10
.github/workflows/codeql.yml
vendored
10
.github/workflows/codeql.yml
vendored
@@ -19,10 +19,10 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -34,19 +34,19 @@ jobs:
|
||||
repo.maven.apache.org:443
|
||||
uploads.github.com:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
|
||||
with:
|
||||
java-version: 17.0.13
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.9
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Perform minimal build
|
||||
if: matrix.language == 'java'
|
||||
run: mvn -T1C clean package -DskipTests -Dverification.skip
|
||||
- name: Perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
|
||||
with:
|
||||
category: /language:${{ matrix.language }}
|
||||
|
||||
13
.github/workflows/deploy-website.yml
vendored
13
.github/workflows/deploy-website.yml
vendored
@@ -9,10 +9,10 @@ concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -21,6 +21,7 @@ jobs:
|
||||
api.github.com:443
|
||||
bestpractices.coreinfrastructure.org:443
|
||||
blog.picnic.nl:443
|
||||
docs.github.com:443
|
||||
errorprone.info:443
|
||||
github.com:443
|
||||
img.shields.io:443
|
||||
@@ -39,10 +40,10 @@ jobs:
|
||||
www.youtube.com:443
|
||||
youtrack.jetbrains.com:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
|
||||
- uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
|
||||
with:
|
||||
working-directory: ./website
|
||||
bundler-cache: true
|
||||
@@ -68,13 +69,13 @@ jobs:
|
||||
permissions:
|
||||
id-token: write
|
||||
pages: write
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
|
||||
13
.github/workflows/openssf-scorecard.yml
vendored
13
.github/workflows/openssf-scorecard.yml
vendored
@@ -18,33 +18,36 @@ jobs:
|
||||
contents: read
|
||||
security-events: write
|
||||
id-token: write
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.deps.dev:443
|
||||
api.github.com:443
|
||||
api.osv.dev:443
|
||||
api.scorecard.dev:443
|
||||
api.securityscorecards.dev:443
|
||||
github.com:443
|
||||
index.docker.io:443
|
||||
oss-fuzz-build-logs.storage.googleapis.com:443
|
||||
repo.maven.apache.org:443
|
||||
*.sigstore.dev:443
|
||||
www.bestpractices.dev:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run OpenSSF Scorecard analysis
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
||||
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
publish_results: ${{ github.ref == 'refs/heads/master' }}
|
||||
- name: Update GitHub's code scanning dashboard
|
||||
uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
uses: github/codeql-action/upload-sarif@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
8
.github/workflows/pitest-analyze-pr.yml
vendored
8
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -9,10 +9,10 @@ permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
analyze-pr:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
|
||||
with:
|
||||
checkout-fetch-depth: 2
|
||||
java-version: 17.0.13
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
- name: Aggregate Pitest reports
|
||||
run: mvn pitest-git:aggregate -DkilledEmoji=":tada:" -DmutantEmoji=":zombie:" -DtrailingText="Mutation testing report by [Pitest](https://pitest.org/). Review any surviving mutants by inspecting the line comments under [_Files changed_](${{ github.event.number }}/files)."
|
||||
- name: Upload Pitest reports as artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: pitest-reports
|
||||
path: ./target/pit-reports-ci
|
||||
|
||||
6
.github/workflows/pitest-update-pr.yml
vendored
6
.github/workflows/pitest-update-pr.yml
vendored
@@ -17,10 +17,10 @@ jobs:
|
||||
checks: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
|
||||
with:
|
||||
java-version: 17.0.13
|
||||
java-distribution: temurin
|
||||
|
||||
32
.github/workflows/run-integration-tests.yml
vendored
32
.github/workflows/run-integration-tests.yml
vendored
@@ -1,9 +1,9 @@
|
||||
# If requested by means of a pull request comment, runs integration tests
|
||||
# against the project, using the code found on the pull request branch.
|
||||
# XXX: Generalize this to a matrix build of multiple integration tests,
|
||||
# possibly using multiple JDK or OS versions.
|
||||
# XXX: Investigate whether the comment can specify which integration tests run
|
||||
# run. See this example of a dynamic build matrix:
|
||||
# XXX: Review whether then build matrix should also vary JDK or OS versions.
|
||||
# XXX: Support `/integration-test [name...]` comment syntax to specify the
|
||||
# subset of integration tests to run.
|
||||
# See this example of a dynamic build matrix:
|
||||
# https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object
|
||||
name: "Integration tests"
|
||||
on:
|
||||
@@ -16,24 +16,34 @@ jobs:
|
||||
name: On-demand integration test
|
||||
if: |
|
||||
github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test')
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
integration-test: [ "checkstyle", "metrics", "prometheus-java-client" ]
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
# XXX: After updating the validation build flags in
|
||||
# `integration-tests/prometheus-java-client.sh`, review whether the
|
||||
# Docker domains specified here can be dropped.
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
auth.docker.io:443
|
||||
checkstyle.org:443
|
||||
example.com:80
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
oss.sonatype.org:443
|
||||
production.cloudflare.docker.com:443
|
||||
raw.githubusercontent.com:443
|
||||
registry-1.docker.io:443
|
||||
repo.maven.apache.org:443
|
||||
repository.sonatype.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
|
||||
with:
|
||||
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
|
||||
java-version: 17.0.13
|
||||
@@ -42,12 +52,12 @@ jobs:
|
||||
- name: Install project to local Maven repository
|
||||
run: mvn -T1C install -DskipTests -Dverification.skip
|
||||
- name: Run integration test
|
||||
run: xvfb-run ./integration-tests/checkstyle.sh "${{ runner.temp }}/artifacts"
|
||||
run: xvfb-run "./integration-tests/${{ matrix.integration-test }}.sh" "${{ runner.temp }}/artifacts"
|
||||
- name: Upload artifacts on failure
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: integration-test-checkstyle
|
||||
name: "integration-test-${{ matrix.integration-test }}"
|
||||
path: "${{ runner.temp }}/artifacts"
|
||||
- name: Remove installed project artifacts
|
||||
run: mvn build-helper:remove-project-artifact
|
||||
run: mvn dependency:purge-local-repository -DmanualInclude='${project.groupId}' -DresolutionFuzziness=groupId
|
||||
|
||||
6
.github/workflows/sonarcloud.yml
vendored
6
.github/workflows/sonarcloud.yml
vendored
@@ -16,10 +16,10 @@ jobs:
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
*.sonarcloud.io:443
|
||||
sonarcloud.io:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
|
||||
with:
|
||||
checkout-fetch-depth: 0
|
||||
java-version: 17.0.13
|
||||
|
||||
@@ -3,11 +3,24 @@
|
||||
"extends": [
|
||||
"helpers:pinGitHubActionDigests"
|
||||
],
|
||||
"customManagers": [
|
||||
{
|
||||
"customType": "regex",
|
||||
"fileMatch": [
|
||||
"^integration-tests/.*(-init\\.patch|\\.sh)$"
|
||||
],
|
||||
"matchStrings": [
|
||||
"\\b(?<packageName>[a-z0-9_.-]+?:[a-z0-9_.-]+?):(?<currentValue>[^:]+?):[a-zA-Z0-9_-]+\\b",
|
||||
"<version>(?<currentValue>.*?)<!-- Renovate: (?<packageName>.*?) --></version>"
|
||||
],
|
||||
"datasourceTemplate": "maven"
|
||||
}
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchPackagePatterns": [
|
||||
"^org\\.springframework:spring-framework-bom$",
|
||||
"^org\\.springframework\\.boot:spring-boot[a-z-]*$"
|
||||
"matchPackageNames": [
|
||||
"/^org\\.springframework:spring-framework-bom$/",
|
||||
"/^org\\.springframework\\.boot:spring-boot[a-z-]*$/"
|
||||
],
|
||||
"separateMinorPatch": true
|
||||
},
|
||||
|
||||
22
README.md
22
README.md
@@ -205,19 +205,20 @@ Relevant Maven build parameters:
|
||||
version of Error Prone. This is useful e.g. when testing a locally built
|
||||
Error Prone SNAPSHOT.
|
||||
- `-Perror-prone-fork` runs the build using Picnic's [Error Prone
|
||||
fork][error-prone-fork-repo], hosted on [Jitpack][error-prone-fork-jitpack].
|
||||
This fork generally contains a few changes on top of the latest Error Prone
|
||||
release.
|
||||
fork][error-prone-fork-repo], hosted using [GitHub
|
||||
Packages][error-prone-fork-packages]. This fork generally contains a few
|
||||
changes on top of the latest Error Prone release. Using this profile
|
||||
generally requires passing `-s settings.xml`, with [suitably
|
||||
configured][github-packages-auth] `GITHUB_ACTOR` and `GITHUB_TOKEN`
|
||||
environment variables.
|
||||
- `-Pself-check` runs the checks defined by this project against itself.
|
||||
Pending a release of [google/error-prone#3301][error-prone-pull-3301], this
|
||||
flag must currently be used in combination with `-Perror-prone-fork`.
|
||||
|
||||
Other highly relevant commands:
|
||||
|
||||
- `mvn fmt:format` formats the code using
|
||||
[`google-java-format`][google-java-format].
|
||||
- [`./run-full-build.sh`][script-run-full-build] builds the project twice,
|
||||
where the second pass validates compatbility with Picnic's [Error Prone
|
||||
where the second pass validates compatibility with Picnic's [Error Prone
|
||||
fork][error-prone-fork-repo] and compliance of the code with any rules
|
||||
defined within this project. (Consider running this before [opening a pull
|
||||
request][contributing-pull-request], as the PR checks also perform this
|
||||
@@ -235,8 +236,9 @@ Other highly relevant commands:
|
||||
against _all_ code in the current working directory. For more information
|
||||
check the [PIT Maven plugin][pitest-maven].
|
||||
|
||||
When running the project's tests in IntelliJ IDEA, you might see the following
|
||||
error:
|
||||
Opening the project in IntelliJ IDEA may require running `mvn clean install`
|
||||
first. Additionally, when running the project's tests using the IDE, you might
|
||||
see the following error:
|
||||
|
||||
```
|
||||
java: exporting a package from system module jdk.compiler is not allowed with --release
|
||||
@@ -274,14 +276,14 @@ channel; please see our [security policy][security] for details.
|
||||
[contributing]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md
|
||||
[contributing-pull-request]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md#-opening-a-pull-request
|
||||
[error-prone-bugchecker]: https://github.com/google/error-prone/blob/master/check_api/src/main/java/com/google/errorprone/bugpatterns/BugChecker.java
|
||||
[error-prone-fork-jitpack]: https://jitpack.io/#PicnicSupermarket/error-prone
|
||||
[error-prone-fork-packages]: https://github.com/PicnicSupermarket/error-prone/packages
|
||||
[error-prone-fork-repo]: https://github.com/PicnicSupermarket/error-prone
|
||||
[error-prone-gradle-installation-guide]: https://github.com/tbroyer/gradle-errorprone-plugin
|
||||
[error-prone-installation-guide]: https://errorprone.info/docs/installation#maven
|
||||
[error-prone-orig-repo]: https://github.com/google/error-prone
|
||||
[error-prone-pull-3301]: https://github.com/google/error-prone/pull/3301
|
||||
[github-actions-build-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml/badge.svg
|
||||
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml?query=branch:master&event=push
|
||||
[github-packages-auth]: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages
|
||||
[google-java-format]: https://github.com/google/google-java-format
|
||||
[idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052
|
||||
[license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.19.1</version>
|
||||
<version>0.21.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>documentation-support</artifactId>
|
||||
@@ -15,24 +15,6 @@
|
||||
<url>https://error-prone.picnic.tech</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_annotation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_check_api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_test_helpers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>error-prone-utils</artifactId>
|
||||
@@ -72,6 +54,24 @@
|
||||
<artifactId>auto-value-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_annotation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_check_api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_test_helpers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.19.1</version>
|
||||
<version>0.21.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
@@ -15,31 +15,6 @@
|
||||
<url>https://error-prone.picnic.tech</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_annotation</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_check_api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_test_helpers</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>documentation-support</artifactId>
|
||||
@@ -87,6 +62,31 @@
|
||||
<artifactId>auto-value-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_annotation</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_check_api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_test_helpers</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
@@ -167,6 +167,11 @@
|
||||
<artifactId>value-annotations</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jooq</groupId>
|
||||
<artifactId>jooq</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<artifactId>jspecify</artifactId>
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.TypeCastTree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
@@ -48,11 +49,14 @@ public final class ClassCastLambdaUsage extends BugChecker implements LambdaExpr
|
||||
}
|
||||
|
||||
Type type = ASTHelpers.getType(typeCast);
|
||||
if (type == null || type.isParameterized() || type.isPrimitive()) {
|
||||
if (type == null
|
||||
|| type.isParameterized()
|
||||
|| type.isPrimitive()
|
||||
|| type.getKind() == TypeKind.TYPEVAR) {
|
||||
/*
|
||||
* The method reference syntax does not support casting to parameterized types. Additionally,
|
||||
* `Class#cast` does not support the same range of type conversions between (boxed) primitive
|
||||
* types as the cast operator.
|
||||
* The method reference syntax does not support casting to parameterized types, and type
|
||||
* variables aren't supported either. Additionally, `Class#cast` does not support the same
|
||||
* range of type conversions between (boxed) primitive types as the cast operator.
|
||||
*/
|
||||
// XXX: Depending on the declared type of the value being cast, in some cases we _can_ rewrite
|
||||
// primitive casts. Add support for this.
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Verify;
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Var;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import java.util.Collections;
|
||||
import java.util.Formattable;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags {@link String#format} and {@link String#formatted} invocations
|
||||
* that can be omitted by delegating to another format method.
|
||||
*/
|
||||
// XXX: The special-casing of Throwable applies only to SLF4J 1.6.0+; see
|
||||
// https://www.slf4j.org/faq.html#paramException. That should be documented.
|
||||
// XXX: Some of the `Matcher`s defined here are also declared by the `Slf4jLogStatement` and
|
||||
// `RedundantStringConversion` checks. Look into deduplicating them.
|
||||
// XXX: Should we also simplify e.g. `LOG.error(String.join("sep", arg1, arg2), throwable)`? Perhaps
|
||||
// that's too obscure.
|
||||
// XXX: This check currently only flags string format expressions that are a direct argument to
|
||||
// another format-capable method invocation. Indirect cases, such as where the result is assigned to
|
||||
// a variable, are currently not covered.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "String formatting can be deferred",
|
||||
link = BUG_PATTERNS_BASE_URL + "EagerStringFormatting",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = {PERFORMANCE, SIMPLIFICATION})
|
||||
public final class EagerStringFormatting extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> FORMATTABLE = isSubtypeOf(Formattable.class);
|
||||
private static final Matcher<ExpressionTree> LOCALE = isSubtypeOf(Locale.class);
|
||||
private static final Matcher<ExpressionTree> SLF4J_MARKER = isSubtypeOf("org.slf4j.Marker");
|
||||
private static final Matcher<ExpressionTree> THROWABLE = isSubtypeOf(Throwable.class);
|
||||
private static final Matcher<ExpressionTree> REQUIRE_NON_NULL_INVOCATION =
|
||||
staticMethod().onClass(Objects.class.getCanonicalName()).named("requireNonNull");
|
||||
private static final Matcher<ExpressionTree> GUAVA_GUARD_INVOCATION =
|
||||
anyOf(
|
||||
staticMethod()
|
||||
.onClass(Preconditions.class.getCanonicalName())
|
||||
.namedAnyOf("checkArgument", "checkNotNull", "checkState"),
|
||||
staticMethod()
|
||||
.onClass(Verify.class.getCanonicalName())
|
||||
.namedAnyOf("verify", "verifyNotNull"));
|
||||
private static final Matcher<ExpressionTree> SLF4J_LOGGER_INVOCATION =
|
||||
instanceMethod()
|
||||
.onDescendantOf("org.slf4j.Logger")
|
||||
.namedAnyOf("trace", "debug", "info", "warn", "error");
|
||||
private static final Matcher<ExpressionTree> STATIC_FORMAT_STRING =
|
||||
staticMethod().onClass(String.class.getCanonicalName()).named("format");
|
||||
private static final Matcher<ExpressionTree> INSTANCE_FORMAT_STRING =
|
||||
instanceMethod().onDescendantOf(String.class.getCanonicalName()).named("formatted");
|
||||
private static final String MESSAGE_NEVER_NULL_ARGUMENT =
|
||||
"String formatting never yields `null` expression";
|
||||
|
||||
/** Instantiates a new {@link EagerStringFormatting} instance. */
|
||||
public EagerStringFormatting() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
Tree parent = state.getPath().getParentPath().getLeaf();
|
||||
if (!(parent instanceof MethodInvocationTree methodInvocation)) {
|
||||
/*
|
||||
* Fast path: this isn't a method invocation whose result is an argument to another method
|
||||
* invocation.
|
||||
*/
|
||||
// XXX: This logic assumes that the string format operation isn't redundantly wrapped in
|
||||
// parentheses. Similar assumptions likely exist throughout the code base. Investigate how to
|
||||
// structurally cover such cases.
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return StringFormatExpression.tryCreate(tree, state)
|
||||
.map(expr -> analyzeFormatStringContext(expr, methodInvocation, state))
|
||||
.orElse(Description.NO_MATCH);
|
||||
}
|
||||
|
||||
private Description analyzeFormatStringContext(
|
||||
StringFormatExpression stringFormat, MethodInvocationTree context, VisitorState state) {
|
||||
if (REQUIRE_NON_NULL_INVOCATION.matches(context, state)) {
|
||||
return analyzeRequireNonNullStringFormatContext(stringFormat, context);
|
||||
}
|
||||
|
||||
if (GUAVA_GUARD_INVOCATION.matches(context, state)) {
|
||||
return analyzeGuavaGuardStringFormatContext(stringFormat, context, state);
|
||||
}
|
||||
|
||||
if (SLF4J_LOGGER_INVOCATION.matches(context, state)) {
|
||||
return analyzeSlf4jLoggerStringFormatContext(stringFormat, context, state);
|
||||
}
|
||||
|
||||
/*
|
||||
* The string formatting operation does not appear to happen in a context that admits of
|
||||
* simplification or optimization.
|
||||
*/
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
private Description analyzeRequireNonNullStringFormatContext(
|
||||
StringFormatExpression stringFormat, MethodInvocationTree context) {
|
||||
List<? extends ExpressionTree> arguments = context.getArguments();
|
||||
if (arguments.size() != 2 || arguments.get(0).equals(stringFormat.expression())) {
|
||||
/* Vacuous validation that string formatting doesn't yield `null`. */
|
||||
return buildDescription(context).setMessage(MESSAGE_NEVER_NULL_ARGUMENT).build();
|
||||
}
|
||||
|
||||
if (stringFormat.arguments().stream()
|
||||
.anyMatch(EagerStringFormatting::isNonFinalLocalVariable)) {
|
||||
/*
|
||||
* The format operation depends on a variable that isn't final or effectively final; moving
|
||||
* it into a lambda expression would cause a compilation error.
|
||||
*/
|
||||
return buildDescription(context)
|
||||
.setMessage(message() + " (but this requires introducing an effectively final variable)")
|
||||
.build();
|
||||
}
|
||||
|
||||
/* Suggest that the string formatting is deferred. */
|
||||
return describeMatch(context, SuggestedFix.prefixWith(stringFormat.expression(), "() -> "));
|
||||
}
|
||||
|
||||
private Description analyzeGuavaGuardStringFormatContext(
|
||||
StringFormatExpression stringFormat, MethodInvocationTree context, VisitorState state) {
|
||||
List<? extends ExpressionTree> arguments = context.getArguments();
|
||||
if (arguments.get(0).equals(stringFormat.expression())) {
|
||||
/*
|
||||
* Vacuous `checkNotNull` or `verifyNotNull` validation that string formatting doesn't yield
|
||||
* `null`.
|
||||
*/
|
||||
return buildDescription(context).setMessage(MESSAGE_NEVER_NULL_ARGUMENT).build();
|
||||
}
|
||||
|
||||
if (stringFormat.simplifiableFormatString().isEmpty() || arguments.size() > 2) {
|
||||
/*
|
||||
* The format string cannot be simplified, or the format string produces a format string
|
||||
* itself, or its result is the input to another format operation. These are complex cases
|
||||
* that we'll only flag.
|
||||
*/
|
||||
return createSimplificationSuggestion(context, "Guava");
|
||||
}
|
||||
|
||||
return describeMatch(context, stringFormat.suggestFlattening("%s", state));
|
||||
}
|
||||
|
||||
private Description analyzeSlf4jLoggerStringFormatContext(
|
||||
StringFormatExpression stringFormat, MethodInvocationTree context, VisitorState state) {
|
||||
if (stringFormat.simplifiableFormatString().isEmpty()) {
|
||||
/* We can't simplify this case; only flag it. */
|
||||
return createSimplificationSuggestion(context, "SLF4J");
|
||||
}
|
||||
|
||||
List<? extends ExpressionTree> arguments = context.getArguments();
|
||||
int leftOffset = SLF4J_MARKER.matches(arguments.get(0), state) ? 1 : 0;
|
||||
int rightOffset = THROWABLE.matches(arguments.get(arguments.size() - 1), state) ? 1 : 0;
|
||||
if (arguments.size() != leftOffset + 1 + rightOffset) {
|
||||
/*
|
||||
* The format string produces a format string itself, or its result is the input to another
|
||||
* format operation. This is a complex case that we'll only flag.
|
||||
*/
|
||||
return createSimplificationSuggestion(context, "SLF4J");
|
||||
}
|
||||
|
||||
return describeMatch(context, stringFormat.suggestFlattening("{}", state));
|
||||
}
|
||||
|
||||
private static boolean isNonFinalLocalVariable(Tree tree) {
|
||||
Symbol symbol = ASTHelpers.getSymbol(tree);
|
||||
return symbol instanceof VarSymbol
|
||||
&& symbol.owner instanceof MethodSymbol
|
||||
&& !ASTHelpers.isConsideredFinal(symbol);
|
||||
}
|
||||
|
||||
private Description createSimplificationSuggestion(MethodInvocationTree context, String library) {
|
||||
return buildDescription(context)
|
||||
.setMessage(
|
||||
"%s (assuming that %s's simplified formatting support suffices)"
|
||||
.formatted(message(), library))
|
||||
.build();
|
||||
}
|
||||
|
||||
/** Description of a string format expression. */
|
||||
@AutoValue
|
||||
abstract static class StringFormatExpression {
|
||||
/** The full string format expression. */
|
||||
abstract MethodInvocationTree expression();
|
||||
|
||||
/** The format string expression. */
|
||||
abstract Tree formatString();
|
||||
|
||||
/** The string format arguments to be plugged into its format string. */
|
||||
abstract ImmutableList<ExpressionTree> arguments();
|
||||
|
||||
/**
|
||||
* The constant format string, if it contains only {@code %s} placeholders, and the number of
|
||||
* said placeholders matches the number of format arguments.
|
||||
*/
|
||||
abstract Optional<String> simplifiableFormatString();
|
||||
|
||||
private SuggestedFix suggestFlattening(String newPlaceholder, VisitorState state) {
|
||||
return SuggestedFix.replace(
|
||||
expression(),
|
||||
Stream.concat(
|
||||
Stream.of(deriveFormatStringExpression(newPlaceholder, state)),
|
||||
arguments().stream().map(arg -> SourceCode.treeToString(arg, state)))
|
||||
.collect(joining(", ")));
|
||||
}
|
||||
|
||||
private String deriveFormatStringExpression(String newPlaceholder, VisitorState state) {
|
||||
String formatString =
|
||||
String.format(
|
||||
simplifiableFormatString()
|
||||
.orElseThrow(() -> new VerifyException("Format string cannot be simplified")),
|
||||
Collections.nCopies(arguments().size(), newPlaceholder).toArray());
|
||||
|
||||
/*
|
||||
* If the suggested replacement format string is the same as the original, then use the
|
||||
* expression's existing source code representation. This way string constant references are
|
||||
* not unnecessarily replaced.
|
||||
*/
|
||||
return formatString.equals(ASTHelpers.constValue(formatString(), String.class))
|
||||
? SourceCode.treeToString(formatString(), state)
|
||||
: SourceCode.toStringConstantExpression(formatString, state);
|
||||
}
|
||||
|
||||
private static Optional<StringFormatExpression> tryCreate(
|
||||
MethodInvocationTree tree, VisitorState state) {
|
||||
if (INSTANCE_FORMAT_STRING.matches(tree, state)) {
|
||||
return Optional.of(
|
||||
create(
|
||||
tree,
|
||||
requireNonNull(ASTHelpers.getReceiver(tree), "Receiver unexpectedly absent"),
|
||||
ImmutableList.copyOf(tree.getArguments()),
|
||||
state));
|
||||
}
|
||||
|
||||
if (STATIC_FORMAT_STRING.matches(tree, state)) {
|
||||
List<? extends ExpressionTree> arguments = tree.getArguments();
|
||||
int argOffset = LOCALE.matches(arguments.get(0), state) ? 1 : 0;
|
||||
return Optional.of(
|
||||
create(
|
||||
tree,
|
||||
arguments.get(argOffset),
|
||||
ImmutableList.copyOf(arguments.subList(argOffset + 1, arguments.size())),
|
||||
state));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static StringFormatExpression create(
|
||||
MethodInvocationTree expression,
|
||||
Tree formatString,
|
||||
ImmutableList<ExpressionTree> arguments,
|
||||
VisitorState state) {
|
||||
return new AutoValue_EagerStringFormatting_StringFormatExpression(
|
||||
expression,
|
||||
formatString,
|
||||
arguments,
|
||||
Optional.ofNullable(ASTHelpers.constValue(formatString, String.class))
|
||||
.filter(template -> isSimplifiable(template, arguments, state)));
|
||||
}
|
||||
|
||||
private static boolean isSimplifiable(
|
||||
String formatString, ImmutableList<ExpressionTree> arguments, VisitorState state) {
|
||||
if (arguments.stream().anyMatch(arg -> FORMATTABLE.matches(arg, state))) {
|
||||
/* `Formattable` arguments can have arbitrary format semantics. */
|
||||
return false;
|
||||
}
|
||||
|
||||
@Var int placeholderCount = 0;
|
||||
for (int p = formatString.indexOf('%'); p != -1; p = formatString.indexOf('%', p + 2)) {
|
||||
if (p == formatString.length() - 1) {
|
||||
/* Malformed format string with trailing `%`. */
|
||||
return false;
|
||||
}
|
||||
|
||||
char modifier = formatString.charAt(p + 1);
|
||||
if (modifier == 's') {
|
||||
placeholderCount++;
|
||||
} else if (modifier != '%') {
|
||||
/* Only `%s` and `%%` (a literal `%`) are supported. */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return placeholderCount == arguments.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.symbolMatcher;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.google.errorprone.util.Visibility;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.Element;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags single-argument method invocations with an iterable of explicitly
|
||||
* enumerated values, for which a semantically equivalent varargs variant (appears to) exists as
|
||||
* well.
|
||||
*
|
||||
* <p>This check drops selected {@link ImmutableSet#of} and {@link Set#of} invocations, with the
|
||||
* assumption that these operations do not deduplicate the collection of explicitly enumerated
|
||||
* values. It also drops {@link ImmutableMultiset#of} and {@link Set#of} invocations, with the
|
||||
* assumption that these do not materially impact iteration order.
|
||||
*
|
||||
* <p>This checker attempts to identify {@link Iterable}-accepting methods for which a varargs
|
||||
* overload exists, and suggests calling the varargs overload instead. This is an imperfect
|
||||
* heuristic, but it e.g. allows invocations of <a
|
||||
* href="https://immutables.github.io/immutable.html#copy-methods">Immutables-generated {@code
|
||||
* with*}</a> methods to be simplified.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Iterable creation can be avoided by using a varargs alternative method",
|
||||
link = BUG_PATTERNS_BASE_URL + "ExplicitArgumentEnumeration",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = {PERFORMANCE, SIMPLIFICATION})
|
||||
public final class ExplicitArgumentEnumeration extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> EXPLICIT_ITERABLE_CREATOR =
|
||||
anyOf(
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
ImmutableList.class.getCanonicalName(),
|
||||
ImmutableMultiset.class.getCanonicalName(),
|
||||
ImmutableSet.class.getCanonicalName(),
|
||||
List.class.getCanonicalName(),
|
||||
Set.class.getCanonicalName())
|
||||
.named("of"),
|
||||
allOf(
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
ImmutableList.class.getCanonicalName(),
|
||||
ImmutableMultiset.class.getCanonicalName(),
|
||||
ImmutableSet.class.getCanonicalName())
|
||||
.named("copyOf"),
|
||||
symbolMatcher(
|
||||
(symbol, state) ->
|
||||
state
|
||||
.getSymtab()
|
||||
.arrayClass
|
||||
.equals(((MethodSymbol) symbol).params().get(0).type.tsym))),
|
||||
staticMethod().onClass(Arrays.class.getCanonicalName()).named("asList"));
|
||||
private static final Matcher<ExpressionTree> IMMUTABLE_COLLECTION_BUILDER =
|
||||
instanceMethod().onDescendantOf(ImmutableCollection.Builder.class.getCanonicalName());
|
||||
private static final Matcher<ExpressionTree> OBJECT_ENUMERABLE_ASSERT =
|
||||
instanceMethod().onDescendantOf("org.assertj.core.api.ObjectEnumerableAssert");
|
||||
private static final Matcher<ExpressionTree> STEP_VERIFIER_STEP =
|
||||
instanceMethod().onDescendantOf("reactor.test.StepVerifier.Step");
|
||||
private static final ImmutableTable<Matcher<ExpressionTree>, String, String> ALTERNATIVE_METHODS =
|
||||
ImmutableTable.<Matcher<ExpressionTree>, String, String>builder()
|
||||
.put(IMMUTABLE_COLLECTION_BUILDER, "addAll", "add")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsAnyElementsOf", "containsAnyOf")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsAll", "contains")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsExactlyElementsOf", "containsExactly")
|
||||
.put(
|
||||
OBJECT_ENUMERABLE_ASSERT,
|
||||
"containsExactlyInAnyOrderElementsOf",
|
||||
"containsExactlyInAnyOrder")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsOnlyElementsOf", "containsOnly")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsOnlyOnceElementsOf", "containsOnlyOnce")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "doesNotContainAnyElementsOf", "doesNotContain")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "hasSameElementsAs", "containsOnly")
|
||||
.put(STEP_VERIFIER_STEP, "expectNextSequence", "expectNext")
|
||||
.buildOrThrow();
|
||||
|
||||
/** Instantiates a new {@link ExplicitArgumentEnumeration} instance. */
|
||||
public ExplicitArgumentEnumeration() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
if (tree.getArguments().size() != 1) {
|
||||
/* Performance optimization: non-unary method invocations cannot be simplified. */
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
MethodSymbol method = ASTHelpers.getSymbol(tree);
|
||||
if (!isUnaryIterableAcceptingMethod(method, state) || isLocalOverload(method, state)) {
|
||||
/*
|
||||
* This isn't a method invocation we can simplify, or it's an invocation of a local overload.
|
||||
* The latter type of invocation we do not suggest replacing, as this is fairly likely to
|
||||
* introduce an unbounded recursive call chain.
|
||||
*/
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
ExpressionTree argument = tree.getArguments().get(0);
|
||||
if (!EXPLICIT_ITERABLE_CREATOR.matches(argument, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return trySuggestCallingVarargsOverload(method, (MethodInvocationTree) argument, state)
|
||||
.or(() -> trySuggestCallingCustomAlternative(tree, (MethodInvocationTree) argument, state))
|
||||
.map(fix -> describeMatch(tree, fix))
|
||||
.orElse(Description.NO_MATCH);
|
||||
}
|
||||
|
||||
private static boolean isUnaryIterableAcceptingMethod(MethodSymbol method, VisitorState state) {
|
||||
List<VarSymbol> params = method.params();
|
||||
return !method.isVarArgs()
|
||||
&& params.size() == 1
|
||||
&& ASTHelpers.isSubtype(params.get(0).type, state.getSymtab().iterableType, state);
|
||||
}
|
||||
|
||||
private static boolean isLocalOverload(MethodSymbol calledMethod, VisitorState state) {
|
||||
MethodTree enclosingMethod = state.findEnclosing(MethodTree.class);
|
||||
if (enclosingMethod == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MethodSymbol callingMethod = ASTHelpers.getSymbol(enclosingMethod);
|
||||
return Objects.equals(callingMethod.getEnclosingElement(), calledMethod.getEnclosingElement())
|
||||
&& callingMethod.getSimpleName().equals(calledMethod.getSimpleName());
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> trySuggestCallingVarargsOverload(
|
||||
MethodSymbol method, MethodInvocationTree argument, VisitorState state) {
|
||||
/*
|
||||
* Collect all overloads of the given method that we are sure to be able to call. Note that the
|
||||
* `isAtLeastAsVisible` check is conservative heuristic.
|
||||
*/
|
||||
ImmutableList<MethodSymbol> overloads =
|
||||
ASTHelpers.matchingMethods(
|
||||
method.getSimpleName(),
|
||||
m -> isAtLeastAsVisible(m, method),
|
||||
method.enclClass().type,
|
||||
state.getTypes())
|
||||
.collect(toImmutableList());
|
||||
|
||||
/*
|
||||
* If all overloads have a single parameter, and at least one of them is a varargs method, then
|
||||
* we assume that unwrapping the iterable argument will cause a suitable overload to be invoked.
|
||||
* (Note that there may be multiple varargs overloads, either with different parameter types, or
|
||||
* due to method overriding; this check does not attempt to determine which exact method or
|
||||
* overload will be invoked as a result of the suggested simplification.)
|
||||
*
|
||||
* Note that this is a (highly!) imperfect heuristic, but it is sufficient to prevent e.g.
|
||||
* unwrapping of arguments to `org.jooq.impl.DSL#row`, which can cause the expression's return
|
||||
* type to change from `RowN` to (e.g.) `Row2`.
|
||||
*/
|
||||
// XXX: There are certainly cases where it _would_ be nice to unwrap the arguments to
|
||||
// `org.jooq.impl.DSL#row(Collection<?>)`. Look into this.
|
||||
// XXX: Ideally we do check that one of the overloads accepts the unwrapped arguments.
|
||||
// XXX: Ideally we validate that eligible overloads have compatible return types.
|
||||
boolean hasLikelySuitableVarargsOverload =
|
||||
overloads.stream().allMatch(m -> m.params().size() == 1)
|
||||
&& overloads.stream().anyMatch(MethodSymbol::isVarArgs);
|
||||
|
||||
return hasLikelySuitableVarargsOverload
|
||||
? Optional.of(SourceCode.unwrapMethodInvocation(argument, state))
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> trySuggestCallingCustomAlternative(
|
||||
MethodInvocationTree tree, MethodInvocationTree argument, VisitorState state) {
|
||||
return ALTERNATIVE_METHODS.rowMap().entrySet().stream()
|
||||
.filter(e -> e.getKey().matches(tree, state))
|
||||
.findFirst()
|
||||
.flatMap(e -> trySuggestCallingCustomAlternative(tree, argument, state, e.getValue()));
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> trySuggestCallingCustomAlternative(
|
||||
MethodInvocationTree tree,
|
||||
MethodInvocationTree argument,
|
||||
VisitorState state,
|
||||
Map<String, String> alternatives) {
|
||||
return Optional.ofNullable(
|
||||
alternatives.get(ASTHelpers.getSymbol(tree).getSimpleName().toString()))
|
||||
.map(
|
||||
replacement ->
|
||||
SuggestedFix.builder()
|
||||
.merge(SuggestedFixes.renameMethodInvocation(tree, replacement, state))
|
||||
.merge(SourceCode.unwrapMethodInvocation(argument, state))
|
||||
.build());
|
||||
}
|
||||
|
||||
private static boolean isAtLeastAsVisible(Element symbol, Element reference) {
|
||||
return Visibility.fromModifiers(symbol.getModifiers())
|
||||
.compareTo(Visibility.fromModifiers(reference.getModifiers()))
|
||||
>= 0;
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
@@ -84,6 +85,7 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca
|
||||
ImmutableSetMultimap.class.getCanonicalName(),
|
||||
ImmutableTable.class.getCanonicalName())
|
||||
.named("copyOf"),
|
||||
staticMethod().onClass(Instant.class.getCanonicalName()).namedAnyOf("from"),
|
||||
staticMethod().onClass(Matchers.class.getCanonicalName()).namedAnyOf("allOf", "anyOf"),
|
||||
staticMethod().onClass("reactor.adapter.rxjava.RxJava2Adapter"),
|
||||
staticMethod()
|
||||
|
||||
@@ -101,6 +101,8 @@ public final class JUnitMethodDeclaration extends BugChecker implements MethodTr
|
||||
.build());
|
||||
}
|
||||
|
||||
// XXX: Consider dropping leading underscores that otherwise result when canonicalizing
|
||||
// `test_some_method_name`.
|
||||
private static Optional<String> tryCanonicalizeMethodName(MethodSymbol symbol) {
|
||||
return Optional.of(symbol.getQualifiedName().toString())
|
||||
.filter(name -> name.startsWith(TEST_PREFIX))
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import java.time.Clock;
|
||||
import java.time.InstantSource;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
@@ -69,6 +70,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
|
||||
ImmutableSet.of(
|
||||
ASTHelpers.class.getCanonicalName(),
|
||||
Clock.class.getCanonicalName(),
|
||||
InstantSource.class.getCanonicalName(),
|
||||
Strings.class.getCanonicalName(),
|
||||
VisitorState.class.getCanonicalName(),
|
||||
ZoneOffset.class.getCanonicalName(),
|
||||
@@ -129,6 +131,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
|
||||
"builder",
|
||||
"copyOf",
|
||||
"create",
|
||||
"EPOCH",
|
||||
"from",
|
||||
"getDefaultInstance",
|
||||
"INSTANCE",
|
||||
@@ -182,7 +185,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
|
||||
}
|
||||
}
|
||||
|
||||
return imports.build();
|
||||
return imports.buildOrThrow();
|
||||
}
|
||||
|
||||
private static boolean shouldNotBeStaticallyImported(String type, String member) {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.LiteralTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} that flags string constants with extraneous escaping. */
|
||||
// XXX: Also cover `\"` sequences inside text blocks. Note that this requires a more subtle
|
||||
// approach, as double-quote characters will need to remain escaped if removing the backslash would
|
||||
// create a new sequence of three or more double-quotes. (TBD whether we'd like to enforce a
|
||||
// "preferred" approach to escaping, e.g. by always escaping the last of a triplet, such that the
|
||||
// over-all number of escaped characters is minimized.)
|
||||
// XXX: Also flag `'\"'` char literals.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Inside string expressions single quotes do not need to be escaped",
|
||||
link = BUG_PATTERNS_BASE_URL + "RedundantStringEscape",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class RedundantStringEscape extends BugChecker implements LiteralTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Instantiates a new {@link RedundantStringEscape} instance. */
|
||||
public RedundantStringEscape() {}
|
||||
|
||||
@Override
|
||||
public Description matchLiteral(LiteralTree tree, VisitorState state) {
|
||||
String constant = ASTHelpers.constValue(tree, String.class);
|
||||
if (constant == null || constant.indexOf('\'') < 0) {
|
||||
/* Fast path: this isn't a string constant with a single quote. */
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
String source = SourceCode.treeToString(tree, state);
|
||||
if (!containsBannedEscapeSequence(source)) {
|
||||
/* Semi-fast path: this expression doesn't contain an escaped single quote. */
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/* Slow path: suggest dropping the escape characters. */
|
||||
return describeMatch(tree, SuggestedFix.replace(tree, dropRedundantEscapeSequences(source)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given string constant source expression contains an escaped single quote.
|
||||
*
|
||||
* @implNote As the input is a literal Java string expression, it will start and end with a double
|
||||
* quote; as such any found backslash will not be the string's final character.
|
||||
*/
|
||||
private static boolean containsBannedEscapeSequence(String source) {
|
||||
for (int p = source.indexOf('\\'); p != -1; p = source.indexOf('\\', p + 2)) {
|
||||
if (source.charAt(p + 1) == '\'') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplifies the given string constant source expression by dropping the backslash preceding an
|
||||
* escaped single quote.
|
||||
*
|
||||
* @implNote Note that this method does not delegate to {@link
|
||||
* SourceCode#toStringConstantExpression}, as that operation may replace other Unicode
|
||||
* characters with their associated escape sequence.
|
||||
* @implNote As the input is a literal Java string expression, it will start and end with a double
|
||||
* quote; as such any found backslash will not be the string's final character.
|
||||
*/
|
||||
private static String dropRedundantEscapeSequences(String source) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
for (int p = 0; p < source.length(); p++) {
|
||||
char c = source.charAt(p);
|
||||
if (c != '\\' || source.charAt(p + 1) != '\'') {
|
||||
result.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,6 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
/** A {@link BugChecker} that flags SLF4J usages that are likely to be in error. */
|
||||
// XXX: The special-casing of Throwable applies only to SLF4J 1.6.0+; see
|
||||
// https://www.slf4j.org/faq.html#paramException. That should be documented.
|
||||
// XXX: Also simplify `LOG.error(String.format("Something %s", arg), throwable)`.
|
||||
// XXX: Also simplify `LOG.error(String.join("sep", arg1, arg2), throwable)`? Perhaps too obscure.
|
||||
// XXX: Write a similar checker for Spring RestTemplates, String.format and friends, Guava
|
||||
// preconditions, ...
|
||||
@AutoService(BugChecker.class)
|
||||
@@ -41,7 +39,7 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
tags = LIKELY_ERROR)
|
||||
public final class Slf4jLogStatement extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> MARKER = isSubtypeOf("org.slf4j.Marker");
|
||||
private static final Matcher<ExpressionTree> SLF4J_MARKER = isSubtypeOf("org.slf4j.Marker");
|
||||
private static final Matcher<ExpressionTree> THROWABLE = isSubtypeOf(Throwable.class);
|
||||
private static final Matcher<ExpressionTree> SLF4J_LOGGER_INVOCATION =
|
||||
instanceMethod()
|
||||
@@ -71,7 +69,7 @@ public final class Slf4jLogStatement extends BugChecker implements MethodInvocat
|
||||
* SLF4J log statements may accept a "marker" as a first argument, before the format string.
|
||||
* We ignore such markers.
|
||||
*/
|
||||
int lTrim = MARKER.matches(args.get(0), state) ? 1 : 0;
|
||||
int lTrim = SLF4J_MARKER.matches(args.get(0), state) ? 1 : 0;
|
||||
/*
|
||||
* SLF4J treats the final argument to a log statement specially if it is a `Throwabe`: it
|
||||
* will always choose to render the associated stacktrace, even if the argument has a
|
||||
|
||||
@@ -53,7 +53,7 @@ public final class Slf4jLoggerDeclaration extends BugChecker implements Variable
|
||||
private static final Matcher<ExpressionTree> IS_GET_LOGGER =
|
||||
staticMethod().onDescendantOf("org.slf4j.LoggerFactory").named("getLogger");
|
||||
private static final String CANONICAL_STATIC_LOGGER_NAME_FLAG =
|
||||
"Slf4jLogDeclaration:CanonicalStaticLoggerName";
|
||||
"Slf4jLoggerDeclaration:CanonicalStaticLoggerName";
|
||||
private static final String DEFAULT_CANONICAL_LOGGER_NAME = "LOG";
|
||||
private static final Matcher<ExpressionTree> IS_STATIC_ENCLOSING_CLASS_REFERENCE =
|
||||
classLiteral(Slf4jLoggerDeclaration::isEnclosingClassReference);
|
||||
|
||||
@@ -54,7 +54,7 @@ public final class SpringMvcAnnotation extends BugChecker implements AnnotationT
|
||||
.put("PATCH", "PatchMapping")
|
||||
.put("POST", "PostMapping")
|
||||
.put("PUT", "PutMapping")
|
||||
.build();
|
||||
.buildOrThrow();
|
||||
|
||||
/** Instantiates a new {@link SpringMvcAnnotation} instance. */
|
||||
public SpringMvcAnnotation() {}
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.util.Constants;
|
||||
import java.util.Formattable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -37,7 +36,9 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
*/
|
||||
// XXX: What about `v1 + "sep" + v2` and similar expressions? Do we want to rewrite those to
|
||||
// `String.join`, or should some `String.join` invocations be rewritten to use the `+` operator?
|
||||
// (The latter suggestion would conflict with the `FormatStringConcatenation` check.)
|
||||
// (The latter suggestion would conflict with the `FormatStringConcatenation` check, but does make
|
||||
// more sense when `"sep"` is a long string. Similarly for `String.format("%s some long text %s",
|
||||
// arg1, arg2)`.)
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Prefer `String#join` over `String#format`",
|
||||
@@ -150,7 +151,7 @@ public final class StringJoin extends BugChecker implements MethodInvocationTree
|
||||
SuggestedFix.Builder fix =
|
||||
SuggestedFix.builder()
|
||||
.replace(tree.getMethodSelect(), "String.join")
|
||||
.replace(arguments.next(), Constants.format(separator));
|
||||
.replace(arguments.next(), SourceCode.toStringConstantExpression(separator, state));
|
||||
|
||||
while (arguments.hasNext()) {
|
||||
ExpressionTree argument = arguments.next();
|
||||
|
||||
@@ -16,10 +16,12 @@ import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MemberReferenceTreeMatcher;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MemberReferenceTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
@@ -41,7 +43,8 @@ import java.time.ZonedDateTime;
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = FRAGILE_CODE)
|
||||
public final class TimeZoneUsage extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
public final class TimeZoneUsage extends BugChecker
|
||||
implements MethodInvocationTreeMatcher, MemberReferenceTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> BANNED_TIME_METHOD =
|
||||
anyOf(
|
||||
@@ -59,6 +62,10 @@ public final class TimeZoneUsage extends BugChecker implements MethodInvocationT
|
||||
"tickMillis",
|
||||
"tickMinutes",
|
||||
"tickSeconds"),
|
||||
staticMethod()
|
||||
.onClassAny(Instant.class.getCanonicalName())
|
||||
.named("now")
|
||||
.withNoParameters(),
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
LocalDate.class.getCanonicalName(),
|
||||
@@ -67,17 +74,22 @@ public final class TimeZoneUsage extends BugChecker implements MethodInvocationT
|
||||
OffsetDateTime.class.getCanonicalName(),
|
||||
OffsetTime.class.getCanonicalName(),
|
||||
ZonedDateTime.class.getCanonicalName())
|
||||
.named("now"),
|
||||
staticMethod()
|
||||
.onClassAny(Instant.class.getCanonicalName())
|
||||
.named("now")
|
||||
.withNoParameters());
|
||||
.named("now"));
|
||||
|
||||
/** Instantiates a new {@link TimeZoneUsage} instance. */
|
||||
public TimeZoneUsage() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
return getDescription(tree, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) {
|
||||
return getDescription(tree, state);
|
||||
}
|
||||
|
||||
private Description getDescription(ExpressionTree tree, VisitorState state) {
|
||||
return BANNED_TIME_METHOD.matches(tree, state)
|
||||
? buildDescription(tree).build()
|
||||
: Description.NO_MATCH;
|
||||
|
||||
@@ -18,6 +18,7 @@ final class AssertJCharSequenceRules {
|
||||
@BeforeTemplate
|
||||
void before(CharSequence charSequence) {
|
||||
Refaster.anyOf(
|
||||
assertThat(charSequence.isEmpty()).isTrue(),
|
||||
assertThat(charSequence.length()).isEqualTo(0L),
|
||||
assertThat(charSequence.length()).isNotPositive());
|
||||
}
|
||||
@@ -33,6 +34,7 @@ final class AssertJCharSequenceRules {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(CharSequence charSequence) {
|
||||
return Refaster.anyOf(
|
||||
assertThat(charSequence.isEmpty()).isFalse(),
|
||||
assertThat(charSequence.length()).isNotEqualTo(0),
|
||||
assertThat(charSequence.length()).isPositive());
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.util.Collection;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
import org.assertj.core.api.AbstractIterableAssert;
|
||||
import org.assertj.core.api.AbstractIterableSizeAssert;
|
||||
import org.assertj.core.api.EnumerableAssert;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@@ -21,6 +24,11 @@ final class AssertJEnumerableRules {
|
||||
enumAssert.hasSizeLessThan(1));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
|
||||
enumAssert.size().isNotPositive();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(EnumerableAssert<?, E> enumAssert) {
|
||||
enumAssert.isEmpty();
|
||||
@@ -34,30 +42,170 @@ final class AssertJEnumerableRules {
|
||||
enumAssert.hasSizeGreaterThan(0), enumAssert.hasSizeGreaterThanOrEqualTo(1));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
AbstractIterableAssert<?, ?, E, ?> before(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
|
||||
return Refaster.anyOf(
|
||||
enumAssert.size().isNotEqualTo(0).returnToIterable(),
|
||||
enumAssert.size().isPositive().returnToIterable());
|
||||
}
|
||||
|
||||
// XXX: If this template matches, then the expression's return type changes incompatibly.
|
||||
// Consider moving this template to a separate block (statement) rule.
|
||||
@BeforeTemplate
|
||||
AbstractIntegerAssert<?> before2(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
|
||||
return Refaster.anyOf(enumAssert.size().isNotEqualTo(0), enumAssert.size().isPositive());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert) {
|
||||
return enumAssert.isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumerableAssertHasSameSizeAs<S, T> {
|
||||
static final class EnumerableAssertHasSize<E> {
|
||||
@BeforeTemplate
|
||||
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Iterable<T> iterable) {
|
||||
AbstractIterableAssert<?, ?, E, ?> before(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isEqualTo(size).returnToIterable();
|
||||
}
|
||||
|
||||
// XXX: If this template matches, then the expression's return type changes incompatibly.
|
||||
// Consider moving this template to a separate block (statement) rule.
|
||||
@BeforeTemplate
|
||||
AbstractIterableSizeAssert<?, ?, E, ?> before2(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isEqualTo(size);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
|
||||
return enumAssert.hasSize(size);
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumerableAssertHasSizeLessThan<E> {
|
||||
@BeforeTemplate
|
||||
AbstractIterableAssert<?, ?, E, ?> before(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isLessThan(size).returnToIterable();
|
||||
}
|
||||
|
||||
// XXX: If this template matches, then the expression's return type changes incompatibly.
|
||||
// Consider moving this template to a separate block (statement) rule.
|
||||
@BeforeTemplate
|
||||
AbstractIterableSizeAssert<?, ?, E, ?> before2(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isLessThan(size);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
|
||||
return enumAssert.hasSizeLessThan(size);
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumerableAssertHasSizeLessThanOrEqualTo<E> {
|
||||
@BeforeTemplate
|
||||
AbstractIterableAssert<?, ?, E, ?> before(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isLessThanOrEqualTo(size).returnToIterable();
|
||||
}
|
||||
|
||||
// XXX: If this template matches, then the expression's return type changes incompatibly.
|
||||
// Consider moving this template to a separate block (statement) rule.
|
||||
@BeforeTemplate
|
||||
AbstractIterableSizeAssert<?, ?, E, ?> before2(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isLessThanOrEqualTo(size);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
|
||||
return enumAssert.hasSizeLessThanOrEqualTo(size);
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumerableAssertHasSizeGreaterThan<E> {
|
||||
@BeforeTemplate
|
||||
AbstractIterableAssert<?, ?, E, ?> before(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isGreaterThan(size).returnToIterable();
|
||||
}
|
||||
|
||||
// XXX: If this template matches, then the expression's return type changes incompatibly.
|
||||
// Consider moving this template to a separate block (statement) rule.
|
||||
@BeforeTemplate
|
||||
AbstractIterableSizeAssert<?, ?, E, ?> before2(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isGreaterThan(size);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
|
||||
return enumAssert.hasSizeGreaterThan(size);
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumerableAssertHasSizeGreaterThanOrEqualTo<E> {
|
||||
@BeforeTemplate
|
||||
AbstractIterableAssert<?, ?, E, ?> before(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isGreaterThanOrEqualTo(size).returnToIterable();
|
||||
}
|
||||
|
||||
// XXX: If this template matches, then the expression's return type changes incompatibly.
|
||||
// Consider moving this template to a separate block (statement) rule.
|
||||
@BeforeTemplate
|
||||
AbstractIterableSizeAssert<?, ?, E, ?> before2(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
|
||||
return enumAssert.size().isGreaterThanOrEqualTo(size);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
|
||||
return enumAssert.hasSizeGreaterThanOrEqualTo(size);
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumerableAssertHasSizeBetween<E> {
|
||||
@BeforeTemplate
|
||||
AbstractIterableAssert<?, ?, E, ?> before(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int lower, int upper) {
|
||||
return enumAssert.size().isBetween(lower, upper).returnToIterable();
|
||||
}
|
||||
|
||||
// XXX: If this template matches, then the expression's return type changes incompatibly.
|
||||
// Consider moving this template to a separate block (statement) rule.
|
||||
@BeforeTemplate
|
||||
AbstractIterableSizeAssert<?, ?, E, ?> before2(
|
||||
AbstractIterableAssert<?, ?, E, ?> enumAssert, int lower, int upper) {
|
||||
return enumAssert.size().isBetween(lower, upper);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int lower, int upper) {
|
||||
return enumAssert.hasSizeBetween(lower, upper);
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumerableAssertHasSameSizeAs<S, E> {
|
||||
@BeforeTemplate
|
||||
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Iterable<E> iterable) {
|
||||
return enumAssert.hasSize(Iterables.size(iterable));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Collection<T> iterable) {
|
||||
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Collection<E> iterable) {
|
||||
return enumAssert.hasSize(iterable.size());
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, T[] iterable) {
|
||||
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, E[] iterable) {
|
||||
return enumAssert.hasSize(iterable.length);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<T> iterable) {
|
||||
EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<E> iterable) {
|
||||
return enumAssert.hasSameSizeAs(iterable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Collection;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
import org.assertj.core.api.IterableAssert;
|
||||
import org.assertj.core.api.ObjectAssert;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@OnlineDocumentation
|
||||
final class AssertJIterableRules {
|
||||
private AssertJIterableRules() {}
|
||||
|
||||
static final class AssertThatIterableIsEmpty<E> {
|
||||
@BeforeTemplate
|
||||
void before(Iterable<E> iterable) {
|
||||
assertThat(iterable.iterator()).isExhausted();
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Collection<E> iterable) {
|
||||
assertThat(iterable.isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Collection<E> iterable) {
|
||||
assertThat(iterable).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIterableIsNotEmpty<E> {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(Iterable<E> iterable) {
|
||||
return assertThat(iterable.iterator()).hasNext();
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(Collection<E> iterable) {
|
||||
return assertThat(iterable.isEmpty()).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
IterableAssert<E> after(Iterable<E> iterable) {
|
||||
return assertThat(iterable).isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIterableSize<E> {
|
||||
@BeforeTemplate
|
||||
AbstractIntegerAssert<?> before(Iterable<E> iterable) {
|
||||
return assertThat(Iterables.size(iterable));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
AbstractIntegerAssert<?> before(Collection<E> iterable) {
|
||||
return assertThat(iterable.size());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractIntegerAssert<?> after(Iterable<E> iterable) {
|
||||
return assertThat(iterable).size();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: In practice this rule isn't very useful, as it only matches invocations of
|
||||
// `assertThat(E)`. In most cases a more specific overload of `assertThat` is invoked, in which
|
||||
// case this rule won't match. Look into a more robust approach.
|
||||
static final class AssertThatIterableHasOneElementEqualTo<S, E extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectAssert<S> before(Iterable<S> iterable, E element) {
|
||||
return assertThat(Iterables.getOnlyElement(iterable)).isEqualTo(element);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
IterableAssert<S> after(Iterable<S> iterable, E element) {
|
||||
return assertThat(iterable).containsExactly(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Iterator;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import org.assertj.core.api.IteratorAssert;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@OnlineDocumentation
|
||||
final class AssertJIteratorRules {
|
||||
private AssertJIteratorRules() {}
|
||||
|
||||
static final class AssertThatHasNext<T> {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(Iterator<T> iterator) {
|
||||
return assertThat(iterator.hasNext()).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
IteratorAssert<T> after(Iterator<T> iterator) {
|
||||
return assertThat(iterator).hasNext();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIsExhausted<T> {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(Iterator<T> iterator) {
|
||||
return assertThat(iterator.hasNext()).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
IteratorAssert<T> after(Iterator<T> iterator) {
|
||||
return assertThat(iterator).isExhausted();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import org.assertj.core.api.AbstractCollectionAssert;
|
||||
@@ -182,13 +181,13 @@ final class AssertJMapRules {
|
||||
static final class AssertThatMapContainsOnlyKeys<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractCollectionAssert<?, Collection<? extends K>, K, ?> before(
|
||||
Map<K, V> map, Set<? extends K> keys) {
|
||||
Map<K, V> map, Iterable<? extends K> keys) {
|
||||
return assertThat(map.keySet()).hasSameElementsAs(keys);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, Set<? extends K> keys) {
|
||||
MapAssert<K, V> after(Map<K, V> map, Iterable<? extends K> keys) {
|
||||
return assertThat(map).containsOnlyKeys(keys);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@@ -31,19 +32,6 @@ final class AssertJStringRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatStringIsEmpty {
|
||||
@BeforeTemplate
|
||||
void before(String string) {
|
||||
assertThat(string.isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(String string) {
|
||||
assertThat(string).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AbstractStringAssertStringIsNotEmpty {
|
||||
@BeforeTemplate
|
||||
AbstractStringAssert<?> before(AbstractStringAssert<?> stringAssert) {
|
||||
@@ -56,16 +44,29 @@ final class AssertJStringRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatStringIsNotEmpty {
|
||||
static final class AssertThatStringContains {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(String string) {
|
||||
return assertThat(string.isEmpty()).isFalse();
|
||||
AbstractBooleanAssert<?> before(String string, CharSequence substring) {
|
||||
return assertThat(string.contains(substring)).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractAssert<?, ?> after(String string) {
|
||||
return assertThat(string).isNotEmpty();
|
||||
AbstractStringAssert<?> after(String string, CharSequence substring) {
|
||||
return assertThat(string).contains(substring);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatStringDoesNotContain {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(String string, CharSequence substring) {
|
||||
return assertThat(string.contains(substring)).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractStringAssert<?> after(String string, CharSequence substring) {
|
||||
return assertThat(string).doesNotContain(substring);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNullPointerException;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.throwable;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
@@ -16,6 +19,7 @@ import java.io.IOException;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.AbstractThrowableAssert;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.assertj.core.api.ThrowableAssertAlternative;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/**
|
||||
@@ -31,6 +35,21 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
final class AssertJThrowingCallableRules {
|
||||
private AssertJThrowingCallableRules() {}
|
||||
|
||||
static final class AssertThatThrownByIsInstanceOf<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
void before(ThrowingCallable throwingCallable, Class<T> exceptionType) {
|
||||
Refaster.anyOf(
|
||||
assertThatThrownBy(throwingCallable).asInstanceOf(throwable(exceptionType)),
|
||||
assertThatThrownBy(throwingCallable).asInstanceOf(type(exceptionType)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Class<T> exceptionType) {
|
||||
assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalArgumentException {
|
||||
@BeforeTemplate
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) {
|
||||
@@ -61,6 +80,27 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByIllegalArgumentException" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatIllegalArgumentException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -171,6 +211,27 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalStateExceptionRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByIllegalStateException" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatIllegalStateException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalStateExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -279,6 +340,27 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByNullPointerExceptionRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByNullPointerException" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatNullPointerException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(NullPointerException.class)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByNullPointerExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -386,6 +468,26 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIOExceptionRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatIOException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IOException.class)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIOExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
|
||||
@@ -452,24 +554,24 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownBy {
|
||||
static final class AssertThatThrownByAsInstanceOfThrowable<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) {
|
||||
ThrowableAssertAlternative<T> before(
|
||||
ThrowingCallable throwingCallable, Class<T> exceptionType) {
|
||||
return assertThatExceptionOfType(exceptionType).isThrownBy(throwingCallable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) {
|
||||
return assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
|
||||
AbstractThrowableAssert<?, T> after(ThrowingCallable throwingCallable, Class<T> exceptionType) {
|
||||
return assertThatThrownBy(throwingCallable).asInstanceOf(throwable(exceptionType));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
@@ -489,9 +591,37 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
String message) {
|
||||
return assertThatExceptionOfType(exceptionType)
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(exceptionType)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
@@ -517,7 +647,8 @@ final class AssertJThrowingCallableRules {
|
||||
|
||||
static final class AssertThatThrownByHasMessageStartingWith {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
@@ -541,7 +672,8 @@ final class AssertJThrowingCallableRules {
|
||||
|
||||
static final class AssertThatThrownByHasMessageContaining {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
@@ -565,7 +697,8 @@ final class AssertJThrowingCallableRules {
|
||||
|
||||
static final class AssertThatThrownByHasMessageNotContaining {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
|
||||
@@ -121,18 +121,18 @@ final class AssortedRules {
|
||||
*/
|
||||
static final class DisjointSets<T> {
|
||||
@BeforeTemplate
|
||||
boolean before(Set<T> set1, Set<T> set2) {
|
||||
return Sets.intersection(set1, set2).isEmpty();
|
||||
boolean before(Set<T> collection1, Set<T> collection2) {
|
||||
return Sets.intersection(collection1, collection2).isEmpty();
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
boolean before2(Set<T> set1, Set<T> set2) {
|
||||
return set1.stream().noneMatch(set2::contains);
|
||||
boolean before2(Collection<T> collection1, Collection<T> collection2) {
|
||||
return collection1.stream().noneMatch(collection2::contains);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(Set<T> set1, Set<T> set2) {
|
||||
return disjoint(set1, set2);
|
||||
boolean after(Collection<T> collection1, Collection<T> collection2) {
|
||||
return disjoint(collection1, collection2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.sun.tools.javac.util.Constants;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import javax.lang.model.element.Name;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/** Refaster rules related to {@link com.google.errorprone.bugpatterns.BugChecker} classes. */
|
||||
@OnlineDocumentation
|
||||
@@ -56,16 +57,26 @@ final class BugCheckerRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer using the {@link Constants} API over more verbose alternatives. */
|
||||
/**
|
||||
* Prefer {@link SourceCode#toStringConstantExpression(Object,
|
||||
* com.google.errorprone.VisitorState)} over alternatives that unnecessarily escape single quote
|
||||
* characters.
|
||||
*/
|
||||
static final class ConstantsFormat {
|
||||
@BeforeTemplate
|
||||
String before(CharSequence value) {
|
||||
return Constants.format(value);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
String before(String value) {
|
||||
return String.format("\"%s\"", Convert.quote(value));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(String value) {
|
||||
return Constants.format(value);
|
||||
String after(CharSequence value) {
|
||||
return SourceCode.toStringConstantExpression(
|
||||
value, Refaster.emitCommentBefore("REPLACEME", null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link CharSequence}s. */
|
||||
@OnlineDocumentation
|
||||
final class CharSequenceRules {
|
||||
private CharSequenceRules() {}
|
||||
|
||||
/**
|
||||
* Prefer {@link CharSequence#isEmpty()} over alternatives that consult the char sequence's
|
||||
* length.
|
||||
*/
|
||||
// XXX: Drop this rule once we (and OpenRewrite) no longer support projects targeting Java 14 or
|
||||
// below.
|
||||
static final class CharSequenceIsEmpty {
|
||||
@BeforeTemplate
|
||||
boolean before(CharSequence charSequence) {
|
||||
return Refaster.anyOf(
|
||||
charSequence.length() == 0, charSequence.length() <= 0, charSequence.length() < 1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(CharSequence charSequence) {
|
||||
return charSequence.isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,14 +158,14 @@ final class CollectionRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class SetRemoveAllCollection<T, S extends T> {
|
||||
static final class CollectionRemoveAllFromCollectionBlock<T, S extends T> {
|
||||
@BeforeTemplate
|
||||
void before(Set<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
void before(Collection<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
elementsToRemove.forEach(removeFrom::remove);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before2(Set<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
void before2(Collection<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
for (T element : elementsToRemove) {
|
||||
removeFrom.remove(element);
|
||||
}
|
||||
@@ -175,14 +175,14 @@ final class CollectionRules {
|
||||
// that this is supported out of the box. After doing so, also drop the `S extends T` type
|
||||
// constraint; ideally this check applies to any `S`.
|
||||
@BeforeTemplate
|
||||
void before3(Set<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
void before3(Collection<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
for (S element : elementsToRemove) {
|
||||
removeFrom.remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(Set<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
void after(Collection<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
removeFrom.removeAll(elementsToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import java.io.File;
|
||||
@@ -11,6 +12,7 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
@@ -93,6 +95,12 @@ final class FileRules {
|
||||
/**
|
||||
* Prefer {@link Files#createTempFile(String, String, FileAttribute[])} over alternatives that
|
||||
* create files with more liberal permissions.
|
||||
*
|
||||
* <p>Note that {@link File#createTempFile} treats the given prefix as a path, and ignores all but
|
||||
* its file name. That is, the actual prefix used is derived from all characters following the
|
||||
* final file separator (if any). This is not the case with {@link Files#createTempFile}, which
|
||||
* will instead throw an {@link IllegalArgumentException} if the prefix contains any file
|
||||
* separators.
|
||||
*/
|
||||
static final class FilesCreateTempFileToFile {
|
||||
@BeforeTemplate
|
||||
@@ -117,6 +125,12 @@ final class FileRules {
|
||||
/**
|
||||
* Prefer {@link Files#createTempFile(Path, String, String, FileAttribute[])} over alternatives
|
||||
* that create files with more liberal permissions.
|
||||
*
|
||||
* <p>Note that {@link File#createTempFile} treats the given prefix as a path, and ignores all but
|
||||
* its file name. That is, the actual prefix used is derived from all characters following the
|
||||
* final file separator (if any). This is not the case with {@link Files#createTempFile}, which
|
||||
* will instead throw an {@link IllegalArgumentException} if the prefix contains any file
|
||||
* separators.
|
||||
*/
|
||||
static final class FilesCreateTempFileInCustomDirectoryToFile {
|
||||
@BeforeTemplate
|
||||
@@ -129,4 +143,35 @@ final class FileRules {
|
||||
return Files.createTempFile(directory.toPath(), prefix, suffix).toFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke {@link File#mkdirs()} before {@link Files#exists(Path, LinkOption...)} to avoid
|
||||
* concurrency issues.
|
||||
*/
|
||||
static final class PathToFileMkDirsFilesExists {
|
||||
@BeforeTemplate
|
||||
boolean before(Path path) {
|
||||
return Files.exists(path) || path.toFile().mkdirs();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(Path path) {
|
||||
return path.toFile().mkdirs() || Files.exists(path);
|
||||
}
|
||||
}
|
||||
|
||||
/** Invoke {@link File#mkdirs()} before {@link File#exists()} to avoid concurrency issues. */
|
||||
static final class FileMkDirsFileExists {
|
||||
@BeforeTemplate
|
||||
boolean before(File file) {
|
||||
return file.exists() || file.mkdirs();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(File file) {
|
||||
return file.mkdirs() || file.exists();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,7 @@ final class ImmutableListMultimapRules {
|
||||
* Prefer {@link ImmutableListMultimap#builder()} over the associated constructor on constructions
|
||||
* that produce a less-specific type.
|
||||
*/
|
||||
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
|
||||
// https://github.com/google/error-prone/pull/2706.
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableListMultimapBuilder<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableMultimap.Builder<K, V> before() {
|
||||
|
||||
@@ -28,8 +28,7 @@ final class ImmutableListRules {
|
||||
private ImmutableListRules() {}
|
||||
|
||||
/** Prefer {@link ImmutableList#builder()} over the associated constructor. */
|
||||
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
|
||||
// https://github.com/google/error-prone/pull/2706.
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableListBuilder<T> {
|
||||
@BeforeTemplate
|
||||
ImmutableList.Builder<T> before() {
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
@@ -31,8 +32,7 @@ final class ImmutableMapRules {
|
||||
private ImmutableMapRules() {}
|
||||
|
||||
/** Prefer {@link ImmutableMap#builder()} over the associated constructor. */
|
||||
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
|
||||
// https://github.com/google/error-prone/pull/2706.
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableMapBuilder<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableMap.Builder<K, V> before() {
|
||||
@@ -45,12 +45,28 @@ final class ImmutableMapRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link ImmutableMap.Builder#buildOrThrow()} over the less explicit {@link
|
||||
* ImmutableMap.Builder#build()}.
|
||||
*/
|
||||
static final class ImmutableMapBuilderBuildOrThrow<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(ImmutableMap.Builder<K, V> builder) {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableMap<K, V> after(ImmutableMap.Builder<K, V> builder) {
|
||||
return builder.buildOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives. */
|
||||
static final class EntryToImmutableMap<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.<K, V>builder().put(entry).build(),
|
||||
ImmutableMap.<K, V>builder().put(entry).buildOrThrow(),
|
||||
Stream.of(entry).collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
|
||||
@@ -105,16 +121,17 @@ final class ImmutableMapRules {
|
||||
/** Prefer {@link ImmutableMap#copyOf(Iterable)} over more contrived alternatives. */
|
||||
static final class EntryIterableToImmutableMap<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(Map<? extends K, ? extends V> iterable) {
|
||||
Map<K, V> before(Map<? extends K, ? extends V> iterable) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.copyOf(iterable.entrySet()),
|
||||
ImmutableMap.<K, V>builder().putAll(iterable).build());
|
||||
ImmutableMap.<K, V>builder().putAll(iterable).buildOrThrow(),
|
||||
Map.copyOf(iterable));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(Iterable<? extends Map.Entry<? extends K, ? extends V>> iterable) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.<K, V>builder().putAll(iterable).build(),
|
||||
ImmutableMap.<K, V>builder().putAll(iterable).buildOrThrow(),
|
||||
Streams.stream(iterable).collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
|
||||
@@ -140,8 +157,6 @@ final class ImmutableMapRules {
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract V valueFunction(@MayOptionallyUse E element);
|
||||
|
||||
// XXX: We could add variants in which the entry is created some other way, but we have another
|
||||
// rule that covers canonicalization to `Map.entry`.
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(Stream<E> stream) {
|
||||
return stream
|
||||
@@ -225,7 +240,11 @@ final class ImmutableMapRules {
|
||||
static final class ImmutableMapOf<K, V> {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before() {
|
||||
return Refaster.anyOf(ImmutableMap.<K, V>builder().build(), emptyMap(), Map.of());
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.<K, V>builder().buildOrThrow(),
|
||||
ImmutableMap.ofEntries(),
|
||||
emptyMap(),
|
||||
Map.of());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -244,7 +263,10 @@ final class ImmutableMapRules {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before(K k1, V v1) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.<K, V>builder().put(k1, v1).build(), singletonMap(k1, v1), Map.of(k1, v1));
|
||||
ImmutableMap.<K, V>builder().put(k1, v1).buildOrThrow(),
|
||||
ImmutableMap.ofEntries(Map.entry(k1, v1)),
|
||||
singletonMap(k1, v1),
|
||||
Map.of(k1, v1));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -262,7 +284,8 @@ final class ImmutableMapRules {
|
||||
static final class ImmutableMapOf2<K, V> {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before(K k1, V v1, K k2, V v2) {
|
||||
return Map.of(k1, v1, k2, v2);
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.ofEntries(Map.entry(k1, v1), Map.entry(k2, v2)), Map.of(k1, v1, k2, v2));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -280,7 +303,9 @@ final class ImmutableMapRules {
|
||||
static final class ImmutableMapOf3<K, V> {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3) {
|
||||
return Map.of(k1, v1, k2, v2, k3, v3);
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.ofEntries(Map.entry(k1, v1), Map.entry(k2, v2), Map.entry(k3, v3)),
|
||||
Map.of(k1, v1, k2, v2, k3, v3));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -300,7 +325,10 @@ final class ImmutableMapRules {
|
||||
static final class ImmutableMapOf4<K, V> {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
|
||||
return Map.of(k1, v1, k2, v2, k3, v3, k4, v4);
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.ofEntries(
|
||||
Map.entry(k1, v1), Map.entry(k2, v2), Map.entry(k3, v3), Map.entry(k4, v4)),
|
||||
Map.of(k1, v1, k2, v2, k3, v3, k4, v4));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -320,7 +348,14 @@ final class ImmutableMapRules {
|
||||
static final class ImmutableMapOf5<K, V> {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
|
||||
return Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
|
||||
return Refaster.anyOf(
|
||||
ImmutableMap.ofEntries(
|
||||
Map.entry(k1, v1),
|
||||
Map.entry(k2, v2),
|
||||
Map.entry(k3, v3),
|
||||
Map.entry(k4, v4),
|
||||
Map.entry(k5, v5)),
|
||||
Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -338,14 +373,14 @@ final class ImmutableMapRules {
|
||||
abstract boolean keyFilter(@MayOptionallyUse K key);
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(ImmutableMap<K, V> map) {
|
||||
ImmutableMap<K, V> before(Map<K, V> map) {
|
||||
return map.entrySet().stream()
|
||||
.filter(e -> keyFilter(e.getKey()))
|
||||
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableMap<K, V> after(ImmutableMap<K, V> map) {
|
||||
ImmutableMap<K, V> after(Map<K, V> map) {
|
||||
return ImmutableMap.copyOf(Maps.filterKeys(map, k -> keyFilter(k)));
|
||||
}
|
||||
}
|
||||
@@ -359,18 +394,34 @@ final class ImmutableMapRules {
|
||||
abstract boolean valueFilter(@MayOptionallyUse V value);
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(ImmutableMap<K, V> map) {
|
||||
ImmutableMap<K, V> before(Map<K, V> map) {
|
||||
return map.entrySet().stream()
|
||||
.filter(e -> valueFilter(e.getValue()))
|
||||
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableMap<K, V> after(ImmutableMap<K, V> map) {
|
||||
ImmutableMap<K, V> after(Map<K, V> map) {
|
||||
return ImmutableMap.copyOf(Maps.filterValues(map, v -> valueFilter(v)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link ImmutableMap#ofEntries(Map.Entry[])} over alternatives that don't communicate the
|
||||
* immutability of the resulting map at the type level.
|
||||
*/
|
||||
static final class ImmutableMapOfEntries<K, V> {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before(@Repeated Map.Entry<? extends K, ? extends V> entries) {
|
||||
return Map.ofEntries(entries);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableMap<K, V> after(@Repeated Map.Entry<? extends K, ? extends V> entries) {
|
||||
return ImmutableMap.ofEntries(entries);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add a rule for this:
|
||||
// Maps.transformValues(streamOfEntries.collect(groupBy(fun)), ImmutableMap::copyOf)
|
||||
// ->
|
||||
|
||||
@@ -21,8 +21,7 @@ final class ImmutableMultisetRules {
|
||||
private ImmutableMultisetRules() {}
|
||||
|
||||
/** Prefer {@link ImmutableMultiset#builder()} over the associated constructor. */
|
||||
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
|
||||
// https://github.com/google/error-prone/pull/2706.
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableMultisetBuilder<T> {
|
||||
@BeforeTemplate
|
||||
ImmutableMultiset.Builder<T> before() {
|
||||
|
||||
@@ -29,8 +29,7 @@ final class ImmutableSetMultimapRules {
|
||||
private ImmutableSetMultimapRules() {}
|
||||
|
||||
/** Prefer {@link ImmutableSetMultimap#builder()} over the associated constructor. */
|
||||
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
|
||||
// https://github.com/google/error-prone/pull/2706.
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableSetMultimapBuilder<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableSetMultimap.Builder<K, V> before() {
|
||||
|
||||
@@ -29,8 +29,7 @@ final class ImmutableSetRules {
|
||||
private ImmutableSetRules() {}
|
||||
|
||||
/** Prefer {@link ImmutableSet#builder()} over the associated constructor. */
|
||||
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
|
||||
// https://github.com/google/error-prone/pull/2706.
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableSetBuilder<T> {
|
||||
@BeforeTemplate
|
||||
ImmutableSet.Builder<T> before() {
|
||||
|
||||
@@ -37,8 +37,7 @@ final class ImmutableSortedMapRules {
|
||||
* Prefer {@link ImmutableSortedMap#naturalOrder()} over the alternative that requires explicitly
|
||||
* providing the {@link Comparator}.
|
||||
*/
|
||||
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
|
||||
// https://github.com/google/error-prone/pull/2706.
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableSortedMapNaturalOrderBuilder<K extends Comparable<? super K>, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableSortedMap.Builder<K, V> before() {
|
||||
@@ -55,8 +54,7 @@ final class ImmutableSortedMapRules {
|
||||
* Prefer {@link ImmutableSortedMap#reverseOrder()} over the alternative that requires explicitly
|
||||
* providing the {@link Comparator}.
|
||||
*/
|
||||
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
|
||||
// https://github.com/google/error-prone/pull/2706.
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableSortedMapReverseOrderBuilder<K extends Comparable<? super K>, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableSortedMap.Builder<K, V> before() {
|
||||
@@ -73,7 +71,7 @@ final class ImmutableSortedMapRules {
|
||||
static final class EmptyImmutableSortedMap<K extends Comparable<? super K>, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableSortedMap<K, V> before() {
|
||||
return ImmutableSortedMap.<K, V>naturalOrder().build();
|
||||
return ImmutableSortedMap.<K, V>naturalOrder().buildOrThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -91,7 +89,7 @@ final class ImmutableSortedMapRules {
|
||||
static final class PairToImmutableSortedMap<K extends Comparable<? super K>, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableSortedMap<K, V> before(K key, V value) {
|
||||
return ImmutableSortedMap.<K, V>naturalOrder().put(key, value).build();
|
||||
return ImmutableSortedMap.<K, V>naturalOrder().put(key, value).buildOrThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -107,7 +105,7 @@ final class ImmutableSortedMapRules {
|
||||
@BeforeTemplate
|
||||
ImmutableSortedMap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableSortedMap.<K, V>naturalOrder().put(entry).build(),
|
||||
ImmutableSortedMap.<K, V>naturalOrder().put(entry).buildOrThrow(),
|
||||
Stream.of(entry)
|
||||
.collect(
|
||||
toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)));
|
||||
@@ -128,7 +126,7 @@ final class ImmutableSortedMapRules {
|
||||
return Refaster.anyOf(
|
||||
ImmutableSortedMap.copyOf(iterable, naturalOrder()),
|
||||
ImmutableSortedMap.copyOf(iterable.entrySet()),
|
||||
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).build());
|
||||
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).buildOrThrow());
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
@@ -136,7 +134,7 @@ final class ImmutableSortedMapRules {
|
||||
Iterable<? extends Map.Entry<? extends K, ? extends V>> iterable) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableSortedMap.copyOf(iterable, naturalOrder()),
|
||||
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).build(),
|
||||
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).buildOrThrow(),
|
||||
Streams.stream(iterable)
|
||||
.collect(
|
||||
toImmutableSortedMap(
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.collect.ImmutableTable.toImmutableTable;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.collect.Tables;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link ImmutableTable}s. */
|
||||
@OnlineDocumentation
|
||||
final class ImmutableTableRules {
|
||||
private ImmutableTableRules() {}
|
||||
|
||||
/** Prefer {@link ImmutableTable#builder()} over the associated constructor. */
|
||||
// XXX: This rule may drop generic type information, leading to non-compilable code.
|
||||
static final class ImmutableTableBuilder<R, C, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableTable.Builder<R, C, V> before() {
|
||||
return new ImmutableTable.Builder<>();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableTable.Builder<R, C, V> after() {
|
||||
return ImmutableTable.builder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link ImmutableTable.Builder#buildOrThrow()} over the less explicit {@link
|
||||
* ImmutableTable.Builder#build()}.
|
||||
*/
|
||||
static final class ImmutableTableBuilderBuildOrThrow<R, C, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableTable<R, C, V> before(ImmutableTable.Builder<R, C, V> builder) {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableTable<R, C, V> after(ImmutableTable.Builder<R, C, V> builder) {
|
||||
return builder.buildOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link ImmutableTable#of(Object, Object, Object)} over more contrived alternatives. */
|
||||
static final class CellToImmutableTable<R, C, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableTable<R, C, V> before(Table.Cell<? extends R, ? extends C, ? extends V> cell) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableTable.<R, C, V>builder().put(cell).buildOrThrow(),
|
||||
Stream.of(cell)
|
||||
.collect(
|
||||
toImmutableTable(
|
||||
Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableTable<R, C, V> after(Table.Cell<? extends R, ? extends C, ? extends V> cell) {
|
||||
return ImmutableTable.of(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't map a stream's elements to table cells, only to subsequently collect them into an {@link
|
||||
* ImmutableTable}. The collection can be performed directly.
|
||||
*/
|
||||
abstract static class StreamOfCellsToImmutableTable<E, R, C, V> {
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract R rowFunction(@MayOptionallyUse E element);
|
||||
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract C columnFunction(@MayOptionallyUse E element);
|
||||
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract V valueFunction(@MayOptionallyUse E element);
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableTable<R, C, V> before(Stream<E> stream) {
|
||||
return stream
|
||||
.map(e -> Tables.immutableCell(rowFunction(e), columnFunction(e), valueFunction(e)))
|
||||
.collect(
|
||||
toImmutableTable(
|
||||
Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
ImmutableTable<R, C, V> after(Stream<E> stream) {
|
||||
return stream.collect(
|
||||
toImmutableTable(e -> rowFunction(e), e -> columnFunction(e), e -> valueFunction(e)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link ImmutableTable#of()} over more contrived alternatives . */
|
||||
static final class ImmutableTableOf<R, C, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableTable<R, C, V> before() {
|
||||
return ImmutableTable.<R, C, V>builder().buildOrThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableTable<R, C, V> after() {
|
||||
return ImmutableTable.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.Assertions.offset;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
@@ -34,7 +36,8 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
* <p>Note that, while both libraries throw an {@link AssertionError} in case of an assertion
|
||||
* failure, the exact subtype used generally differs.
|
||||
*/
|
||||
// XXX: Not all JUnit `Assertions` methods have an associated Refaster rule yet; expand this class.
|
||||
// XXX: The `AssertThat*Array*ContainsExactly*` rules assume that `expected` and `actual` are not
|
||||
// both `null`.
|
||||
// XXX: Introduce a `@Matcher` on `Executable` and `ThrowingSupplier` expressions, such that they
|
||||
// are only matched if they are also compatible with the `ThrowingCallable` functional interface.
|
||||
// When implementing such a matcher, note that expressions with a non-void return type such as
|
||||
@@ -50,39 +53,6 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
"assertAll(String, Collection<Executable>)",
|
||||
"assertAll(String, Executable[])",
|
||||
"assertAll(String, Stream<Executable>)",
|
||||
"assertArrayEquals(boolean[], boolean[])",
|
||||
"assertArrayEquals(boolean[], boolean[], String)",
|
||||
"assertArrayEquals(boolean[], boolean[], Supplier<String>)",
|
||||
"assertArrayEquals(byte[], byte[])",
|
||||
"assertArrayEquals(byte[], byte[], String)",
|
||||
"assertArrayEquals(byte[], byte[], Supplier<String>)",
|
||||
"assertArrayEquals(char[], char[])",
|
||||
"assertArrayEquals(char[], char[], String)",
|
||||
"assertArrayEquals(char[], char[], Supplier<String>)",
|
||||
"assertArrayEquals(double[], double[])",
|
||||
"assertArrayEquals(double[], double[], double)",
|
||||
"assertArrayEquals(double[], double[], double, String)",
|
||||
"assertArrayEquals(double[], double[], double, Supplier<String>)",
|
||||
"assertArrayEquals(double[], double[], String)",
|
||||
"assertArrayEquals(double[], double[], Supplier<String>)",
|
||||
"assertArrayEquals(float[], float[])",
|
||||
"assertArrayEquals(float[], float[], float)",
|
||||
"assertArrayEquals(float[], float[], float, String)",
|
||||
"assertArrayEquals(float[], float[], float, Supplier<String>)",
|
||||
"assertArrayEquals(float[], float[], String)",
|
||||
"assertArrayEquals(float[], float[], Supplier<String>)",
|
||||
"assertArrayEquals(int[], int[])",
|
||||
"assertArrayEquals(int[], int[], String)",
|
||||
"assertArrayEquals(int[], int[], Supplier<String>)",
|
||||
"assertArrayEquals(long[], long[])",
|
||||
"assertArrayEquals(long[], long[], String)",
|
||||
"assertArrayEquals(long[], long[], Supplier<String>)",
|
||||
"assertArrayEquals(Object[], Object[])",
|
||||
"assertArrayEquals(Object[], Object[], String)",
|
||||
"assertArrayEquals(Object[], Object[], Supplier<String>)",
|
||||
"assertArrayEquals(short[], short[])",
|
||||
"assertArrayEquals(short[], short[], String)",
|
||||
"assertArrayEquals(short[], short[], Supplier<String>)",
|
||||
"assertEquals(Byte, Byte)",
|
||||
"assertEquals(Byte, byte)",
|
||||
"assertEquals(byte, Byte)",
|
||||
@@ -302,6 +272,436 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
final class JUnitToAssertJRules {
|
||||
private JUnitToAssertJRules() {}
|
||||
|
||||
static final class AssertThatBooleanArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(boolean[] actual, boolean[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean[] actual, boolean[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatBooleanArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(boolean[] actual, String message, boolean[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean[] actual, String message, boolean[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatBooleanArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(boolean[] actual, Supplier<String> message, boolean[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean[] actual, Supplier<String> message, boolean[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatByteArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(byte[] actual, byte[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(byte[] actual, byte[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatByteArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(byte[] actual, String message, byte[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(byte[] actual, String message, byte[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatByteArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(byte[] actual, Supplier<String> message, byte[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(byte[] actual, Supplier<String> message, byte[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCharArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(char[] actual, char[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(char[] actual, char[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCharArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(char[] actual, String message, char[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(char[] actual, String message, char[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCharArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(char[] actual, Supplier<String> message, char[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(char[] actual, Supplier<String> message, char[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatShortArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(short[] actual, short[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(short[] actual, short[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatShortArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(short[] actual, String message, short[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(short[] actual, String message, short[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatShortArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(short[] actual, Supplier<String> message, short[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(short[] actual, Supplier<String> message, short[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIntArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(int[] actual, int[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(int[] actual, int[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIntArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(int[] actual, String message, int[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(int[] actual, String message, int[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIntArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(int[] actual, Supplier<String> message, int[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(int[] actual, Supplier<String> message, int[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatLongArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(long[] actual, long[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(long[] actual, long[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatLongArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(long[] actual, String message, long[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(long[] actual, String message, long[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatLongArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(long[] actual, Supplier<String> message, long[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(long[] actual, Supplier<String> message, long[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatFloatArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(float[] actual, float[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float[] actual, float[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatFloatArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(float[] actual, String message, float[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float[] actual, String message, float[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatFloatArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(float[] actual, Supplier<String> message, float[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float[] actual, Supplier<String> message, float[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatFloatArrayContainsExactlyWithOffset {
|
||||
@BeforeTemplate
|
||||
void before(float[] actual, float[] expected, float delta) {
|
||||
assertArrayEquals(expected, actual, delta);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float[] actual, float[] expected, float delta) {
|
||||
assertThat(actual).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatFloatArrayWithFailMessageContainsExactlyWithOffset {
|
||||
@BeforeTemplate
|
||||
void before(float[] actual, String message, float[] expected, float delta) {
|
||||
assertArrayEquals(expected, actual, delta, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float[] actual, String message, float[] expected, float delta) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatFloatArrayWithFailMessageSupplierContainsExactlyWithOffset {
|
||||
@BeforeTemplate
|
||||
void before(float[] actual, Supplier<String> message, float[] expected, float delta) {
|
||||
assertArrayEquals(expected, actual, delta, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float[] actual, Supplier<String> message, float[] expected, float delta) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatDoubleArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(double[] actual, double[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(double[] actual, double[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatDoubleArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(double[] actual, String message, double[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(double[] actual, String message, double[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatDoubleArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(double[] actual, Supplier<String> message, double[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(double[] actual, Supplier<String> message, double[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatDoubleArrayContainsExactlyWithOffset {
|
||||
@BeforeTemplate
|
||||
void before(double[] actual, double[] expected, double delta) {
|
||||
assertArrayEquals(expected, actual, delta);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(double[] actual, double[] expected, double delta) {
|
||||
assertThat(actual).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatDoubleArrayWithFailMessageContainsExactlyWithOffset {
|
||||
@BeforeTemplate
|
||||
void before(double[] actual, String message, double[] expected, double delta) {
|
||||
assertArrayEquals(expected, actual, delta, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(double[] actual, String message, double[] expected, double delta) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatDoubleArrayWithFailMessageSupplierContainsExactlyWithOffset {
|
||||
@BeforeTemplate
|
||||
void before(
|
||||
double[] actual, Supplier<String> messageSupplier, double[] expected, double delta) {
|
||||
assertArrayEquals(expected, actual, delta, messageSupplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(double[] actual, Supplier<String> messageSupplier, double[] expected, double delta) {
|
||||
assertThat(actual).withFailMessage(messageSupplier).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatObjectArrayContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(Object[] actual, Object[] expected) {
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object[] actual, Object[] expected) {
|
||||
assertThat(actual).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatObjectArrayWithFailMessageContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(Object[] actual, String message, Object[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object[] actual, String message, Object[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatObjectArrayWithFailMessageSupplierContainsExactly {
|
||||
@BeforeTemplate
|
||||
void before(Object[] actual, Supplier<String> message, Object[] expected) {
|
||||
assertArrayEquals(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object[] actual, Supplier<String> message, Object[] expected) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class Fail<T> {
|
||||
@BeforeTemplate
|
||||
T before() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
import static java.util.Objects.requireNonNullElseGet;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
@@ -94,11 +95,14 @@ final class NullRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Objects#isNull(Object)} over the equivalent lambda function. */
|
||||
/**
|
||||
* Prefer {@link Objects#isNull(Object)} over the equivalent lambda function or more contrived
|
||||
* alternatives.
|
||||
*/
|
||||
static final class IsNullFunction<T> {
|
||||
@BeforeTemplate
|
||||
Predicate<T> before() {
|
||||
return o -> o == null;
|
||||
return Refaster.anyOf(o -> o == null, not(Objects::nonNull));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -107,11 +111,14 @@ final class NullRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Objects#nonNull(Object)} over the equivalent lambda function. */
|
||||
/**
|
||||
* Prefer {@link Objects#nonNull(Object)} over the equivalent lambda function or more contrived
|
||||
* alternatives.
|
||||
*/
|
||||
static final class NonNullFunction<T> {
|
||||
@BeforeTemplate
|
||||
Predicate<T> before() {
|
||||
return o -> o != null;
|
||||
return Refaster.anyOf(o -> o != null, not(Objects::isNull));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -279,6 +279,11 @@ final class OptionalRules {
|
||||
*/
|
||||
// XXX: Do we need the `.filter(Optional::isPresent)`? If it's absent the caller probably assumed
|
||||
// that the values are present. (If we drop it, we should rewrite vacuous filter steps.)
|
||||
// XXX: The rewritten `filter`/`map` expression may be more performant than its replacement. See
|
||||
// https://github.com/palantir/gradle-baseline/pull/2946. (There are plans to pair Refaster rules
|
||||
// with JMH benchmarks; this would be a great use case.)
|
||||
// XXX: Perhaps `stream.mapMulti(Optional::ifPresent)` is what we should use. See
|
||||
// https://github.com/palantir/gradle-baseline/pull/2996.
|
||||
static final class StreamFlatMapOptional<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(Stream<Optional<T>> stream) {
|
||||
@@ -395,10 +400,7 @@ final class OptionalRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary operations on an {@link Optional} that ultimately result in that very same
|
||||
* {@link Optional}.
|
||||
*/
|
||||
/** Don't unnecessarily transform an {@link Optional} to an equivalent instance. */
|
||||
static final class OptionalIdentity<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedOptionals")
|
||||
|
||||
@@ -8,12 +8,15 @@ import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.common.primitives.Shorts;
|
||||
import com.google.common.primitives.UnsignedBytes;
|
||||
import com.google.common.primitives.UnsignedInts;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with primitives. */
|
||||
@@ -525,10 +528,7 @@ final class PrimitiveRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Integer#toUnsignedString(int,int)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
/** Prefer JDK's {@link Integer#toUnsignedString(int,int)} over third-party alternatives. */
|
||||
static final class IntegerToUnsignedStringWithRadix {
|
||||
@BeforeTemplate
|
||||
String before(int i, int radix) {
|
||||
@@ -541,10 +541,7 @@ final class PrimitiveRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
/** Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party alternatives. */
|
||||
static final class LongToUnsignedStringWithRadix {
|
||||
@BeforeTemplate
|
||||
String before(long i, int radix) {
|
||||
@@ -556,4 +553,49 @@ final class PrimitiveRules {
|
||||
return Long.toUnsignedString(i, radix);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Arrays#compareUnsigned(byte[], byte[])} over third-party alternatives. */
|
||||
// XXX: This rule will yield non-compilable code if the result of the replaced expression is
|
||||
// dereferenced. Investigate how to make this safe.
|
||||
static final class ArraysCompareUnsignedBytes {
|
||||
@BeforeTemplate
|
||||
Comparator<byte[]> before() {
|
||||
return UnsignedBytes.lexicographicalComparator();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Comparator<byte[]> after() {
|
||||
return Arrays::compareUnsigned;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Arrays#compareUnsigned(int[], int[])} over third-party alternatives. */
|
||||
// XXX: This rule will yield non-compilable code if the result of the replaced expression is
|
||||
// dereferenced. Investigate how to make this safe.
|
||||
static final class ArraysCompareUnsignedInts {
|
||||
@BeforeTemplate
|
||||
Comparator<int[]> before() {
|
||||
return UnsignedInts.lexicographicalComparator();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Comparator<int[]> after() {
|
||||
return Arrays::compareUnsigned;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Arrays#compareUnsigned(long[], long[])} over third-party alternatives. */
|
||||
// XXX: This rule will yield non-compilable code if the result of the replaced expression is
|
||||
// dereferenced. Investigate how to make this safe.
|
||||
static final class ArraysCompareUnsignedLongs {
|
||||
@BeforeTemplate
|
||||
Comparator<long[]> before() {
|
||||
return UnsignedLongs.lexicographicalComparator();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Comparator<long[]> after() {
|
||||
return Arrays::compareUnsigned;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,9 +489,16 @@ final class ReactorRules {
|
||||
return Flux.range(value, 1);
|
||||
}
|
||||
|
||||
// XXX: Consider generalizing part of this template using an Error Prone check that covers any
|
||||
// sequence of explicitly enumerated values passed to an iteration order-preserving collection
|
||||
// factory method.
|
||||
@BeforeTemplate
|
||||
Flux<T> before(T value) {
|
||||
return Mono.just(value).repeat().take(1);
|
||||
return Refaster.anyOf(
|
||||
Mono.just(value).flux(),
|
||||
Mono.just(value).repeat().take(1),
|
||||
Flux.fromIterable(ImmutableList.of(value)),
|
||||
Flux.fromIterable(ImmutableSet.of(value)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -889,6 +896,38 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer immediately unwrapping {@link Optional} transformation results inside {@link
|
||||
* Flux#mapNotNull(Function)} over more contrived alternatives.
|
||||
*/
|
||||
abstract static class FluxMapNotNullTransformationOrElse<T, S> {
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract Optional<S> transformation(@MayOptionallyUse T value);
|
||||
|
||||
@BeforeTemplate
|
||||
Flux<S> before(Flux<T> flux) {
|
||||
return flux.map(v -> transformation(v)).mapNotNull(o -> o.orElse(null));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<S> after(Flux<T> flux) {
|
||||
return flux.mapNotNull(x -> transformation(x).orElse(null));
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#mapNotNull(Function)} over more contrived alternatives. */
|
||||
static final class FluxMapNotNullOrElse<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Flux<Optional<T>> flux) {
|
||||
return flux.filter(Optional::isPresent).map(Optional::orElseThrow);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Flux<Optional<T>> flux) {
|
||||
return flux.mapNotNull(x -> x.orElse(null));
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#flux()}} over more contrived alternatives. */
|
||||
static final class MonoFlux<T> {
|
||||
@BeforeTemplate
|
||||
@@ -907,7 +946,11 @@ final class ReactorRules {
|
||||
static final class MonoThen<T> {
|
||||
@BeforeTemplate
|
||||
Mono<@Nullable Void> before(Mono<T> mono) {
|
||||
return Refaster.anyOf(mono.ignoreElement().then(), mono.flux().then());
|
||||
return Refaster.anyOf(
|
||||
mono.ignoreElement().then(),
|
||||
mono.flux().then(),
|
||||
Mono.when(mono),
|
||||
Mono.whenDelayError(mono));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -1046,10 +1089,12 @@ final class ReactorRules {
|
||||
// rule. Consider introducing an Error Prone check for this.
|
||||
static final class MonoSingleOptional<T> {
|
||||
@BeforeTemplate
|
||||
Mono<Optional<T>> before(Mono<T> mono) {
|
||||
Mono<Optional<T>> before(Mono<T> mono, Optional<T> optional, Mono<Optional<T>> alternate) {
|
||||
return Refaster.anyOf(
|
||||
mono.flux().collect(toOptional()),
|
||||
mono.map(Optional::of).defaultIfEmpty(Optional.empty()),
|
||||
mono.map(Optional::of),
|
||||
mono.singleOptional().defaultIfEmpty(optional),
|
||||
mono.singleOptional().switchIfEmpty(alternate),
|
||||
mono.transform(Mono::singleOptional));
|
||||
}
|
||||
|
||||
@@ -1742,6 +1787,91 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasSubscribed()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasSubscribed<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
Refaster.anyOf(
|
||||
assertThat(probe.wasSubscribed()).isTrue(),
|
||||
assertThat(probe.subscribeCount()).isNotNegative(),
|
||||
assertThat(probe.subscribeCount()).isNotEqualTo(0),
|
||||
assertThat(probe.subscribeCount()).isPositive());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasSubscribed();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasNotSubscribed()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasNotSubscribed<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
Refaster.anyOf(
|
||||
assertThat(probe.wasSubscribed()).isFalse(),
|
||||
assertThat(probe.subscribeCount()).isEqualTo(0),
|
||||
assertThat(probe.subscribeCount()).isNotPositive());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasNotSubscribed();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasCancelled()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasCancelled<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
assertThat(probe.wasCancelled()).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasNotCancelled()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasNotCancelled<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
assertThat(probe.wasCancelled()).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasNotCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasRequested()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasRequested<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
assertThat(probe.wasRequested()).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasRequested();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasNotRequested()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasNotRequested<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
assertThat(probe.wasRequested()).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasNotRequested();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#as(Function)} when creating a {@link StepVerifier}. */
|
||||
static final class StepVerifierFromMono<T> {
|
||||
@BeforeTemplate
|
||||
@@ -1768,6 +1898,60 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link StepVerifier#verify()} over a dangling {@link
|
||||
* StepVerifier#verifyThenAssertThat()}.
|
||||
*/
|
||||
// XXX: Application of this rule (and several others in this class) will cause invalid code if the
|
||||
// result of the rewritten expression is dereferenced. Consider introducing a bug checker that
|
||||
// identifies rules that change the return type of an expression and annotates them accordingly.
|
||||
// The associated annotation can then be used to instruct an annotation processor to generate
|
||||
// corresponding `void` rules that match only statements. This would allow the `Refaster` check to
|
||||
// conditionally skip "not fully safe" rules. This allows conditionally flagging more dubious
|
||||
// code, at the risk of compilation failures. With this rule, for example, we want to explicitly
|
||||
// nudge users towards `StepVerifier.Step#assertNext(Consumer)` or
|
||||
// `StepVerifier.Step#expectNext(Object)`, together with `Step#verifyComplete()`.
|
||||
static final class StepVerifierVerify {
|
||||
@BeforeTemplate
|
||||
StepVerifier.Assertions before(StepVerifier stepVerifier) {
|
||||
return stepVerifier.verifyThenAssertThat();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Duration after(StepVerifier stepVerifier) {
|
||||
return stepVerifier.verify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link StepVerifier#verify(Duration)} over a dangling {@link
|
||||
* StepVerifier#verifyThenAssertThat(Duration)}.
|
||||
*/
|
||||
static final class StepVerifierVerifyDuration {
|
||||
@BeforeTemplate
|
||||
StepVerifier.Assertions before(StepVerifier stepVerifier, Duration duration) {
|
||||
return stepVerifier.verifyThenAssertThat(duration);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Duration after(StepVerifier stepVerifier, Duration duration) {
|
||||
return stepVerifier.verify(duration);
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily invoke {@link StepVerifier#verifyLater()} multiple times. */
|
||||
static final class StepVerifierVerifyLater {
|
||||
@BeforeTemplate
|
||||
StepVerifier before(StepVerifier stepVerifier) {
|
||||
return stepVerifier.verifyLater().verifyLater();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
StepVerifier after(StepVerifier stepVerifier) {
|
||||
return stepVerifier.verifyLater();
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily have {@link StepVerifier.Step} expect no elements. */
|
||||
static final class StepVerifierStepIdentity<T> {
|
||||
@BeforeTemplate
|
||||
@@ -1868,6 +2052,12 @@ final class ReactorRules {
|
||||
return step.expectErrorMatches(predicate).verify();
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("StepVerifierVerify" /* This is a more specific template. */)
|
||||
StepVerifier.Assertions before2(StepVerifier.LastStep step, Predicate<Throwable> predicate) {
|
||||
return step.expectError().verifyThenAssertThat().hasOperatorErrorMatching(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Duration after(StepVerifier.LastStep step, Predicate<Throwable> predicate) {
|
||||
return step.verifyErrorMatches(predicate);
|
||||
@@ -1890,6 +2080,30 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link StepVerifier.LastStep#verifyErrorSatisfies(Consumer)} with AssertJ over more
|
||||
* contrived alternatives.
|
||||
*/
|
||||
static final class StepVerifierLastStepVerifyErrorSatisfiesAssertJ<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("StepVerifierVerify" /* This is a more specific template. */)
|
||||
StepVerifier.Assertions before(StepVerifier.LastStep step, Class<T> clazz, String message) {
|
||||
return Refaster.anyOf(
|
||||
step.expectError()
|
||||
.verifyThenAssertThat()
|
||||
.hasOperatorErrorOfType(clazz)
|
||||
.hasOperatorErrorWithMessage(message),
|
||||
step.expectError(clazz).verifyThenAssertThat().hasOperatorErrorWithMessage(message),
|
||||
step.expectErrorMessage(message).verifyThenAssertThat().hasOperatorErrorOfType(clazz));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
Duration after(StepVerifier.LastStep step, Class<T> clazz, String message) {
|
||||
return step.verifyErrorSatisfies(t -> assertThat(t).isInstanceOf(clazz).hasMessage(message));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link StepVerifier.LastStep#verifyErrorMessage(String)} over more verbose alternatives.
|
||||
*/
|
||||
@@ -1973,6 +2187,22 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't propagate {@link Mono} cancellations to upstream cache value computations, as completion
|
||||
* of such computations may benefit concurrent or subsequent cache usages.
|
||||
*/
|
||||
static final class MonoFromFutureAsyncLoadingCacheGetAll<K1, K2 extends K1, V> {
|
||||
@BeforeTemplate
|
||||
Mono<Map<K1, V>> before(AsyncLoadingCache<K1, V> cache, Iterable<K2> keys) {
|
||||
return Mono.fromFuture(() -> cache.getAll(keys));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<Map<K1, V>> after(AsyncLoadingCache<K1, V> cache, Iterable<K2> keys) {
|
||||
return Mono.fromFuture(() -> cache.getAll(keys), /* suppressCancel= */ true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#fromStream(Supplier)} over {@link Flux#fromStream(Stream)}, as the former
|
||||
* yields a {@link Flux} that is more likely to behave as expected when subscribed to more than
|
||||
|
||||
@@ -297,6 +297,22 @@ final class StreamRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer an unconditional {@link Map#get(Object)} call followed by a {@code null} check over a
|
||||
* call to {@link Map#containsKey(Object)}, as the former avoids a second lookup operation.
|
||||
*/
|
||||
static final class StreamMapFilter<T, K, V> {
|
||||
@BeforeTemplate
|
||||
Stream<V> before(Stream<T> stream, Map<K, V> map) {
|
||||
return stream.filter(map::containsKey).map(map::get);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<V> after(Stream<T> stream, Map<K, V> map) {
|
||||
return stream.map(map::get).filter(Objects::nonNull);
|
||||
}
|
||||
}
|
||||
|
||||
static final class StreamMin<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
|
||||
|
||||
@@ -29,11 +29,14 @@ final class StringRules {
|
||||
private StringRules() {}
|
||||
|
||||
/** Prefer {@link String#isEmpty()} over alternatives that consult the string's length. */
|
||||
// XXX: Now that we build with JDK 15+, this rule can be generalized to cover all `CharSequence`
|
||||
// subtypes. This does require a mechanism (perhaps an annotation, or a separate Maven module) to
|
||||
// make sure that non-String expressions are rewritten only if client code also targets JDK 15+.
|
||||
// XXX: Drop this rule once we (and OpenRewrite) no longer support projects targeting Java 14 or
|
||||
// below. The `CharSequenceIsEmpty` rule then suffices. (This rule exists so that e.g. projects
|
||||
// that target JDK 11 can disable `CharSequenceIsEmpty` without losing a valuable rule.)
|
||||
// XXX: Look into a more general approach to supporting different Java language levels, such as
|
||||
// rule selection based on some annotation, or a separate Maven module.
|
||||
static final class StringIsEmpty {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("CharSequenceIsEmpty" /* This is a more specific template. */)
|
||||
boolean before(String str) {
|
||||
return Refaster.anyOf(str.length() == 0, str.length() <= 0, str.length() < 1);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
@@ -65,16 +66,18 @@ final class SuggestedFixRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link SuggestedFix#swap(Tree, Tree)} over more contrived alternatives. */
|
||||
/**
|
||||
* Prefer {@link SuggestedFix#swap(Tree, Tree, VisitorState)} over more contrived alternatives.
|
||||
*/
|
||||
static final class SuggestedFixSwap {
|
||||
@BeforeTemplate
|
||||
SuggestedFix before(Tree tree1, Tree tree2) {
|
||||
return SuggestedFix.builder().swap(tree1, tree2).build();
|
||||
SuggestedFix before(Tree tree1, Tree tree2, VisitorState state) {
|
||||
return SuggestedFix.builder().swap(tree1, tree2, state).build();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
SuggestedFix after(Tree tree1, Tree tree2) {
|
||||
return SuggestedFix.swap(tree1, tree2);
|
||||
SuggestedFix after(Tree tree1, Tree tree2, VisitorState state) {
|
||||
return SuggestedFix.swap(tree1, tree2, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,71 +53,20 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
// XXX: As-is these rules do not result in a complete migration:
|
||||
// - Expressions containing comments are skipped due to a limitation of Refaster.
|
||||
// - Assertions inside lambda expressions are also skipped. Unclear why.
|
||||
// XXX: The `assertEquals` tests for this class generally use the same expression for `expected` and
|
||||
// XXX: Many of the test expressions for these rules use the same expression for `expected` and
|
||||
// `actual`, which makes the validation weaker than necessary; fix this. (And investigate whether we
|
||||
// can introduce validation for this.)
|
||||
@OnlineDocumentation
|
||||
@TypeMigration(
|
||||
of = Assert.class,
|
||||
unmigratedMethods = {
|
||||
// XXX: Add migrations for the methods below.
|
||||
"assertEquals(Boolean, Boolean)",
|
||||
"assertEquals(Boolean, boolean)",
|
||||
"assertEquals(boolean, Boolean)",
|
||||
"assertEquals(Boolean, Boolean, String)",
|
||||
"assertEquals(Boolean, boolean, String)",
|
||||
"assertEquals(boolean, Boolean, String)",
|
||||
"assertEquals(Byte, Byte)",
|
||||
"assertEquals(Byte, byte)",
|
||||
"assertEquals(byte, Byte)",
|
||||
"assertEquals(Byte, Byte, String)",
|
||||
"assertEquals(Byte, byte, String)",
|
||||
"assertEquals(byte, Byte, String)",
|
||||
"assertEquals(char, Character)",
|
||||
"assertEquals(char, Character, String)",
|
||||
"assertEquals(Character, char)",
|
||||
"assertEquals(Character, char, String)",
|
||||
"assertEquals(Character, Character)",
|
||||
"assertEquals(Character, Character, String)",
|
||||
"assertEquals(Double, Double)",
|
||||
"assertEquals(Double, double)",
|
||||
"assertEquals(double, Double)",
|
||||
"assertEquals(Double, Double, String)",
|
||||
"assertEquals(Double, double, String)",
|
||||
"assertEquals(double, Double, String)",
|
||||
"assertEquals(double[], double[], double)",
|
||||
"assertEquals(double[], double[], double, String)",
|
||||
"assertEquals(Float, Float)",
|
||||
"assertEquals(Float, float)",
|
||||
"assertEquals(float, Float)",
|
||||
"assertEquals(Float, Float, String)",
|
||||
"assertEquals(Float, float, String)",
|
||||
"assertEquals(float, Float, String)",
|
||||
"assertEquals(float[], float[], float)",
|
||||
"assertEquals(float[], float[], float, String)",
|
||||
"assertEquals(int, Integer)",
|
||||
"assertEquals(int, Integer, String)",
|
||||
"assertEquals(Integer, int)",
|
||||
"assertEquals(Integer, int, String)",
|
||||
"assertEquals(Integer, Integer)",
|
||||
"assertEquals(Integer, Integer, String)",
|
||||
"assertEquals(Long, Long)",
|
||||
"assertEquals(Long, long)",
|
||||
"assertEquals(long, Long)",
|
||||
"assertEquals(Long, Long, String)",
|
||||
"assertEquals(Long, long, String)",
|
||||
"assertEquals(Short, Short)",
|
||||
"assertEquals(Short, short)",
|
||||
"assertEquals(short, Short)",
|
||||
"assertEquals(Short, Short, String)",
|
||||
"assertEquals(Short, short, String)",
|
||||
"assertEquals(short, Short, String)",
|
||||
/*
|
||||
* These `assertEqualsDeep` methods cannot (easily) be expressed using AssertJ because they
|
||||
* mix regular equality and array equality:
|
||||
*/
|
||||
"assertEqualsDeep(Map<?, ?>, Map<?, ?>)",
|
||||
"assertEqualsDeep(Map<?, ?>, Map<?, ?>, String)",
|
||||
"assertEqualsDeep(Set<?>, Set<?>)",
|
||||
"assertEqualsDeep(Set<?>, Set<?>, String)",
|
||||
// XXX: Add migrations for the methods below.
|
||||
"assertEqualsNoOrder(Collection<?>, Collection<?>)",
|
||||
@@ -351,47 +300,168 @@ final class TestNGToAssertJRules {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S1448" /* Each variant requires a separate `@BeforeTemplate` method. */)
|
||||
static final class AssertEqual {
|
||||
@BeforeTemplate
|
||||
void before(boolean actual, boolean expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(boolean actual, Boolean expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Boolean actual, boolean expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Boolean actual, Boolean expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(byte actual, byte expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(byte actual, Byte expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Byte actual, byte expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Byte actual, Byte expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(char actual, char expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(char actual, Character expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Character actual, char expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Character actual, Character expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(short actual, short expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(short actual, Short expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Short actual, short expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Short actual, Short expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(int actual, int expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(int actual, Integer expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Integer actual, int expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Integer actual, Integer expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(long actual, long expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(long actual, Long expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Long actual, long expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Long actual, Long expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(float actual, float expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(float actual, Float expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Float actual, float expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Float actual, Float expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(double actual, double expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(double actual, Double expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Double actual, double expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Double actual, Double expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Object expected) {
|
||||
assertEquals(actual, expected);
|
||||
@@ -414,47 +484,168 @@ final class TestNGToAssertJRules {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S1448" /* Each variant requires a separate `@BeforeTemplate` method. */)
|
||||
static final class AssertEqualWithMessage {
|
||||
@BeforeTemplate
|
||||
void before(boolean actual, String message, boolean expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(boolean actual, String message, Boolean expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Boolean actual, String message, boolean expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Boolean actual, String message, Boolean expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(byte actual, String message, byte expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(byte actual, String message, Byte expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Byte actual, String message, byte expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Byte actual, String message, Byte expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(char actual, String message, char expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(char actual, String message, Character expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Character actual, String message, char expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Character actual, String message, Character expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(short actual, String message, short expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(short actual, String message, Short expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Short actual, String message, short expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Short actual, String message, Short expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(int actual, String message, int expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(int actual, String message, Integer expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Integer actual, String message, int expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Integer actual, String message, Integer expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(long actual, String message, long expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(long actual, String message, Long expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Long actual, String message, long expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Long actual, String message, Long expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(float actual, String message, float expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(float actual, String message, Float expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Float actual, String message, float expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Float actual, String message, Float expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(double actual, String message, double expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(double actual, String message, Double expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Double actual, String message, double expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Double actual, String message, Double expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(Object actual, String message, Object expected) {
|
||||
assertEquals(actual, expected, message);
|
||||
@@ -485,7 +676,7 @@ final class TestNGToAssertJRules {
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float actual, float expected, float delta) {
|
||||
void after(Float actual, float expected, float delta) {
|
||||
assertThat(actual).isCloseTo(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
@@ -635,6 +826,58 @@ final class TestNGToAssertJRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertEqualFloatArraysWithDelta {
|
||||
@BeforeTemplate
|
||||
void before(float[] actual, float[] expected, float delta) {
|
||||
assertEquals(actual, expected, delta);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float[] actual, float[] expected, float delta) {
|
||||
assertThat(actual).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertEqualFloatArraysWithDeltaWithMessage {
|
||||
@BeforeTemplate
|
||||
void before(float[] actual, String message, float[] expected, float delta) {
|
||||
assertEquals(actual, expected, delta, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(float[] actual, String message, float[] expected, float delta) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertEqualDoubleArraysWithDelta {
|
||||
@BeforeTemplate
|
||||
void before(double[] actual, double[] expected, double delta) {
|
||||
assertEquals(actual, expected, delta);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(double[] actual, double[] expected, double delta) {
|
||||
assertThat(actual).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertEqualDoubleArraysWithDeltaWithMessage {
|
||||
@BeforeTemplate
|
||||
void before(double[] actual, String message, double[] expected, double delta) {
|
||||
assertEquals(actual, expected, delta, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(double[] actual, String message, double[] expected, double delta) {
|
||||
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertEqualArraysIrrespectiveOfOrder {
|
||||
@BeforeTemplate
|
||||
void before(Object[] actual, Object[] expected) {
|
||||
|
||||
@@ -142,6 +142,63 @@ final class TimeRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily transform an {@link Instant} to an equivalent instance. */
|
||||
static final class InstantIdentity {
|
||||
@BeforeTemplate
|
||||
Instant before(Instant instant, TemporalUnit temporalUnit) {
|
||||
return Refaster.anyOf(
|
||||
instant.plus(Duration.ZERO),
|
||||
instant.plus(0, temporalUnit),
|
||||
instant.plusNanos(0),
|
||||
instant.plusMillis(0),
|
||||
instant.plusSeconds(0),
|
||||
instant.minus(Duration.ZERO),
|
||||
instant.minus(0, temporalUnit),
|
||||
instant.minusNanos(0),
|
||||
instant.minusMillis(0),
|
||||
instant.minusSeconds(0),
|
||||
Instant.parse(instant.toString()),
|
||||
instant.truncatedTo(ChronoUnit.NANOS),
|
||||
Instant.ofEpochSecond(instant.getEpochSecond(), instant.getNano()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Instant after(Instant instant) {
|
||||
return instant;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Instant#truncatedTo(TemporalUnit)} over less obvious alternatives.
|
||||
*
|
||||
* <p>Note that {@link Instant#toEpochMilli()} throws an {@link ArithmeticException} for dates
|
||||
* very far in the past or future, while the suggested alternative doesn't.
|
||||
*/
|
||||
static final class InstantTruncatedToMilliseconds {
|
||||
@BeforeTemplate
|
||||
Instant before(Instant instant) {
|
||||
return Instant.ofEpochMilli(instant.toEpochMilli());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Instant after(Instant instant) {
|
||||
return instant.truncatedTo(ChronoUnit.MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Instant#truncatedTo(TemporalUnit)} over less obvious alternatives. */
|
||||
static final class InstantTruncatedToSeconds {
|
||||
@BeforeTemplate
|
||||
Instant before(Instant instant) {
|
||||
return Instant.ofEpochSecond(instant.getEpochSecond());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Instant after(Instant instant) {
|
||||
return instant.truncatedTo(ChronoUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Instant#atOffset(ZoneOffset)} over more verbose alternatives. */
|
||||
static final class InstantAtOffset {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -16,7 +16,7 @@ final class ClassCastLambdaUsageTest {
|
||||
"import java.util.stream.Stream;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" <T> void m() {",
|
||||
" Number localVariable = 0;",
|
||||
"",
|
||||
" Stream.of(0).map(i -> i);",
|
||||
@@ -32,13 +32,14 @@ final class ClassCastLambdaUsageTest {
|
||||
" i -> {",
|
||||
" return (Integer) i;",
|
||||
" });",
|
||||
" Stream.<ImmutableSet>of(ImmutableSet.of(5)).map(s -> (ImmutableSet<Number>) s);",
|
||||
" Stream.of(ImmutableSet.of(6)).map(s -> (ImmutableSet<?>) s);",
|
||||
" Stream.of(7).reduce((a, b) -> (Integer) a);",
|
||||
" IntStream.of(8).mapToObj(i -> (char) i);",
|
||||
" Stream.<ImmutableSet>of(ImmutableSet.of(6)).map(s -> (ImmutableSet<Number>) s);",
|
||||
" Stream.of(ImmutableSet.of(7)).map(s -> (ImmutableSet<?>) s);",
|
||||
" Stream.of(8).reduce((a, b) -> (Integer) a);",
|
||||
" IntStream.of(9).mapToObj(i -> (char) i);",
|
||||
" Stream.of(10).map(i -> (T) i);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Stream.of(8).map(i -> (Integer) i);",
|
||||
" Stream.of(11).map(i -> (Integer) i);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class EagerStringFormattingTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(EagerStringFormatting.class, getClass())
|
||||
.expectErrorMessage("DEFER", m -> m.contains("String formatting can be deferred\n"))
|
||||
.expectErrorMessage(
|
||||
"DEFER_EXTRA_VARIABLE",
|
||||
m ->
|
||||
m.contains(
|
||||
"String formatting can be deferred (but this requires introducing an effectively final variable)"))
|
||||
.expectErrorMessage(
|
||||
"DEFER_SIMPLIFIED_GUAVA",
|
||||
m ->
|
||||
m.contains(
|
||||
"String formatting can be deferred (assuming that Guava's simplified formatting support suffices)"))
|
||||
.expectErrorMessage(
|
||||
"DEFER_SIMPLIFIED_SLF4J",
|
||||
m ->
|
||||
m.contains(
|
||||
"String formatting can be deferred (assuming that SLF4J's simplified formatting support suffices)"))
|
||||
.expectErrorMessage(
|
||||
"VACUOUS", m -> m.contains("String formatting never yields `null` expression"))
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static com.google.common.base.Preconditions.checkNotNull;",
|
||||
"import static com.google.common.base.Preconditions.checkState;",
|
||||
"import static com.google.common.base.Verify.verify;",
|
||||
"import static com.google.common.base.Verify.verifyNotNull;",
|
||||
"import static java.util.Objects.requireNonNull;",
|
||||
"",
|
||||
"import java.util.Formattable;",
|
||||
"import java.util.Locale;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
" private int nonFinalField = 0;",
|
||||
"",
|
||||
" void m() {",
|
||||
" Formattable formattable = (formatter, flags, width, precision) -> {};",
|
||||
" int effectivelyFinalLocal = 0;",
|
||||
" /* A local variable that is also not effectively final. */",
|
||||
" int nonFinalLocal = 0;",
|
||||
" nonFinalLocal = 1;",
|
||||
"",
|
||||
" String.format(\"%s\", \"foo\");",
|
||||
" String.format(Locale.US, \"%s\", \"foo\");",
|
||||
" \"%s\".formatted(\"foo\");",
|
||||
" String.format(\"%s\", \"foo\", \"bar\");",
|
||||
" String.format(\"%s %s\", \"foo\", \"bar\");",
|
||||
" String.format(\"%s %s %%\", \"foo\", \"bar\");",
|
||||
"",
|
||||
" System.out.println(String.format(\"%s\", nonFinalLocal));",
|
||||
"",
|
||||
" requireNonNull(\"never-null\");",
|
||||
" requireNonNull(\"never-null\", () -> String.format(\"Format string: %s\", nonFinalField));",
|
||||
" // BUG: Diagnostic matches: VACUOUS",
|
||||
" requireNonNull(String.format(\"Never-null format string: %s\", nonFinalField));",
|
||||
" // BUG: Diagnostic matches: VACUOUS",
|
||||
" requireNonNull(\"Never-null format string: %s\".formatted(nonFinalField), \"message\");",
|
||||
" // BUG: Diagnostic matches: VACUOUS",
|
||||
" requireNonNull(",
|
||||
" String.format(\"Never-null format string\"), String.format(\"Malformed format string: %\"));",
|
||||
" // BUG: Diagnostic matches: DEFER_EXTRA_VARIABLE",
|
||||
" requireNonNull(\"never-null\", String.format(\"Format string: %s\", nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" requireNonNull(\"never-null\", String.format(\"Format string: %s\", effectivelyFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" requireNonNull(",
|
||||
" \"never-null\",",
|
||||
" String.format(",
|
||||
" \"Custom format string: %s, %d, %s\", getClass(), nonFinalField, \"string-constant\"));",
|
||||
"",
|
||||
" checkArgument(true);",
|
||||
" checkNotNull(\"never-null\");",
|
||||
" checkState(false);",
|
||||
" verify(true);",
|
||||
" verifyNotNull(\"never-null\");",
|
||||
" checkArgument(false, \"Without format string\");",
|
||||
" checkNotNull(\"never-null\", \"Without format string\");",
|
||||
" checkState(true, \"Without format string\");",
|
||||
" verify(false, \"Without format string\");",
|
||||
" verifyNotNull(\"never-null\", \"Without format string\");",
|
||||
" checkArgument(true, \"With format string: %s\", nonFinalLocal);",
|
||||
" checkNotNull(\"never-null\", \"With format string: %s\", nonFinalLocal);",
|
||||
" checkState(false, \"With format string: %s\", nonFinalLocal);",
|
||||
" verify(true, \"With format string: %s\", nonFinalLocal);",
|
||||
" verifyNotNull(\"never-null\", \"With format string: %s\", nonFinalLocal);",
|
||||
" // BUG: Diagnostic matches: VACUOUS",
|
||||
" checkNotNull(String.format(\"Never-null format string: %s\", nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: VACUOUS",
|
||||
" verifyNotNull(\"Never-null format string: %s\".formatted(nonFinalLocal), \"message\");",
|
||||
" // BUG: Diagnostic matches: VACUOUS",
|
||||
" checkNotNull(",
|
||||
" String.format(\"Never-null format string\"), String.format(\"Malformed format string: %\"));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" checkArgument(true, String.format(toString()));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" checkNotNull(\"never-null\", toString().formatted());",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" checkState(true, String.format(\"Custom format string: %d\", nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" verify(true, \"Mismatched format string:\".formatted(nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" verifyNotNull(\"never-null\", \"Mismatched format string: %d\".formatted());",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" checkArgument(true, String.format(\"Malformed format string: %\"));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" checkNotNull(\"never-null\", \"Format string with `Formattable`: %s\".formatted(formattable));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" checkState(true, String.format(\"Generated format string: %%s\"), nonFinalLocal);",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
|
||||
" verify(",
|
||||
" true,",
|
||||
" \"Format string with format string argument: %s\",",
|
||||
" String.format(\"Format string argument: %s\", nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" verifyNotNull(",
|
||||
" \"never-null\", String.format(\"Format string: %s, %s\", nonFinalLocal, nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" checkArgument(true, \"Format string: %s%%\".formatted(nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" checkNotNull(",
|
||||
" \"never-null\", String.format(Locale.US, \"Format string with locale: %s\", nonFinalLocal));",
|
||||
"",
|
||||
" LOG.trace(\"Without format string\");",
|
||||
" LOG.debug(\"With format string: {}\", nonFinalLocal);",
|
||||
" LOG.info((Marker) null, \"With marker\");",
|
||||
" LOG.warn((Marker) null, \"With marker and format string: {}\", nonFinalLocal);",
|
||||
" LOG.error(\"With throwable\", new RuntimeException());",
|
||||
" LOG.trace(\"With throwable and format string: {}\", nonFinalLocal, new RuntimeException());",
|
||||
" LOG.debug((Marker) null, \"With marker and throwable\", new RuntimeException());",
|
||||
" LOG.info(",
|
||||
" (Marker) null,",
|
||||
" \"With marker, throwable and format string: {}\",",
|
||||
" nonFinalLocal,",
|
||||
" new RuntimeException());",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.warn(String.format(toString()));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.error(toString().formatted());",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.trace(String.format(\"Custom format string: %d\", nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.debug(\"Mismatched format string:\".formatted(nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.info(\"Mismatched format string %d:\".formatted());",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.warn(String.format(\"Malformed format string: %\"));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.error(\"Format string with `Formattable`: %s\".formatted(formattable));",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.trace(String.format(\"Generated format string: {}\"), nonFinalLocal);",
|
||||
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
|
||||
" LOG.debug(",
|
||||
" \"Format string with format string argument: {}\",",
|
||||
" String.format(\"Format string argument: %s\", nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" LOG.info(String.format(\"Vacuous format string %%\"));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" LOG.warn(String.format(\"With format string: %s, %s\", nonFinalLocal, nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" LOG.error(String.format(Locale.ROOT, \"With vacuous localized format string %%\"));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" LOG.trace((Marker) null, String.format(\"With marker and format string: %s\", nonFinalLocal));",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" LOG.debug(",
|
||||
" String.format(\"With throwable and format string: %s\", nonFinalLocal),",
|
||||
" new RuntimeException());",
|
||||
" // BUG: Diagnostic matches: DEFER",
|
||||
" LOG.info(",
|
||||
" (Marker) null,",
|
||||
" String.format(\"With marker, throwable and format string: %s\", nonFinalLocal),",
|
||||
" new RuntimeException());",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(EagerStringFormatting.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static com.google.common.base.Preconditions.checkNotNull;",
|
||||
"import static com.google.common.base.Preconditions.checkState;",
|
||||
"import static com.google.common.base.Verify.verify;",
|
||||
"import static com.google.common.base.Verify.verifyNotNull;",
|
||||
"import static java.util.Objects.requireNonNull;",
|
||||
"",
|
||||
"import java.util.Locale;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
" private static final String GUAVA_COMPATIBLE_PATTERN = \"with-only-%s-placeholder\";",
|
||||
" private static final String GUAVA_INCOMPATIBLE_PATTERN = \"with-%%-marker\";",
|
||||
"",
|
||||
" void m() {",
|
||||
" requireNonNull(\"never-null\", String.format(\"Format string: %s\", 0));",
|
||||
"",
|
||||
" checkArgument(true, String.format(\"Vacuous format string %%\"));",
|
||||
" checkNotNull(\"never-null\", \"Format string: %s %s%%\".formatted(1, 2));",
|
||||
" checkState(false, String.format(Locale.US, \"Format string with locale: %s\", 3));",
|
||||
" verify(true, GUAVA_COMPATIBLE_PATTERN.formatted(4));",
|
||||
" verifyNotNull(\"never-null\", String.format(Locale.ENGLISH, GUAVA_COMPATIBLE_PATTERN, 5));",
|
||||
" checkArgument(false, GUAVA_INCOMPATIBLE_PATTERN.formatted());",
|
||||
" checkNotNull(\"never-null\", String.format(GUAVA_INCOMPATIBLE_PATTERN));",
|
||||
"",
|
||||
" LOG.trace(\"Vacuous format string %%\".formatted());",
|
||||
" LOG.debug(String.format(\"With format string: %s, %s%%\", 6, 7));",
|
||||
" LOG.info(String.format(Locale.ROOT, \"With vacuous localized format string %%\"));",
|
||||
" LOG.warn((Marker) null, \"With marker and format string: %s\".formatted(8));",
|
||||
" LOG.error(",
|
||||
" String.format(Locale.US, \"With throwable and format string: %s, %s\", 9, 10),",
|
||||
" new RuntimeException());",
|
||||
" LOG.trace(",
|
||||
" (Marker) null,",
|
||||
" \"With marker, throwable and format string: %s\".formatted(11),",
|
||||
" new RuntimeException());",
|
||||
" LOG.debug(GUAVA_COMPATIBLE_PATTERN.formatted(12));",
|
||||
" LOG.info(String.format(Locale.ENGLISH, GUAVA_COMPATIBLE_PATTERN, 13));",
|
||||
" LOG.warn(GUAVA_INCOMPATIBLE_PATTERN.formatted());",
|
||||
" LOG.error(String.format(GUAVA_INCOMPATIBLE_PATTERN));",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static com.google.common.base.Preconditions.checkNotNull;",
|
||||
"import static com.google.common.base.Preconditions.checkState;",
|
||||
"import static com.google.common.base.Verify.verify;",
|
||||
"import static com.google.common.base.Verify.verifyNotNull;",
|
||||
"import static java.util.Objects.requireNonNull;",
|
||||
"",
|
||||
"import java.util.Locale;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
" private static final String GUAVA_COMPATIBLE_PATTERN = \"with-only-%s-placeholder\";",
|
||||
" private static final String GUAVA_INCOMPATIBLE_PATTERN = \"with-%%-marker\";",
|
||||
"",
|
||||
" void m() {",
|
||||
" requireNonNull(\"never-null\", () -> String.format(\"Format string: %s\", 0));",
|
||||
"",
|
||||
" checkArgument(true, \"Vacuous format string %\");",
|
||||
" checkNotNull(\"never-null\", \"Format string: %s %s%\", 1, 2);",
|
||||
" checkState(false, \"Format string with locale: %s\", 3);",
|
||||
" verify(true, GUAVA_COMPATIBLE_PATTERN, 4);",
|
||||
" verifyNotNull(\"never-null\", GUAVA_COMPATIBLE_PATTERN, 5);",
|
||||
" checkArgument(false, \"with-%-marker\");",
|
||||
" checkNotNull(\"never-null\", \"with-%-marker\");",
|
||||
"",
|
||||
" LOG.trace(\"Vacuous format string %\");",
|
||||
" LOG.debug(\"With format string: {}, {}%\", 6, 7);",
|
||||
" LOG.info(\"With vacuous localized format string %\");",
|
||||
" LOG.warn((Marker) null, \"With marker and format string: {}\", 8);",
|
||||
" LOG.error(\"With throwable and format string: {}, {}\", 9, 10, new RuntimeException());",
|
||||
" LOG.trace(",
|
||||
" (Marker) null, \"With marker, throwable and format string: {}\", 11, new RuntimeException());",
|
||||
" LOG.debug(\"with-only-{}-placeholder\", 12);",
|
||||
" LOG.info(\"with-only-{}-placeholder\", 13);",
|
||||
" LOG.warn(\"with-%-marker\");",
|
||||
" LOG.error(\"with-%-marker\");",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ExplicitArgumentEnumerationTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(ExplicitArgumentEnumeration.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"import org.jooq.impl.DSL;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.test.StepVerifier;",
|
||||
"",
|
||||
"class A {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private final int value = unaryMethod(ImmutableList.of(1, 2));",
|
||||
"",
|
||||
" void m() {",
|
||||
" ImmutableList<String> list = ImmutableList.of();",
|
||||
" assertThat(ImmutableList.of()).containsAnyElementsOf(list);",
|
||||
"",
|
||||
" ImmutableList.<ImmutableList<String>>builder().add(ImmutableList.of());",
|
||||
"",
|
||||
" DSL.row(ImmutableList.of(1, 2));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" unaryMethod(ImmutableList.of(1, 2));",
|
||||
" unaryMethodWithLessVisibleOverload(ImmutableList.of(1, 2));",
|
||||
" binaryMethod(ImmutableList.of(1, 2), 3);",
|
||||
"",
|
||||
" ImmutableList.builder()",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" .addAll(ImmutableList.of())",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" .addAll(ImmutableList.copyOf(new String[0]))",
|
||||
" .addAll(ImmutableList.copyOf(ImmutableList.of()))",
|
||||
" .build();",
|
||||
"",
|
||||
" assertThat(ImmutableList.of(1))",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" .containsAnyElementsOf(ImmutableList.of(1))",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" .isSubsetOf(ImmutableList.of(1));",
|
||||
"",
|
||||
" Flux.just(1, 2)",
|
||||
" .as(StepVerifier::create)",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" .expectNextSequence(ImmutableList.of(1, 2))",
|
||||
" .verifyComplete();",
|
||||
"",
|
||||
" CompilationTestHelper.newInstance(BugChecker.class, getClass())",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" .setArgs(ImmutableList.of(\"foo\"))",
|
||||
" .withClasspath();",
|
||||
" }",
|
||||
"",
|
||||
" private int unaryMethod(ImmutableList<Integer> args) {",
|
||||
" return 0;",
|
||||
" }",
|
||||
"",
|
||||
" private int unaryMethod(Integer... args) {",
|
||||
" return unaryMethod(ImmutableList.copyOf(args));",
|
||||
" }",
|
||||
"",
|
||||
" void unaryMethodWithLessVisibleOverload(ImmutableList<Integer> args) {}",
|
||||
"",
|
||||
" private void unaryMethodWithLessVisibleOverload(Integer... args) {",
|
||||
" unaryMethodWithLessVisibleOverload(ImmutableList.copyOf(args));",
|
||||
" }",
|
||||
"",
|
||||
" private void binaryMethod(ImmutableList<Integer> args, int extraArg) {}",
|
||||
"",
|
||||
" private void binaryMethod(Integer... args) {",
|
||||
" binaryMethod(ImmutableList.copyOf(args), 0);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(ExplicitArgumentEnumeration.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableMultiset;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"import java.util.Arrays;",
|
||||
"import java.util.List;",
|
||||
"import java.util.Set;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.test.StepVerifier;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" ImmutableList.builder().addAll(ImmutableList.of()).build();",
|
||||
"",
|
||||
" assertThat(ImmutableList.of()).containsAnyElementsOf(ImmutableMultiset.of());",
|
||||
" assertThat(ImmutableList.of()).containsAll(ImmutableSet.of());",
|
||||
" assertThat(ImmutableList.of()).containsExactlyElementsOf(List.of());",
|
||||
" assertThat(ImmutableList.of()).containsExactlyInAnyOrderElementsOf(Set.of());",
|
||||
" assertThat(ImmutableList.of()).containsSequence(Arrays.asList());",
|
||||
" assertThat(ImmutableList.of()).containsSubsequence(ImmutableList.of(1));",
|
||||
" assertThat(ImmutableList.of()).doesNotContainAnyElementsOf(ImmutableMultiset.of(2));",
|
||||
" assertThat(ImmutableList.of()).doesNotContainSequence(ImmutableSet.of(3));",
|
||||
" assertThat(ImmutableList.of()).doesNotContainSubsequence(List.of(4));",
|
||||
" assertThat(ImmutableList.of()).hasSameElementsAs(Set.of(5));",
|
||||
" assertThat(ImmutableList.of()).isSubsetOf(Arrays.asList(6));",
|
||||
"",
|
||||
" Flux.empty()",
|
||||
" .as(StepVerifier::create)",
|
||||
" .expectNextSequence(ImmutableList.of(1, 2))",
|
||||
" .verifyComplete();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(BugChecker.class, getClass())",
|
||||
" .setArgs(ImmutableList.of(\"foo\", \"bar\"));",
|
||||
" CompilationTestHelper.newInstance(BugChecker.class, getClass())",
|
||||
" .setArgs(ImmutableList.of(\"foo\", \"bar\"));",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableMultiset;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"import java.util.Arrays;",
|
||||
"import java.util.List;",
|
||||
"import java.util.Set;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.test.StepVerifier;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" ImmutableList.builder().add().build();",
|
||||
"",
|
||||
" assertThat(ImmutableList.of()).containsAnyOf();",
|
||||
" assertThat(ImmutableList.of()).contains();",
|
||||
" assertThat(ImmutableList.of()).containsExactly();",
|
||||
" assertThat(ImmutableList.of()).containsExactlyInAnyOrder();",
|
||||
" assertThat(ImmutableList.of()).containsSequence();",
|
||||
" assertThat(ImmutableList.of()).containsSubsequence(1);",
|
||||
" assertThat(ImmutableList.of()).doesNotContain(2);",
|
||||
" assertThat(ImmutableList.of()).doesNotContainSequence(3);",
|
||||
" assertThat(ImmutableList.of()).doesNotContainSubsequence(4);",
|
||||
" assertThat(ImmutableList.of()).containsOnly(5);",
|
||||
" assertThat(ImmutableList.of()).isSubsetOf(6);",
|
||||
"",
|
||||
" Flux.empty().as(StepVerifier::create).expectNext(1, 2).verifyComplete();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(BugChecker.class, getClass()).setArgs(\"foo\", \"bar\");",
|
||||
" CompilationTestHelper.newInstance(BugChecker.class, getClass()).setArgs(\"foo\", \"bar\");",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ final class IdentityConversionTest {
|
||||
"import com.google.common.collect.ImmutableTable;",
|
||||
"import com.google.errorprone.matchers.Matcher;",
|
||||
"import com.google.errorprone.matchers.Matchers;",
|
||||
"import java.time.Instant;",
|
||||
"import java.time.ZonedDateTime;",
|
||||
"import reactor.adapter.rxjava.RxJava2Adapter;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
@@ -149,6 +151,10 @@ final class IdentityConversionTest {
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableTable<Object, Object, Object> o11 = ImmutableTable.copyOf(ImmutableTable.of());",
|
||||
"",
|
||||
" Instant instant1 = Instant.from(ZonedDateTime.now());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Instant instant2 = Instant.from(Instant.now());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Matcher allOf1 = Matchers.allOf(instanceMethod());",
|
||||
" Matcher allOf2 = Matchers.allOf(instanceMethod(), staticMethod());",
|
||||
|
||||
@@ -11,7 +11,7 @@ final class JUnitMethodDeclarationTest {
|
||||
CompilationTestHelper.newInstance(JUnitMethodDeclaration.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.*;",
|
||||
"",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.AfterEach;",
|
||||
@@ -154,8 +154,10 @@ final class JUnitMethodDeclarationTest {
|
||||
" void overload() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that `arguments` is already statically imported)",
|
||||
" void testArguments() {}",
|
||||
" // BUG: Diagnostic contains: (but note that another method named `arguments` is in scope)",
|
||||
" void testArguments() {",
|
||||
" arguments();",
|
||||
" }",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that `public` is not a valid identifier)",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
@@ -294,9 +293,8 @@ final class LexicographicalAnnotationAttributeListingTest {
|
||||
/* Some violations are not flagged because they are not in- or excluded. */
|
||||
CompilationTestHelper.newInstance(LexicographicalAnnotationAttributeListing.class, getClass())
|
||||
.setArgs(
|
||||
ImmutableList.of(
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar",
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value"))
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar",
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value")
|
||||
.addSourceLines(
|
||||
"pkg/A.java",
|
||||
"package pkg;",
|
||||
|
||||
@@ -55,6 +55,10 @@ final class NonStaticImportTest {
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.Instant.MIN;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.InstantSource.system;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.LocalDate.EPOCH;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.ZoneOffset.SHORT_IDS;",
|
||||
"import static java.time.ZoneOffset.UTC;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
@@ -71,6 +75,7 @@ final class NonStaticImportTest {
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.time.Instant;",
|
||||
"import java.time.LocalDate;",
|
||||
"import java.time.ZoneOffset;",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Map;",
|
||||
@@ -82,8 +87,10 @@ final class NonStaticImportTest {
|
||||
" void m() {",
|
||||
" nullToEmpty(null);",
|
||||
" copyOf(ImmutableList.of());",
|
||||
" LocalDate epoch = EPOCH;",
|
||||
" int max = MAX_VALUE;",
|
||||
" int min = MIN_VALUE;",
|
||||
" system();",
|
||||
" systemUTC();",
|
||||
" Instant minInstant = MIN;",
|
||||
" Map<String, String> shortIds = SHORT_IDS;",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
@@ -408,8 +407,7 @@ final class RedundantStringConversionTest {
|
||||
void identificationOfCustomConversionMethod() {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.setArgs(
|
||||
ImmutableList.of(
|
||||
"-XepOpt:RedundantStringConversion:ExtraConversionMethods=java.lang.Enum#name(),A#name(),A.B#toString(int)"))
|
||||
"-XepOpt:RedundantStringConversion:ExtraConversionMethods=java.lang.Enum#name(),A#name(),A.B#toString(int)")
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.math.RoundingMode;",
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class RedundantStringEscapeTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(RedundantStringEscape.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.Arrays;",
|
||||
"import java.util.List;",
|
||||
"",
|
||||
"class A {",
|
||||
" List<String> m() {",
|
||||
" return Arrays.asList(",
|
||||
" \"foo\",",
|
||||
" \"ß\",",
|
||||
" \"'\",",
|
||||
" \"\\\"\",",
|
||||
" \"\\\\\",",
|
||||
" \"\\\\'\",",
|
||||
" \"'\\\\\",",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"\\\\\\'\",",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"\\'\\\\\",",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"\\'\",",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"'\\'\",",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"\\''\",",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"\\'\\'\",",
|
||||
" (",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" /* Leading comment. */ \"\\'\" /* Trailing comment. */),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"\\'foo\\\"bar\\'baz\\\"qux\\'\");",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(RedundantStringEscape.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import java.util.Arrays;",
|
||||
"import java.util.List;",
|
||||
"",
|
||||
"class A {",
|
||||
" List<String> m() {",
|
||||
" return Arrays.asList(",
|
||||
" \"\\'\",",
|
||||
" \"'\\'\",",
|
||||
" \"\\''\",",
|
||||
" \"\\'\\'\",",
|
||||
" \"\\'ß\\'\",",
|
||||
" (",
|
||||
" /* Leading comment. */ \"\\'\" /* Trailing comment. */),",
|
||||
" \"\\'foo\\\"bar\\'baz\\\"qux\\'\");",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import java.util.Arrays;",
|
||||
"import java.util.List;",
|
||||
"",
|
||||
"class A {",
|
||||
" List<String> m() {",
|
||||
" return Arrays.asList(",
|
||||
" \"'\",",
|
||||
" \"''\",",
|
||||
" \"''\",",
|
||||
" \"''\",",
|
||||
" \"'ß'\",",
|
||||
" (",
|
||||
" /* Leading comment. */ \"'\" /* Trailing comment. */),",
|
||||
" \"'foo\\\"bar'baz\\\"qux'\");",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
@@ -189,7 +188,7 @@ final class Slf4jLoggerDeclarationTest {
|
||||
@Test
|
||||
void replacementWithCustomLoggerName() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
|
||||
.setArgs(ImmutableList.of("-XepOpt:Slf4jLogDeclaration:CanonicalStaticLoggerName=FOO_BAR"))
|
||||
.setArgs("-XepOpt:Slf4jLoggerDeclaration:CanonicalStaticLoggerName=FOO_BAR")
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import org.slf4j.Logger;",
|
||||
|
||||
@@ -21,6 +21,7 @@ final class TimeZoneUsageTest {
|
||||
"import java.time.OffsetTime;",
|
||||
"import java.time.ZoneId;",
|
||||
"import java.time.ZonedDateTime;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
@@ -31,68 +32,122 @@ final class TimeZoneUsageTest {
|
||||
" Clock.tick(clock, Duration.ZERO);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Clock.systemUTC();",
|
||||
" clock.getZone();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Clock.systemDefaultZone();",
|
||||
" Mono.fromSupplier(clock::getZone);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" clock.withZone(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(clock::withZone);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Clock.system(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(Clock::system);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Clock.systemDefaultZone();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(Clock::systemDefaultZone);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Clock.systemUTC();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(Clock::systemUTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Clock.tickMillis(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(Clock::tickMillis);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Clock.tickMinutes(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(Clock::tickMinutes);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Clock.tickSeconds(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" clock.getZone();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" clock.withZone(UTC);",
|
||||
" Mono.<ZoneId>empty().map(Clock::tickSeconds);",
|
||||
"",
|
||||
" Instant.now(clock);",
|
||||
" Mono.<Clock>empty().map(Instant::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Instant.now();",
|
||||
" // This is equivalent to `clock.instant()`, which is fine.",
|
||||
" Instant.now(clock);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(Instant::now);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalDate.now();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(LocalDate::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalDate.now(clock);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<Clock>empty().map(LocalDate::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalDate.now(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(LocalDate::now);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalDateTime.now();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(LocalDateTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalDateTime.now(clock);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<Clock>empty().map(LocalDateTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalDateTime.now(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(LocalDateTime::now);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalTime.now();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(LocalTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalTime.now(clock);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<Clock>empty().map(LocalTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LocalTime.now(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(LocalTime::now);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" OffsetDateTime.now();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(OffsetDateTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" OffsetDateTime.now(clock);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<Clock>empty().map(OffsetDateTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" OffsetDateTime.now(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(OffsetDateTime::now);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" OffsetTime.now();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(OffsetTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" OffsetTime.now(clock);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<Clock>empty().map(OffsetTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" OffsetTime.now(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(OffsetTime::now);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ZonedDateTime.now();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.fromSupplier(ZonedDateTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ZonedDateTime.now(clock);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<Clock>empty().map(ZonedDateTime::now);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ZonedDateTime.now(UTC);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.<ZoneId>empty().map(ZonedDateTime::now);",
|
||||
" }",
|
||||
"",
|
||||
" abstract class ForwardingClock extends Clock {",
|
||||
|
||||
@@ -23,6 +23,8 @@ final class RefasterRulesTest {
|
||||
AssertJEnumerableRules.class,
|
||||
AssertJFloatRules.class,
|
||||
AssertJIntegerRules.class,
|
||||
AssertJIterableRules.class,
|
||||
AssertJIteratorRules.class,
|
||||
AssertJLongRules.class,
|
||||
AssertJMapRules.class,
|
||||
AssertJNumberRules.class,
|
||||
@@ -36,13 +38,13 @@ final class RefasterRulesTest {
|
||||
AssortedRules.class,
|
||||
BigDecimalRules.class,
|
||||
BugCheckerRules.class,
|
||||
CharSequenceRules.class,
|
||||
ClassRules.class,
|
||||
CollectionRules.class,
|
||||
ComparatorRules.class,
|
||||
DoubleStreamRules.class,
|
||||
EqualityRules.class,
|
||||
FileRules.class,
|
||||
InputStreamRules.class,
|
||||
ImmutableEnumSetRules.class,
|
||||
ImmutableListRules.class,
|
||||
ImmutableListMultimapRules.class,
|
||||
@@ -53,6 +55,8 @@ final class RefasterRulesTest {
|
||||
ImmutableSortedMapRules.class,
|
||||
ImmutableSortedMultisetRules.class,
|
||||
ImmutableSortedSetRules.class,
|
||||
ImmutableTableRules.class,
|
||||
InputStreamRules.class,
|
||||
IntStreamRules.class,
|
||||
JUnitRules.class,
|
||||
JUnitToAssertJRules.class,
|
||||
|
||||
@@ -8,13 +8,16 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class AssertJCharSequenceRulesTest implements RefasterRuleCollectionTestCase {
|
||||
void testAssertThatCharSequenceIsEmpty() {
|
||||
assertThat("foo".length()).isEqualTo(0L);
|
||||
assertThat("foo".length()).isNotPositive();
|
||||
assertThat("foo".isEmpty()).isTrue();
|
||||
assertThat("bar".length()).isEqualTo(0L);
|
||||
assertThat("baz".length()).isNotPositive();
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatCharSequenceIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat("foo".length()).isNotEqualTo(0), assertThat("bar".length()).isPositive());
|
||||
assertThat("foo".isEmpty()).isFalse(),
|
||||
assertThat("bar".length()).isNotEqualTo(0),
|
||||
assertThat("baz".length()).isPositive());
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatCharSequenceHasSize() {
|
||||
|
||||
@@ -9,11 +9,15 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
final class AssertJCharSequenceRulesTest implements RefasterRuleCollectionTestCase {
|
||||
void testAssertThatCharSequenceIsEmpty() {
|
||||
assertThat("foo").isEmpty();
|
||||
assertThat("foo").isEmpty();
|
||||
assertThat("bar").isEmpty();
|
||||
assertThat("baz").isEmpty();
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatCharSequenceIsNotEmpty() {
|
||||
return ImmutableSet.of(assertThat("foo").isNotEmpty(), assertThat("bar").isNotEmpty());
|
||||
return ImmutableSet.of(
|
||||
assertThat("foo").isNotEmpty(),
|
||||
assertThat("bar").isNotEmpty(),
|
||||
assertThat("baz").isNotEmpty());
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatCharSequenceHasSize() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.EnumerableAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
@@ -14,14 +15,56 @@ final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase
|
||||
}
|
||||
|
||||
void testEnumerableAssertIsEmpty() {
|
||||
assertThat(ImmutableSet.of()).hasSize(0);
|
||||
assertThat(ImmutableSet.of()).hasSizeLessThanOrEqualTo(0);
|
||||
assertThat(ImmutableSet.of()).hasSizeLessThan(1);
|
||||
assertThat(ImmutableSet.of(1)).hasSize(0);
|
||||
assertThat(ImmutableSet.of(2)).hasSizeLessThanOrEqualTo(0);
|
||||
assertThat(ImmutableSet.of(3)).hasSizeLessThan(1);
|
||||
assertThat(ImmutableSet.of(4)).size().isNotPositive();
|
||||
}
|
||||
|
||||
ImmutableSet<EnumerableAssert<?, Character>> testEnumerableAssertIsNotEmpty() {
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat("foo").hasSizeGreaterThan(0), assertThat("bar").hasSizeGreaterThanOrEqualTo(1));
|
||||
assertThat(ImmutableSet.of(1)).hasSizeGreaterThan(0),
|
||||
assertThat(ImmutableSet.of(2)).hasSizeGreaterThanOrEqualTo(1),
|
||||
assertThat(ImmutableSet.of(3)).size().isNotEqualTo(0).returnToIterable(),
|
||||
assertThat(ImmutableSet.of(4)).size().isPositive().returnToIterable(),
|
||||
assertThat(ImmutableSet.of(5)).size().isNotEqualTo(0),
|
||||
assertThat(ImmutableSet.of(6)).size().isPositive());
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSize() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).size().isEqualTo(2).returnToIterable(),
|
||||
assertThat(ImmutableSet.of(3)).size().isEqualTo(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeLessThan() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).size().isLessThan(2).returnToIterable(),
|
||||
assertThat(ImmutableSet.of(3)).size().isLessThan(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeLessThanOrEqualTo() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).size().isLessThanOrEqualTo(2).returnToIterable(),
|
||||
assertThat(ImmutableSet.of(3)).size().isLessThanOrEqualTo(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeGreaterThan() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).size().isGreaterThan(2).returnToIterable(),
|
||||
assertThat(ImmutableSet.of(3)).size().isGreaterThan(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeGreaterThanOrEqualTo() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).size().isGreaterThanOrEqualTo(2).returnToIterable(),
|
||||
assertThat(ImmutableSet.of(3)).size().isGreaterThanOrEqualTo(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeBetween() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).size().isBetween(2, 3).returnToIterable(),
|
||||
assertThat(ImmutableSet.of(4)).size().isBetween(5, 6));
|
||||
}
|
||||
|
||||
ImmutableSet<EnumerableAssert<?, Integer>> testEnumerableAssertHasSameSizeAs() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.EnumerableAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
@@ -14,13 +15,55 @@ final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase
|
||||
}
|
||||
|
||||
void testEnumerableAssertIsEmpty() {
|
||||
assertThat(ImmutableSet.of()).isEmpty();
|
||||
assertThat(ImmutableSet.of()).isEmpty();
|
||||
assertThat(ImmutableSet.of()).isEmpty();
|
||||
assertThat(ImmutableSet.of(1)).isEmpty();
|
||||
assertThat(ImmutableSet.of(2)).isEmpty();
|
||||
assertThat(ImmutableSet.of(3)).isEmpty();
|
||||
assertThat(ImmutableSet.of(4)).isEmpty();
|
||||
}
|
||||
|
||||
ImmutableSet<EnumerableAssert<?, Character>> testEnumerableAssertIsNotEmpty() {
|
||||
return ImmutableSet.of(assertThat("foo").isNotEmpty(), assertThat("bar").isNotEmpty());
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).isNotEmpty(),
|
||||
assertThat(ImmutableSet.of(2)).isNotEmpty(),
|
||||
assertThat(ImmutableSet.of(3)).isNotEmpty(),
|
||||
assertThat(ImmutableSet.of(4)).isNotEmpty(),
|
||||
assertThat(ImmutableSet.of(5)).isNotEmpty(),
|
||||
assertThat(ImmutableSet.of(6)).isNotEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSize() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).hasSize(2), assertThat(ImmutableSet.of(3)).hasSize(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeLessThan() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).hasSizeLessThan(2),
|
||||
assertThat(ImmutableSet.of(3)).hasSizeLessThan(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeLessThanOrEqualTo() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).hasSizeLessThanOrEqualTo(2),
|
||||
assertThat(ImmutableSet.of(3)).hasSizeLessThanOrEqualTo(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeGreaterThan() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).hasSizeGreaterThan(2),
|
||||
assertThat(ImmutableSet.of(3)).hasSizeGreaterThan(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeGreaterThanOrEqualTo() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).hasSizeGreaterThanOrEqualTo(2),
|
||||
assertThat(ImmutableSet.of(3)).hasSizeGreaterThanOrEqualTo(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertHasSizeBetween() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).hasSizeBetween(2, 3),
|
||||
assertThat(ImmutableSet.of(4)).hasSizeBetween(5, 6));
|
||||
}
|
||||
|
||||
ImmutableSet<EnumerableAssert<?, Integer>> testEnumerableAssertHasSameSizeAs() {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class AssertJIterableRulesTest implements RefasterRuleCollectionTestCase {
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Iterables.class);
|
||||
}
|
||||
|
||||
void testAssertThatIterableIsEmpty() {
|
||||
assertThat(ImmutableSet.of(1).iterator()).isExhausted();
|
||||
assertThat(ImmutableSet.of(2).isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatIterableIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1).iterator()).hasNext(),
|
||||
assertThat(ImmutableSet.of(2).isEmpty()).isFalse());
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractIntegerAssert<?>> testAssertThatIterableSize() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(Iterables.size(ImmutableSet.of(1))), assertThat(ImmutableSet.of(2).size()));
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatIterableHasOneElementEqualTo() {
|
||||
return assertThat(Iterables.getOnlyElement(ImmutableSet.of(new Object()))).isEqualTo("foo");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class AssertJIterableRulesTest implements RefasterRuleCollectionTestCase {
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Iterables.class);
|
||||
}
|
||||
|
||||
void testAssertThatIterableIsEmpty() {
|
||||
assertThat(ImmutableSet.of(1)).isEmpty();
|
||||
assertThat(ImmutableSet.of(2)).isEmpty();
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatIterableIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).isNotEmpty(), assertThat(ImmutableSet.of(2)).isNotEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractIntegerAssert<?>> testAssertThatIterableSize() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableSet.of(1)).size(), assertThat(ImmutableSet.of(2)).size());
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatIterableHasOneElementEqualTo() {
|
||||
return assertThat(ImmutableSet.of(new Object())).containsExactly("foo");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class AssertJIteratorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
AbstractAssert<?, ?> testAssertThatHasNext() {
|
||||
return assertThat(ImmutableSet.of().iterator().hasNext()).isTrue();
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatIsExhausted() {
|
||||
return assertThat(ImmutableSet.of().iterator().hasNext()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class AssertJIteratorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
AbstractAssert<?, ?> testAssertThatHasNext() {
|
||||
return assertThat(ImmutableSet.of().iterator()).hasNext();
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatIsExhausted() {
|
||||
return assertThat(ImmutableSet.of().iterator()).isExhausted();
|
||||
}
|
||||
}
|
||||
@@ -21,16 +21,16 @@ final class AssertJStringRulesTest implements RefasterRuleCollectionTestCase {
|
||||
assertThat("foo").isEqualTo("");
|
||||
}
|
||||
|
||||
void testAssertThatStringIsEmpty() {
|
||||
assertThat("foo".isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
AbstractStringAssert<?> testAbstractStringAssertStringIsNotEmpty() {
|
||||
return assertThat("foo").isNotEqualTo("");
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatStringIsNotEmpty() {
|
||||
return assertThat("foo".isEmpty()).isFalse();
|
||||
AbstractAssert<?, ?> testAssertThatStringContains() {
|
||||
return assertThat("foo".contains("bar")).isTrue();
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatStringDoesNotContain() {
|
||||
return assertThat("foo".contains("bar")).isFalse();
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMatches() {
|
||||
|
||||
@@ -22,16 +22,16 @@ final class AssertJStringRulesTest implements RefasterRuleCollectionTestCase {
|
||||
assertThat("foo").isEmpty();
|
||||
}
|
||||
|
||||
void testAssertThatStringIsEmpty() {
|
||||
assertThat("foo").isEmpty();
|
||||
}
|
||||
|
||||
AbstractStringAssert<?> testAbstractStringAssertStringIsNotEmpty() {
|
||||
return assertThat("foo").isNotEmpty();
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatStringIsNotEmpty() {
|
||||
return assertThat("foo").isNotEmpty();
|
||||
AbstractAssert<?, ?> testAssertThatStringContains() {
|
||||
return assertThat("foo").contains("bar");
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatStringDoesNotContain() {
|
||||
return assertThat("foo").doesNotContain("bar");
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMatches() {
|
||||
|
||||
@@ -6,6 +6,8 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNullPointerException;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.throwable;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
@@ -20,7 +22,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
assertThatIOException(),
|
||||
assertThatIllegalArgumentException(),
|
||||
assertThatIllegalStateException(),
|
||||
assertThatNullPointerException());
|
||||
assertThatNullPointerException(),
|
||||
type(Throwable.class));
|
||||
}
|
||||
|
||||
void testAssertThatThrownByIsInstanceOf() {
|
||||
assertThatThrownBy(() -> {}).asInstanceOf(throwable(IllegalArgumentException.class));
|
||||
assertThatThrownBy(() -> {}).asInstanceOf(type(IllegalArgumentException.class));
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentException() {
|
||||
@@ -31,6 +39,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
return assertThatIllegalArgumentException().isThrownBy(() -> {}).withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage() {
|
||||
return assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> {})
|
||||
.havingRootCause()
|
||||
.withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionHasMessageParameters() {
|
||||
return assertThatIllegalArgumentException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
|
||||
}
|
||||
@@ -59,6 +74,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
return assertThatIllegalStateException().isThrownBy(() -> {}).withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionRootCauseHasMessage() {
|
||||
return assertThatIllegalStateException()
|
||||
.isThrownBy(() -> {})
|
||||
.havingRootCause()
|
||||
.withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionHasMessageParameters() {
|
||||
return assertThatIllegalStateException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
|
||||
}
|
||||
@@ -83,6 +105,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
return assertThatNullPointerException().isThrownBy(() -> {}).withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionRootCauseHasMessage() {
|
||||
return assertThatNullPointerException()
|
||||
.isThrownBy(() -> {})
|
||||
.havingRootCause()
|
||||
.withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionHasMessageParameters() {
|
||||
return assertThatNullPointerException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
|
||||
}
|
||||
@@ -107,6 +136,10 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
return assertThatIOException().isThrownBy(() -> {}).withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionRootCauseHasMessage() {
|
||||
return assertThatIOException().isThrownBy(() -> {}).havingRootCause().withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionHasMessageParameters() {
|
||||
return assertThatIOException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
|
||||
}
|
||||
@@ -123,7 +156,7 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
return assertThatIOException().isThrownBy(() -> {}).withMessageNotContaining("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownBy() {
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByAsInstanceOfThrowable() {
|
||||
return assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {});
|
||||
}
|
||||
|
||||
@@ -133,6 +166,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
.withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByRootCauseHasMessage() {
|
||||
return assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> {})
|
||||
.havingRootCause()
|
||||
.withMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessageParameters() {
|
||||
return assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> {})
|
||||
|
||||
@@ -6,6 +6,8 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNullPointerException;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.throwable;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.io.IOException;
|
||||
@@ -21,7 +23,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
assertThatIOException(),
|
||||
assertThatIllegalArgumentException(),
|
||||
assertThatIllegalStateException(),
|
||||
assertThatNullPointerException());
|
||||
assertThatNullPointerException(),
|
||||
type(Throwable.class));
|
||||
}
|
||||
|
||||
void testAssertThatThrownByIsInstanceOf() {
|
||||
assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentException() {
|
||||
@@ -34,6 +42,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
.hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.rootCause()
|
||||
.hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionHasMessageParameters() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
@@ -68,6 +83,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
return assertThatThrownBy(() -> {}).isInstanceOf(IllegalStateException.class).hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionRootCauseHasMessage() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.rootCause()
|
||||
.hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionHasMessageParameters() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
@@ -100,6 +122,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
return assertThatThrownBy(() -> {}).isInstanceOf(NullPointerException.class).hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionRootCauseHasMessage() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(NullPointerException.class)
|
||||
.rootCause()
|
||||
.hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionHasMessageParameters() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(NullPointerException.class)
|
||||
@@ -132,6 +161,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
return assertThatThrownBy(() -> {}).isInstanceOf(IOException.class).hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionRootCauseHasMessage() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(IOException.class)
|
||||
.rootCause()
|
||||
.hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionHasMessageParameters() {
|
||||
return assertThatThrownBy(() -> {}).isInstanceOf(IOException.class).hasMessage("foo %s", "bar");
|
||||
}
|
||||
@@ -152,8 +188,8 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
.hasMessageNotContaining("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownBy() {
|
||||
return assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class);
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByAsInstanceOfThrowable() {
|
||||
return assertThatThrownBy(() -> {}).asInstanceOf(throwable(IllegalArgumentException.class));
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessage() {
|
||||
@@ -162,6 +198,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
|
||||
.hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByRootCauseHasMessage() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.rootCause()
|
||||
.hasMessage("foo");
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessageParameters() {
|
||||
return assertThatThrownBy(() -> {})
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.sun.tools.javac.util.Constants;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import javax.lang.model.element.Name;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
@@ -11,7 +12,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Convert.class, FixChoosers.class);
|
||||
return ImmutableSet.of(Constants.class, Convert.class, FixChoosers.class);
|
||||
}
|
||||
|
||||
ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() {
|
||||
@@ -29,8 +30,8 @@ final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
|
||||
.addOutputLines("A.java", "class A {}");
|
||||
}
|
||||
|
||||
String testConstantsFormat() {
|
||||
return String.format("\"%s\"", Convert.quote("foo"));
|
||||
ImmutableSet<String> testConstantsFormat() {
|
||||
return ImmutableSet.of(Constants.format("foo"), String.format("\"%s\"", Convert.quote("bar")));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testNameContentEquals() {
|
||||
|
||||
@@ -8,11 +8,12 @@ import com.sun.tools.javac.util.Constants;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import javax.lang.model.element.Name;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Convert.class, FixChoosers.class);
|
||||
return ImmutableSet.of(Constants.class, Convert.class, FixChoosers.class);
|
||||
}
|
||||
|
||||
ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() {
|
||||
@@ -28,8 +29,10 @@ final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
|
||||
.expectUnchanged();
|
||||
}
|
||||
|
||||
String testConstantsFormat() {
|
||||
return Constants.format("foo");
|
||||
ImmutableSet<String> testConstantsFormat() {
|
||||
return ImmutableSet.of(
|
||||
SourceCode.toStringConstantExpression("foo", /* REPLACEME */ null),
|
||||
SourceCode.toStringConstantExpression("bar", /* REPLACEME */ null));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testNameContentEquals() {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class CharSequenceRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Boolean> testCharSequenceIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
new StringBuilder("foo").length() == 0,
|
||||
new StringBuilder("bar").length() <= 0,
|
||||
new StringBuilder("baz").length() < 1,
|
||||
new StringBuilder("qux").length() != 0,
|
||||
new StringBuilder("quux").length() > 0,
|
||||
new StringBuilder("corge").length() >= 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class CharSequenceRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Boolean> testCharSequenceIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
new StringBuilder("foo").isEmpty(),
|
||||
new StringBuilder("bar").isEmpty(),
|
||||
new StringBuilder("baz").isEmpty(),
|
||||
!new StringBuilder("qux").isEmpty(),
|
||||
!new StringBuilder("quux").isEmpty(),
|
||||
!new StringBuilder("corge").isEmpty());
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Iterables.removeAll(new ArrayList<>(), ImmutableSet.of("foo"));
|
||||
}
|
||||
|
||||
void testSetRemoveAllCollection() {
|
||||
void testCollectionRemoveAllFromCollectionBlock() {
|
||||
ImmutableSet.of("foo").forEach(new HashSet<>()::remove);
|
||||
for (Number element : ImmutableList.of(1)) {
|
||||
new HashSet<Number>().remove(element);
|
||||
|
||||
@@ -58,7 +58,7 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return new ArrayList<>().removeAll(ImmutableSet.of("foo"));
|
||||
}
|
||||
|
||||
void testSetRemoveAllCollection() {
|
||||
void testCollectionRemoveAllFromCollectionBlock() {
|
||||
new HashSet<>().removeAll(ImmutableSet.of("foo"));
|
||||
new HashSet<Number>().removeAll(ImmutableList.of(1));
|
||||
new HashSet<Number>().removeAll(ImmutableSet.of(2));
|
||||
|
||||
@@ -39,4 +39,16 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
|
||||
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
|
||||
return File.createTempFile("foo", "bar", new File("baz"));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testPathToFileMkDirsFilesExists() {
|
||||
return ImmutableSet.of(
|
||||
Files.exists(Path.of("foo")) || Path.of("foo").toFile().mkdirs(),
|
||||
!Files.exists(Path.of("bar")) && !Path.of("bar").toFile().mkdirs());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testFileMkDirsFileExists() {
|
||||
return ImmutableSet.of(
|
||||
new File("foo").exists() || new File("foo").mkdirs(),
|
||||
!new File("bar").exists() && !new File("bar").mkdirs());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,16 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
|
||||
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
|
||||
return Files.createTempFile(new File("baz").toPath(), "foo", "bar").toFile();
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testPathToFileMkDirsFilesExists() {
|
||||
return ImmutableSet.of(
|
||||
Path.of("foo").toFile().mkdirs() || Files.exists(Path.of("foo")),
|
||||
!Path.of("bar").toFile().mkdirs() && !Files.exists(Path.of("bar")));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testFileMkDirsFileExists() {
|
||||
return ImmutableSet.of(
|
||||
new File("foo").mkdirs() || new File("foo").exists(),
|
||||
!new File("bar").mkdirs() && !new File("bar").exists());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,13 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return new ImmutableMap.Builder<>();
|
||||
}
|
||||
|
||||
ImmutableMap<Object, Object> testImmutableMapBuilderBuildOrThrow() {
|
||||
return ImmutableMap.builder().build();
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableMap<String, Integer>> testEntryToImmutableMap() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.<String, Integer>builder().put(Map.entry("foo", 1)).build(),
|
||||
ImmutableMap.<String, Integer>builder().put(Map.entry("foo", 1)).buildOrThrow(),
|
||||
Stream.of(Map.entry("foo", 1))
|
||||
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
@@ -51,13 +55,14 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableMap.copyOf(Maps.asMap(ImmutableSet.of(10), Integer::valueOf)));
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableMap<String, Integer>> testEntryIterableToImmutableMap() {
|
||||
ImmutableSet<Map<String, Integer>> testEntryIterableToImmutableMap() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.copyOf(ImmutableMap.of("foo", 1).entrySet()),
|
||||
ImmutableMap.<String, Integer>builder().putAll(ImmutableMap.of("foo", 1)).build(),
|
||||
ImmutableMap.<String, Integer>builder().putAll(ImmutableMap.of("foo", 1)).buildOrThrow(),
|
||||
Map.copyOf(ImmutableMap.of("foo", 1)),
|
||||
ImmutableMap.<String, Integer>builder()
|
||||
.putAll(ImmutableMap.of("foo", 1).entrySet())
|
||||
.build(),
|
||||
.buildOrThrow(),
|
||||
ImmutableMap.of("foo", 1).entrySet().stream()
|
||||
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)),
|
||||
Streams.stream(Iterables.cycle(Map.entry("foo", 1)))
|
||||
@@ -100,32 +105,51 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.<String, String>builder().build(),
|
||||
ImmutableMap.<String, String>builder().buildOrThrow(),
|
||||
ImmutableMap.ofEntries(),
|
||||
Collections.<String, String>emptyMap(),
|
||||
Map.<String, String>of());
|
||||
}
|
||||
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf1() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.<String, String>builder().put("k1", "v1").build(),
|
||||
ImmutableMap.<String, String>builder().put("k1", "v1").buildOrThrow(),
|
||||
ImmutableMap.ofEntries(Map.entry("k1", "v1")),
|
||||
Collections.singletonMap("k1", "v1"),
|
||||
Map.of("k1", "v1"));
|
||||
}
|
||||
|
||||
Map<String, String> testImmutableMapOf2() {
|
||||
return Map.of("k1", "v1", "k2", "v2");
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf2() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.ofEntries(Map.entry("k1", "v1"), Map.entry("k2", "v2")),
|
||||
Map.of("k1", "v1", "k2", "v2"));
|
||||
}
|
||||
|
||||
Map<String, String> testImmutableMapOf3() {
|
||||
return Map.of("k1", "v1", "k2", "v2", "k3", "v3");
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf3() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.ofEntries(Map.entry("k1", "v1"), Map.entry("k2", "v2"), Map.entry("k3", "v3")),
|
||||
Map.of("k1", "v1", "k2", "v2", "k3", "v3"));
|
||||
}
|
||||
|
||||
Map<String, String> testImmutableMapOf4() {
|
||||
return Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4");
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf4() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.ofEntries(
|
||||
Map.entry("k1", "v1"),
|
||||
Map.entry("k2", "v2"),
|
||||
Map.entry("k3", "v3"),
|
||||
Map.entry("k4", "v4")),
|
||||
Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4"));
|
||||
}
|
||||
|
||||
Map<String, String> testImmutableMapOf5() {
|
||||
return Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5");
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf5() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.ofEntries(
|
||||
Map.entry("k1", "v1"),
|
||||
Map.entry("k2", "v2"),
|
||||
Map.entry("k3", "v3"),
|
||||
Map.entry("k4", "v4"),
|
||||
Map.entry("k5", "v5")),
|
||||
Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"));
|
||||
}
|
||||
|
||||
ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterKeys() {
|
||||
@@ -139,4 +163,11 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
.filter(entry -> entry.getValue() > 0)
|
||||
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
ImmutableSet<Map<String, Integer>> testImmutableMapOfEntries() {
|
||||
return ImmutableSet.of(
|
||||
Map.ofEntries(),
|
||||
Map.ofEntries(Map.entry("foo", 1)),
|
||||
Map.ofEntries(Map.entry("bar", 2), Map.entry("baz", 3)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableMap.builder();
|
||||
}
|
||||
|
||||
ImmutableMap<Object, Object> testImmutableMapBuilderBuildOrThrow() {
|
||||
return ImmutableMap.builder().buildOrThrow();
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableMap<String, Integer>> testEntryToImmutableMap() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of(Map.entry("foo", 1).getKey(), Map.entry("foo", 1).getValue()),
|
||||
@@ -46,8 +50,9 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Maps.toMap(ImmutableSet.of(10), Integer::valueOf));
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableMap<String, Integer>> testEntryIterableToImmutableMap() {
|
||||
ImmutableSet<Map<String, Integer>> testEntryIterableToImmutableMap() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.copyOf(ImmutableMap.of("foo", 1)),
|
||||
ImmutableMap.copyOf(ImmutableMap.of("foo", 1)),
|
||||
ImmutableMap.copyOf(ImmutableMap.of("foo", 1)),
|
||||
ImmutableMap.copyOf(ImmutableMap.of("foo", 1).entrySet()),
|
||||
@@ -83,28 +88,39 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf() {
|
||||
return ImmutableSet.of(ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
|
||||
}
|
||||
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf1() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("k1", "v1"), ImmutableMap.of("k1", "v1"), ImmutableMap.of("k1", "v1"));
|
||||
ImmutableMap.of("k1", "v1"),
|
||||
ImmutableMap.of("k1", "v1"),
|
||||
ImmutableMap.of("k1", "v1"),
|
||||
ImmutableMap.of("k1", "v1"));
|
||||
}
|
||||
|
||||
Map<String, String> testImmutableMapOf2() {
|
||||
return ImmutableMap.of("k1", "v1", "k2", "v2");
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf2() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("k1", "v1", "k2", "v2"), ImmutableMap.of("k1", "v1", "k2", "v2"));
|
||||
}
|
||||
|
||||
Map<String, String> testImmutableMapOf3() {
|
||||
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf3() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"),
|
||||
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"));
|
||||
}
|
||||
|
||||
Map<String, String> testImmutableMapOf4() {
|
||||
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4");
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf4() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4"),
|
||||
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4"));
|
||||
}
|
||||
|
||||
Map<String, String> testImmutableMapOf5() {
|
||||
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5");
|
||||
ImmutableSet<Map<String, String>> testImmutableMapOf5() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"),
|
||||
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"));
|
||||
}
|
||||
|
||||
ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterKeys() {
|
||||
@@ -114,4 +130,11 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterValues() {
|
||||
return ImmutableMap.copyOf(Maps.filterValues(ImmutableMap.of("foo", 1), v -> v > 0));
|
||||
}
|
||||
|
||||
ImmutableSet<Map<String, Integer>> testImmutableMapOfEntries() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.ofEntries(),
|
||||
ImmutableMap.ofEntries(Map.entry("foo", 1)),
|
||||
ImmutableMap.ofEntries(Map.entry("bar", 2), Map.entry("baz", 3)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,16 +32,16 @@ final class ImmutableSortedMapRulesTest implements RefasterRuleCollectionTestCas
|
||||
}
|
||||
|
||||
ImmutableSortedMap<String, Integer> testEmptyImmutableSortedMap() {
|
||||
return ImmutableSortedMap.<String, Integer>naturalOrder().build();
|
||||
return ImmutableSortedMap.<String, Integer>naturalOrder().buildOrThrow();
|
||||
}
|
||||
|
||||
ImmutableSortedMap<String, Integer> testPairToImmutableSortedMap() {
|
||||
return ImmutableSortedMap.<String, Integer>naturalOrder().put("foo", 1).build();
|
||||
return ImmutableSortedMap.<String, Integer>naturalOrder().put("foo", 1).buildOrThrow();
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableSortedMap<String, Integer>> testEntryToImmutableSortedMap() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableSortedMap.<String, Integer>naturalOrder().put(Map.entry("foo", 1)).build(),
|
||||
ImmutableSortedMap.<String, Integer>naturalOrder().put(Map.entry("foo", 1)).buildOrThrow(),
|
||||
Stream.of(Map.entry("foo", 1))
|
||||
.collect(toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
@@ -52,10 +52,10 @@ final class ImmutableSortedMapRulesTest implements RefasterRuleCollectionTestCas
|
||||
ImmutableSortedMap.copyOf(ImmutableSortedMap.of("foo", 1).entrySet()),
|
||||
ImmutableSortedMap.<String, Integer>naturalOrder()
|
||||
.putAll(ImmutableSortedMap.of("foo", 1))
|
||||
.build(),
|
||||
.buildOrThrow(),
|
||||
ImmutableSortedMap.<String, Integer>naturalOrder()
|
||||
.putAll(ImmutableSortedMap.of("foo", 1).entrySet())
|
||||
.build(),
|
||||
.buildOrThrow(),
|
||||
ImmutableSortedMap.of("foo", 1).entrySet().stream()
|
||||
.collect(toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)),
|
||||
Streams.stream(Iterables.cycle(Map.entry("foo", 1)))
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.collect.ImmutableTable.toImmutableTable;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.collect.Tables;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class ImmutableTableRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Table.class);
|
||||
}
|
||||
|
||||
ImmutableTable.Builder<String, Integer, String> testImmutableTableBuilder() {
|
||||
return new ImmutableTable.Builder<>();
|
||||
}
|
||||
|
||||
ImmutableTable<Object, Object, Object> testImmutableTableBuilderBuildOrThrow() {
|
||||
return ImmutableTable.builder().build();
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableTable<String, Integer, String>> testCellToImmutableTable() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableTable.<String, Integer, String>builder()
|
||||
.put(Tables.immutableCell("foo", 1, "bar"))
|
||||
.buildOrThrow(),
|
||||
Stream.of(Tables.immutableCell("baz", 2, "qux"))
|
||||
.collect(
|
||||
toImmutableTable(
|
||||
Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue)));
|
||||
}
|
||||
|
||||
ImmutableTable<Integer, String, Integer> testStreamOfCellsToImmutableTable() {
|
||||
return Stream.of(1, 2, 3)
|
||||
.map(n -> Tables.immutableCell(n, n.toString(), n * 2))
|
||||
.collect(
|
||||
toImmutableTable(
|
||||
Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue));
|
||||
}
|
||||
|
||||
ImmutableTable<String, String, String> testImmutableTableOf() {
|
||||
return ImmutableTable.<String, String, String>builder().buildOrThrow();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.collect.ImmutableTable.toImmutableTable;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.collect.Tables;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class ImmutableTableRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Table.class);
|
||||
}
|
||||
|
||||
ImmutableTable.Builder<String, Integer, String> testImmutableTableBuilder() {
|
||||
return ImmutableTable.builder();
|
||||
}
|
||||
|
||||
ImmutableTable<Object, Object, Object> testImmutableTableBuilderBuildOrThrow() {
|
||||
return ImmutableTable.builder().buildOrThrow();
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableTable<String, Integer, String>> testCellToImmutableTable() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableTable.of(
|
||||
Tables.immutableCell("foo", 1, "bar").getRowKey(),
|
||||
Tables.immutableCell("foo", 1, "bar").getColumnKey(),
|
||||
Tables.immutableCell("foo", 1, "bar").getValue()),
|
||||
ImmutableTable.of(
|
||||
Tables.immutableCell("baz", 2, "qux").getRowKey(),
|
||||
Tables.immutableCell("baz", 2, "qux").getColumnKey(),
|
||||
Tables.immutableCell("baz", 2, "qux").getValue()));
|
||||
}
|
||||
|
||||
ImmutableTable<Integer, String, Integer> testStreamOfCellsToImmutableTable() {
|
||||
return Stream.of(1, 2, 3).collect(toImmutableTable(n -> n, n -> n.toString(), n -> n * 2));
|
||||
}
|
||||
|
||||
ImmutableTable<String, String, String> testImmutableTableOf() {
|
||||
return ImmutableTable.of();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.offset;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
@@ -24,6 +26,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
assertInstanceOf(null, null),
|
||||
assertThrows(null, null),
|
||||
assertThrowsExactly(null, null),
|
||||
offset(0.0),
|
||||
(Runnable) () -> assertArrayEquals((int[]) null, null),
|
||||
(Runnable) () -> assertFalse(true),
|
||||
(Runnable) () -> assertNotNull(null),
|
||||
(Runnable) () -> assertNotSame(null, null),
|
||||
@@ -32,6 +36,138 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
(Runnable) () -> assertTrue(true));
|
||||
}
|
||||
|
||||
void testAssertThatBooleanArrayContainsExactly() {
|
||||
assertArrayEquals(new boolean[] {true}, new boolean[] {false});
|
||||
}
|
||||
|
||||
void testAssertThatBooleanArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new boolean[] {true}, new boolean[] {false}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatBooleanArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new boolean[] {true}, new boolean[] {false}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatByteArrayContainsExactly() {
|
||||
assertArrayEquals(new byte[] {1}, new byte[] {2});
|
||||
}
|
||||
|
||||
void testAssertThatByteArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new byte[] {1}, new byte[] {2}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatByteArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new byte[] {1}, new byte[] {2}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatCharArrayContainsExactly() {
|
||||
assertArrayEquals(new char[] {'a'}, new char[] {'b'});
|
||||
}
|
||||
|
||||
void testAssertThatCharArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new char[] {'a'}, new char[] {'b'}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatCharArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new char[] {'a'}, new char[] {'b'}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatShortArrayContainsExactly() {
|
||||
assertArrayEquals(new short[] {1}, new short[] {2});
|
||||
}
|
||||
|
||||
void testAssertThatShortArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new short[] {1}, new short[] {2}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatShortArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new short[] {1}, new short[] {2}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatIntArrayContainsExactly() {
|
||||
assertArrayEquals(new int[] {1}, new int[] {2});
|
||||
}
|
||||
|
||||
void testAssertThatIntArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new int[] {1}, new int[] {2}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatIntArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new int[] {1}, new int[] {2}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatLongArrayContainsExactly() {
|
||||
assertArrayEquals(new long[] {1L}, new long[] {2L});
|
||||
}
|
||||
|
||||
void testAssertThatLongArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new long[] {1L}, new long[] {2L}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatLongArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new long[] {1L}, new long[] {2L}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayContainsExactly() {
|
||||
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F});
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayContainsExactlyWithOffset() {
|
||||
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, 0.1f);
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayWithFailMessageContainsExactlyWithOffset() {
|
||||
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, 0.1f, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayWithFailMessageSupplierContainsExactlyWithOffset() {
|
||||
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, 0.1f, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayContainsExactly() {
|
||||
assertArrayEquals(new double[] {1.0}, new double[] {2.0});
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayContainsExactlyWithOffset() {
|
||||
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, 0.1);
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayWithFailMessageContainsExactlyWithOffset() {
|
||||
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, 0.1, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayWithFailMessageSupplierContainsExactlyWithOffset() {
|
||||
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, 0.1, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatObjectArrayContainsExactly() {
|
||||
assertArrayEquals(new Object[] {"foo"}, new Object[] {"bar"});
|
||||
}
|
||||
|
||||
void testAssertThatObjectArrayWithFailMessageContainsExactly() {
|
||||
assertArrayEquals(new Object[] {"foo"}, new Object[] {"bar"}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatObjectArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertArrayEquals(new Object[] {"foo"}, new Object[] {"bar"}, () -> "foo");
|
||||
}
|
||||
|
||||
Object testFail() {
|
||||
return Assertions.fail();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.offset;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
@@ -27,6 +29,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
assertInstanceOf(null, null),
|
||||
assertThrows(null, null),
|
||||
assertThrowsExactly(null, null),
|
||||
offset(0.0),
|
||||
(Runnable) () -> assertArrayEquals((int[]) null, null),
|
||||
(Runnable) () -> assertFalse(true),
|
||||
(Runnable) () -> assertNotNull(null),
|
||||
(Runnable) () -> assertNotSame(null, null),
|
||||
@@ -35,6 +39,150 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
(Runnable) () -> assertTrue(true));
|
||||
}
|
||||
|
||||
void testAssertThatBooleanArrayContainsExactly() {
|
||||
assertThat(new boolean[] {false}).containsExactly(new boolean[] {true});
|
||||
}
|
||||
|
||||
void testAssertThatBooleanArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new boolean[] {false}).withFailMessage("foo").containsExactly(new boolean[] {true});
|
||||
}
|
||||
|
||||
void testAssertThatBooleanArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new boolean[] {false})
|
||||
.withFailMessage(() -> "foo")
|
||||
.containsExactly(new boolean[] {true});
|
||||
}
|
||||
|
||||
void testAssertThatByteArrayContainsExactly() {
|
||||
assertThat(new byte[] {2}).containsExactly(new byte[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatByteArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new byte[] {2}).withFailMessage("foo").containsExactly(new byte[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatByteArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new byte[] {2}).withFailMessage(() -> "foo").containsExactly(new byte[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatCharArrayContainsExactly() {
|
||||
assertThat(new char[] {'b'}).containsExactly(new char[] {'a'});
|
||||
}
|
||||
|
||||
void testAssertThatCharArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new char[] {'b'}).withFailMessage("foo").containsExactly(new char[] {'a'});
|
||||
}
|
||||
|
||||
void testAssertThatCharArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new char[] {'b'}).withFailMessage(() -> "foo").containsExactly(new char[] {'a'});
|
||||
}
|
||||
|
||||
void testAssertThatShortArrayContainsExactly() {
|
||||
assertThat(new short[] {2}).containsExactly(new short[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatShortArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new short[] {2}).withFailMessage("foo").containsExactly(new short[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatShortArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new short[] {2}).withFailMessage(() -> "foo").containsExactly(new short[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatIntArrayContainsExactly() {
|
||||
assertThat(new int[] {2}).containsExactly(new int[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatIntArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new int[] {2}).withFailMessage("foo").containsExactly(new int[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatIntArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new int[] {2}).withFailMessage(() -> "foo").containsExactly(new int[] {1});
|
||||
}
|
||||
|
||||
void testAssertThatLongArrayContainsExactly() {
|
||||
assertThat(new long[] {2L}).containsExactly(new long[] {1L});
|
||||
}
|
||||
|
||||
void testAssertThatLongArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new long[] {2L}).withFailMessage("foo").containsExactly(new long[] {1L});
|
||||
}
|
||||
|
||||
void testAssertThatLongArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new long[] {2L}).withFailMessage(() -> "foo").containsExactly(new long[] {1L});
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayContainsExactly() {
|
||||
assertThat(new float[] {2.0F}).containsExactly(new float[] {1.0F});
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new float[] {2.0F}).withFailMessage("foo").containsExactly(new float[] {1.0F});
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new float[] {2.0F}).withFailMessage(() -> "foo").containsExactly(new float[] {1.0F});
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayContainsExactlyWithOffset() {
|
||||
assertThat(new float[] {2.0F}).containsExactly(new float[] {1.0F}, offset(0.1f));
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayWithFailMessageContainsExactlyWithOffset() {
|
||||
assertThat(new float[] {2.0F})
|
||||
.withFailMessage("foo")
|
||||
.containsExactly(new float[] {1.0F}, offset(0.1f));
|
||||
}
|
||||
|
||||
void testAssertThatFloatArrayWithFailMessageSupplierContainsExactlyWithOffset() {
|
||||
assertThat(new float[] {2.0F})
|
||||
.withFailMessage(() -> "foo")
|
||||
.containsExactly(new float[] {1.0F}, offset(0.1f));
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayContainsExactly() {
|
||||
assertThat(new double[] {2.0}).containsExactly(new double[] {1.0});
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new double[] {2.0}).withFailMessage("foo").containsExactly(new double[] {1.0});
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new double[] {2.0}).withFailMessage(() -> "foo").containsExactly(new double[] {1.0});
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayContainsExactlyWithOffset() {
|
||||
assertThat(new double[] {2.0}).containsExactly(new double[] {1.0}, offset(0.1));
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayWithFailMessageContainsExactlyWithOffset() {
|
||||
assertThat(new double[] {2.0})
|
||||
.withFailMessage("foo")
|
||||
.containsExactly(new double[] {1.0}, offset(0.1));
|
||||
}
|
||||
|
||||
void testAssertThatDoubleArrayWithFailMessageSupplierContainsExactlyWithOffset() {
|
||||
assertThat(new double[] {2.0})
|
||||
.withFailMessage(() -> "foo")
|
||||
.containsExactly(new double[] {1.0}, offset(0.1));
|
||||
}
|
||||
|
||||
void testAssertThatObjectArrayContainsExactly() {
|
||||
assertThat(new Object[] {"bar"}).containsExactly(new Object[] {"foo"});
|
||||
}
|
||||
|
||||
void testAssertThatObjectArrayWithFailMessageContainsExactly() {
|
||||
assertThat(new Object[] {"bar"}).withFailMessage("foo").containsExactly(new Object[] {"foo"});
|
||||
}
|
||||
|
||||
void testAssertThatObjectArrayWithFailMessageSupplierContainsExactly() {
|
||||
assertThat(new Object[] {"bar"})
|
||||
.withFailMessage(() -> "foo")
|
||||
.containsExactly(new Object[] {"foo"});
|
||||
}
|
||||
|
||||
Object testFail() {
|
||||
return org.assertj.core.api.Assertions.fail();
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.function.Predicate;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class NullRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(MoreObjects.class, Optional.class);
|
||||
return ImmutableSet.of(MoreObjects.class, Optional.class, not(null));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsNull() {
|
||||
@@ -30,11 +32,11 @@ final class NullRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.ofNullable("foo").orElseGet(() -> "bar");
|
||||
}
|
||||
|
||||
long testIsNullFunction() {
|
||||
return Stream.of("foo").filter(s -> s == null).count();
|
||||
ImmutableSet<Predicate<String>> testIsNullFunction() {
|
||||
return ImmutableSet.of(s -> s == null, not(Objects::nonNull));
|
||||
}
|
||||
|
||||
long testNonNullFunction() {
|
||||
return Stream.of("foo").filter(s -> s != null).count();
|
||||
ImmutableSet<Predicate<String>> testNonNullFunction() {
|
||||
return ImmutableSet.of(s -> s != null, not(Objects::isNull));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,19 @@ package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
import static java.util.Objects.requireNonNullElseGet;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.function.Predicate;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class NullRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(MoreObjects.class, Optional.class);
|
||||
return ImmutableSet.of(MoreObjects.class, Optional.class, not(null));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsNull() {
|
||||
@@ -32,11 +33,11 @@ final class NullRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return requireNonNullElseGet("foo", () -> "bar");
|
||||
}
|
||||
|
||||
long testIsNullFunction() {
|
||||
return Stream.of("foo").filter(Objects::isNull).count();
|
||||
ImmutableSet<Predicate<String>> testIsNullFunction() {
|
||||
return ImmutableSet.of(Objects::isNull, Objects::isNull);
|
||||
}
|
||||
|
||||
long testNonNullFunction() {
|
||||
return Stream.of("foo").filter(Objects::nonNull).count();
|
||||
ImmutableSet<Predicate<String>> testNonNullFunction() {
|
||||
return ImmutableSet.of(Objects::nonNull, Objects::nonNull);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.common.primitives.Shorts;
|
||||
import com.google.common.primitives.UnsignedBytes;
|
||||
import com.google.common.primitives.UnsignedInts;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import java.util.Comparator;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@@ -25,6 +27,7 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Ints.class,
|
||||
Longs.class,
|
||||
Shorts.class,
|
||||
UnsignedBytes.class,
|
||||
UnsignedInts.class,
|
||||
UnsignedLongs.class);
|
||||
}
|
||||
@@ -222,4 +225,16 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
String testLongToUnsignedStringWithRadix() {
|
||||
return UnsignedLongs.toString(1, 2);
|
||||
}
|
||||
|
||||
Comparator<byte[]> testArraysCompareUnsignedBytes() {
|
||||
return UnsignedBytes.lexicographicalComparator();
|
||||
}
|
||||
|
||||
Comparator<int[]> testArraysCompareUnsignedInts() {
|
||||
return UnsignedInts.lexicographicalComparator();
|
||||
}
|
||||
|
||||
Comparator<long[]> testArraysCompareUnsignedLongs() {
|
||||
return UnsignedLongs.lexicographicalComparator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,11 @@ import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.common.primitives.Shorts;
|
||||
import com.google.common.primitives.UnsignedBytes;
|
||||
import com.google.common.primitives.UnsignedInts;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@@ -25,6 +28,7 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Ints.class,
|
||||
Longs.class,
|
||||
Shorts.class,
|
||||
UnsignedBytes.class,
|
||||
UnsignedInts.class,
|
||||
UnsignedLongs.class);
|
||||
}
|
||||
@@ -222,4 +226,16 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
String testLongToUnsignedStringWithRadix() {
|
||||
return Long.toUnsignedString(1, 2);
|
||||
}
|
||||
|
||||
Comparator<byte[]> testArraysCompareUnsignedBytes() {
|
||||
return Arrays::compareUnsigned;
|
||||
}
|
||||
|
||||
Comparator<int[]> testArraysCompareUnsignedInts() {
|
||||
return Arrays::compareUnsigned;
|
||||
}
|
||||
|
||||
Comparator<long[]> testArraysCompareUnsignedLongs() {
|
||||
return Arrays::compareUnsigned;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -44,6 +45,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
List.class,
|
||||
ImmutableCollection.class,
|
||||
ImmutableMap.class,
|
||||
assertThat(false),
|
||||
assertThat(0),
|
||||
maxBy(null),
|
||||
minBy(null),
|
||||
@@ -186,7 +188,12 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxJust() {
|
||||
return ImmutableSet.of(Flux.range(0, 1), Mono.just(2).repeat().take(1));
|
||||
return ImmutableSet.of(
|
||||
Flux.range(0, 1),
|
||||
Mono.just(2).flux(),
|
||||
Mono.just(3).repeat().take(1),
|
||||
Flux.fromIterable(ImmutableList.of(4)),
|
||||
Flux.fromIterable(ImmutableSet.of(5)));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<?>> testMonoIdentity() {
|
||||
@@ -324,6 +331,14 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.just(1).switchMap(n -> Mono.fromSupplier(() -> n * 2)));
|
||||
}
|
||||
|
||||
Flux<String> testFluxMapNotNullTransformationOrElse() {
|
||||
return Flux.just(1).map(x -> Optional.of(x.toString())).mapNotNull(x -> x.orElse(null));
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxMapNotNullOrElse() {
|
||||
return Flux.just(Optional.of(1)).filter(Optional::isPresent).map(Optional::orElseThrow);
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testMonoFlux() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").flatMapMany(Mono::just),
|
||||
@@ -332,7 +347,11 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Void>> testMonoThen() {
|
||||
return ImmutableSet.of(Mono.just("foo").ignoreElement().then(), Mono.just("bar").flux().then());
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").ignoreElement().then(),
|
||||
Mono.just("bar").flux().then(),
|
||||
Mono.when(Mono.just("baz")),
|
||||
Mono.whenDelayError(Mono.just("qux")));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Void>> testFluxThen() {
|
||||
@@ -378,8 +397,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Mono<Optional<String>>> testMonoSingleOptional() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").flux().collect(toOptional()),
|
||||
Mono.just("bar").map(Optional::of).defaultIfEmpty(Optional.empty()),
|
||||
Mono.just("baz").transform(Mono::singleOptional));
|
||||
Mono.just("bar").map(Optional::of),
|
||||
Mono.just("baz").singleOptional().defaultIfEmpty(Optional.empty()),
|
||||
Mono.just("quux").singleOptional().switchIfEmpty(Mono.just(Optional.empty())),
|
||||
Mono.just("quuz").transform(Mono::singleOptional));
|
||||
}
|
||||
|
||||
Mono<Number> testMonoCast() {
|
||||
@@ -589,6 +610,35 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(PublisherProbe.of(Mono.empty()), PublisherProbe.of(Flux.empty()));
|
||||
}
|
||||
|
||||
void testPublisherProbeAssertWasSubscribed() {
|
||||
assertThat(PublisherProbe.of(Mono.just(1)).wasSubscribed()).isTrue();
|
||||
assertThat(PublisherProbe.of(Mono.just(2)).subscribeCount()).isNotNegative();
|
||||
assertThat(PublisherProbe.of(Mono.just(3)).subscribeCount()).isNotEqualTo(0);
|
||||
assertThat(PublisherProbe.of(Mono.just(4)).subscribeCount()).isPositive();
|
||||
}
|
||||
|
||||
void testPublisherProbeAssertWasNotSubscribed() {
|
||||
assertThat(PublisherProbe.of(Mono.just(1)).wasSubscribed()).isFalse();
|
||||
assertThat(PublisherProbe.of(Mono.just(2)).subscribeCount()).isEqualTo(0);
|
||||
assertThat(PublisherProbe.of(Mono.just(3)).subscribeCount()).isNotPositive();
|
||||
}
|
||||
|
||||
void testPublisherProbeAssertWasCancelled() {
|
||||
assertThat(PublisherProbe.empty().wasCancelled()).isTrue();
|
||||
}
|
||||
|
||||
void testPublisherProbeAssertWasNotCancelled() {
|
||||
assertThat(PublisherProbe.empty().wasCancelled()).isFalse();
|
||||
}
|
||||
|
||||
void testPublisherProbeAssertWasRequested() {
|
||||
assertThat(PublisherProbe.empty().wasRequested()).isTrue();
|
||||
}
|
||||
|
||||
void testPublisherProbeAssertWasNotRequested() {
|
||||
assertThat(PublisherProbe.empty().wasRequested()).isFalse();
|
||||
}
|
||||
|
||||
ImmutableSet<StepVerifier.FirstStep<Integer>> testStepVerifierFromMono() {
|
||||
return ImmutableSet.of(
|
||||
StepVerifier.create(Mono.just(1)), Mono.just(2).flux().as(StepVerifier::create));
|
||||
@@ -598,6 +648,18 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return StepVerifier.create(Flux.just(1));
|
||||
}
|
||||
|
||||
Object testStepVerifierVerify() {
|
||||
return Mono.empty().as(StepVerifier::create).expectError().verifyThenAssertThat();
|
||||
}
|
||||
|
||||
Object testStepVerifierVerifyDuration() {
|
||||
return Mono.empty().as(StepVerifier::create).expectError().verifyThenAssertThat(Duration.ZERO);
|
||||
}
|
||||
|
||||
StepVerifier testStepVerifierVerifyLater() {
|
||||
return Mono.empty().as(StepVerifier::create).expectError().verifyLater().verifyLater();
|
||||
}
|
||||
|
||||
ImmutableSet<StepVerifier.Step<Integer>> testStepVerifierStepIdentity() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just(1).as(StepVerifier::create).expectNext(),
|
||||
@@ -638,17 +700,43 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
.verifyErrorSatisfies(t -> assertThat(t).isInstanceOf(AssertionError.class)));
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorMatches() {
|
||||
return Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.expectErrorMatches(IllegalArgumentException.class::equals)
|
||||
.verify();
|
||||
ImmutableSet<?> testStepVerifierLastStepVerifyErrorMatches() {
|
||||
return ImmutableSet.of(
|
||||
Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.expectErrorMatches(IllegalArgumentException.class::equals)
|
||||
.verify(),
|
||||
Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.expectError()
|
||||
.verifyThenAssertThat()
|
||||
.hasOperatorErrorMatching(IllegalStateException.class::equals));
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorSatisfies() {
|
||||
return Mono.empty().as(StepVerifier::create).expectErrorSatisfies(t -> {}).verify();
|
||||
}
|
||||
|
||||
ImmutableSet<?> testStepVerifierLastStepVerifyErrorSatisfiesAssertJ() {
|
||||
return ImmutableSet.of(
|
||||
Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.expectError()
|
||||
.verifyThenAssertThat()
|
||||
.hasOperatorErrorOfType(IllegalArgumentException.class)
|
||||
.hasOperatorErrorWithMessage("foo"),
|
||||
Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.expectError(IllegalStateException.class)
|
||||
.verifyThenAssertThat()
|
||||
.hasOperatorErrorWithMessage("bar"),
|
||||
Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.expectErrorMessage("baz")
|
||||
.verifyThenAssertThat()
|
||||
.hasOperatorErrorOfType(AssertionError.class));
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorMessage() {
|
||||
return Mono.empty().as(StepVerifier::create).expectErrorMessage("foo").verify();
|
||||
}
|
||||
@@ -669,6 +757,11 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Mono.fromFuture(() -> ((AsyncLoadingCache<Integer, String>) null).get(0));
|
||||
}
|
||||
|
||||
Mono<Map<Integer, String>> testMonoFromFutureAsyncLoadingCacheGetAll() {
|
||||
return Mono.fromFuture(
|
||||
() -> ((AsyncLoadingCache<Integer, String>) null).getAll(ImmutableSet.of()));
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFromStreamSupplier() {
|
||||
return Flux.fromStream(Stream.of(1));
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user