1
2
3
4
5 package mockit.internal.expectations;
6
7 import static java.util.Collections.emptyList;
8
9 import edu.umd.cs.findbugs.annotations.NonNull;
10 import edu.umd.cs.findbugs.annotations.Nullable;
11
12 import java.util.Collections;
13 import java.util.List;
14
15 import mockit.internal.expectations.invocation.ExpectedInvocation;
16
17 import org.checkerframework.checker.index.qual.NonNegative;
18
19 final class OrderedVerificationPhase extends BaseVerificationPhase {
20 @NonNegative
21 private final int expectationCount;
22 @NonNegative
23 private int indexIncrement;
24
25 OrderedVerificationPhase(@NonNull ReplayPhase replayPhase) {
26 super(replayPhase);
27 discardExpectationsAndArgumentsAlreadyVerified(replayPhase.invocations);
28 expectationCount = replayPhase.invocations.size();
29 indexIncrement = 1;
30 }
31
32 private void discardExpectationsAndArgumentsAlreadyVerified(List<Expectation> expectationsInReplayOrder) {
33 for (VerifiedExpectation verified : executionState.verifiedExpectations) {
34 int i = expectationsInReplayOrder.indexOf(verified.expectation);
35
36 if (i >= 0) {
37 expectationsInReplayOrder.set(i, null);
38 }
39 }
40 }
41
42 @NonNull
43 @Override
44 List<ExpectedInvocation> findExpectation(@Nullable Object mock, @NonNull String mockClassDesc,
45 @NonNull String mockNameAndDesc, @NonNull Object[] args) {
46 Expectation expectation = currentVerification;
47 int i = replayIndex;
48
49 while (i >= 0 && i < expectationCount) {
50 Expectation replayExpectation = replayPhase.invocations.get(i);
51 Object replayInstance = replayPhase.invocationInstances.get(i);
52 Object[] replayArgs = replayPhase.invocationArguments.get(i);
53
54 i += indexIncrement;
55
56 if (replayExpectation == null) {
57 continue;
58 }
59
60 if (!matchInstance && executionState.isToBeMatchedOnInstance(mock, mockNameAndDesc)) {
61 matchInstance = true;
62 }
63
64 if (matches(mock, mockClassDesc, mockNameAndDesc, args, replayExpectation, replayInstance, replayArgs)) {
65 currentExpectation = replayExpectation;
66 i += 1 - indexIncrement;
67 indexIncrement = 1;
68 replayIndex = i;
69
70 if (expectation != null) {
71 expectation.constraints.invocationCount++;
72 }
73
74 break;
75 }
76 }
77
78 return emptyList();
79 }
80
81 @Override
82 void addVerifiedExpectation(@NonNull Expectation expectation, @NonNull Object[] args) {
83 VerifiedExpectation verifiedExpectation = new VerifiedExpectation(expectation, args, argMatchers, replayIndex);
84 addVerifiedExpectation(verifiedExpectation);
85 }
86
87 @Override
88 @SuppressWarnings("OverlyComplexMethod")
89 void handleInvocationCountConstraint(int minInvocations, int maxInvocations) {
90 Error errorThrown = pendingError;
91 pendingError = null;
92
93 if (errorThrown != null && minInvocations > 0) {
94 throw errorThrown;
95 }
96
97 Expectation verifying = currentVerification;
98
99 if (verifying == null) {
100 return;
101 }
102
103 ExpectedInvocation invocation = verifying.invocation;
104 argMatchers = invocation.arguments.getMatchers();
105 int invocationCount = 1;
106
107 while (replayIndex < expectationCount) {
108 Expectation replayExpectation = replayPhase.invocations.get(replayIndex);
109
110 if (replayExpectation != null && matchesCurrentVerification(invocation, replayExpectation)) {
111 invocationCount++;
112 verifying.constraints.invocationCount++;
113
114 if (invocationCount > maxInvocations) {
115 if (maxInvocations >= 0) {
116 throw replayExpectation.invocation.errorForUnexpectedInvocation();
117 }
118
119 break;
120 }
121 } else if (invocationCount >= minInvocations) {
122 break;
123 }
124
125 replayIndex++;
126 }
127
128 argMatchers = null;
129
130 int n = minInvocations - invocationCount;
131
132 if (n > 0) {
133 throw invocation.errorForMissingInvocations(n, Collections.<ExpectedInvocation> emptyList());
134 }
135
136 verifyMaxInvocations(verifying, maxInvocations);
137 }
138
139 private boolean matchesCurrentVerification(@NonNull ExpectedInvocation invocation,
140 @NonNull Expectation replayExpectation) {
141 Object mock = invocation.instance;
142 String mockClassDesc = invocation.getClassDesc();
143 String mockNameAndDesc = invocation.getMethodNameAndDescription();
144 Object[] args = invocation.arguments.getValues();
145 matchInstance = invocation.matchInstance;
146
147 if (executionState.isToBeMatchedOnInstance(mock, mockNameAndDesc)) {
148 matchInstance = true;
149 }
150
151 Object replayInstance = replayPhase.invocationInstances.get(replayIndex);
152 Object[] replayArgs = replayPhase.invocationArguments.get(replayIndex);
153
154 return matches(mock, mockClassDesc, mockNameAndDesc, args, replayExpectation, replayInstance, replayArgs);
155 }
156
157 private void verifyMaxInvocations(@NonNull Expectation verifying, int maxInvocations) {
158 if (maxInvocations >= 0) {
159 int n = verifying.constraints.invocationCount - maxInvocations;
160
161 if (n > 0) {
162 Object[] replayArgs = replayPhase.invocationArguments.get(replayIndex - 1);
163 throw verifying.invocation.errorForUnexpectedInvocations(replayArgs, n);
164 }
165 }
166 }
167 }