View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
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  
14  import mockit.internal.expectations.invocation.ExpectedInvocation;
15  import mockit.internal.expectations.invocation.InvocationArguments;
16  import mockit.internal.util.ClassLoad;
17  
18  import org.checkerframework.checker.index.qual.NonNegative;
19  
20  final class FullVerificationPhase extends UnorderedVerificationPhase {
21      @NonNull
22      private final Object[] mockedTypesAndInstancesToVerify;
23  
24      FullVerificationPhase(@NonNull ReplayPhase replayPhase, @NonNull Object[] mockedTypesAndInstancesToVerify) {
25          super(replayPhase);
26          this.mockedTypesAndInstancesToVerify = mockedTypesAndInstancesToVerify;
27      }
28  
29      @Nullable
30      @Override
31      Error endVerification() {
32          if (pendingError != null) {
33              return pendingError;
34          }
35  
36          List<Expectation> expectationsInReplayOrder = replayPhase.invocations;
37          List<Expectation> notVerified = new ArrayList<>();
38  
39          for (int i = 0, n = expectationsInReplayOrder.size(); i < n; i++) {
40              Expectation replayExpectation = expectationsInReplayOrder.get(i);
41  
42              if (replayExpectation != null && isEligibleForFullVerification(replayExpectation)) {
43                  Object[] replayArgs = replayPhase.invocationArguments.get(i);
44  
45                  if (!wasVerified(replayExpectation, replayArgs, i)) {
46                      notVerified.add(replayExpectation);
47                  }
48              }
49          }
50  
51          if (!notVerified.isEmpty()) {
52              if (mockedTypesAndInstancesToVerify.length == 0) {
53                  Expectation firstUnexpected = notVerified.get(0);
54                  return firstUnexpected.invocation.errorForUnexpectedInvocation();
55              }
56  
57              return validateThatUnverifiedInvocationsAreAllowed(notVerified);
58          }
59  
60          return null;
61      }
62  
63      private static boolean isEligibleForFullVerification(@NonNull Expectation replayExpectation) {
64          return !replayExpectation.executedRealImplementation && replayExpectation.constraints.minInvocations <= 0;
65      }
66  
67      private boolean wasVerified(@NonNull Expectation replayExpectation, @NonNull Object[] replayArgs,
68              @NonNegative int expectationIndex) {
69          InvocationArguments invokedArgs = replayExpectation.invocation.arguments;
70          List<VerifiedExpectation> verifiedExpectations = executionState.verifiedExpectations;
71  
72          for (VerifiedExpectation verified : verifiedExpectations) {
73              if (verified.expectation == replayExpectation) {
74                  Object[] storedArgs = invokedArgs.prepareForVerification(verified.arguments, verified.argMatchers);
75                  boolean argumentsMatch = invokedArgs.isMatch(replayArgs, getInstanceMap());
76                  invokedArgs.setValuesWithNoMatchers(storedArgs);
77  
78                  if (argumentsMatch && verified.matchesReplayIndex(expectationIndex)) {
79                      return true;
80                  }
81              }
82          }
83  
84          invokedArgs.setValuesWithNoMatchers(replayArgs);
85          return false;
86      }
87  
88      @Nullable
89      private Error validateThatUnverifiedInvocationsAreAllowed(@NonNull List<Expectation> unverified) {
90          for (Expectation expectation : unverified) {
91              ExpectedInvocation invocation = expectation.invocation;
92  
93              if (isInvocationToBeVerified(invocation)) {
94                  return invocation.errorForUnexpectedInvocation();
95              }
96          }
97  
98          return null;
99      }
100 
101     private boolean isInvocationToBeVerified(@NonNull ExpectedInvocation unverifiedInvocation) {
102         String invokedClassName = unverifiedInvocation.getClassName();
103         Object invokedInstance = unverifiedInvocation.instance;
104 
105         for (Object mockedTypeOrInstance : mockedTypesAndInstancesToVerify) {
106             if (mockedTypeOrInstance instanceof Class) {
107                 Class<?> mockedType = (Class<?>) mockedTypeOrInstance;
108 
109                 if (invokedClassName.equals(mockedType.getName())) {
110                     return true;
111                 }
112             } else if (invokedInstance == null) {
113                 ClassLoader loader = mockedTypeOrInstance.getClass().getClassLoader();
114                 Class<?> invokedClass = ClassLoad.loadFromLoader(loader, invokedClassName);
115 
116                 if (invokedClass.isInstance(mockedTypeOrInstance)) {
117                     return true;
118                 }
119             } else if (unverifiedInvocation.matchInstance) {
120                 if (mockedTypeOrInstance == invokedInstance) {
121                     return true;
122                 }
123             } else if (invokedInstance.getClass().isInstance(mockedTypeOrInstance)) {
124                 return true;
125             }
126         }
127 
128         return false;
129     }
130 }