• 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.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