Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1 add recipe to migrate dataprovider annotation #10

Merged
merged 12 commits into from
Apr 26, 2024
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.github.mboegers.openrewrite.testngtojupiter.parameterized;

import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.*;
import org.openrewrite.java.tree.J;

import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class MigrateDataProvider extends Recipe {
@Override
public String getDisplayName() {
return "Migrate @DataProvider utilities";
}

@Override
public String getDescription() {
return "Wrap `@DataProvider` methods into a Jupiter parameterized test MethodSource.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new MigrateDataProviderVisitor();
}

private class MigrateDataProviderVisitor extends JavaIsoVisitor<ExecutionContext> {
private static final AnnotationMatcher DATAPROVIDER_MATCHER = new AnnotationMatcher("@org.testng.annotations.DataProvider");

private static final JavaTemplate methodeSourceTemplate = JavaTemplate.builder("""
public static Stream<Arguments> #{}Source() {
return Arrays.stream(#{}()).map(Arguments::of);
}
""")
.imports("org.junit.jupiter.params.provider.Arguments", "java.util.Arrays", "java.util.stream.Stream")
.contextSensitive()
.javaParser(JavaParser.fromJavaVersion()
.logCompilationWarningsAndErrors(true)
.classpath("junit-jupiter-api", "junit-jupiter-params", "testng"))
.build();
private static final RemoveAnnotationVisitor removeAnnotationVisitor = new RemoveAnnotationVisitor(DATAPROVIDER_MATCHER);

@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, org.openrewrite.ExecutionContext executionContext) {
classDecl = super.visitClassDeclaration(classDecl, executionContext);
MBoegers marked this conversation as resolved.
Show resolved Hide resolved

Set<J.MethodDeclaration> dataProviders = classDecl.getBody().getStatements().stream()
.filter(J.MethodDeclaration.class::isInstance)
.map(J.MethodDeclaration.class::cast)
.filter(m -> m.getLeadingAnnotations().stream().anyMatch(DATAPROVIDER_MATCHER::matches))
.collect(Collectors.toSet());

for (J.MethodDeclaration provider : dataProviders) {
String providerMethodName = provider.getSimpleName();
String providerName = provider.getLeadingAnnotations().stream()
.filter(DATAPROVIDER_MATCHER::matches)
.map(J.Annotation::getArguments)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(J.Assignment.class::isInstance)
.map(J.Assignment.class::cast)
.filter(a -> "name".equals(((J.Identifier) a.getVariable()).getSimpleName()))
.map(J.Assignment::getAssignment)
.filter(J.Literal.class::isInstance)
.map(J.Literal.class::cast)
.map(J.Literal::getValue)
.map(Objects::toString)
.findAny()
.orElse(providerMethodName);

classDecl = classDecl.withBody(methodeSourceTemplate.apply(
new Cursor(getCursor(), classDecl.getBody()), classDecl.getBody().getCoordinates().lastStatement(),
providerName, providerMethodName));
}

doAfterVisit(new RemoveAnnotationVisitor(DATAPROVIDER_MATCHER));
maybeRemoveImport("org.testng.annotations.DataProvider");
maybeAddImport("org.junit.jupiter.params.provider.Arguments");
maybeAddImport("java.util.Arrays");
maybeAddImport("java.util.stream.Stream");

return classDecl;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.github.mboegers.openrewrite.testngtojupiter.parameterized;

import org.intellij.lang.annotations.Language;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openrewrite.java.JavaParser;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.java.Assertions.java;

class MigrateDataProviderTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
spec.parser(JavaParser.fromJavaVersion()
.logCompilationWarningsAndErrors(true)
.classpath("junit-jupiter-api", "junit-jupiter-params", "testng"))
.recipe(new MigrateDataProvider());
}

@Nested
class Wrap {
/*
* annotation parameter other than name are ignored
*/
@Test
void withName() {
@Language("java") String is = """
import org.testng.annotations.DataProvider;

public class BoxPrimitiveDataProvider {
@DataProvider(name = "anotherBoxPrimitiveDataProvider")
public static Object[][] boxPrimitiveDataProvider() { /*...*/ }
}
""";
@Language("java") String should = """
import org.junit.jupiter.params.provider.Arguments;

import java.util.Arrays;
import java.util.stream.Stream;

public class BoxPrimitiveDataProvider {
public static Object[][] boxPrimitiveDataProvider() { /*...*/ }

public static Stream<Arguments> anotherBoxPrimitiveDataProviderSource() {
return Arrays.stream(boxPrimitiveDataProvider()).map(Arguments::of);
}
}
""";
rewriteRun(java(is, should));
}

@Test
void withDefaultName() {
@Language("java") String is = """
import org.testng.annotations.DataProvider;

public class BoxPrimitiveDataProvider {
@DataProvider
public static Object[][] boxPrimitiveDataProvider() { /*...*/ }
}
""";
@Language("java") String should = """
import org.junit.jupiter.params.provider.Arguments;

import java.util.Arrays;
import java.util.stream.Stream;

public class BoxPrimitiveDataProvider {
public static Object[][] boxPrimitiveDataProvider() { /*...*/ }

public static Stream<Arguments> boxPrimitiveDataProviderSource() {
return Arrays.stream(boxPrimitiveDataProvider()).map(Arguments::of);
}
}
""";
rewriteRun(java(is, should));
}
}
}
Loading