Skip to content

Commit 263a222

Browse files
amishra-utimtebeek
andauthored
Add support for CsvSource migration (#706)
* Add support for CsvSource migration * Adopt Annotated Trait to simplify argument wrangling --------- Co-authored-by: Tim te Beek <[email protected]>
1 parent fd6cf53 commit 263a222

File tree

2 files changed

+163
-32
lines changed

2 files changed

+163
-32
lines changed

src/main/java/org/openrewrite/java/testing/junit5/JUnitParamsRunnerToParameterized.java

+57-32
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import org.openrewrite.internal.ListUtils;
2121
import org.openrewrite.java.*;
2222
import org.openrewrite.java.search.UsesType;
23+
import org.openrewrite.java.trait.Annotated;
24+
import org.openrewrite.java.trait.Literal;
25+
import org.openrewrite.java.trait.Traits;
2326
import org.openrewrite.java.tree.Expression;
2427
import org.openrewrite.java.tree.J;
2528
import org.openrewrite.java.tree.Space;
@@ -47,8 +50,10 @@ public class JUnitParamsRunnerToParameterized extends Recipe {
4750
private static final AnnotationMatcher PARAMETERS_MATCHER = new AnnotationMatcher("@junitparams.Parameters");
4851
private static final AnnotationMatcher TEST_CASE_NAME_MATCHER = new AnnotationMatcher("@junitparams.naming.TestCaseName");
4952
private static final AnnotationMatcher NAMED_PARAMETERS_MATCHER = new AnnotationMatcher("@junitparams.NamedParameters");
53+
private static final AnnotationMatcher CONVERTER_MATCHER = new AnnotationMatcher("@junitparams.converters.Param");
5054

5155
private static final String INIT_METHOD_REFERENCES = "init-method-references";
56+
private static final String CSV_PARAMS = "csv-params";
5257
private static final String PARAMETERS_FOR_PREFIX = "parametersFor";
5358
private static final String PARAMETERIZED_TESTS = "parameterized-tests";
5459
private static final String INIT_METHODS_MAP = "named-parameters-map";
@@ -78,8 +83,9 @@ private static class ParameterizedTemplateVisitor extends JavaIsoVisitor<Executi
7883
@Override
7984
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
8085
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);
81-
Set<String> initMethods = getCursor().getMessage(INIT_METHOD_REFERENCES);
82-
if (initMethods != null && !initMethods.isEmpty()) {
86+
Set<String> initMethods = getCursor().computeMessageIfAbsent(INIT_METHOD_REFERENCES, v -> new HashSet<>());
87+
Boolean hasCsvParams = getCursor().getMessage(CSV_PARAMS);
88+
if (!initMethods.isEmpty() || Boolean.TRUE.equals(hasCsvParams)) {
8389
doAfterVisit(new ParametersNoArgsImplicitMethodSource(initMethods,
8490
getCursor().computeMessageIfAbsent(INIT_METHODS_MAP, v -> new HashMap<>()),
8591
getCursor().computeMessageIfAbsent(CONVERSION_NOT_SUPPORTED, v -> new HashSet<>()),
@@ -105,13 +111,17 @@ public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ct
105111
J.Annotation anno = super.visitAnnotation(annotation, ctx);
106112
Cursor classDeclCursor = getCursor().dropParentUntil(J.ClassDeclaration.class::isInstance);
107113
if (PARAMETERS_MATCHER.matches(anno)) {
114+
Annotated annotated = Traits.annotated(PARAMETERS_MATCHER).require(annotation, getCursor().getParentOrThrow());
115+
String annotationArgumentValue = getAnnotationArgumentForInitMethod(annotated, "method", "named");
108116
classDeclCursor.computeMessageIfAbsent(PARAMETERIZED_TESTS, v -> new HashSet<>())
109117
.add(getCursor().firstEnclosing(J.MethodDeclaration.class).getSimpleName());
110-
String annotationArgumentValue = getAnnotationArgumentForInitMethod(anno, "method", "named");
111118
if (annotationArgumentValue != null) {
112119
for (String method : annotationArgumentValue.split(",")) {
113120
classDeclCursor.computeMessageIfAbsent(INIT_METHOD_REFERENCES, v -> new HashSet<>()).add(method);
114121
}
122+
} else if (isSupportedCsvParam(annotated)) {
123+
anno = getCsVParamTemplate(ctx).apply(updateCursor(anno), anno.getCoordinates().replace(), anno.getArguments().get(0));
124+
classDeclCursor.putMessage(CSV_PARAMS, Boolean.TRUE);
115125
} else if (anno.getArguments() != null && !anno.getArguments().isEmpty()) {
116126
// This conversion is not supported add a comment to the annotation and the method name to the not supported list
117127
String comment = " JunitParamsRunnerToParameterized conversion not supported";
@@ -125,48 +135,62 @@ public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ct
125135
unsupportedMethods.add(junitParamsDefaultInitMethodName(m.getSimpleName()));
126136
}
127137
} else if (NAMED_PARAMETERS_MATCHER.matches(annotation)) {
128-
String namedInitMethod = getLiteralAnnotationArgumentValue(annotation);
129-
if (namedInitMethod != null) {
138+
Annotated annotated = Traits.annotated(NAMED_PARAMETERS_MATCHER).require(annotation, getCursor().getParentOrThrow());
139+
Optional<Literal> value = annotated.getDefaultAttribute("value");
140+
if (value.isPresent()) {
130141
J.MethodDeclaration m = getCursor().dropParentUntil(J.MethodDeclaration.class::isInstance).getValue();
131142
classDeclCursor.computeMessageIfAbsent(INIT_METHOD_REFERENCES, v -> new HashSet<>()).add(m.getSimpleName());
132-
classDeclCursor.computeMessageIfAbsent(INIT_METHODS_MAP, v -> new HashMap<>()).put(namedInitMethod, m.getSimpleName());
143+
classDeclCursor.computeMessageIfAbsent(INIT_METHODS_MAP, v -> new HashMap<>()).put(value.get().getString(), m.getSimpleName());
133144
}
134145
} else if (TEST_CASE_NAME_MATCHER.matches(anno)) {
146+
Annotated annotated = Traits.annotated(TEST_CASE_NAME_MATCHER).require(annotation, getCursor().getParentOrThrow());
135147
// test name for ParameterizedTest argument
136-
Object testNameArg = getLiteralAnnotationArgumentValue(anno);
137-
String testName = testNameArg != null ? testNameArg.toString() : "{method}({params}) [{index}]";
138-
J.MethodDeclaration md = getCursor().dropParentUntil(J.MethodDeclaration.class::isInstance).getValue();
139-
classDeclCursor.computeMessageIfAbsent(INIT_METHODS_MAP, v -> new HashMap<>()).put(md.getSimpleName(), testName);
148+
Optional<Literal> value = annotated.getDefaultAttribute("value");
149+
if (value.isPresent()) {
150+
Object testNameArg = value.get().getString();
151+
String testName = testNameArg != null ? testNameArg.toString() : "{method}({params}) [{index}]";
152+
J.MethodDeclaration md = getCursor().dropParentUntil(J.MethodDeclaration.class::isInstance).getValue();
153+
classDeclCursor.computeMessageIfAbsent(INIT_METHODS_MAP, v -> new HashMap<>()).put(md.getSimpleName(), testName);
154+
}
140155
}
141156
return anno;
142157
}
143158

144-
private @Nullable String getLiteralAnnotationArgumentValue(J.Annotation anno) {
145-
String annotationArgumentValue = null;
146-
if (anno.getArguments() != null && anno.getArguments().size() == 1 && anno.getArguments().get(0) instanceof J.Literal) {
147-
J.Literal literal = (J.Literal) anno.getArguments().get(0);
148-
annotationArgumentValue = literal.getValue() != null ? literal.getValue().toString() : null;
159+
private @Nullable String getAnnotationArgumentForInitMethod(Annotated annotated, String... variableNames) {
160+
for (String variableName : variableNames) {
161+
Optional<Literal> attribute = annotated.getAttribute(variableName);
162+
if (attribute.isPresent()) {
163+
return attribute.get().getString();
164+
}
149165
}
150-
return annotationArgumentValue;
166+
return null;
151167
}
152168

153-
private @Nullable String getAnnotationArgumentForInitMethod(J.Annotation anno, String... variableNames) {
154-
String value = null;
155-
if (anno.getArguments() != null && anno.getArguments().size() == 1 &&
156-
anno.getArguments().get(0) instanceof J.Assignment &&
157-
((J.Assignment) anno.getArguments().get(0)).getVariable() instanceof J.Identifier &&
158-
((J.Assignment) anno.getArguments().get(0)).getAssignment() instanceof J.Literal) {
159-
J.Assignment annoArg = (J.Assignment) anno.getArguments().get(0);
160-
J.Literal assignment = (J.Literal) annoArg.getAssignment();
161-
String identifier = ((J.Identifier) annoArg.getVariable()).getSimpleName();
162-
for (String variableName : variableNames) {
163-
if (variableName.equals(identifier)) {
164-
value = assignment.getValue() != null ? assignment.getValue().toString() : null;
165-
break;
166-
}
167-
}
169+
private boolean isSupportedCsvParam(Annotated annotated) {
170+
if (annotated.getTree().getArguments() == null || annotated.getTree().getArguments().size() != 1) {
171+
return false;
168172
}
169-
return value;
173+
Optional<Literal> value = annotated.getDefaultAttribute("value");
174+
return value.isPresent() &&
175+
value.get().isArray() &&
176+
!doTestParamsHaveCustomConverter(getCursor().firstEnclosing(J.MethodDeclaration.class));
177+
}
178+
179+
private boolean doTestParamsHaveCustomConverter(J.@Nullable MethodDeclaration method) {
180+
if (method == null) {
181+
return false;
182+
}
183+
return method.getParameters().stream()
184+
.filter(param -> param instanceof J.VariableDeclarations)
185+
.map(J.VariableDeclarations.class::cast)
186+
.anyMatch(v -> v.getLeadingAnnotations().stream().anyMatch(CONVERTER_MATCHER::matches));
187+
}
188+
189+
private static JavaTemplate getCsVParamTemplate(ExecutionContext ctx) {
190+
return JavaTemplate.builder("@CsvSource(#{any(java.lang.String[])})")
191+
.imports("org.junit.jupiter.params.provider.CsvSource")
192+
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "junit-jupiter-params"))
193+
.build();
170194
}
171195
}
172196

@@ -228,6 +252,7 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex
228252
maybeRemoveImport("junitparams.naming.TestCaseName");
229253
maybeAddImport("org.junit.jupiter.params.ParameterizedTest");
230254
maybeAddImport("org.junit.jupiter.params.provider.MethodSource");
255+
maybeAddImport("org.junit.jupiter.params.provider.CsvSource");
231256
return cd;
232257
}
233258

src/test/java/org/openrewrite/java/testing/junit5/JUnitParamsRunnerToParameterizedTest.java

+106
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,112 @@ private static Object named3() {
197197
);
198198
}
199199

200+
@Test
201+
void csvSource() {
202+
//language=java
203+
rewriteRun(
204+
java(
205+
"""
206+
import org.junit.Test;
207+
import org.junit.runner.RunWith;
208+
import junitparams.JUnitParamsRunner;
209+
import junitparams.Parameters;
210+
211+
@RunWith(JUnitParamsRunner.class)
212+
class CsvSourceTests {
213+
@Test
214+
@Parameters({"Lav,20", "Katy,25"})
215+
public void csvSource(String name, int age) { }
216+
}
217+
""",
218+
"""
219+
import org.junit.jupiter.params.ParameterizedTest;
220+
import org.junit.jupiter.params.provider.CsvSource;
221+
222+
class CsvSourceTests {
223+
@ParameterizedTest
224+
@CsvSource({"Lav,20", "Katy,25"})
225+
public void csvSource(String name, int age) { }
226+
}
227+
"""
228+
)
229+
);
230+
}
231+
232+
@Test
233+
void csvSourceWithExplicitValue() {
234+
//language=java
235+
rewriteRun(
236+
java(
237+
"""
238+
import org.junit.Test;
239+
import org.junit.runner.RunWith;
240+
import junitparams.JUnitParamsRunner;
241+
import junitparams.Parameters;
242+
243+
@RunWith(JUnitParamsRunner.class)
244+
class CsvSourceTests {
245+
@Test
246+
@Parameters(value = {"Lav,20", "Katy,25"})
247+
public void csvSource(String name, int age) { }
248+
}
249+
""",
250+
"""
251+
import org.junit.jupiter.params.ParameterizedTest;
252+
import org.junit.jupiter.params.provider.CsvSource;
253+
254+
class CsvSourceTests {
255+
@ParameterizedTest
256+
@CsvSource(value = {"Lav,20", "Katy,25"})
257+
public void csvSource(String name, int age) { }
258+
}
259+
"""
260+
)
261+
);
262+
}
263+
264+
@Test
265+
void csvSourceWithCustomConverterNotConverted() {
266+
//language=java
267+
rewriteRun(
268+
java(
269+
"""
270+
import org.junit.Test;
271+
import org.junit.runner.RunWith;
272+
import java.util.Date;
273+
import junitparams.converters.Param;
274+
import junitparams.JUnitParamsRunner;
275+
import junitparams.Parameters;
276+
import junitparams.converters.NullableConverter;
277+
278+
@RunWith(JUnitParamsRunner.class)
279+
class CsvSourceTests {
280+
@Test
281+
@Parameters({"01.12.2012"})
282+
public void csvSource(@Param(converter = NullableConverter.class) Date date) { }
283+
}
284+
""",
285+
"""
286+
import org.junit.Test;
287+
import org.junit.runner.RunWith;
288+
import java.util.Date;
289+
import junitparams.converters.Param;
290+
import junitparams.JUnitParamsRunner;
291+
import junitparams.Parameters;
292+
import junitparams.converters.NullableConverter;
293+
294+
@RunWith(JUnitParamsRunner.class)
295+
class CsvSourceTests {
296+
@Test
297+
// JunitParamsRunnerToParameterized conversion not supported
298+
@Parameters({"01.12.2012"})
299+
public void csvSource(@Param(converter = NullableConverter.class) Date date) { }
300+
}
301+
"""
302+
)
303+
);
304+
}
305+
200306
@Test
201307
void enumSourceNotConverted() {
202308
//language=java

0 commit comments

Comments
 (0)