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