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