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