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