1 /*
2  * Copyright 2001-2009 OFFIS, Tammo Freese
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.easymock.internal;
17 
18 import static java.lang.Character.*;
19 
20 import java.io.IOException;
21 import java.io.Serializable;
22 import java.lang.reflect.Array;
23 import java.lang.reflect.Method;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 
27 import org.easymock.internal.matchers.Captures;
28 
29 public class Invocation implements Serializable {
30 
31     private static final long serialVersionUID = 1604995470419943411L;
32 
33     private final Object mock;
34 
35     private transient Method method;
36 
37     private final Object[] arguments;
38 
39     private final Collection<Captures<?>> currentCaptures = new ArrayList<Captures<?>>(
40             0);
41 
Invocation(Object mock, Method method, Object[] args)42     public Invocation(Object mock, Method method, Object[] args) {
43         this.mock = mock;
44         this.method = method;
45         this.arguments = expandVarArgs(method.isVarArgs(), args);
46     }
47 
expandVarArgs(final boolean isVarArgs, final Object[] args)48     private static Object[] expandVarArgs(final boolean isVarArgs,
49             final Object[] args) {
50         if (!isVarArgs) {
51             return args == null ? new Object[0] : args;
52         }
53         if (args[args.length - 1] == null) {
54             return args;
55         }
56         Object[] varArgs = createObjectArray(args[args.length - 1]);
57         final int nonVarArgsCount = args.length - 1;
58         final int varArgsCount = varArgs.length;
59         Object[] newArgs = new Object[nonVarArgsCount + varArgsCount];
60         System.arraycopy(args, 0, newArgs, 0, nonVarArgsCount);
61         System.arraycopy(varArgs, 0, newArgs, nonVarArgsCount, varArgsCount);
62         return newArgs;
63     }
64 
createObjectArray(Object array)65     private static Object[] createObjectArray(Object array) {
66         if (array instanceof Object[]) {
67             return (Object[]) array;
68         }
69         Object[] result = new Object[Array.getLength(array)];
70         for (int i = 0; i < Array.getLength(array); i++) {
71             result[i] = Array.get(array, i);
72         }
73         return result;
74     }
75 
getMock()76     public Object getMock() {
77         return mock;
78     }
79 
getMethod()80     public Method getMethod() {
81         return method;
82     }
83 
getArguments()84     public Object[] getArguments() {
85         return arguments;
86     }
87 
88     @Override
equals(Object o)89     public boolean equals(Object o) {
90         if (o == null || !o.getClass().equals(this.getClass()))
91             return false;
92 
93         Invocation other = (Invocation) o;
94 
95         return this.mock.equals(other.mock) && this.method.equals(other.method)
96                 && this.equalArguments(other.arguments);
97     }
98 
99     @Override
hashCode()100     public int hashCode() {
101         throw new UnsupportedOperationException("hashCode() is not implemented");
102     }
103 
equalArguments(Object[] arguments)104     private boolean equalArguments(Object[] arguments) {
105         if (this.arguments.length != arguments.length) {
106             return false;
107         }
108         for (int i = 0; i < this.arguments.length; i++) {
109             Object myArgument = this.arguments[i];
110             Object otherArgument = arguments[i];
111 
112             if (isPrimitiveParameter(i)) {
113                 if (!myArgument.equals(otherArgument)) {
114                     return false;
115                 }
116             } else {
117                 if (myArgument != otherArgument) {
118                     return false;
119                 }
120             }
121         }
122         return true;
123     }
124 
isPrimitiveParameter(int parameterPosition)125     private boolean isPrimitiveParameter(int parameterPosition) {
126         Class<?>[] parameterTypes = method.getParameterTypes();
127         if (method.isVarArgs()) {
128             parameterPosition = Math.min(parameterPosition,
129                     parameterTypes.length - 1);
130         }
131         return parameterTypes[parameterPosition].isPrimitive();
132     }
133 
134     @SuppressWarnings("deprecation")
matches(Invocation actual, org.easymock.ArgumentsMatcher matcher)135     public boolean matches(Invocation actual, org.easymock.ArgumentsMatcher matcher) {
136         return this.mock.equals(actual.mock)
137                 && this.method.equals(actual.method)
138                 && matcher.matches(this.arguments, actual.arguments);
139     }
140 
141     @SuppressWarnings("deprecation")
toString(org.easymock.ArgumentsMatcher matcher)142     public String toString(org.easymock.ArgumentsMatcher matcher) {
143         return getMockAndMethodName() + "(" + matcher.toString(arguments) + ")";
144     }
145 
getMockAndMethodName()146     public String getMockAndMethodName() {
147         String mockName = mock.toString();
148         String methodName = method.getName();
149         if (toStringIsDefined(mock) && isJavaIdentifier(mockName)) {
150             return mockName + "." + methodName;
151         } else {
152             return methodName;
153         }
154     }
155 
addCapture(Captures<Object> capture, Object value)156     public void addCapture(Captures<Object> capture, Object value) {
157         capture.setPotentialValue(value);
158         currentCaptures.add(capture);
159     }
160 
validateCaptures()161     public void validateCaptures() {
162         for (Captures<?> c : currentCaptures) {
163             c.validateCapture();
164         }
165     }
166 
clearCaptures()167     public void clearCaptures() {
168         for (Captures<?> c : currentCaptures) {
169             c.setPotentialValue(null);
170         }
171         currentCaptures.clear();
172     }
173 
toStringIsDefined(Object o)174     private boolean toStringIsDefined(Object o) {
175         try {
176             o.getClass().getDeclaredMethod("toString", (Class[]) null)
177                     .getModifiers();
178             return true;
179         } catch (SecurityException ignored) {
180             // ///CLOVER:OFF
181             return false;
182             // ///CLOVER:ON
183         } catch (NoSuchMethodException shouldNeverHappen) {
184             // ///CLOVER:OFF
185             throw new RuntimeException("The toString() method could not be found!");
186             // ///CLOVER:ON
187         }
188     }
189 
isJavaIdentifier(String mockName)190     public static boolean isJavaIdentifier(String mockName) {
191         if (mockName.length() == 0 || mockName.indexOf(' ') > -1
192                 || !Character.isJavaIdentifierStart(mockName.charAt(0))) {
193             return false;
194         }
195         for (char c : mockName.substring(1).toCharArray()) {
196             if (!isJavaIdentifierPart(c)) {
197                 return false;
198             }
199         }
200         return true;
201     }
202 
readObject(java.io.ObjectInputStream stream)203     private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
204         stream.defaultReadObject();
205         try {
206             method = ((MethodSerializationWrapper) stream.readObject()).getMethod();
207         } catch (NoSuchMethodException e) {
208             // ///CLOVER:OFF
209             throw new IOException(e.toString());
210             // ///CLOVER:ON
211         }
212     }
213 
writeObject(java.io.ObjectOutputStream stream)214     private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
215         stream.defaultWriteObject();
216         stream.writeObject(new MethodSerializationWrapper(method));
217     }
218 }
219