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 44 public MockSettings serializable() { 45 return serializable(SerializableMode.BASIC); 46 } 47 48 @Override 49 public MockSettings serializable(SerializableMode mode) { 50 this.serializableMode = mode; 51 return this; 52 } 53 54 @Override 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 72 public MockName getMockName() { 73 return mockName; 74 } 75 76 @Override 77 public Set<Class<?>> getExtraInterfaces() { 78 return extraInterfaces; 79 } 80 81 @Override 82 public Object getSpiedInstance() { 83 return spiedInstance; 84 } 85 86 @Override 87 public MockSettings name(String name) { 88 this.name = name; 89 return this; 90 } 91 92 @Override 93 public MockSettings spiedInstance(Object spiedInstance) { 94 this.spiedInstance = spiedInstance; 95 return this; 96 } 97 98 @Override 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 108 public Answer<Object> getDefaultAnswer() { 109 return defaultAnswer; 110 } 111 112 @Override 113 public MockSettingsImpl<T> stubOnly() { 114 this.stubOnly = true; 115 return this; 116 } 117 118 @Override 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 129 public MockSettings outerInstance(Object outerClassInstance) { 130 this.outerClassInstance = outerClassInstance; 131 return this; 132 } 133 134 @Override 135 public MockSettings withoutAnnotations() { 136 stripAnnotations = true; 137 return this; 138 } 139 140 @Override 141 public boolean isUsingConstructor() { 142 return useConstructor; 143 } 144 145 @Override 146 public Object getOuterClassInstance() { 147 return outerClassInstance; 148 } 149 150 @Override 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 162 public boolean isStubOnly() { 163 return this.stubOnly; 164 } 165 166 @Override 167 public MockSettings verboseLogging() { 168 if (!invocationListenersContainsType(VerboseMockInvocationLogger.class)) { 169 invocationListeners(new VerboseMockInvocationLogger()); 170 } 171 return this; 172 } 173 174 @Override 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 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 196 public MockSettings verificationStartedListeners(VerificationStartedListener... listeners) { 197 addListeners(listeners, this.verificationStartedListeners, "verificationStartedListeners"); 198 return this; 199 } 200 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 211 public List<InvocationListener> getInvocationListeners() { 212 return this.invocationListeners; 213 } 214 215 public boolean hasInvocationListeners() { 216 return !invocationListeners.isEmpty(); 217 } 218 219 @Override 220 public Class<T> getTypeToMock() { 221 return typeToMock; 222 } 223 224 @Override 225 public <T> MockCreationSettings<T> build(Class<T> typeToMock) { 226 return validatedSettings(typeToMock, (CreationSettings<T>) this); 227 } 228 229 private static <T> CreationSettings<T> validatedSettings(Class<T> typeToMock, CreationSettings<T> source) { 230 MockCreationValidator validator = new MockCreationValidator(); 231 232 validator.validateType(typeToMock); 233 validator.validateExtraInterfaces(typeToMock, source.getExtraInterfaces()); 234 validator.validateMockedType(typeToMock, source.getSpiedInstance()); 235 236 //TODO SF - add this validation and also add missing coverage 237 // validator.validateDelegatedInstance(classToMock, settings.getDelegatedInstance()); 238 239 validator.validateConstructorUse(source.isUsingConstructor(), source.getSerializableMode()); 240 241 //TODO SF - I don't think we really need CreationSettings type 242 //TODO do we really need to copy the entire settings every time we create mock object? it does not seem necessary. 243 CreationSettings<T> settings = new CreationSettings<T>(source); 244 settings.setMockName(new MockNameImpl(source.getName(), typeToMock)); 245 settings.setTypeToMock(typeToMock); 246 settings.setExtraInterfaces(prepareExtraInterfaces(source)); 247 return settings; 248 } 249 250 private static Set<Class<?>> prepareExtraInterfaces(CreationSettings settings) { 251 Set<Class<?>> interfaces = new HashSet<Class<?>>(settings.getExtraInterfaces()); 252 if(settings.isSerializable()) { 253 interfaces.add(Serializable.class); 254 } 255 return interfaces; 256 } 257 258 } 259 260