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.creation; 6 7 import static java.util.Arrays.asList; 8 9 import static org.mockito.internal.exceptions.Reporter.defaultAnswerDoesNotAcceptNullParameter; 10 import static org.mockito.internal.exceptions.Reporter.extraInterfacesAcceptsOnlyInterfaces; 11 import static org.mockito.internal.exceptions.Reporter.extraInterfacesDoesNotAcceptNullParameters; 12 import static org.mockito.internal.exceptions.Reporter.extraInterfacesRequiresAtLeastOneInterface; 13 import static org.mockito.internal.exceptions.Reporter.methodDoesNotAcceptParameter; 14 import static org.mockito.internal.exceptions.Reporter.requiresAtLeastOneListener; 15 import static org.mockito.internal.util.collections.Sets.newSet; 16 17 import java.io.Serializable; 18 import java.util.ArrayList; 19 import java.util.HashSet; 20 import java.util.List; 21 import java.util.Set; 22 23 import org.mockito.MockSettings; 24 import org.mockito.exceptions.base.MockitoException; 25 import org.mockito.internal.creation.settings.CreationSettings; 26 import org.mockito.internal.debugging.VerboseMockInvocationLogger; 27 import org.mockito.internal.util.Checks; 28 import org.mockito.internal.util.MockCreationValidator; 29 import org.mockito.internal.util.MockNameImpl; 30 import org.mockito.listeners.InvocationListener; 31 import org.mockito.listeners.StubbingLookupListener; 32 import org.mockito.listeners.VerificationStartedListener; 33 import org.mockito.mock.MockCreationSettings; 34 import org.mockito.mock.MockName; 35 import org.mockito.mock.SerializableMode; 36 import org.mockito.stubbing.Answer; 37 38 @SuppressWarnings("unchecked") 39 public class MockSettingsImpl<T> extends CreationSettings<T> 40 implements MockSettings, MockCreationSettings<T> { 41 42 private static final long serialVersionUID = 4475297236197939569L; 43 private boolean useConstructor; 44 private Object outerClassInstance; 45 private Object[] constructorArgs; 46 47 @Override serializable()48 public MockSettings serializable() { 49 return serializable(SerializableMode.BASIC); 50 } 51 52 @Override serializable(SerializableMode mode)53 public MockSettings serializable(SerializableMode mode) { 54 this.serializableMode = mode; 55 return this; 56 } 57 58 @Override extraInterfaces(Class<?>.... extraInterfaces)59 public MockSettings extraInterfaces(Class<?>... extraInterfaces) { 60 if (extraInterfaces == null || extraInterfaces.length == 0) { 61 throw extraInterfacesRequiresAtLeastOneInterface(); 62 } 63 64 for (Class<?> i : extraInterfaces) { 65 if (i == null) { 66 throw extraInterfacesDoesNotAcceptNullParameters(); 67 } else if (!i.isInterface()) { 68 throw extraInterfacesAcceptsOnlyInterfaces(i); 69 } 70 } 71 this.extraInterfaces = newSet(extraInterfaces); 72 return this; 73 } 74 75 @Override getMockName()76 public MockName getMockName() { 77 return mockName; 78 } 79 80 @Override getExtraInterfaces()81 public Set<Class<?>> getExtraInterfaces() { 82 return extraInterfaces; 83 } 84 85 @Override getSpiedInstance()86 public Object getSpiedInstance() { 87 return spiedInstance; 88 } 89 90 @Override name(String name)91 public MockSettings name(String name) { 92 this.name = name; 93 return this; 94 } 95 96 @Override spiedInstance(Object spiedInstance)97 public MockSettings spiedInstance(Object spiedInstance) { 98 this.spiedInstance = spiedInstance; 99 return this; 100 } 101 102 @Override defaultAnswer(Answer defaultAnswer)103 public MockSettings defaultAnswer(Answer defaultAnswer) { 104 this.defaultAnswer = defaultAnswer; 105 if (defaultAnswer == null) { 106 throw defaultAnswerDoesNotAcceptNullParameter(); 107 } 108 return this; 109 } 110 111 @Override getDefaultAnswer()112 public Answer<Object> getDefaultAnswer() { 113 return defaultAnswer; 114 } 115 116 @Override stubOnly()117 public MockSettingsImpl<T> stubOnly() { 118 this.stubOnly = true; 119 return this; 120 } 121 122 @Override useConstructor(Object... constructorArgs)123 public MockSettings useConstructor(Object... constructorArgs) { 124 Checks.checkNotNull( 125 constructorArgs, 126 "constructorArgs", 127 "If you need to pass null, please cast it to the right type, e.g.: useConstructor((String) null)"); 128 this.useConstructor = true; 129 this.constructorArgs = constructorArgs; 130 return this; 131 } 132 133 @Override outerInstance(Object outerClassInstance)134 public MockSettings outerInstance(Object outerClassInstance) { 135 this.outerClassInstance = outerClassInstance; 136 return this; 137 } 138 139 @Override withoutAnnotations()140 public MockSettings withoutAnnotations() { 141 stripAnnotations = true; 142 return this; 143 } 144 145 @Override isUsingConstructor()146 public boolean isUsingConstructor() { 147 return useConstructor; 148 } 149 150 @Override getOuterClassInstance()151 public Object getOuterClassInstance() { 152 return outerClassInstance; 153 } 154 155 @Override getConstructorArgs()156 public Object[] getConstructorArgs() { 157 if (outerClassInstance == null) { 158 return constructorArgs; 159 } 160 List<Object> resultArgs = new ArrayList<>(constructorArgs.length + 1); 161 resultArgs.add(outerClassInstance); 162 resultArgs.addAll(asList(constructorArgs)); 163 return resultArgs.toArray(new Object[constructorArgs.length + 1]); 164 } 165 166 @Override isStubOnly()167 public boolean isStubOnly() { 168 return this.stubOnly; 169 } 170 171 @Override verboseLogging()172 public MockSettings verboseLogging() { 173 if (!invocationListenersContainsType(VerboseMockInvocationLogger.class)) { 174 invocationListeners(new VerboseMockInvocationLogger()); 175 } 176 return this; 177 } 178 179 @Override invocationListeners(InvocationListener... listeners)180 public MockSettings invocationListeners(InvocationListener... listeners) { 181 addListeners(listeners, invocationListeners, "invocationListeners"); 182 return this; 183 } 184 185 @Override stubbingLookupListeners(StubbingLookupListener... listeners)186 public MockSettings stubbingLookupListeners(StubbingLookupListener... listeners) { 187 addListeners(listeners, stubbingLookupListeners, "stubbingLookupListeners"); 188 return this; 189 } 190 addListeners(T[] listeners, List<T> container, String method)191 static <T> void addListeners(T[] listeners, List<T> container, String method) { 192 if (listeners == null) { 193 throw methodDoesNotAcceptParameter(method, "null vararg array."); 194 } 195 if (listeners.length == 0) { 196 throw requiresAtLeastOneListener(method); 197 } 198 for (T listener : listeners) { 199 if (listener == null) { 200 throw methodDoesNotAcceptParameter(method, "null listeners."); 201 } 202 container.add(listener); 203 } 204 } 205 206 @Override verificationStartedListeners(VerificationStartedListener... listeners)207 public MockSettings verificationStartedListeners(VerificationStartedListener... listeners) { 208 addListeners(listeners, this.verificationStartedListeners, "verificationStartedListeners"); 209 return this; 210 } 211 invocationListenersContainsType(Class<?> clazz)212 private boolean invocationListenersContainsType(Class<?> clazz) { 213 for (InvocationListener listener : invocationListeners) { 214 if (listener.getClass().equals(clazz)) { 215 return true; 216 } 217 } 218 return false; 219 } 220 hasInvocationListeners()221 public boolean hasInvocationListeners() { 222 return !getInvocationListeners().isEmpty(); 223 } 224 225 @Override getTypeToMock()226 public Class<T> getTypeToMock() { 227 return typeToMock; 228 } 229 230 @Override build(Class<T2> typeToMock)231 public <T2> MockCreationSettings<T2> build(Class<T2> typeToMock) { 232 return validatedSettings(typeToMock, (CreationSettings<T2>) this); 233 } 234 235 @Override buildStatic(Class<T2> classToMock)236 public <T2> MockCreationSettings<T2> buildStatic(Class<T2> classToMock) { 237 return validatedStaticSettings(classToMock, (CreationSettings<T2>) this); 238 } 239 240 @Override lenient()241 public MockSettings lenient() { 242 this.lenient = true; 243 return this; 244 } 245 validatedSettings( Class<T> typeToMock, CreationSettings<T> source)246 private static <T> CreationSettings<T> validatedSettings( 247 Class<T> typeToMock, CreationSettings<T> source) { 248 MockCreationValidator validator = new MockCreationValidator(); 249 250 validator.validateType(typeToMock); 251 validator.validateExtraInterfaces(typeToMock, source.getExtraInterfaces()); 252 validator.validateMockedType(typeToMock, source.getSpiedInstance()); 253 254 // TODO SF - add this validation and also add missing coverage 255 // validator.validateDelegatedInstance(classToMock, settings.getDelegatedInstance()); 256 257 validator.validateConstructorUse(source.isUsingConstructor(), source.getSerializableMode()); 258 259 // TODO SF - I don't think we really need CreationSettings type 260 // TODO do we really need to copy the entire settings every time we create mock object? it 261 // does not seem necessary. 262 CreationSettings<T> settings = new CreationSettings<T>(source); 263 settings.setMockName(new MockNameImpl(source.getName(), typeToMock, false)); 264 settings.setTypeToMock(typeToMock); 265 settings.setExtraInterfaces(prepareExtraInterfaces(source)); 266 return settings; 267 } 268 validatedStaticSettings( Class<T> classToMock, CreationSettings<T> source)269 private static <T> CreationSettings<T> validatedStaticSettings( 270 Class<T> classToMock, CreationSettings<T> source) { 271 272 if (classToMock.isPrimitive()) { 273 throw new MockitoException( 274 "Cannot create static mock of primitive type " + classToMock); 275 } 276 if (!source.getExtraInterfaces().isEmpty()) { 277 throw new MockitoException( 278 "Cannot specify additional interfaces for static mock of " + classToMock); 279 } 280 if (source.getSpiedInstance() != null) { 281 throw new MockitoException( 282 "Cannot specify spied instance for static mock of " + classToMock); 283 } 284 285 CreationSettings<T> settings = new CreationSettings<T>(source); 286 settings.setMockName(new MockNameImpl(source.getName(), classToMock, true)); 287 settings.setTypeToMock(classToMock); 288 return settings; 289 } 290 prepareExtraInterfaces(CreationSettings settings)291 private static Set<Class<?>> prepareExtraInterfaces(CreationSettings settings) { 292 Set<Class<?>> interfaces = new HashSet<>(settings.getExtraInterfaces()); 293 if (settings.isSerializable()) { 294 interfaces.add(Serializable.class); 295 } 296 return interfaces; 297 } 298 } 299