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 package com.gargoylesoftware.base.testing;
39
40 import com.gargoylesoftware.base.util.DetailedNullPointerException;
41 import java.lang.reflect.InvocationTargetException;
42 import java.lang.reflect.Method;
43 import java.io.ByteArrayInputStream;
44 import java.io.ByteArrayOutputStream;
45 import java.io.IOException;
46 import java.io.ObjectInputStream;
47 import java.io.ObjectOutputStream;
48 import junit.framework.AssertionFailedError;
49
50
51 /***
52 * Utility methods dealing with JUnit testing.
53 *
54 * @version $Revision: 1.7 $
55 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
56 */
57 public class TestUtil {
58
59
60 private TestUtil() {
61 }
62
63 /***
64 * Serialize the specified object to a stream and then deserialize
65 * it again. This tests the following things:
66 * <ol>
67 * <li>Ensures that the original and reconstructed objects
68 * are equal.
69 * <li>The object can be serialized
70 * </ol>
71 *
72 * @param object The object to test
73 * @param checkEquality True if the original and copy should be
74 * equal according to the semantics of the equals() method.
75 * @return The copy.
76 * @throws IOException If an error occcurs during serialization.
77 */
78 public static Object testSerialization(
79 final Object object,
80 final boolean checkEquality )
81 throws
82 IOException {
83
84 assertNotNull("object", object);
85
86 final Object copy = copyBySerialization(object);
87
88 if( checkEquality ) {
89 checkEquality( object, copy );
90 }
91
92 return copy;
93 }
94
95 /***
96 * Same as testSerialization(object, true). Provided as a convenience as
97 * the equality check is usually wanted.
98 * @param object The object to test
99 * @return The copy.
100 * @throws IOException If an error occcurs during serialization.
101 */
102 public static Object testSerialization(
103 final Object object )
104 throws
105 IOException {
106
107 return testSerialization( object, true );
108 }
109
110 /***
111 * Copy an object by serializing it into a buffer and then deserializing
112 * it again.
113 *
114 * @param object The original.
115 * @return The copy.
116 * @throws IOException If an error occcurs during serialization.
117 */
118 public static Object copyBySerialization( final Object object )
119 throws
120 IOException {
121
122 assertNotNull("object", object);
123
124 try {
125 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
126 final ObjectOutputStream oos = new ObjectOutputStream(bos);
127 oos.writeObject(object);
128 oos.flush();
129
130 final byte[] b = bos.toByteArray();
131 final ByteArrayInputStream bis = new ByteArrayInputStream(b);
132 final ObjectInputStream ois = new ObjectInputStream(bis);
133 final Object copy = ois.readObject();
134
135 return copy;
136 }
137 catch( final ClassNotFoundException e ) {
138
139 throw new NoClassDefFoundError("Class not found: "+e.getMessage());
140 }
141 }
142
143 /***
144 * The the clone() method on an object.
145 * @param object The original object to clone.
146 * @param checkEquality True if the original and copy are to be compared
147 * for equality after the clone().
148 * @throws IllegalAccessException If we do not have authority to call the
149 * clone() method.
150 * @throws InvocationTargetException If an exception is thrown during
151 * the processing of the clone() method
152 */
153 public static void testClone( final Object object, final boolean checkEquality )
154 throws
155 IllegalAccessException,
156 InvocationTargetException {
157
158 if( object instanceof Cloneable == false ) {
159 throw new AssertionFailedError("Object is not cloneable");
160 }
161
162 Method cloneMethod;
163 try {
164 cloneMethod = object.getClass().getDeclaredMethod("clone", new Class[0] );
165 }
166 catch( final NoSuchMethodException e ) {
167 throw new AssertionFailedError("Object does not have a public clone() method");
168 }
169
170 final Object copy = cloneMethod.invoke( object, new Object[0] );
171 if( checkEquality ) {
172 checkEquality( object, copy );
173 }
174 }
175
176 /***
177 * Assert that the two objects are equal
178 * @param original The original object
179 * @param copy The object to compare against
180 */
181 private static void checkEquality( final Object original, final Object copy ) {
182 if( copy.equals( original ) == false ) {
183 throw new AssertionFailedError("Objects are different: original=["+original+"] copy=["+copy+"]");
184 }
185
186 if( copy.hashCode() != original.hashCode() ) {
187 throw new AssertionFailedError("Hashcodes are different: original=["
188 +original.hashCode()+"] copy=["
189 +copy.hashCode()+"]");
190 }
191 }
192
193
194 /***
195 * Assert that a and b appear equal. See {@link #appearsEqual(Object,Object)}
196 * for an explanation of "appears"
197 *
198 * @param message The message to display if the assert fails.
199 * @param a The first object to compare
200 * @param b The second object to compare
201 */
202 public static void assertAppearsEqual(
203 final String message, final Object a, final Object b ) {
204
205 if( appearsEqual(a, b) == false ) {
206 throw new AssertionFailedError(message);
207 }
208 }
209
210
211 /***
212 * Assert that a and b do not appear equal. See {@link #appearsEqual(Object,Object)}
213 * for an explanation of "appears"
214 *
215 * @param message The message to display if the assert fails.
216 * @param a The first object to compare
217 * @param b The second object to compare
218 */
219 public static void assertAppearsNotEqual(
220 final String message, final Object a, final Object b ) {
221
222 if( appearsEqual(a, b) == true ) {
223 throw new AssertionFailedError(message);
224 }
225 }
226
227
228 /***
229 * Return true if the two objects appear to be equal. Some objects cannot
230 * be compared for equality because they don't implement either the equals
231 * method or the Comparable interface. An example would be the Event objects
232 * used by AWT and Swing.<p>
233 *
234 * This method will attempt to determine if the two objects are equal by
235 * calling all the public accessor methods on the objects and performing
236 * equals checks on the results.<p>
237 *
238 * If an exception is thrown during the invocation of any of the getXX()
239 * methods then that method will be ignored for the purpose of considering
240 * equality.
241 *
242 * @param a The first object to be compared
243 * @param b The second object to be compared
244 * @return True if the two objects appear to be the same.
245 */
246 public static boolean appearsEqual( final Object a, final Object b ) {
247 if( a == null && b == null ) {
248 return true;
249 }
250 if( a == null || b == null ) {
251 return false;
252 }
253 final Class clazz = a.getClass();
254 if( b.getClass() != clazz ) {
255 return false;
256 }
257
258 final Object noArgs[] = new Object[0];
259 final Method getMethods[] = clazz.getDeclaredMethods();
260 for( int i=0; i<getMethods.length; i++ ) {
261 final Method method = getMethods[i];
262 if( method.getParameterTypes().length == 0 ) {
263 try {
264 if( isEqual( method.invoke(a, noArgs), method.invoke(b, noArgs) ) == false ) {
265 return false;
266 }
267 }
268 catch( final IllegalAccessException e ) {
269
270 e.printStackTrace();
271 }
272 catch( final InvocationTargetException e ) {
273
274 e.printStackTrace();
275 }
276 }
277 }
278
279 return true;
280 }
281
282
283 private static boolean isEqual( final Object a, final Object b ) {
284 final boolean isEqual;
285 if( a == null && b == null ) {
286 isEqual = true;
287 }
288 else if( a == null || b == null ) {
289 isEqual = false;
290 }
291 else {
292 isEqual = a.equals(b);
293 }
294
295 return isEqual;
296 }
297
298
299 /***
300 * Verify that the specified value is not null. If it is then throw an exception
301 *
302 * @param fieldName The name of the field to check
303 * @param fieldValue The value of the field to check
304 * @exception DetailedNullPointerException If fieldValue is null
305 */
306 public static final void assertNotNull( final String fieldName, final Object fieldValue )
307 throws DetailedNullPointerException {
308
309 if( fieldValue == null ) {
310 throw new DetailedNullPointerException(fieldName);
311 }
312 }
313 }
314