20
20
import org .openrewrite .internal .ListUtils ;
21
21
import org .openrewrite .java .*;
22
22
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 ;
23
26
import org .openrewrite .java .tree .Expression ;
24
27
import org .openrewrite .java .tree .J ;
25
28
import org .openrewrite .java .tree .Space ;
@@ -47,8 +50,10 @@ public class JUnitParamsRunnerToParameterized extends Recipe {
47
50
private static final AnnotationMatcher PARAMETERS_MATCHER = new AnnotationMatcher ("@junitparams.Parameters" );
48
51
private static final AnnotationMatcher TEST_CASE_NAME_MATCHER = new AnnotationMatcher ("@junitparams.naming.TestCaseName" );
49
52
private static final AnnotationMatcher NAMED_PARAMETERS_MATCHER = new AnnotationMatcher ("@junitparams.NamedParameters" );
53
+ private static final AnnotationMatcher CONVERTER_MATCHER = new AnnotationMatcher ("@junitparams.converters.Param" );
50
54
51
55
private static final String INIT_METHOD_REFERENCES = "init-method-references" ;
56
+ private static final String CSV_PARAMS = "csv-params" ;
52
57
private static final String PARAMETERS_FOR_PREFIX = "parametersFor" ;
53
58
private static final String PARAMETERIZED_TESTS = "parameterized-tests" ;
54
59
private static final String INIT_METHODS_MAP = "named-parameters-map" ;
@@ -78,8 +83,9 @@ private static class ParameterizedTemplateVisitor extends JavaIsoVisitor<Executi
78
83
@ Override
79
84
public J .ClassDeclaration visitClassDeclaration (J .ClassDeclaration classDecl , ExecutionContext ctx ) {
80
85
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 )) {
83
89
doAfterVisit (new ParametersNoArgsImplicitMethodSource (initMethods ,
84
90
getCursor ().computeMessageIfAbsent (INIT_METHODS_MAP , v -> new HashMap <>()),
85
91
getCursor ().computeMessageIfAbsent (CONVERSION_NOT_SUPPORTED , v -> new HashSet <>()),
@@ -105,13 +111,17 @@ public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ct
105
111
J .Annotation anno = super .visitAnnotation (annotation , ctx );
106
112
Cursor classDeclCursor = getCursor ().dropParentUntil (J .ClassDeclaration .class ::isInstance );
107
113
if (PARAMETERS_MATCHER .matches (anno )) {
114
+ Annotated annotated = Traits .annotated (PARAMETERS_MATCHER ).require (annotation , getCursor ().getParentOrThrow ());
115
+ String annotationArgumentValue = getAnnotationArgumentForInitMethod (annotated , "method" , "named" );
108
116
classDeclCursor .computeMessageIfAbsent (PARAMETERIZED_TESTS , v -> new HashSet <>())
109
117
.add (getCursor ().firstEnclosing (J .MethodDeclaration .class ).getSimpleName ());
110
- String annotationArgumentValue = getAnnotationArgumentForInitMethod (anno , "method" , "named" );
111
118
if (annotationArgumentValue != null ) {
112
119
for (String method : annotationArgumentValue .split ("," )) {
113
120
classDeclCursor .computeMessageIfAbsent (INIT_METHOD_REFERENCES , v -> new HashSet <>()).add (method );
114
121
}
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 );
115
125
} else if (anno .getArguments () != null && !anno .getArguments ().isEmpty ()) {
116
126
// This conversion is not supported add a comment to the annotation and the method name to the not supported list
117
127
String comment = " JunitParamsRunnerToParameterized conversion not supported" ;
@@ -125,48 +135,62 @@ public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ct
125
135
unsupportedMethods .add (junitParamsDefaultInitMethodName (m .getSimpleName ()));
126
136
}
127
137
} 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 ()) {
130
141
J .MethodDeclaration m = getCursor ().dropParentUntil (J .MethodDeclaration .class ::isInstance ).getValue ();
131
142
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 ());
133
144
}
134
145
} else if (TEST_CASE_NAME_MATCHER .matches (anno )) {
146
+ Annotated annotated = Traits .annotated (TEST_CASE_NAME_MATCHER ).require (annotation , getCursor ().getParentOrThrow ());
135
147
// 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
+ }
140
155
}
141
156
return anno ;
142
157
}
143
158
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
+ }
149
165
}
150
- return annotationArgumentValue ;
166
+ return null ;
151
167
}
152
168
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 ;
168
172
}
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 ();
170
194
}
171
195
}
172
196
@@ -228,6 +252,7 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex
228
252
maybeRemoveImport ("junitparams.naming.TestCaseName" );
229
253
maybeAddImport ("org.junit.jupiter.params.ParameterizedTest" );
230
254
maybeAddImport ("org.junit.jupiter.params.provider.MethodSource" );
255
+ maybeAddImport ("org.junit.jupiter.params.provider.CsvSource" );
231
256
return cd ;
232
257
}
233
258
0 commit comments