Compare commits

...

256 Commits

Author SHA1 Message Date
Rick Ossendrijver
561adcd0d6 Add spaces when adding @Test annotation 2024-07-05 10:13:41 +02:00
Stephan Schroevers
05c5ba2677 Use compatible Maven 2024-07-03 14:25:20 +02:00
Stephan Schroevers
efb9ea91b7 Introduce Jitpack config 2024-07-03 14:14:54 +02:00
Rick Ossendrijver
36ed176c4c Drop incorrect add-exports 2024-07-02 15:42:46 +02:00
Rick Ossendrijver
aa21c57185 Exclude from analysis 2024-07-01 15:07:05 +02:00
Rick Ossendrijver
6e7f21f827 Revert "Apply EP best practices suggestions"
This reverts commit 37580fa5ff.
2024-07-01 14:37:44 +02:00
Rick Ossendrijver
37580fa5ff Apply EP best practices suggestions 2024-07-01 11:56:19 +02:00
Rick Ossendrijver
b26ec206a0 Add Refaster rules 2024-06-25 09:27:53 +02:00
Rick Ossendrijver
354d98dbb7 Apply EPS suggestions 2024-06-19 14:17:30 +02:00
Rick Ossendrijver
6b99639f0e Add specific improvement for OpenJDK 2024-06-19 12:41:55 +02:00
Rick Ossendrijver
a5d4a3e87f Fix Error Prone warnings and pom violation 2024-06-19 11:53:28 +02:00
Rick Ossendrijver
c19a30cdb8 Bump version in testng-junit-migrator 2024-06-19 11:53:28 +02:00
Gijs de Jong
b61dc4e151 Add @DataProvider edge cases 2024-06-19 11:53:27 +02:00
Gijs de Jong
27a248def0 Kill mutants 2024-06-19 11:53:27 +02:00
Gijs de Jong
0e72a531e0 Add test case for conservativeMode 2024-06-19 11:53:26 +02:00
Gijs de Jong
8842b11ad3 Simplify AttributeMigrator 2024-06-19 11:53:26 +02:00
Gijs de Jong
39550227a7 kill mutant 2024-06-19 11:53:25 +02:00
Rick Ossendrijver
867985819a Move VisitorState to be the last parameter in signature 2024-06-19 11:53:25 +02:00
Gijs de Jong
0a6c880e9c fix build 2024-06-19 11:53:24 +02:00
Gijs de Jong
ae4a196fd6 Clean up TestNGScanner 2024-06-19 11:53:24 +02:00
Gijs de Jong
b5ef39c89c Address review 2024-06-19 11:53:23 +02:00
Gijs de Jong
21b6fc7bd1 Implement UnsupportedAttributeMigrator as Migrator 2024-06-19 11:53:23 +02:00
Gijs de Jong
cec781b317 Prefer attribute for annotation attributes 2024-06-19 11:53:23 +02:00
Gijs de Jong
76778344f6 Introduce UnsupportedAttributeMigrator 2024-06-19 11:53:22 +02:00
Gijs de Jong
c663c0cb7a Add Known Limitations section 2024-06-19 11:53:22 +02:00
Gijs de Jong
0f7231a3ad Use @Builder immutable builders 2024-06-19 11:53:21 +02:00
Rick Ossendrijver
4affdc8519 Swap canFix and createFix and other improvements 2024-06-19 11:53:21 +02:00
Rick Ossendrijver
97d87cc9c0 Assorted improvements 2024-06-19 11:53:20 +02:00
Rick Ossendrijver
4c9ab70bb6 Fix pom version 2024-06-19 11:53:20 +02:00
Rick Ossendrijver
03232ad9b9 Post-post rebase fix 2024-06-19 11:53:19 +02:00
Rick Ossendrijver
4f48e05d8f Post-rebase fix 2024-06-19 11:53:19 +02:00
Gijs de Jong
57eb44285a Emphasize importance of checking migrated code 2024-06-19 11:53:18 +02:00
Dima Legeza
4dd39610e7 Replace missed sed commands with platform-independent $sed_command with additional $grep_command usage alignment 2024-06-19 11:53:18 +02:00
Gijs de Jong
643fd4e8a5 Update package-info.java 2024-06-19 11:53:18 +02:00
Gijs de Jong
67c57c2442 clean up some code smells 2024-06-19 11:53:17 +02:00
Gijs de Jong
2ec3938737 0.10.1 2024-06-19 11:53:17 +02:00
Gijs de Jong
486ee7353f (hopefully) fix SonarCloud warnings 2024-06-19 11:53:16 +02:00
Gijs de Jong
7cbe859b8c Specify explicit immutability 2024-06-19 11:53:16 +02:00
Gijs de Jong
3cfcdda0fc Clarify setup/teardown methods 2024-06-19 11:53:15 +02:00
Gijs de Jong
952759209d fmt 2024-06-19 11:53:15 +02:00
Gijs de Jong
9ad5f6e37c Kill mutants in DataProvider 2024-06-19 11:53:14 +02:00
Gijs de Jong
ebb6ff46b4 Add support for the timeOut attribute 2024-06-19 11:53:14 +02:00
Gijs de Jong
a305bf6da0 macOs 2024-06-19 11:53:13 +02:00
Rick Ossendrijver
1d3cc10ff0 Suggestions 2024-06-19 11:53:13 +02:00
Rick Ossendrijver
8d93549935 Rename "argument" with "attribute" and minor improvements 2024-06-19 11:53:12 +02:00
Gijs de Jong
7096ce6075 Use /bin/bash 2024-06-19 11:53:12 +02:00
Gijs de Jong
9652c6f990 Add macOs support to migrator script 2024-06-19 11:53:12 +02:00
Gijs de Jong
f02d9adcb2 Improve macos specific instructions 2024-06-19 11:53:11 +02:00
Gijs de Jong
9dda67e6cc Clarify gnu-{grep, sed} requirements 2024-06-19 11:53:11 +02:00
Gijs de Jong
51fdf18577 Clarify macos requirements picnic script 2024-06-19 11:53:10 +02:00
Gijs de Jong
e3253011c3 Continue migration if JUnit dependency is present 2024-06-19 11:53:10 +02:00
Gijs de Jong
d1836383ab Version 0.9.1-SNAPSHOT 2024-06-19 11:53:09 +02:00
Gijs de Jong
882b256c18 Handle {Before, After}Test annotations 2024-06-19 11:53:09 +02:00
Gijs de Jong
36e0765734 Add --count flag instructions 2024-06-19 11:53:08 +02:00
Gijs de Jong
d46a1ab87e Add support for non parent modukes 2024-06-19 11:53:08 +02:00
Gijs de Jong
3be79074d8 Explain where to run script 2024-06-19 11:53:07 +02:00
Gijs de Jong
d8991627a7 Improve installion steps 2024-06-19 11:53:07 +02:00
Rick Ossendrijver
1344321746 Further improve README 2024-06-19 11:53:07 +02:00
Rick Ossendrijver
559a55b7d0 Tweak README 2024-06-19 11:53:06 +02:00
Gijs de Jong
2e28ac9828 Improve metadata builder api 2024-06-19 11:53:06 +02:00
Gijs de Jong
4d7b88a986 Mention picnic specific migration script 2024-06-19 11:53:05 +02:00
Gijs de Jong
c0e177e4cd eps suggestions 2024-06-19 11:53:05 +02:00
Gijs de Jong
768b05bee6 More DataProvider test cases 2024-06-19 11:53:04 +02:00
Rick Ossendrijver
048203434e Some more tweaks 2024-06-19 11:53:04 +02:00
Rick Ossendrijver
9b89c0863c Update and improve TestNGScanner{,Test} 2024-06-19 11:53:03 +02:00
Rick Ossendrijver
d03d536376 Suggestions and delete SourceCodeTest 2024-06-19 11:53:03 +02:00
Gijs de Jong
c812c95ea9 Add tests for TestNGMatchers 2024-06-19 11:53:02 +02:00
Gijs de Jong
0d23dd1845 Make setup/teardown methods static if needed 2024-06-19 11:53:02 +02:00
Gijs de Jong
e29c08604d Copy over SourceCode test 2024-06-19 11:53:01 +02:00
Gijs de Jong
22c1f07017 Copy SourceCode from contrib 2024-06-19 11:53:01 +02:00
Gijs de Jong
9dd7621c18 Add tests for Tag name specifications 2024-06-19 11:53:00 +02:00
Gijs de Jong
3c59795c1b Adhere to JUnit Tag requirements 2024-06-19 11:53:00 +02:00
Gijs de Jong
2688088750 Introduce GroupsArgumentMigrator 2024-06-19 11:53:00 +02:00
Gijs de Jong
a7b3378bda fmt 2024-06-19 11:52:59 +02:00
Gijs de Jong
d7a10eda13 Handle empty list of expectedExceptions 2024-06-19 11:52:59 +02:00
Gijs de Jong
78e833ff85 Return empty fix for enabled test 2024-06-19 11:52:58 +02:00
Gijs de Jong
edf2b7ca79 Prevent non-test methods from being flagged as such 2024-06-19 11:52:58 +02:00
Gijs de Jong
9ab79cb69b Introduce EnabledArgumentMigrator 2024-06-19 11:52:57 +02:00
Gijs de Jong
ac78cc709d Add support for setup/teardown methods 2024-06-19 11:52:57 +02:00
Rick Ossendrijver
2ef223ec9d Suggestions and try to make the build green 2024-06-19 11:52:56 +02:00
Gijs de Jong
2f797a322a Flatten package structure 2024-06-19 11:52:56 +02:00
Gijs de Jong
3537e58305 suggestion
Co-authored-by: Rick Ossendrijver <rick.ossendrijver@gmail.com>
2024-06-19 11:52:55 +02:00
Gijs de Jong
f5e816d967 Fix build 2024-06-19 11:52:55 +02:00
Gijs de Jong
c0acb8b202 Assume @DataProvider has a return tree 2024-06-19 11:52:55 +02:00
Gijs de Jong
8f2183b6c2 Improve readme 2024-06-19 11:52:54 +02:00
Gijs de Jong
278b679049 Improve migration script 2024-06-19 11:52:54 +02:00
Gijs de Jong
29657997f3 suggestions 2024-06-19 11:52:53 +02:00
Gijs de Jong
3562e4c764 Update README.md 2024-06-19 11:52:53 +02:00
Gijs de Jong
d1b9f93cad Update run-testng-junit-migration.sh 2024-06-19 11:52:52 +02:00
Gijs de Jong
fc177a9355 Initial migration script 2024-06-19 11:52:52 +02:00
Gijs de Jong
9ef2692885 format pom 2024-06-19 11:52:51 +02:00
Gijs de Jong
35ada6b449 remove old check 2024-06-19 11:52:51 +02:00
Gijs de Jong
1a98a4d599 Add test case for multiple expected exceptions 2024-06-19 11:52:50 +02:00
Gijs de Jong
e5d7482133 Fix tests 2024-06-19 11:52:50 +02:00
Gijs de Jong
69e987363a Flatten migrator hierarchy 2024-06-19 11:52:49 +02:00
Gijs de Jong
dad73a8447 suggestions 2024-06-19 11:52:49 +02:00
Gijs de Jong
f22b344d87 Create testngjunitmigrator module 2024-06-19 11:52:49 +02:00
Gijs de Jong
8d78b5b316 Remove unused TestNGMigrationContext 2024-06-19 11:52:48 +02:00
Gijs de Jong
6024caf99c add tests for TestNGScanner 2024-06-19 11:52:48 +02:00
Gijs de Jong
ff60c7be25 use jspecify Nullable 2024-06-19 11:52:47 +02:00
Gijs de Jong
891e3dde5f eps suggestions 2024-06-19 11:52:47 +02:00
Gijs de Jong
ee4d3a70fa fmt 2024-06-19 11:52:46 +02:00
Gijs de Jong
81c0e300a1 Fix tests + behaviour 2024-06-19 11:52:46 +02:00
Gijs de Jong
79abb132f5 Refactor TestNGMetaData to be immutable 2024-06-19 11:52:45 +02:00
Gijs de Jong
d94518cbed begin 2024-06-19 11:52:45 +02:00
Gijs de Jong
6f862401ab Argument migrator 2024-06-19 11:52:44 +02:00
Gijs de Jong
aeae1dd66e feedback 2024-06-19 11:52:44 +02:00
Rick Ossendrijver
8a032bea18 Suggestions and add XXXs 2024-06-19 11:52:43 +02:00
Gijs de Jong
2c3ca2f885 Implement aggressive migration mode + tests 2024-06-19 11:52:43 +02:00
Gijs de Jong
d4a22682cd Implement aggressiveMigration mode 2024-06-19 11:52:43 +02:00
Gijs de Jong
4c03041a47 Remove old code + improve tests 2024-06-19 11:52:42 +02:00
Gijs de Jong
c96cb95ec3 add javadoc 2024-06-19 11:52:42 +02:00
Gijs de Jong
91923ef168 suggestions 2024-06-19 11:52:41 +02:00
Gijs de Jong
b086db14d9 eps suggestions 2024-06-19 11:52:41 +02:00
Gijs de Jong
369566f6f1 Add more test cases 2024-06-19 11:52:40 +02:00
Rick Ossendrijver
555bf36a7a Add XXXs 2024-06-19 11:52:40 +02:00
Rick Ossendrijver
81b27dab08 Tweaks 2024-06-19 11:52:39 +02:00
Gijs de Jong
ecdd2c0f61 Add support for expectedExceptions argument 2024-06-19 11:52:39 +02:00
Gijs de Jong
ef9dd72364 Add/remove imports 2024-06-19 11:52:38 +02:00
Gijs de Jong
f2031b8308 Restructure migration 2024-06-19 11:52:38 +02:00
Gijs de Jong
6995f5627a Add support for migrating groups attribute 2024-06-19 11:52:38 +02:00
Gijs de Jong
2ad8deb6af Remove redundant naming 2024-06-19 11:52:37 +02:00
Gijs de Jong
8f0eea6e44 Improve AnnotationAttributeReplacement 2024-06-19 11:52:37 +02:00
Gijs de Jong
8859417f42 Handle test setup and teardown migration 2024-06-19 11:52:36 +02:00
Gijs de Jong
cc35110ff5 Ignore extends clause in TestNGClassLevelTestAnnotation 2024-06-19 11:52:36 +02:00
Gijs de Jong
eed6f39b10 Introduce BugCheckers TestNG -> JUnit migration
Fix `TestNGDataProviderCheckTest`

Suggestions

Suggested changes

Introduce `BugChecker`s TestNG -> JUnit migration

Fix `TestNGDataProviderCheckTest`

Suggestions

Suggested changes

Apply fixes for new bugchecks

Rename checks for `BugPatternNaming`

Only match migratable tests

Update javadoc with *legal* characters

Remove static method in inner class

Requested changes

Introduce support for 1d array dataprovider

Retain comments in data provider return tree

Self-apply EP checks

Swapped around a few methods and fix mutable issue

Suggested changes

Suggestions

Suggestions

Suggestions 2

Prefer `orElseThrow()` over `.get()`
2024-06-19 11:52:35 +02:00
Picnic-DevPla-Bot
1e229949fc Upgrade Jakarta Servlet 6.0.0 -> 6.1.0 (#1216)
See:
- https://github.com/eclipse-ee4j/servlet-api/compare/6.0.0-RELEASE...6.1.0-RELEASE
2024-06-18 11:04:56 +02:00
Picnic-DevPla-Bot
28a93e949e Upgrade maven-dependency-plugin 3.6.1 -> 3.7.0 (#1217)
See:
- https://github.com/apache/maven-dependency-plugin/releases/tag/maven-dependency-plugin-3.7.0
- https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.6.1...maven-dependency-plugin-3.7.0
2024-06-18 09:11:59 +02:00
Picnic-DevPla-Bot
40ad38bc2a Upgrade maven-release-plugin 3.0.1 -> 3.1.0 (#1221)
See:
- https://github.com/apache/maven-release/releases/tag/maven-release-3.1.0
- https://github.com/apache/maven-release/compare/maven-release-3.0.1...maven-release-3.1.0
2024-06-18 09:02:56 +02:00
Picnic-DevPla-Bot
e125c6b7e2 Upgrade Spring Security 6.3.0 -> 6.3.1 (#1222)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.3.1
- https://github.com/spring-projects/spring-security/compare/6.3.0...6.3.1
2024-06-18 08:36:10 +02:00
Picnic-DevPla-Bot
5596c4530d Upgrade MongoDB driver 5.1.0 -> 5.1.1 (#1218)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%205.1.0%20AND%20fixVersion%20%3C%3D%205.1.1
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.1.1
- https://github.com/mongodb/mongo-java-driver/compare/r5.1.0...r5.1.1
2024-06-17 14:03:25 +02:00
Stephan Schroevers
d81fe19836 Extend FluxConcatMap Refaster rule (#1213) 2024-06-10 15:34:16 +02:00
Picnic-DevPla-Bot
d6838ec947 Upgrade errorprone-slf4j 0.1.24 -> 0.1.25 (#1212)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.25
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.24...v0.1.25
2024-06-10 09:13:54 +02:00
Picnic-DevPla-Bot
b36a69aa5f Upgrade git-commit-id-maven-plugin 8.0.2 -> 9.0.0 (#1211)
See:
- https://github.com/git-commit-id/git-commit-id-maven-plugin/releases/tag/v9.0.0
- https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v8.0.2...v9.0.0
2024-06-10 08:32:32 +02:00
Picnic-DevPla-Bot
831b757bb1 Upgrade OpenRewrite Templating 1.9.2 -> 1.10.0 (#1210)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.10.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.9.2...v1.10.0
2024-06-08 23:23:26 +02:00
Picnic-DevPla-Bot
527fc5785b Upgrade OpenRewrite 2.11.1 -> 2.12.0 (#1209)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.12.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.11.1...v2.12.0
2024-06-08 12:18:41 +02:00
Picnic-DevPla-Bot
8c8055d381 Upgrade maven-checkstyle-plugin 3.3.1 -> 3.4.0 (#1208)
See https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.3.1...maven-checkstyle-plugin-3.4.0
2024-06-07 11:08:31 +02:00
Picnic-Bot
b658c19c03 Upgrade Spring Boot 3.2.5 -> 3.3.0 (#1196)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.2.6
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.0-M1
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.0-M2
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.0-M3
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.0-RC1
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.0
- https://github.com/spring-projects/spring-boot/compare/v3.2.5...v3.3.0
2024-06-05 09:42:42 +02:00
Picnic-DevPla-Bot
85976e199f Upgrade Checker Framework Annotations 3.43.0 -> 3.44.0 (#1207)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.44.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.43.0...checker-framework-3.44.0
2024-06-05 09:20:12 +02:00
Picnic-DevPla-Bot
f6a392e118 Upgrade Guava 33.2.0-jre -> 33.2.1-jre (#1202)
See:
- https://guava.dev/releases/33.2.1-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v33.2.1
- https://github.com/google/guava/compare/v33.2.0...v33.2.1
2024-06-04 16:39:05 +02:00
Picnic-DevPla-Bot
539fcae745 Upgrade maven-javadoc-plugin 3.6.3 -> 3.7.0 (#1205)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MJAVADOC%20AND%20fixVersion%20%3E%203.6.3%20AND%20fixVersion%20%3C%3D%203.7.0
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.7.0
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.3...maven-javadoc-plugin-3.7.0
2024-06-04 14:47:57 +02:00
Picnic-DevPla-Bot
29f1a3d2a6 Upgrade maven-enforcer-plugin 3.4.1 -> 3.5.0 (#1201)
See:
- https://github.com/apache/maven-enforcer/releases/tag/enforcer-3.5.0
- https://github.com/apache/maven-enforcer/compare/enforcer-3.4.1...enforcer-3.5.0
2024-06-04 13:56:07 +02:00
Picnic-DevPla-Bot
01f139b6a4 Upgrade NullAway 0.10.26 -> 0.11.0 (#1204)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.11.0
- https://github.com/uber/NullAway/compare/v0.10.26...v0.11.0
2024-06-04 13:37:52 +02:00
Picnic-DevPla-Bot
c61980721e Upgrade AutoValue 1.10.4 -> 1.11.0 (#1203)
See:
- https://github.com/google/auto/releases/tag/auto-value-1.11.0
- https://github.com/google/auto/compare/auto-value-1.10.4...auto-value-1.11.0
2024-06-04 13:06:01 +02:00
Picnic-DevPla-Bot
471a1ebff1 Upgrade Byte Buddy 1.14.16 -> 1.14.17 (#1199)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.17
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.16...byte-buddy-1.14.17
2024-06-04 07:55:19 +02:00
Picnic-DevPla-Bot
b8d9ff0971 Upgrade sonar-maven-plugin 3.11.0.3922 -> 4.0.0.4121 (#1206)
See:
- https://github.com/SonarSource/sonar-scanner-maven/releases/tag/4.0.0.4121
- https://github.com/SonarSource/sonar-scanner-maven/compare/3.11.0.3922...4.0.0.4121
2024-06-04 07:37:39 +02:00
Picnic-Bot
e02d836c12 Upgrade Modernizer Maven Plugin 2.8.0 -> 2.9.0 (#1195)
See:
- https://github.com/gaul/modernizer-maven-plugin/releases/tag/modernizer-maven-plugin-2.9.0
- https://github.com/gaul/modernizer-maven-plugin/compare/modernizer-maven-plugin-2.8.0...modernizer-maven-plugin-2.9.0
2024-05-27 16:09:23 +02:00
Picnic-Bot
abd47eb269 Upgrade Checkstyle 10.16.0 -> 10.17.0 (#1198)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.17.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.16.0...checkstyle-10.17.0
2024-05-27 14:42:20 +02:00
Stephan Schroevers
5219fd8f6c Allow OpenSSF Scorecard analysis to access api.scorecard.dev (#1193) 2024-05-25 19:02:02 +02:00
Picnic-Bot
588fc38f81 Upgrade OpenRewrite 2.11.0 -> 2.11.1 (#1190)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.11.1
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.11.0...v2.11.1
2024-05-24 13:49:50 +02:00
Picnic-Bot
e3aa8a5d12 Upgrade OpenRewrite Templating 1.9.0 -> 1.9.2 (#1191)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.9.1
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.9.2
- https://github.com/openrewrite/rewrite-templating/compare/v1.9.0...v1.9.2
2024-05-24 13:31:25 +02:00
Picnic-Bot
3255c0b6eb Upgrade Spring 6.1.7 -> 6.1.8 (#1192)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.1.8
- https://github.com/spring-projects/spring-framework/compare/v6.1.7...v6.1.8
2024-05-24 13:21:50 +02:00
Picnic-Bot
d2dbd88f25 Upgrade Byte Buddy 1.14.15 -> 1.14.16 (#1189)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.16
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.15...byte-buddy-1.14.16
2024-05-24 11:41:07 +02:00
Picnic-Bot
ff824cfa20 Upgrade Spring Security 6.2.4 -> 6.3.0 (#1186)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.3.0-M1
- https://github.com/spring-projects/spring-security/releases/tag/6.3.0-M2
- https://github.com/spring-projects/spring-security/releases/tag/6.3.0-M3
- https://github.com/spring-projects/spring-security/releases/tag/6.3.0-RC1
- https://github.com/spring-projects/spring-security/releases/tag/6.3.0
- https://github.com/spring-projects/spring-security/compare/6.2.4...6.3.0
2024-05-23 16:39:20 +02:00
Picnic-Bot
43303e770a Upgrade actions/checkout v4.1.4 -> v4.1.6 (#1184)
See:
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v416
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v415
2024-05-23 10:36:32 +02:00
Picnic-Bot
cfadbca32a Upgrade ossf/scorecard-action v2.3.1 -> v2.3.3 (#1185)
See:
- https://github.com/ossf/scorecard-action/releases/tag/v2.3.3
- https://github.com/ossf/scorecard-action/compare/v2.3.1...v2.3.2
2024-05-23 09:05:16 +02:00
Picnic-Bot
e7ca4a5325 Upgrade s4u/setup-maven-action v1.12.0 -> v1.13.0 (#1187)
See:
- https://github.com/s4u/setup-maven-action/releases/tag/v1.13.0
2024-05-22 10:23:23 +02:00
Picnic-Bot
7bab1eb7fd Upgrade step-security/harden-runner v2.7.1 -> v2.8.0 (#1188)
See:
- https://github.com/step-security/harden-runner/releases/tag/v2.8.0
2024-05-22 08:36:34 +02:00
Picnic-DevPla-Bot
072e39da32 Upgrade build-helper-maven-plugin 3.5.0 -> 3.6.0 (#1182)
See:
- https://github.com/mojohaus/build-helper-maven-plugin/releases/tag/3.6.0
- https://github.com/mojohaus/build-helper-maven-plugin/compare/3.5.0...3.6.0
2024-05-21 09:49:09 +02:00
Picnic-DevPla-Bot
ec7e84ac45 Upgrade Swagger 2.2.21 -> 2.2.22 (#1178)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.22
- https://github.com/swagger-api/swagger-core/compare/v2.2.21...v2.2.22
2024-05-21 09:39:03 +02:00
Picnic-DevPla-Bot
4228a63ad1 Upgrade Project Reactor 2023.0.5 -> 2023.0.6 (#1176)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.6
- https://github.com/reactor/reactor/compare/2023.0.5...2023.0.6
2024-05-21 09:16:03 +02:00
Picnic-DevPla-Bot
6093e6f322 Upgrade OpenRewrite Templating 1.8.1 -> 1.9.0 (#1181)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.9.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.8.1...v1.9.0
2024-05-21 09:06:51 +02:00
Picnic-DevPla-Bot
ee103a99f6 Upgrade Spring 6.1.6 -> 6.1.7 (#1180)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.1.7
- https://github.com/spring-projects/spring-framework/compare/v6.1.6...v6.1.7
2024-05-21 08:58:01 +02:00
Pieter Dirk Soels
c34065beab Improve Renovate configuration (#1179) 2024-05-21 07:29:26 +02:00
Picnic-DevPla-Bot
d9e1f3ad5d Upgrade sortpom-maven-plugin 3.4.1 -> 4.0.0 (#1183)
See:
- https://github.com/Ekryd/sortpom/wiki/Versions
- https://github.com/Ekryd/sortpom/compare/sortpom-parent-3.4.1...sortpom-parent-4.0.0
2024-05-20 21:28:31 +02:00
Stephan Schroevers
8a8290587a Update step-security/harden-runner configuration (#1177)
This resolves recent build failures by ensuring that JDKs can be
downloaded.
2024-05-19 14:14:20 +02:00
Picnic-DevPla-Bot
162aa0d458 Upgrade tidy-maven-plugin 1.2.0 -> 1.3.0 (#1175)
See:
- https://github.com/mojohaus/tidy-maven-plugin/releases/tag/1.3.0
- https://github.com/mojohaus/tidy-maven-plugin/compare/tidy-maven-plugin-1.2.0...1.3.0
2024-05-13 08:07:12 +02:00
Picnic-DevPla-Bot
0fb37c45b5 Upgrade Mockito 5.11.0 -> 5.12.0 (#1174)
See:
- https://github.com/mockito/mockito/releases/tag/v5.12.0
- https://github.com/mockito/mockito/compare/v5.11.0...v5.12.0
2024-05-12 10:16:02 +02:00
Picnic-DevPla-Bot
0c2ce44742 Upgrade AspectJ 1.9.22 -> 1.9.22.1 (#1173)
See:
- https://github.com/eclipse-aspectj/aspectj/releases/tag/V1_9_22_1
- https://github.com/eclipse-aspectj/aspectj/compare/V1_9_22...V1_9_22_1
2024-05-12 10:03:43 +02:00
Picnic-DevPla-Bot
f089157443 Upgrade Byte Buddy 1.14.14 -> 1.14.15 (#1169)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.15
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.14...byte-buddy-1.14.15
2024-05-11 14:59:23 +02:00
Picnic-DevPla-Bot
e192dacdfb Upgrade pitest-maven-plugin 1.16.0 -> 1.16.1 (#1172)
See:
- https://github.com/hcoles/pitest/releases/tag/1.16.1
- https://github.com/hcoles/pitest/compare/1.16.0...1.16.1
2024-05-10 19:24:00 +02:00
Picnic-DevPla-Bot
8418652de0 Upgrade OpenRewrite Templating 1.8.0 -> 1.8.1 (#1170)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.8.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.8.0...v1.8.1
2024-05-10 19:13:24 +02:00
Picnic-DevPla-Bot
1d8ac35660 Upgrade OpenRewrite 2.10.0 -> 2.11.0 (#1171)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.11.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.10.0...v2.11.0
2024-05-10 19:00:31 +02:00
Picnic-DevPla-Bot
913cd2ee3a Upgrade Jackson 2.17.0 -> 2.17.1 (#1168)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.17.1
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.17.0...jackson-bom-2.17.1
2024-05-06 08:56:55 +02:00
Picnic-DevPla-Bot
6adaa6c4f6 Upgrade NullAway 0.10.25 -> 0.10.26 (#1167)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.26
- https://github.com/uber/NullAway/compare/v0.10.25...v0.10.26
2024-05-05 12:13:46 +02:00
Stephan Schroevers
08dbb8c298 Upgrade Error Prone 2.26.1 -> 2.27.1 (#1155)
See:
- https://github.com/google/error-prone/releases/tag/v2.27.0
- https://github.com/google/error-prone/releases/tag/v2.27.1
- https://github.com/google/error-prone/compare/v2.26.1...v2.27.1
- https://github.com/PicnicSupermarket/error-prone/compare/v2.26.1-picnic-2...v2.27.1-picnic-1
2024-05-04 16:08:58 +02:00
Picnic-DevPla-Bot
e7bc0e113c Upgrade Guava 33.1.0-jre -> 33.2.0-jre (#1166)
See:
- https://guava.dev/releases/33.2.0-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v33.2.0
- https://github.com/google/guava/compare/v33.1.0...v33.2.0
2024-05-04 13:07:51 +02:00
Picnic-DevPla-Bot
6d2c926b0e Upgrade errorprone-slf4j 0.1.23 -> 0.1.24 (#1164)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.24
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.23...v0.1.24
2024-05-04 12:58:25 +02:00
Picnic-DevPla-Bot
60e15cb569 Upgrade Checker Framework Annotations 3.42.0 -> 3.43.0 (#1165)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.43.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.42.0...checker-framework-3.43.0
2024-05-04 12:44:17 +02:00
Picnic-Bot
22f61d3032 Upgrade maven-install-plugin 3.1.1 -> 3.1.2 (#1159)
See:
- https://github.com/apache/maven-install-plugin/releases/tag/maven-install-plugin-3.1.2
- https://github.com/apache/maven-install-plugin/compare/maven-install-plugin-3.1.1...maven-install-plugin-3.1.2
2024-05-02 09:30:44 +02:00
Picnic-DevPla-Bot
5d2a726aec Upgrade MongoDB driver 5.0.1 -> 5.1.0 (#1163)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%205.0.1%20AND%20fixVersion%20%3C%3D%205.1.0
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.1.0
- https://github.com/mongodb/mongo-java-driver/compare/r5.0.1...r5.1.0
2024-05-02 08:57:49 +02:00
Picnic-Bot
192322a982 Upgrade OpenRewrite Templating 1.6.4 -> 1.8.0 (#1153)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.7.0
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.7.1
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.7.2
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.8.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.6.4...v1.8.0
2024-05-02 08:20:24 +02:00
Picnic-Bot
ddf5d803bd Upgrade Checkstyle 10.15.0 -> 10.16.0 (#1161)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.16.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.15.0...checkstyle-10.16.0
2024-04-30 10:53:04 +02:00
Phil Werli
02fb6d468a Introduce OptionalEmpty Refaster rule (#1156) 2024-04-30 10:09:46 +02:00
Picnic-Bot
e7d50c247d Upgrade step-security/harden-runner v2.7.0 -> v2.7.1 (#1160)
See:
- https://github.com/step-security/harden-runner/releases/tag/v2.7.1
2024-04-30 10:02:09 +02:00
Picnic-Bot
85cfb4b4b7 Upgrade maven-deploy-plugin 3.1.1 -> 3.1.2 (#1158)
See:
- https://github.com/apache/maven-deploy-plugin/releases/tag/maven-deploy-plugin-3.1.2
- https://github.com/apache/maven-deploy-plugin/compare/maven-deploy-plugin-3.1.1...maven-deploy-plugin-3.1.2
2024-04-30 08:56:36 +02:00
Picnic-Bot
0684c577ac Upgrade TestNG 7.10.1 -> 7.10.2 (#1157)
See:
- https://github.com/testng-team/testng/releases/tag/7.10.2
- https://github.com/testng-team/testng/compare/7.10.1...7.10.2
2024-04-30 08:10:56 +02:00
Picnic-Bot
32778edc74 Upgrade actions/checkout v4.1.3 -> v4.1.4 (#1154)
See:
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v414
2024-04-26 10:10:52 +02:00
Picnic-Bot
1e6780afc1 Upgrade OpenRewrite 2.9.0 -> 2.10.0 (#1152)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.10.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.9.0...v2.10.0
2024-04-25 09:52:16 +02:00
Picnic-Bot
ef4e004141 Upgrade Byte Buddy 1.14.13 -> 1.14.14 (#1151)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.14
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.13...byte-buddy-1.14.14
2024-04-25 09:09:49 +02:00
Picnic-Bot
72c5a42feb Upgrade actions/upload-artifact v4.3.2 -> v4.3.3 (#1150)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.3.3
2024-04-23 11:24:02 +02:00
Picnic-Bot
271e01a02c Upgrade actions/checkout v4.1.1 -> v4.1.3 (#1149)
See:
- https://github.com/actions/checkout/releases/tag/v4.1.3
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v412
2024-04-23 10:48:35 +02:00
Picnic-Bot
d47549d68f Upgrade maven-jar-plugin 3.4.0 -> 3.4.1 (#1146)
See:
- https://github.com/apache/maven-jar-plugin/releases/tag/maven-jar-plugin-3.4.1
- https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.0...maven-jar-plugin-3.4.1
2024-04-22 13:05:52 +02:00
Picnic-Bot
01687c7f3e Upgrade maven-gpg-plugin 3.2.3 -> 3.2.4 (#1145)
See:
- https://github.com/apache/maven-gpg-plugin/releases/tag/maven-gpg-plugin-3.2.4
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.3...maven-gpg-plugin-3.2.4
2024-04-22 08:50:57 +02:00
Picnic-Bot
85cb7ffdb1 Upgrade CodeQL v3.24.9 -> v3.25.1 (#1147)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v3.25.0...v3.25.1
- https://github.com/github/codeql-action/compare/v3.24.10...v3.25.0
- https://github.com/github/codeql-action/compare/v3.24.9...v3.24.10
2024-04-22 07:44:09 +02:00
Picnic-Bot
0367037f0a Upgrade ruby/setup-ruby v1.173.0 -> v1.174.0 (#1148)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.174.0
2024-04-22 07:30:17 +02:00
Picnic-Bot
6669a2e1ec Upgrade Spring Boot 3.2.4 -> 3.2.5 (#1144)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.2.5
- https://github.com/spring-projects/spring-boot/compare/v3.2.4...v3.2.5
2024-04-20 13:37:38 +02:00
Picnic-Bot
eb36c1e493 Upgrade actions/upload-artifact v4.3.1 -> v4.3.2 (#1143)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.3.2
2024-04-19 10:14:36 +02:00
Picnic-Bot
8f5faf0f6a Upgrade OpenRewrite Templating 1.6.3 -> 1.6.4 (#1142)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.6.4
- https://github.com/openrewrite/rewrite-templating/compare/v1.6.3...v1.6.4
2024-04-19 09:55:53 +02:00
Picnic-Bot
5fad0ea04f Upgrade Spring Security 6.2.3 -> 6.2.4 (#1140)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.2.4
- https://github.com/spring-projects/spring-security/compare/6.2.3...6.2.4
2024-04-17 08:01:53 +02:00
Stephan Schroevers
4558f8affb Update FluxTake Refaster rule for Reactor 3.5.0+ (#1128) 2024-04-16 17:04:48 +02:00
Picnic-Bot
7be27614da Upgrade maven-jar-plugin 3.3.0 -> 3.4.0 (#1137)
See:
- https://github.com/apache/maven-jar-plugin/releases/tag/maven-jar-plugin-3.4.0
- https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.3.0...maven-jar-plugin-3.4.0
2024-04-15 08:45:16 +02:00
Picnic-Bot
7118d6bf03 Upgrade Spring 6.1.5 -> 6.1.6 (#1133)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.1.6
- https://github.com/spring-projects/spring-framework/compare/v6.1.5...v6.1.6
2024-04-15 08:32:41 +02:00
Picnic-Bot
eb84ddf500 Upgrade maven-gpg-plugin 3.2.2 -> 3.2.3 (#1134)
See:
- https://github.com/apache/maven-gpg-plugin/releases/tag/maven-gpg-plugin-3.2.3
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.2...maven-gpg-plugin-3.2.3
2024-04-15 07:44:29 +02:00
Picnic-Bot
032109756d Upgrade SLF4J 2.0.12 -> 2.0.13 (#1136)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_2.0.12...v_2.0.13
2024-04-15 07:36:02 +02:00
Picnic-Bot
9e230302e9 Upgrade Project Reactor 2023.0.4 -> 2023.0.5 (#1130)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.5
- https://github.com/reactor/reactor/compare/2023.0.4...2023.0.5
2024-04-11 09:46:18 +02:00
Picnic-Bot
4708fec201 Upgrade TestNG 7.10.0 -> 7.10.1 (#1131)
See:
- https://github.com/testng-team/testng/releases/tag/7.10.1
- https://github.com/testng-team/testng/compare/7.10.0...7.10.1
2024-04-10 15:10:21 +02:00
Picnic-Bot
d102d6acbb Upgrade pitest-maven-plugin 1.15.8 -> 1.16.0 (#1127)
See:
- https://github.com/hcoles/pitest/releases/tag/1.16.0
- https://github.com/hcoles/pitest/compare/1.15.8...1.16.0
2024-04-10 08:05:25 +02:00
Picnic-Bot
bc67883579 Upgrade TestNG 7.9.0 -> 7.10.0 (#1126)
See:
- https://github.com/testng-team/testng/releases/tag/7.10.0
- https://github.com/testng-team/testng/compare/7.9.0...7.10.0
2024-04-08 07:18:40 +02:00
Picnic-Bot
069d6ff2f4 Upgrade maven-source-plugin 3.3.0 -> 3.3.1 (#1125)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MSOURCES%20AND%20fixVersion%20%3E%203.3.0%20AND%20fixVersion%20%3C%3D%203.3.1
- https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.3.0...maven-source-plugin-3.3.1
2024-04-06 14:52:39 +02:00
Picnic-Bot
6fbf4d81f0 Upgrade OpenRewrite 2.8.1 -> 2.9.0 (#1123)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.9.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.8.1...v2.9.0
2024-04-06 13:04:51 +02:00
Picnic-Bot
3d51acd613 Upgrade MongoDB driver 5.0.0 -> 5.0.1 (#1121)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%205.0.0%20AND%20fixVersion%20%3C%3D%205.0.1
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.0.1
- https://github.com/mongodb/mongo-java-driver/compare/r5.0.0...r5.0.1
2024-04-04 14:48:14 +02:00
Picnic-Bot
d2fb576ecc Upgrade jacoco-maven-plugin 0.8.11 -> 0.8.12 (#1122)
See:
- https://github.com/jacoco/jacoco/releases/tag/v0.8.12
- https://github.com/jacoco/jacoco/compare/v0.8.11...v0.8.12
2024-04-04 14:31:03 +02:00
Stephan Schroevers
d658901231 Upgrade Error Prone fork v2.26.1-picnic-1 -> v2.26.1-picnic-2 (#1119)
See:
- https://github.com/PicnicSupermarket/error-prone/releases/tag/v2.26.1-picnic-2
- https://github.com/PicnicSupermarket/error-prone/compare/v2.26.1-picnic-1...v2.26.1-picnic-2
2024-04-03 16:46:24 +02:00
Picnic-Bot
76d1ca7bdf Upgrade Checkstyle 10.14.2 -> 10.15.0 (#1118)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.15.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.14.2...checkstyle-10.15.0
2024-04-03 11:22:32 +02:00
Picnic-Bot
341977b227 Upgrade Google Java Format 1.21.0 -> 1.22.0 (#1120)
See:
- https://github.com/google/google-java-format/releases/tag/v1.22.0
- https://github.com/google/google-java-format/compare/v1.21.0...v1.22.0
2024-04-03 08:27:53 +02:00
Rick Ossendrijver
75872dc2f5 Introduce Cody as IntelliJ icon (#1075) 2024-03-30 19:18:42 +01:00
Picnic-Bot
b609537a52 Upgrade pomchecker-maven-plugin 1.10.0 -> 1.11.0 (#1112)
See:
- https://github.com/kordamp/pomchecker/releases/tag/v1.11.0
- https://github.com/kordamp/pomchecker/compare/v1.10.0...v1.11.0
2024-03-30 15:09:54 +01:00
Picnic-Bot
1469d1e157 Upgrade maven-gpg-plugin 3.2.1 -> 3.2.2 (#1113)
See:
- https://github.com/apache/maven-gpg-plugin/releases/tag/maven-gpg-plugin-3.2.2
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.1...maven-gpg-plugin-3.2.2
2024-03-30 14:02:27 +01:00
Picnic-Bot
111b7d04f2 Upgrade actions/configure-pages v4.0.0 -> v5.0.0 (#1117)
See:
- https://github.com/actions/configure-pages/releases/tag/v5.0.0
2024-03-30 13:53:38 +01:00
Picnic-Bot
9e297df1c7 Upgrade errorprone-slf4j 0.1.22 -> 0.1.23 (#1111)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.23
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.22...v0.1.23
2024-03-30 13:27:28 +01:00
Picnic-Bot
7babb48751 Upgrade NullAway 0.10.24 -> 0.10.25 (#1116)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.25
- https://github.com/uber/NullAway/compare/v0.10.24...v0.10.25
2024-03-30 12:46:03 +01:00
Picnic-Bot
dfaffacbb5 Upgrade Byte Buddy 1.14.12 -> 1.14.13 (#1115)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.13
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.12...byte-buddy-1.14.13
2024-03-30 12:26:44 +01:00
Stephan Schroevers
769779cf21 Introduce Refaster rules that resolve EnumOrdinal violations (#1104) 2024-03-27 15:44:19 +01:00
Rick Ossendrijver
9d8a5af44a Start release notes with "Update considerations and deprecations" section (#1105) 2024-03-25 14:19:31 +01:00
Picnic-Bot
8a84acca7b Upgrade Forbidden APIs plugin 3.6 -> 3.7 (#1107)
See:
- https://github.com/policeman-tools/forbidden-apis/wiki/Changes
- https://github.com/policeman-tools/forbidden-apis/compare/3.6...3.7
2024-03-25 10:41:39 +01:00
Picnic-Bot
b551f90d38 Upgrade dawidd6/action-download-artifact v3.1.2 -> v3.1.4 (#1109)
See:
- https://github.com/dawidd6/action-download-artifact/releases/tag/v3.1.4
- https://github.com/dawidd6/action-download-artifact/releases/tag/v3.1.3
2024-03-25 10:12:27 +01:00
Picnic-Bot
789a9cc0aa Upgrade AspectJ 1.9.21.2 -> 1.9.22 (#1106)
See:
- https://github.com/eclipse-aspectj/aspectj/releases/tag/V1_9_22
- https://github.com/eclipse-aspectj/aspectj/compare/V1_9_21_2...V1_9_22
2024-03-25 09:53:18 +01:00
Picnic-Bot
13e35338af Upgrade ruby/setup-ruby v1.172.0 -> v1.173.0 (#1110)
See https://github.com/ruby/setup-ruby/releases/tag/v1.173.0
2024-03-25 09:43:35 +01:00
Stephan Schroevers
281a003dd7 Introduce OptionalOrElse check (#1024)
While there, extend the `OptionalIdentity` Refaster rule to
automatically resolve one class of `NestedOptionals` violations.
2024-03-25 09:29:17 +01:00
Picnic-Bot
e40df7e1b8 Upgrade CodeQL v3.24.5 -> v3.24.9 (#1108)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v3.24.8...v3.24.9
- https://github.com/github/codeql-action/compare/v3.24.7...v3.24.8
- https://github.com/github/codeql-action/compare/v3.24.6...v3.24.7
- https://github.com/github/codeql-action/compare/v3.24.5...v3.24.6
2024-03-25 08:42:59 +01:00
Picnic-Bot
bb2b1e6034 Upgrade Spring Boot 3.2.3 -> 3.2.4 (#1103)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.2.4
- https://github.com/spring-projects/spring-boot/compare/v3.2.3...v3.2.4
2024-03-23 12:49:26 +01:00
Stephan Schroevers
f8cac19330 Compact and replace StreamIs{,Not}Empty Refaster rules (#1028)
The new `StreamFindAnyIs{Empty,Present}` rules are simpler thanks to the
use of `@AlsoNegation`. In some cases an additional application of the
`OptionalIsEmpty` rule will be required.
2024-03-22 08:23:18 +01:00
Picnic-Bot
52fe79c343 Upgrade Swagger 2.2.20 -> 2.2.21 (#1102)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.21
- https://github.com/swagger-api/swagger-core/compare/v2.2.20...v2.2.21
2024-03-22 08:11:48 +01:00
Picnic-Bot
0b696b95b6 Upgrade maven-compiler-plugin 3.12.1 -> 3.13.0 (#1101)
See:
- https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-3.13.0
- https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.12.1...maven-compiler-plugin-3.13.0
2024-03-21 10:39:37 +01:00
Picnic-Bot
63bc903f83 Upgrade Spring Security 6.2.2 -> 6.2.3 (#1093)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.2.3
- https://github.com/spring-projects/spring-security/compare/6.2.2...6.2.3
2024-03-21 08:17:04 +01:00
Stephan Schroevers
b166d0daea Update Error Prone compatibility matrix (#1092)
While there, improve the generation script.
2024-03-21 07:31:07 +01:00
Picnic-Bot
6914dae822 Upgrade swagger-annotations 1.6.13 -> 1.6.14 (#1100)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.13
- https://github.com/swagger-api/swagger-core/compare/v1.6.12...v1.6.13
2024-03-20 17:46:13 +01:00
Picnic-Bot
c5fb53d725 Upgrade Guava 33.0.0-jre -> 33.1.0-jre (#1086)
See:
- https://guava.dev/releases/33.1.0-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v33.1.0
- https://github.com/google/guava/compare/v33.0.0...v33.1.0
2024-03-20 10:59:23 +01:00
Picnic-Bot
d36d20da08 Upgrade OpenRewrite Templating 1.6.2 -> 1.6.3 (#1099)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.6.3
- https://github.com/openrewrite/rewrite-templating/compare/v1.6.2...v1.6.3
2024-03-20 08:35:53 +01:00
Picnic-Bot
502281f4d3 Upgrade maven-gpg-plugin 3.2.0 -> 3.2.1 (#1096)
See:
- https://github.com/apache/maven-gpg-plugin/releases/tag/maven-gpg-plugin-3.2.1
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.0...maven-gpg-plugin-3.2.1
2024-03-20 08:06:38 +01:00
Picnic-Bot
daa4f19c57 Upgrade OpenRewrite 2.8.0 -> 2.8.1 (#1098)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.8.1
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.8.0...v2.8.1
2024-03-20 07:42:57 +01:00
Picnic-Bot
02f726f43c Upgrade git-commit-id-maven-plugin 8.0.1 -> 8.0.2 (#1095)
See:
- https://github.com/git-commit-id/git-commit-id-maven-plugin/releases/tag/v8.0.2
- https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v8.0.1...v8.0.2
2024-03-19 11:57:38 +01:00
Picnic-Bot
b9e8186159 Upgrade actions/deploy-pages v4.0.4 -> v4.0.5 (#1094)
See:
- https://github.com/actions/deploy-pages/releases/tag/v4.0.5
2024-03-19 10:55:56 +01:00
Picnic-Bot
85baadd5df Upgrade Error Prone 2.25.0 -> 2.26.1 (#1078)
See:
- https://github.com/google/error-prone/releases/tag/v2.26.0
- https://github.com/google/error-prone/releases/tag/v2.26.1
- https://github.com/google/error-prone/compare/v2.25.0...v2.26.1
- https://github.com/PicnicSupermarket/error-prone/compare/v2.25.0-picnic-2...v2.26.1-picnic-1
2024-03-19 08:07:43 +01:00
Picnic-Bot
ab871ec9bb Upgrade Checkstyle 10.14.0 -> 10.14.2 (#1079)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.14.1
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.14.2
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.14.0...checkstyle-10.14.2
2024-03-18 15:26:27 +01:00
Picnic-Bot
753928f4da Upgrade Project Reactor 2023.0.3 -> 2023.0.4 (#1085)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.4
- https://github.com/reactor/reactor/compare/2023.0.3...2023.0.4
2024-03-18 14:29:36 +01:00
Picnic-Bot
fe84bada33 Upgrade AspectJ 1.9.21.1 -> 1.9.21.2 (#1089)
See:
- https://github.com/eclipse-aspectj/aspectj/releases/tag/V1_9_21_2
- https://github.com/eclipse/org.aspectj/compare/V1_9_21_1...V1_9_21_2
2024-03-18 12:54:41 +01:00
Picnic-Bot
5b8d6ed9c5 Upgrade Spring 6.1.4 -> 6.1.5 (#1091)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.1.5
- https://github.com/spring-projects/spring-framework/compare/v6.1.4...v6.1.5
2024-03-18 11:50:49 +01:00
Picnic-Bot
2ad2fdfb0f Upgrade sortpom-maven-plugin 3.4.0 -> 3.4.1 (#1077)
See:
- https://github.com/Ekryd/sortpom/wiki/Versions
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.4.1
- https://github.com/Ekryd/sortpom/compare/sortpom-parent-3.4.0...sortpom-parent-3.4.1
2024-03-18 11:01:03 +01:00
Picnic-Bot
a10558a044 Upgrade maven-gpg-plugin 3.1.0 -> 3.2.0 (#1082)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MGPG%20AND%20fixVersion%20%3E%203.1.0%20AND%20fixVersion%20%3C%3D%203.2.0
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.1.0...maven-gpg-plugin-3.2.0
2024-03-18 10:00:55 +01:00
Picnic-Bot
7316d05c22 Upgrade sonar-maven-plugin 3.10.0.2594 -> 3.11.0.3922 (#1090)
See:
- https://github.com/SonarSource/sonar-scanner-maven/releases/tag/3.11.0.3922
- https://github.com/SonarSource/sonar-scanner-maven/compare/3.10.0.2594...3.11.0.3922
2024-03-18 09:43:40 +01:00
Picnic-Bot
3177db55b8 Upgrade OpenRewrite 2.7.1 -> 2.8.0 (#1081)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.8.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.7.1...v2.8.0
2024-03-18 08:45:48 +01:00
Picnic-Bot
a6a63f9553 Upgrade Jackson 2.16.2 -> 2.17.0 (#1087)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.17
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.16.2...jackson-bom-2.17.0
2024-03-18 07:14:09 +01:00
Rick Ossendrijver
df0eb9ee2f Drop unused field in Slf4jLogStatementTest (#1084) 2024-03-17 10:49:53 +01:00
Stephan Schroevers
e3cda3ea49 [maven-release-plugin] prepare for next development iteration 2024-03-15 13:04:44 +01:00
76 changed files with 3284 additions and 175 deletions

8
.github/release.yml vendored
View File

@@ -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"

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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
View File

@@ -4,6 +4,7 @@
.DS_Store
.factorypath
.idea
!.idea/icon.svg
.project
.settings
target

65
.idea/icon.svg generated Normal file
View 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

View File

@@ -12,7 +12,7 @@
"separateMinorPatch": true
},
{
"matchDepNames": [
"matchPackageNames": [
"dawidd6/action-download-artifact",
"github/codeql-action",
"ruby/setup-ruby"

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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());
}
}

View File

@@ -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) {

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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));

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);",
"",

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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() {

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
View 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
View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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();
}

View File

@@ -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>

View File

@@ -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>

View 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

View 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>

View 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!"

View File

@@ -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);
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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()));
}
}

View File

@@ -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));
}
}

View File

@@ -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();
}
}

View File

@@ -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());
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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() {}
}

View File

@@ -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))));
}
}

View File

@@ -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());
}
}
}

View File

@@ -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());
}
}

View File

@@ -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))));
}
}

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,4 @@
/** Picnic Refaster rules. */
@com.google.errorprone.annotations.CheckReturnValue
@org.jspecify.annotations.NullMarked
package tech.picnic.errorprone.testngjunit.refasterrules;

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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());
}
}
}

View File

@@ -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"

View File

@@ -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}"