View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
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 }