001: /*
002: *******************************************************************************
003: * Copyright (C) 2004-2005, International Business Machines Corporation and *
004: * others. All Rights Reserved. *
005: *******************************************************************************
006: */
007: package com.ibm.icu.dev.test;
008:
009: import java.lang.reflect.Constructor;
010: import java.lang.reflect.Method;
011: import java.util.Collection;
012: import java.util.Iterator;
013: import java.util.LinkedList;
014: import java.util.List;
015: import java.util.Map;
016: import java.util.Set;
017: import java.util.TreeSet;
018:
019: import com.ibm.icu.text.UnicodeSet;
020:
021: /**
022: * To use, override the abstract and the protected methods as necessary.
023: * Tests boilerplate invariants:
024: * <br>a.equals(a)
025: * <br>!a.equals(null)
026: * <br>if a.equals(b) then
027: * <br>(1) a.hashCode() == b.hashCode // note: the reverse is not necessarily true.
028: * <br>(2) a functions in all aspects as equivalent to b
029: * <br>(3) b.equals(a)
030: * <br>if b = clone(a)
031: * <br>(1) b.equals(a), and the above checks
032: * <br>(2) if mutable(a), then a.clone() != a // note: the reverse is not necessarily true.
033: * @author Davis
034: */
035: public abstract class TestBoilerplate extends TestFmwk {
036:
037: public final void TestMain() throws Exception {
038: List list = new LinkedList();
039: while (_addTestObject(list)) {
040: }
041: Object[] testArray = list.toArray();
042: for (int i = 0; i < testArray.length; ++i) {
043: //logln("Testing " + i);
044: Object a = testArray[i];
045: int aHash = a.hashCode();
046: if (a.equals(null)) {
047: errln("Equality/Null invariant fails: " + i);
048: }
049: if (!a.equals(a)) {
050: errln("Self-Equality invariant fails: " + i);
051: }
052: Object b;
053: if (_canClone(a)) {
054: b = _clone(a);
055: if (b == a) {
056: if (_isMutable(a)) {
057: errln("Clone/Mutability invariant fails: " + i);
058: }
059: } else {
060: if (!a.equals(b)) {
061: errln("Clone/Equality invariant fails: " + i);
062: }
063: }
064: _checkEquals(i, -1, a, aHash, b);
065: }
066: for (int j = i; j < testArray.length; ++j) {
067: b = testArray[j];
068: if (a.equals(b))
069: _checkEquals(i, j, a, aHash, b);
070: }
071: }
072: }
073:
074: private void _checkEquals(int i, int j, Object a, int aHash,
075: Object b) {
076: int bHash = b.hashCode();
077: if (!b.equals(a))
078: errln("Equality/Symmetry", i, j);
079: if (aHash != bHash)
080: errln("Equality/Hash", i, j);
081: if (a != b && !_hasSameBehavior(a, b)) {
082: errln("Equality/Equivalence", i, j);
083: }
084: }
085:
086: private void errln(String title, int i, int j) {
087: if (j < 0)
088: errln("Clone/" + title + "invariant fails: " + i);
089: else
090: errln(title + "invariant fails: " + i + "," + j);
091: }
092:
093: /**
094: * Must be overridden to check whether a and be behave the same
095: */
096: protected abstract boolean _hasSameBehavior(Object a, Object b);
097:
098: /**
099: * This method will be called multiple times until false is returned.
100: * The results should be a mixture of different objects of the same
101: * type: some equal and most not equal.
102: * The subclasser controls how many are produced (recommend about
103: * 100, based on the size of the objects and how costly they are
104: * to run this test on. The running time grows with the square of the
105: * count.
106: * NOTE: this method will only be called if the objects test as equal.
107: */
108: protected abstract boolean _addTestObject(List c);
109:
110: /**
111: * Override if the tested objects are mutable.
112: * <br>Since Java doesn't tell us, we need a function to tell if so.
113: * The default is true, so must be overridden if not.
114: */
115: protected boolean _isMutable(Object a) {
116: return true;
117: }
118:
119: /**
120: * Override if the tested objects can be cloned.
121: */
122: protected boolean _canClone(Object a) {
123: return true;
124: }
125:
126: /**
127: * Produce a clone of the object. Tries two methods
128: * (a) clone
129: * (b) constructor
130: * Must be overridden if _canClone returns true and
131: * the above methods don't work.
132: * @param a
133: * @return clone
134: */
135: protected Object _clone(Object a) throws Exception {
136: Class aClass = a.getClass();
137: try {
138: Method cloner = aClass.getMethod("clone", null);
139: return cloner.invoke(a, null);
140: } catch (NoSuchMethodException e) {
141: Constructor constructor = aClass
142: .getConstructor(new Class[] { aClass });
143: return constructor.newInstance(new Object[] { a });
144: }
145: }
146:
147: /* Utilities */
148: public static boolean verifySetsIdentical(AbstractTestLog here,
149: UnicodeSet set1, UnicodeSet set2) {
150: if (set1.equals(set2))
151: return true;
152: here.errln("Sets differ:");
153: here.errln("UnicodeMap - HashMap");
154: here
155: .errln(new UnicodeSet(set1).removeAll(set2).toPattern(
156: true));
157: here.errln("HashMap - UnicodeMap");
158: here
159: .errln(new UnicodeSet(set2).removeAll(set1).toPattern(
160: true));
161: return false;
162: }
163:
164: public static boolean verifySetsIdentical(AbstractTestLog here,
165: Set values1, Set values2) {
166: if (values1.equals(values2))
167: return true;
168: Set temp;
169: here.errln("Values differ:");
170: here.errln("UnicodeMap - HashMap");
171: temp = new TreeSet(values1);
172: temp.removeAll(values2);
173: here.errln(show(temp));
174: here.errln("HashMap - UnicodeMap");
175: temp = new TreeSet(values2);
176: temp.removeAll(values1);
177: here.errln(show(temp));
178: return false;
179: }
180:
181: public static String show(Map m) {
182: StringBuffer buffer = new StringBuffer();
183: for (Iterator it = m.keySet().iterator(); it.hasNext();) {
184: Object key = it.next();
185: buffer.append(key + "=>" + m.get(key) + "\r\n");
186: }
187: return buffer.toString();
188: }
189:
190: public static UnicodeSet getSet(Map m, Object value) {
191: UnicodeSet result = new UnicodeSet();
192: for (Iterator it = m.keySet().iterator(); it.hasNext();) {
193: Object key = it.next();
194: Object val = m.get(key);
195: if (!val.equals(value))
196: continue;
197: result.add(((Integer) key).intValue());
198: }
199: return result;
200: }
201:
202: public static String show(Collection c) {
203: StringBuffer buffer = new StringBuffer();
204: for (Iterator it = c.iterator(); it.hasNext();) {
205: buffer.append(it.next() + "\r\n");
206: }
207: return buffer.toString();
208: }
209:
210: }
|