1 /*
2  * Copyright 2016 Federico Tomassetti
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.github.javaparser.symbolsolver.model.typesystem;
18 
19 import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration;
20 import com.github.javaparser.resolution.types.ResolvedTypeVariable;
21 import com.github.javaparser.resolution.types.ResolvedWildcard;
22 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
23 import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
24 import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
25 import org.junit.jupiter.api.BeforeEach;
26 import org.junit.jupiter.api.Test;
27 
28 import java.util.Collections;
29 
30 import static org.junit.jupiter.api.Assertions.assertEquals;
31 import static org.junit.jupiter.api.Assertions.assertTrue;
32 import static org.junit.jupiter.api.Assertions.assertThrows;
33 
34 class WildcardUsageTest {
35 
36     class Foo {
37     }
38 
39     class Bar extends Foo {
40     }
41 
42     private TypeSolver typeSolver;
43     private ReferenceTypeImpl foo;
44     private ReferenceTypeImpl bar;
45     private ReferenceTypeImpl object;
46     private ReferenceTypeImpl string;
47     private ResolvedWildcard unbounded = ResolvedWildcard.UNBOUNDED;
48     private ResolvedWildcard superFoo;
49     private ResolvedWildcard superBar;
50     private ResolvedWildcard extendsFoo;
51     private ResolvedWildcard extendsBar;
52     private ResolvedWildcard superA;
53     private ResolvedWildcard extendsA;
54     private ResolvedWildcard superString;
55     private ResolvedWildcard extendsString;
56     private ResolvedTypeVariable a;
57 
58     @BeforeEach
setup()59     void setup() {
60         typeSolver = new ReflectionTypeSolver();
61         foo = new ReferenceTypeImpl(new ReflectionClassDeclaration(Foo.class, typeSolver), typeSolver);
62         bar = new ReferenceTypeImpl(new ReflectionClassDeclaration(Bar.class, typeSolver), typeSolver);
63         object = new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver);
64         string = new ReferenceTypeImpl(new ReflectionClassDeclaration(String.class, typeSolver), typeSolver);
65         superFoo = ResolvedWildcard.superBound(foo);
66         superBar = ResolvedWildcard.superBound(bar);
67         extendsFoo = ResolvedWildcard.extendsBound(foo);
68         extendsBar = ResolvedWildcard.extendsBound(bar);
69         a = new ResolvedTypeVariable(ResolvedTypeParameterDeclaration.onType("A", "foo.Bar", Collections.emptyList()));
70         superA = ResolvedWildcard.superBound(a);
71         extendsA = ResolvedWildcard.extendsBound(a);
72         superString = ResolvedWildcard.superBound(string);
73         extendsString = ResolvedWildcard.extendsBound(string);
74     }
75 
76     @Test
testIsArray()77     void testIsArray() {
78         assertEquals(false, unbounded.isArray());
79         assertEquals(false, superFoo.isArray());
80         assertEquals(false, superBar.isArray());
81         assertEquals(false, extendsFoo.isArray());
82         assertEquals(false, extendsBar.isArray());
83     }
84 
85     @Test
testIsPrimitive()86     void testIsPrimitive() {
87         assertEquals(false, unbounded.isPrimitive());
88         assertEquals(false, superFoo.isPrimitive());
89         assertEquals(false, superBar.isPrimitive());
90         assertEquals(false, extendsFoo.isPrimitive());
91         assertEquals(false, extendsBar.isPrimitive());
92     }
93 
94     @Test
testIsNull()95     void testIsNull() {
96         assertEquals(false, unbounded.isNull());
97         assertEquals(false, superFoo.isNull());
98         assertEquals(false, superBar.isNull());
99         assertEquals(false, extendsFoo.isNull());
100         assertEquals(false, extendsBar.isNull());
101     }
102 
103     @Test
testIsReference()104     void testIsReference() {
105         assertEquals(true, unbounded.isReference());
106         assertEquals(true, superFoo.isReference());
107         assertEquals(true, superBar.isReference());
108         assertEquals(true, extendsFoo.isReference());
109         assertEquals(true, extendsBar.isReference());
110     }
111 
112     @Test
testIsReferenceType()113     void testIsReferenceType() {
114         assertEquals(false, unbounded.isReferenceType());
115         assertEquals(false, superFoo.isReferenceType());
116         assertEquals(false, superBar.isReferenceType());
117         assertEquals(false, extendsFoo.isReferenceType());
118         assertEquals(false, extendsBar.isReferenceType());
119     }
120 
121     @Test
testIsVoid()122     void testIsVoid() {
123         assertEquals(false, unbounded.isVoid());
124         assertEquals(false, superFoo.isVoid());
125         assertEquals(false, superBar.isVoid());
126         assertEquals(false, extendsFoo.isVoid());
127         assertEquals(false, extendsBar.isVoid());
128     }
129 
130     @Test
testIsTypeVariable()131     void testIsTypeVariable() {
132         assertEquals(false, unbounded.isTypeVariable());
133         assertEquals(false, superFoo.isTypeVariable());
134         assertEquals(false, superBar.isTypeVariable());
135         assertEquals(false, extendsFoo.isTypeVariable());
136         assertEquals(false, extendsBar.isTypeVariable());
137     }
138 
139     @Test
testIsWildcard()140     void testIsWildcard() {
141         assertEquals(true, unbounded.isWildcard());
142         assertEquals(true, superFoo.isWildcard());
143         assertEquals(true, superBar.isWildcard());
144         assertEquals(true, extendsFoo.isWildcard());
145         assertEquals(true, extendsBar.isWildcard());
146     }
147 
148     @Test
testAsArrayTypeUsage()149     void testAsArrayTypeUsage() {
150         assertThrows(UnsupportedOperationException.class, () -> unbounded.asArrayType());
151     }
152 
153     @Test
testAsReferenceTypeUsage()154     void testAsReferenceTypeUsage() {
155         assertThrows(UnsupportedOperationException.class, () -> unbounded.asReferenceType());
156     }
157 
158     @Test
testAsTypeParameter()159     void testAsTypeParameter() {
160         assertThrows(UnsupportedOperationException.class, () -> unbounded.asTypeParameter());
161     }
162 
163     @Test
testAsPrimitive()164     void testAsPrimitive() {
165         assertThrows(UnsupportedOperationException.class, () -> unbounded.asPrimitive());
166     }
167 
168     @Test
testAsWildcard()169     void testAsWildcard() {
170         assertTrue(unbounded == unbounded.asWildcard());
171         assertTrue(superFoo == superFoo.asWildcard());
172         assertTrue(superBar == superBar.asWildcard());
173         assertTrue(extendsFoo == extendsFoo.asWildcard());
174         assertTrue(extendsBar == extendsBar.asWildcard());
175     }
176 
177     @Test
testAsDescribe()178     void testAsDescribe() {
179         assertEquals("?", unbounded.describe());
180         assertEquals("? super com.github.javaparser.symbolsolver.model.typesystem.WildcardUsageTest.Foo", superFoo.describe());
181         assertEquals("? super com.github.javaparser.symbolsolver.model.typesystem.WildcardUsageTest.Bar", superBar.describe());
182         assertEquals("? extends com.github.javaparser.symbolsolver.model.typesystem.WildcardUsageTest.Foo", extendsFoo.describe());
183         assertEquals("? extends com.github.javaparser.symbolsolver.model.typesystem.WildcardUsageTest.Bar", extendsBar.describe());
184     }
185 
186     @Test
testReplaceParam()187     void testReplaceParam() {
188         ResolvedTypeParameterDeclaration tpA = ResolvedTypeParameterDeclaration.onType("A", "foo.Bar", Collections.emptyList());
189         ResolvedTypeParameterDeclaration tpB = ResolvedTypeParameterDeclaration.onType("B", "foo.Bar", Collections.emptyList());
190         assertTrue(unbounded == unbounded.replaceTypeVariables(tpA, string));
191         assertTrue(superFoo == superFoo.replaceTypeVariables(tpA, string));
192         assertTrue(extendsFoo == extendsFoo.replaceTypeVariables(tpA, string));
193         assertEquals(superString, superA.replaceTypeVariables(tpA, string));
194         assertEquals(extendsString, extendsA.replaceTypeVariables(tpA, string));
195         assertTrue(superA == superA.replaceTypeVariables(tpB, string));
196         assertTrue(extendsA == extendsA.replaceTypeVariables(tpB, string));
197     }
198 
199     @Test
testIsAssignableBySimple()200     void testIsAssignableBySimple() {
201         assertEquals(false, unbounded.isAssignableBy(object));
202         assertEquals(true, object.isAssignableBy(unbounded));
203         assertEquals(false, string.isAssignableBy(unbounded));
204         assertEquals(true, superFoo.isAssignableBy(foo));
205         assertEquals(false, foo.isAssignableBy(superFoo));
206         assertEquals(false, extendsFoo.isAssignableBy(foo));
207         assertEquals(true, foo.isAssignableBy(extendsFoo));
208     }
209 
210     /*@Test
211     public void testIsAssignableByGenerics() {
212         assertEquals(false, listOfStrings.isAssignableBy(listOfWildcardExtendsString));
213         assertEquals(false, listOfStrings.isAssignableBy(listOfWildcardExtendsString));
214         assertEquals(true,  listOfWildcardExtendsString.isAssignableBy(listOfStrings));
215         assertEquals(false, listOfWildcardExtendsString.isAssignableBy(listOfWildcardSuperString));
216         assertEquals(true,  listOfWildcardSuperString.isAssignableBy(listOfStrings));
217         assertEquals(false, listOfWildcardSuperString.isAssignableBy(listOfWildcardExtendsString));
218     }
219 
220     @Test
221     public void testIsAssignableByGenericsInheritance() {
222         assertEquals(true, collectionOfString.isAssignableBy(collectionOfString));
223         assertEquals(true, collectionOfString.isAssignableBy(listOfStrings));
224         assertEquals(true, collectionOfString.isAssignableBy(linkedListOfString));
225 
226         assertEquals(false, listOfStrings.isAssignableBy(collectionOfString));
227         assertEquals(true, listOfStrings.isAssignableBy(listOfStrings));
228         assertEquals(true, listOfStrings.isAssignableBy(linkedListOfString));
229 
230         assertEquals(false, linkedListOfString.isAssignableBy(collectionOfString));
231         assertEquals(false, linkedListOfString.isAssignableBy(listOfStrings));
232         assertEquals(true, linkedListOfString.isAssignableBy(linkedListOfString));
233     }
234 
235     @Test
236     public void testGetAllAncestorsConsideringTypeParameters() {
237         assertTrue(linkedListOfString.getAllAncestors().contains(object));
238         assertTrue(linkedListOfString.getAllAncestors().contains(listOfStrings));
239         assertTrue(linkedListOfString.getAllAncestors().contains(collectionOfString));
240         assertFalse(linkedListOfString.getAllAncestors().contains(listOfA));
241     }
242 
243     @Test
244     public void testGetAllAncestorsConsideringGenericsCases() {
245         ReferenceTypeUsage foo = new ReferenceTypeUsage(new ReflectionClassDeclaration(Foo.class, typeSolver), typeSolver);
246         ReferenceTypeUsage bar = new ReferenceTypeUsage(new ReflectionClassDeclaration(Bar.class, typeSolver), typeSolver);
247         ReferenceTypeUsage left, right;
248 
249         //YES MoreBazzing<Foo, Bar> e1 = new MoreBazzing<Foo, Bar>();
250         assertEquals(true,
251                 new ReferenceTypeUsage(
252                     new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
253                     ImmutableList.of(foo, bar), typeSolver)
254                 .isAssignableBy(new ReferenceTypeUsage(
255                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
256                                 ImmutableList.of(foo, bar), typeSolver))
257         );
258 
259         //YES MoreBazzing<? extends Foo, Bar> e2 = new MoreBazzing<Foo, Bar>();
260         assertEquals(true,
261                 new ReferenceTypeUsage(
262                         new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
263                         ImmutableList.of(WildcardUsage.extendsBound(foo), bar), typeSolver)
264                         .isAssignableBy(new ReferenceTypeUsage(
265                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
266                                 ImmutableList.of(foo, bar), typeSolver))
267         );
268 
269         //YES MoreBazzing<Foo, ? extends Bar> e3 = new MoreBazzing<Foo, Bar>();
270         assertEquals(true,
271                 new ReferenceTypeUsage(
272                         new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
273                         ImmutableList.of(foo, WildcardUsage.extendsBound(bar)), typeSolver)
274                         .isAssignableBy(new ReferenceTypeUsage(
275                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
276                                 ImmutableList.of(foo, bar), typeSolver))
277         );
278 
279         //YES MoreBazzing<? extends Foo, ? extends Foo> e4 = new MoreBazzing<Foo, Bar>();
280         assertEquals(true,
281                 new ReferenceTypeUsage(
282                         new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
283                         ImmutableList.of(WildcardUsage.extendsBound(foo), WildcardUsage.extendsBound(foo)), typeSolver)
284                         .isAssignableBy(new ReferenceTypeUsage(
285                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
286                                 ImmutableList.of(foo, bar), typeSolver))
287         );
288 
289         //YES MoreBazzing<? extends Foo, ? extends Foo> e5 = new MoreBazzing<Bar, Bar>();
290         left = new ReferenceTypeUsage(
291                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
292                 ImmutableList.of(WildcardUsage.extendsBound(foo), WildcardUsage.extendsBound(foo)), typeSolver);
293         right = new ReferenceTypeUsage(
294                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
295                 ImmutableList.of(bar, bar), typeSolver);
296         assertEquals(true, left.isAssignableBy(right));
297 
298         //YES Bazzer<Object, String, String> e6 = new MoreBazzing<String, Object>();
299         left = new ReferenceTypeUsage(
300                 new ReflectionClassDeclaration(Bazzer.class, typeSolver),
301                 ImmutableList.of(object, string, string), typeSolver);
302         right = new ReferenceTypeUsage(
303                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
304                 ImmutableList.of(string, object), typeSolver);
305         assertEquals(true, left.isAssignableBy(right));
306 
307         //YES Bazzer<String,String,String> e7 = new MoreBazzing<String, String>();
308         assertEquals(true,
309                 new ReferenceTypeUsage(
310                         new ReflectionClassDeclaration(Bazzer.class, typeSolver),
311                         ImmutableList.of(string, string, string), typeSolver)
312                         .isAssignableBy(new ReferenceTypeUsage(
313                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
314                                 ImmutableList.of(string, string), typeSolver))
315         );
316 
317         //YES Bazzer<Bar,String,Foo> e8 = new MoreBazzing<Foo, Bar>();
318         assertEquals(true,
319                 new ReferenceTypeUsage(
320                         new ReflectionClassDeclaration(Bazzer.class, typeSolver),
321                         ImmutableList.of(bar, string, foo), typeSolver)
322                         .isAssignableBy(new ReferenceTypeUsage(
323                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
324                                 ImmutableList.of(foo, bar), typeSolver))
325         );
326 
327         //YES Bazzer<Foo,String,Bar> e9 = new MoreBazzing<Bar, Foo>();
328         assertEquals(true,
329                 new ReferenceTypeUsage(
330                         new ReflectionClassDeclaration(Bazzer.class, typeSolver),
331                         ImmutableList.of(foo, string, bar), typeSolver)
332                         .isAssignableBy(new ReferenceTypeUsage(
333                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
334                                 ImmutableList.of(bar, foo), typeSolver))
335         );
336 
337         //NO Bazzer<Bar,String,Foo> n1 = new MoreBazzing<Bar, Foo>();
338         assertEquals(false,
339                 new ReferenceTypeUsage(
340                         new ReflectionClassDeclaration(Bazzer.class, typeSolver),
341                         ImmutableList.of(bar,string,foo), typeSolver)
342                         .isAssignableBy(new ReferenceTypeUsage(
343                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
344                                 ImmutableList.of(bar, foo), typeSolver))
345         );
346 
347         //NO Bazzer<Bar,String,Bar> n2 = new MoreBazzing<Bar, Foo>();
348         assertEquals(false,
349                 new ReferenceTypeUsage(
350                         new ReflectionClassDeclaration(Bazzer.class, typeSolver),
351                         ImmutableList.of(bar, string, foo), typeSolver)
352                         .isAssignableBy(new ReferenceTypeUsage(
353                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
354                                 ImmutableList.of(bar, foo), typeSolver))
355         );
356 
357         //NO Bazzer<Foo,Object,Bar> n3 = new MoreBazzing<Bar, Foo>();
358         assertEquals(false,
359                 new ReferenceTypeUsage(
360                         new ReflectionClassDeclaration(Bazzer.class, typeSolver),
361                         ImmutableList.of(foo, object, bar), typeSolver)
362                         .isAssignableBy(new ReferenceTypeUsage(
363                                 new ReflectionClassDeclaration(MoreBazzing.class, typeSolver),
364                                 ImmutableList.of(bar, foo), typeSolver))
365         );
366     }
367 
368     @Test
369     public void charSequenceIsAssignableToObject() {
370         TypeSolver typeSolver = new JreTypeSolver();
371         ReferenceTypeUsage charSequence = new ReferenceTypeUsage(new ReflectionInterfaceDeclaration(CharSequence.class, typeSolver), typeSolver);
372         ReferenceTypeUsage object = new ReferenceTypeUsage(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver);
373         assertEquals(false, charSequence.isAssignableBy(object));
374         assertEquals(true, object.isAssignableBy(charSequence));
375     }
376 
377     @Test
378     public void testGetFieldTypeExisting() {
379         class Foo<A> {
380             List<A> elements;
381         }
382 
383         TypeSolver typeSolver = new JreTypeSolver();
384         ReferenceTypeUsage ref = new ReferenceTypeUsage(new ReflectionClassDeclaration(Foo.class, typeSolver), typeSolver);
385 
386         assertEquals(true, ref.getFieldType("elements").isPresent());
387         assertEquals(true, ref.getFieldType("elements").get().isReferenceType());
388         assertEquals(List.class.getCanonicalName(), ref.getFieldType("elements").get().asReferenceType().getQualifiedName());
389         assertEquals(1, ref.getFieldType("elements").get().asReferenceType().typeParametersValues().size());
390         assertEquals(true, ref.getFieldType("elements").get().asReferenceType().typeParametersValues().get(0).isTypeParameter());
391         assertEquals("A", ref.getFieldType("elements").get().asReferenceType().typeParametersValues().get(0).asTypeParameter().getName());
392 
393         ref = new ReferenceTypeUsage(new ReflectionClassDeclaration(Foo.class, typeSolver),
394                 ImmutableList.of(new ReferenceTypeUsage(new ReflectionClassDeclaration(String.class, typeSolver), typeSolver)),
395                 typeSolver);
396 
397         assertEquals(true, ref.getFieldType("elements").isPresent());
398         assertEquals(true, ref.getFieldType("elements").get().isReferenceType());
399         assertEquals(List.class.getCanonicalName(), ref.getFieldType("elements").get().asReferenceType().getQualifiedName());
400         assertEquals(1, ref.getFieldType("elements").get().asReferenceType().typeParametersValues().size());
401         assertEquals(true, ref.getFieldType("elements").get().asReferenceType().typeParametersValues().get(0).isReferenceType());
402         assertEquals(String.class.getCanonicalName(), ref.getFieldType("elements").get().asReferenceType().typeParametersValues().get(0).asReferenceType().getQualifiedName());
403     }
404 
405     @Test
406     public void testGetFieldTypeUnexisting() {
407         class Foo<A> {
408             List<A> elements;
409         }
410 
411         TypeSolver typeSolver = new JreTypeSolver();
412         ReferenceTypeUsage ref = new ReferenceTypeUsage(new ReflectionClassDeclaration(Foo.class, typeSolver), typeSolver);
413 
414         assertEquals(false, ref.getFieldType("bar").isPresent());
415 
416         ref = new ReferenceTypeUsage(new ReflectionClassDeclaration(Foo.class, typeSolver),
417                 ImmutableList.of(new ReferenceTypeUsage(new ReflectionClassDeclaration(String.class, typeSolver), typeSolver)),
418                 typeSolver);
419 
420         assertEquals(false, ref.getFieldType("bar").isPresent());
421     }*/
422 
423 }
424