1
2
3
4
5 package mockit.internal.expectations.mocking;
6
7 import static mockit.internal.util.AutoBoxing.isWrapperOfPrimitiveType;
8 import static mockit.internal.util.GeneratedClasses.getMockedClass;
9 import static mockit.internal.util.GeneratedClasses.isGeneratedImplementationClass;
10
11 import edu.umd.cs.findbugs.annotations.NonNull;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17
18 import mockit.internal.expectations.MockingFilters;
19 import mockit.internal.state.TestRun;
20
21 public final class PartialMocking extends BaseTypeRedefinition {
22 @NonNull
23 public final List<Object> targetInstances;
24 @NonNull
25 private final Map<Class<?>, byte[]> modifiedClassfiles;
26
27 public PartialMocking() {
28 targetInstances = new ArrayList<>(2);
29 modifiedClassfiles = new HashMap<>();
30 }
31
32 public void redefineTypes(@NonNull Object[] instancesToBePartiallyMocked) {
33 for (Object instance : instancesToBePartiallyMocked) {
34 redefineClassHierarchy(instance);
35 }
36
37 if (!modifiedClassfiles.isEmpty()) {
38 TestRun.mockFixture().redefineMethods(modifiedClassfiles);
39 modifiedClassfiles.clear();
40 }
41 }
42
43 private void redefineClassHierarchy(@NonNull Object mockInstance) {
44 if (mockInstance instanceof Class) {
45 throw new IllegalArgumentException(
46 "Invalid Class argument for partial mocking (use a MockUp instead): " + mockInstance);
47 }
48
49 targetClass = getMockedClass(mockInstance);
50 applyPartialMockingToGivenInstance(mockInstance);
51
52 InstanceFactory instanceFactory = createInstanceFactory(targetClass);
53 instanceFactory.lastInstance = mockInstance;
54
55 TestRun.mockFixture().registerInstanceFactoryForMockedType(targetClass, instanceFactory);
56 TestRun.getExecutingTest().getCascadingTypes().add(false, targetClass);
57 }
58
59 private void applyPartialMockingToGivenInstance(@NonNull Object instance) {
60 validateTargetClassType();
61 redefineMethodsAndConstructorsInTargetType();
62 targetInstances.add(instance);
63 }
64
65 private void validateTargetClassType() {
66 if (targetClass.isInterface() || targetClass.isAnnotation() || targetClass.isArray()
67 || targetClass.isPrimitive() || targetClass.isSynthetic()
68 || MockingFilters.isSubclassOfUnmockable(targetClass) || isWrapperOfPrimitiveType(targetClass)
69 || isGeneratedImplementationClass(targetClass)) {
70 throw new IllegalArgumentException("Invalid type for partial mocking: " + targetClass);
71 }
72 }
73
74 @Override
75 void configureClassModifier(@NonNull MockedClassModifier modifier) {
76 modifier.useDynamicMocking();
77 }
78
79 @Override
80 void applyClassRedefinition(@NonNull Class<?> realClass, @NonNull byte[] modifiedClass) {
81 modifiedClassfiles.put(realClass, modifiedClass);
82 }
83 }