@@ -79,7 +79,7 @@ public Set<String> getTags() {
7979 @ Override
8080 public String getDescription () {
8181 return "Many AssertJ chained assertions have dedicated assertions that function the same. " +
82- "It is best to use the dedicated assertions." ;
82+ "It is best to use the dedicated assertions." ;
8383 }
8484
8585 @ Override
@@ -108,19 +108,28 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocat
108108 }
109109
110110 J .MethodInvocation assertThatArg = (J .MethodInvocation ) assertThat .getArguments ().get (0 );
111- if (!CHAINED_ASSERT_MATCHER .matches (assertThatArg ) && ! hasZeroArgument ( mi ) ) {
111+ if (!CHAINED_ASSERT_MATCHER .matches (assertThatArg )) {
112112 return mi ;
113113 }
114114
115- // method call has select
116- Expression select = assertThatArg .getSelect () != null ? assertThatArg .getSelect () : assertThatArg ;
117- if (!TypeUtils .isAssignableTo (requiredType , select .getType ())) {
115+ // Extract the actual argument for the new assertThat call
116+ Expression actual = assertThatArg .getSelect () != null ? assertThatArg .getSelect () : assertThatArg ;
117+ if (!TypeUtils .isAssignableTo (requiredType , actual .getType ())) {
118118 return mi ;
119119 }
120+ List <Expression > arguments = new ArrayList <>();
121+ arguments .add (actual );
120122
121- List <Expression > arguments = new ArrayList <>(Collections .singletonList (select ));
122- String template = getTemplate (arguments , assertThatArg , mi );
123- String formattedTemplate = String .format (template , dedicatedAssertion );
123+ // Special case for more expressive assertions: assertThat(x.size()).isEqualTo(0) -> isEmpty()
124+ if ("size" .equals (chainedAssertion ) && "isEqualTo" .equals (assertToReplace ) && hasZeroArgument (mi )) {
125+ return applyTemplate ("assertThat(#{any()}).isEmpty()" , arguments , mi , ctx );
126+ }
127+
128+ String template = getStringTemplateAndAppendArguments (assertThatArg , mi , arguments );
129+ return applyTemplate (String .format (template , dedicatedAssertion ), arguments , mi , ctx );
130+ }
131+
132+ private J .MethodInvocation applyTemplate (String formattedTemplate , List <Expression > arguments , J .MethodInvocation mi , ExecutionContext ctx ) {
124133 return JavaTemplate .builder (formattedTemplate )
125134 .contextSensitive ()
126135 .javaParser (JavaParser .fromJavaVersion ().classpathFromResources (ctx , "junit-jupiter-api-5.9" , "assertj-core-3.24" ))
@@ -129,33 +138,50 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocat
129138 }
130139 }
131140
132- private String getTemplate (List <Expression > arguments , J .MethodInvocation assertThatArg , J .MethodInvocation methodToReplace ) {
133- if (hasZeroArgument (methodToReplace )) {
141+ private String getStringTemplateAndAppendArguments (J .MethodInvocation assertThatArg , J .MethodInvocation methodToReplace , List <Expression > arguments ) {
142+ Expression assertThatArgument = assertThatArg .getArguments ().get (0 );
143+ Expression methodToReplaceArgument = methodToReplace .getArguments ().get (0 );
144+ boolean assertThatArgumentIsEmpty = assertThatArgument instanceof J .Empty ;
145+ boolean methodToReplaceArgumentIsEmpty = methodToReplaceArgument instanceof J .Empty ;
146+
147+ // If both arguments are empty, then the select is already added to the arguments list, and we use a minimal template
148+ if (assertThatArgumentIsEmpty && methodToReplaceArgumentIsEmpty ) {
134149 return "assertThat(#{any()}).%s()" ;
135150 }
136151
137- if (!( assertThatArg . getArguments (). get ( 0 ) instanceof J . Empty )
138- && !( methodToReplace . getArguments (). get ( 0 ) instanceof J . Empty ) ) {
139- // Note: this should be the only case when more than one argument needs to be handled. When the assertions involve the map functions
140- arguments .add (assertThatArg . getArguments (). get ( 0 ) );
141- arguments .add (methodToReplace . getArguments (). get ( 0 ) );
152+ // If both arguments are not empty, then we add both to the arguments to the arguments list, and return a template with two arguments
153+ if (! assertThatArgumentIsEmpty && !methodToReplaceArgumentIsEmpty ) {
154+ // This should only happen for map assertions using a key and value
155+ arguments .add (assertThatArgument );
156+ arguments .add (methodToReplaceArgument );
142157 return "assertThat(#{any()}).%s(#{any()}, #{any()})" ;
143158 }
144159
145- if (!(assertThatArg .getArguments ().get (0 ) instanceof J .Empty )
146- || !(methodToReplace .getArguments ().get (0 ) instanceof J .Empty )) {
147- Expression argumentToAdd = assertThatArg .getArguments ().get (0 ) instanceof J .Empty ? methodToReplace .getArguments ().get (0 ) : assertThatArg .getArguments ().get (0 );
148- argumentToAdd = argumentToAdd instanceof J .MethodInvocation ? ((J .MethodInvocation ) argumentToAdd ).getSelect () : argumentToAdd ;
149- arguments .add (argumentToAdd );
160+ // If either argument is empty, we choose which one to add to the arguments list, and optionally extract the select
161+ arguments .add (extractEitherArgument (assertThatArgumentIsEmpty , assertThatArgument , methodToReplaceArgument ));
150162
151- if (requiredType .equals ("java.nio.file.Path" ) && dedicatedAssertion .contains ("Raw" )
152- && TypeUtils .isAssignableTo ("java.lang.String" , assertThatArg .getArguments ().get (0 ).getType ())) {
153- return "assertThat(#{any()}).%s(Path.of(#{any()}))" ;
154- }
155- return "assertThat(#{any()}).%s(#{any()})" ;
163+ // Special case for Path.of() assertions
164+ if ("java.nio.file.Path" .equals (requiredType ) && dedicatedAssertion .contains ("Raw" )
165+ && TypeUtils .isAssignableTo ("java.lang.String" , assertThatArgument .getType ())) {
166+ return "assertThat(#{any()}).%s(Path.of(#{any()}))" ;
156167 }
157168
158- return "assertThat(#{any()}).%s()" ;
169+ return "assertThat(#{any()}).%s(#{any()})" ;
170+
171+ }
172+
173+ private static Expression extractEitherArgument (boolean assertThatArgumentIsEmpty , Expression assertThatArgument , Expression methodToReplaceArgument ) {
174+ if (assertThatArgumentIsEmpty ) {
175+ return methodToReplaceArgument ;
176+ }
177+ // Only on the assertThat argument do we possibly replace the argument with the select; such as list.size() -> list
178+ if (assertThatArgument instanceof J .MethodInvocation ) {
179+ Expression select = ((J .MethodInvocation ) assertThatArgument ).getSelect ();
180+ if (select != null ) {
181+ return select ;
182+ }
183+ }
184+ return assertThatArgument ;
159185 }
160186
161187 private boolean hasZeroArgument (J .MethodInvocation method ) {
0 commit comments