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;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import java.util.ArrayList;
11  import java.util.List;
12  import java.util.Map;
13  
14  import mockit.internal.expectations.argumentMatching.ArgumentMatcher;
15  import mockit.internal.expectations.invocation.ExpectedInvocation;
16  import mockit.internal.expectations.invocation.InvocationArguments;
17  
18  import org.checkerframework.checker.index.qual.NonNegative;
19  
20  public abstract class BaseVerificationPhase extends TestOnlyPhase {
21      @NonNull
22      final ReplayPhase replayPhase;
23      @NonNull
24      private final List<VerifiedExpectation> currentVerifiedExpectations;
25      @Nullable
26      Expectation currentVerification;
27      int replayIndex;
28      @Nullable
29      Error pendingError;
30      @Nullable
31      ExpectedInvocation matchingInvocationWithDifferentArgs;
32  
33      BaseVerificationPhase(@NonNull ReplayPhase replayPhase) {
34          super(replayPhase.executionState);
35          this.replayPhase = replayPhase;
36          currentVerifiedExpectations = new ArrayList<>();
37      }
38  
39      @Nullable
40      @Override
41      final Object handleInvocation(@Nullable Object mock, int mockAccess, @NonNull String mockClassDesc,
42              @NonNull String mockNameAndDesc, @Nullable String genericSignature, boolean withRealImpl,
43              @NonNull Object[] args) {
44          if (pendingError != null) {
45              replayPhase.failureState.setErrorThrown(pendingError);
46              pendingError = null;
47              return null;
48          }
49  
50          matchInstance = mock != null && (executionState.equivalentInstances.isReplacementInstance(mock, mockNameAndDesc)
51                  || isEnumElement(mock));
52  
53          ExpectedInvocation currentInvocation = new ExpectedInvocation(mock, mockAccess, mockClassDesc, mockNameAndDesc,
54                  matchInstance, genericSignature, args);
55          currentInvocation.arguments.setMatchers(argMatchers);
56          currentVerification = new Expectation(currentInvocation);
57  
58          currentExpectation = null;
59          currentVerifiedExpectations.clear();
60          List<ExpectedInvocation> matchingInvocationsWithDifferentArgs = findExpectation(mock, mockClassDesc,
61                  mockNameAndDesc, args);
62          argMatchers = null;
63  
64          if (replayPhase.failureState.getErrorThrown() != null) {
65              return null;
66          }
67  
68          if (currentExpectation == null) {
69              pendingError = currentVerification.invocation
70                      .errorForMissingInvocation(matchingInvocationsWithDifferentArgs);
71              currentExpectation = currentVerification;
72          }
73  
74          return currentExpectation.invocation.getDefaultValueForReturnType();
75      }
76  
77      @NonNull
78      abstract List<ExpectedInvocation> findExpectation(@Nullable Object mock, @NonNull String mockClassDesc,
79              @NonNull String mockNameAndDesc, @NonNull Object[] args);
80  
81      final boolean matches(@Nullable Object mock, @NonNull String mockClassDesc, @NonNull String mockNameAndDesc,
82              @NonNull Object[] args, @NonNull Expectation replayExpectation, @Nullable Object replayInstance,
83              @NonNull Object[] replayArgs) {
84          ExpectedInvocation invocation = replayExpectation.invocation;
85          boolean constructor = invocation.isConstructor();
86          Map<Object, Object> replacementMap = getReplacementMap();
87          matchingInvocationWithDifferentArgs = null;
88  
89          if (invocation.isMatch(mock, mockClassDesc, mockNameAndDesc, replacementMap)) {
90              boolean matching;
91  
92              if (mock == null || invocation.instance == null || constructor && !matchInstance) {
93                  matching = true;
94              } else {
95                  matching = executionState.equivalentInstances.areMatchingInstances(matchInstance, invocation.instance,
96                          mock);
97              }
98  
99              if (matching) {
100                 matchingInvocationWithDifferentArgs = invocation;
101 
102                 InvocationArguments invocationArguments = invocation.arguments;
103                 List<ArgumentMatcher<?>> originalMatchers = invocationArguments.getMatchers();
104                 Object[] originalArgs = invocationArguments.prepareForVerification(args, argMatchers);
105                 boolean argumentsMatch = invocationArguments.isMatch(replayArgs, getInstanceMap());
106                 invocationArguments.setValuesAndMatchers(originalArgs, originalMatchers);
107 
108                 if (argumentsMatch) {
109                     addVerifiedExpectation(replayExpectation, replayArgs);
110                     return true;
111                 }
112             }
113         }
114 
115         return false;
116     }
117 
118     abstract void addVerifiedExpectation(@NonNull Expectation expectation, @NonNull Object[] args);
119 
120     final void addVerifiedExpectation(@NonNull VerifiedExpectation verifiedExpectation) {
121         executionState.verifiedExpectations.add(verifiedExpectation);
122         currentVerifiedExpectations.add(verifiedExpectation);
123     }
124 
125     @Override
126     final void setMaxInvocationCount(int maxInvocations) {
127         if (maxInvocations == 0 || pendingError == null) {
128             super.setMaxInvocationCount(maxInvocations);
129         }
130     }
131 
132     @Nullable
133     Error endVerification() {
134         return pendingError;
135     }
136 
137     @Nullable
138     final Object getArgumentValueForCurrentVerification(@NonNegative int parameterIndex) {
139         List<VerifiedExpectation> verifiedExpectations = executionState.verifiedExpectations;
140 
141         if (verifiedExpectations.isEmpty()) {
142             return currentVerification == null ? null
143                     : currentVerification.invocation.getArgumentValues()[parameterIndex];
144         }
145 
146         VerifiedExpectation lastMatched = verifiedExpectations.get(verifiedExpectations.size() - 1);
147         return lastMatched.arguments[parameterIndex];
148     }
149 
150     @NonNull
151     public final <T> List<T> getNewInstancesMatchingVerifiedConstructorInvocation() {
152         List<T> newInstances = new ArrayList<>();
153 
154         for (VerifiedExpectation verifiedExpectation : currentVerifiedExpectations) {
155             // noinspection unchecked
156             T newInstance = (T) verifiedExpectation.captureNewInstance();
157             newInstances.add(newInstance);
158         }
159 
160         return newInstances;
161     }
162 }