diff --git a/build.gradle.kts b/build.gradle.kts index a5334ec16..6447c9476 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -71,8 +71,9 @@ dependencies { exclude(group = "org.yaml", module = "snakeyaml") } testRuntimeOnly("org.easymock:easymock:latest.release") - testRuntimeOnly("org.testng:testng:latest.release") + testRuntimeOnly("org.jboss.arquillian.junit:arquillian-junit-core:latest.release") testRuntimeOnly("org.mockito.kotlin:mockito-kotlin:latest.release") testRuntimeOnly("org.testcontainers:testcontainers:latest.release") testRuntimeOnly("org.testcontainers:nginx:latest.release") + testRuntimeOnly("org.testng:testng:latest.release") } diff --git a/src/main/java/org/openrewrite/java/testing/arquillian/ReplaceArquillianInSequenceAnnotation.java b/src/main/java/org/openrewrite/java/testing/arquillian/ReplaceArquillianInSequenceAnnotation.java new file mode 100644 index 000000000..5dd34af5c --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/arquillian/ReplaceArquillianInSequenceAnnotation.java @@ -0,0 +1,88 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.arquillian; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.*; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.service.AnnotationService; +import org.openrewrite.java.tree.J; + +import java.util.Comparator; + +public class ReplaceArquillianInSequenceAnnotation extends Recipe { + + @Override + public String getDisplayName() { + return "Arquillian JUnit 4 `@InSequence` to JUnit Jupiter `@Order`"; + } + + @Override + public String getDescription() { + return "Transforms the Arquillian JUnit 4 `@InSequence` to the JUnit Jupiter `@Order`."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check( + new UsesType<>("org.jboss.arquillian.junit.InSequence", false), + new JavaIsoVisitor() { + private final String IN_SEQUENCE = "org.jboss.arquillian.junit.InSequence"; + private final String TEST_METHOD_ORDER = "org.junit.jupiter.api.TestMethodOrder"; + private final String METHOD_ORDERER = "org.junit.jupiter.api.MethodOrderer"; + private final AnnotationMatcher IN_SEQUENCE_MATCHER = new AnnotationMatcher("@" + IN_SEQUENCE); + private final AnnotationMatcher TEST_METHOD_ORDER_MATCHER = new AnnotationMatcher("@" + TEST_METHOD_ORDER); + + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { + doAfterVisit(new ChangeType(IN_SEQUENCE, "org.junit.jupiter.api.Order", true).getVisitor()); + return super.visitClassDeclaration(classDecl, ctx); + } + + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { + J.MethodDeclaration m = super.visitMethodDeclaration(method, ctx); + if (service(AnnotationService.class).matches(updateCursor(m), IN_SEQUENCE_MATCHER)) { + J.ClassDeclaration classWithInSequenceMethods = getCursor().firstEnclosing(J.ClassDeclaration.class); + if (classWithInSequenceMethods != null) { + doAfterVisit(new JavaIsoVisitor() { + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { + J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx); + if (cd.getName().equals(classWithInSequenceMethods.getName()) && + !service(AnnotationService.class).matches(updateCursor(cd), TEST_METHOD_ORDER_MATCHER)) { + maybeAddImport(METHOD_ORDERER); + maybeAddImport(TEST_METHOD_ORDER); + return JavaTemplate.builder("@TestMethodOrder(MethodOrderer.class)") + .imports(METHOD_ORDERER, TEST_METHOD_ORDER) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "junit-jupiter-api-5")) + .build() + .apply(getCursor(), classDecl.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); + } + return cd; + } + }); + } + } + return m; + } + } + ); + } +} diff --git a/src/main/java/org/openrewrite/java/testing/arquillian/package-info.java b/src/main/java/org/openrewrite/java/testing/arquillian/package-info.java new file mode 100644 index 000000000..7b2e08cac --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/arquillian/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package org.openrewrite.java.testing.arquillian; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/resources/META-INF/rewrite/arquillian.yml b/src/main/resources/META-INF/rewrite/arquillian.yml new file mode 100644 index 000000000..58251f1cf --- /dev/null +++ b/src/main/resources/META-INF/rewrite/arquillian.yml @@ -0,0 +1,41 @@ +# +# Copyright 2024 the original author or authors. +#

+# Licensed under the Moderne Source Available License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +#

+# https://docs.moderne.io/licensing/moderne-source-available-license +#

+# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.testing.arquillian.ArquillianJUnit4ToArquillianJUnit5 +displayName: Use Arquillian JUnit 5 Extension +description: Migrates Arquillian JUnit 4 to JUnit 5. +tags: + - testing + - junit + - arquillian +recipeList: + - org.openrewrite.java.testing.junit5.RunnerToExtension: + runners: + - org.jboss.arquillian.junit.Arquillian + extension: org.jboss.arquillian.junit5.ArquillianExtension + - org.openrewrite.java.dependencies.ChangeDependency: + oldGroupId: org.jboss.arquillian.junit + oldArtifactId: arquillian-junit-container + newGroupId: org.jboss.arquillian.junit5 + newArtifactId: arquillian-junit5-container + newVersion: x + - org.openrewrite.java.testing.arquillian.ReplaceArquillianInSequenceAnnotation + - org.openrewrite.java.ChangePackage: + oldPackageName: org.jboss.arquillian.junit + newPackageName: org.jboss.arquillian.junit5 + recursive: true diff --git a/src/main/resources/META-INF/rewrite/junit5.yml b/src/main/resources/META-INF/rewrite/junit5.yml index 490fc67aa..d32fd41d9 100755 --- a/src/main/resources/META-INF/rewrite/junit5.yml +++ b/src/main/resources/META-INF/rewrite/junit5.yml @@ -142,6 +142,7 @@ recipeList: - org.openrewrite.java.ChangeType: oldFullyQualifiedTypeName: org.jbehave.core.junit.JUnitStories newFullyQualifiedTypeName: org.jbehave.core.junit.JupiterStories + - org.openrewrite.java.testing.arquillian.ArquillianJUnit4ToArquillianJUnit5 - org.openrewrite.java.testing.dbrider.MigrateDbRiderSpringToDbRiderJUnit5 --- @@ -322,4 +323,3 @@ recipeList: groupId: org.junit.platform artifactId: junit-platform-surefire-provider version: 1.1.0 - diff --git a/src/test/java/org/openrewrite/java/testing/arquillian/ArquillianJUnit4ToArquillianJunit5Test.java b/src/test/java/org/openrewrite/java/testing/arquillian/ArquillianJUnit4ToArquillianJunit5Test.java new file mode 100644 index 000000000..81134ce80 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/arquillian/ArquillianJUnit4ToArquillianJunit5Test.java @@ -0,0 +1,78 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.arquillian; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.mavenProject; +import static org.openrewrite.maven.Assertions.pomXml; + +class ArquillianJUnit4ToArquillianJunit5Test implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipeFromResource( + "/META-INF/rewrite/arquillian.yml", + "org.openrewrite.java.testing.arquillian.ArquillianJUnit4ToArquillianJUnit5"); + } + + @DocumentExample + @Test + void convert() { + rewriteRun( + mavenProject("project", + //language=xml + pomXml( + """ + + 4.0.0 + org.openrewrite + arquillian + 1.0-SNAPSHOT + + + org.jboss.arquillian.junit + arquillian-junit-container + 1.7.0.Final + test + + + + """, + """ + + 4.0.0 + org.openrewrite + arquillian + 1.0-SNAPSHOT + + + org.jboss.arquillian.junit5 + arquillian-junit5-container + 1.9.1.Final + test + + + + """ + ) + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/testing/arquillian/ReplaceArquillianInSequenceAnnotationTest.java b/src/test/java/org/openrewrite/java/testing/arquillian/ReplaceArquillianInSequenceAnnotationTest.java new file mode 100644 index 000000000..ee41cac14 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/arquillian/ReplaceArquillianInSequenceAnnotationTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.testing.arquillian; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class ReplaceArquillianInSequenceAnnotationTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion().classpath("arquillian-junit-core")) + .recipe(new ReplaceArquillianInSequenceAnnotation()); + } + + @DocumentExample + @Test + void replaceInSequenceAnnotation() { + rewriteRun( + //language=java + java( + """ + import org.jboss.arquillian.junit.InSequence; + + class A { + @InSequence(2) + void second() {} + + @InSequence(1) + void first() {} + } + """, + """ + import org.junit.jupiter.api.MethodOrderer; + import org.junit.jupiter.api.Order; + import org.junit.jupiter.api.TestMethodOrder; + + @TestMethodOrder(MethodOrderer.class) + class A { + @Order(2) + void second() {} + + @Order(1) + void first() {} + } + """ + ) + ); + } +}