-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
MatcherApplicationStrategy.java
146 lines (123 loc) · 5.94 KB
/
MatcherApplicationStrategy.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
* Copyright (c) 2016 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.invocation;
import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.CapturingMatcher;
import org.mockito.internal.matchers.VarargMatcher;
import org.mockito.invocation.Invocation;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.internal.invocation.MatcherApplicationStrategy.MatcherApplicationType.ERROR_UNSUPPORTED_NUMBER_OF_MATCHERS;
import static org.mockito.internal.invocation.MatcherApplicationStrategy.MatcherApplicationType.EXPERIMENTAL_VARARGS;
import static org.mockito.internal.invocation.MatcherApplicationStrategy.MatcherApplicationType.MATCH_EACH_VARARGS_WITH_LAST_MATCHER;
import static org.mockito.internal.invocation.MatcherApplicationStrategy.MatcherApplicationType.ONE_MATCHER_PER_ARGUMENT;
public class MatcherApplicationStrategy {
private final Invocation invocation;
private final List<ArgumentMatcher<?>> matchers;
private final MatcherApplicationType matchingType;
private MatcherApplicationStrategy(Invocation invocation, List<ArgumentMatcher<?>> matchers, MatcherApplicationType matchingType) {
this.invocation = invocation;
if (matchingType == MATCH_EACH_VARARGS_WITH_LAST_MATCHER) {
int times = varargLength(invocation);
this.matchers = appendLastMatcherNTimes(matchers, times);
} else {
this.matchers = matchers;
}
this.matchingType = matchingType;
}
/**
* Returns the {@link MatcherApplicationStrategy} that must be used to capture the
* arguments of the given <b>invocation</b> using the given <b>matchers</b>.
*
* @param invocation
* that contain the arguments to capture
* @param matchers
* that will be used to capture the arguments of the invocation,
* the passed {@link List} is not required to contain a
* {@link CapturingMatcher}
* @return never <code>null</code>
*/
public static MatcherApplicationStrategy getMatcherApplicationStrategyFor(Invocation invocation, List<ArgumentMatcher<?>> matchers) {
MatcherApplicationType type = getMatcherApplicationType(invocation, matchers);
return new MatcherApplicationStrategy(invocation, matchers, type);
}
/**
* Applies the given {@link ArgumentMatcherAction} to all arguments and
* corresponding matchers
*
* @param action
* must not be <code>null</code>
* @return
* <ul>
* <li><code>true</code> if the given <b>action</b> returned
* <code>true</code> for all arguments and matchers passed to it.
* <li><code>false</code> if the given <b>action</b> returned
* <code>false</code> for one of the passed arguments and matchers
* <li><code>false</code> if the given matchers don't fit to the given invocation
* because too many or to few matchers are available.
* </ul>
*/
public boolean forEachMatcherAndArgument(ArgumentMatcherAction action) {
if (matchingType == ERROR_UNSUPPORTED_NUMBER_OF_MATCHERS)
return false;
if (matchingType == EXPERIMENTAL_VARARGS) {
//varargs use case
int i = 0;
for (ArgumentMatcher<?> m : matchers) {
Object arg = invocation.getRawArguments()[i++];
if (!action.apply(m, arg)) {
return false;
}
}
} else {
Object[] arguments = invocation.getArguments();
for (int i = 0; i < arguments.length; i++) {
ArgumentMatcher<?> matcher = matchers.get(i);
Object argument = arguments[i];
if (!action.apply(matcher, argument)) {
return false;
}
}
}
return true;
}
private static MatcherApplicationType getMatcherApplicationType(Invocation invocation, List<ArgumentMatcher<?>> matchers) {
final int rawArguments = invocation.getRawArguments().length;
final int expandedArguments = invocation.getArguments().length;
final int matcherCount = matchers.size();
if (expandedArguments == matcherCount) {
return ONE_MATCHER_PER_ARGUMENT;
}
if (rawArguments == matcherCount && isLastMatcherVargargMatcher(matchers)) {
return MATCH_EACH_VARARGS_WITH_LAST_MATCHER;
}
if (invocation.getRawArguments().length != invocation.getArguments().length && matchers.size() == invocation.getRawArguments().length) {
return EXPERIMENTAL_VARARGS;
}
return ERROR_UNSUPPORTED_NUMBER_OF_MATCHERS;
}
private static boolean isLastMatcherVargargMatcher(final List<ArgumentMatcher<?>> matchers) {
return lastMatcher(matchers) instanceof VarargMatcher;
}
private static List<ArgumentMatcher<?>> appendLastMatcherNTimes(List<ArgumentMatcher<?>> matchers, int timesToAppendLastMatcher) {
ArgumentMatcher<?> lastMatcher = lastMatcher(matchers);
List<ArgumentMatcher<?>> expandedMatchers = new ArrayList<ArgumentMatcher<?>>(matchers);
for (int i = 0; i < timesToAppendLastMatcher; i++) {
expandedMatchers.add(lastMatcher);
}
return expandedMatchers;
}
private static int varargLength(Invocation invocation) {
int rawArgumentCount = invocation.getRawArguments().length;
int expandedArgumentCount = invocation.getArguments().length;
return expandedArgumentCount - rawArgumentCount;
}
private static ArgumentMatcher<?> lastMatcher(List<ArgumentMatcher<?>> matchers) {
return matchers.get(matchers.size() - 1);
}
enum MatcherApplicationType {
ONE_MATCHER_PER_ARGUMENT, MATCH_EACH_VARARGS_WITH_LAST_MATCHER, EXPERIMENTAL_VARARGS, ERROR_UNSUPPORTED_NUMBER_OF_MATCHERS;
}
}