1
2
3
4
5
6 package mockit.internal.expectations.mocking;
7
8 import edu.umd.cs.findbugs.annotations.NonNull;
9 import edu.umd.cs.findbugs.annotations.Nullable;
10
11 import java.lang.annotation.Annotation;
12 import java.lang.reflect.Type;
13 import java.util.ArrayList;
14 import java.util.List;
15
16 import mockit.internal.util.TestMethod;
17
18 import org.checkerframework.checker.index.qual.NonNegative;
19
20 public final class ParameterTypeRedefinitions extends TypeRedefinitions {
21 @NonNull
22 private final TestMethod testMethod;
23 @NonNull
24 private final MockedType[] mockParameters;
25 @NonNull
26 private final List<MockedType> injectableParameters;
27
28 public ParameterTypeRedefinitions(@NonNull TestMethod testMethod, @NonNull Object[] parameterValues) {
29 this.testMethod = testMethod;
30 int n = testMethod.getParameterCount();
31 mockParameters = new MockedType[n];
32 injectableParameters = new ArrayList<>(n);
33
34 for (int i = 0; i < n; i++) {
35 Object mock = parameterValues[i];
36 createMockedTypeFromMockParameterDeclaration(i, mock);
37 }
38
39 InstanceFactory[] instanceFactories = redefineMockedTypes();
40 instantiateMockedTypes(instanceFactories);
41 }
42
43 private void createMockedTypeFromMockParameterDeclaration(@NonNegative int parameterIndex, @Nullable Object mock) {
44 Type parameterType = testMethod.getParameterType(parameterIndex);
45 Annotation[] annotationsOnParameter = testMethod.getParameterAnnotations(parameterIndex);
46 Class<?> parameterImplementationClass = mock == null ? null : mock.getClass();
47 MockedType mockedType = new MockedType(testMethod, parameterIndex, parameterType, annotationsOnParameter,
48 parameterImplementationClass);
49
50 if (mockedType.isMockableType()) {
51 mockParameters[parameterIndex] = mockedType;
52 }
53
54 if (mockedType.injectable) {
55 injectableParameters.add(mockedType);
56 testMethod.setParameterValue(parameterIndex, mockedType.providedValue);
57 }
58 }
59
60 @NonNull
61 private InstanceFactory[] redefineMockedTypes() {
62 int n = mockParameters.length;
63 InstanceFactory[] instanceFactories = new InstanceFactory[n];
64
65 for (int i = 0; i < n; i++) {
66 MockedType mockedType = mockParameters[i];
67
68 if (mockedType != null) {
69 instanceFactories[i] = redefineMockedType(mockedType);
70 }
71 }
72
73 return instanceFactories;
74 }
75
76 @Nullable
77 private InstanceFactory redefineMockedType(@NonNull MockedType mockedType) {
78 TypeRedefinition typeRedefinition = new TypeRedefinition(mockedType);
79 InstanceFactory instanceFactory = typeRedefinition.redefineType();
80
81 if (instanceFactory != null) {
82 addTargetClass(mockedType);
83 }
84
85 return instanceFactory;
86 }
87
88 private void registerCaptureOfNewInstances(@NonNull MockedType mockedType, @NonNull Object originalInstance) {
89 if (captureOfNewInstances == null) {
90 captureOfNewInstances = new CaptureOfNewInstances();
91 }
92
93 captureOfNewInstances.registerCaptureOfNewInstances(mockedType, originalInstance);
94 captureOfNewInstances.makeSureAllSubtypesAreModified(mockedType);
95 }
96
97 private void instantiateMockedTypes(@NonNull InstanceFactory[] instanceFactories) {
98 for (int paramIndex = 0; paramIndex < instanceFactories.length; paramIndex++) {
99 InstanceFactory instanceFactory = instanceFactories[paramIndex];
100
101 if (instanceFactory != null) {
102 MockedType mockedType = mockParameters[paramIndex];
103 @NonNull
104 Object mockedInstance = instantiateMockedType(mockedType, instanceFactory, paramIndex);
105 testMethod.setParameterValue(paramIndex, mockedInstance);
106 mockedType.providedValue = mockedInstance;
107 }
108 }
109 }
110
111 @NonNull
112 private Object instantiateMockedType(@NonNull MockedType mockedType, @NonNull InstanceFactory instanceFactory,
113 @NonNegative int paramIndex) {
114 Object mock = testMethod.getParameterValue(paramIndex);
115
116 if (mock == null) {
117 mock = instanceFactory.create();
118 }
119
120 registerMock(mockedType, mock);
121
122 if (mockedType.withInstancesToCapture()) {
123 registerCaptureOfNewInstances(mockedType, mock);
124 }
125
126 return mock;
127 }
128
129 @NonNull
130 public List<MockedType> getInjectableParameters() {
131 return injectableParameters;
132 }
133 }