1/* 2 ******************************************************************************* 3 * Copyright (C) 2004-2007, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7package com.ibm.icu.dev.test; 8 9import java.lang.reflect.Constructor; 10import java.lang.reflect.Method; 11import java.util.Collection; 12import java.util.Iterator; 13import java.util.LinkedList; 14import java.util.List; 15import java.util.Map; 16import java.util.Set; 17import java.util.TreeSet; 18 19import com.ibm.icu.text.UnicodeSet; 20 21/** 22 * To use, override the abstract and the protected methods as necessary. 23 * Tests boilerplate invariants: 24 * <br>a.equals(a) 25 * <br>!a.equals(null) 26 * <br>if a.equals(b) then 27 * <br>(1) a.hashCode() == b.hashCode // note: the reverse is not necessarily true. 28 * <br>(2) a functions in all aspects as equivalent to b 29 * <br>(3) b.equals(a) 30 * <br>if b = clone(a) 31 * <br>(1) b.equals(a), and the above checks 32 * <br>(2) if mutable(a), then a.clone() != a // note: the reverse is not necessarily true. 33 * @author Davis 34 */ 35public abstract class TestBoilerplate extends TestFmwk { 36 37 public final void TestMain() throws Exception { 38 List list = new LinkedList(); 39 while (_addTestObject(list)) { 40 } 41 Object[] testArray = list.toArray(); 42 for (int i = 0; i < testArray.length; ++i) { 43 //logln("Testing " + i); 44 Object a = testArray[i]; 45 int aHash = a.hashCode(); 46 if (a.equals(null)) { 47 errln("Equality/Null invariant fails: " + i); 48 } 49 if (!a.equals(a)) { 50 errln("Self-Equality invariant fails: " + i); 51 } 52 Object b; 53 if (_canClone(a)) { 54 b = _clone(a); 55 if (b == a) { 56 if (_isMutable(a)) { 57 errln("Clone/Mutability invariant fails: " + i); 58 } 59 } else { 60 if (!a.equals(b)) { 61 errln("Clone/Equality invariant fails: " + i); 62 } 63 } 64 _checkEquals(i, -1, a, aHash, b); 65 } 66 for (int j = i; j < testArray.length; ++j) { 67 b = testArray[j]; 68 if (a.equals(b)) _checkEquals(i, j, a, aHash, b); 69 } 70 } 71 } 72 73 private void _checkEquals(int i, int j, Object a, int aHash, Object b) { 74 int bHash = b.hashCode(); 75 if (!b.equals(a)) errln("Equality/Symmetry",i, j); 76 if (aHash != bHash) errln("Equality/Hash",i, j); 77 if (a != b && !_hasSameBehavior(a,b)) { 78 errln("Equality/Equivalence",i, j); 79 } 80 } 81 82 private void errln(String title, int i, int j) { 83 if (j < 0) errln("Clone/" + title + "invariant fails: " + i); 84 else errln(title + "invariant fails: " + i + "," + j); 85 } 86 87 /** 88 * Must be overridden to check whether a and be behave the same 89 */ 90 protected abstract boolean _hasSameBehavior(Object a, Object b); 91 92 /** 93 * This method will be called multiple times until false is returned. 94 * The results should be a mixture of different objects of the same 95 * type: some equal and most not equal. 96 * The subclasser controls how many are produced (recommend about 97 * 100, based on the size of the objects and how costly they are 98 * to run this test on. The running time grows with the square of the 99 * count. 100 * NOTE: this method will only be called if the objects test as equal. 101 */ 102 protected abstract boolean _addTestObject(List c); 103 /** 104 * Override if the tested objects are mutable. 105 * <br>Since Java doesn't tell us, we need a function to tell if so. 106 * The default is true, so must be overridden if not. 107 */ 108 protected boolean _isMutable(Object a) { 109 return true; 110 } 111 /** 112 * Override if the tested objects can be cloned. 113 */ 114 protected boolean _canClone(Object a) { 115 return true; 116 } 117 /** 118 * Produce a clone of the object. Tries two methods 119 * (a) clone 120 * (b) constructor 121 * Must be overridden if _canClone returns true and 122 * the above methods don't work. 123 * @param a 124 * @return clone 125 */ 126 protected Object _clone(Object a) throws Exception { 127 Class aClass = a.getClass(); 128 try { 129 Method cloner = aClass.getMethod("clone", (Class[])null); 130 return cloner.invoke(a,(Object[])null); 131 } catch (NoSuchMethodException e) { 132 Constructor constructor = aClass.getConstructor(new Class[] {aClass}); 133 return constructor.newInstance(new Object[]{a}); 134 } 135 } 136 137 /* Utilities */ 138 public static boolean verifySetsIdentical(AbstractTestLog here, UnicodeSet set1, UnicodeSet set2) { 139 if (set1.equals(set2)) return true; 140 here.errln("Sets differ:"); 141 here.errln("UnicodeMap - HashMap"); 142 here.errln(new UnicodeSet(set1).removeAll(set2).toPattern(true)); 143 here.errln("HashMap - UnicodeMap"); 144 here.errln(new UnicodeSet(set2).removeAll(set1).toPattern(true)); 145 return false; 146 } 147 148 public static boolean verifySetsIdentical(AbstractTestLog here, Set values1, Set values2) { 149 if (values1.equals(values2)) return true; 150 Set temp; 151 here.errln("Values differ:"); 152 here.errln("UnicodeMap - HashMap"); 153 temp = new TreeSet(values1); 154 temp.removeAll(values2); 155 here.errln(show(temp)); 156 here.errln("HashMap - UnicodeMap"); 157 temp = new TreeSet(values2); 158 temp.removeAll(values1); 159 here.errln(show(temp)); 160 return false; 161 } 162 163 public static String show(Map m) { 164 StringBuffer buffer = new StringBuffer(); 165 for (Iterator it = m.keySet().iterator(); it.hasNext();) { 166 Object key = it.next(); 167 buffer.append(key + "=>" + m.get(key) + "\r\n"); 168 } 169 return buffer.toString(); 170 } 171 172 public static UnicodeSet getSet(Map m, Object value) { 173 UnicodeSet result = new UnicodeSet(); 174 for (Iterator it = m.keySet().iterator(); it.hasNext();) { 175 Object key = it.next(); 176 Object val = m.get(key); 177 if (!val.equals(value)) continue; 178 result.add(((Integer)key).intValue()); 179 } 180 return result; 181 } 182 183 public static String show(Collection c) { 184 StringBuffer buffer = new StringBuffer(); 185 for (Iterator it = c.iterator(); it.hasNext();) { 186 buffer.append(it.next() + "\r\n"); 187 } 188 return buffer.toString(); 189 } 190 191 192} 193