diff --git a/src/main/java/org/openrewrite/java/testing/junit6/RemoveInterceptDynamicTest.java b/src/main/java/org/openrewrite/java/testing/junit6/RemoveInterceptDynamicTest.java index 4aa06e65c..804125e2b 100644 --- a/src/main/java/org/openrewrite/java/testing/junit6/RemoveInterceptDynamicTest.java +++ b/src/main/java/org/openrewrite/java/testing/junit6/RemoveInterceptDynamicTest.java @@ -21,33 +21,62 @@ import org.openrewrite.Preconditions; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.search.DeclaresMethod; import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Statement; + +import static org.openrewrite.java.VariableNameUtils.GenerationStrategy.INCREMENT_NUMBER; +import static org.openrewrite.java.VariableNameUtils.generateVariableName; public class RemoveInterceptDynamicTest extends Recipe { - private static final MethodMatcher INTERCEPT_DYNAMIC_TEST_MATCHER = new MethodMatcher( - "org.junit.jupiter.api.extension.InvocationInterceptor interceptDynamicTest(..)", true); + private static final String DYNAMIC_TEST_INVOCATION_CONTEXT = "org.junit.jupiter.api.extension.DynamicTestInvocationContext"; + private static final MethodMatcher TWO_ARGUMENT_INTERCEPT_DYNAMIC_TEST = new MethodMatcher("org.junit.jupiter.api.extension.InvocationInterceptor interceptDynamicTest(org.junit.jupiter.api.extension.InvocationInterceptor$Invocation, org.junit.jupiter.api.extension.ExtensionContext)", true); + private static final MethodMatcher THREE_ARGUMENT_INTERCEPT_DYNAMIC_TEST = new MethodMatcher("org.junit.jupiter.api.extension.InvocationInterceptor interceptDynamicTest(org.junit.jupiter.api.extension.InvocationInterceptor$Invocation, " + DYNAMIC_TEST_INVOCATION_CONTEXT + ", org.junit.jupiter.api.extension.ExtensionContext)", true); @Getter - final String displayName = "Remove `InvocationInterceptor.interceptDynamicTest`"; + final String displayName = "Migrate the two-argument `InvocationInterceptor.interceptDynamicTest`"; @Getter - final String description = "JUnit 6 removed the `interceptDynamicTest(Invocation, ExtensionContext)` method from " + - "`InvocationInterceptor`. This recipe removes implementations of this deprecated method."; + final String description = "JUnit 6 removed the deprecated `InvocationInterceptor#interceptDynamicTest(Invocation, ExtensionContext)`. " + + "Java overrides gain a `DynamicTestInvocationContext` parameter, so they keep their body and override the remaining three-argument overload. " + + "Overrides in classes that already override the three-argument overload, and non-Java overrides, are removed."; @Override public TreeVisitor getVisitor() { - return Preconditions.check(new DeclaresMethod<>(INTERCEPT_DYNAMIC_TEST_MATCHER), new JavaIsoVisitor() { + return Preconditions.check(new DeclaresMethod<>(TWO_ARGUMENT_INTERCEPT_DYNAMIC_TEST), new JavaIsoVisitor() { @Override public J.@Nullable MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { J.MethodDeclaration md = super.visitMethodDeclaration(method, ctx); - if (INTERCEPT_DYNAMIC_TEST_MATCHER.matches(md.getMethodType())) { + JavaType.Method methodType = md.getMethodType(); + if (methodType == null || !TWO_ARGUMENT_INTERCEPT_DYNAMIC_TEST.matches(methodType)) { + return md; + } + if (getCursor().firstEnclosing(J.CompilationUnit.class) == null || + methodType.getDeclaringType().getMethods().stream().anyMatch(THREE_ARGUMENT_INTERCEPT_DYNAMIC_TEST::matches)) { return null; } - return md; + + String parameterName = generateVariableName("invocationContext", getCursor(), INCREMENT_NUMBER); + J.MethodDeclaration withContext = JavaTemplate.builder("DynamicTestInvocationContext " + parameterName) + .imports(DYNAMIC_TEST_INVOCATION_CONTEXT) + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "junit-jupiter-api-6")) + .build() + .apply(getCursor(), md.getCoordinates().replaceParameters()); + Statement contextParameter = withContext.getParameters().get(0).withPrefix(md.getParameters().get(1).getPrefix()); + JavaType contextType = withContext.getMethodType().getParameterTypes().get(0); + maybeAddImport(DYNAMIC_TEST_INVOCATION_CONTEXT); + return md + .withParameters(ListUtils.insert(md.getParameters(), contextParameter, 1)) + .withMethodType(methodType + .withParameterNames(ListUtils.insert(methodType.getParameterNames(), parameterName, 1)) + .withParameterTypes(ListUtils.insert(methodType.getParameterTypes(), contextType, 1))); } }); } diff --git a/src/main/resources/META-INF/rewrite/recipes.csv b/src/main/resources/META-INF/rewrite/recipes.csv index 05e4b50fe..b4c4badb0 100644 --- a/src/main/resources/META-INF/rewrite/recipes.csv +++ b/src/main/resources/META-INF/rewrite/recipes.csv @@ -208,7 +208,7 @@ maven,org.openrewrite.recipe:rewrite-testing-frameworks,org.openrewrite.java.tes maven,org.openrewrite.recipe:rewrite-testing-frameworks,org.openrewrite.java.testing.junit6.MinimumJreConditions,Migrate JUnit JRE conditions,"This recipe will: - Remove tests that are only active on JREs that are below the specified version. - Adjust ranges to use minimum the specified version.",1,JUnit 6,Testing,Java,Recipes for migrating to [JUnit 6](https://junit.org/).,,Basic building blocks for transforming Java code.,"[{""name"":""javaVersion"",""type"":""String"",""displayName"":""JRE version"",""description"":""The minimum JRE version to use for test conditions."",""example"":""17"",""required"":true}]", -maven,org.openrewrite.recipe:rewrite-testing-frameworks,org.openrewrite.java.testing.junit6.RemoveInterceptDynamicTest,Remove `InvocationInterceptor.interceptDynamicTest`,"JUnit 6 removed the `interceptDynamicTest(Invocation, ExtensionContext)` method from `InvocationInterceptor`. This recipe removes implementations of this deprecated method.",1,JUnit 6,Testing,Java,Recipes for migrating to [JUnit 6](https://junit.org/).,,Basic building blocks for transforming Java code.,, +maven,org.openrewrite.recipe:rewrite-testing-frameworks,org.openrewrite.java.testing.junit6.RemoveInterceptDynamicTest,Migrate the two-argument `InvocationInterceptor.interceptDynamicTest`,"JUnit 6 removed the deprecated `InvocationInterceptor#interceptDynamicTest(Invocation, ExtensionContext)`. Java overrides gain a `DynamicTestInvocationContext` parameter, so they keep their body and override the remaining three-argument overload. Overrides in classes that already override the three-argument overload, and non-Java overrides, are removed.",1,JUnit 6,Testing,Java,Recipes for migrating to [JUnit 6](https://junit.org/).,,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-testing-frameworks,org.openrewrite.java.testing.junit6.RemoveJreOther,Remove deprecated `JRE.OTHER` from `@EnabledOnJre`/`@DisabledOnJre` arrays,JUnit 6.1 deprecated `JRE.OTHER` in favor of `int`/`int[]` annotation attributes. This recipe removes `JRE.OTHER` entries from `@EnabledOnJre` and `@DisabledOnJre` array values when other JRE constants remain. Lone `JRE.OTHER` usages are left untouched because they have no mechanical replacement; review them manually.,1,JUnit 6,Testing,Java,Recipes for migrating to [JUnit 6](https://junit.org/).,,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-testing-frameworks,org.openrewrite.java.testing.mockito.AddJUnit4ReplacingPowerMockModule,Add JUnit 4 where the PowerMock JUnit 4 module provided it,"Adds `junit:junit` to modules that use JUnit 4 and depend on `powermock-module-junit4`, which brings JUnit 4 in transitively, so that their tests still compile once the PowerMock dependencies are removed. A module that declares `junit:junit` itself is left as it is.",2,Mockito,Testing,Java,,,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-testing-frameworks,org.openrewrite.java.testing.mockito.AddMockitoExtensionIfAnnotationsUsed,Adds Mockito extensions to Mockito tests,Adds `@ExtendWith(MockitoExtension.class)` to JUnit 5 tests or `@RunWith(MockitoJUnitRunner.class)` to JUnit 4 tests using Mockito annotations like `@Mock` or `@Captor`.,1,Mockito,Testing,Java,,,Basic building blocks for transforming Java code.,, diff --git a/src/test/java/org/openrewrite/java/testing/junit6/RemoveInterceptDynamicTestTest.java b/src/test/java/org/openrewrite/java/testing/junit6/RemoveInterceptDynamicTestTest.java index 6b10f0239..e748de107 100644 --- a/src/test/java/org/openrewrite/java/testing/junit6/RemoveInterceptDynamicTestTest.java +++ b/src/test/java/org/openrewrite/java/testing/junit6/RemoveInterceptDynamicTestTest.java @@ -36,13 +36,12 @@ public void defaults(RecipeSpec spec) { @DocumentExample @Test - void removeInterceptDynamicTestMethod() { + void addInvocationContextParameter() { rewriteRun( java( """ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.InvocationInterceptor; - import org.junit.jupiter.api.extension.ReflectiveInvocationContext; class MyInterceptor implements InvocationInterceptor { @Override @@ -51,28 +50,126 @@ public void interceptDynamicTest(Invocation invocation, ExtensionContext e invocation.proceed(); System.out.println("After dynamic test"); } + } + """, + """ + import org.junit.jupiter.api.extension.DynamicTestInvocationContext; + import org.junit.jupiter.api.extension.ExtensionContext; + import org.junit.jupiter.api.extension.InvocationInterceptor; + class MyInterceptor implements InvocationInterceptor { @Override - public void interceptTestMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { + public void interceptDynamicTest(Invocation invocation, DynamicTestInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { + System.out.println("Before dynamic test"); + invocation.proceed(); + System.out.println("After dynamic test"); + } + } + """ + ) + ); + } + + @Test + void avoidClashWithExistingName() { + rewriteRun( + java( + """ + import org.junit.jupiter.api.extension.ExtensionContext; + import org.junit.jupiter.api.extension.InvocationInterceptor; + + class MyInterceptor implements InvocationInterceptor { + private final String invocationContext = "dynamic"; + + @Override + public void interceptDynamicTest(Invocation invocation, ExtensionContext extensionContext) throws Throwable { + System.out.println(invocationContext); + invocation.proceed(); + } + } + """, + """ + import org.junit.jupiter.api.extension.DynamicTestInvocationContext; + import org.junit.jupiter.api.extension.ExtensionContext; + import org.junit.jupiter.api.extension.InvocationInterceptor; + + class MyInterceptor implements InvocationInterceptor { + private final String invocationContext = "dynamic"; + + @Override + public void interceptDynamicTest(Invocation invocation, DynamicTestInvocationContext invocationContext1, ExtensionContext extensionContext) throws Throwable { + System.out.println(invocationContext); + invocation.proceed(); + } + } + """ + ) + ); + } + + @Test + void removeTwoArgumentOverloadWhenThreeArgumentOverloadIsDeclared() { + rewriteRun( + java( + """ + import org.junit.jupiter.api.extension.DynamicTestInvocationContext; + import org.junit.jupiter.api.extension.ExtensionContext; + import org.junit.jupiter.api.extension.InvocationInterceptor; + + class MyInterceptor implements InvocationInterceptor { + @Override + public void interceptDynamicTest(Invocation invocation, ExtensionContext extensionContext) throws Throwable { invocation.proceed(); } - private static class Method {} + @Override + public void interceptDynamicTest(Invocation invocation, DynamicTestInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { + System.out.println(invocationContext.getExecutable()); + invocation.proceed(); + } } """, """ + import org.junit.jupiter.api.extension.DynamicTestInvocationContext; + import org.junit.jupiter.api.extension.ExtensionContext; + import org.junit.jupiter.api.extension.InvocationInterceptor; + + class MyInterceptor implements InvocationInterceptor { + + @Override + public void interceptDynamicTest(Invocation invocation, DynamicTestInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { + System.out.println(invocationContext.getExecutable()); + invocation.proceed(); + } + } + """ + ) + ); + } + + @Test + void keepThreeArgumentOverload() { + rewriteRun( + java( + """ + import java.lang.reflect.Method; + + import org.junit.jupiter.api.extension.DynamicTestInvocationContext; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.InvocationInterceptor; import org.junit.jupiter.api.extension.ReflectiveInvocationContext; class MyInterceptor implements InvocationInterceptor { + @Override + public void interceptDynamicTest(Invocation invocation, DynamicTestInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { + System.out.println(invocationContext.getExecutable()); + invocation.proceed(); + } @Override public void interceptTestMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { invocation.proceed(); } - - private static class Method {} } """ )