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 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 }