forked from mockito/mockito
/
MatcherApplicationStrategy.java
134 lines (115 loc) · 4.96 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
/*
* Copyright (c) 2016 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.invocation;
import java.util.ArrayList;
import java.util.List;
import org.mockito.ArgumentMatcher;
import org.mockito.internal.hamcrest.HamcrestArgumentMatcher;
import org.mockito.internal.matchers.CapturingMatcher;
import org.mockito.internal.matchers.VarargMatcher;
import org.mockito.invocation.Invocation;
public class MatcherApplicationStrategy {
private final Invocation invocation;
private final List<? extends ArgumentMatcher<?>> matchers;
private MatcherApplicationStrategy(
Invocation invocation, List<? extends ArgumentMatcher<?>> matchers) {
this.invocation = invocation;
this.matchers = matchers;
}
/**
* 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<? extends ArgumentMatcher<?>> matchers) {
return new MatcherApplicationStrategy(invocation, matchers);
}
/**
* 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) {
final boolean maybeVararg =
invocation.getMethod().isVarArgs()
&& invocation.getRawArguments().length == matchers.size();
if (maybeVararg) {
final Class<?> matcherType = lastMatcher().type();
final Class<?> paramType = lastParameterType();
if (paramType.isAssignableFrom(matcherType)) {
return argsMatch(invocation.getRawArguments(), matchers, action);
}
}
if (invocation.getArguments().length == matchers.size()) {
return argsMatch(invocation.getArguments(), matchers, action);
}
if (maybeVararg && isLastMatcherVarargMatcher()) {
int times = varargLength();
final List<? extends ArgumentMatcher<?>> matchers = appendLastMatcherNTimes(times);
return argsMatch(invocation.getArguments(), matchers, action);
}
return false;
}
private boolean argsMatch(
Object[] arguments,
List<? extends ArgumentMatcher<?>> matchers,
ArgumentMatcherAction action) {
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 boolean isLastMatcherVarargMatcher() {
ArgumentMatcher<?> argumentMatcher = lastMatcher();
if (argumentMatcher instanceof HamcrestArgumentMatcher<?>) {
return ((HamcrestArgumentMatcher<?>) argumentMatcher).isVarargMatcher();
}
return argumentMatcher instanceof VarargMatcher;
}
private List<? extends ArgumentMatcher<?>> appendLastMatcherNTimes(
int timesToAppendLastMatcher) {
ArgumentMatcher<?> lastMatcher = lastMatcher();
List<ArgumentMatcher<?>> expandedMatchers = new ArrayList<ArgumentMatcher<?>>(matchers);
for (int i = 0; i < timesToAppendLastMatcher; i++) {
expandedMatchers.add(lastMatcher);
}
return expandedMatchers;
}
private int varargLength() {
int rawArgumentCount = invocation.getRawArguments().length;
int expandedArgumentCount = invocation.getArguments().length;
return expandedArgumentCount - rawArgumentCount;
}
private ArgumentMatcher<?> lastMatcher() {
return matchers.get(matchers.size() - 1);
}
private Class<?> lastParameterType() {
final Class<?>[] parameterTypes = invocation.getMethod().getParameterTypes();
return parameterTypes[parameterTypes.length - 1];
}
}