1
2
3
4
5
6 package mockit;
7
8 import static java.lang.reflect.Modifier.isAbstract;
9
10 import static mockit.internal.util.GeneratedClasses.isGeneratedImplementationClassName;
11
12 import edu.umd.cs.findbugs.annotations.NonNull;
13 import edu.umd.cs.findbugs.annotations.Nullable;
14
15 import java.lang.reflect.ParameterizedType;
16 import java.lang.reflect.Proxy;
17 import java.lang.reflect.Type;
18 import java.lang.reflect.TypeVariable;
19
20 import mockit.internal.classGeneration.ConcreteSubclass;
21 import mockit.internal.faking.CaptureOfFakedImplementations;
22 import mockit.internal.faking.FakeClassSetup;
23 import mockit.internal.faking.FakeClasses;
24 import mockit.internal.faking.FakeStates;
25 import mockit.internal.faking.FakedImplementationClass;
26 import mockit.internal.reflection.ConstructorReflection;
27 import mockit.internal.reflection.MockInvocationHandler;
28 import mockit.internal.startup.Startup;
29 import mockit.internal.state.TestRun;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public abstract class MockUp<T> {
75 static {
76 Startup.verifyInitialization();
77 }
78
79
80
81
82 protected final Type targetType;
83
84 @Nullable
85 private final Class<?> mockedClass;
86 @Nullable
87 private T mockInstance;
88 @Nullable
89 private T invokedInstance;
90
91
92
93
94
95
96
97
98 protected MockUp() {
99 MockUp<?> previousMockUp = findPreviouslyFakedClassIfMockUpAlreadyApplied();
100
101 if (previousMockUp != null) {
102 targetType = previousMockUp.targetType;
103 mockedClass = previousMockUp.mockedClass;
104 return;
105 }
106
107 targetType = getTypeToFake();
108 Class<T> classToMock = null;
109
110 if (targetType instanceof Class<?>) {
111
112 classToMock = (Class<T>) targetType;
113 } else if (targetType instanceof ParameterizedType) {
114 ParameterizedType parameterizedType = (ParameterizedType) targetType;
115
116 classToMock = (Class<T>) parameterizedType.getRawType();
117 }
118
119 if (classToMock != null) {
120 mockedClass = redefineClassOrImplementInterface(classToMock);
121 } else {
122 Type[] typesToMock = ((TypeVariable<?>) targetType).getBounds();
123
124 mockedClass = typesToMock.length > 1
125 ? new FakedImplementationClass<T>(this).createImplementation(typesToMock)
126 : new CaptureOfFakedImplementations(this, typesToMock[0]).apply();
127 }
128
129
130 FakeStates fakeStates = TestRun.getFakeStates();
131 if (TestRun.isInsideTestMethodOrAssertThrows()) {
132 fakeStates.verifyMissingInvocations();
133 fakeStates.resetExpectations();
134 }
135 }
136
137 @Nullable
138 private MockUp<?> findPreviouslyFakedClassIfMockUpAlreadyApplied() {
139 FakeClasses mockClasses = TestRun.getFakeClasses();
140 FakeClasses.MockUpInstances mockUpInstances = mockClasses.findPreviouslyAppliedMockUps(this);
141
142 if (mockUpInstances != null && mockUpInstances.hasMockUpsForSingleInstances()) {
143 return mockUpInstances.initialMockUp;
144 }
145
146 return null;
147 }
148
149
150
151
152
153
154 @NonNull
155 private Type getTypeToFake() {
156 Class<?> currentClass = getClass();
157
158 do {
159 Type superclass = currentClass.getGenericSuperclass();
160
161 if (superclass instanceof ParameterizedType) {
162 return ((ParameterizedType) superclass).getActualTypeArguments()[0];
163 }
164
165 if (superclass == MockUp.class) {
166 throw new IllegalArgumentException("No target type");
167 }
168
169 currentClass = (Class<?>) superclass;
170 } while (true);
171 }
172
173 @NonNull
174 private Class<?> redefineClassOrImplementInterface(@NonNull Class<T> classToMock) {
175 if (classToMock.isInterface()) {
176 return createInstanceOfMockedImplementationClass(classToMock, targetType);
177 }
178
179 Class<T> realClass = classToMock;
180
181 if (isAbstract(classToMock.getModifiers())) {
182 classToMock = new ConcreteSubclass<T>(classToMock).generateClass();
183 }
184
185 redefineMethods(realClass, classToMock, targetType);
186 return classToMock;
187 }
188
189 @NonNull
190 private Class<T> createInstanceOfMockedImplementationClass(@NonNull Class<T> classToMock,
191 @Nullable Type typeToMock) {
192 return new FakedImplementationClass<T>(this).createImplementation(classToMock, typeToMock);
193 }
194
195 private void redefineMethods(@NonNull Class<T> realClass, @NonNull Class<T> classToMock,
196 @Nullable Type genericMockedType) {
197 new FakeClassSetup(realClass, classToMock, genericMockedType, this).redefineMethods();
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212 protected MockUp(Class<?> targetClass) {
213 targetType = targetClass;
214 MockUp<?> previousMockUp = findPreviouslyFakedClassIfMockUpAlreadyApplied();
215
216 if (previousMockUp != null) {
217 mockedClass = previousMockUp.mockedClass;
218 return;
219 }
220
221 if (targetClass.isInterface()) {
222
223 mockedClass = createInstanceOfMockedImplementationClass((Class<T>) targetClass, targetClass);
224 } else {
225 mockedClass = targetClass;
226
227 Class<T> realClass = (Class<T>) targetClass;
228 redefineMethods(realClass, realClass, null);
229 mockInstance = null;
230 }
231 }
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251 protected MockUp(T targetInstance) {
252 MockUp<?> previousMockUp = findPreviouslyFakedClassIfMockUpAlreadyApplied();
253
254 if (previousMockUp != null) {
255 targetType = previousMockUp.targetType;
256 mockedClass = previousMockUp.mockedClass;
257 setMockInstance(targetInstance);
258 return;
259 }
260
261 @SuppressWarnings("unchecked")
262 Class<T> classToMock = (Class<T>) targetInstance.getClass();
263 targetType = classToMock;
264 mockedClass = classToMock;
265 redefineMethods(classToMock, classToMock, classToMock);
266
267 setMockInstance(targetInstance);
268 }
269
270 private void setMockInstance(@NonNull T mockInstance) {
271 TestRun.getFakeClasses().addFake(this, mockInstance);
272 this.mockInstance = mockInstance;
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289 public final T getMockInstance() {
290 if (invokedInstance == Void.class) {
291 return null;
292 }
293
294 if (invokedInstance != null) {
295 return invokedInstance;
296 }
297
298 if (mockInstance == null && mockedClass != null) {
299 @SuppressWarnings("unchecked")
300 T newInstance = (T) createMockInstance(mockedClass);
301 setMockInstance(newInstance);
302 }
303
304 return mockInstance;
305 }
306
307 @NonNull
308 private Object createMockInstance(@NonNull Class<?> mockedClass) {
309 String mockedClassName = mockedClass.getName();
310
311 if (isGeneratedImplementationClassName(mockedClassName)) {
312 return ConstructorReflection.newInstanceUsingPublicDefaultConstructor(mockedClass);
313 }
314
315 if (Proxy.isProxyClass(mockedClass)) {
316 return MockInvocationHandler.newMockedInstance(mockedClass);
317 }
318
319 return ConstructorReflection.newUninitializedInstance(mockedClass);
320 }
321
322
323
324
325
326
327
328
329
330 protected void onTearDown() {
331 }
332
333 }