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