1
2
3
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
156 T newInstance = (T) verifiedExpectation.captureNewInstance();
157 newInstances.add(newInstance);
158 }
159
160 return newInstances;
161 }
162 }