Compare commits

...

208 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
50 changed files with 2718 additions and 98 deletions

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@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
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@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
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,10 +39,10 @@ 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@5f19ec79cedfadb78ab837f95b87734d0003c899 # v1.173.0
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
with:
working-directory: ./website
bundler-cache: true
@@ -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

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@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
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,16 +20,18 @@ 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

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

View File

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

View File

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

@@ -290,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,
@@ -305,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);
}
}
@@ -357,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,
@@ -372,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);
}
}

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.

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

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

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

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

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

83
pom.xml
View File

@@ -48,6 +48,7 @@
<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">
@@ -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.26.1</version.error-prone-orig>
<version.error-prone-slf4j>0.1.23</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.25</version.nullaway>
<version.nullaway>0.11.0</version.nullaway>
<version.pitest-git>1.1.4</version.pitest-git>
<version.rewrite-templating>1.6.3</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.17.0</version>
<version>2.17.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -338,7 +339,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-bom</artifactId>
<version>33.1.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.4</version>
<version>2023.0.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -377,12 +378,12 @@
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.21</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.13</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.22</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.1</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.9.0</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.5</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.4</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>6.2.3</version>
<version>6.3.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.10.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.1</version>
<version>4.0.0</version>
<configuration>
<createBackupFile>false</createBackupFile>
<encoding>${project.build.sourceEncoding}</encoding>
@@ -624,7 +625,7 @@
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
<version>8.0.2</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.15.0</version>
<version>10.17.0</version>
</dependency>
<dependency>
<groupId>io.spring.nohttp</groupId>
@@ -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.2.2</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>
@@ -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
@@ -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.11.0.3922</version>
<version>4.0.0.4121</version>
</plugin>
</plugins>
</pluginManagement>

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

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

@@ -3,6 +3,8 @@
releases:
- version: 0.16.1
compatible:
- "2.27.1"
- "2.27.0"
- "2.26.1"
- "2.26.0"
- "2.25.0"
@@ -11,6 +13,8 @@ releases:
- "2.23.0"
- version: 0.16.0
compatible:
- "2.27.1"
- "2.27.0"
- "2.26.1"
- "2.26.0"
- "2.25.0"
@@ -19,6 +23,8 @@ releases:
- "2.23.0"
- version: 0.15.0
compatible:
- "2.27.1"
- "2.27.0"
- "2.26.1"
- "2.26.0"
- "2.25.0"
@@ -27,6 +33,8 @@ releases:
- "2.23.0"
- version: 0.14.0
compatible:
- "2.27.1"
- "2.27.0"
- "2.26.1"
- "2.26.0"
- "2.25.0"