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