• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html#License
3 /*
4  *******************************************************************************
5  * Copyright (C) 2006-2011, International Business Machines Corporation and    *
6  * others. All Rights Reserved.                                                *
7  *******************************************************************************
8  */
9 
10 package com.ibm.icu.tests;
11 
12 import java.io.ByteArrayInputStream;
13 import java.io.ByteArrayOutputStream;
14 import java.io.Externalizable;
15 import java.io.IOException;
16 import java.io.ObjectInputStream;
17 import java.io.ObjectOutputStream;
18 import java.io.Serializable;
19 import java.lang.reflect.Array;
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.util.Locale;
23 
24 import com.ibm.icu.util.TimeZone;
25 import com.ibm.icu.util.ULocale;
26 
27 import junit.framework.TestCase;
28 
29 /**
30  * Implement boilerplate tests.
31  * Currently there is only one method, testEHCS, which tests equals, hashCode,
32  * clone, and serialization.
33  */
34 public abstract class ICUTestCase extends TestCase {
35     private static final Object[] EMPTY_ARGS = {};
36 	private static final Class<?>[] EMPTY_CLASSES = {};
37 
38     private static final Locale oldLocale = Locale.getDefault();
39     private static final ULocale oldULocale = ULocale.getDefault();
40     private static final java.util.TimeZone oldJTimeZone = java.util.TimeZone.getDefault();
41     private static final TimeZone oldITimeZone = TimeZone.getDefault();
42 
43     // TODO: what's the best way to check this?
44     public static final boolean testingWrapper = true;
45 
setUp()46     protected void setUp() throws Exception {
47         super.setUp();
48         Locale.setDefault(Locale.US);
49         ULocale.setDefault(ULocale.US);
50         java.util.TimeZone.setDefault(java.util.TimeZone.getTimeZone("PST"));
51         TimeZone.setDefault(TimeZone.getTimeZone("PST"));
52     }
53 
tearDown()54     protected void tearDown() throws Exception {
55         ULocale.setDefault(oldULocale);
56         Locale.setDefault(oldLocale);
57         TimeZone.setDefault(oldITimeZone);
58         java.util.TimeZone.setDefault(oldJTimeZone);
59         super.tearDown();
60     }
61 
62     private static final Object test = new Object();
63 
64     /**
65      * Assert that two objects are _not_ equal.  Curiously missing from Assert.
66      * @param lhs an object to test, may be null
67      * @param rhs an object to test, may be null
68      */
assertNotEqual(Object lhs, Object rhs)69     public static void assertNotEqual(Object lhs, Object rhs) {
70         if (lhs == null) {
71             if (rhs == null) fail("null equals null");
72         } else {
73             if (lhs.equals(rhs)) {
74                 fail(lhs.toString() + " equals " + rhs);
75             }
76         }
77     }
78 
assertNotEqual(long lhs, long rhs)79     public static void assertNotEqual(long lhs, long rhs) {
80         if (lhs == rhs) {
81             fail("values are equal: " + lhs);
82         }
83     }
84 
85     /**
86      * Test whether equality, hashCode, clone, and serialization work as expected.
87      * Equals(Object) is assumed to return false (not throw an exception) if passed
88      * null or an object of an incompatible class.
89      * Hashcodes must be equal iff the two objects compare equal.  No attempt is made to
90      * evaluate the quality of the hashcode distribution, so (in particular) degenerate
91      * hashcode implementations will pass this test.
92      * Clone will be tested if the method "clone" is public on the class of obj.
93      * It is assumed to return an object that compares equal to obj.
94      * Serialization will be tested if object implements Serializable or Externalizable.
95      * It is assumed the serialized/deserialized object compares equal to obj.
96      * @param obj the object to test
97      * @param eq an object that should compare equal to, but is not the same as, obj.
98      *     it should be assignable to the class of obj.
99      * @param neq a non-null object that should not compare equal to obj.
100      *     it should be assignable to the class of obj.
101      */
testEHCS(Object obj, Object eq, Object neq)102 	public static void testEHCS(Object obj, Object eq, Object neq) {
103         if (obj == null || eq == null || neq == null) {
104             throw new NullPointerException();
105         }
106         Class<? extends Object> cls = obj.getClass();
107         if (!(cls.isAssignableFrom(eq.getClass()) && cls.isAssignableFrom(neq.getClass()))) {
108             throw new IllegalArgumentException("unassignable classes");
109         }
110 
111         // reflexive
112         assertEquals(obj, obj);
113 
114         // should return false, not throw exception
115         assertNotEqual(obj, test);
116         assertNotEqual(obj, null);
117 
118         // commutative
119         assertEquals(obj, eq);
120         assertEquals(eq, obj);
121 
122         assertNotEqual(obj, neq);
123         assertNotEqual(neq, obj);
124 
125         // equal objects MUST have equal hashes, unequal objects MAY have equal hashes
126         assertEquals(obj.hashCode(), eq.hashCode());
127 
128         Object clone = null;
129         try {
130             // look for public clone method and call it if available
131             Method method_clone = cls.getMethod("clone", EMPTY_CLASSES);
132             clone = method_clone.invoke(obj, EMPTY_ARGS);
133             assertNotNull(clone);
134         }
135         catch(NoSuchMethodException e) {
136             // ok
137         }
138         catch(InvocationTargetException e) {
139             // ok
140         }
141         catch(IllegalAccessException e) {
142             // ok
143         }
144 
145         if (clone != null) {
146             assertEquals(obj, clone);
147             assertEquals(clone, obj);
148         }
149 
150         if (obj instanceof Serializable || obj instanceof Externalizable) {
151             Object ser = null;
152             try {
153                 ByteArrayOutputStream bos = new ByteArrayOutputStream();
154                 ObjectOutputStream oos = new ObjectOutputStream(bos);
155                 oos.writeObject(clone);
156                 oos.close();
157 
158                 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
159                 ObjectInputStream ois = new ObjectInputStream(bis);
160                 ser = ois.readObject();
161                 ois.close();
162             }
163             catch(IOException e) {
164                 System.err.println(e.getMessage());
165                 throw new RuntimeException(e);
166             }
167             catch(ClassNotFoundException e) {
168                 System.err.println(e.getMessage());
169                 throw new RuntimeException(e);
170             }
171 
172             if (ser != null) {
173                 assertEquals(obj, ser);
174                 assertEquals(ser, obj);
175                 assertEquals(obj.hashCode(), ser.hashCode());
176             }
177         }
178     }
179 
180     /**
181      * Fail if the arrays are not equal.  To be equal, the arrays must
182      * be the same length, and each element in the left array must compare
183      * equal to the corresponding element of the right array.
184      * Also fails if one of the objects is not an array.
185      * @param lhs the left array
186      * @param rhs the right array
187      */
assertArraysEqual(Object lhs, Object rhs)188     public static void assertArraysEqual(Object lhs, Object rhs) {
189         Class<? extends Object> lcls = lhs.getClass();
190         Class<? extends Object> rcls = rhs.getClass();
191         if (!(lcls.isArray() && rcls.isArray())) {
192             fail("objects are not arrays");
193         }
194         String result = arraysAreEqual(lhs, rhs);
195         if (result != null) {
196             fail(result);
197         }
198     }
199 
200     /**
201      * Fail if the arrays are equal.  Also fails if one or the other
202      * argument is not an array.
203      * @param lhs the left array
204      * @param rhs the right array
205      */
assertArraysNotEqual(Object lhs, Object rhs)206     public static void assertArraysNotEqual(Object lhs, Object rhs) {
207         Class<? extends Object> lcls = lhs.getClass();
208         Class<? extends Object> rcls = rhs.getClass();
209         if (!(lcls.isArray() && rcls.isArray())) {
210             fail("objects are not arrays");
211         }
212         String result = arraysAreEqual(lhs, rhs);
213         if (result == null) {
214             fail("arrays are equal");
215         }
216     }
217 
218     // slow but general
arraysAreEqual(Object lhsa, Object rhsa)219     private static String arraysAreEqual(Object lhsa, Object rhsa) {
220         int lhsl = Array.getLength(lhsa);
221         int rhsl = Array.getLength(rhsa);
222         if (lhsl != rhsl) {
223             return "length " + lhsl + " != " + rhsl;
224         }
225         boolean lhsaA = lhsa.getClass().getComponentType().isArray();
226         boolean rhsaA = rhsa.getClass().getComponentType().isArray();
227         if (lhsaA != rhsaA) {
228             return (lhsaA ? "" : "non-") + "array != " + (rhsaA ? "" : "non-") + "array";
229         }
230         for (int i = 0; i < lhsl; ++i) {
231             Object lhse = Array.get(lhsa, i);
232             Object rhse = Array.get(rhsa, i);
233             if (lhse == null) {
234                 if (rhse != null) {
235                     return "null != " + rhse;
236                 }
237             } else {
238                 if (lhsaA) {
239                     String result = arraysAreEqual(lhse, rhse);
240                     if (result != null) {
241                         if (result.charAt(0) != '[') {
242                             result = " " + result;
243                         }
244                         return "[" + i + "]" + result;
245                     }
246                 } else {
247                     if (!lhse.equals(rhse)) {
248                         return lhse.toString() + " != " + rhse;
249                     }
250                 }
251             }
252         }
253         return null;
254     }
255 
256     // much more painful and slow than it should be... partly because of the
257     // oddness of clone, partly because arrays don't provide a Method for
258     // 'clone' despite the fact that they implement it and make it public.
cloneComplex(Object obj)259     public static Object cloneComplex(Object obj) {
260         Object result = null;
261         if (obj != null) {
262             Class<? extends Object> cls = obj.getClass();
263             if (cls.isArray()) {
264                 int len = Array.getLength(obj);
265                 Class<?> typ = cls.getComponentType();
266                 result = Array.newInstance(typ, len);
267                 boolean prim = typ.isPrimitive();
268                 for (int i = 0; i < len; ++i) {
269                     Object elem = Array.get(obj, i);
270                     Array.set(result, i, prim ? elem : cloneComplex(elem));
271                 }
272             } else {
273                 result = obj; // default
274                 try {
275                     Method cloneM = cls.getMethod("clone", EMPTY_CLASSES);
276                     result = cloneM.invoke(obj, EMPTY_ARGS);
277                 }
278                 catch (NoSuchMethodException e) {
279                 }
280                 catch (IllegalAccessException e) {
281                 }
282                 catch (InvocationTargetException e) {
283                 }
284             }
285         }
286         return result;
287     }
288 }
289