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