View Javadoc
1   package net.florianschoppmann.java.type;
2   
3   import org.testng.Assert;
4   import org.testng.ITest;
5   import org.testng.annotations.BeforeClass;
6   import org.testng.annotations.Test;
7   
8   import javax.lang.model.element.TypeElement;
9   import javax.lang.model.element.TypeParameterElement;
10  import javax.lang.model.type.DeclaredType;
11  import javax.lang.model.type.PrimitiveType;
12  import javax.lang.model.type.TypeKind;
13  import javax.lang.model.type.TypeMirror;
14  import javax.lang.model.type.TypeVariable;
15  import javax.lang.model.type.WildcardType;
16  import java.io.Serializable;
17  import java.util.ArrayList;
18  import java.util.Arrays;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.LinkedHashMap;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Objects;
25  import java.util.Set;
26  
27  import static org.testng.Assert.assertEquals;
28  import static org.testng.Assert.assertFalse;
29  import static org.testng.Assert.assertNull;
30  import static org.testng.Assert.assertTrue;
31  
32  /**
33   * Contract test for {@link AbstractTypes}.
34   *
35   * <p>This class should be instantiated and returned by a TestNG factory method (that is, a method annotated with
36   * {@link org.testng.annotations.Factory}).
37   */
38  public final class AbstractTypesContract implements ITest {
39      private final AbstractTypesProvider provider;
40      private AbstractTypes types;
41      private final Map<Class<?>, TypeElement> typeElementMap = new LinkedHashMap<>();
42  
43      /**
44       * Constructs a new contract-test instance with the given provider.
45       *
46       * @param provider provider of {@link AbstractTypes} instance, must not be null
47       * @throws NullPointerException if the argument is null
48       */
49      public AbstractTypesContract(AbstractTypesProvider provider) {
50          Objects.requireNonNull(provider);
51  
52          this.provider = provider;
53      }
54  
55      @Override
56      public String getTestName() {
57          return provider.getClass().getName();
58      }
59  
60      final TypeElement element(Class<?> clazz) {
61          return Objects.requireNonNull(typeElementMap.get(clazz));
62      }
63  
64      private PrimitiveType primitiveType(Class<?> clazz) {
65          assert clazz.isPrimitive();
66  
67          if (clazz.equals(double.class)) {
68              return types.getPrimitiveType(TypeKind.DOUBLE);
69          } else if (clazz.equals(float.class)) {
70              return types.getPrimitiveType(TypeKind.FLOAT);
71          } else if (clazz.equals(long.class)) {
72              return types.getPrimitiveType(TypeKind.LONG);
73          } else if (clazz.equals(int.class)) {
74              return types.getPrimitiveType(TypeKind.INT);
75          } else if (clazz.equals(short.class)) {
76              return types.getPrimitiveType(TypeKind.SHORT);
77          } else if (clazz.equals(byte.class)) {
78              return types.getPrimitiveType(TypeKind.BYTE);
79          } else if (clazz.equals(boolean.class)) {
80              return types.getPrimitiveType(TypeKind.BOOLEAN);
81          } else if (clazz.equals(char.class)) {
82              return types.getPrimitiveType(TypeKind.CHAR);
83          } else {
84              throw new IllegalArgumentException(String.format("Unexpected primitive type: %s", clazz));
85          }
86      }
87  
88      /**
89       * Returns the type mirror corresponding to the given {@link Class} object.
90       *
91       * <p>If the given class is a generic declaration, the returned type will be a raw type (by calling
92       * {@link AbstractTypes#getDeclaredType(TypeElement, TypeMirror...)} with an empty list of type arguments).
93       *
94       * @param clazz the {@link Class} object
95       * @return the type mirror
96       */
97      private TypeMirror type(Class<?> clazz) {
98          if (clazz.isPrimitive()) {
99              return primitiveType(clazz);
100         } else if (clazz.isArray()) {
101             return types.getArrayType(type(clazz.getComponentType()));
102         } else if (typeElementMap.containsKey(clazz)) {
103             // If clazz represents a generic type declaration, this method returns the raw type.
104             return types.getDeclaredType(typeElementMap.get(clazz));
105         }
106 
107         throw new IllegalArgumentException(String.format("Unexpected type: %s", clazz));
108     }
109 
110     private interface SimpleA { }
111 
112     private interface SimpleB extends SimpleA { }
113 
114     private interface SimpleC extends SimpleB { }
115 
116     private interface SimpleParameterized<T> extends Serializable { }
117 
118     private interface ExtendsParameterized<T extends SimpleC> { }
119 
120     private interface SubExtendsParameterized<T extends SimpleC> extends ExtendsParameterized<T> { }
121 
122     private interface RawSubExtendsParameterized<T> extends ExtendsParameterized { }
123 
124     private interface DiamondA<T, U> { }
125 
126     private interface DiamondB<T> extends DiamondA<T[], Integer[]> { }
127 
128     private interface DiamondC<U> extends DiamondA<String[], U[]> { }
129 
130     private interface DiamondD extends DiamondB<String>, DiamondC<Integer> { }
131 
132     private interface SubDiamondB<T> extends DiamondB<T[]> { }
133 
134     private interface SubSubDiamondB extends SubDiamondB<Integer[]> { }
135 
136     private abstract static class IntegerListSet implements Set<List<Integer>>, Comparable<IntegerListSet> { }
137 
138     private abstract static class ImmutableIntegerListSet extends IntegerListSet { }
139 
140     private abstract static class InterdependentRecursiveBoundA<
141         T extends InterdependentRecursiveBoundA<T, U>,
142         U extends T
143     > { }
144 
145     private abstract static class InterdependentRecursiveBoundB
146             extends InterdependentRecursiveBoundA<InterdependentRecursiveBoundB, InterdependentRecursiveBoundB>
147             implements Serializable {
148         private static final long serialVersionUID = -4490638717891611814L;
149     }
150 
151     private static class OuterClass<T extends Number> {
152         private final class InnerClass<U extends List<?> & Serializable> { }
153     }
154 
155     /**
156      * Performs initialization steps necessary in order to run the contract tests subsequently.
157      */
158     @BeforeClass
159     public void setup() {
160         provider.preContract();
161 
162         List<Class<?>> classesNeeded = Arrays.asList(
163             Object.class, Enum.class, Cloneable.class, Serializable.class, Comparable.class,
164             Collection.class, List.class, ArrayList.class, Set.class,
165             Number.class, Integer.class,
166             String.class,
167             getClass(),
168             IntegerListSet.class, ImmutableIntegerListSet.class,
169             DiamondA.class, DiamondB.class, DiamondC.class, DiamondD.class, SubDiamondB.class, SubSubDiamondB.class,
170             SimpleA.class, SimpleB.class, SimpleC.class,
171             ExtendsParameterized.class, SubExtendsParameterized.class,
172             RawSubExtendsParameterized.class,
173             SimpleParameterized.class,
174             InterdependentRecursiveBoundA.class, InterdependentRecursiveBoundB.class,
175             OuterClass.class, OuterClass.InnerClass.class
176         );
177 
178         for (Class<?> clazz: classesNeeded) {
179             typeElementMap.put(clazz, null);
180         }
181 
182         types = provider.getTypes(typeElementMap);
183     }
184 
185     /**
186      * Verifies the {@link TypeElement} instances in {@link #typeElementMap}.
187      *
188      * <p>The following is verified:
189      * <ul><li>
190      *     {@link TypeElement#asType()} returns "a <i>prototypical</i> type" which is "the element's invocation on the
191      *     type variables corresponding to its own formal type parameters".
192      * </li><li>
193      *     {@link #type(Class)} returns a raw type if the given class object represents a generic type declaration.
194      * </li><li>
195      *     Passing the raw type returned by {@link #type(Class)} to
196      *     {@link AbstractTypes#toString(TypeMirror)} yields a string equal to the class's name.
197      * </li></ul>
198      */
199     @Test
200     public void testSetup() {
201         for (Map.Entry<Class<?>, TypeElement> entry: typeElementMap.entrySet()) {
202             Class<?> clazz = entry.getKey();
203             TypeElement typeElement = entry.getValue();
204 
205             assertTrue(typeElement.getKind().isClass() || typeElement.getKind().isInterface());
206             DeclaredType prototypicalType = (DeclaredType) typeElement.asType();
207             assertEquals(typeElement.getTypeParameters().size(), prototypicalType.getTypeArguments().size());
208 
209             for (TypeMirror typeArgument: prototypicalType.getTypeArguments()) {
210                 assertTrue(typeArgument.getKind() == TypeKind.TYPEVAR && typeArgument instanceof TypeVariable);
211             }
212 
213             DeclaredType rawType = (DeclaredType) type(clazz);
214             assertTrue(rawType.getTypeArguments().isEmpty());
215 
216             assertEquals(clazz.getCanonicalName(), types.toString(rawType));
217         }
218     }
219 
220     /**
221      * Verifies that {@link AbstractTypes#requireValidElement(javax.lang.model.element.Element)} throws a
222      * {@link NullPointerException} if passed null.
223      */
224     @Test(expectedExceptions = NullPointerException.class)
225     public void requireValidElement() {
226         types.requireValidElement(null);
227     }
228 
229     /**
230      * Verifies that {@link AbstractTypes#requireValidType(TypeMirror)} does not throw an
231      * exception if passed null.
232      */
233     @Test
234     public void requireValidType() {
235         types.requireValidType(null);
236     }
237 
238     /**
239      * Verifies that {@link AbstractTypes#requireValidTypes(TypeMirror[])} throws exceptions if
240      * passed null or an array with null element.
241      */
242     @Test
243     public void requireValidTypes() {
244         try {
245             types.requireValidTypes(null);
246             Assert.fail("Expected exception.");
247         } catch (NullPointerException ignored) { }
248 
249         try {
250             types.requireValidTypes(new TypeMirror[] { null });
251             Assert.fail("Expected exception.");
252         } catch (NullPointerException ignored) { }
253     }
254 
255     private static void typeMirrorAssertExpectedName(TypeMirror typeMirror, Class<?> clazz) {
256         assertEquals(typeMirror.getKind(), TypeKind.DECLARED);
257         TypeElement element = (TypeElement) ((DeclaredType) typeMirror).asElement();
258         assertEquals(element.getQualifiedName().toString(), clazz.getName());
259     }
260 
261     /**
262      * Verifies {@link AbstractTypes#typeMirror(java.lang.reflect.Type)}.
263      */
264     @Test
265     public void typeMirror() {
266         typeMirrorAssertExpectedName(types.typeMirror(Object.class), Object.class);
267         typeMirrorAssertExpectedName(types.typeMirror(Serializable.class), Serializable.class);
268         typeMirrorAssertExpectedName(types.typeMirror(Cloneable.class), Cloneable.class);
269     }
270 
271     /**
272      * Verifies {@link AbstractTypes#substitute(TypeMirror, Map)}.
273      */
274     @Test
275     public void substitute() {
276         TypeElement diamondADeclaration = element(DiamondA.class);
277         Map<TypeParameterElement, TypeMirror> substitutions = new LinkedHashMap<>();
278         substitutions.put(diamondADeclaration.getTypeParameters().get(0), type(String.class));
279         DeclaredType expectedType = types.getDeclaredType(
280             (DeclaredType) type(getClass()),
281             diamondADeclaration,
282             type(String.class), diamondADeclaration.getTypeParameters().get(1).asType()
283         );
284         assertEquals(types.substitute(diamondADeclaration.asType(), substitutions), expectedType);
285 
286         WildcardType extendsStringWildcardArgument = types.getWildcardType(type(String.class), null);
287         assertEquals(types.substitute(extendsStringWildcardArgument, substitutions), extendsStringWildcardArgument);
288     }
289 
290     /**
291      * Verifies {@link AbstractTypes#resolveActualTypeArguments(TypeElement, TypeMirror)} when the second argument is
292      * a generic type, a non-generic type, or a primitive type.
293      */
294     @Test
295     public void resolveActualTypeArguments() {
296         // Verify edge case: resolving type arguments on the same type
297         assertEquals(types.resolveActualTypeArguments(element(List.class), type(List.class)), Collections.emptyList());
298 
299         // listOfIntegersType now represents List<Integer>
300         DeclaredType listOfIntegersType = types.getDeclaredType(element(List.class), type(Integer.class));
301 
302         // Simple test without inheritance: List and List<Integer>
303         assertEquals(
304             types.resolveActualTypeArguments(element(List.class), listOfIntegersType),
305             Collections.singletonList(type(Integer.class))
306         );
307 
308         // Now with inheritance.
309         assertEquals(
310             types.resolveActualTypeArguments(element(Set.class), type(IntegerListSet.class)),
311             Collections.singletonList(listOfIntegersType)
312         );
313         assertEquals(
314             types.resolveActualTypeArguments(element(Set.class), type(ImmutableIntegerListSet.class)),
315             Collections.singletonList(listOfIntegersType)
316         );
317 
318         // Verify that non-generic type does not have actual type arguments
319         assertEquals(
320             types.resolveActualTypeArguments(element(IntegerListSet.class), type(ImmutableIntegerListSet.class)),
321             Collections.emptyList()
322         );
323 
324         // In case there is no subtype relationship, null is returned
325         assertNull(
326             types.resolveActualTypeArguments(element(ImmutableIntegerListSet.class), type(IntegerListSet.class))
327         );
328         assertNull(types.resolveActualTypeArguments(element(List.class), type(Collection.class)));
329         assertNull(types.resolveActualTypeArguments(element(List.class), type(int.class)));
330     }
331 
332     /**
333      * Verifies {@link AbstractTypes#resolveActualTypeArguments(TypeElement, TypeMirror)} if the second argument is a
334      * raw type.
335      */
336     @Test
337     public void resolveActualTypeArgumentsRaw() {
338         // Resolving unbound type parameters (because the subclass inherits from a raw type) returns an empty list
339         assertEquals(
340             types.resolveActualTypeArguments(
341                 element(ExtendsParameterized.class),
342                 type(RawSubExtendsParameterized.class)
343             ),
344             Collections.emptyList()
345         );
346 
347         // Resolving the type argument of a raw type is the same as resolving the type arguments of the corresponding
348         // prototypical type of the sub-type declaration.
349         assertEquals(
350             types.resolveActualTypeArguments(
351                 element(ExtendsParameterized.class),
352                 type(SubExtendsParameterized.class)
353             ),
354             types.resolveActualTypeArguments(
355                 element(ExtendsParameterized.class),
356                 element(SubExtendsParameterized.class).asType()
357             )
358         );
359         assertEquals(
360             ((DeclaredType) element(SubExtendsParameterized.class).asType()).getTypeArguments().get(0),
361             element(SubExtendsParameterized.class).getTypeParameters().get(0).asType()
362         );
363     }
364 
365     /**
366      * Verifies {@link AbstractTypes#resolveActualTypeArguments(TypeElement, TypeMirror)} if the second argument
367      * contains an actual type argument that is an array type.
368      */
369     @Test
370     public void resolveActualTypeArgumentsArrays() {
371         // declaredType now represents DiamondB<String[]>
372         DeclaredType declaredType = types.getDeclaredType(element(DiamondB.class), types.getArrayType(type(String.class)));
373         assertEquals(
374             types.resolveActualTypeArguments(element(DiamondA.class), declaredType),
375             Arrays.asList(type(String[][].class), type(Integer[].class))
376         );
377 
378         assertEquals(
379             types.resolveActualTypeArguments(element(DiamondA.class), type(DiamondD.class)),
380             Arrays.asList(type(String[].class), type(Integer[].class))
381         );
382 
383         // Test raw type SubDiamondB. The super types of a raw type are the supertypes of the prototypical type (as defined by
384         // TypeElement#asType())
385         TypeMirror expectedTypeArgument
386             = types.getArrayType(types.getArrayType(element(SubDiamondB.class).getTypeParameters().get(0).asType()));
387         assertEquals(
388             types.resolveActualTypeArguments(element(DiamondA.class), type(SubDiamondB.class)),
389             Arrays.asList(expectedTypeArgument, type(Integer[].class))
390         );
391 
392         assertEquals(
393             types.resolveActualTypeArguments(element(DiamondA.class), type(SubSubDiamondB.class)),
394             Arrays.asList(type(Integer[][][].class), type(Integer[].class))
395         );
396     }
397 
398     /**
399      * Verifies {@link AbstractTypes#isSubtype(TypeMirror, TypeMirror)} if one of the types is a primitive type.
400      */
401     @Test
402     public void testIsSubtypePrimitive() {
403         // Primitives
404         assertTrue(types.isSubtype(type(double.class), type(double.class)));
405         assertTrue(types.isSubtype(type(float.class), type(double.class)));
406         assertTrue(types.isSubtype(type(long.class), type(double.class)));
407         assertTrue(types.isSubtype(type(int.class),  type(double.class)));
408         assertTrue(types.isSubtype(type(short.class),type(double.class)));
409         assertTrue(types.isSubtype(type(byte.class), type(double.class)));
410         assertTrue(types.isSubtype(type(char.class), type(double.class)));
411 
412         assertTrue(types.isSubtype(type(int.class), type(int.class)));
413         assertTrue(types.isSubtype(type(short.class), type(int.class)));
414         assertTrue(types.isSubtype(type(byte.class), type(int.class)));
415         assertTrue(types.isSubtype(type(char.class), type(int.class)));
416 
417         assertTrue(types.isSubtype(type(short.class), type(short.class)));
418         assertTrue(types.isSubtype(type(byte.class), type(short.class)));
419         assertFalse(types.isSubtype(type(char.class), type(short.class)));
420 
421         assertFalse(types.isSubtype(type(Object.class), type(int.class)));
422         assertFalse(types.isSubtype(type(int.class), type(Object.class)));
423         assertFalse(types.isSubtype(type(Integer.class), type(int.class)));
424         assertFalse(types.isSubtype(type(int.class), type(Integer.class)));
425         assertFalse(types.isSubtype(type(int[].class), type(int.class)));
426         assertFalse(types.isSubtype(type(int.class), type(int[].class)));
427 
428         // JLS-mandated classes
429         assertTrue(types.isSubtype(type(Object.class), type(Object.class)));
430         assertTrue(types.isSubtype(type(Serializable.class), type(Object.class)));
431         assertFalse(types.isSubtype(type(Object.class), type(Serializable.class)));
432 
433         // Elementary subtyping
434         assertTrue(types.isSubtype(type(Number.class), type(Object.class)));
435         assertFalse(types.isSubtype(type(Object.class), type(Number.class)));
436     }
437 
438     /**
439      * Verifies {@link AbstractTypes#isSubtype(TypeMirror, TypeMirror)} if one of the types is the null type.
440      */
441     @Test
442     public void testIsSubtypeNull() {
443         assertFalse(types.isSubtype(types.getNullType(), type(int.class)));
444         assertFalse(types.isSubtype(type(int.class), types.getNullType()));
445 
446         assertFalse(types.isSubtype(type(Object.class), types.getNullType()));
447         assertTrue(types.isSubtype(types.getNullType(), type(Object.class)));
448     }
449 
450     /**
451      * Verifies {@link AbstractTypes#isSubtype(TypeMirror, TypeMirror)} if one of the types is an array type.
452      */
453     @Test
454     public void testIsSubtypeArray() {
455         // arrayType represents List<String>[][]
456         TypeMirror arrayType
457             = types.getArrayType(types.getArrayType(types.getDeclaredType(element(List.class), type(String.class))));
458 
459         assertTrue(types.isSubtype(arrayType, arrayType));
460         assertTrue(types.isSubtype(arrayType, type(Serializable.class)));
461         assertTrue(types.isSubtype(arrayType, type(Cloneable.class)));
462         assertTrue(types.isSubtype(arrayType, type(Object.class)));
463         assertTrue(types.isSubtype(arrayType, type(Object[].class)));
464         assertTrue(types.isSubtype(arrayType, type(Object[][].class)));
465 
466         assertFalse(types.isSubtype(arrayType, type(Number.class)));
467         assertFalse(types.isSubtype(type(Number.class), arrayType));
468 
469         assertTrue(types.isSubtype(type(int[][].class), type(int[][].class)));
470         assertTrue(types.isSubtype(type(char[][].class), type(int[][].class)));
471         assertFalse(types.isSubtype(type(int[][].class), type(char[][].class)));
472     }
473 
474     /**
475      * Verifies {@link AbstractTypes#isSubtype(TypeMirror, TypeMirror)} if one of the types is an intersection type.
476      */
477     @Test
478     public void testIsSubtypeIntersection() {
479         TypeMirror serializableAndCloneableType
480             = types.getIntersectionType(type(Serializable.class), type(Cloneable.class));
481 
482         assertTrue(types.isSubtype(serializableAndCloneableType, type(Serializable.class)));
483         assertTrue(types.isSubtype(serializableAndCloneableType, type(Cloneable.class)));
484         assertTrue(types.isSubtype(serializableAndCloneableType, serializableAndCloneableType));
485         assertFalse(types.isSubtype(type(Cloneable.class), serializableAndCloneableType));
486 
487         TypeMirror serializableCloneableListType
488             = types.getIntersectionType(type(Serializable.class), type(Cloneable.class), type(List.class));
489 
490         // Mathematically, the following should be true, but a subtype relationship is not mandated by the JLS.
491         // Therefore, currently we use assertFalse.
492         assertFalse(types.isSubtype(serializableCloneableListType, serializableAndCloneableType));
493     }
494 
495     /**
496      * Verifies {@link AbstractTypes#isSubtype(TypeMirror, TypeMirror)} if one of the types is a raw type.
497      */
498     @Test
499     public void testIsSubtypeRaw() {
500         // Test that raw type DiamondB is subtype of raw type DiamondA
501         assertTrue(types.isSubtype(type(DiamondB.class), type(DiamondA.class)));
502 
503         // aWildcardType: DiamondA<? extends Object[], Integer[]>
504         DeclaredType aWildcardType = types.getDeclaredType(
505             element(DiamondA.class),
506             types.getWildcardType(type(Object[].class), null),
507             type(Integer[].class)
508         );
509         // According to JLS §4.10.2, DiamondA<? extends Object[], Integer[]>  :>  DiamondA<T[], Integer[]>  :>  DiamondB
510         assertTrue(types.isSubtype(type(DiamondB.class), aWildcardType));
511 
512 
513         // aType: DiamondA<Object[], Integer[]>
514         DeclaredType aType = types.getDeclaredType(element(DiamondA.class), type(Object[].class), type(Integer[].class));
515         // Since T[] (i.e., the first type argument to DiamondB's direct superclass) is not contained by Object[] (in
516         // the sense of JLS §4.5.1), the raw type DiamondB is not a subtype of DiamondA<Object[], Integer[]>
517         assertFalse(types.isSubtype(type(DiamondB.class), aType));
518 
519         // List is not a subtype of List<?>. While
520         // List list = (List<?>) null
521         // would compile without error (even without warning), this is not because of a subtype relationship, but only
522         // allowed because of JLS §5.1.9 (unchecked conversion).
523         DeclaredType rawListType = (DeclaredType) type(List.class);
524         DeclaredType anyListType = types.getDeclaredType(element(List.class), types.getWildcardType(null, null));
525         assertFalse(types.isSubtype(rawListType, anyListType));
526         assertTrue(types.isSubtype(anyListType, rawListType));
527 
528         assertTrue(types.isSubtype(type(RawSubExtendsParameterized.class), type(ExtendsParameterized.class)));
529         // rawParameterizedType: RawSubExtendsParameterized<Integer>
530         DeclaredType rawParameterizedType
531             = types.getDeclaredType(element(RawSubExtendsParameterized.class), type(Integer.class));
532         assertTrue(types.isSubtype(rawParameterizedType, type(ExtendsParameterized.class)));
533         // See explanation for List test case above.
534         assertFalse(
535             types.isSubtype(
536                 rawParameterizedType,
537                 types.getDeclaredType(element(ExtendsParameterized.class), types.getWildcardType(null, null))
538             )
539         );
540     }
541 
542     @Test
543     public void testIsSubtypeArrayTypeParameters() {
544         // aType: DiamondA<? extends Serializable, ? extends Number[]>
545         DeclaredType aType = types.getDeclaredType(
546             element(DiamondA.class),
547             types.getWildcardType(type(Serializable.class), null),
548             types.getWildcardType(type(Number[].class), null)
549         );
550         // bType: DiamondB<?>
551         DeclaredType bType = types.getDeclaredType(element(DiamondB.class), types.getWildcardType(null, null));
552         assertTrue(types.isSubtype(bType, aType));
553 
554         // a2Type: DiamondA<? extends Object[], ? extends Number[]>
555         DeclaredType a2Type = types.getDeclaredType(
556             element(DiamondA.class),
557             types.getWildcardType(type(Object[].class), null),
558             types.getWildcardType(type(Number[].class), null)
559         );
560         // b2Type: DiamondB<Integer>
561         DeclaredType b2Type = types.getDeclaredType(element(DiamondB.class), type(Integer.class));
562         assertTrue(types.isSubtype(b2Type, a2Type));
563 
564         // a3Type: DiamondA<? extends Serializable, ? extends Number[]>
565         DeclaredType a3Type = types.getDeclaredType(
566             element(DiamondA.class),
567             types.getWildcardType(type(Serializable.class), null),
568             types.getWildcardType(type(Number[].class), null)
569         );
570         assertTrue(types.isSubtype(type(DiamondD.class), a3Type));
571     }
572 
573     @Test
574     public void testIsSubtypeSimpleTypeParameters() {
575         // collectionOfNumbersType: Collection<Number>
576         DeclaredType collectionOfNumbersType = types.getDeclaredType(element(Collection.class), type(Number.class));
577 
578         // JLS §4.10.2, raw type is supertype
579         assertTrue(types.isSubtype(collectionOfNumbersType, type(Collection.class)));
580 
581         // A generic type is not a supertype of the raw type. Assignment is allowed, though, through an unchecked
582         // conversion (JLS §5.1.9), which "causes a compile-time unchecked warning".
583         assertFalse(types.isSubtype(type(Collection.class), collectionOfNumbersType));
584 
585         // collectionOfIntegersType: Collection<Integer>
586         DeclaredType collectionOfIntegersType = types.getDeclaredType(element(Collection.class), type(Integer.class));
587 
588         // Collection<Integer> is not a subtype of Collection<Number>
589         assertFalse(types.isSubtype(collectionOfIntegersType, collectionOfNumbersType));
590 
591         // wildcardCollectionType now represents Collection<? extends Number>
592         DeclaredType wildcardCollectionType = types.getDeclaredType(
593             element(Collection.class),
594             types.getWildcardType(type(Number.class), null)
595         );
596         assertTrue(types.isSubtype(collectionOfIntegersType, wildcardCollectionType));
597     }
598 
599     @Test
600     public void testIsSubtypeWildcards() {
601         // setType1: Set<List<Integer>>
602         DeclaredType setType1 = types.getDeclaredType(
603             element(Set.class),
604             types.getDeclaredType(element(List.class), type(Integer.class))
605         );
606         assertTrue(types.isSubtype(type(IntegerListSet.class), setType1));
607 
608         // setType2: Set<? extends List<? extends Integer>>
609         DeclaredType setType2 = types.getDeclaredType(
610             element(Set.class),
611             types.getWildcardType(
612                 types.getDeclaredType(element(List.class), types.getWildcardType(type(Integer.class), null)),
613                 null
614             )
615         );
616         assertTrue(types.isSubtype(type(IntegerListSet.class), setType2));
617 
618         // setType3: Set<? super List<? super Integer>>
619         DeclaredType setType3 = types.getDeclaredType(
620             element(Set.class),
621             types.getWildcardType(
622                 null,
623                 types.getDeclaredType(element(List.class), types.getWildcardType(null, type(Integer.class)))
624             )
625         );
626         // setType4: Set<Collection<? super Integer>>
627         DeclaredType setType4 = types.getDeclaredType(
628             element(Set.class),
629             types.getDeclaredType(element(Collection.class), types.getWildcardType(null, type(Integer.class)))
630         );
631         assertTrue(types.isSubtype(setType4, setType3));
632 
633         // setType5: Set<Collection<? super Number>>
634         DeclaredType setType5 = types.getDeclaredType(
635             element(Set.class),
636             types.getDeclaredType(element(Collection.class), types.getWildcardType(null, type(Number.class)))
637         );
638         // Note that Set<Collection<? super Number>> is not a subtype of Set<? super List<? super Integer>>. Otherwise,
639         // List<? super Number> would be a subtype of Collection<? super Integer>, implying that "? super Integer"
640         // contains (§4.5.1) "? super Number", implying that Number is a subtype of Integer. A contradiction.
641         assertFalse(types.isSubtype(setType5, setType3));
642 
643         // Also, IntegerListSet, which implements Set<List<Integer>>, is not a subtype of
644         // Set<? super List<? super Integer>>. Otherwise, List<Integer> would be contained by
645         // "? super List<? super Integer>", implying that List<? super Integer> is a subtype of List<Integer>. A
646         // contradiction.
647         assertFalse(types.isSubtype(type(IntegerListSet.class), setType3));
648 
649         // simpleParameterizedType1: ExtendsParameterized<? extends SimpleA>
650         DeclaredType superType = types.getDeclaredType(
651             element(ExtendsParameterized.class),
652             types.getWildcardType(type(SimpleA.class), null)
653         );
654         // simpleParameterizedType2: ExtendsParameterized<? extends SimpleB>
655         DeclaredType subType = types.getDeclaredType(
656             element(ExtendsParameterized.class),
657             types.getWildcardType(type(SimpleB.class), null)
658         );
659         assertTrue(types.isSubtype(subType, superType));
660         // ExtendsParameterized<? extends SimpleA> is a subtype of
661         // ExtendsParameterized<? extends SimpleB>, even
662         // though SimpleB does not "contain" (JLS §4.5.1) SimpleA. Reason: The "contains"
663         // relationship is irrelevant for the test, because the supertypes of
664         // ExtendsParameterized<? extends SimpleB> are exactly those that are the supertypes of its capture
665         // conversion (JLS §4.10.2).
666         assertTrue(types.isSubtype(superType, subType));
667 
668         // extendsParameterized1: ExtendsParameterized<? super SimpleC>
669         DeclaredType extendsParameterized1 = types.getDeclaredType(
670             element(ExtendsParameterized.class),
671             types.getWildcardType(null, type(SimpleC.class))
672         );
673         assertTrue(types.isSubtype(extendsParameterized1, superType));
674 
675         // extendsParameterized2: ExtendsParameterized<SimpleC>
676         DeclaredType extendsParameterized2
677             = types.getDeclaredType(element(ExtendsParameterized.class), type(SimpleC.class));
678         assertTrue(types.isSubtype(extendsParameterized2, superType));
679 
680         // simpleParameterizedType1: SimpleParameterized<? extends SimpleA>
681         DeclaredType simpleParameterizedType1 = types.getDeclaredType(
682             element(SimpleParameterized.class),
683             types.getWildcardType(type(SimpleA.class), null)
684         );
685         // simpleParameterizedType2 now represents SimpleParameterized<? extends SimpleB>
686         DeclaredType simpleParameterizedType2 = types.getDeclaredType(
687             element(SimpleParameterized.class),
688             types.getWildcardType(type(SimpleB.class), null)
689         );
690         assertTrue(types.isSubtype(simpleParameterizedType2, simpleParameterizedType1));
691         // Note that this is unlike above, because the type parameter of SimpleParameterized does not have an explicit
692         // lower bound.
693         assertFalse(types.isSubtype(simpleParameterizedType1, simpleParameterizedType2));
694     }
695 
696     /**
697      * Verifies {@link AbstractTypes#capture(TypeMirror)}.
698      */
699     @Test
700     public void capture() {
701         assertEquals(types.capture(type(Integer.class)), type(Integer.class));
702 
703         DeclaredType outerClassType = types.getDeclaredType(element(OuterClass.class), type(Integer.class));
704         DeclaredType arrayListOfIntegersType = types.getDeclaredType(element(ArrayList.class), type(Integer.class));
705         // innerClassType: OuterClass<Integer>.InnerClass<? extends ArrayList<Integer>>
706         DeclaredType innerClassType = types.getDeclaredType(
707             outerClassType,
708             element(OuterClass.InnerClass.class),
709             types.getWildcardType(arrayListOfIntegersType, null)
710         );
711 
712         DeclaredType capturedType = (DeclaredType) types.capture(innerClassType);
713         TypeVariable actualTypeArgument = (TypeVariable) capturedType.getTypeArguments().get(0);
714 
715         // intersectionType = glb(ArrayList<Integer>, List<?>, Serializable)
716         IntersectionType intersectionType = (IntersectionType) actualTypeArgument.getUpperBound();
717         assertTrue(isSubtypeOfOneOf(arrayListOfIntegersType, intersectionType.getBounds()));
718 
719         PrimitiveType intType = types.getPrimitiveType(TypeKind.INT);
720         assertTrue(types.isSameType(types.capture(intType), intType));
721     }
722 
723     @Test
724     public void captureSingleRecursiveBound() {
725         // enumType: Enum<?>
726         DeclaredType enumType = types.getDeclaredType(element(Enum.class), types.getWildcardType(null, null));
727 
728         // capture: java.lang.Enum<capture<?>>
729         DeclaredType capture = (DeclaredType) types.capture(enumType);
730 
731         assertEquals(capture.getTypeArguments().size(), 1);
732         TypeVariable newTypeVariable = (TypeVariable) capture.getTypeArguments().get(0);
733         DeclaredType upperBound = (DeclaredType) newTypeVariable.getUpperBound();
734         assertEquals(upperBound.getKind(), TypeKind.DECLARED);
735 
736         // Since Enum has a recursive type bound, upperBound must represent Enum<capture<?>> as well!
737         assertEquals(capture, upperBound);
738 
739         // The following should be implied, but explicit test does not hurt
740         TypeElement upperBoundAsElement = (TypeElement) upperBound.asElement();
741         assertTrue(upperBoundAsElement.getQualifiedName().contentEquals(Enum.class.getName()));
742     }
743 
744     @Test
745     public void captureInterdependentRecursiveBound() {
746         // aType1: InterdependentRecursiveBoundA<?, ?>
747         DeclaredType aType1 = types.getDeclaredType(
748             element(InterdependentRecursiveBoundA.class),
749             types.getWildcardType(null, null),
750             types.getWildcardType(null, null)
751         );
752         DeclaredType aCapture1 = (DeclaredType) types.capture(aType1);
753         TypeVariable captureForT1 = (TypeVariable) aCapture1.getTypeArguments().get(0);
754         TypeVariable captureForU1 = (TypeVariable) aCapture1.getTypeArguments().get(1);
755 
756         DeclaredType captureForTUpperBound1 = (DeclaredType) captureForT1.getUpperBound();
757         assertEquals(captureForTUpperBound1.getTypeArguments().get(0), captureForT1);
758         assertEquals(captureForTUpperBound1.getTypeArguments().get(1), captureForU1);
759         assertEquals(captureForU1.getUpperBound(), captureForT1);
760 
761 
762         // aType2: InterdependentRecursiveBoundA<? super InterdependentRecursiveBoundB, ? extends Serializable>
763         DeclaredType aType2 = types.getDeclaredType(
764             element(InterdependentRecursiveBoundA.class),
765             types.getWildcardType(null, type(InterdependentRecursiveBoundB.class)),
766             types.getWildcardType(type(Serializable.class), null)
767         );
768         DeclaredType aCapture2 = (DeclaredType) types.capture(aType2);
769         assertEquals(aCapture2.getTypeArguments().size(), 2);
770 
771         TypeVariable captureForT2 = (TypeVariable) aCapture2.getTypeArguments().get(0);
772         TypeVariable captureForU2 = (TypeVariable) aCapture2.getTypeArguments().get(1);
773 
774         DeclaredType captureForTUpperBound2 = (DeclaredType) captureForT2.getUpperBound();
775         assertEquals(captureForTUpperBound2.getTypeArguments().get(0), captureForT2);
776         assertEquals(captureForTUpperBound2.getTypeArguments().get(1), captureForU2);
777         DeclaredType captureForTLowerBound2 = (DeclaredType) captureForT2.getLowerBound();
778         assertEquals(captureForTLowerBound2, type(InterdependentRecursiveBoundB.class));
779 
780         IntersectionType intersectionType = (IntersectionType) captureForU2.getUpperBound();
781         assertTrue(intersectionType.getBounds().contains(captureForT2));
782         assertTrue(intersectionType.getBounds().contains(type(Serializable.class)));
783 
784         // aType3: InterdependentRecursiveBoundA<InterdependentRecursiveBoundB, ?>
785         DeclaredType aType3 = types.getDeclaredType(
786             element(InterdependentRecursiveBoundA.class),
787             type(InterdependentRecursiveBoundB.class),
788             types.getWildcardType(null, null)
789         );
790         DeclaredType aCapture3 = (DeclaredType) types.capture(aType3);
791         assertEquals(aCapture3.getTypeArguments().get(0), type(InterdependentRecursiveBoundB.class));
792         TypeVariable captureForU3 = (TypeVariable) aCapture3.getTypeArguments().get(1);
793         assertEquals(captureForU3.getUpperBound(), type(InterdependentRecursiveBoundB.class));
794     }
795 
796     /**
797      * Verifies that {@link AbstractTypes#contains(TypeMirror, TypeMirror)} throws expected exceptions.
798      */
799     @Test
800     public void testContainsInvalidArguments() {
801         try {
802             types.contains(type(Object.class), null);
803             Assert.fail("Exception expected.");
804         } catch (NullPointerException ignore) { }
805 
806         try {
807             types.contains(null, type(Object.class));
808             Assert.fail("Exception expected.");
809         } catch (NullPointerException ignore) { }
810 
811         try {
812             types.contains(null, null);
813             Assert.fail("Exception expected.");
814         } catch (NullPointerException ignore) { }
815     }
816 
817     /**
818      * Verifies {@link AbstractTypes#contains(TypeMirror, TypeMirror)}.
819      */
820     @Test
821     public void testContains() {
822         WildcardType extendsWildcard = types.getWildcardType(null, null);
823         WildcardType extendsObjectWildcard = types.getWildcardType(type(Object.class), null);
824         WildcardType extendsIntegerWildcard = types.getWildcardType(type(Integer.class), null);
825         WildcardType extendsNumberWildcard = types.getWildcardType(type(Number.class), null);
826         WildcardType superIntegerWildcard = types.getWildcardType(null, type(Integer.class));
827         WildcardType superNumberWildcard = types.getWildcardType(null, type(Number.class));
828 
829         // ? extends T <= ? extends S if T <: S
830         assertTrue(types.contains(extendsNumberWildcard, extendsIntegerWildcard));
831         assertFalse(types.contains(extendsIntegerWildcard, extendsNumberWildcard));
832 
833         // ? extends T <= ?
834         assertTrue(types.contains(extendsWildcard, extendsIntegerWildcard));
835         assertFalse(types.contains(extendsIntegerWildcard, extendsWildcard));
836 
837         // ? super T <= ? super S if S <: T
838         assertTrue(types.contains(superIntegerWildcard, superNumberWildcard));
839         assertFalse(types.contains(superNumberWildcard, superIntegerWildcard));
840 
841         // ? super T <= ?
842         assertTrue(types.contains(extendsWildcard, superIntegerWildcard));
843         assertFalse(types.contains(superIntegerWildcard, extendsWildcard));
844 
845         // ? super T <= ? extends Object
846         assertTrue(types.contains(extendsObjectWildcard, superIntegerWildcard));
847         assertFalse(types.contains(superIntegerWildcard, extendsObjectWildcard));
848         assertFalse(types.contains(extendsNumberWildcard, superIntegerWildcard));
849 
850         // T <= T
851         assertTrue(types.contains(type(Integer.class), type(Integer.class)));
852         assertFalse(types.contains(type(Number.class), type(Integer.class)));
853         assertFalse(types.contains(type(Integer.class), type(Number.class)));
854 
855         // T <= ? extends T
856         assertTrue(types.contains(extendsIntegerWildcard, type(Integer.class)));
857         assertFalse(types.contains(type(Integer.class), extendsIntegerWildcard));
858 
859         // T <= ? super T
860         assertTrue(types.contains(superIntegerWildcard, type(Integer.class)));
861         assertFalse(types.contains(type(Integer.class), superIntegerWildcard));
862 
863         // Verify transitive closure
864 
865         // T <= ?
866         assertTrue(types.contains(extendsWildcard, type(Integer.class)));
867         assertFalse(types.contains(type(Integer.class), extendsWildcard));
868 
869         // T <= ? extends Object
870         assertTrue(types.contains(extendsObjectWildcard, type(Integer.class)));
871         assertFalse(types.contains(type(Integer.class), extendsObjectWildcard));
872 
873         // ? <= ? super T
874         assertFalse(types.contains(superNumberWildcard, extendsWildcard));
875 
876         // ? [extends Object] <= ? [extends Object]
877         assertTrue(types.contains(extendsObjectWildcard, extendsObjectWildcard));
878         assertTrue(types.contains(extendsObjectWildcard, extendsWildcard));
879         assertTrue(types.contains(extendsWildcard, extendsWildcard));
880         assertTrue(types.contains(extendsWildcard, extendsObjectWildcard));
881 
882         assertFalse(types.contains(extendsNumberWildcard, extendsObjectWildcard));
883         assertFalse(types.contains(extendsNumberWildcard, extendsWildcard));
884     }
885 
886     /**
887      * Verifies that {@link AbstractTypes#erasure(TypeMirror)} throws expected exceptions.
888      */
889     @Test
890     public void testErasureInvalidArguments() {
891         try {
892             types.erasure(null);
893             Assert.fail("Exception expected.");
894         } catch (NullPointerException ignore) { }
895     }
896 
897     /**
898      * Verifies {@link AbstractTypes#erasure(TypeMirror)}.
899      */
900     @Test
901     public void testErasure() {
902         // Parameterized type
903         DeclaredType listOfStringsType = types.getDeclaredType(element(List.class), type(String.class));
904         assertTrue(types.isSameType(types.erasure(listOfStringsType), type(List.class)));
905 
906         // Nested type
907         DeclaredType outerClassType = types.getDeclaredType(element(OuterClass.class), type(Integer.class));
908         DeclaredType arrayListOfIntegersType = types.getDeclaredType(element(ArrayList.class), type(Integer.class));
909         DeclaredType innerClassType
910             = types.getDeclaredType(outerClassType, element(OuterClass.InnerClass.class), arrayListOfIntegersType);
911 
912         DeclaredType expectedErasedNestedType
913             = types.getDeclaredType((DeclaredType) type(OuterClass.class), element(OuterClass.InnerClass.class));
914         assertTrue(types.isSameType(types.erasure(innerClassType), expectedErasedNestedType));
915 
916         // Array type
917         TypeMirror arrayType = types.getArrayType(listOfStringsType);
918         assertTrue(types.isSameType(types.erasure(arrayType), types.getArrayType(type(List.class))));
919 
920         // Type variable
921         TypeElement listDeclaration = element(List.class);
922         TypeVariable simpleTypeVariable = types.createTypeVariable(listDeclaration.getTypeParameters().get(0), null);
923         types.setTypeVariableBounds(simpleTypeVariable, type(Number.class), types.getNullType());
924         assertTrue(types.isSameType(types.erasure(simpleTypeVariable), type(Number.class)));
925 
926         TypeVariable multiBoundTypeVariable
927             = types.createTypeVariable(listDeclaration.getTypeParameters().get(0), null);
928         types.setTypeVariableBounds(multiBoundTypeVariable,
929             types.getIntersectionType(type(List.class), type(Serializable.class)), types.getNullType());
930         assertTrue(types.isSameType(types.erasure(multiBoundTypeVariable), type(List.class)));
931 
932         // Every other type
933         PrimitiveType booleanType = types.getPrimitiveType(TypeKind.BOOLEAN);
934         assertTrue(types.isSameType(types.erasure(booleanType), booleanType));
935         assertTrue(types.isSameType(types.erasure(types.getNullType()), types.getNullType()));
936     }
937 
938     /**
939      * Verifies that {@link AbstractTypes#asElement(TypeMirror)} throws expected exceptions.
940      */
941     @Test
942     public void asElementInvalidArguments() {
943         try {
944             types.asElement(null);
945             Assert.fail("Exception expected.");
946         } catch (NullPointerException ignore) { }
947     }
948 
949     /**
950      * Verifies {@link AbstractTypes#asElement(TypeMirror)}.
951      */
952     @Test
953     public void asElement() {
954         assertEquals(types.asElement(type(List.class)), element(List.class));
955         assertEquals(types.asElement(type(Integer.class)), element(Integer.class));
956 
957         TypeElement listDeclaration = element(List.class);
958         TypeVariable simpleTypeVariable = types.createTypeVariable(listDeclaration.getTypeParameters().get(0), null);
959         types.setTypeVariableBounds(simpleTypeVariable, type(Number.class), types.getNullType());
960         assertEquals(types.asElement(simpleTypeVariable), listDeclaration.getTypeParameters().get(0));
961 
962         assertNull(types.asElement(types.getPrimitiveType(TypeKind.INT)));
963     }
964 
965     /**
966      * Verifies {@link TypeElement#asType()}.
967      */
968     @Test
969     public void asType() {
970         DeclaredType typesContractType = (DeclaredType) type(getClass());
971         TypeElement outerClassDeclaration = element(OuterClass.class);
972         TypeElement innerClassDeclaration = element(OuterClass.InnerClass.class);
973 
974         DeclaredType outerClassType= types.getDeclaredType(
975             typesContractType, outerClassDeclaration, outerClassDeclaration.getTypeParameters().get(0).asType());
976         DeclaredType innerClassType = types.getDeclaredType(
977             outerClassType, innerClassDeclaration, innerClassDeclaration.getTypeParameters().get(0).asType());
978         assertEquals(innerClassDeclaration.asType(), innerClassType);
979     }
980 
981     /**
982      * Verifies that {@link AbstractTypes#isSameType(TypeMirror, TypeMirror)} throws expected exceptions.
983      */
984     @Test
985     public void testIsSameTypeInvalidArguments() {
986         try {
987             types.isSameType(null, type(Object.class));
988             Assert.fail("Exception expected.");
989         } catch (NullPointerException ignore) { }
990 
991         try {
992             types.isSameType(type(Object.class), null);
993             Assert.fail("Exception expected.");
994         } catch (NullPointerException ignore) { }
995 
996         try {
997             types.isSameType(null, null);
998             Assert.fail("Exception expected.");
999         } catch (NullPointerException ignore) { }
1000     }
1001 
1002     /**
1003      * Verifies {@link AbstractTypes#isSameType(TypeMirror, TypeMirror)}.
1004      */
1005     @Test
1006     public void testIsSameType() {
1007         assertTrue(types.isSameType(type(Object.class), type(Object.class)));
1008         assertFalse(types.isSameType(type(Object.class), type(Number.class)));
1009 
1010         WildcardType wildcardType = types.getWildcardType(null, null);
1011         assertFalse(types.isSameType(wildcardType, wildcardType));
1012     }
1013 
1014     private boolean isSubtypeOfOneOf(TypeMirror subtype, List<? extends TypeMirror> supertypes) {
1015         for (TypeMirror supertype: supertypes) {
1016             if (types.isSubtype(subtype, supertype)) {
1017                 return true;
1018             }
1019         }
1020         return false;
1021     }
1022 
1023     /**
1024      * Verifies
1025      * {@link AbstractTypes#getTypeVariable(TypeParameterElement, TypeMirror, TypeMirror, WildcardType)}.
1026      */
1027     @Test
1028     public void testGetTypeVariable() {
1029         TypeElement listDeclaration = element(List.class);
1030         TypeParameterElement elementTypeParameter = listDeclaration.getTypeParameters().get(0);
1031 
1032         TypeVariable typeVariable
1033             = types.getTypeVariable(elementTypeParameter, type(Integer.class), types.getNullType(), null);
1034         assertEquals(typeVariable.asElement(), elementTypeParameter);
1035         assertTrue(types.isSameType(typeVariable.getUpperBound(), type(Integer.class)));
1036         assertTrue(types.isSameType(typeVariable.getLowerBound(), types.getNullType()));
1037         assertNull(types.capturedTypeArgument(typeVariable));
1038     }
1039 
1040     /**
1041      * Verifies {@link AbstractTypes#createTypeVariable(TypeParameterElement, WildcardType)}.
1042      */
1043     @Test
1044     public void createTypeVariable() {
1045         TypeElement listDeclaration = element(List.class);
1046         TypeParameterElement elementTypeParameter = listDeclaration.getTypeParameters().get(0);
1047 
1048         TypeVariable typeVariable = types.createTypeVariable(elementTypeParameter, null);
1049         try {
1050             typeVariable.getUpperBound();
1051             Assert.fail("Expected exception.");
1052         } catch (IllegalStateException ignored) { }
1053 
1054         try {
1055             typeVariable.getLowerBound();
1056             Assert.fail("Expected exception.");
1057         } catch (IllegalStateException ignored) { }
1058     }
1059 
1060     /**
1061      * Verifies {@link AbstractTypes#setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)}.
1062      */
1063     @Test
1064     public void testSetTypeVariableBounds() {
1065         TypeElement listDeclaration = element(List.class);
1066         TypeParameterElement elementTypeParameter = listDeclaration.getTypeParameters().get(0);
1067 
1068         TypeVariable typeVariable = types.createTypeVariable(elementTypeParameter, null);
1069         types.setTypeVariableBounds(typeVariable, type(Integer.class), types.getNullType());
1070         assertEquals(typeVariable.asElement(), elementTypeParameter);
1071         assertTrue(types.isSameType(typeVariable.getUpperBound(), type(Integer.class)));
1072         assertTrue(types.isSameType(typeVariable.getLowerBound(), types.getNullType()));
1073         assertNull(types.capturedTypeArgument(typeVariable));
1074 
1075         try {
1076             types.setTypeVariableBounds(typeVariable, type(Integer.class), types.getNullType());
1077             Assert.fail("Expected exception.");
1078         } catch (IllegalStateException ignored) { }
1079     }
1080 
1081     @Test
1082     public void testGetIntersectionType() {
1083         IntersectionType intersectionType = types.getIntersectionType(type(Cloneable.class), type(Serializable.class));
1084         assertTrue(isSubtypeOfOneOf(type(Serializable.class), intersectionType.getBounds()));
1085 
1086         try {
1087             types.getIntersectionType();
1088             Assert.fail("Expected exception.");
1089         } catch (IllegalArgumentException ignored) { }
1090 
1091         try {
1092             types.getIntersectionType(type(Cloneable.class), null);
1093             Assert.fail("Expected exception.");
1094         } catch (NullPointerException ignored) { }
1095 
1096         try {
1097             types.getIntersectionType(null, type(Cloneable.class));
1098             Assert.fail("Expected exception.");
1099         } catch (NullPointerException ignored) { }
1100     }
1101 
1102     @Test
1103     public void testToString() {
1104         // PrimitiveType
1105         for (TypeKind primitive: Arrays.asList(TypeKind.DOUBLE, TypeKind.FLOAT, TypeKind.LONG, TypeKind.INT,
1106                 TypeKind.SHORT, TypeKind.BYTE, TypeKind.CHAR, TypeKind.BOOLEAN)) {
1107             assertEquals(types.toString(types.getPrimitiveType(primitive)), primitive.toString().toLowerCase());
1108         }
1109 
1110         // NullType
1111         assertEquals(types.toString(types.getNullType()), "null");
1112 
1113         // NoType
1114         for (TypeKind noType: Arrays.asList(TypeKind.VOID, TypeKind.NONE)) {
1115             assertEquals(types.toString(types.getNoType(noType)), noType.toString().toLowerCase());
1116         }
1117 
1118         // DeclaredType
1119         DeclaredType outerClassType = types.getDeclaredType(element(OuterClass.class), type(Integer.class));
1120         DeclaredType arrayListOfIntegersType = types.getDeclaredType(element(ArrayList.class), type(Integer.class));
1121         // innerClassType: OuterClass<Integer>.InnerClass<? extends ArrayList<Integer>>
1122         DeclaredType innerClassType = types.getDeclaredType(
1123             outerClassType,
1124             element(OuterClass.InnerClass.class),
1125             types.getWildcardType(arrayListOfIntegersType, null)
1126         );
1127         assertEquals(types.toString(innerClassType), String.format("%s<%s>.%s<? extends %s<%s>>",
1128             OuterClass.class.getCanonicalName(), Integer.class.getCanonicalName(),
1129             OuterClass.InnerClass.class.getSimpleName(),
1130             ArrayList.class.getCanonicalName(), Integer.class.getCanonicalName()));
1131 
1132         // ArrayType
1133         assertEquals(types.toString(types.getArrayType(type(Integer.class))), Integer[].class.getCanonicalName());
1134 
1135         // TypeVariable
1136         TypeVariable typeVariable = (TypeVariable) element(List.class).getTypeParameters().get(0).asType();
1137         assertEquals(types.toString(typeVariable), List.class.getTypeParameters()[0].getName());
1138         // listOfNumbersType: List<? extends Number>
1139         DeclaredType listOfNumbersType
1140             = types.getDeclaredType(element(List.class), types.getWildcardType(type(Number.class), null));
1141         TypeVariable capturedTypeVariable
1142             = (TypeVariable) ((DeclaredType) types.capture(listOfNumbersType)).getTypeArguments().get(0);
1143         assertEquals(types.toString(capturedTypeVariable),
1144             String.format("capture<? extends %s>", Number.class.getCanonicalName()));
1145 
1146         // WildcardType
1147         WildcardType wildcardArgument = types.getWildcardType(null, type(Integer.class));
1148         assertEquals(types.toString(wildcardArgument), String.format("? super %s", Integer.class.getCanonicalName()));
1149 
1150         // IntersectionType
1151         IntersectionType intersectionType = types.getIntersectionType(type(Cloneable.class), type(Serializable.class));
1152         assertEquals(types.toString(intersectionType),
1153             String.format("%s & %s", Cloneable.class.getCanonicalName(), Serializable.class.getCanonicalName()));
1154     }
1155 
1156     /**
1157      * Verifies that {@link AbstractTypes#unboxedType(TypeMirror)} throws expected exceptions.
1158      */
1159     @Test
1160     public void unboxedType() {
1161         try {
1162             types.unboxedType(type(List.class));
1163             Assert.fail("Expected exception.");
1164         } catch (IllegalArgumentException ignored) { }
1165 
1166         try {
1167             types.unboxedType(types.getNullType());
1168             Assert.fail("Expected exception.");
1169         } catch (IllegalArgumentException ignored) { }
1170     }
1171 
1172     /**
1173      * Verifies that {@link AbstractTypes#boxedClass(PrimitiveType)} throws expected exceptions.
1174      */
1175     @Test
1176     public void boxedClass() {
1177         try {
1178             types.boxedClass(null);
1179             Assert.fail("Expected exception.");
1180         } catch (NullPointerException ignored) { }
1181     }
1182 
1183     /**
1184      * Verifies that {@link AbstractTypes#unboxedType(TypeMirror)} and {@link AbstractTypes#boxedClass(PrimitiveType)}
1185      * are (essentially) inverse methods of each other.
1186      */
1187     @Test
1188     public void boxingAndUnboxing() {
1189         for (TypeKind primitive: Arrays.asList(TypeKind.DOUBLE, TypeKind.FLOAT, TypeKind.LONG, TypeKind.INT,
1190                 TypeKind.SHORT, TypeKind.BYTE, TypeKind.CHAR, TypeKind.BOOLEAN)) {
1191             PrimitiveType primitiveType = types.getPrimitiveType(primitive);
1192             TypeElement boxedClass = types.boxedClass(primitiveType);
1193             PrimitiveType unboxedType = types.unboxedType(boxedClass.asType());
1194 
1195             assertEquals(unboxedType, primitiveType);
1196             assertEquals(unboxedType.getKind(), primitive);
1197         }
1198     }
1199 
1200     /**
1201      * Verifies that {@link AbstractTypes#getPrimitiveType(TypeKind)} throws expected exceptions.
1202      */
1203     @Test
1204     public void testGetPrimitiveType() {
1205         try {
1206             types.getPrimitiveType(null);
1207             Assert.fail("Expected exception.");
1208         } catch (NullPointerException ignored) { }
1209 
1210         try {
1211             types.getPrimitiveType(TypeKind.ARRAY);
1212             Assert.fail("Expected exception.");
1213         } catch (IllegalArgumentException ignored) { }
1214     }
1215 
1216     @Test
1217     public void testGetNoType() {
1218         for (TypeKind noTypeKind: Arrays.asList(TypeKind.VOID, TypeKind.NONE)) {
1219             assertEquals(types.getNoType(noTypeKind).getKind(), noTypeKind);
1220         }
1221 
1222         try {
1223             types.getNoType(null);
1224             Assert.fail("Expected exception.");
1225         } catch (NullPointerException ignored) { }
1226 
1227         try {
1228             types.getNoType(TypeKind.PACKAGE);
1229             Assert.fail("Expected exception.");
1230         } catch (IllegalArgumentException ignored) { }
1231     }
1232 
1233     @Test
1234     public void testGetNullType() {
1235         assertEquals(types.getNullType().getKind(), TypeKind.NULL);
1236     }
1237 
1238     private static void testEqualsAndHashCode(Object first, Object second) {
1239         assertTrue(first.equals(first));
1240         assertTrue(second.equals(second));
1241         assertTrue(first.equals(second));
1242         assertTrue(second.equals(first));
1243 
1244         assertFalse(first.equals(null));
1245         assertFalse(first.equals(new Object()));
1246 
1247         assertEquals(first.hashCode(), second.hashCode());
1248     }
1249 
1250     @Test
1251     public void testEqualsAndHashCode() {
1252         testEqualsAndHashCode(types.getArrayType(type(Integer.class)), types.getArrayType(type(Integer.class)));
1253         testEqualsAndHashCode(types.getPrimitiveType(TypeKind.INT), types.getPrimitiveType(TypeKind.INT));
1254         TypeElement integerDeclaration = element(Integer.class);
1255         testEqualsAndHashCode(types.getDeclaredType(integerDeclaration), types.getDeclaredType(integerDeclaration));
1256         testEqualsAndHashCode(
1257             types.getIntersectionType(type(Serializable.class), type(Cloneable.class)),
1258             types.getIntersectionType(type(Serializable.class), type(Cloneable.class))
1259         );
1260         testEqualsAndHashCode(
1261             types.getWildcardType(type(Integer.class), null),
1262             types.getWildcardType(type(Integer.class), null)
1263         );
1264         testEqualsAndHashCode(types.getNullType(), types.getNullType());
1265         testEqualsAndHashCode(types.getNoType(TypeKind.VOID), types.getNoType(TypeKind.VOID));
1266         TypeElement listDeclaration = element(List.class);
1267         TypeParameterElement listTypeParameter = listDeclaration.getTypeParameters().get(0);
1268         TypeVariable listTypeArgument = (TypeVariable) listTypeParameter.asType();
1269         testEqualsAndHashCode(
1270             listTypeArgument,
1271             types.getTypeVariable(listTypeParameter, listTypeArgument.getUpperBound(), listTypeArgument.getLowerBound(),
1272                 null)
1273         );
1274 
1275         testEqualsAndHashCode(element(Serializable.class), element(Serializable.class));
1276         testEqualsAndHashCode(listTypeParameter, listTypeParameter);
1277     }
1278 
1279     @Test
1280     public void typeElementTest() {
1281         TypeElement outerClassDeclaration = element(OuterClass.class);
1282         TypeElement innerClassDeclaration = element(OuterClass.InnerClass.class);
1283         assertEquals(innerClassDeclaration.getEnclosingElement(), outerClassDeclaration);
1284         assertTrue(outerClassDeclaration.getEnclosedElements().contains(innerClassDeclaration));
1285         assertTrue(outerClassDeclaration.getEnclosedElements().containsAll(outerClassDeclaration.getTypeParameters()));
1286 
1287         TypeElement integerDeclaration = element(Integer.class);
1288         assertEquals(integerDeclaration.getSuperclass(), type(Number.class));
1289         DeclaredType integerComparableType = types.getDeclaredType(element(Comparable.class), type(Integer.class));
1290         assertEquals(integerDeclaration.getInterfaces(), Collections.singletonList(integerComparableType));
1291         assertEquals(integerDeclaration.getQualifiedName().toString(), Integer.class.getName());
1292         assertEquals(integerDeclaration.getSimpleName().toString(), Integer.class.getSimpleName());
1293         assertEquals(integerDeclaration.asType(), type(Integer.class));
1294 
1295         // Support for methods not strictly necessary for type-system operations is optional (for instance,
1296         // getKind() or getNestingKind())
1297     }
1298 
1299     @Test
1300     public void typeParameterElementTest() {
1301         TypeElement outerClassDeclaration = element(OuterClass.class);
1302         TypeParameterElement outerClassTypeParameter = outerClassDeclaration.getTypeParameters().get(0);
1303         assertEquals(outerClassTypeParameter.getEnclosingElement(), outerClassDeclaration);
1304         assertEquals(outerClassTypeParameter.getEnclosedElements(), Collections.emptyList());
1305         assertEquals(
1306             outerClassTypeParameter.asType(),
1307             types.getTypeVariable(outerClassTypeParameter, type(Number.class), types.getNullType(), null)
1308         );
1309         assertEquals(outerClassTypeParameter.getBounds(), Collections.singletonList(type(Number.class)));
1310         assertEquals(
1311             outerClassTypeParameter.getSimpleName().toString(),
1312             OuterClass.class.getTypeParameters()[0].getName()
1313         );
1314         assertEquals(outerClassTypeParameter.getGenericElement(), outerClassTypeParameter.getEnclosingElement());
1315     }
1316 }