mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
256 Commits
v0.16.1
...
gdejong/te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
561adcd0d6 | ||
|
|
05c5ba2677 | ||
|
|
efb9ea91b7 | ||
|
|
36ed176c4c | ||
|
|
aa21c57185 | ||
|
|
6e7f21f827 | ||
|
|
37580fa5ff | ||
|
|
b26ec206a0 | ||
|
|
354d98dbb7 | ||
|
|
6b99639f0e | ||
|
|
a5d4a3e87f | ||
|
|
c19a30cdb8 | ||
|
|
b61dc4e151 | ||
|
|
27a248def0 | ||
|
|
0e72a531e0 | ||
|
|
8842b11ad3 | ||
|
|
39550227a7 | ||
|
|
867985819a | ||
|
|
0a6c880e9c | ||
|
|
ae4a196fd6 | ||
|
|
b5ef39c89c | ||
|
|
21b6fc7bd1 | ||
|
|
cec781b317 | ||
|
|
76778344f6 | ||
|
|
c663c0cb7a | ||
|
|
0f7231a3ad | ||
|
|
4affdc8519 | ||
|
|
97d87cc9c0 | ||
|
|
4c9ab70bb6 | ||
|
|
03232ad9b9 | ||
|
|
4f48e05d8f | ||
|
|
57eb44285a | ||
|
|
4dd39610e7 | ||
|
|
643fd4e8a5 | ||
|
|
67c57c2442 | ||
|
|
2ec3938737 | ||
|
|
486ee7353f | ||
|
|
7cbe859b8c | ||
|
|
3cfcdda0fc | ||
|
|
952759209d | ||
|
|
9ad5f6e37c | ||
|
|
ebb6ff46b4 | ||
|
|
a305bf6da0 | ||
|
|
1d3cc10ff0 | ||
|
|
8d93549935 | ||
|
|
7096ce6075 | ||
|
|
9652c6f990 | ||
|
|
f02d9adcb2 | ||
|
|
9dda67e6cc | ||
|
|
51fdf18577 | ||
|
|
e3253011c3 | ||
|
|
d1836383ab | ||
|
|
882b256c18 | ||
|
|
36e0765734 | ||
|
|
d46a1ab87e | ||
|
|
3be79074d8 | ||
|
|
d8991627a7 | ||
|
|
1344321746 | ||
|
|
559a55b7d0 | ||
|
|
2e28ac9828 | ||
|
|
4d7b88a986 | ||
|
|
c0e177e4cd | ||
|
|
768b05bee6 | ||
|
|
048203434e | ||
|
|
9b89c0863c | ||
|
|
d03d536376 | ||
|
|
c812c95ea9 | ||
|
|
0d23dd1845 | ||
|
|
e29c08604d | ||
|
|
22c1f07017 | ||
|
|
9dd7621c18 | ||
|
|
3c59795c1b | ||
|
|
2688088750 | ||
|
|
a7b3378bda | ||
|
|
d7a10eda13 | ||
|
|
78e833ff85 | ||
|
|
edf2b7ca79 | ||
|
|
9ab79cb69b | ||
|
|
ac78cc709d | ||
|
|
2ef223ec9d | ||
|
|
2f797a322a | ||
|
|
3537e58305 | ||
|
|
f5e816d967 | ||
|
|
c0acb8b202 | ||
|
|
8f2183b6c2 | ||
|
|
278b679049 | ||
|
|
29657997f3 | ||
|
|
3562e4c764 | ||
|
|
d1b9f93cad | ||
|
|
fc177a9355 | ||
|
|
9ef2692885 | ||
|
|
35ada6b449 | ||
|
|
1a98a4d599 | ||
|
|
e5d7482133 | ||
|
|
69e987363a | ||
|
|
dad73a8447 | ||
|
|
f22b344d87 | ||
|
|
8d78b5b316 | ||
|
|
6024caf99c | ||
|
|
ff60c7be25 | ||
|
|
891e3dde5f | ||
|
|
ee4d3a70fa | ||
|
|
81c0e300a1 | ||
|
|
79abb132f5 | ||
|
|
d94518cbed | ||
|
|
6f862401ab | ||
|
|
aeae1dd66e | ||
|
|
8a032bea18 | ||
|
|
2c3ca2f885 | ||
|
|
d4a22682cd | ||
|
|
4c03041a47 | ||
|
|
c96cb95ec3 | ||
|
|
91923ef168 | ||
|
|
b086db14d9 | ||
|
|
369566f6f1 | ||
|
|
555bf36a7a | ||
|
|
81b27dab08 | ||
|
|
ecdd2c0f61 | ||
|
|
ef9dd72364 | ||
|
|
f2031b8308 | ||
|
|
6995f5627a | ||
|
|
2ad8deb6af | ||
|
|
8f0eea6e44 | ||
|
|
8859417f42 | ||
|
|
cc35110ff5 | ||
|
|
eed6f39b10 | ||
|
|
1e229949fc | ||
|
|
28a93e949e | ||
|
|
40ad38bc2a | ||
|
|
e125c6b7e2 | ||
|
|
5596c4530d | ||
|
|
d81fe19836 | ||
|
|
d6838ec947 | ||
|
|
b36a69aa5f | ||
|
|
831b757bb1 | ||
|
|
527fc5785b | ||
|
|
8c8055d381 | ||
|
|
b658c19c03 | ||
|
|
85976e199f | ||
|
|
f6a392e118 | ||
|
|
539fcae745 | ||
|
|
29f1a3d2a6 | ||
|
|
01f139b6a4 | ||
|
|
c61980721e | ||
|
|
471a1ebff1 | ||
|
|
b8d9ff0971 | ||
|
|
e02d836c12 | ||
|
|
abd47eb269 | ||
|
|
5219fd8f6c | ||
|
|
588fc38f81 | ||
|
|
e3aa8a5d12 | ||
|
|
3255c0b6eb | ||
|
|
d2dbd88f25 | ||
|
|
ff824cfa20 | ||
|
|
43303e770a | ||
|
|
cfadbca32a | ||
|
|
e7ca4a5325 | ||
|
|
7bab1eb7fd | ||
|
|
072e39da32 | ||
|
|
ec7e84ac45 | ||
|
|
4228a63ad1 | ||
|
|
6093e6f322 | ||
|
|
ee103a99f6 | ||
|
|
c34065beab | ||
|
|
d9e1f3ad5d | ||
|
|
8a8290587a | ||
|
|
162aa0d458 | ||
|
|
0fb37c45b5 | ||
|
|
0c2ce44742 | ||
|
|
f089157443 | ||
|
|
e192dacdfb | ||
|
|
8418652de0 | ||
|
|
1d8ac35660 | ||
|
|
913cd2ee3a | ||
|
|
6adaa6c4f6 | ||
|
|
08dbb8c298 | ||
|
|
e7bc0e113c | ||
|
|
6d2c926b0e | ||
|
|
60e15cb569 | ||
|
|
22f61d3032 | ||
|
|
5d2a726aec | ||
|
|
192322a982 | ||
|
|
ddf5d803bd | ||
|
|
02fb6d468a | ||
|
|
e7d50c247d | ||
|
|
85cfb4b4b7 | ||
|
|
0684c577ac | ||
|
|
32778edc74 | ||
|
|
1e6780afc1 | ||
|
|
ef4e004141 | ||
|
|
72c5a42feb | ||
|
|
271e01a02c | ||
|
|
d47549d68f | ||
|
|
01687c7f3e | ||
|
|
85cb7ffdb1 | ||
|
|
0367037f0a | ||
|
|
6669a2e1ec | ||
|
|
eb36c1e493 | ||
|
|
8f5faf0f6a | ||
|
|
5fad0ea04f | ||
|
|
4558f8affb | ||
|
|
7be27614da | ||
|
|
7118d6bf03 | ||
|
|
eb84ddf500 | ||
|
|
032109756d | ||
|
|
9e230302e9 | ||
|
|
4708fec201 | ||
|
|
d102d6acbb | ||
|
|
bc67883579 | ||
|
|
069d6ff2f4 | ||
|
|
6fbf4d81f0 | ||
|
|
3d51acd613 | ||
|
|
d2fb576ecc | ||
|
|
d658901231 | ||
|
|
76d1ca7bdf | ||
|
|
341977b227 | ||
|
|
75872dc2f5 | ||
|
|
b609537a52 | ||
|
|
1469d1e157 | ||
|
|
111b7d04f2 | ||
|
|
9e297df1c7 | ||
|
|
7babb48751 | ||
|
|
dfaffacbb5 | ||
|
|
769779cf21 | ||
|
|
9d8a5af44a | ||
|
|
8a84acca7b | ||
|
|
b551f90d38 | ||
|
|
789a9cc0aa | ||
|
|
13e35338af | ||
|
|
281a003dd7 | ||
|
|
e40df7e1b8 | ||
|
|
bb2b1e6034 | ||
|
|
f8cac19330 | ||
|
|
52fe79c343 | ||
|
|
0b696b95b6 | ||
|
|
63bc903f83 | ||
|
|
b166d0daea | ||
|
|
6914dae822 | ||
|
|
c5fb53d725 | ||
|
|
d36d20da08 | ||
|
|
502281f4d3 | ||
|
|
daa4f19c57 | ||
|
|
02f726f43c | ||
|
|
b9e8186159 | ||
|
|
85baadd5df | ||
|
|
ab871ec9bb | ||
|
|
753928f4da | ||
|
|
fe84bada33 | ||
|
|
5b8d6ed9c5 | ||
|
|
2ad2fdfb0f | ||
|
|
a10558a044 | ||
|
|
7316d05c22 | ||
|
|
3177db55b8 | ||
|
|
a6a63f9553 | ||
|
|
df0eb9ee2f | ||
|
|
e3cda3ea49 |
8
.github/release.yml
vendored
8
.github/release.yml
vendored
@@ -3,16 +3,16 @@ changelog:
|
||||
labels:
|
||||
- "ignore-changelog"
|
||||
categories:
|
||||
- title: ":warning: Update considerations and deprecations"
|
||||
labels:
|
||||
- "breaking change"
|
||||
- "deprecation"
|
||||
- title: ":rocket: New Error Prone checks and Refaster rules"
|
||||
labels:
|
||||
- "new feature"
|
||||
- title: ":sparkles: Improvements"
|
||||
labels:
|
||||
- "improvement"
|
||||
- title: ":warning: Update considerations and deprecations"
|
||||
labels:
|
||||
- "breaking change"
|
||||
- "deprecation"
|
||||
- title: ":bug: Bug fixes"
|
||||
labels:
|
||||
- "bug"
|
||||
|
||||
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -26,13 +26,15 @@ jobs:
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
github.com:443
|
||||
jitpack.io:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
# We run the build twice for each supported JDK: once against the
|
||||
# original Error Prone release, using only Error Prone checks available
|
||||
@@ -40,7 +42,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@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
java-distribution: ${{ matrix.distribution }}
|
||||
|
||||
9
.github/workflows/codeql.yml
vendored
9
.github/workflows/codeql.yml
vendored
@@ -22,30 +22,31 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
api.github.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
uploads.github.com:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
java-version: 17.0.10
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
|
||||
uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
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@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
|
||||
uses: github/codeql-action/analyze@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
with:
|
||||
category: /language:${{ matrix.language }}
|
||||
|
||||
12
.github/workflows/deploy-website.yml
vendored
12
.github/workflows/deploy-website.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -39,15 +39,15 @@ jobs:
|
||||
www.youtube.com:443
|
||||
youtrack.jetbrains.com:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0
|
||||
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
|
||||
with:
|
||||
working-directory: ./website
|
||||
bundler-cache: true
|
||||
- name: Configure Github Pages
|
||||
uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4.0.0
|
||||
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
|
||||
- name: Generate documentation
|
||||
run: ./generate-docs.sh
|
||||
- name: Build website with Jekyll
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -82,4 +82,4 @@ jobs:
|
||||
api.github.com:443
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@decdde0ac072f6dcbe43649d82d9c635fff5b4e4 # v4.0.4
|
||||
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
|
||||
|
||||
9
.github/workflows/openssf-scorecard.yml
vendored
9
.github/workflows/openssf-scorecard.yml
vendored
@@ -21,13 +21,14 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.github.com:443
|
||||
api.osv.dev:443
|
||||
api.scorecard.dev:443
|
||||
api.securityscorecards.dev:443
|
||||
fulcio.sigstore.dev:443
|
||||
github.com:443
|
||||
@@ -36,16 +37,16 @@ jobs:
|
||||
tuf-repo-cdn.sigstore.dev:443
|
||||
www.bestpractices.dev:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run OpenSSF Scorecard analysis
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
||||
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@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
|
||||
uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
8
.github/workflows/pitest-analyze-pr.yml
vendored
8
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -12,15 +12,17 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
checkout-fetch-depth: 2
|
||||
java-version: 17.0.10
|
||||
@@ -36,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@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: pitest-reports
|
||||
path: ./target/pit-reports-ci
|
||||
|
||||
8
.github/workflows/pitest-update-pr.yml
vendored
8
.github/workflows/pitest-update-pr.yml
vendored
@@ -20,22 +20,24 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
api.github.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
java-version: 17.0.10
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
- name: Download Pitest analysis artifact
|
||||
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
|
||||
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
name: pitest-reports
|
||||
|
||||
8
.github/workflows/run-integration-tests.yml
vendored
8
.github/workflows/run-integration-tests.yml
vendored
@@ -19,19 +19,21 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
checkstyle.org:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
oss.sonatype.org:443
|
||||
raw.githubusercontent.com: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@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
|
||||
java-version: 17.0.10
|
||||
@@ -43,7 +45,7 @@ jobs:
|
||||
run: xvfb-run ./integration-tests/checkstyle.sh "${{ runner.temp }}/artifacts"
|
||||
- name: Upload artifacts on failure
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: integration-test-checkstyle
|
||||
path: "${{ runner.temp }}/artifacts"
|
||||
|
||||
6
.github/workflows/sonarcloud.yml
vendored
6
.github/workflows/sonarcloud.yml
vendored
@@ -19,19 +19,21 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
ea6ne4j2sb.execute-api.eu-central-1.amazonaws.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
sc-cleancode-sensorcache-eu-central-1-prod.s3.amazonaws.com:443
|
||||
scanner.sonarcloud.io:443
|
||||
sonarcloud.io:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
checkout-fetch-depth: 0
|
||||
java-version: 17.0.10
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@
|
||||
.DS_Store
|
||||
.factorypath
|
||||
.idea
|
||||
!.idea/icon.svg
|
||||
.project
|
||||
.settings
|
||||
target
|
||||
|
||||
65
.idea/icon.svg
generated
Normal file
65
.idea/icon.svg
generated
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 1259 1199" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-624.154,-988.431)">
|
||||
<g transform="matrix(1,0,0,1,-70.1122,-35.0561)">
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1227.03,1988.79C1237.78,2070.45 1225.83,2190.1 1192.24,2194.53C1158.65,2198.95 1116.14,2086.46 1105.39,2004.81C1094.64,1923.16 1128.44,1902.11 1153.32,1898.84C1178.18,1895.56 1216.28,1907.14 1227.03,1988.79Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1151.08,1881.86C1134.93,1883.99 1114.77,1892.69 1101.6,1913.17C1088.42,1933.64 1082.71,1963.73 1088.42,2007.04C1094.04,2049.75 1107.59,2099.16 1124.51,2138.68C1132.97,2158.45 1142.15,2175.68 1152.59,2188.86C1163.04,2202.05 1176.31,2213.89 1194.48,2211.5C1212.65,2209.11 1222.39,2194.23 1229.07,2178.8C1235.75,2163.36 1240.15,2144.34 1243.21,2123.05C1249.32,2080.5 1249.63,2029.27 1244,1986.56C1238.3,1943.24 1225,1915.66 1206.98,1899.29C1188.95,1882.93 1167.22,1879.74 1151.08,1881.86ZM1155.55,1915.81C1164.27,1914.66 1174.03,1915.62 1183.96,1924.64C1193.89,1933.66 1205.01,1952.69 1210.06,1991.03C1215.18,2029.97 1214.89,2079.4 1209.32,2118.19C1206.53,2137.58 1202.32,2154.4 1197.65,2165.2C1194.14,2173.29 1190.82,2176.3 1189.96,2177.22C1188.89,2176.55 1184.91,2174.51 1179.43,2167.6C1172.12,2158.38 1163.7,2143.22 1155.99,2125.21C1140.57,2089.18 1127.49,2041.51 1122.36,2002.57C1117.32,1964.24 1123.13,1942.97 1130.39,1931.69C1137.65,1920.42 1146.82,1916.96 1155.55,1915.81Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1516.33,1963.1C1466.19,1897.75 1427.4,1906.77 1407.5,1922.05C1387.59,1937.32 1368.84,1972.45 1418.98,2037.8C1431.75,2054.44 1447.26,2071.84 1463.69,2088.19C1495.18,2119.52 1534.33,2139.39 1582.98,2126.14C1606.4,2119.76 1622.19,2110.46 1623.75,2098.64C1625.79,2083.16 1603,2065.78 1569.69,2050.47C1554.75,2019.83 1535.59,1988.2 1516.33,1963.1Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1397.07,1908.46C1409.99,1898.55 1430.41,1890.44 1454.2,1895.61C1478,1900.77 1503.31,1918 1529.91,1952.67C1548.92,1977.44 1567.3,2007.65 1582.28,2037.56C1597.47,2044.87 1610.74,2052.64 1621.09,2061.47C1632.68,2071.35 1642.93,2084.12 1640.73,2100.88C1639.05,2113.64 1630.31,2122.66 1620.9,2128.78C1611.49,2134.9 1600.29,2139.17 1587.48,2142.66C1532.39,2157.66 1485.57,2134.11 1451.61,2100.32C1434.7,2083.49 1418.73,2065.6 1405.39,2048.22C1378.79,2013.56 1368.69,1984.64 1369.86,1960.32C1371.04,1936 1384.15,1918.38 1397.07,1908.46ZM1417.92,1935.63C1410.94,1940.99 1404.71,1948.57 1404.07,1961.97C1403.43,1975.37 1409.02,1996.69 1432.56,2027.38C1444.76,2043.27 1459.82,2060.18 1475.77,2076.05C1504.8,2104.93 1536.26,2121.12 1578.48,2109.62C1589.1,2106.73 1597.5,2103.16 1602.23,2100.08C1605.14,2098.18 1606.16,2096.97 1606.54,2096.46C1606.07,2095.66 1604.57,2092.39 1598.86,2087.52C1591.24,2081.02 1578.31,2073.28 1562.54,2066.03L1556.98,2063.47L1554.29,2057.97C1539.86,2028.35 1521.12,1997.46 1502.75,1973.52C1479.2,1942.84 1460.05,1931.91 1446.94,1929.07C1433.84,1926.23 1424.9,1930.27 1417.92,1935.63Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M917.121,1633.14C845.801,1674.32 730.68,1709.07 713.738,1679.73C696.797,1650.39 784.453,1568.07 855.777,1526.89C927.102,1485.71 959.48,1508.89 972.02,1530.62C984.562,1552.34 988.445,1591.97 917.121,1633.14Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M986.848,1522.06C978.707,1507.95 962.949,1492.66 938.992,1488.32C915.031,1483.98 885.055,1490.22 847.219,1512.07C809.906,1533.61 769.453,1565.03 739.41,1595.79C724.391,1611.17 711.977,1626.24 703.797,1640.94C695.617,1655.64 689.746,1672.42 698.914,1688.29C708.078,1704.17 725.547,1707.48 742.363,1707.74C759.184,1708.01 778.445,1704.79 799.273,1699.47C840.934,1688.83 888.375,1669.51 925.684,1647.97C963.52,1626.12 983.91,1603.29 992.137,1580.37C1000.36,1557.45 994.988,1536.16 986.848,1522.06ZM957.195,1539.18C961.594,1546.79 964.438,1556.18 959.906,1568.8C955.379,1581.43 942.047,1598.98 908.562,1618.32C874.551,1637.96 828.77,1656.6 790.801,1666.3C771.816,1671.14 754.664,1673.69 742.902,1673.5C734.082,1673.37 730.035,1671.45 728.859,1671C729.062,1669.76 729.426,1665.3 733.715,1657.59C739.434,1647.31 750.215,1633.73 763.906,1619.72C791.285,1591.68 830.324,1561.36 864.336,1541.72C897.824,1522.38 919.695,1519.62 932.895,1522.01C946.09,1524.4 952.797,1531.56 957.195,1539.18Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1791.57,1526.89C1862.89,1568.07 1950.54,1650.39 1933.61,1679.74C1916.66,1709.08 1801.54,1674.33 1730.22,1633.15C1658.9,1591.97 1662.78,1552.34 1675.32,1530.62C1687.86,1508.89 1720.24,1485.72 1791.57,1526.89Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1660.5,1522.06C1652.35,1536.16 1646.98,1557.45 1655.21,1580.37C1663.43,1603.29 1683.82,1626.13 1721.66,1647.97C1758.97,1669.52 1806.41,1688.84 1848.07,1699.48C1868.9,1704.79 1888.16,1708.01 1904.98,1707.75C1921.79,1707.48 1939.27,1704.17 1948.43,1688.3C1957.59,1672.42 1951.73,1655.64 1943.55,1640.94C1935.37,1626.25 1922.95,1611.17 1907.93,1595.79C1877.89,1565.04 1837.43,1533.61 1800.12,1512.07C1762.29,1490.22 1732.31,1483.98 1708.35,1488.32C1684.39,1492.66 1668.64,1507.95 1660.5,1522.06ZM1690.15,1539.18C1694.55,1531.56 1701.25,1524.4 1714.45,1522.02C1727.64,1519.62 1749.52,1522.39 1783,1541.72C1817.02,1561.36 1856.06,1591.68 1883.44,1619.72C1897.12,1633.73 1907.91,1647.32 1913.63,1657.59C1917.92,1665.3 1918.28,1669.77 1918.48,1671.01C1917.31,1671.45 1913.26,1673.37 1904.44,1673.51C1892.68,1673.69 1875.52,1671.15 1856.54,1666.3C1818.57,1656.61 1772.79,1637.96 1738.78,1618.32C1705.29,1598.99 1691.97,1581.43 1687.43,1568.81C1682.91,1556.18 1685.75,1546.8 1690.15,1539.18Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.81,1013.67C1058.16,1014.17 843.293,1229.45 843.297,1494.11L843.223,1862.19C843.223,1955.32 919.055,2031.16 1012.19,2031.16C1054.55,2031.16 1093.39,2015.51 1123.09,1989.7C1169.54,2049.44 1242.17,2087.79 1323.7,2087.79C1405.22,2087.79 1477.84,2049.45 1524.28,1989.73C1553.98,2015.52 1592.81,2031.16 1635.15,2031.16C1728.29,2031.16 1804.12,1955.32 1804.12,1862.19L1804.12,1494.1C1804.12,1229.09 1588.7,1013.67 1323.69,1013.67L1322.84,1013.67L1322.81,1013.67ZM1322.92,1068.46L1323.69,1068.46C1559.09,1068.46 1749.33,1258.7 1749.33,1494.11L1749.33,1862.19C1749.33,1925.92 1698.88,1976.37 1635.15,1976.37C1596.91,1976.37 1563.67,1958.03 1542.94,1929.68L1517.91,1895.48L1497,1932.34C1462.85,1992.53 1398.48,2033 1323.7,2033C1248.9,2033 1184.52,1992.51 1150.38,1932.3L1129.45,1895.41L1104.43,1929.65C1083.69,1958.02 1050.44,1976.37 1012.19,1976.37C948.461,1976.37 898.016,1925.93 898.012,1862.2L898.086,1494.11C898.086,1259.03 1087.84,1068.92 1322.92,1068.47L1322.92,1068.46Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.86,1041.07C1072.99,1041.54 870.684,1244.23 870.688,1494.11L870.648,1862.19C870.648,1940.62 933.789,2003.77 1012.22,2003.77C1073.65,2003.77 1125.69,1965.03 1145.37,1910.56C1201.73,1934.69 1262.41,1947.14 1323.72,1947.14C1385.02,1947.14 1445.69,1934.69 1502.04,1910.57C1521.72,1965.04 1573.76,2003.77 1635.19,2003.77C1713.62,2003.77 1776.76,1940.62 1776.76,1862.19L1776.76,1494.11C1776.76,1243.9 1573.93,1041.07 1323.72,1041.07L1322.86,1041.07Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1323.7,1494.1C1449.2,1494.1 1550.24,1595.14 1550.24,1720.64L1550.24,1833.86C1550.24,1959.36 1449.2,2060.4 1323.7,2060.4C1198.2,2060.4 1097.16,1959.36 1097.16,1833.86L1097.16,1720.64C1097.16,1595.14 1198.2,1494.1 1323.7,1494.1Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.86,1041.07C1262.14,1041.18 1204.25,1053.27 1151.36,1075.05C1316.07,1142.87 1432.03,1304.93 1432.03,1494.11L1432.03,1811.95C1432.03,2003.63 1209.62,2024.85 1126.54,1945.82C1177.52,2034.1 1254.55,2060.4 1323.7,2060.4C1408.4,2060.4 1481.95,2014.37 1520.82,1945.86C1546.53,1981.01 1588.08,2003.77 1635.15,2003.77C1713.58,2003.77 1776.72,1940.62 1776.72,1862.19L1776.72,1494.11C1776.72,1243.9 1573.89,1041.07 1323.68,1041.07L1322.86,1041.07Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.86,1041.07C1304.33,1041.1 1286.06,1042.28 1268.11,1044.48C1492.04,1071.93 1665.46,1262.75 1665.46,1494.11L1665.46,1862.19C1665.46,1920.85 1630.14,1970.94 1579.54,1992.48C1596.59,1999.74 1615.38,2003.77 1635.15,2003.77C1713.58,2003.77 1776.72,1940.62 1776.72,1862.19L1776.72,1494.11C1776.72,1243.9 1573.89,1041.07 1323.68,1041.07L1322.86,1041.07Z" style="fill:rgb(189,191,175);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.85,1034.22C1069.29,1034.69 863.84,1240.54 863.84,1494.11L863.766,1862.19C863.766,1944.3 930.078,2010.61 1012.19,2010.61C1057.88,2010.61 1098.53,1989.94 1125.71,1957.58C1166.88,2023.5 1240.02,2067.25 1323.7,2067.25C1407.36,2067.25 1480.48,2023.52 1521.66,1957.62C1548.84,1989.96 1589.47,2010.61 1635.15,2010.61C1717.25,2010.61 1783.57,1944.3 1783.57,1862.19L1783.57,1494.11C1783.57,1240.2 1577.59,1034.21 1323.68,1034.22L1322.85,1034.22ZM1322.86,1047.92L1323.68,1047.92C1570.19,1047.92 1769.87,1247.6 1769.87,1494.11L1769.87,1862.19C1769.87,1936.95 1709.91,1996.92 1635.15,1996.92C1590.29,1996.92 1550.82,1975.26 1526.36,1941.82L1520.1,1933.27L1514.87,1942.48C1477.18,2008.91 1405.92,2053.55 1323.7,2053.55C1241.46,2053.55 1170.19,2008.89 1132.5,1942.44L1127.27,1933.21L1121.02,1941.77C1096.56,1975.24 1057.07,1996.92 1012.19,1996.92C937.43,1996.92 877.469,1936.95 877.465,1862.19L877.539,1494.11C877.539,1247.94 1076.7,1048.39 1322.86,1047.92Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1576.29,1470.72C1576.29,1481.36 1568.75,1491.56 1555.31,1499.08C1541.88,1506.6 1523.67,1510.83 1504.68,1510.83C1465.12,1510.83 1433.06,1492.87 1433.06,1470.72C1433.06,1448.57 1465.12,1430.62 1504.68,1430.62C1523.67,1430.62 1541.88,1434.84 1555.31,1442.36C1568.75,1449.89 1576.29,1460.09 1576.29,1470.72Z" style="fill:rgb(255,155,173);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1214.28,1470.72C1214.28,1481.36 1206.73,1491.56 1193.31,1499.08C1179.87,1506.6 1161.66,1510.83 1142.66,1510.83C1103.11,1510.83 1071.05,1492.87 1071.05,1470.72C1071.05,1448.57 1103.11,1430.62 1142.66,1430.62C1161.66,1430.62 1179.87,1434.84 1193.31,1442.36C1206.73,1449.89 1214.28,1460.09 1214.28,1470.72Z" style="fill:rgb(255,155,173);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1104.39,1401.46C1104.39,1375.15 1118.45,1350.79 1141.24,1337.63C1164.03,1324.48 1192.16,1324.48 1214.95,1337.63C1237.74,1350.79 1251.81,1375.15 1251.81,1401.46L1224.41,1401.46C1224.41,1384.9 1215.6,1369.64 1201.25,1361.36C1186.9,1353.07 1169.29,1353.07 1154.94,1361.36C1140.59,1369.64 1131.78,1384.9 1131.78,1401.46L1104.39,1401.46Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1395.54,1401.46C1395.54,1375.15 1409.61,1350.79 1432.39,1337.63C1455.18,1324.48 1483.32,1324.48 1506.11,1337.63C1528.89,1350.79 1542.96,1375.15 1542.96,1401.46L1515.56,1401.46C1515.56,1384.9 1506.75,1369.64 1492.41,1361.36C1478.06,1353.07 1460.44,1353.07 1446.09,1361.36C1431.74,1369.64 1422.93,1384.9 1422.93,1401.46L1395.54,1401.46Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1256.81,1448.61C1256.81,1472.48 1269.56,1494.57 1290.24,1506.51C1310.92,1518.45 1336.42,1518.45 1357.1,1506.51C1377.78,1494.57 1390.53,1472.48 1390.53,1448.61L1376.83,1448.61C1376.83,1467.61 1366.71,1485.15 1350.25,1494.65C1333.79,1504.15 1313.55,1504.15 1297.09,1494.65C1280.63,1485.15 1270.51,1467.61 1270.51,1448.61L1256.81,1448.61Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
@@ -12,7 +12,7 @@
|
||||
"separateMinorPatch": true
|
||||
},
|
||||
{
|
||||
"matchDepNames": [
|
||||
"matchPackageNames": [
|
||||
"dawidd6/action-download-artifact",
|
||||
"github/codeql-action",
|
||||
"ruby/setup-ruby"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>documentation-support</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
@@ -162,7 +162,7 @@
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
|
||||
@@ -232,7 +232,7 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
|
||||
@Override
|
||||
public @Nullable Void visitReturn(ReturnTree node, @Nullable Void unused) {
|
||||
returnExpressions.add(node.getExpression());
|
||||
return super.visitReturn(node, unused);
|
||||
return super.visitReturn(node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -192,7 +192,7 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
@Override
|
||||
public @Nullable Void visitIdentifier(IdentifierTree node, @Nullable Void unused) {
|
||||
nodes.add(ImmutableList.of(node.getName().toString()));
|
||||
return super.visitIdentifier(node, unused);
|
||||
return super.visitIdentifier(node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,13 +203,13 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
? STRING_ARGUMENT_SPLITTER.splitToStream(str).collect(toImmutableList())
|
||||
: ImmutableList.of(String.valueOf(value)));
|
||||
|
||||
return super.visitLiteral(node, unused);
|
||||
return super.visitLiteral(node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitPrimitiveType(PrimitiveTypeTree node, @Nullable Void unused) {
|
||||
nodes.add(ImmutableList.of(node.getPrimitiveTypeKind().toString()));
|
||||
return super.visitPrimitiveType(node, unused);
|
||||
return super.visitPrimitiveType(node, null);
|
||||
}
|
||||
}.scan(array, null);
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitIdentifier(node, unused);
|
||||
return super.visitIdentifier(node, null);
|
||||
}
|
||||
}.scan(tree, null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.NONE;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.Iterables;
|
||||
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.refaster.Refaster;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags arguments to {@link Optional#orElse(Object)} that should be
|
||||
* deferred using {@link Optional#orElseGet(Supplier)}.
|
||||
*
|
||||
* <p>The suggested fix assumes that the argument to {@code orElse} does not have side effects. If
|
||||
* it does, the suggested fix changes the program's semantics. Such fragile code must instead be
|
||||
* refactored such that the side-effectful code does not appear accidental.
|
||||
*/
|
||||
// XXX: Consider also implementing the inverse, in which `.orElseGet(() -> someConstant)` is
|
||||
// flagged.
|
||||
// XXX: Once the `MethodReferenceUsageCheck` becomes generally usable, consider leaving the method
|
||||
// reference cleanup to that check, and express the remainder of the logic in this class using a
|
||||
// Refaster template, i.c.w. a `@Matches` constraint that implements the `requiresComputation`
|
||||
// logic.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
"""
|
||||
Prefer `Optional#orElseGet` over `Optional#orElse` if the fallback requires additional \
|
||||
computation""",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = PERFORMANCE)
|
||||
public final class OptionalOrElse extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> OPTIONAL_OR_ELSE_METHOD =
|
||||
instanceMethod().onExactClass(Optional.class.getCanonicalName()).namedAnyOf("orElse");
|
||||
// XXX: Also exclude invocations of `@Placeholder`-annotated methods.
|
||||
private static final Matcher<ExpressionTree> REFASTER_METHOD =
|
||||
staticMethod().onClass(Refaster.class.getCanonicalName());
|
||||
|
||||
/** Instantiates a new {@link OptionalOrElse} instance. */
|
||||
public OptionalOrElse() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
if (!OPTIONAL_OR_ELSE_METHOD.matches(tree, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
ExpressionTree argument = Iterables.getOnlyElement(tree.getArguments());
|
||||
if (!requiresComputation(argument) || REFASTER_METHOD.matches(argument, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a match. Construct the method reference or lambda expression to be passed to the
|
||||
* replacement `#orElseGet` invocation.
|
||||
*/
|
||||
String newArgument =
|
||||
tryMethodReferenceConversion(argument, state)
|
||||
.orElseGet(() -> "() -> " + SourceCode.treeToString(argument, state));
|
||||
|
||||
/* Construct the suggested fix, replacing the method invocation and its argument. */
|
||||
SuggestedFix fix =
|
||||
SuggestedFix.builder()
|
||||
.merge(SuggestedFixes.renameMethodInvocation(tree, "orElseGet", state))
|
||||
.replace(argument, newArgument)
|
||||
.build();
|
||||
|
||||
return describeMatch(tree, fix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given expression contains anything other than a literal or a (possibly
|
||||
* dereferenced) variable or constant.
|
||||
*/
|
||||
private static boolean requiresComputation(ExpressionTree tree) {
|
||||
return !(tree instanceof IdentifierTree
|
||||
|| tree instanceof LiteralTree
|
||||
|| (tree instanceof MemberSelectTree memberSelect
|
||||
&& !requiresComputation(memberSelect.getExpression()))
|
||||
|| ASTHelpers.constValue(tree) != null);
|
||||
}
|
||||
|
||||
/** Returns the nullary method reference matching the given expression, if any. */
|
||||
private static Optional<String> tryMethodReferenceConversion(
|
||||
ExpressionTree tree, VisitorState state) {
|
||||
if (!(tree instanceof MethodInvocationTree methodInvocation)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (!methodInvocation.getArguments().isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (!(methodInvocation.getMethodSelect() instanceof MemberSelectTree memberSelect)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (requiresComputation(memberSelect.getExpression())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(
|
||||
SourceCode.treeToString(memberSelect.getExpression(), state)
|
||||
+ "::"
|
||||
+ (methodInvocation.getTypeArguments().isEmpty()
|
||||
? ""
|
||||
: methodInvocation.getTypeArguments().stream()
|
||||
.map(arg -> SourceCode.treeToString(arg, state))
|
||||
.collect(joining(",", "<", ">")))
|
||||
+ memberSelect.getIdentifier());
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ final class CollectionRules {
|
||||
"java:S1155" /* This violation will be rewritten. */,
|
||||
"LexicographicalAnnotationAttributeListing" /* `key-*` entry must remain last. */,
|
||||
"OptionalFirstCollectionElement" /* This is a more specific template. */,
|
||||
"StreamIsEmpty" /* This is a more specific template. */,
|
||||
"StreamFindAnyIsEmpty" /* This is a more specific template. */,
|
||||
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
|
||||
})
|
||||
boolean before(Collection<T> collection) {
|
||||
|
||||
@@ -16,8 +16,11 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
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.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.Arrays;
|
||||
@@ -92,6 +95,24 @@ final class ComparatorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't explicitly compare enums by their ordinal. */
|
||||
abstract static class ComparingEnum<E extends Enum<E>, T> {
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract E toEnumFunction(@MayOptionallyUse T value);
|
||||
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("EnumOrdinal" /* This violation will be rewritten. */)
|
||||
Comparator<T> before() {
|
||||
return comparingInt(v -> toEnumFunction(v).ordinal());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
Comparator<T> after() {
|
||||
return comparing(v -> toEnumFunction(v));
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't explicitly create {@link Comparator}s unnecessarily. */
|
||||
static final class ThenComparing<S, T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
@@ -269,7 +290,7 @@ final class ComparatorRules {
|
||||
static final class MinOfPairCustomOrder<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S1067" /* The conditional operators are independent. */)
|
||||
T before(T value1, T value2, Comparator<T> cmp) {
|
||||
T before(T value1, T value2, Comparator<? super T> cmp) {
|
||||
return Refaster.anyOf(
|
||||
cmp.compare(value1, value2) <= 0 ? value1 : value2,
|
||||
cmp.compare(value1, value2) > 0 ? value2 : value1,
|
||||
@@ -284,7 +305,7 @@ final class ComparatorRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(T value1, T value2, Comparator<T> cmp) {
|
||||
T after(T value1, T value2, Comparator<? super T> cmp) {
|
||||
return Comparators.min(value1, value2, cmp);
|
||||
}
|
||||
}
|
||||
@@ -336,7 +357,7 @@ final class ComparatorRules {
|
||||
static final class MaxOfPairCustomOrder<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S1067" /* The conditional operators are independent. */)
|
||||
T before(T value1, T value2, Comparator<T> cmp) {
|
||||
T before(T value1, T value2, Comparator<? super T> cmp) {
|
||||
return Refaster.anyOf(
|
||||
cmp.compare(value1, value2) >= 0 ? value1 : value2,
|
||||
cmp.compare(value1, value2) < 0 ? value2 : value1,
|
||||
@@ -351,7 +372,7 @@ final class ComparatorRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(T value1, T value2, Comparator<T> cmp) {
|
||||
T after(T value1, T value2, Comparator<? super T> cmp) {
|
||||
return Comparators.max(value1, value2, cmp);
|
||||
}
|
||||
}
|
||||
@@ -419,4 +440,34 @@ final class ComparatorRules {
|
||||
return maxBy(naturalOrder());
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't explicitly compare enums by their ordinal. */
|
||||
static final class IsLessThan<E extends Enum<E>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("EnumOrdinal" /* This violation will be rewritten. */)
|
||||
boolean before(E value1, E value2) {
|
||||
return value1.ordinal() < value2.ordinal();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(E value1, E value2) {
|
||||
return value1.compareTo(value2) < 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't explicitly compare enums by their ordinal. */
|
||||
static final class IsLessThanOrEqualTo<E extends Enum<E>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("EnumOrdinal" /* This violation will be rewritten. */)
|
||||
boolean before(E value1, E value2) {
|
||||
return value1.ordinal() <= value2.ordinal();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(E value1, E value2) {
|
||||
return value1.compareTo(value2) <= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ final class EqualityRules {
|
||||
// XXX: This Refaster rule is the topic of https://github.com/google/error-prone/issues/559. We
|
||||
// work around the issue by selecting the "largest replacements". See the `Refaster` check.
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("EnumOrdinal" /* This violation will be rewritten. */)
|
||||
boolean before(T a, T b) {
|
||||
return Refaster.anyOf(a.equals(b), Objects.equals(a, b));
|
||||
return Refaster.anyOf(a.equals(b), Objects.equals(a, b), a.ordinal() == b.ordinal());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -27,6 +27,19 @@ import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
|
||||
final class OptionalRules {
|
||||
private OptionalRules() {}
|
||||
|
||||
/** Prefer {@link Optional#empty()} over the more contrived alternative. */
|
||||
static final class OptionalEmpty<T> {
|
||||
@BeforeTemplate
|
||||
Optional<T> before() {
|
||||
return Optional.ofNullable(null);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Optional<T> after() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class OptionalOfNullable<T> {
|
||||
// XXX: Refaster should be smart enough to also rewrite occurrences in which there are
|
||||
// parentheses around the null check, but that's currently not the case. Try to fix that.
|
||||
@@ -360,7 +373,7 @@ final class OptionalRules {
|
||||
/** Prefer {@link Optional#or(Supplier)} over more verbose alternatives. */
|
||||
static final class OptionalOrOtherOptional<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedOptionals" /* Auto-fix for the `NestedOptionals` check. */)
|
||||
@SuppressWarnings("NestedOptionals")
|
||||
Optional<T> before(Optional<T> optional1, Optional<T> optional2) {
|
||||
// XXX: Note that rewriting the first and third variant will change the code's behavior if
|
||||
// `optional2` has side-effects.
|
||||
@@ -386,9 +399,13 @@ final class OptionalRules {
|
||||
*/
|
||||
static final class OptionalIdentity<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedOptionals")
|
||||
Optional<T> before(Optional<T> optional, Comparator<? super T> comparator) {
|
||||
return Refaster.anyOf(
|
||||
optional.or(Refaster.anyOf(() -> Optional.empty(), Optional::empty)),
|
||||
optional
|
||||
.map(Optional::of)
|
||||
.orElseGet(Refaster.anyOf(() -> Optional.empty(), Optional::empty)),
|
||||
optional.stream().findFirst(),
|
||||
optional.stream().findAny(),
|
||||
optional.stream().min(comparator),
|
||||
@@ -442,9 +459,7 @@ final class OptionalRules {
|
||||
static final class OptionalStream<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(Optional<T> optional) {
|
||||
return Refaster.anyOf(
|
||||
optional.map(Stream::of).orElse(Stream.empty()),
|
||||
optional.map(Stream::of).orElseGet(Stream::empty));
|
||||
return optional.map(Stream::of).orElseGet(Stream::empty);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -3,7 +3,6 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.MoreCollectors.toOptional;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
@@ -52,7 +51,6 @@ import reactor.util.context.Context;
|
||||
import reactor.util.function.Tuple2;
|
||||
import tech.picnic.errorprone.refaster.annotation.Description;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.annotation.Severity;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
|
||||
import tech.picnic.errorprone.refaster.matchers.ThrowsCheckedException;
|
||||
@@ -380,30 +378,23 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#take(long, boolean)} over {@link Flux#take(long)}.
|
||||
* Prefer {@link Flux#take(long)} over {@link Flux#take(long, boolean)} where relevant.
|
||||
*
|
||||
* <p>In Reactor versions prior to 3.5.0, {@code Flux#take(long)} makes an unbounded request
|
||||
* upstream, and is equivalent to {@code Flux#take(long, false)}. In 3.5.0, the behavior of {@code
|
||||
* Flux#take(long)} will change to that of {@code Flux#take(long, true)}.
|
||||
*
|
||||
* <p>The intent with this Refaster rule is to get the new behavior before upgrading to Reactor
|
||||
* 3.5.0.
|
||||
* upstream, and is equivalent to {@code Flux#take(long, false)}. From version 3.5.0 onwards, the
|
||||
* behavior of {@code Flux#take(long)} instead matches {@code Flux#take(long, true)}.
|
||||
*/
|
||||
// XXX: Drop this rule some time after upgrading to Reactor 3.6.0, or introduce a way to apply
|
||||
// this rule only when an older version of Reactor is on the classpath.
|
||||
// XXX: Once Reactor 3.6.0 is out, introduce a rule that rewrites code in the opposite direction.
|
||||
@Description(
|
||||
"Prior to Reactor 3.5.0, `take(n)` requests and unbounded number of elements upstream.")
|
||||
@Severity(WARNING)
|
||||
"From Reactor 3.5.0 onwards, `take(n)` no longer requests an unbounded number of elements upstream.")
|
||||
static final class FluxTake<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Flux<T> flux, long n) {
|
||||
return flux.take(n);
|
||||
return flux.take(n, /* limitRequest= */ true);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Flux<T> flux, long n) {
|
||||
return flux.take(n, /* limitRequest= */ true);
|
||||
return flux.take(n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,6 +557,7 @@ final class ReactorRules {
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super P, ? extends Publisher<? extends S>> identityOperation) {
|
||||
return Refaster.anyOf(
|
||||
flux.concatMap(function, 0),
|
||||
flux.flatMap(function, 1),
|
||||
flux.flatMapSequential(function, 1),
|
||||
flux.map(function).concatMap(identityOperation));
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
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.Matches;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
@@ -256,7 +257,7 @@ final class StreamRules {
|
||||
// XXX: This rule assumes that any matched `Collector` does not perform any filtering.
|
||||
// (Perhaps we could add a `@Matches` guard that validates that the collector expression does not
|
||||
// contain a `Collectors#filtering` call. That'd still not be 100% accurate, though.)
|
||||
static final class StreamIsEmpty<T, K, V, C extends Collection<K>, M extends Map<K, V>> {
|
||||
static final class StreamFindAnyIsEmpty<T, K, V, C extends Collection<K>, M extends Map<K, V>> {
|
||||
@BeforeTemplate
|
||||
boolean before(Stream<T> stream, Collector<? super T, ?, ? extends C> collector) {
|
||||
return Refaster.anyOf(
|
||||
@@ -274,20 +275,20 @@ final class StreamRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(Stream<T> stream) {
|
||||
return stream.findAny().isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/** In order to test whether a stream has any element, simply try to find one. */
|
||||
static final class StreamIsNotEmpty<T> {
|
||||
/**
|
||||
* Prefer {@link Stream#findAny()} over {@link Stream#findFirst()} if one only cares whether the
|
||||
* stream is nonempty.
|
||||
*/
|
||||
static final class StreamFindAnyIsPresent<T> {
|
||||
@BeforeTemplate
|
||||
boolean before(Stream<T> stream) {
|
||||
return Refaster.anyOf(
|
||||
stream.count() != 0,
|
||||
stream.count() > 0,
|
||||
stream.count() >= 1,
|
||||
stream.findFirst().isPresent());
|
||||
return stream.findFirst().isPresent();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
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 OptionalOrElseTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(OptionalOrElse.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.errorprone.refaster.Refaster;",
|
||||
"import java.util.Optional;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final Optional<Object> optional = Optional.empty();",
|
||||
" private final String string = optional.toString();",
|
||||
"",
|
||||
" void m() {",
|
||||
" Optional.empty().orElse(null);",
|
||||
" optional.orElse(null);",
|
||||
" optional.orElse(\"constant\");",
|
||||
" optional.orElse(\"constant\" + 0);",
|
||||
" optional.orElse(Boolean.TRUE);",
|
||||
" optional.orElse(string);",
|
||||
" optional.orElse(this.string);",
|
||||
" optional.orElse(Refaster.anyOf(\"constant\", \"another\"));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.empty().orElse(string + \"constant\");",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(string + \"constant\");",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(\"constant\".toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(string.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(this.string.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(String.valueOf(42));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(string.toString().length());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(\"constant\".equals(string));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(string.equals(string));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(this.string.equals(string));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(foo());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(this.foo());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(new Object() {});",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" optional.orElse(new int[0].length);",
|
||||
" }",
|
||||
"",
|
||||
" private <T> T foo() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(OptionalOrElse.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import java.util.Optional;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final Optional<Object> optional = Optional.empty();",
|
||||
" private final String string = optional.toString();",
|
||||
"",
|
||||
" void m() {",
|
||||
" optional.orElse(string + \"constant\");",
|
||||
" optional.orElse(\"constant\".toString());",
|
||||
" optional.orElse(string.toString());",
|
||||
" optional.orElse(this.string.toString());",
|
||||
" optional.orElse(String.valueOf(42));",
|
||||
" optional.orElse(string.toString().length());",
|
||||
" optional.orElse(string.equals(string));",
|
||||
" optional.orElse(foo());",
|
||||
" optional.orElse(this.<Number>foo());",
|
||||
" optional.orElse(this.<String, Integer>bar());",
|
||||
" optional.orElse(new Object() {});",
|
||||
" optional.orElse(new int[0].length);",
|
||||
" }",
|
||||
"",
|
||||
" private <T> T foo() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"",
|
||||
" private <S, T> T bar() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import java.util.Optional;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final Optional<Object> optional = Optional.empty();",
|
||||
" private final String string = optional.toString();",
|
||||
"",
|
||||
" void m() {",
|
||||
" optional.orElseGet(() -> string + \"constant\");",
|
||||
" optional.orElseGet(\"constant\"::toString);",
|
||||
" optional.orElseGet(string::toString);",
|
||||
" optional.orElseGet(this.string::toString);",
|
||||
" optional.orElseGet(() -> String.valueOf(42));",
|
||||
" optional.orElseGet(() -> string.toString().length());",
|
||||
" optional.orElseGet(() -> string.equals(string));",
|
||||
" optional.orElseGet(() -> foo());",
|
||||
" optional.orElseGet(this::<Number>foo);",
|
||||
" optional.orElseGet(this::<String, Integer>bar);",
|
||||
" optional.orElseGet(() -> new Object() {});",
|
||||
" optional.orElseGet(() -> new int[0].length);",
|
||||
" }",
|
||||
"",
|
||||
" private <T> T foo() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"",
|
||||
" private <S, T> T bar() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ final class Slf4jLogStatementTest {
|
||||
"class A {",
|
||||
" private static final String FMT0 = \"format-string-without-placeholders\";",
|
||||
" private static final String FMT1 = \"format-string-with-{}-placeholder\";",
|
||||
" private static final String FMT2 = \"format-string-with-{}-{}-placeholders\";",
|
||||
" private static final String FMT_ERR = \"format-string-with-%s-placeholder\";",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
|
||||
@@ -9,6 +9,7 @@ import static java.util.stream.Collectors.minBy;
|
||||
import com.google.common.collect.Comparators;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -54,6 +55,10 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparator.comparing(s -> "foo", Comparator.comparingInt(String::length)));
|
||||
}
|
||||
|
||||
Comparator<String> testComparingEnum() {
|
||||
return Comparator.comparingInt(s -> RoundingMode.valueOf(s).ordinal());
|
||||
}
|
||||
|
||||
Comparator<String> testThenComparing() {
|
||||
return Comparator.<String>naturalOrder().thenComparing(Comparator.comparing(String::isEmpty));
|
||||
}
|
||||
@@ -173,4 +178,16 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Collector<Integer, ?, Optional<Integer>> testMaxByNaturalOrder() {
|
||||
return minBy(reverseOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsLessThan() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.ordinal() < RoundingMode.DOWN.ordinal(),
|
||||
RoundingMode.UP.ordinal() >= RoundingMode.DOWN.ordinal());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsLessThanOrEqualTo() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.ordinal() <= RoundingMode.DOWN.ordinal(),
|
||||
RoundingMode.UP.ordinal() > RoundingMode.DOWN.ordinal());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
@@ -9,6 +10,7 @@ import static java.util.stream.Collectors.minBy;
|
||||
import com.google.common.collect.Comparators;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -52,6 +54,10 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparator.comparing(s -> "foo", Comparator.comparingInt(String::length)));
|
||||
}
|
||||
|
||||
Comparator<String> testComparingEnum() {
|
||||
return comparing(s -> RoundingMode.valueOf(s));
|
||||
}
|
||||
|
||||
Comparator<String> testThenComparing() {
|
||||
return Comparator.<String>naturalOrder().thenComparing(String::isEmpty);
|
||||
}
|
||||
@@ -163,4 +169,16 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Collector<Integer, ?, Optional<Integer>> testMaxByNaturalOrder() {
|
||||
return maxBy(naturalOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsLessThan() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.compareTo(RoundingMode.DOWN) < 0,
|
||||
RoundingMode.UP.compareTo(RoundingMode.DOWN) >= 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsLessThanOrEqualTo() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.compareTo(RoundingMode.DOWN) <= 0,
|
||||
RoundingMode.UP.compareTo(RoundingMode.DOWN) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
|
||||
RoundingMode.UP.ordinal() == RoundingMode.DOWN.ordinal(),
|
||||
!RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
!Objects.equals(RoundingMode.UP, RoundingMode.DOWN));
|
||||
!Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
|
||||
RoundingMode.UP.ordinal() != RoundingMode.DOWN.ordinal());
|
||||
}
|
||||
|
||||
boolean testEqualsPredicate() {
|
||||
|
||||
@@ -21,6 +21,8 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP != RoundingMode.DOWN,
|
||||
RoundingMode.UP != RoundingMode.DOWN,
|
||||
RoundingMode.UP != RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(Streams.class);
|
||||
}
|
||||
|
||||
Optional<String> testOptionalEmpty() {
|
||||
return Optional.ofNullable(null);
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalOfNullable() {
|
||||
return ImmutableSet.of(
|
||||
toString() == null ? Optional.empty() : Optional.of(toString()),
|
||||
@@ -120,10 +124,12 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").or(() -> Optional.empty()),
|
||||
Optional.of("bar").or(Optional::empty),
|
||||
Optional.of("baz").stream().findFirst(),
|
||||
Optional.of("qux").stream().findAny(),
|
||||
Optional.of("quux").stream().min(String::compareTo),
|
||||
Optional.of("quuz").stream().max(String::compareTo));
|
||||
Optional.of("baz").map(Optional::of).orElseGet(() -> Optional.empty()),
|
||||
Optional.of("qux").map(Optional::of).orElseGet(Optional::empty),
|
||||
Optional.of("quux").stream().findFirst(),
|
||||
Optional.of("quuz").stream().findAny(),
|
||||
Optional.of("corge").stream().min(String::compareTo),
|
||||
Optional.of("grault").stream().max(String::compareTo));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFilter() {
|
||||
@@ -136,9 +142,7 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of(1).stream().map(String::valueOf).findAny();
|
||||
}
|
||||
|
||||
ImmutableSet<Stream<String>> testOptionalStream() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").map(Stream::of).orElse(Stream.empty()),
|
||||
Optional.of("bar").map(Stream::of).orElseGet(Stream::empty));
|
||||
Stream<String> testOptionalStream() {
|
||||
return Optional.of("foo").map(Stream::of).orElseGet(Stream::empty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(Streams.class);
|
||||
}
|
||||
|
||||
Optional<String> testOptionalEmpty() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalOfNullable() {
|
||||
return ImmutableSet.of(Optional.ofNullable(toString()), Optional.ofNullable(toString()));
|
||||
}
|
||||
@@ -120,7 +124,9 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Optional.of("baz"),
|
||||
Optional.of("qux"),
|
||||
Optional.of("quux"),
|
||||
Optional.of("quuz"));
|
||||
Optional.of("quuz"),
|
||||
Optional.of("corge"),
|
||||
Optional.of("grault"));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFilter() {
|
||||
@@ -132,7 +138,7 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of(1).map(String::valueOf);
|
||||
}
|
||||
|
||||
ImmutableSet<Stream<String>> testOptionalStream() {
|
||||
return ImmutableSet.of(Optional.of("foo").stream(), Optional.of("bar").stream());
|
||||
Stream<String> testOptionalStream() {
|
||||
return Optional.of("foo").stream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxTake() {
|
||||
return Flux.just(1, 2, 3).take(1);
|
||||
return Flux.just(1, 2, 3).take(1, true);
|
||||
}
|
||||
|
||||
Mono<String> testMonoDefaultIfEmpty() {
|
||||
@@ -207,11 +207,12 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMap() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).flatMap(Mono::just, 1),
|
||||
Flux.just(2).flatMapSequential(Mono::just, 1),
|
||||
Flux.just(3).map(Mono::just).concatMap(identity()),
|
||||
Flux.just(4).map(Mono::just).concatMap(v -> v),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
Flux.just(1).concatMap(Mono::just, 0),
|
||||
Flux.just(2).flatMap(Mono::just, 1),
|
||||
Flux.just(3).flatMapSequential(Mono::just, 1),
|
||||
Flux.just(4).map(Mono::just).concatMap(identity()),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> v),
|
||||
Flux.just(6).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapWithPrefetch() {
|
||||
|
||||
@@ -147,7 +147,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxTake() {
|
||||
return Flux.just(1, 2, 3).take(1, true);
|
||||
return Flux.just(1, 2, 3).take(1);
|
||||
}
|
||||
|
||||
Mono<String> testMonoDefaultIfEmpty() {
|
||||
@@ -214,7 +214,8 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.just(2).concatMap(Mono::just),
|
||||
Flux.just(3).concatMap(Mono::just),
|
||||
Flux.just(4).concatMap(Mono::just),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
Flux.just(5).concatMap(Mono::just),
|
||||
Flux.just(6).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapWithPrefetch() {
|
||||
|
||||
@@ -120,7 +120,7 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of("bar").map(String::length).findFirst());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsEmpty() {
|
||||
ImmutableSet<Boolean> testStreamFindAnyIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).count() == 0,
|
||||
Stream.of(2).count() <= 0,
|
||||
@@ -131,15 +131,14 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of(7).collect(collectingAndThen(toImmutableList(), ImmutableList::isEmpty)),
|
||||
Stream.of(8).collect(collectingAndThen(toImmutableMap(k -> k, v -> v), Map::isEmpty)),
|
||||
Stream.of(9)
|
||||
.collect(collectingAndThen(toImmutableMap(k -> k, v -> v), ImmutableMap::isEmpty)));
|
||||
.collect(collectingAndThen(toImmutableMap(k -> k, v -> v), ImmutableMap::isEmpty)),
|
||||
Stream.of(10).count() != 0,
|
||||
Stream.of(11).count() > 0,
|
||||
Stream.of(12).count() >= 1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).count() != 0,
|
||||
Stream.of(2).count() > 0,
|
||||
Stream.of(3).count() >= 1,
|
||||
Stream.of(4).findFirst().isPresent());
|
||||
boolean testStreamFindAnyIsPresent() {
|
||||
return Stream.of(1).findFirst().isPresent();
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testStreamMin() {
|
||||
|
||||
@@ -121,7 +121,7 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of("bar").findFirst().map(String::length));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsEmpty() {
|
||||
ImmutableSet<Boolean> testStreamFindAnyIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).findAny().isEmpty(),
|
||||
Stream.of(2).findAny().isEmpty(),
|
||||
@@ -131,15 +131,14 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of(6).findAny().isEmpty(),
|
||||
Stream.of(7).findAny().isEmpty(),
|
||||
Stream.of(8).findAny().isEmpty(),
|
||||
Stream.of(9).findAny().isEmpty());
|
||||
Stream.of(9).findAny().isEmpty(),
|
||||
!Stream.of(10).findAny().isEmpty(),
|
||||
!Stream.of(11).findAny().isEmpty(),
|
||||
!Stream.of(12).findAny().isEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).findAny().isPresent(),
|
||||
Stream.of(2).findAny().isPresent(),
|
||||
Stream.of(3).findAny().isPresent(),
|
||||
Stream.of(4).findAny().isPresent());
|
||||
boolean testStreamFindAnyIsPresent() {
|
||||
return Stream.of(1).findAny().isPresent();
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testStreamMin() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-experimental</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-guidelines</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-utils</artifactId>
|
||||
|
||||
@@ -53686,6 +53686,15 @@
|
||||
final ModuleFactory moduleFactory = TestUtil.getPackageObjectFactory();
|
||||
|
||||
final Path path = Paths.get(XdocUtil.DIRECTORY_PATH + "/config.xml");
|
||||
@@ -1081,7 +1083,7 @@ public class XdocsPagesTest {
|
||||
Optional.ofNullable(field)
|
||||
.map(nonNullField -> nonNullField.getAnnotation(XdocsPropertyType.class))
|
||||
.map(propertyType -> propertyType.value().getDescription())
|
||||
- .orElse(fieldClass.getSimpleName());
|
||||
+ .orElseGet(fieldClass::getSimpleName);
|
||||
final String expectedValue =
|
||||
getModulePropertyExpectedValue(sectionName, propertyName, field, fieldClass, instance);
|
||||
|
||||
@@ -1364,7 +1366,7 @@ public class XdocsPagesTest {
|
||||
final Object[] array = (Object[]) value;
|
||||
valuesStream = Arrays.stream(array);
|
||||
|
||||
7
jitpack.yml
Normal file
7
jitpack.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
before_install:
|
||||
- source "${HOME}/.sdkman/bin/sdkman-init.sh"
|
||||
- sdk update
|
||||
- sdk install java 17.0.10-tem
|
||||
- sdk use java 17.0.10-tem
|
||||
- sdk install maven 3.9.8
|
||||
- sdk use maven 3.9.8
|
||||
103
pom.xml
103
pom.xml
@@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Picnic :: Error Prone Support</name>
|
||||
@@ -48,11 +48,12 @@
|
||||
<module>refaster-runner</module>
|
||||
<module>refaster-support</module>
|
||||
<module>refaster-test-support</module>
|
||||
<module>testng-junit-migrator</module>
|
||||
</modules>
|
||||
|
||||
<scm child.scm.developerConnection.inherit.append.path="false" child.scm.url.inherit.append.path="false">
|
||||
<developerConnection>scm:git:git@github.com:PicnicSupermarket/error-prone-support.git</developerConnection>
|
||||
<tag>v0.16.1</tag>
|
||||
<tag>HEAD</tag>
|
||||
<url>https://github.com/PicnicSupermarket/error-prone-support</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
@@ -148,7 +149,7 @@
|
||||
<groupId.error-prone>com.google.errorprone</groupId.error-prone>
|
||||
<!-- The build timestamp is derived from the most recent commit
|
||||
timestamp in support of reproducible builds. -->
|
||||
<project.build.outputTimestamp>2024-03-15T12:02:48Z</project.build.outputTimestamp>
|
||||
<project.build.outputTimestamp>2024-03-15T12:04:44Z</project.build.outputTimestamp>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- Glob pattern identifying Refaster rule definition files. These
|
||||
Java classes don't contain "regular" code, and thus require special
|
||||
@@ -205,19 +206,19 @@
|
||||
one place. We use these to keep dependencies in sync. Version numbers
|
||||
that need to be referenced only once should *not* be listed here. -->
|
||||
<version.auto-service>1.1.1</version.auto-service>
|
||||
<version.auto-value>1.10.4</version.auto-value>
|
||||
<version.auto-value>1.11.0</version.auto-value>
|
||||
<version.error-prone>${version.error-prone-orig}</version.error-prone>
|
||||
<version.error-prone-fork>v${version.error-prone-orig}-picnic-2</version.error-prone-fork>
|
||||
<version.error-prone-orig>2.25.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.22</version.error-prone-slf4j>
|
||||
<version.error-prone-fork>v${version.error-prone-orig}-picnic-1</version.error-prone-fork>
|
||||
<version.error-prone-orig>2.27.1</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.25</version.error-prone-slf4j>
|
||||
<version.guava-beta-checker>1.0</version.guava-beta-checker>
|
||||
<version.jdk>17</version.jdk>
|
||||
<version.maven>3.9.5</version.maven>
|
||||
<version.mockito>5.11.0</version.mockito>
|
||||
<version.mockito>5.12.0</version.mockito>
|
||||
<version.nopen-checker>1.0.1</version.nopen-checker>
|
||||
<version.nullaway>0.10.24</version.nullaway>
|
||||
<version.nullaway>0.11.0</version.nullaway>
|
||||
<version.pitest-git>1.1.4</version.pitest-git>
|
||||
<version.rewrite-templating>1.6.2</version.rewrite-templating>
|
||||
<version.rewrite-templating>1.10.0</version.rewrite-templating>
|
||||
<version.surefire>3.2.3</version.surefire>
|
||||
</properties>
|
||||
|
||||
@@ -296,7 +297,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson</groupId>
|
||||
<artifactId>jackson-bom</artifactId>
|
||||
<version>2.16.2</version>
|
||||
<version>2.17.1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -328,7 +329,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.googlejavaformat</groupId>
|
||||
<artifactId>google-java-format</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.22.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
@@ -338,7 +339,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-bom</artifactId>
|
||||
<version>33.0.0-jre</version>
|
||||
<version>33.2.1-jre</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -360,7 +361,7 @@
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
<version>2023.0.3</version>
|
||||
<version>2023.0.6</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -372,17 +373,17 @@
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.6.13</version>
|
||||
<version>1.6.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>2.2.20</version>
|
||||
<version>2.2.22</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
@@ -407,7 +408,7 @@
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.12</version>
|
||||
<version>1.14.17</version>
|
||||
</dependency>
|
||||
<!-- Specified so that Renovate will file Maven upgrade PRs, which
|
||||
subsequently will cause `maven-enforcer-plugin` to require that
|
||||
@@ -420,7 +421,7 @@
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.21.1</version>
|
||||
<version>1.9.22.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
@@ -432,7 +433,7 @@
|
||||
<dependency>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<version>3.42.0</version>
|
||||
<version>3.44.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
@@ -466,7 +467,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-core</artifactId>
|
||||
<version>5.0.0</version>
|
||||
<version>5.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
@@ -476,40 +477,40 @@
|
||||
<dependency>
|
||||
<groupId>org.openrewrite.recipe</groupId>
|
||||
<artifactId>rewrite-recipe-bom</artifactId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.12.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-bom</artifactId>
|
||||
<version>2.0.12</version>
|
||||
<version>2.0.13</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>6.1.4</version>
|
||||
<version>6.1.8</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<version>3.2.3</version>
|
||||
<version>3.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-bom</artifactId>
|
||||
<version>6.2.2</version>
|
||||
<version>6.3.1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>7.9.0</version>
|
||||
<version>7.10.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
@@ -520,7 +521,7 @@
|
||||
<plugin>
|
||||
<groupId>com.github.ekryd.sortpom</groupId>
|
||||
<artifactId>sortpom-maven-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<version>4.0.0</version>
|
||||
<configuration>
|
||||
<createBackupFile>false</createBackupFile>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
@@ -577,7 +578,7 @@
|
||||
<plugin>
|
||||
<groupId>de.thetaphi</groupId>
|
||||
<artifactId>forbiddenapis</artifactId>
|
||||
<version>3.6</version>
|
||||
<version>3.7</version>
|
||||
<configuration>
|
||||
<bundledSignatures>
|
||||
<bundledSignature>jdk-internal</bundledSignature>
|
||||
@@ -624,7 +625,7 @@
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<version>8.0.1</version>
|
||||
<version>9.0.0</version>
|
||||
<configuration>
|
||||
<injectAllReactorProjects>true</injectAllReactorProjects>
|
||||
<runOnlyOnce>true</runOnlyOnce>
|
||||
@@ -643,7 +644,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.4.0</version>
|
||||
<configuration>
|
||||
<checkstyleRules>
|
||||
<!-- We only enable rules that are not enforced by
|
||||
@@ -679,6 +680,7 @@
|
||||
<property name="allowNonPrintableEscapes" value="true" />
|
||||
</module>
|
||||
<module name="AvoidNoArgumentSuperConstructorCall" />
|
||||
<module name="ConstructorsDeclarationGrouping" />
|
||||
<module name="DeclarationOrder">
|
||||
<!-- We don't enforce sorting fields by
|
||||
their visibility modifier, for two
|
||||
@@ -891,7 +893,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>10.14.0</version>
|
||||
<version>10.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spring.nohttp</groupId>
|
||||
@@ -916,7 +918,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<!-- XXX: Inline and drop the version
|
||||
@@ -963,7 +965,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<!-- XXX: Drop `ignoreAllNonTestScoped` once
|
||||
https://issues.apache.org/jira/browse/MNG-6058 is
|
||||
@@ -978,7 +980,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.2</version>
|
||||
<configuration>
|
||||
<retryFailedDeploymentCount>3</retryFailedDeploymentCount>
|
||||
</configuration>
|
||||
@@ -986,7 +988,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<fail>false</fail>
|
||||
<rules>
|
||||
@@ -1041,6 +1043,9 @@
|
||||
<requireJavaVersion>
|
||||
<version>${version.jdk}</version>
|
||||
</requireJavaVersion>
|
||||
<requireMatchingCoordinates>
|
||||
<moduleNameMustMatchArtifactId>true</moduleNameMustMatchArtifactId>
|
||||
</requireMatchingCoordinates>
|
||||
<requireMavenVersion>
|
||||
<version>${version.maven}</version>
|
||||
</requireMavenVersion>
|
||||
@@ -1068,7 +1073,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
@@ -1081,12 +1086,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<skipIfEmpty>true</skipIfEmpty>
|
||||
<archive>
|
||||
@@ -1114,7 +1119,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.6.3</version>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</additionalJOption>
|
||||
@@ -1143,7 +1148,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||
<preparationProfiles>release</preparationProfiles>
|
||||
@@ -1170,7 +1175,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-source-jar</id>
|
||||
@@ -1200,7 +1205,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<version>3.6.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
@@ -1330,7 +1335,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>tidy-maven-plugin</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.3.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>check-pom</id>
|
||||
@@ -1351,7 +1356,7 @@
|
||||
<plugin>
|
||||
<groupId>org.gaul</groupId>
|
||||
<artifactId>modernizer-maven-plugin</artifactId>
|
||||
<version>2.8.0</version>
|
||||
<version>2.9.0</version>
|
||||
<configuration>
|
||||
<exclusionPatterns>
|
||||
<!-- The plugin suggests replacing usages of
|
||||
@@ -1382,7 +1387,7 @@
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.11</version>
|
||||
<version>0.8.12</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<!-- Refaster rules are tested using a custom method
|
||||
@@ -1394,7 +1399,7 @@
|
||||
<plugin>
|
||||
<groupId>org.kordamp.maven</groupId>
|
||||
<artifactId>pomchecker-maven-plugin</artifactId>
|
||||
<version>1.10.0</version>
|
||||
<version>1.11.0</version>
|
||||
<configuration>
|
||||
<failOnError>false</failOnError>
|
||||
<release>false</release>
|
||||
@@ -1412,7 +1417,7 @@
|
||||
<plugin>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-maven</artifactId>
|
||||
<version>1.15.8</version>
|
||||
<version>1.16.1</version>
|
||||
<configuration>
|
||||
<excludedClasses>
|
||||
<!-- AutoValue generated classes. -->
|
||||
@@ -1466,7 +1471,7 @@
|
||||
<plugin>
|
||||
<groupId>org.sonarsource.scanner.maven</groupId>
|
||||
<artifactId>sonar-maven-plugin</artifactId>
|
||||
<version>3.10.0.2594</version>
|
||||
<version>4.0.0.4121</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
|
||||
@@ -112,7 +112,7 @@ final class RefasterRuleCompilerTaskListener implements TaskListener {
|
||||
return (sym != null
|
||||
&& sym.getQualifiedName()
|
||||
.contentEquals(BeforeTemplate.class.getCanonicalName()))
|
||||
|| super.visitAnnotation(node, unused);
|
||||
|| super.visitAnnotation(node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-runner</artifactId>
|
||||
|
||||
@@ -166,7 +166,7 @@ public final class Refaster extends BugChecker implements CompilationUnitTreeMat
|
||||
"Refaster Rule",
|
||||
description.getLink(),
|
||||
String.join(": ", description.checkName, description.getRawMessage()))
|
||||
.overrideSeverity(severityOverride.orElse(description.severity()))
|
||||
.overrideSeverity(severityOverride.orElseGet(description::severity))
|
||||
.addAllFixes(description.fixes)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-support</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
|
||||
147
testng-junit-migrator/README.md
Normal file
147
testng-junit-migrator/README.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# TestNG to JUnit Jupiter migrator
|
||||
|
||||
This module contains a tool to automatically migrate TestNG tests to JUnit
|
||||
Jupiter. The tool is built on top of [Error Prone][error-prone-orig-repo]. To
|
||||
use it, read the installation guide below.
|
||||
|
||||
### Installation
|
||||
|
||||
1. First, follow Error Prone's [installation
|
||||
guide][error-prone-installation-guide]. For extra information, see this
|
||||
[README][eps-readme]. (This step can be skipped for Picnic repositories!)
|
||||
2. Clone the Error Prone Support repository and checkout the branch
|
||||
`gdejong/testng-migrator`.
|
||||
3. Next, run `mvn versions:set -DnewVersion=0.17.1-testng-migration -DgenerateBackupPoms=false`.
|
||||
This will update set the version to `0.17.1-testng-migration`.
|
||||
4. Next, run `mvn clean install`. This will create a `0.17.1-testng-migrator` version
|
||||
of the `testng-junit-migrator` module. The version will now be available in your local Maven repository.
|
||||
5. Finally, add the following profile to your `pom.xml`. This should be the `pom.xml` in the root of your module.
|
||||
Usually this is the parent `pom.xml`, but single module projects are also supported.
|
||||
|
||||
```xml
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>testng-migrator</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths combine.children="append">
|
||||
<path>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>testng-junit-migrator</artifactId>
|
||||
<version>0.10.1-testng-migration</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
```
|
||||
|
||||
Having this profile allows the migration script to verify the correctness of
|
||||
the result by making sure the same amount of tests are executed.
|
||||
|
||||
## Run the migration
|
||||
|
||||
> **Note**
|
||||
> For Picnic repositories there is an extra step required _before_ running the
|
||||
> migration, see [here](#picnic-specific).
|
||||
|
||||
Now that the migration is set up, one can start the migration by executing the
|
||||
[run-testng-junit-migrator.sh][migration-script] script in the same directory as the `pom.xml` file we changed earlier.
|
||||
|
||||
This script will:
|
||||
|
||||
1. Add the required `JUnit` dependencies to your `pom.xml`.
|
||||
2. Run the `testng-to-junit` migration.
|
||||
|
||||
> **Note**
|
||||
> Please verify that the migrated code still compiles after each step of the compilation.
|
||||
|
||||
### Counting tests
|
||||
|
||||
The amount of tests executed before the migration can be counted using the `--count` flag:
|
||||
```sh
|
||||
./run-testng-junit-migrator.sh --count
|
||||
```
|
||||
This will count the amount of tests that are executed. This is recommended before running the migration
|
||||
to allow for comparison.
|
||||
|
||||
### Picnic specific
|
||||
|
||||
The `PicnicSupermarket/picnic-scratch` repository contains a helper script
|
||||
`java-platform/testng-junit-migration.sh` that migrates some more
|
||||
Picnic-specific code. This should be executed _before_ starting the actual
|
||||
migration.
|
||||
|
||||
> **Warning**
|
||||
> This is a warning for `macOs` users.
|
||||
> Make sure gnu-grep and gnu-sed are installed!
|
||||
>
|
||||
> ```brew install grep gnu-sed```
|
||||
|
||||
Continue with performing the actual migration [here](#run-the-migration).
|
||||
Afterward, run the `./picnic-shared-tools/patch.sh` script.
|
||||
|
||||
Now you are done! 🤘🚀
|
||||
|
||||
### Migration code example
|
||||
|
||||
Consider the following TestNG test class:
|
||||
|
||||
```java
|
||||
// TestNG code:
|
||||
@Test
|
||||
public class A {
|
||||
public void simpleTest() {}
|
||||
|
||||
@Test(priority = 2)
|
||||
public void priorityTest() {}
|
||||
|
||||
@DataProvider
|
||||
private static Object[][] dataProviderTestCases() {
|
||||
return new Object[]{{1}, {2}, {3}};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "dataProviderTestCases")
|
||||
public void dataProviderTest(int number) {}
|
||||
}
|
||||
```
|
||||
|
||||
This migration tool will turn this into the following:
|
||||
|
||||
```java
|
||||
// JUnit Jupiter code:
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class A {
|
||||
@Test
|
||||
void simpleTest() {}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void priorityTest() {}
|
||||
|
||||
private static Stream<Argument> dataProviderTestCases() {
|
||||
return Stream.of(arguments(1), arguments(2), arguments(3));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("dataProviderTestCases")
|
||||
public void dataProviderTest(int number) {}
|
||||
}
|
||||
```
|
||||
|
||||
### Known limitations
|
||||
- Certain `@DataProvider` methods cannot be automatically migrated (e.g., `return Stream.of(...).toArray(Object[][]::new)`).
|
||||
- Some uncommon `@Test` attributes are not supported, such as `ignoreMissingDependencies` and `dependsOnMethods`.
|
||||
- Test setup and teardown methods `@{Before, After}Test` are migrated to `@{Before, After}Each` to avoid introducing breaking changes. `@{Before, After}All` require a static method, while `@{Before, After}Test` are instance methods.
|
||||
|
||||
[eps-readme]: ../README.md
|
||||
[error-prone-installation-guide]: https://errorprone.info/docs/installation#maven
|
||||
[error-prone-orig-repo]: https://github.com/google/error-prone
|
||||
[migration-script]: run-testng-junit-migration.sh
|
||||
156
testng-junit-migrator/pom.xml
Normal file
156
testng-junit-migrator/pom.xml
Normal file
@@ -0,0 +1,156 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>testng-junit-migrator</artifactId>
|
||||
|
||||
<name>Picnic :: Error Prone Support :: TestNG JUnit Migrator</name>
|
||||
<description>A tool to migrate TestNG tests to JUnit</description>
|
||||
<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>refaster-compiler</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-support</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto</groupId>
|
||||
<artifactId>auto-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.service</groupId>
|
||||
<artifactId>auto-service-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.value</groupId>
|
||||
<artifactId>auto-value-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<artifactId>jspecify</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-java</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-java-11</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-templating</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths combine.children="append">
|
||||
<path>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-support</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
<compilerArgs combine.children="append">
|
||||
<arg>-Xplugin:RefasterRuleCompiler</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
142
testng-junit-migrator/run-testng-junit-migration.sh
Executable file
142
testng-junit-migrator/run-testng-junit-migration.sh
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
# If this is not a Maven build, exit here to skip Maven-specific steps.
|
||||
if [ ! -f pom.xml ]; then
|
||||
echo "Not a Maven build, exiting."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
function insert_dependency() {
|
||||
groupId=${1:?groupId not specified or empty}
|
||||
artifactId=${2:?artifactId not specified or empty}
|
||||
classifier=${3?classifier not specified}
|
||||
scope=${4?scope not specified}
|
||||
pomFile=${5:-pom.xml}
|
||||
|
||||
# If the dependency declaration is already present (irrespective of scope),
|
||||
# then we don't modify the file.
|
||||
xmlstarlet sel -T -N 'x=http://maven.apache.org/POM/4.0.0' \
|
||||
-t -m "/x:project/x:dependencies/x:dependency[
|
||||
x:groupId/text() = '${groupId}' and
|
||||
x:artifactId/text() = '${artifactId}' and
|
||||
(x:classifier/text() = '${classifier}' or '${classifier}' = '')
|
||||
]" -nl "${pomFile}" && return 0
|
||||
|
||||
# Determine the index at which to insert the dependency declaration.
|
||||
insertionIndex="$(
|
||||
(xmlstarlet sel -T -N 'x=http://maven.apache.org/POM/4.0.0' \
|
||||
-t -m '/x:project/x:dependencies/x:dependency' \
|
||||
-v 'concat(x:groupId, " : ", x:artifactId, " : ", x:classifier, " : ", x:scope)' -nl \
|
||||
"${pomFile}" || true) |
|
||||
awk "\$0 < \"${groupId} : ${artifactId} : ${classifier} : ${scope}\"" |
|
||||
wc -l
|
||||
)"
|
||||
|
||||
# Generate a placeholder that will be inserted at the place where the new
|
||||
# dependency declaration should reside. We need to jump through this hoop
|
||||
# because `xmlstarlet` does not support insertion of complex XML
|
||||
# sub-documents.
|
||||
placeholder="$(head -c 30 /dev/urandom | base64 | $sed_command 's,[^a-zA-Z0-9],,g')"
|
||||
|
||||
# Insert the placeholder. (Note that only one case will match.)
|
||||
xmlstarlet ed -L -P -N 'x=http://maven.apache.org/POM/4.0.0' \
|
||||
-s "/x:project[not(x:dependencies)]" \
|
||||
-t elem -n dependencies -v "${placeholder}" \
|
||||
-i "/x:project/x:dependencies/x:dependency[${insertionIndex} = 0 and position() = 1]" \
|
||||
-t text -n placeholder -v "${placeholder}" \
|
||||
-a "/x:project/x:dependencies/x:dependency[${insertionIndex}]" \
|
||||
-t text -n placeholder -v "${placeholder}" \
|
||||
"${pomFile}"
|
||||
|
||||
# Generate the XML subdocument we _actually_ want to insert.
|
||||
decl="$(echo "
|
||||
<dependency>
|
||||
<groupId>${groupId}</groupId>
|
||||
<artifactId>${artifactId}</artifactId>
|
||||
<classifier>${classifier}</classifier>
|
||||
<scope>${scope}</scope>
|
||||
</dependency>" |
|
||||
$sed_command '/></d' |
|
||||
$sed_command ':a;N;$!ba;s/\n/\\n/g')"
|
||||
|
||||
# Replace the placeholder with the actual dependency declaration.
|
||||
$sed_command -i "s,${placeholder},${decl}," "${pomFile}"
|
||||
}
|
||||
|
||||
if [[ -n "${1-}" ]] && [[ "${1}" == "--count" ]]; then
|
||||
echo "Counting number of tests..."
|
||||
test_results=$(mvn test | $grep_command -n "Results:" -A 3 | $grep_command -oP "Tests run: \K\d+(?=,)" | awk '{s+=$1} END {print s}')
|
||||
echo "Number of tests run: $test_results"
|
||||
exit
|
||||
fi
|
||||
|
||||
function handle_file() {
|
||||
module=${1:?module not specified or empty}
|
||||
groupId=${2:?groupId not specified or empty}
|
||||
artifactId=${3:?artifactId not specified or empty}
|
||||
classifier=${4?classifier not specified}
|
||||
scope=${5?scope not specified}
|
||||
pomFile=${6:-pom.xml}
|
||||
|
||||
if [[ -d $module ]] && [[ -f "$module/pom.xml" ]]; then
|
||||
cd "$module"
|
||||
insert_dependency "$groupId" "$artifactId" "$classifier" "$scope"
|
||||
echo "[$module] Added $groupId:$artifactId"
|
||||
cd -
|
||||
fi
|
||||
}
|
||||
|
||||
case "$(uname -s)" in
|
||||
Linux*)
|
||||
grep_command="grep"
|
||||
sed_command="sed"
|
||||
;;
|
||||
Darwin*)
|
||||
grep_command="ggrep"
|
||||
sed_command="gsed"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distribution $(uname -s) for this script."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Migrating to JUnit 5..."
|
||||
echo "Adding required dependencies..."
|
||||
|
||||
if $grep_command -q "<packaging>pom</packaging>" "pom.xml"; then
|
||||
|
||||
for module in $($grep_command -rl "org.testng.annotations.Test" $(pwd) | awk -F "$(pwd)" '{print $2}' | awk -F '/' '{print $2}' | uniq); do
|
||||
(
|
||||
handle_file "$module" "org.junit.jupiter" "junit-jupiter-api" "" "test"
|
||||
)
|
||||
(
|
||||
handle_file "$module" "org.junit.jupiter" "junit-jupiter-engine" "" "test"
|
||||
)
|
||||
done
|
||||
for module in $($grep_command -rl "org.testng.annotations.DataProvider" $(pwd) | awk -F "$(pwd)" '{print $2}' | awk -F '/' '{print $2}' | uniq); do
|
||||
(
|
||||
handle_file "$module" "org.junit.jupiter" "junit-jupiter-params" "" "test"
|
||||
)
|
||||
done
|
||||
else
|
||||
if $grep_command -rq "org.testng.annotations.Test" "src/"; then
|
||||
handle_file "./" "org.junit.jupiter" "junit-jupiter-api" "" "test"
|
||||
handle_file "./" "org.junit.jupiter" "junit-jupiter-engine" "" "test"
|
||||
fi
|
||||
if $grep_command -rq "org.testng.annotations.DataProvider" "src/"; then
|
||||
handle_file "./" "org.junit.jupiter" "junit-jupiter-params" "" "test"
|
||||
fi
|
||||
fi
|
||||
echo "Running migration..."
|
||||
mvn \
|
||||
-Perror-prone \
|
||||
-Ptestng-migrator \
|
||||
-Ppatch \
|
||||
clean test-compile fmt:format \
|
||||
-Derror-prone.patch-checks="TestNGJUnitMigration" \
|
||||
-Dverification.skip
|
||||
|
||||
echo "Finished executing migration!"
|
||||
@@ -0,0 +1,29 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* Interface implemented by classes that define how to migrate a specific attribute from a TestNG
|
||||
* {@code Test} annotation to JUnit.
|
||||
*/
|
||||
@Immutable
|
||||
interface AttributeMigrator {
|
||||
/**
|
||||
* Attempts to create a {@link SuggestedFix}.
|
||||
*
|
||||
* @param methodTree The method tree the annotation is on.
|
||||
* @param state The visitor state.
|
||||
* @return an {@link Optional} containing the created fix. This returns an {@link
|
||||
* Optional#empty()} if the {@link AttributeMigrator} is not able to migrate the attribute.
|
||||
*/
|
||||
Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
VisitorState state);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* A {@link AttributeMigrator} that migrates the {@code org.testng.annotations.Test#dataProvider}
|
||||
* attributes.
|
||||
*/
|
||||
@Immutable
|
||||
final class DataProviderAttributeMigrator implements AttributeMigrator {
|
||||
@Override
|
||||
public Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
ExpressionTree dataProviderNameExpressionTree = annotation.getAttributes().get("dataProvider");
|
||||
if (dataProviderNameExpressionTree == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String dataProviderName = ASTHelpers.constValue(dataProviderNameExpressionTree, String.class);
|
||||
if (!metadata.getDataProviderMetadata().containsKey(dataProviderName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(
|
||||
SuggestedFix.builder()
|
||||
.addImport("org.junit.jupiter.params.ParameterizedTest")
|
||||
.addImport("org.junit.jupiter.params.provider.MethodSource")
|
||||
.prefixWith(methodTree, "@ParameterizedTest\n")
|
||||
.prefixWith(methodTree, String.format("@MethodSource(\"%s\")%n", dataProviderName))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.sun.source.tree.Tree.Kind.NEW_ARRAY;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.google.errorprone.util.ErrorProneToken;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.NewArrayTree;
|
||||
import com.sun.source.tree.ReturnTree;
|
||||
import com.sun.tools.javac.parser.Tokens.Comment;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.util.SourceCode;
|
||||
|
||||
// XXX: Can this one also implement a `Migrator`?
|
||||
/** A helper class that migrates a TestNG {@code DataProvider} to a JUnit {@code MethodSource}. */
|
||||
final class DataProviderMigrator {
|
||||
/** This regular expression replaces matches instances of `this.getClass()` and `getClass()`. */
|
||||
private static final Pattern GET_CLASS =
|
||||
Pattern.compile("((?<!\\b\\.)|(\\bthis\\.))(getClass\\(\\))");
|
||||
|
||||
private DataProviderMigrator() {}
|
||||
|
||||
/**
|
||||
* Tells whether the specified {@code DataProvider} can be migrated.
|
||||
*
|
||||
* @param methodTree The dataprovider methode tree.
|
||||
* @return {@code true} if the data provider can be migrated or else {@code false}.
|
||||
*/
|
||||
static boolean canFix(MethodTree methodTree) {
|
||||
return getDataProviderReturnTree(getReturnTree(methodTree)).isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link SuggestedFix} required to migrate a TestNG {@code DataProvider} to a JUnit
|
||||
* {@code MethodSource}.
|
||||
*
|
||||
* @param classTree The class containing the data provider.
|
||||
* @param methodTree The data provider method.
|
||||
* @param state The {@link VisitorState}.
|
||||
* @return An {@link Optional} containing the created fix.
|
||||
*/
|
||||
static Optional<SuggestedFix> createFix(
|
||||
ClassTree classTree, MethodTree methodTree, VisitorState state) {
|
||||
return tryMigrateDataProvider(methodTree, classTree, state);
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> tryMigrateDataProvider(
|
||||
MethodTree methodTree, ClassTree classTree, VisitorState state) {
|
||||
ReturnTree returnTree = getReturnTree(methodTree);
|
||||
|
||||
return getDataProviderReturnTree(returnTree)
|
||||
.map(
|
||||
dataProviderReturnTree ->
|
||||
SuggestedFix.builder()
|
||||
.addStaticImport("org.junit.jupiter.params.provider.Arguments.arguments")
|
||||
.addImport(Stream.class.getCanonicalName())
|
||||
.addImport("org.junit.jupiter.params.provider.Arguments")
|
||||
.delete(methodTree)
|
||||
.postfixWith(
|
||||
methodTree,
|
||||
buildMethodSource(
|
||||
classTree.getSimpleName().toString(),
|
||||
methodTree.getName().toString(),
|
||||
methodTree,
|
||||
returnTree,
|
||||
dataProviderReturnTree,
|
||||
state))
|
||||
.build());
|
||||
}
|
||||
|
||||
private static ReturnTree getReturnTree(MethodTree methodTree) {
|
||||
return methodTree.getBody().getStatements().stream()
|
||||
.filter(ReturnTree.class::isInstance)
|
||||
.findFirst()
|
||||
.map(ReturnTree.class::cast)
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
private static Optional<NewArrayTree> getDataProviderReturnTree(ReturnTree returnTree) {
|
||||
if (returnTree.getExpression().getKind() != NEW_ARRAY
|
||||
|| ((NewArrayTree) returnTree.getExpression()).getInitializers().isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of((NewArrayTree) returnTree.getExpression());
|
||||
}
|
||||
|
||||
private static String buildMethodSource(
|
||||
String className,
|
||||
String name,
|
||||
MethodTree methodTree,
|
||||
ReturnTree returnTree,
|
||||
NewArrayTree newArrayTree,
|
||||
VisitorState state) {
|
||||
StringBuilder sourceBuilder =
|
||||
new StringBuilder()
|
||||
.append(" private static Stream<Arguments> ")
|
||||
.append(name)
|
||||
.append(" () ");
|
||||
|
||||
if (!methodTree.getThrows().isEmpty()) {
|
||||
sourceBuilder
|
||||
.append(" throws ")
|
||||
.append(
|
||||
methodTree.getThrows().stream()
|
||||
.filter(IdentifierTree.class::isInstance)
|
||||
.map(IdentifierTree.class::cast)
|
||||
.map(identifierTree -> identifierTree.getName().toString())
|
||||
.collect(joining(", ")));
|
||||
}
|
||||
|
||||
return sourceBuilder
|
||||
.append(" {\n")
|
||||
.append(extractMethodBodyWithoutReturnStatement(methodTree, returnTree, state))
|
||||
.append(" return ")
|
||||
.append(buildArgumentStream(className, newArrayTree, state))
|
||||
.append(";\n}")
|
||||
.toString();
|
||||
}
|
||||
|
||||
private static String extractMethodBodyWithoutReturnStatement(
|
||||
MethodTree methodTree, ReturnTree returnTree, VisitorState state) {
|
||||
String body = SourceCode.treeToString(methodTree.getBody(), state);
|
||||
return body.substring(2, body.indexOf(SourceCode.treeToString(returnTree, state)) - 1);
|
||||
}
|
||||
|
||||
private static String buildArgumentStream(
|
||||
String className, NewArrayTree newArrayTree, VisitorState state) {
|
||||
int startPos = ASTHelpers.getStartPosition(newArrayTree);
|
||||
int endPos = state.getEndPosition(newArrayTree);
|
||||
ImmutableMap<Integer, List<Comment>> comments =
|
||||
state.getOffsetTokens(startPos, endPos).stream()
|
||||
.collect(toImmutableMap(ErrorProneToken::pos, ErrorProneToken::comments));
|
||||
|
||||
StringBuilder argumentsBuilder = new StringBuilder();
|
||||
argumentsBuilder.append(
|
||||
newArrayTree.getInitializers().stream()
|
||||
.map(
|
||||
expression ->
|
||||
wrapTestValueWithArguments(
|
||||
expression,
|
||||
comments.getOrDefault(
|
||||
ASTHelpers.getStartPosition(expression), ImmutableList.of()),
|
||||
state))
|
||||
.collect(joining(",")));
|
||||
|
||||
/*
|
||||
* This replaces all instances of `{,this.}getClass()` with the fully qualified class name to
|
||||
* retain functionality in static context.
|
||||
*/
|
||||
return GET_CLASS
|
||||
.matcher(String.format("Stream.of(%s%n)", argumentsBuilder))
|
||||
.replaceAll(className + ".class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a value in {@code org.junit.jupiter.params.provider#arguments()}.
|
||||
*
|
||||
* <p>Drops curly braces from array initialisation values.
|
||||
*/
|
||||
private static String wrapTestValueWithArguments(
|
||||
ExpressionTree tree, List<Comment> comments, VisitorState state) {
|
||||
String source = SourceCode.treeToString(tree, state);
|
||||
|
||||
String argumentValue =
|
||||
tree.getKind() == NEW_ARRAY ? source.substring(1, source.length() - 1) : source;
|
||||
|
||||
return String.format(
|
||||
"\t\t%s%n\t\targuments(%s)",
|
||||
comments.stream().map(Comment::getText).collect(joining("\n")), argumentValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
import tech.picnic.errorprone.util.SourceCode;
|
||||
|
||||
/** A {@link AttributeMigrator} that migrates the {@code description} attribute. */
|
||||
@Immutable
|
||||
final class DescriptionAttributeMigrator implements AttributeMigrator {
|
||||
@Override
|
||||
public Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
return Optional.ofNullable(annotation.getAttributes().get("description"))
|
||||
.map(
|
||||
description ->
|
||||
SuggestedFix.builder()
|
||||
.addImport("org.junit.jupiter.api.DisplayName")
|
||||
.prefixWith(
|
||||
methodTree,
|
||||
String.format(
|
||||
"@DisplayName(%s)%n", SourceCode.treeToString(description, state)))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
|
||||
/** A {@link AttributeMigrator} that migrates the {@code enabled} attribute. */
|
||||
@Immutable
|
||||
final class EnabledAttributeMigrator implements AttributeMigrator {
|
||||
@Override
|
||||
public Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
return Optional.ofNullable(annotation.getAttributes().get("enabled"))
|
||||
.map(enabled -> ((LiteralTree) enabled).getValue())
|
||||
.filter(Boolean.FALSE::equals)
|
||||
.map(
|
||||
unused ->
|
||||
SuggestedFix.builder()
|
||||
.addImport("org.junit.jupiter.api.Disabled")
|
||||
.prefixWith(methodTree, "@Disabled\n")
|
||||
.build())
|
||||
.or(() -> Optional.of(SuggestedFix.emptyFix()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.auto.common.MoreStreams.toImmutableList;
|
||||
import static com.sun.source.tree.Tree.Kind.MEMBER_SELECT;
|
||||
import static com.sun.source.tree.Tree.Kind.NEW_ARRAY;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.BlockTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.NewArrayTree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
import tech.picnic.errorprone.util.SourceCode;
|
||||
|
||||
/** A {@link AttributeMigrator} that migrates the {@code expectedExceptions} attribute. */
|
||||
@Immutable
|
||||
final class ExpectedExceptionsAttributeMigrator implements AttributeMigrator {
|
||||
@Override
|
||||
public Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
return Optional.ofNullable(annotation.getAttributes().get("expectedExceptions"))
|
||||
.map(
|
||||
expectedExceptions ->
|
||||
getExpectedException(expectedExceptions, state)
|
||||
.map(
|
||||
expectedException -> {
|
||||
SuggestedFix.Builder fix =
|
||||
SuggestedFix.builder()
|
||||
.replace(
|
||||
methodTree.getBody(),
|
||||
buildWrappedBody(
|
||||
methodTree.getBody(), expectedException, state));
|
||||
ImmutableList<String> removedExceptions =
|
||||
getRemovedExceptions(expectedExceptions, state);
|
||||
if (!removedExceptions.isEmpty()) {
|
||||
fix.prefixWith(
|
||||
methodTree,
|
||||
String.format(
|
||||
"// XXX: Removed handling of `%s` because this migration doesn't support%n// XXX: multiple expected exceptions.%n",
|
||||
String.join(", ", removedExceptions)));
|
||||
}
|
||||
|
||||
return fix.build();
|
||||
})
|
||||
.orElseGet(SuggestedFix::emptyFix));
|
||||
}
|
||||
|
||||
private static Optional<String> getExpectedException(
|
||||
ExpressionTree expectedExceptions, VisitorState state) {
|
||||
if (expectedExceptions.getKind() == NEW_ARRAY) {
|
||||
NewArrayTree arrayTree = (NewArrayTree) expectedExceptions;
|
||||
if (arrayTree.getInitializers().isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(SourceCode.treeToString(arrayTree.getInitializers().get(0), state));
|
||||
} else if (expectedExceptions.getKind() == MEMBER_SELECT) {
|
||||
return Optional.of(SourceCode.treeToString(expectedExceptions, state));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static ImmutableList<String> getRemovedExceptions(
|
||||
ExpressionTree expectedExceptions, VisitorState state) {
|
||||
if (expectedExceptions.getKind() != NEW_ARRAY) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
NewArrayTree arrayTree = (NewArrayTree) expectedExceptions;
|
||||
return arrayTree.getInitializers().subList(1, arrayTree.getInitializers().size()).stream()
|
||||
.map(initializer -> SourceCode.treeToString(initializer, state))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
private static String buildWrappedBody(BlockTree tree, String exception, VisitorState state) {
|
||||
return String.format(
|
||||
"{%norg.junit.jupiter.api.Assertions.assertThrows(%s, () -> %s);%n}",
|
||||
exception, SourceCode.treeToString(tree, state));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.NewArrayTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
import tech.picnic.errorprone.util.SourceCode;
|
||||
|
||||
/** A {@link AttributeMigrator} that migrates the {@code group} attribute. */
|
||||
@Immutable
|
||||
final class GroupsAttributeMigrator implements AttributeMigrator {
|
||||
@Override
|
||||
public Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
ExpressionTree groupsExpression = annotation.getAttributes().get("groups");
|
||||
if (groupsExpression == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
ImmutableList<String> groups = extractGroups(groupsExpression, state);
|
||||
if (!groups.stream().allMatch(GroupsAttributeMigrator::isValidTagName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
SuggestedFix.Builder fix = SuggestedFix.builder().addImport("org.junit.jupiter.api.Tag");
|
||||
groups.forEach(group -> fix.prefixWith(methodTree, String.format("@Tag(\"%s\")%n", group)));
|
||||
|
||||
return Optional.of(fix.build());
|
||||
}
|
||||
|
||||
private static boolean isValidTagName(String tagName) {
|
||||
return !tagName.isEmpty() && tagName.chars().noneMatch(Character::isISOControl);
|
||||
}
|
||||
|
||||
private static ImmutableList<String> extractGroups(ExpressionTree dataValue, VisitorState state) {
|
||||
if (dataValue.getKind() == Tree.Kind.STRING_LITERAL) {
|
||||
return ImmutableList.of(trimTagName(SourceCode.treeToString(dataValue, state)));
|
||||
}
|
||||
|
||||
NewArrayTree groupsTree = (NewArrayTree) dataValue;
|
||||
return groupsTree.getInitializers().stream()
|
||||
.map(initializer -> trimTagName(SourceCode.treeToString(initializer, state)))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
private static String trimTagName(String tagName) {
|
||||
return tagName.replaceAll("(^\")|(\"$)", "").trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
import tech.picnic.errorprone.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link AttributeMigrator} that migrates the {@code org.testng.annotations.Test#priority}
|
||||
* attribute.
|
||||
*/
|
||||
@Immutable
|
||||
final class PriorityAttributeMigrator implements AttributeMigrator {
|
||||
@Override
|
||||
public Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
return Optional.ofNullable(annotation.getAttributes().get("priority"))
|
||||
.map(
|
||||
priority ->
|
||||
SuggestedFix.builder()
|
||||
.addImport("org.junit.jupiter.api.Order")
|
||||
.addImport("org.junit.jupiter.api.TestMethodOrder")
|
||||
.addImport("org.junit.jupiter.api.MethodOrderer")
|
||||
.prefixWith(
|
||||
methodTree,
|
||||
String.format("@Order(%s)%n", SourceCode.treeToString(priority, state)))
|
||||
.prefixWith(
|
||||
metadata.getClassTree(),
|
||||
"@TestMethodOrder(MethodOrderer.OrderAnnotation.class)\n")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Optional;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.SetupTeardownType;
|
||||
|
||||
/**
|
||||
* A helper class that migrates TestNG setup and teardown methods to their JUnit Jupiter equivalent.
|
||||
*/
|
||||
final class SetupTeardownMethodMigrator {
|
||||
private SetupTeardownMethodMigrator() {}
|
||||
|
||||
/**
|
||||
* Create the {@link SuggestedFix} required to migrate a TestNG setup/teardown methods to the
|
||||
* JUnit Jupiter variant.
|
||||
*
|
||||
* @param tree The setup/teardown method tree.
|
||||
* @param type The setup/teardown type.
|
||||
* @param state The visitor state.
|
||||
* @return An {@link Optional} containing the created fix.
|
||||
*/
|
||||
static Optional<SuggestedFix> createFix(
|
||||
MethodTree tree, SetupTeardownType type, VisitorState state) {
|
||||
return getSetupTeardownAnnotationTree(tree, type, state)
|
||||
.map(
|
||||
annotation -> {
|
||||
SuggestedFix.Builder fix =
|
||||
SuggestedFix.builder()
|
||||
.replace(annotation, String.format("@%s", type.getJunitAnnotationClass()));
|
||||
if (type.requiresStaticMethod()
|
||||
&& !tree.getModifiers().getFlags().contains(Modifier.STATIC)) {
|
||||
SuggestedFixes.addModifiers(tree, state, Modifier.STATIC).ifPresent(fix::merge);
|
||||
}
|
||||
|
||||
return fix.build();
|
||||
});
|
||||
}
|
||||
|
||||
private static Optional<? extends AnnotationTree> getSetupTeardownAnnotationTree(
|
||||
MethodTree tree, SetupTeardownType type, VisitorState state) {
|
||||
return ASTHelpers.getAnnotations(tree).stream()
|
||||
.filter(annotation -> type.getAnnotationMatcher().matches(annotation, state))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/** The annotation attributes that are supported by the TestNG to JUnit Jupiter migration. */
|
||||
enum TestAnnotationAttribute {
|
||||
DATA_PROVIDER("dataProvider", new DataProviderAttributeMigrator()),
|
||||
DESCRIPTION("description", new DescriptionAttributeMigrator()),
|
||||
ENABLED("enabled", new EnabledAttributeMigrator()),
|
||||
EXPECTED_EXCEPTIONS("expectedExceptions", new ExpectedExceptionsAttributeMigrator()),
|
||||
GROUPS("groups", new GroupsAttributeMigrator()),
|
||||
PRIORITY("priority", new PriorityAttributeMigrator()),
|
||||
TIMEOUT("timeOut", new TimeOutAttributeMigrator());
|
||||
|
||||
private final String name;
|
||||
private final AttributeMigrator attributeMigrator;
|
||||
|
||||
TestAnnotationAttribute(String name, AttributeMigrator attributeMigrator) {
|
||||
this.name = name;
|
||||
this.attributeMigrator = attributeMigrator;
|
||||
}
|
||||
|
||||
AttributeMigrator getAttributeMigrator() {
|
||||
return attributeMigrator;
|
||||
}
|
||||
|
||||
static Optional<TestAnnotationAttribute> fromString(String attribute) {
|
||||
return stream(values()).filter(v -> v.name.equals(attribute)).findFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.errorprone.BugPattern.LinkType.NONE;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.REFACTORING;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.ErrorProneFlags;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.DataProviderMetadata;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.SetupTeardownType;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that migrates TestNG unit tests to JUnit 5.
|
||||
*
|
||||
* <p>Supported TestNG annotation attributes are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code dataProvider}
|
||||
* <li>{@code description}
|
||||
* <li>{@code isEnabled}
|
||||
* <li>{@code expectedExceptions}
|
||||
* <li>{@code priority}
|
||||
* <li>{@code groups}
|
||||
* </ul>
|
||||
*
|
||||
* This migration will also take care of any setup/teardown methods.
|
||||
*
|
||||
* <p>Note: As the {@code @BeforeAll} and {@code @AfterAll} methods in JUnit are required to be
|
||||
* static, this <em>might</em> introduce breaking changes.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Migrate TestNG tests to their JUnit equivalent",
|
||||
linkType = NONE,
|
||||
tags = REFACTORING,
|
||||
severity = ERROR)
|
||||
public final class TestNGJUnitMigration extends BugChecker implements CompilationUnitTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String CONSERVATIVE_MIGRATION_MODE_FLAG =
|
||||
"TestNGJUnitMigration:ConservativeMode";
|
||||
|
||||
private final boolean conservativeMode;
|
||||
|
||||
/**
|
||||
* Instantiates a new {@link TestNGJUnitMigration} instance. This will default to the aggressive
|
||||
* migration mode.
|
||||
*/
|
||||
public TestNGJUnitMigration() {
|
||||
this(ErrorProneFlags.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new {@link TestNGJUnitMigration} with the specified {@link ErrorProneFlags}.
|
||||
*
|
||||
* @param flags The Error Prone flags used to set the migration mode.
|
||||
*/
|
||||
@Inject
|
||||
TestNGJUnitMigration(ErrorProneFlags flags) {
|
||||
conservativeMode = flags.getBoolean(CONSERVATIVE_MIGRATION_MODE_FLAG).orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
|
||||
TestNGScanner scanner = new TestNGScanner(state);
|
||||
ImmutableMap<ClassTree, TestNgMetadata> classMetaData = scanner.collectMetadataForClasses(tree);
|
||||
|
||||
new TreeScanner<@Nullable Void, TestNgMetadata>() {
|
||||
@Override
|
||||
public @Nullable Void visitClass(ClassTree node, TestNgMetadata testNgMetadata) {
|
||||
TestNgMetadata metadata = classMetaData.get(node);
|
||||
if (metadata == null) {
|
||||
return super.visitClass(node, testNgMetadata);
|
||||
}
|
||||
|
||||
for (DataProviderMetadata dataProviderMetadata : metadata.getDataProvidersInUse()) {
|
||||
DataProviderMigrator.createFix(
|
||||
metadata.getClassTree(), dataProviderMetadata.getMethodTree(), state)
|
||||
.ifPresent(
|
||||
fix ->
|
||||
state.reportMatch(
|
||||
describeMatch(
|
||||
dataProviderMetadata.getMethodTree(),
|
||||
fix.toBuilder().removeStaticImport("org.testng.Assert.*").build())));
|
||||
}
|
||||
|
||||
for (Entry<MethodTree, SetupTeardownType> entry : metadata.getSetupTeardown().entrySet()) {
|
||||
SetupTeardownMethodMigrator.createFix(entry.getKey(), entry.getValue(), state)
|
||||
.ifPresent(fix -> state.reportMatch(describeMatch(entry.getKey(), fix)));
|
||||
}
|
||||
|
||||
super.visitClass(node, metadata);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitMethod(MethodTree tree, TestNgMetadata metadata) {
|
||||
/* Make sure ALL Tests in the class can be migrated. */
|
||||
if (conservativeMode && !canMigrateAllTestsInClass(metadata, state)) {
|
||||
return super.visitMethod(tree, metadata);
|
||||
}
|
||||
|
||||
metadata
|
||||
.getAnnotation(tree)
|
||||
.ifPresent(
|
||||
annotation -> {
|
||||
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
|
||||
buildAttributeFixes(metadata, annotation, tree, state).forEach(fixBuilder::merge);
|
||||
|
||||
fixBuilder.merge(migrateAnnotation(annotation, tree));
|
||||
state.reportMatch(describeMatch(tree, fixBuilder.build()));
|
||||
});
|
||||
return super.visitMethod(tree, metadata);
|
||||
}
|
||||
}.scan(tree, null);
|
||||
|
||||
/* All suggested fixes are already directly reported to the `VisitorState`. */
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
private static ImmutableList<SuggestedFix> buildAttributeFixes(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotationMetadata,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
return annotationMetadata.getAttributes().entrySet().stream()
|
||||
.flatMap(
|
||||
entry ->
|
||||
trySuggestFix(metadata, annotationMetadata, entry.getKey(), methodTree, state)
|
||||
.stream())
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
private static boolean canMigrateTest(
|
||||
MethodTree methodTree,
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotationMetadata,
|
||||
VisitorState state) {
|
||||
ImmutableList<TestAnnotationAttribute> attributes =
|
||||
annotationMetadata.getAttributes().keySet().stream()
|
||||
.map(TestAnnotationAttribute::fromString)
|
||||
.flatMap(Optional::stream)
|
||||
.collect(toImmutableList());
|
||||
return (annotationMetadata.getAttributes().isEmpty() || !attributes.isEmpty())
|
||||
&& attributes.stream()
|
||||
.allMatch(
|
||||
kind ->
|
||||
kind.getAttributeMigrator()
|
||||
.migrate(metadata, annotationMetadata, methodTree, state)
|
||||
.isPresent());
|
||||
}
|
||||
|
||||
private static boolean canMigrateAllTestsInClass(TestNgMetadata metadata, VisitorState state) {
|
||||
return metadata.getMethodAnnotations().entrySet().stream()
|
||||
.allMatch(entry -> canMigrateTest(entry.getKey(), metadata, entry.getValue(), state));
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> trySuggestFix(
|
||||
TestNgMetadata metadata,
|
||||
AnnotationMetadata annotation,
|
||||
String attributeName,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
return TestAnnotationAttribute.fromString(attributeName)
|
||||
.map(TestAnnotationAttribute::getAttributeMigrator)
|
||||
.flatMap(migrator -> migrator.migrate(metadata, annotation, methodTree, state))
|
||||
.or(
|
||||
() ->
|
||||
UnsupportedAttributeMigrator.migrate(annotation, methodTree, attributeName, state));
|
||||
}
|
||||
|
||||
private static SuggestedFix migrateAnnotation(
|
||||
AnnotationMetadata annotationMetadata, MethodTree methodTree) {
|
||||
SuggestedFix.Builder fixBuilder =
|
||||
SuggestedFix.builder().delete(annotationMetadata.getAnnotationTree());
|
||||
if (!annotationMetadata.getAttributes().containsKey("dataProvider")) {
|
||||
fixBuilder.prefixWith(methodTree, "@org.junit.jupiter.api.Test\n ");
|
||||
}
|
||||
|
||||
return fixBuilder.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.TestNgMatchers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
|
||||
/**
|
||||
* A collection of TestNG-specific helper methods and {@link Matcher}s.
|
||||
*
|
||||
* <p>These constants and methods are additions to the ones found in {@link TestNgMatchers}.
|
||||
*/
|
||||
final class TestNGMatchers {
|
||||
/**
|
||||
* Matches the TestNG {@code Test} annotation specifically. As {@link
|
||||
* TestNgMatchers#hasTestNgAnnotation(ClassTree)} also other TestNG annotations.
|
||||
*/
|
||||
public static final Matcher<AnnotationTree> TESTNG_TEST_ANNOTATION =
|
||||
isType("org.testng.annotations.Test");
|
||||
|
||||
/** Matches the TestNG {@code DataProvider} annotation specifically. */
|
||||
public static final Matcher<MethodTree> TESTNG_VALUE_FACTORY_METHOD =
|
||||
hasAnnotation("org.testng.annotations.DataProvider");
|
||||
|
||||
private TestNGMatchers() {}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
|
||||
import static com.google.errorprone.matchers.Matchers.hasModifier;
|
||||
import static com.google.errorprone.matchers.Matchers.not;
|
||||
import static tech.picnic.errorprone.testngjunit.TestNGMatchers.TESTNG_TEST_ANNOTATION;
|
||||
import static tech.picnic.errorprone.testngjunit.TestNGMatchers.TESTNG_VALUE_FACTORY_METHOD;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AssignmentTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import java.util.Optional;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.DataProviderMetadata;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.SetupTeardownType;
|
||||
|
||||
/**
|
||||
* A {@link TreeScanner} which will scan a {@link com.sun.source.tree.CompilationUnitTree} and
|
||||
* collect data required for the migration from each class in the compilation unit.
|
||||
*
|
||||
* <p>This data can be retrieved using {@link #collectMetadataForClasses(CompilationUnitTree)}.
|
||||
*/
|
||||
final class TestNGScanner extends TreeScanner<@Nullable Void, TestNgMetadata.Builder> {
|
||||
private static final Matcher<MethodTree> TESTNG_TEST_METHOD =
|
||||
anyOf(
|
||||
hasAnnotation("org.testng.annotations.Test"),
|
||||
allOf(hasModifier(Modifier.PUBLIC), not(hasModifier(Modifier.STATIC))));
|
||||
|
||||
private final ImmutableMap.Builder<ClassTree, TestNgMetadata> metadataBuilder =
|
||||
ImmutableMap.builder();
|
||||
private final VisitorState state;
|
||||
|
||||
TestNGScanner(VisitorState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitClass(ClassTree tree, TestNgMetadata.Builder unused) {
|
||||
TestNgMetadata.Builder builder = TestNgMetadata.builder();
|
||||
builder.setClassTree(tree);
|
||||
getTestNgAnnotation(tree, state).ifPresent(builder::setClassLevelAnnotationMetadata);
|
||||
super.visitClass(tree, builder);
|
||||
metadataBuilder.put(tree, builder.build());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitMethod(MethodTree tree, TestNgMetadata.Builder builder) {
|
||||
if (ASTHelpers.isGeneratedConstructor(tree)) {
|
||||
return super.visitMethod(tree, builder);
|
||||
}
|
||||
|
||||
if (TESTNG_VALUE_FACTORY_METHOD.matches(tree, state) && DataProviderMigrator.canFix(tree)) {
|
||||
builder
|
||||
.dataProviderMetadataBuilder()
|
||||
.put(tree.getName().toString(), DataProviderMetadata.create(tree));
|
||||
return super.visitMethod(tree, builder);
|
||||
}
|
||||
|
||||
Optional<SetupTeardownType> setupTeardownType = SetupTeardownType.matchType(tree, state);
|
||||
if (setupTeardownType.isPresent()) {
|
||||
builder.setupTeardownBuilder().put(tree, setupTeardownType.orElseThrow());
|
||||
return super.visitMethod(tree, builder);
|
||||
}
|
||||
|
||||
if (TESTNG_TEST_METHOD.matches(tree, state)) {
|
||||
getTestNgAnnotation(tree, state)
|
||||
.or(builder::getClassLevelAnnotationMetadata)
|
||||
.ifPresent(annotation -> builder.methodAnnotationsBuilder().put(tree, annotation));
|
||||
}
|
||||
|
||||
return super.visitMethod(tree, builder);
|
||||
}
|
||||
|
||||
public ImmutableMap<ClassTree, TestNgMetadata> collectMetadataForClasses(
|
||||
CompilationUnitTree tree) {
|
||||
scan(tree, null);
|
||||
return metadataBuilder.build();
|
||||
}
|
||||
|
||||
@CanIgnoreReturnValue
|
||||
private static Optional<AnnotationMetadata> getTestNgAnnotation(Tree tree, VisitorState state) {
|
||||
return ASTHelpers.getAnnotations(tree).stream()
|
||||
.filter(annotation -> TESTNG_TEST_ANNOTATION.matches(annotation, state))
|
||||
.findFirst()
|
||||
.map(
|
||||
annotationTree ->
|
||||
AnnotationMetadata.create(
|
||||
annotationTree,
|
||||
annotationTree.getArguments().stream()
|
||||
.filter(AssignmentTree.class::isInstance)
|
||||
.map(AssignmentTree.class::cast)
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
assignment ->
|
||||
((IdentifierTree) assignment.getVariable())
|
||||
.getName()
|
||||
.toString(),
|
||||
AssignmentTree::getExpression))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* POJO containing data collected using {@link TestNGScanner} for use in {@link
|
||||
* TestNGJUnitMigration}.
|
||||
*/
|
||||
@AutoValue
|
||||
abstract class TestNgMetadata {
|
||||
abstract ClassTree getClassTree();
|
||||
|
||||
abstract Optional<AnnotationMetadata> getClassLevelAnnotationMetadata();
|
||||
|
||||
abstract ImmutableMap<MethodTree, AnnotationMetadata> getMethodAnnotations();
|
||||
|
||||
abstract ImmutableMap<MethodTree, SetupTeardownType> getSetupTeardown();
|
||||
|
||||
/**
|
||||
* Retrieve the tests that can be migrated.
|
||||
*
|
||||
* @return An {@link ImmutableMap} with mapping {@code DataProvider}'s name to its respective
|
||||
* metadata.
|
||||
*/
|
||||
public abstract ImmutableMap<String, DataProviderMetadata> getDataProviderMetadata();
|
||||
|
||||
final ImmutableList<DataProviderMetadata> getDataProvidersInUse() {
|
||||
return getDataProviderMetadata().entrySet().stream()
|
||||
.filter(
|
||||
entry ->
|
||||
getAnnotations().stream()
|
||||
.anyMatch(
|
||||
annotation -> {
|
||||
ExpressionTree dataProviderNameExpression =
|
||||
annotation.getAttributes().get("dataProvider");
|
||||
if (dataProviderNameExpression == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ASTHelpers.constValue(dataProviderNameExpression, String.class)
|
||||
.equals(entry.getKey());
|
||||
}))
|
||||
.map(Map.Entry::getValue)
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
final ImmutableSet<AnnotationMetadata> getAnnotations() {
|
||||
return ImmutableSet.copyOf(getMethodAnnotations().values());
|
||||
}
|
||||
|
||||
final Optional<AnnotationMetadata> getAnnotation(MethodTree methodTree) {
|
||||
return Optional.ofNullable(getMethodAnnotations().get(methodTree));
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_TestNgMetadata.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder {
|
||||
abstract ImmutableMap.Builder<MethodTree, AnnotationMetadata> methodAnnotationsBuilder();
|
||||
|
||||
abstract ImmutableMap.Builder<MethodTree, SetupTeardownType> setupTeardownBuilder();
|
||||
|
||||
abstract ImmutableMap.Builder<String, DataProviderMetadata> dataProviderMetadataBuilder();
|
||||
|
||||
abstract Builder setClassTree(ClassTree value);
|
||||
|
||||
abstract Optional<AnnotationMetadata> getClassLevelAnnotationMetadata();
|
||||
|
||||
abstract Builder setClassLevelAnnotationMetadata(AnnotationMetadata value);
|
||||
|
||||
abstract Builder setMethodAnnotations(ImmutableMap<MethodTree, AnnotationMetadata> value);
|
||||
|
||||
abstract Builder setSetupTeardown(ImmutableMap<MethodTree, SetupTeardownType> value);
|
||||
|
||||
abstract Builder setDataProviderMetadata(ImmutableMap<String, DataProviderMetadata> value);
|
||||
|
||||
abstract TestNgMetadata build();
|
||||
}
|
||||
|
||||
/**
|
||||
* POJO containing data for a specific {@code Test} annotation for use in {@link
|
||||
* TestNGJUnitMigration}.
|
||||
*/
|
||||
@AutoValue
|
||||
public abstract static class AnnotationMetadata {
|
||||
/**
|
||||
* Get the {@link AnnotationTree} of this metadata instance.
|
||||
*
|
||||
* @return the annotation tree this metadata contains information on.
|
||||
*/
|
||||
public abstract AnnotationTree getAnnotationTree();
|
||||
|
||||
/**
|
||||
* A mapping for all attributes in the annotation to their value.
|
||||
*
|
||||
* @return an {@link ImmutableMap} mapping each annotation attribute to their respective value.
|
||||
*/
|
||||
public abstract ImmutableMap<String, ExpressionTree> getAttributes();
|
||||
|
||||
/**
|
||||
* Instantiate a new {@link AnnotationMetadata}.
|
||||
*
|
||||
* @param annotationTree The annotation tree.
|
||||
* @param attributes The attributes in that annotation tree.
|
||||
* @return The new {@link AnnotationMetadata} instance.
|
||||
*/
|
||||
public static AnnotationMetadata create(
|
||||
AnnotationTree annotationTree, ImmutableMap<String, ExpressionTree> attributes) {
|
||||
return new AutoValue_TestNgMetadata_AnnotationMetadata(annotationTree, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ImmutableEnumChecker" /* Matcher instances are final. */)
|
||||
public enum SetupTeardownType {
|
||||
// XXX: Consider using `@BeforeAll` to more accurately preserve behavior. However, note that it
|
||||
// requires a static method and therefore may introduce breaking changes.
|
||||
BEFORE_TEST(
|
||||
"org.testng.annotations.BeforeTest",
|
||||
"org.junit.jupiter.api.BeforeEach",
|
||||
/* requiresStaticMethod= */ false),
|
||||
BEFORE_CLASS(
|
||||
"org.testng.annotations.BeforeClass",
|
||||
"org.junit.jupiter.api.BeforeAll",
|
||||
/* requiresStaticMethod= */ true),
|
||||
BEFORE_METHOD(
|
||||
"org.testng.annotations.BeforeMethod",
|
||||
"org.junit.jupiter.api.BeforeEach",
|
||||
/* requiresStaticMethod= */ false),
|
||||
// XXX: Consider using `@AfterAll` to more accurately preserve behavior. However, note that it
|
||||
// requires a static method and therefore may introduce breaking changes.
|
||||
AFTER_TEST(
|
||||
"org.testng.annotations.AfterTest",
|
||||
"org.junit.jupiter.api.AfterEach",
|
||||
/* requiresStaticMethod= */ false),
|
||||
AFTER_CLASS(
|
||||
"org.testng.annotations.AfterClass",
|
||||
"org.junit.jupiter.api.AfterAll",
|
||||
/* requiresStaticMethod= */ true),
|
||||
AFTER_METHOD(
|
||||
"org.testng.annotations.AfterMethod",
|
||||
"org.junit.jupiter.api.AfterEach",
|
||||
/* requiresStaticMethod= */ false);
|
||||
|
||||
private final Matcher<AnnotationTree> annotationMatcher;
|
||||
private final Matcher<MethodTree> methodTreeMatcher;
|
||||
private final String junitAnnotationClass;
|
||||
private final boolean requiresStaticMethod;
|
||||
|
||||
SetupTeardownType(
|
||||
String testNgAnnotationClass, String junitAnnotationClass, boolean requiresStaticMethod) {
|
||||
annotationMatcher = isType(testNgAnnotationClass);
|
||||
methodTreeMatcher = hasAnnotation(testNgAnnotationClass);
|
||||
this.junitAnnotationClass = junitAnnotationClass;
|
||||
this.requiresStaticMethod = requiresStaticMethod;
|
||||
}
|
||||
|
||||
static Optional<SetupTeardownType> matchType(MethodTree methodTree, VisitorState state) {
|
||||
return Arrays.stream(values())
|
||||
.filter(v -> v.methodTreeMatcher.matches(methodTree, state))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
Matcher<AnnotationTree> getAnnotationMatcher() {
|
||||
return annotationMatcher;
|
||||
}
|
||||
|
||||
String getJunitAnnotationClass() {
|
||||
return junitAnnotationClass;
|
||||
}
|
||||
|
||||
// XXX: Improve method name.
|
||||
boolean requiresStaticMethod() {
|
||||
return requiresStaticMethod;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains data for a {@code DataProvider} annotation for use in {@link TestNGJUnitMigration}.
|
||||
*/
|
||||
@AutoValue
|
||||
public abstract static class DataProviderMetadata {
|
||||
abstract MethodTree getMethodTree();
|
||||
|
||||
abstract String getName();
|
||||
|
||||
/**
|
||||
* Instantiate a new {@link DataProviderMetadata} instance.
|
||||
*
|
||||
* @param methodTree The value factory method tree.
|
||||
* @return A new {@link DataProviderMetadata} instance.
|
||||
*/
|
||||
public static DataProviderMetadata create(MethodTree methodTree) {
|
||||
return new AutoValue_TestNgMetadata_DataProviderMetadata(
|
||||
methodTree, methodTree.getName().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import tech.picnic.errorprone.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link AttributeMigrator} that migrates the {@code org.testng.annotations.Test#timeOut}
|
||||
* attribute. The TestNG {@code org.testng.annotations.Test#timeOut} attribute is always in
|
||||
* milliseconds, the JUnit variant {@code @Timeout} takes a value in seconds by default, hence we
|
||||
* add the {@link java.util.concurrent.TimeUnit#MILLISECONDS} attribute.
|
||||
*/
|
||||
@Immutable
|
||||
final class TimeOutAttributeMigrator implements AttributeMigrator {
|
||||
@Override
|
||||
public Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata metadata,
|
||||
TestNgMetadata.AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
VisitorState state) {
|
||||
return Optional.ofNullable(annotation.getAttributes().get("timeOut"))
|
||||
.map(
|
||||
timeOut ->
|
||||
SuggestedFix.builder()
|
||||
.addImport("org.junit.jupiter.api.Timeout")
|
||||
.addStaticImport(TimeUnit.class.getCanonicalName() + ".MILLISECONDS")
|
||||
.prefixWith(
|
||||
methodTree,
|
||||
String.format(
|
||||
"@Timeout(value = %s, unit = MILLISECONDS)%n",
|
||||
SourceCode.treeToString(timeOut, state)))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link AttributeMigrator} that leaves a comment for attributes that aren't supported in the
|
||||
* migration.
|
||||
*/
|
||||
@Immutable
|
||||
final class UnsupportedAttributeMigrator {
|
||||
private UnsupportedAttributeMigrator() {}
|
||||
|
||||
static Optional<SuggestedFix> migrate(
|
||||
TestNgMetadata.AnnotationMetadata annotation,
|
||||
MethodTree methodTree,
|
||||
String attributeName,
|
||||
VisitorState state) {
|
||||
return Optional.ofNullable(annotation.getAttributes().get(attributeName))
|
||||
.map(
|
||||
value ->
|
||||
SuggestedFix.prefixWith(
|
||||
methodTree,
|
||||
String.format(
|
||||
"// XXX: Attribute `%s` is not supported, value: `%s`%n",
|
||||
attributeName, SourceCode.treeToString(value, state))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/** TestNG to JUnit migration using Error-Prone. */
|
||||
@com.google.errorprone.annotations.CheckReturnValue
|
||||
@org.jspecify.annotations.NullMarked
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
@@ -0,0 +1,127 @@
|
||||
package tech.picnic.errorprone.testngjunit.refasterrules;
|
||||
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.testng.Assert;
|
||||
|
||||
/** Refaster rules to replace TestNG assertions with JUnit equivalents. */
|
||||
@SuppressWarnings("StaticImport")
|
||||
final class TestNgAssertionsToJUnitRules {
|
||||
private TestNgAssertionsToJUnitRules() {}
|
||||
|
||||
@SuppressWarnings("AssertEqual")
|
||||
static final class AssertEquals {
|
||||
@BeforeTemplate
|
||||
void before(Object expected, Object actual) {
|
||||
Assert.assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object expected, Object actual) {
|
||||
Assertions.assertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("AssertEqualWithMessage")
|
||||
static final class AssertEqualsMessage {
|
||||
@BeforeTemplate
|
||||
void before(Object expected, Object actual, String message) {
|
||||
Assert.assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object expected, Object actual, String message) {
|
||||
Assertions.assertEquals(expected, actual, message);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("AssertUnequal")
|
||||
static final class AssertNotEquals {
|
||||
@BeforeTemplate
|
||||
void before(Object expected, Object actual) {
|
||||
Assert.assertNotEquals(actual, expected);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object expected, Object actual) {
|
||||
Assertions.assertNotEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("AssertUnequalWithMessage")
|
||||
static final class AssertNotEqualsMessage {
|
||||
@BeforeTemplate
|
||||
void before(Object expected, Object actual, String message) {
|
||||
Assert.assertNotEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object expected, Object actual, String message) {
|
||||
Assertions.assertNotEquals(expected, actual, message);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"AssertFalse", "AssertThatIsFalse"})
|
||||
static final class AssertFalseCondition {
|
||||
@BeforeTemplate
|
||||
void before(boolean condition) {
|
||||
Assert.assertFalse(condition);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean condition) {
|
||||
Assertions.assertFalse(condition);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"AssertFalseWithMessage", "AssertThatWithFailMessageStringIsFalse"})
|
||||
static final class AssertFalseConditionMessage {
|
||||
@BeforeTemplate
|
||||
void before(boolean condition, String message) {
|
||||
Assert.assertFalse(condition, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean condition, String message) {
|
||||
Assertions.assertFalse(condition, message);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"AssertThatIsTrue", "AssertTrue"})
|
||||
static final class AssertTrueCondition {
|
||||
@BeforeTemplate
|
||||
void before(boolean condition) {
|
||||
Assert.assertTrue(condition);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean condition) {
|
||||
Assertions.assertTrue(condition);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"AssertThatWithFailMessageStringIsTrue", "AssertTrueWithMessage"})
|
||||
static final class AssertTrueConditionMessage {
|
||||
@BeforeTemplate
|
||||
void before(boolean condition, String message) {
|
||||
Assert.assertTrue(condition, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean condition, String message) {
|
||||
Assertions.assertTrue(condition, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/** Picnic Refaster rules. */
|
||||
@com.google.errorprone.annotations.CheckReturnValue
|
||||
@org.jspecify.annotations.NullMarked
|
||||
package tech.picnic.errorprone.testngjunit.refasterrules;
|
||||
@@ -0,0 +1,27 @@
|
||||
package tech.picnic.errorprone.util;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.sun.source.tree.Tree;
|
||||
|
||||
/**
|
||||
* A collection of Error Prone utility methods for dealing with the source code representation of
|
||||
* AST nodes.
|
||||
*/
|
||||
// XXX: This is a duplicate of `error-prone-contrib`s `SourceCode`, improve this.
|
||||
public final class SourceCode {
|
||||
private SourceCode() {}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the given {@link Tree}, preferring the original source code
|
||||
* (if available) over its prettified representation.
|
||||
*
|
||||
* @param tree The AST node of interest.
|
||||
* @param state A {@link VisitorState} describing the context in which the given {@link Tree} is
|
||||
* found.
|
||||
* @return A non-{@code null} string.
|
||||
*/
|
||||
public static String treeToString(Tree tree, VisitorState state) {
|
||||
String src = state.getSourceForNode(tree);
|
||||
return src != null ? src : tree.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class TestNGJUnitMigrationTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(TestNGJUnitMigration.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.stream.Stream;",
|
||||
"import org.testng.annotations.DataProvider;",
|
||||
"import org.testng.annotations.Test;",
|
||||
"",
|
||||
"@Test",
|
||||
"public class A {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void classLevelAnnotation() {}",
|
||||
"",
|
||||
" public static void staticNotATest() {}",
|
||||
"",
|
||||
" private void notATest() {}",
|
||||
"",
|
||||
" @Test(description = \"bar\")",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void methodAnnotation() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" public static class B {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void nestedClass() {}",
|
||||
" }",
|
||||
"",
|
||||
" @Test(dataProvider = \"\")",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void dataProviderEmptyString() {}",
|
||||
"",
|
||||
" @Test(dataProvider = \"dataProviderTestCases\")",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void dataProvider(int foo) {}",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private static Object[][] dataProviderTestCases() {",
|
||||
" return new Object[][] {{1}, {2}};",
|
||||
" }",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" private static Object[][] unusedDataProvider() {",
|
||||
" return new Object[][] {{1}, {2}};",
|
||||
" }",
|
||||
"",
|
||||
" @Test(dataProvider = \"notMigratableDataProviderTestCases\")",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void notMigratableDataProvider(int foo) {}",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" private static Object[][] notMigratableDataProviderTestCases() {",
|
||||
" return Stream.of(1, 2, 3).map(i -> new Object[] {i}).toArray(Object[][]::new);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void identificationConservativeMode() {
|
||||
CompilationTestHelper.newInstance(TestNGJUnitMigration.class, getClass())
|
||||
.setArgs("-XepOpt:TestNGJUnitMigration:ConservativeMode=true")
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.stream.Stream;",
|
||||
"import org.testng.annotations.DataProvider;",
|
||||
"import org.testng.annotations.Test;",
|
||||
"",
|
||||
"@Test",
|
||||
"public class A {",
|
||||
" public void classLevelAnnotation() {}",
|
||||
"",
|
||||
" @Test(description = \"bar\")",
|
||||
" public void methodAnnotation() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" public static class B {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void nestedClass() {}",
|
||||
" }",
|
||||
"",
|
||||
" @Test(dataProvider = \"notMigratableDataProviderTestCases\")",
|
||||
" public void notMigratableDataProvider(int foo) {}",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" private static Object[][] notMigratableDataProviderTestCases() {",
|
||||
" return Stream.of(1, 2, 3).map(i -> new Object[] {i}).toArray(Object[][]::new);",
|
||||
" }",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"B.java",
|
||||
"import org.testng.annotations.Test;",
|
||||
"",
|
||||
"@Test",
|
||||
"public class B {",
|
||||
" public void classLevelAnnotation() {}",
|
||||
"",
|
||||
" @Test(description = \"bar\")",
|
||||
" public void methodAnnotation() {}",
|
||||
"",
|
||||
" @Test(testName = \"unsupportedAttribute\")",
|
||||
" public void unsupportedAttribute() {}",
|
||||
"",
|
||||
" @Test(testName = \"unsupportedAttribute\", suiteName = \"unsupportedAttribute\")",
|
||||
" public void multipleUnsupportedAttributes() {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"C.java",
|
||||
"import org.testng.annotations.Test;",
|
||||
"",
|
||||
"@Test",
|
||||
"public class C {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void classLevelAnnotation() {}",
|
||||
"",
|
||||
" @Test(description = \"bar\")",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void methodAnnotation() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestNGJUnitMigration.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static org.testng.Assert.*;",
|
||||
"",
|
||||
"import org.testng.annotations.AfterClass;",
|
||||
"import org.testng.annotations.AfterMethod;",
|
||||
"import org.testng.annotations.AfterTest;",
|
||||
"import org.testng.annotations.BeforeClass;",
|
||||
"import org.testng.annotations.BeforeMethod;",
|
||||
"import org.testng.annotations.BeforeTest;",
|
||||
"import org.testng.annotations.DataProvider;",
|
||||
"import org.testng.annotations.Test;",
|
||||
"",
|
||||
"@Test",
|
||||
"class A {",
|
||||
" @BeforeTest",
|
||||
" private void setupTest() {}",
|
||||
"",
|
||||
" @BeforeClass",
|
||||
" private void setupClass() {}",
|
||||
"",
|
||||
" @BeforeMethod",
|
||||
" private void setup() {}",
|
||||
"",
|
||||
" @AfterTest",
|
||||
" private void teardownTest() {}",
|
||||
"",
|
||||
" @AfterClass",
|
||||
" private void teardownClass() {}",
|
||||
"",
|
||||
" @AfterMethod",
|
||||
" private void teardown() {}",
|
||||
"",
|
||||
" public void classLevelAnnotation() {}",
|
||||
"",
|
||||
" @Test(priority = 1, timeOut = 500, description = \"unit\")",
|
||||
" public void priorityTimeOutAndDescription() {}",
|
||||
"",
|
||||
" @Test(testName = \"unsupportedAttribute\")",
|
||||
" public void unsupportedAttribute() {}",
|
||||
"",
|
||||
" @Test(testName = \"unsupportedAttribute\", suiteName = \"unsupportedAttribute\")",
|
||||
" public void multipleUnsupportedAttributes() {}",
|
||||
"",
|
||||
" @Test(dataProvider = \"dataProviderTestCases\")",
|
||||
" public void dataProvider(String string, int number) {}",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" private Object[][] dataProviderTestCases() {",
|
||||
" int[] values = new int[] {1, 2, 3};",
|
||||
" return new Object[][] {",
|
||||
" {\"1\", values[0], getClass()},",
|
||||
" {\"2\", values[1], this.getClass()},",
|
||||
" {\"3\", /* inline comment */ values[2], getClass()}",
|
||||
" };",
|
||||
" }",
|
||||
"",
|
||||
" @Test(dataProvider = \"dataProviderFieldReturnValueTestCases\")",
|
||||
" public void dataProviderFieldReturnValue(int foo, int bar) {}",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" private Object[][] dataProviderFieldReturnValueTestCases() {",
|
||||
" Object[][] foo = new Object[][] {{1, 2}};",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" @Test(dataProvider = \"dataProviderThrowsTestCases\")",
|
||||
" public void dataProviderThrows(String foo, int bar) {}",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" private Object[][] dataProviderThrowsTestCases() throws RuntimeException {",
|
||||
" return new Object[][] {",
|
||||
" {\"1\", 0},",
|
||||
" };",
|
||||
" }",
|
||||
"",
|
||||
" @Test(expectedExceptions = RuntimeException.class)",
|
||||
" public void singleExpectedException() {",
|
||||
" throw new RuntimeException(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" @Test(expectedExceptions = {RuntimeException.class})",
|
||||
" public void singleExpectedExceptionArray() {",
|
||||
" throw new RuntimeException(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" @Test(expectedExceptions = {})",
|
||||
" public void emptyExpectedExceptions() {}",
|
||||
"",
|
||||
" @Test(expectedExceptions = {IllegalArgumentException.class, RuntimeException.class})",
|
||||
" public void multipleExpectedExceptions() {",
|
||||
" throw new RuntimeException(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" @Test(enabled = false)",
|
||||
" public void disabledTest() {}",
|
||||
"",
|
||||
" @Test(enabled = true)",
|
||||
" public void enabledTest() {}",
|
||||
"",
|
||||
" @Test(groups = \"foo\")",
|
||||
" public void groupsTest() {}",
|
||||
"",
|
||||
" @Test(groups = {\"foo\", \"bar\"})",
|
||||
" public void multipleGroupsTest() {}",
|
||||
"",
|
||||
" @Test(groups = {})",
|
||||
" public void emptyGroupsTest() {}",
|
||||
"",
|
||||
" @Test(groups = \"\")",
|
||||
" public void invalidGroupsNameTest() {}",
|
||||
"",
|
||||
" @Test(groups = \" whitespace \")",
|
||||
" public void whitespaceGroupsNameTest() {}",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static java.util.concurrent.TimeUnit.MILLISECONDS;",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"",
|
||||
"import java.util.stream.Stream;",
|
||||
"import org.junit.jupiter.api.Disabled;",
|
||||
"import org.junit.jupiter.api.DisplayName;",
|
||||
"import org.junit.jupiter.api.MethodOrderer;",
|
||||
"import org.junit.jupiter.api.Order;",
|
||||
"import org.junit.jupiter.api.Tag;",
|
||||
"import org.junit.jupiter.api.TestMethodOrder;",
|
||||
"import org.junit.jupiter.api.Timeout;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.Arguments;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"import org.testng.annotations.AfterClass;",
|
||||
"import org.testng.annotations.AfterMethod;",
|
||||
"import org.testng.annotations.AfterTest;",
|
||||
"import org.testng.annotations.BeforeClass;",
|
||||
"import org.testng.annotations.BeforeMethod;",
|
||||
"import org.testng.annotations.BeforeTest;",
|
||||
"import org.testng.annotations.DataProvider;",
|
||||
"import org.testng.annotations.Test;",
|
||||
"",
|
||||
"@TestMethodOrder(MethodOrderer.OrderAnnotation.class)",
|
||||
"class A {",
|
||||
" @org.junit.jupiter.api.BeforeEach",
|
||||
" private void setupTest() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.api.BeforeAll",
|
||||
" private static void setupClass() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.api.BeforeEach",
|
||||
" private void setup() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.api.AfterEach",
|
||||
" private void teardownTest() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.api.AfterAll",
|
||||
" private static void teardownClass() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.api.AfterEach",
|
||||
" private void teardown() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void classLevelAnnotation() {}",
|
||||
"",
|
||||
" @Order(1)",
|
||||
" @Timeout(value = 500, unit = MILLISECONDS)",
|
||||
" @DisplayName(\"unit\")",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void priorityTimeOutAndDescription() {}",
|
||||
"",
|
||||
" // XXX: Attribute `testName` is not supported, value: `\"unsupportedAttribute\"`",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void unsupportedAttribute() {}",
|
||||
"",
|
||||
" // XXX: Attribute `testName` is not supported, value: `\"unsupportedAttribute\"`",
|
||||
" // XXX: Attribute `suiteName` is not supported, value: `\"unsupportedAttribute\"`",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void multipleUnsupportedAttributes() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"dataProviderTestCases\")",
|
||||
" public void dataProvider(String string, int number) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> dataProviderTestCases() {",
|
||||
" int[] values = new int[] {1, 2, 3};",
|
||||
" return Stream.of(",
|
||||
" arguments(\"1\", values[0], A.class),",
|
||||
" arguments(\"2\", values[1], A.class),",
|
||||
" arguments(\"3\", /* inline comment */ values[2], A.class));",
|
||||
" }",
|
||||
"",
|
||||
" // XXX: Attribute `dataProvider` is not supported, value:",
|
||||
" // `\"dataProviderFieldReturnValueTestCases\"`",
|
||||
"",
|
||||
" public void dataProviderFieldReturnValue(int foo, int bar) {}",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" private Object[][] dataProviderFieldReturnValueTestCases() {",
|
||||
" Object[][] foo = new Object[][] {{1, 2}};",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"dataProviderThrowsTestCases\")",
|
||||
" public void dataProviderThrows(String foo, int bar) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> dataProviderThrowsTestCases() throws RuntimeException {",
|
||||
" return Stream.of(arguments(\"1\", 0));",
|
||||
" }",
|
||||
"",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void singleExpectedException() {",
|
||||
" org.junit.jupiter.api.Assertions.assertThrows(",
|
||||
" RuntimeException.class,",
|
||||
" () -> {",
|
||||
" throw new RuntimeException(\"foo\");",
|
||||
" });",
|
||||
" }",
|
||||
"",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void singleExpectedExceptionArray() {",
|
||||
" org.junit.jupiter.api.Assertions.assertThrows(",
|
||||
" RuntimeException.class,",
|
||||
" () -> {",
|
||||
" throw new RuntimeException(\"foo\");",
|
||||
" });",
|
||||
" }",
|
||||
"",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void emptyExpectedExceptions() {}",
|
||||
"",
|
||||
" // XXX: Removed handling of `RuntimeException.class` because this migration doesn't support",
|
||||
" // XXX: multiple expected exceptions.",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void multipleExpectedExceptions() {",
|
||||
" org.junit.jupiter.api.Assertions.assertThrows(",
|
||||
" IllegalArgumentException.class,",
|
||||
" () -> {",
|
||||
" throw new RuntimeException(\"foo\");",
|
||||
" });",
|
||||
" }",
|
||||
"",
|
||||
" @Disabled",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void disabledTest() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void enabledTest() {}",
|
||||
"",
|
||||
" @Tag(\"foo\")",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void groupsTest() {}",
|
||||
"",
|
||||
" @Tag(\"foo\")",
|
||||
" @Tag(\"bar\")",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void multipleGroupsTest() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void emptyGroupsTest() {}",
|
||||
"",
|
||||
" // XXX: Attribute `groups` is not supported, value: `\"\"`",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void invalidGroupsNameTest() {}",
|
||||
"",
|
||||
" @Tag(\"whitespace\")",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" public void whitespaceGroupsNameTest() {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class TestNGMatchersTest {
|
||||
@Test
|
||||
void matches() {
|
||||
CompilationTestHelper.newInstance(TestNGMatchersTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.testng.annotations.DataProvider;",
|
||||
"import org.testng.annotations.Test;",
|
||||
"",
|
||||
"// BUG: Diagnostic contains: TestNG annotation",
|
||||
"@Test",
|
||||
"class A {",
|
||||
" // BUG: Diagnostic contains: TestNG annotation",
|
||||
" @Test",
|
||||
" void basic() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: TestNG annotation",
|
||||
" @Test(dataProvider = \"dataProviderTestCases\")",
|
||||
" void withDataProvider() {}",
|
||||
"",
|
||||
" @DataProvider",
|
||||
" // BUG: Diagnostic contains: TestNG value factory method",
|
||||
" private static Object[][] dataProviderTestCases() {",
|
||||
" return new Object[][] {};",
|
||||
" }",
|
||||
"",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" void junitTest() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} used to report TestNG annotations as errors for testing purposes. */
|
||||
@BugPattern(summary = "Interacts with `TestNGMatchers` for testing purposes", severity = ERROR)
|
||||
public static final class TestNGMatchersTestChecker extends BugChecker
|
||||
implements MethodTreeMatcher, AnnotationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Description matchAnnotation(AnnotationTree annotationTree, VisitorState visitorState) {
|
||||
return TestNGMatchers.TESTNG_TEST_ANNOTATION.matches(annotationTree, visitorState)
|
||||
? buildDescription(annotationTree).setMessage("TestNG annotation").build()
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree methodTree, VisitorState visitorState) {
|
||||
return TestNGMatchers.TESTNG_VALUE_FACTORY_METHOD.matches(methodTree, visitorState)
|
||||
? buildDescription(methodTree).setMessage("TestNG value factory method").build()
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
package tech.picnic.errorprone.testngjunit;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static java.util.function.Predicate.isEqual;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.lang.model.element.Name;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tech.picnic.errorprone.testngjunit.TestNgMetadata.AnnotationMetadata;
|
||||
|
||||
final class TestNGScannerTest {
|
||||
@Test
|
||||
void classLevelAndMethodLevel() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.testng.annotations.Test;",
|
||||
"",
|
||||
"// BUG: Diagnostic contains: Class: A attributes: {}",
|
||||
"@Test",
|
||||
"class A {",
|
||||
"",
|
||||
" public void inferClassLevelAnnotation() {}",
|
||||
"",
|
||||
" void packagePrivateNotATest() {}",
|
||||
"",
|
||||
" private void privateNotATest() {}",
|
||||
"",
|
||||
" static void notATest() {}",
|
||||
"",
|
||||
" public static void staticNotATest() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: Class: A attributes: {}",
|
||||
" @Test",
|
||||
" public void localAnnotation() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: Class: A attributes: {description=\"foo\"}",
|
||||
" @Test(description = \"foo\")",
|
||||
" public void singleArgument() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: Class: A attributes: {priority=1, description=\"foo\"}",
|
||||
" @Test(priority = 1, description = \"foo\")",
|
||||
" public void multipleArguments() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: Class: A attributes: {dataProvider=\"dataProviderTestCases\"}",
|
||||
" @Test(dataProvider = \"dataProviderTestCases\")",
|
||||
" public void dataProvider() {}",
|
||||
"",
|
||||
" @SuppressWarnings(\"onlyMatchTestNGAnnotations\")",
|
||||
" // BUG: Diagnostic contains: Class: B attributes: {description=\"nested\"}",
|
||||
" @Test(description = \"nested\")",
|
||||
" class B {",
|
||||
" public void nestedTest() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: Class: B attributes: {priority=1}",
|
||||
" @Test(priority = 1)",
|
||||
" public void nestedTestWithArguments() {}",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
// XXX: Here we need to add some edge cases for the DataProvider probably?
|
||||
@Test
|
||||
void dataProvider() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.stream.Stream;",
|
||||
"import org.testng.annotations.DataProvider;",
|
||||
"",
|
||||
"class A {",
|
||||
" @DataProvider",
|
||||
" // BUG: Diagnostic contains: Class: A DataProvider: dataProviderTestCases",
|
||||
" private static Object[][] dataProviderTestCases() {",
|
||||
" return new Object[][] {{1}, {2}};",
|
||||
" }",
|
||||
"",
|
||||
" private static Object[][] notMigratableDataProviderTestCases() {",
|
||||
" return Stream.of(1, 2, 3).map(i -> new Object[] {i}).toArray(Object[][]::new);",
|
||||
" }",
|
||||
"",
|
||||
" private static Object[][] notMigratableDataProvider2TestCases() {",
|
||||
" Object[][] testCases = new Object[][] {{1}, {2}};",
|
||||
" return testCases;",
|
||||
" }",
|
||||
"",
|
||||
" private static Object[] notMigratableDataProvider3TestCases() {",
|
||||
" return new Object[] {new Object[] {1}, new Object[] {2}};",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void junitTestClass() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"",
|
||||
"class A {",
|
||||
" @Test",
|
||||
" private void foo() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void normalClass() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines("A.java", "class A {", " private void foo() {}", "}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void teardownAndSetupMethods() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.testng.annotations.AfterClass;",
|
||||
"import org.testng.annotations.AfterMethod;",
|
||||
"import org.testng.annotations.BeforeClass;",
|
||||
"import org.testng.annotations.BeforeMethod;",
|
||||
"",
|
||||
"class A {",
|
||||
" @BeforeClass",
|
||||
" // BUG: Diagnostic contains: Class: A SetupTearDown: BEFORE_CLASS",
|
||||
" private static void beforeClass() {}",
|
||||
"",
|
||||
" @BeforeMethod",
|
||||
" // BUG: Diagnostic contains: Class: A SetupTearDown: BEFORE_METHOD",
|
||||
" private void beforeMethod() {}",
|
||||
"",
|
||||
" @AfterClass",
|
||||
" // BUG: Diagnostic contains: Class: A SetupTearDown: AFTER_CLASS",
|
||||
" private static void afterClass() {}",
|
||||
"",
|
||||
" @AfterMethod",
|
||||
" // BUG: Diagnostic contains: Class: A SetupTearDown: AFTER_METHOD",
|
||||
" private void afterMethod() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags classes with a diagnostics message that indicates, whether a
|
||||
* TestNG element was collected.
|
||||
*/
|
||||
@BugPattern(severity = ERROR, summary = "Interacts with `TestNGScanner` for testing purposes")
|
||||
public static final class TestChecker extends BugChecker
|
||||
implements CompilationUnitTreeMatcher, ClassTreeMatcher, MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
// XXX: find better way to do this
|
||||
private ImmutableMap<ClassTree, TestNgMetadata> classMetaData = ImmutableMap.of();
|
||||
|
||||
@Override
|
||||
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
|
||||
TestNGScanner scanner = new TestNGScanner(state);
|
||||
classMetaData = scanner.collectMetadataForClasses(tree);
|
||||
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchClass(ClassTree tree, VisitorState state) {
|
||||
Optional.ofNullable(classMetaData.get(tree))
|
||||
.flatMap(TestNgMetadata::getClassLevelAnnotationMetadata)
|
||||
.ifPresent(annotation -> reportAnnotationMessage(tree, annotation, state));
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
ClassTree classTree = state.findEnclosing(ClassTree.class);
|
||||
Optional<TestNgMetadata> metadata = Optional.ofNullable(classTree).map(classMetaData::get);
|
||||
|
||||
if (metadata.isEmpty()) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
reportClassLevelAnnotation(classTree, metadata.orElseThrow(), state);
|
||||
reportTestMethods(tree, classTree, metadata.orElseThrow(), state);
|
||||
reportDataProviderMethods(tree, classTree, metadata.orElseThrow(), state);
|
||||
reportSetupTeardownMethods(tree, classTree, metadata.orElseThrow(), state);
|
||||
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
private void reportClassLevelAnnotation(
|
||||
ClassTree classTree, TestNgMetadata metadata, VisitorState state) {
|
||||
metadata
|
||||
.getClassLevelAnnotationMetadata()
|
||||
.ifPresent(annotation -> reportAnnotationMessage(classTree, annotation, state));
|
||||
}
|
||||
|
||||
private void reportTestMethods(
|
||||
MethodTree tree, ClassTree classTree, TestNgMetadata metadata, VisitorState state) {
|
||||
metadata
|
||||
.getClassLevelAnnotationMetadata()
|
||||
.filter(not(isEqual(metadata.getMethodAnnotations().get(tree))))
|
||||
.map(unused -> metadata.getMethodAnnotations().get(tree))
|
||||
.ifPresent(annotation -> reportAnnotationMessage(classTree, annotation, state));
|
||||
}
|
||||
|
||||
private void reportSetupTeardownMethods(
|
||||
MethodTree tree, ClassTree classTree, TestNgMetadata metadata, VisitorState state) {
|
||||
metadata.getSetupTeardown().entrySet().stream()
|
||||
.filter(entry -> entry.getKey().equals(tree))
|
||||
.findFirst()
|
||||
.ifPresent(
|
||||
entry ->
|
||||
reportMethodMessage(
|
||||
classTree.getSimpleName(),
|
||||
"SetupTearDown",
|
||||
entry.getValue().name(),
|
||||
entry.getKey(),
|
||||
state));
|
||||
}
|
||||
|
||||
private void reportDataProviderMethods(
|
||||
MethodTree tree, ClassTree classTree, TestNgMetadata metadata, VisitorState state) {
|
||||
metadata.getDataProviderMetadata().entrySet().stream()
|
||||
.filter(entry -> entry.getValue().getMethodTree().equals(tree))
|
||||
.findFirst()
|
||||
.map(Map.Entry::getValue)
|
||||
.ifPresent(
|
||||
dataProvider -> {
|
||||
reportMethodMessage(
|
||||
classTree.getSimpleName(),
|
||||
"DataProvider",
|
||||
dataProvider.getName(),
|
||||
dataProvider.getMethodTree(),
|
||||
state);
|
||||
});
|
||||
}
|
||||
|
||||
private void reportAnnotationMessage(
|
||||
ClassTree classTree, AnnotationMetadata annotation, VisitorState state) {
|
||||
state.reportMatch(
|
||||
buildDescription(annotation.getAnnotationTree())
|
||||
.setMessage(createMetaDataMessage(classTree, annotation))
|
||||
.build());
|
||||
}
|
||||
|
||||
private void reportMethodMessage(
|
||||
Name className, String message, String name, Tree tree, VisitorState state) {
|
||||
state.reportMatch(
|
||||
buildDescription(tree)
|
||||
.setMessage(String.format("Class: %s %s: %s", className, message, name))
|
||||
.build());
|
||||
}
|
||||
|
||||
private static String createMetaDataMessage(
|
||||
ClassTree classTree, AnnotationMetadata annotationMetadata) {
|
||||
return String.format(
|
||||
"Class: %s attributes: %s",
|
||||
classTree.getSimpleName(), annotationMetadata.getAttributes());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,44 @@
|
||||
# An overview of Error Prone Support releases, along with compatible Error
|
||||
# Prone releases. This data was generated by `generate-version-compatibility-overview.sh`.
|
||||
releases:
|
||||
- version: 0.16.1
|
||||
compatible:
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- version: 0.16.0
|
||||
compatible:
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- version: 0.15.0
|
||||
compatible:
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- version: 0.14.0
|
||||
compatible:
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- "2.22.0"
|
||||
|
||||
@@ -10,15 +10,21 @@ source "${HOME}/.sdkman/bin/sdkman-init.sh"
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
# Currently all released Error Prone Support versions are compatible with Java
|
||||
# 17.
|
||||
java_version=17.0.10-tem
|
||||
(set +u && echo n | sdk install java "${java_version}")
|
||||
sdk use java "${java_version}"
|
||||
|
||||
output_file="$(dirname "${0}")/_data/compatibility.yml"
|
||||
|
||||
ep_versions=$(
|
||||
ep_versions="$(
|
||||
git ls-remote \
|
||||
--exit-code --refs --sort='-v:refname' \
|
||||
https://github.com/google/error-prone.git \
|
||||
'v*.*' \
|
||||
| grep -oP '(?<=/v)[^/]+$'
|
||||
)
|
||||
)"
|
||||
|
||||
work_dir="$(mktemp -d)"
|
||||
trap 'rm -rf -- "${work_dir=}"' INT TERM HUP EXIT
|
||||
@@ -39,26 +45,43 @@ for eps_version in ${eps_versions}; do
|
||||
(set +u && echo n | sdk install maven "${mvn_version}")
|
||||
sdk use maven "${mvn_version}"
|
||||
|
||||
# Collect the list of checks supported by this version of Error Prone
|
||||
# Support.
|
||||
# XXX: Conditionally omit the `MethodReferenceUsage` exclusion once that
|
||||
# check is production-ready.
|
||||
mvn clean compile -Dverification.skip -DskipTests
|
||||
checks="$(
|
||||
find \
|
||||
-path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" \
|
||||
-not -path "*/error-prone-experimental/*" \
|
||||
-not -path "*/error-prone-guidelines/*" \
|
||||
-print0 \
|
||||
| xargs -0 grep -hoP '[^.]+$' \
|
||||
| grep -v '^MethodReferenceUsage$' \
|
||||
| paste -s -d ',' -
|
||||
)"
|
||||
|
||||
# Remove any Error Prone flags used by this build that may not be compatible
|
||||
# with the targeted version of Error Prone. Removal of these build flags does
|
||||
# not influence the compatibility assessment.
|
||||
sed -i -r 's,-XepAllSuggestionsAsWarnings|-Xep:\w+:\w+,,g' pom.xml
|
||||
|
||||
# Using each Error Prone release, attempt to build and test the source, while
|
||||
# also applying the Maven Central-hosted Refaster rules. This determines
|
||||
# source and behavioral (in)compatibility with Error Prone APIs, while also
|
||||
# assessing whether the Refaster rules are deserialization-compatible.
|
||||
# also applying the Maven Central-hosted Error Prone Support-defined checks
|
||||
# and Refaster rules. This determines source and behavioral (in)compatibility
|
||||
# with Error Prone APIs, while also assessing whether the Refaster rules are
|
||||
# deserialization-compatible.
|
||||
for ep_version in ${ep_versions}; do
|
||||
echo "Testing Error Prone Support ${eps_version} with Error Prone ${ep_version}..."
|
||||
mvn clean test \
|
||||
-Perror-prone \
|
||||
-Derror-prone.patch-checks=Refaster \
|
||||
-Derror-prone.patch-checks="${checks}" \
|
||||
-Ppatch \
|
||||
-Pself-check \
|
||||
-Dverification.skip \
|
||||
-Dversion.error-prone-orig="${ep_version}" \
|
||||
&& echo "SUCCESS: { \"eps_version\": \"${eps_version}\", \"ep_version\": \"${ep_version}\" }" || true
|
||||
# Undo any changes applied by Refaster.
|
||||
# Undo any changes applied by the checks.
|
||||
git checkout -- '*.java'
|
||||
done
|
||||
done | tee "${build_log}"
|
||||
|
||||
Reference in New Issue
Block a user