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