1
2
3
4
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 }