1
2
3 package org.virtualmock.call;
4
5 import org.virtualmock.VM;
6 import org.virtualmock.matcher.ArgMatcher;
7
8
9 /***
10 * Represents a method invocation of a recorded mock call. This is a subclass
11 * of Call which only contains information which is specific to recorded
12 * calls.
13 *
14 * @author Chad Woolley
15 * @version $Revision: 1.32 $
16 */
17 public class RecordedCall extends Call {
18 private ArgMatcher[] argMatchers = null;
19
20 /*** Flag to indicate if this call can have unlimited invocations. */
21 private boolean unlimitedInvocations = false;
22
23 /*** The number of times this recorded call has been invoked. */
24 private int invocationCount = 0;
25
26 /***
27 * Creates a new RecordedCall object.
28 *
29 * @param signature the unique identifier for the call
30 * @param argValues an array representing the values of the arguments
31 * passed to (or expected by) the call.
32 */
33 public RecordedCall(Signature signature, Object[] argValues) {
34 super(signature, argValues);
35 }
36
37 /***
38 * Creates a new RecordedCall object.
39 *
40 * @param signature the unique identifier for the call
41 */
42 public RecordedCall(Signature signature) {
43 super(signature);
44 }
45
46 /***
47 * Creates a new RecordedCall object which has a return value.
48 *
49 * @param signature the method signature for the call
50 * @param argValues an array representing the values of the arguments
51 * passed to (or expected by) the call.
52 * @param returnValue the value the call will return
53 */
54 public RecordedCall(Signature signature, Object[] argValues,
55 Object returnValue) {
56 super(signature, argValues, returnValue);
57 }
58
59 /***
60 * Creates a new RecordedCall object which throws an exception.
61 *
62 * @param signature the method signature for the call
63 * @param argValues an array representing the values of the arguments
64 * passed to (or expected by) the call.
65 * @param throwable the exception the call will throw
66 */
67 public RecordedCall(Signature signature, Object[] argValues,
68 Throwable throwable) {
69 super(signature, argValues, throwable);
70 }
71
72 /***
73 * Sets the ArgMatchers that are defined for this call.
74 *
75 * @param argMatchers the array of ArgMatchers to use for this call
76 *
77 * @throws IllegalArgumentException if the number of ArgTypes does not
78 * match the number of ArgMatchers
79 */
80 public void setArgMatchers(ArgMatcher[] argMatchers) {
81 if (getArgTypes().length != argMatchers.length) {
82 throw new IllegalArgumentException(
83 "Number of argMatchers specified ('" + argMatchers.length
84 + "') does not match the number of arguments in this call ('"
85 + getSignature() + "')");
86 }
87
88 this.argMatchers = argMatchers;
89 }
90
91 /***
92 * Gets the ArgMatchers that are defined for this call (if any).
93 *
94 * @return the array of ArgMatchers that are defined for this call, or null
95 * if none have been defined.
96 */
97 public ArgMatcher[] getArgMatchers() {
98 return argMatchers;
99 }
100
101 /***
102 * Indicates if this call is invocable. A call is invocable if has not yet
103 * been invoked, or if unlimited invocation is set.
104 *
105 * @return true if this call is invocable
106 */
107 public boolean isInvocable() {
108 if (hasUnlimitedInvocations() || !isInvoked()) {
109 return true;
110 }
111
112 return false;
113 }
114
115 /***
116 * Returns the number of times incrementInvocationCount() has been called
117 * on this Call.
118 *
119 * @return the number of times incrementInvocationCount() has been called
120 * on this Call.
121 */
122 public int getInvocationCount() {
123 return invocationCount;
124 }
125
126 /***
127 * Returns true if invocation count is greater than zero.
128 *
129 * @return true if invocation count is greater than zero.
130 */
131 public boolean isInvoked() {
132 if (invocationCount > 0) {
133 return true;
134 }
135
136 return false;
137 }
138
139 /***
140 * Set that this call can be invoked an unlimited number of times.
141 *
142 * @param unlimitedInvocations boolean flag.
143 */
144 public void setUnlimitedInvocations(boolean unlimitedInvocations) {
145 this.unlimitedInvocations = unlimitedInvocations;
146 }
147
148 /***
149 * <p>
150 * Performs matching of all arguments on this Call to the specified Call,
151 * based on the ArgMatchers that are defined for this call. For
152 * ArgMatchers where the order is relevant (such as GreaterThanMatcher),
153 * it is important to know that the Call is matched <strong>TO</strong>
154 * the Call. In other words, Call GreaterThan Call is checked to see if
155 * the match is true.
156 * </p>
157 *
158 * <p>
159 * Note that all matching is done based on position. This means that that
160 * all arguments and matchers must be in the same corresponding order on
161 * this Call, the Call which was passed, and the ArgMatchers for this
162 * Call.
163 * </p>
164 *
165 * @param call The Call which will be matched to this Call
166 *
167 * @return true if the this Call matches the Call, or false if it does not
168 *
169 * @throws IllegalArgumentException if the signatures of the calls do not
170 * match
171 *
172 * @todo need to implement support for configurable default ArgMatcher,
173 * instead of hardcoding default to EqualsMatcher
174 */
175 public boolean hasMatchingArgs(Call call) {
176 if (!getSignature().equals(call.getSignature())) {
177 throw new IllegalArgumentException(
178 "Cannot perform argument matching, because the signature of this Call ('"
179 + getSignature()
180 + "') does not match the signature of the Call which was passed ('"
181 + call.getSignature() + "')");
182 }
183
184
185
186
187 Object[] recordedArgValues = getArgValues();
188 Object[] invokedArgValues = call.getArgValues();
189
190 for (int i = 0; i < recordedArgValues.length; i++) {
191 ArgMatcher matcher = null;
192
193 if (getArgMatchers() != null) {
194
195 matcher = getArgMatchers()[i];
196 } else {
197
198 matcher = VM.EQUALS_MATCHER;
199 }
200
201 boolean argMatches =
202 matcher.matches(recordedArgValues[i], invokedArgValues[i]);
203
204 if (!argMatches) {
205 return false;
206 }
207 }
208
209 return true;
210 }
211
212 /***
213 * Return true if this call has unlimited invocations set.
214 *
215 * @return true if this call has unlimited invocations set.
216 */
217 public boolean hasUnlimitedInvocations() {
218 return unlimitedInvocations;
219 }
220
221 /***
222 * Increments the internal invocation count for this call by one.
223 */
224 public void incrementInvocationCount() {
225 invocationCount++;
226 }
227
228 /***
229 * Returns true if hasMatchingSignature() and hasMatchingArgs() both return
230 * true.
231 *
232 * @param call Call to match against
233 *
234 * @return true if hasMatchingSignature() and hasMatchingArgs() both return
235 * true.
236 */
237 public boolean matches(Call call) {
238 if (!hasMatchingSignature(call)) {
239 return false;
240 }
241
242 if (!hasMatchingArgs(call)) {
243 return false;
244 }
245
246 return true;
247 }
248 }