• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockito.internal.util.reflection;
6 
7 import org.junit.Test;
8 
9 import java.io.Serializable;
10 import java.lang.reflect.Method;
11 import java.lang.reflect.Type;
12 import java.lang.reflect.TypeVariable;
13 import java.util.*;
14 
15 import static org.assertj.core.api.Assertions.assertThat;
16 import static org.junit.Assert.fail;
17 import static org.mockito.internal.util.reflection.GenericMetadataSupport.inferFrom;
18 
19 public class GenericMetadataSupportTest {
20 
21     interface GenericsSelfReference<T extends GenericsSelfReference<T>> {
self()22         T self();
23     }
24     interface UpperBoundedTypeWithClass<E extends Number & Comparable<E>> {
get()25         E get();
26     }
27     interface UpperBoundedTypeWithInterfaces<E extends Comparable<E> & Cloneable> {
get()28         E get();
29     }
30     interface ListOfNumbers extends List<Number> {}
31     interface AnotherListOfNumbers extends ListOfNumbers {}
32 
33     abstract class ListOfNumbersImpl implements ListOfNumbers {}
34     abstract class AnotherListOfNumbersImpl extends ListOfNumbersImpl {}
35 
36     interface ListOfAnyNumbers<N extends Number & Cloneable> extends List<N> {}
37 
38     interface GenericsNest<K extends Comparable<K> & Cloneable> extends Map<K, Set<Number>> {
remove(Object key)39         Set<Number> remove(Object key); // override with fixed ParameterizedType
returning_wildcard_with_class_lower_bound()40         List<? super Integer> returning_wildcard_with_class_lower_bound();
returning_wildcard_with_typeVar_lower_bound()41         List<? super K> returning_wildcard_with_typeVar_lower_bound();
returning_wildcard_with_typeVar_upper_bound()42         List<? extends K> returning_wildcard_with_typeVar_upper_bound();
returningK()43         K returningK();
paramType_with_type_params()44         <O extends K> List<O> paramType_with_type_params();
two_type_params()45         <S, T extends S> T two_type_params();
typeVar_with_type_params()46         <O extends K> O typeVar_with_type_params();
47     }
48 
49     static class StringList extends ArrayList<String> { }
50 
51     @Test
typeVariable_of_self_type()52     public void typeVariable_of_self_type() {
53         GenericMetadataSupport genericMetadata = inferFrom(GenericsSelfReference.class).resolveGenericReturnType(firstNamedMethod("self", GenericsSelfReference.class));
54 
55         assertThat(genericMetadata.rawType()).isEqualTo(GenericsSelfReference.class);
56     }
57 
58     @Test
can_get_raw_type_from_Class()59     public void can_get_raw_type_from_Class() throws Exception {
60         assertThat(inferFrom(ListOfAnyNumbers.class).rawType()).isEqualTo(ListOfAnyNumbers.class);
61         assertThat(inferFrom(ListOfNumbers.class).rawType()).isEqualTo(ListOfNumbers.class);
62         assertThat(inferFrom(GenericsNest.class).rawType()).isEqualTo(GenericsNest.class);
63         assertThat(inferFrom(StringList.class).rawType()).isEqualTo(StringList.class);
64     }
65 
66     @Test
can_get_raw_type_from_ParameterizedType()67     public void can_get_raw_type_from_ParameterizedType() throws Exception {
68         assertThat(inferFrom(ListOfAnyNumbers.class.getGenericInterfaces()[0]).rawType()).isEqualTo(List.class);
69         assertThat(inferFrom(ListOfNumbers.class.getGenericInterfaces()[0]).rawType()).isEqualTo(List.class);
70         assertThat(inferFrom(GenericsNest.class.getGenericInterfaces()[0]).rawType()).isEqualTo(Map.class);
71         assertThat(inferFrom(StringList.class.getGenericSuperclass()).rawType()).isEqualTo(ArrayList.class);
72     }
73 
74     @Test
can_get_type_variables_from_Class()75     public void can_get_type_variables_from_Class() throws Exception {
76         assertThat(inferFrom(GenericsNest.class).actualTypeArguments().keySet()).hasSize(1).extracting("name").contains("K");
77         assertThat(inferFrom(ListOfNumbers.class).actualTypeArguments().keySet()).isEmpty();
78         assertThat(inferFrom(ListOfAnyNumbers.class).actualTypeArguments().keySet()).hasSize(1).extracting("name").contains("N");
79         assertThat(inferFrom(Map.class).actualTypeArguments().keySet()).hasSize(2).extracting("name").contains("K", "V");
80         assertThat(inferFrom(Serializable.class).actualTypeArguments().keySet()).isEmpty();
81         assertThat(inferFrom(StringList.class).actualTypeArguments().keySet()).isEmpty();
82     }
83 
84     @Test
can_resolve_type_variables_from_ancestors()85     public void can_resolve_type_variables_from_ancestors() throws Exception {
86         Method listGet = List.class.getMethod("get", int.class);
87         assertThat(inferFrom(AnotherListOfNumbers.class).resolveGenericReturnType(listGet).rawType()).isEqualTo(Number.class);
88         assertThat(inferFrom(AnotherListOfNumbersImpl.class).resolveGenericReturnType(listGet).rawType()).isEqualTo(Number.class);
89     }
90 
91     @Test
can_get_type_variables_from_ParameterizedType()92     public void can_get_type_variables_from_ParameterizedType() throws Exception {
93         assertThat(inferFrom(GenericsNest.class.getGenericInterfaces()[0]).actualTypeArguments().keySet()).hasSize(2).extracting("name").contains("K", "V");
94         assertThat(inferFrom(ListOfAnyNumbers.class.getGenericInterfaces()[0]).actualTypeArguments().keySet()).hasSize(1).extracting("name").contains("E");
95         assertThat(inferFrom(Integer.class.getGenericInterfaces()[0]).actualTypeArguments().keySet()).hasSize(1).extracting("name").contains("T");
96         assertThat(inferFrom(StringBuilder.class.getGenericInterfaces()[0]).actualTypeArguments().keySet()).isEmpty();
97         assertThat(inferFrom(StringList.class).actualTypeArguments().keySet()).isEmpty();
98     }
99 
100     @Test
typeVariable_return_type_of____iterator____resolved_to_Iterator_and_type_argument_to_String()101     public void typeVariable_return_type_of____iterator____resolved_to_Iterator_and_type_argument_to_String() throws Exception {
102         GenericMetadataSupport genericMetadata = inferFrom(StringList.class).resolveGenericReturnType(firstNamedMethod("iterator", StringList.class));
103 
104         assertThat(genericMetadata.rawType()).isEqualTo(Iterator.class);
105         assertThat(genericMetadata.actualTypeArguments().values()).contains(String.class);
106     }
107 
108     @Test
typeVariable_return_type_of____get____resolved_to_Set_and_type_argument_to_Number()109     public void typeVariable_return_type_of____get____resolved_to_Set_and_type_argument_to_Number() throws Exception {
110         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("get", GenericsNest.class));
111 
112         assertThat(genericMetadata.rawType()).isEqualTo(Set.class);
113         assertThat(genericMetadata.actualTypeArguments().values()).contains(Number.class);
114     }
115 
116     @Test
bounded_typeVariable_return_type_of____returningK____resolved_to_Comparable_and_with_BoundedType()117     public void bounded_typeVariable_return_type_of____returningK____resolved_to_Comparable_and_with_BoundedType() throws Exception {
118         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returningK", GenericsNest.class));
119 
120         assertThat(genericMetadata.rawType()).isEqualTo(Comparable.class);
121         GenericMetadataSupport extraInterface_0 = inferFrom(genericMetadata.extraInterfaces().get(0));
122         assertThat(extraInterface_0.rawType()).isEqualTo(Cloneable.class);
123     }
124 
125     @Test
fixed_ParamType_return_type_of____remove____resolved_to_Set_and_type_argument_to_Number()126     public void fixed_ParamType_return_type_of____remove____resolved_to_Set_and_type_argument_to_Number() throws Exception {
127         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("remove", GenericsNest.class));
128 
129         assertThat(genericMetadata.rawType()).isEqualTo(Set.class);
130         assertThat(genericMetadata.actualTypeArguments().values()).contains(Number.class);
131     }
132 
133     @Test
paramType_return_type_of____values____resolved_to_Collection_and_type_argument_to_Parameterized_Set()134     public void paramType_return_type_of____values____resolved_to_Collection_and_type_argument_to_Parameterized_Set() throws Exception {
135         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("values", GenericsNest.class));
136 
137         assertThat(genericMetadata.rawType()).isEqualTo(Collection.class);
138         GenericMetadataSupport fromTypeVariableE = inferFrom(typeVariableValue(genericMetadata.actualTypeArguments(), "E"));
139         assertThat(fromTypeVariableE.rawType()).isEqualTo(Set.class);
140         assertThat(fromTypeVariableE.actualTypeArguments().values()).contains(Number.class);
141     }
142 
143     @Test
paramType_with_type_parameters_return_type_of____paramType_with_type_params____resolved_to_Collection_and_type_argument_to_Parameterized_Set()144     public void paramType_with_type_parameters_return_type_of____paramType_with_type_params____resolved_to_Collection_and_type_argument_to_Parameterized_Set() throws Exception {
145         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("paramType_with_type_params", GenericsNest.class));
146 
147         assertThat(genericMetadata.rawType()).isEqualTo(List.class);
148         Type firstBoundOfE = ((GenericMetadataSupport.TypeVarBoundedType) typeVariableValue(genericMetadata.actualTypeArguments(), "E")).firstBound();
149         assertThat(inferFrom(firstBoundOfE).rawType()).isEqualTo(Comparable.class);
150     }
151 
152     @Test
typeVariable_with_type_parameters_return_type_of____typeVar_with_type_params____resolved_K_hence_to_Comparable_and_with_BoundedType()153     public void typeVariable_with_type_parameters_return_type_of____typeVar_with_type_params____resolved_K_hence_to_Comparable_and_with_BoundedType() throws Exception {
154         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("typeVar_with_type_params", GenericsNest.class));
155 
156         assertThat(genericMetadata.rawType()).isEqualTo(Comparable.class);
157         GenericMetadataSupport extraInterface_0 = inferFrom(genericMetadata.extraInterfaces().get(0));
158         assertThat(extraInterface_0.rawType()).isEqualTo(Cloneable.class);
159     }
160 
161     @Test
class_return_type_of____append____resolved_to_StringBuilder_and_type_arguments()162     public void class_return_type_of____append____resolved_to_StringBuilder_and_type_arguments() throws Exception {
163         GenericMetadataSupport genericMetadata = inferFrom(StringBuilder.class).resolveGenericReturnType(firstNamedMethod("append", StringBuilder.class));
164 
165         assertThat(genericMetadata.rawType()).isEqualTo(StringBuilder.class);
166         assertThat(genericMetadata.actualTypeArguments()).isEmpty();
167     }
168 
169 
170 
171     @Test
paramType_with_wildcard_return_type_of____returning_wildcard_with_class_lower_bound____resolved_to_List_and_type_argument_to_Integer()172     public void paramType_with_wildcard_return_type_of____returning_wildcard_with_class_lower_bound____resolved_to_List_and_type_argument_to_Integer() throws Exception {
173         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returning_wildcard_with_class_lower_bound", GenericsNest.class));
174 
175         assertThat(genericMetadata.rawType()).isEqualTo(List.class);
176         GenericMetadataSupport.BoundedType boundedType = (GenericMetadataSupport.BoundedType) typeVariableValue(genericMetadata.actualTypeArguments(), "E");
177         assertThat(boundedType.firstBound()).isEqualTo(Integer.class);
178         assertThat(boundedType.interfaceBounds()).isEmpty();
179     }
180 
181     @Test
paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_lower_bound____resolved_to_List_and_type_argument_to_Integer()182     public void paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_lower_bound____resolved_to_List_and_type_argument_to_Integer() throws Exception {
183         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returning_wildcard_with_typeVar_lower_bound", GenericsNest.class));
184 
185         assertThat(genericMetadata.rawType()).isEqualTo(List.class);
186         GenericMetadataSupport.BoundedType boundedType = (GenericMetadataSupport.BoundedType) typeVariableValue(genericMetadata.actualTypeArguments(), "E");
187 
188         assertThat(inferFrom(boundedType.firstBound()).rawType()).isEqualTo(Comparable.class);
189         assertThat(boundedType.interfaceBounds()).contains(Cloneable.class);    }
190 
191     @Test
paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_upper_bound____resolved_to_List_and_type_argument_to_Integer()192     public void paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_upper_bound____resolved_to_List_and_type_argument_to_Integer() throws Exception {
193         GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returning_wildcard_with_typeVar_upper_bound", GenericsNest.class));
194 
195         assertThat(genericMetadata.rawType()).isEqualTo(List.class);
196         GenericMetadataSupport.BoundedType boundedType = (GenericMetadataSupport.BoundedType) typeVariableValue(genericMetadata.actualTypeArguments(), "E");
197 
198         assertThat(inferFrom(boundedType.firstBound()).rawType()).isEqualTo(Comparable.class);
199         assertThat(boundedType.interfaceBounds()).contains(Cloneable.class);
200     }
201 
typeVariableValue(Map<TypeVariable<?>, Type> typeVariables, String typeVariableName)202     private Type typeVariableValue(Map<TypeVariable<?>, Type> typeVariables, String typeVariableName) {
203         for (Map.Entry<TypeVariable<?>, Type> typeVariableTypeEntry : typeVariables.entrySet()) {
204             if (typeVariableTypeEntry.getKey().getName().equals(typeVariableName)) {
205                 return typeVariableTypeEntry.getValue();
206             }
207         }
208 
209         fail("'" + typeVariableName + "' was not found in " + typeVariables);
210         return null; // unreachable
211     }
212 
firstNamedMethod(String methodName, Class<?> clazz)213     private Method firstNamedMethod(String methodName, Class<?> clazz) {
214         for (Method method : clazz.getMethods()) {
215             boolean protect_against_different_jdk_ordering_avoiding_bridge_methods = !method.isBridge();
216             if (method.getName().contains(methodName) && protect_against_different_jdk_ordering_avoiding_bridge_methods) {
217                 return method;
218             }
219         }
220         throw new IllegalStateException("The method : '" + methodName + "' do not exist in '" + clazz.getSimpleName() + "'");
221     }
222 }
223