diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index d64cd4917..e6441136f 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index b6114cae7..cdaec8840 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
+distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
diff --git a/src/main/java/org/openrewrite/java/testing/junit5/AddJupiterDependencies.java b/src/main/java/org/openrewrite/java/testing/junit5/AddJupiterDependencies.java
new file mode 100644
index 000000000..928a7646f
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/testing/junit5/AddJupiterDependencies.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.junit5;
+
+import lombok.EqualsAndHashCode;
+import lombok.Value;
+import org.openrewrite.*;
+import org.openrewrite.gradle.marker.GradleDependencyConfiguration;
+import org.openrewrite.gradle.marker.GradleProject;
+import org.openrewrite.groovy.GroovyIsoVisitor;
+import org.openrewrite.groovy.tree.G;
+import org.openrewrite.internal.lang.Nullable;
+import org.openrewrite.java.dependencies.AddDependency;
+import org.openrewrite.maven.MavenIsoVisitor;
+import org.openrewrite.maven.tree.ResolvedDependency;
+import org.openrewrite.maven.tree.Scope;
+import org.openrewrite.xml.tree.Xml;
+
+import java.util.List;
+import java.util.Optional;
+
+@Value
+@EqualsAndHashCode(callSuper = false)
+public class AddJupiterDependencies extends ScanningRecipe {
+ @Override
+ public String getDisplayName() {
+ return "Add JUnit Jupiter dependencies";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Adds JUnit Jupiter dependencies to a Maven or Gradle project. " +
+ "Junit Jupiter can be added either with the artifact junit-jupiter, or both of junit-jupiter-api and junit-jupiter-engine. " +
+ "This adds \"junit-jupiter\" dependency unless \"junit-jupiter-api\" or \"junit-jupiter-engine\" are already present.";
+ }
+
+ @Override
+ public AddDependency.Accumulator getInitialValue(ExecutionContext ctx) {
+ return addJupiterDependency().getInitialValue(ctx);
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getScanner(AddDependency.Accumulator acc) {
+ return addJupiterDependency().getScanner(acc);
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor(AddDependency.Accumulator acc) {
+ AddJupiterGradle gv = new AddJupiterGradle(acc);
+ AddJupiterMaven mv = new AddJupiterMaven(acc);
+ return new TreeVisitor() {
+ @Override
+ public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx, Cursor parent) {
+ if(!(tree instanceof SourceFile)) {
+ return tree;
+ }
+ SourceFile s = (SourceFile) tree;
+ if(gv.isAcceptable(s, ctx)) {
+ s = (SourceFile) gv.visitNonNull(s, ctx);
+ }
+ if(mv.isAcceptable(s, ctx)) {
+ s = (SourceFile) mv.visitNonNull(s, ctx);
+ }
+ return s;
+ }
+ };
+ }
+
+ private static AddDependency addJupiterDependency() {
+ return new AddDependency("org.junit.jupiter", "junit-jupiter", "5.x", null,
+ "org.junit..*", null, null, null, null, "test",
+ null, null, null, null);
+ }
+
+ @Value
+ @EqualsAndHashCode(callSuper = false)
+ private static class AddJupiterGradle extends GroovyIsoVisitor {
+ AddDependency.Accumulator acc;
+
+ @Override
+ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit t, ExecutionContext ctx) {
+ Optional maybeGp = t.getMarkers().findFirst(GradleProject.class);
+ if(!maybeGp.isPresent()) {
+ return t;
+ }
+ GradleProject gp = maybeGp.get();
+ GradleDependencyConfiguration trc = gp.getConfiguration("testRuntimeClasspath");
+ if(trc == null) {
+ return t;
+ }
+ ResolvedDependency jupiterApi = trc.findResolvedDependency("org.junit.jupiter", "junit-jupiter-api");
+ if(jupiterApi == null) {
+ t = (G.CompilationUnit) addJupiterDependency().getVisitor(acc)
+ .visitNonNull(t, ctx);
+ }
+
+ return t;
+ }
+ }
+
+ @Value
+ @EqualsAndHashCode(callSuper = false)
+ private static class AddJupiterMaven extends MavenIsoVisitor {
+ AddDependency.Accumulator acc;
+ @Override
+ public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) {
+ Xml.Document d = document;
+ List jupiterApi = getResolutionResult().findDependencies("org.junit.jupiter", "junit-jupiter-api", Scope.Test);
+ if(jupiterApi.isEmpty()) {
+ d = (Xml.Document) addJupiterDependency().getVisitor(acc)
+ .visitNonNull(d, ctx);
+ }
+ return d;
+ }
+ }
+}
diff --git a/src/main/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiter.java b/src/main/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiter.java
new file mode 100644
index 000000000..995408803
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiter.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.junit5;
+
+import lombok.EqualsAndHashCode;
+import lombok.Value;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.gradle.GradleParser;
+import org.openrewrite.gradle.marker.GradleProject;
+import org.openrewrite.groovy.GroovyIsoVisitor;
+import org.openrewrite.groovy.tree.G;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.internal.lang.Nullable;
+import org.openrewrite.java.MethodMatcher;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeUtils;
+
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+import static java.util.Objects.requireNonNull;
+
+@Value
+@EqualsAndHashCode(callSuper = false)
+public class GradleUseJunitJupiter extends Recipe {
+ @Override
+ public String getDisplayName() {
+ return "Gradle `Test` use JUnit Jupiter";
+ }
+
+ @Override
+ public String getDescription() {
+ return "By default Gradle's `Test` tasks use JUnit 4. " +
+ "Gradle `Test` tasks must be configured with `useJUnitPlatform()` to run JUnit Jupiter tests. " +
+ "This recipe adds the `useJUnitPlatform()` method call to the `Test` task configuration.";
+ }
+
+ private static final String USE_JUNIT_PLATFORM_PATTERN = "org.gradle.api.tasks.testing.Test useJUnitPlatform()";
+ private static final MethodMatcher USE_JUNIT_PLATFORM_MATCHER = new MethodMatcher(USE_JUNIT_PLATFORM_PATTERN);
+ private static final MethodMatcher USE_JUNIT4_MATCHER = new MethodMatcher("org.gradle.api.tasks.testing.Test useJUnit()");
+ private static final MethodMatcher USE_JUNIT4_ALTERNATE_MATCHER = new MethodMatcher("RewriteTestSpec useJUnit()");
+ private static final MethodMatcher TEST_DSL_MATCHER = new MethodMatcher("RewriteGradleProject test(..)");
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ //noinspection NotNullFieldNotInitialized
+ return new GroovyIsoVisitor() {
+
+ GradleProject gp;
+
+ @Override
+ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit compilationUnit, ExecutionContext ctx) {
+ //noinspection DataFlowIssue
+ gp = compilationUnit.getMarkers().findFirst(GradleProject.class).orElse(null);
+ if(gp == null) {
+ return compilationUnit;
+ }
+ if(gp.getPlugins().stream().noneMatch(plugin -> plugin.getFullyQualifiedClassName().contains("org.gradle.api.plugins.JavaBasePlugin"))) {
+ return compilationUnit;
+ }
+ if(containsJUnitPlatformInvocation(compilationUnit)) {
+ return compilationUnit;
+ }
+ // If anywhere in the tree there is a useJunit() we can swap it out for useJUnitPlatform() and be done in one step
+ G.CompilationUnit cu = (G.CompilationUnit) new UpdateExistingUseJunit4()
+ .visitNonNull(compilationUnit, ctx, requireNonNull(getCursor().getParent()));
+ if (cu != compilationUnit) {
+ return cu;
+ }
+ // No useJUnit(), but there might already be configuration of a Test task, add useJUnitPlatform() to it
+ cu = (G.CompilationUnit) new AddJUnitPlatformToExistingTestDsl()
+ .visitNonNull(cu, ctx, requireNonNull(getCursor().getParent()));
+ if(cu != compilationUnit) {
+ return cu;
+ }
+ // No existing test task configuration seems to exist, add a whole new one
+ return (G.CompilationUnit) new AddUseJUnitPlatform()
+ .visitNonNull(cu, ctx, getCursor().getParent());
+ }
+ };
+ }
+
+ private static boolean containsJUnitPlatformInvocation(G.CompilationUnit cu) {
+ AtomicBoolean found = new AtomicBoolean(false);
+ new GroovyIsoVisitor() {
+ @Override
+ public @Nullable J preVisit(J tree, AtomicBoolean found) {
+ if(found.get()) {
+ stopAfterPreVisit();
+ return tree;
+ }
+ return super.preVisit(tree, found);
+ }
+
+ @Override
+ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation m, AtomicBoolean found) {
+ // Groovy gradle scripts being weakly type-attributed means we will miss likely-correct changes if we are too strict
+ if ("useJUnitPlatform".equals(m.getSimpleName()) && (m.getArguments().isEmpty() || m.getArguments().size() == 1 && m.getArguments().get(0) instanceof J.Empty)) {
+ found.set(true);
+ return m;
+ }
+ return super.visitMethodInvocation(m, found);
+ }
+ }.visit(cu, found);
+ return found.get();
+ }
+
+ private static class UpdateExistingUseJunit4 extends GroovyIsoVisitor {
+ @Override
+ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
+ J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
+ // Groovy gradle scripts being weakly type-attributed means we will miss changes if we are too strict
+ if ("useJUnit".equals(m.getSimpleName()) && (m.getArguments().isEmpty() || m.getArguments().size() == 1 && m.getArguments().get(0) instanceof J.Empty)) {
+ JavaType.Method useJUnitPlatformType = Optional.ofNullable(m.getMethodType())
+ .map(JavaType.Method::getDeclaringType)
+ .flatMap(declaringType -> declaringType.getMethods()
+ .stream()
+ .filter(method1 -> method1.getName().equals("useJUnitPlatform"))
+ .findFirst())
+ .orElse(null);
+ return m.withName(m.getName().withSimpleName("useJUnitPlatform"))
+ .withMethodType(useJUnitPlatformType);
+ }
+ return m;
+ }
+ }
+
+ private static class AddUseJUnitPlatform extends GroovyIsoVisitor {
+ @Override
+ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) {
+ G.CompilationUnit template = GradleParser.builder()
+ .build()
+ .parse("plugins {\n" +
+ " id 'java'\n" +
+ "}\n" +
+ "tasks.withType(Test).configureEach {\n" +
+ " useJUnitPlatform()\n" +
+ "}")
+ .map(G.CompilationUnit.class::cast)
+ .collect(Collectors.toList())
+ .get(0);
+ J.MethodInvocation configureEachInvocation = (J.MethodInvocation) template.getStatements().get(1);
+ return cu.withStatements(ListUtils.concat(cu.getStatements(), configureEachInvocation));
+ }
+ }
+
+ private static class AddJUnitPlatformToExistingTestDsl extends GroovyIsoVisitor {
+ @Override
+ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
+ J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
+ String mName = m.getSimpleName();
+ // A non-exhaustive list of common ways by which the task may already be configured
+ // test { }
+ // tasks.withType(Test) { }
+ // tasks.withType(Test).configureEach { }
+ // tasks.named("test") { }
+ // tasks.named("test", Test) { }
+ switch (mName) {
+ case "test":
+ if (!(m.getArguments().size() == 1 && m.getArguments().get(0) instanceof J.Lambda)) {
+ return m;
+ }
+ // Other DSLs may be named "test" so only assume it is test {} if it isn't enclosed in anything else
+ if(getCursor().getParentTreeCursor().firstEnclosing(J.MethodInvocation.class) != null) {
+ return m;
+ }
+ break;
+ case "named":
+ if (m.getArguments().isEmpty()) {
+ return m;
+ }
+ if (!(m.getArguments().get(0) instanceof J.Literal && "test".equals(((J.Literal) m.getArguments().get(0)).getValue()))) {
+ return m;
+ }
+ // The final argument must be a J.Lambda
+ if (!(m.getArguments().get(m.getArguments().size() - 1) instanceof J.Lambda)) {
+ return m;
+ }
+ break;
+ case "withType":
+ if (m.getSelect() == null
+ || !TypeUtils.isOfClassType(m.getSelect().getType(), "org.gradle.api.tasks.TaskContainer")
+ || !(m.getArguments().get(0) instanceof J.Identifier && "Test".equals(((J.Identifier) m.getArguments().get(0)).getSimpleName()))) {
+ return m;
+ }
+ break;
+ case "configureEach":
+ if(m.getArguments().size() != 1 || !(m.getArguments().get(0) instanceof J.Lambda)) {
+ return m;
+ }
+ if(m.getSelect() == null || !(m.getSelect() instanceof J.MethodInvocation)) {
+ return m;
+ }
+ J.MethodInvocation select = (J.MethodInvocation) m.getSelect();
+ if(!"withType".equals(select.getSimpleName())
+ || select.getArguments().size() != 1
+ || !(select.getArguments().get(0) instanceof J.Identifier)
+ || !"Test".equals(((J.Identifier) select.getArguments().get(0)).getSimpleName())) {
+ return m;
+ }
+ break;
+ default:
+ return m;
+ }
+
+ return (J.MethodInvocation) new AddJUnitPlatformAsLastStatementInClosure()
+ .visitNonNull(m, ctx, requireNonNull(getCursor().getParent()));
+ }
+ }
+
+ private static class AddJUnitPlatformAsLastStatementInClosure extends GroovyIsoVisitor {
+ @Override
+ public J.Lambda visitLambda(J.Lambda l, ExecutionContext ctx) {
+ if(!(l.getBody() instanceof J.Block)) {
+ return l;
+ }
+ G.CompilationUnit cu = GradleParser.builder()
+ .build()
+ .parse("plugins {\n" +
+ " id 'java'\n" +
+ "}\n" +
+ "tasks.withType(Test) {\n" +
+ " useJUnitPlatform()\n" +
+ "}")
+ .map(G.CompilationUnit.class::cast)
+ .collect(Collectors.toList())
+ .get(0);
+ J.MethodInvocation useJUnitPlatform = Optional.of(cu.getStatements().get(1))
+ .map(J.MethodInvocation.class::cast)
+ .map(J.MethodInvocation::getArguments)
+ .map(args -> args.get(1))
+ .map(J.Lambda.class::cast)
+ .map(J.Lambda::getBody)
+ .map(J.Block.class::cast)
+ .map(J.Block::getStatements)
+ .map(statements -> statements.get(0))
+ .map(J.Return.class::cast)
+ .map(J.Return::getExpression)
+ .map(J.MethodInvocation.class::cast)
+ .orElse(null);
+ if(useJUnitPlatform == null) {
+ return l;
+ }
+ J.Block b = (J.Block) l.getBody();
+ l = l.withBody(b.withStatements(ListUtils.concat(b.getStatements(), useJUnitPlatform)));
+ return autoFormat(l, ctx, requireNonNull(getCursor().getParent()));
+ }
+ }
+}
diff --git a/src/main/resources/META-INF/rewrite/junit5.yml b/src/main/resources/META-INF/rewrite/junit5.yml
index 99f3aa9a2..90cf92e59 100755
--- a/src/main/resources/META-INF/rewrite/junit5.yml
+++ b/src/main/resources/META-INF/rewrite/junit5.yml
@@ -113,12 +113,7 @@ recipeList:
- org.openrewrite.maven.ExcludeDependency:
groupId: org.junit.vintage
artifactId: junit-vintage-engine
- - org.openrewrite.java.dependencies.AddDependency:
- groupId: org.junit.jupiter
- artifactId: junit-jupiter
- version: 5.x
- onlyIfUsing: org.junit..*
- scope: test
+ - org.openrewrite.java.testing.junit5.AddJupiterDependencies
- org.openrewrite.java.dependencies.AddDependency:
groupId: org.junit.jupiter
artifactId: junit-jupiter-params
@@ -146,6 +141,7 @@ recipeList:
groupId: org.apache.maven.plugins
artifactId: maven-failsafe-plugin
newVersion: 3.1.x
+ - org.openrewrite.java.testing.junit5.GradleUseJunitJupiter
---
type: specs.openrewrite.org/v1beta/recipe
diff --git a/src/test/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiterTest.java b/src/test/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiterTest.java
new file mode 100644
index 000000000..6fc646912
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/testing/junit5/GradleUseJunitJupiterTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.junit5;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.gradle.Assertions.buildGradle;
+import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi;
+
+class GradleUseJunitJupiterTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new GradleUseJunitJupiter())
+ .beforeRecipe(withToolingApi());
+ }
+
+ @DocumentExample
+ @Test
+ void addWhenMissing() {
+ rewriteRun(
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java-library'
+ }
+ tasks.named('classes') { }
+ tasks.withType(JavaCompile) { }
+ tasks.withType(JavaCompile).configureEach { }
+ """,
+ """
+ plugins {
+ id 'java-library'
+ }
+ tasks.named('classes') { }
+ tasks.withType(JavaCompile) { }
+ tasks.withType(JavaCompile).configureEach { }
+ tasks.withType(Test).configureEach {
+ useJUnitPlatform()
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dsl() {
+ rewriteRun(
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java'
+ }
+ test {
+ }
+ """,
+ """
+ plugins {
+ id 'java'
+ }
+ test {
+ useJUnitPlatform()
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dslAlreadyExists() {
+ rewriteRun(
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java'
+ }
+ test {
+ useJUnit()
+ }
+ """,
+ """
+ plugins {
+ id 'java'
+ }
+ test {
+ useJUnitPlatform()
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void tasksWithTypeTest() {
+ rewriteRun(
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java'
+ }
+ tasks.withType(Test) {
+ }
+ """,
+ """
+ plugins {
+ id 'java'
+ }
+ tasks.withType(Test) {
+ useJUnitPlatform()
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void tasksWithTypeTestConfigureEach() {
+ rewriteRun(
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java'
+ }
+ tasks.withType(Test).configureEach {
+ }
+ """,
+ """
+ plugins {
+ id 'java'
+ }
+ tasks.withType(Test).configureEach {
+ useJUnitPlatform()
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void tasksNamedTest() {
+ rewriteRun(
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java'
+ }
+ tasks.named('test', Test) {
+ }
+ """,
+ """
+ plugins {
+ id 'java'
+ }
+ tasks.named('test', Test) {
+ useJUnitPlatform()
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void tasksNamedTestNoType() {
+ rewriteRun(
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java'
+ }
+ tasks.named('test') {
+ }
+ """,
+ """
+ plugins {
+ id 'java'
+ }
+ tasks.named('test') {
+ useJUnitPlatform()
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void leaveOtherTestDslAlone() {
+ rewriteRun(
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java'
+ }
+ sourceSets {
+ test {
+ java {
+ srcDir 'src/test/java'
+ }
+ }
+ }
+ """,
+ """
+ plugins {
+ id 'java'
+ }
+ sourceSets {
+ test {
+ java {
+ srcDir 'src/test/java'
+ }
+ }
+ }
+ tasks.withType(Test).configureEach {
+ useJUnitPlatform()
+ }
+ """
+ )
+ );
+ }
+}
diff --git a/src/test/java/org/openrewrite/java/testing/junit5/JUnit5MigrationTest.java b/src/test/java/org/openrewrite/java/testing/junit5/JUnit5MigrationTest.java
index 030a1004e..022b61840 100644
--- a/src/test/java/org/openrewrite/java/testing/junit5/JUnit5MigrationTest.java
+++ b/src/test/java/org/openrewrite/java/testing/junit5/JUnit5MigrationTest.java
@@ -23,9 +23,17 @@
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;
+import java.util.List;
+import java.util.regex.MatchResult;
+import java.util.regex.Pattern;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.openrewrite.gradle.Assertions.buildGradle;
+import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi;
import static org.openrewrite.java.Assertions.java;
import static org.openrewrite.maven.Assertions.pomXml;
+@SuppressWarnings({"NewClassNamingConvention", "EqualsWithItself", "deprecation", "LanguageMismatch"})
class JUnit5MigrationTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
@@ -46,7 +54,7 @@ void classReference() {
java(
"""
import org.junit.Test;
-
+
public class Sample {
void method() {
Class c = Test.class;
@@ -55,7 +63,7 @@ void method() {
""",
"""
import org.junit.jupiter.api.Test;
-
+
public class Sample {
void method() {
Class c = Test.class;
@@ -75,10 +83,10 @@ void assertThatReceiver() {
"""
import org.junit.Assert;
import org.junit.Test;
-
+
import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.containsInAnyOrder;
-
+
public class SampleTest {
@SuppressWarnings("ALL")
@Test
@@ -90,11 +98,11 @@ public void filterShouldRemoveUnusedConfig() {
""",
"""
import org.junit.jupiter.api.Test;
-
+
import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
-
+
public class SampleTest {
@SuppressWarnings("ALL")
@Test
@@ -112,8 +120,8 @@ public void filterShouldRemoveUnusedConfig() {
@Issue("https://github.com/openrewrite/rewrite-testing-frameworks/issues/279")
void upgradeMavenPluginVersions() {
rewriteRun(
- //language=xml
pomXml(
+ //language=xml
"""
4.0.0
@@ -136,28 +144,15 @@ void upgradeMavenPluginVersions() {
""",
- """
-
- 4.0.0
- com.example.jackson
- test-plugins
- 1.0.0
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 2.22.2
-
-
- org.apache.maven.plugins
- maven-failsafe-plugin
- 2.22.2
-
-
-
-
- """
+ spec -> spec.after(actual -> {
+ List list = Pattern.compile("(.*)")
+ .matcher(actual).results().skip(1).toList();
+ assertThat(list)
+ .hasSize(2)
+ .extracting(mr -> mr.group(1))
+ .allMatch(m -> m.startsWith("3."));
+ return actual;
+ })
)
);
}
@@ -239,7 +234,7 @@ void assertEqualsWithArrayArgumentToAssertArrayEquals() {
java(
"""
import org.junit.Assert;
-
+
class MyTest {
void test() {
Assert.assertEquals(new Object[1], new Object[1]);
@@ -248,7 +243,7 @@ void test() {
""",
"""
import org.junit.jupiter.api.Assertions;
-
+
class MyTest {
void test() {
Assertions.assertArrayEquals(new Object[1], new Object[1]);
@@ -269,16 +264,16 @@ void migrateInheritedTestBeforeAfterAnnotations() {
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-
+
public class AbstractTest {
@Before
public void before() {
}
-
+
@After
public void after() {
}
-
+
@Test
public void test() {
}
@@ -288,16 +283,16 @@ public void test() {
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-
+
public class AbstractTest {
@BeforeEach
public void before() {
}
-
+
@AfterEach
public void after() {
}
-
+
@Test
public void test() {
}
@@ -309,10 +304,10 @@ public void test() {
public class A extends AbstractTest {
public void before() {
}
-
+
public void after() {
}
-
+
public void test() {
}
}
@@ -326,11 +321,11 @@ public class A extends AbstractTest {
@BeforeEach
public void before() {
}
-
+
@AfterEach
public void after() {
}
-
+
@Test
public void test() {
}
@@ -340,4 +335,44 @@ public void test() {
);
}
+ @Test
+ void noJunitDependencyIfApiAlreadyPresent() {
+ rewriteRun(
+ spec -> spec.beforeRecipe(withToolingApi()),
+ //language=groovy
+ buildGradle(
+ """
+ plugins {
+ id 'java-library'
+ }
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
+ }
+ tasks.withType(Test).configureEach {
+ useJUnitPlatform()
+ }
+ """),
+ //language=xml
+ pomXml(
+ """
+
+ 4.0.0
+ dev.ted
+ testcontainer-migrate
+ 0.0.1
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.7.2
+ test
+
+
+
+ """)
+ );
+ }
}