boilerplate testing
X-SVN-Rev: 14567
This commit is contained in:
parent
e61e59075f
commit
ab0b75881b
191
icu4j/src/com/ibm/icu/dev/test/TestBoilerplate.java
Normal file
191
icu4j/src/com/ibm/icu/dev/test/TestBoilerplate.java
Normal file
@ -0,0 +1,191 @@
|
||||
package com.ibm.icu.dev.test;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.ibm.icu.text.UnicodeSet;
|
||||
|
||||
/**
|
||||
* To use, override the abstract and the protected methods as necessary.
|
||||
* Tests boilerplate invariants:
|
||||
* <br>a.equals(a)
|
||||
* <br>!a.equals(null)
|
||||
* <br>if a.equals(b) then
|
||||
* <br>(1) a.hashCode() == b.hashCode // note: the reverse is not necessarily true.
|
||||
* <br>(2) a functions in all aspects as equivalent to b
|
||||
* <br>(3) b.equals(a)
|
||||
* <br>if b = clone(a)
|
||||
* <br>(1) b.equals(a), and the above checks
|
||||
* <br>(2) if mutable(a), then a.clone() != a // note: the reverse is not necessarily true.
|
||||
* @author Davis
|
||||
*/
|
||||
public abstract class TestBoilerplate extends TestFmwk {
|
||||
|
||||
public final void TestMain() throws Exception {
|
||||
List list = new LinkedList();
|
||||
while (_addTestObject(list));
|
||||
Object[] testArray = list.toArray();
|
||||
for (int i = 0; i < testArray.length; ++i) {
|
||||
//logln("Testing " + i);
|
||||
Object a = testArray[i];
|
||||
int aHash = a.hashCode();
|
||||
if (a.equals(null)) {
|
||||
errln("Equality/Null invariant fails: " + i);
|
||||
}
|
||||
if (!a.equals(a)) {
|
||||
errln("Self-Equality invariant fails: " + i);
|
||||
}
|
||||
Object b;
|
||||
if (_canClone(a)) {
|
||||
b = _clone(a);
|
||||
if (b == a) {
|
||||
if (_isMutable(a)) {
|
||||
errln("Clone/Mutability invariant fails: " + i);
|
||||
}
|
||||
} else {
|
||||
if (!a.equals(b)) {
|
||||
errln("Clone/Equality invariant fails: " + i);
|
||||
}
|
||||
}
|
||||
_checkEquals(i, -1, a, aHash, b);
|
||||
}
|
||||
for (int j = i; j < testArray.length; ++j) {
|
||||
b = testArray[j];
|
||||
if (a.equals(b)) _checkEquals(i, j, a, aHash, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _checkEquals(int i, int j, Object a, int aHash, Object b) {
|
||||
int bHash = b.hashCode();
|
||||
if (!b.equals(a)) errln("Equality/Symmetry",i, j);
|
||||
if (aHash != bHash) errln("Equality/Hash",i, j);
|
||||
if (a != b && !_hasSameBehavior(a,b)) {
|
||||
errln("Equality/Equivalence",i, j);
|
||||
}
|
||||
}
|
||||
|
||||
private void errln(String title, int i, int j) {
|
||||
if (j < 0) errln("Clone/" + title + "invariant fails: " + i);
|
||||
else errln(title + "invariant fails: " + i + "," + j);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be overridden to check whether a and be behave the same
|
||||
* @param a
|
||||
* @param b
|
||||
* @return
|
||||
*/
|
||||
protected abstract boolean _hasSameBehavior(Object a, Object b);
|
||||
|
||||
/**
|
||||
* This method will be called multiple times until false is returned.
|
||||
* The results should be a mixture of different objects of the same
|
||||
* type: some equal and most not equal.
|
||||
* The subclasser controls how many are produced (recommend about
|
||||
* 100, based on the size of the objects and how costly they are
|
||||
* to run this test on. The running time grows with the square of the
|
||||
* count.
|
||||
* NOTE: this method will only be called if the objects test as equal.
|
||||
* @return
|
||||
*/
|
||||
protected abstract boolean _addTestObject(List c);
|
||||
/**
|
||||
* Override if the tested objects are mutable.
|
||||
* <br>Since Java doesn't tell us, we need a function to tell if so.
|
||||
* The default is true, so must be overridden if not.
|
||||
* @return
|
||||
*/
|
||||
protected boolean _isMutable(Object a) {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Override if the tested objects can be cloned.
|
||||
* @return
|
||||
*/
|
||||
protected boolean _canClone(Object a) {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Produce a clone of the object. Tries two methods
|
||||
* (a) clone
|
||||
* (b) constructor
|
||||
* Must be overridden if _canClone returns true and
|
||||
* the above methods don't work.
|
||||
* @param a
|
||||
* @return clone
|
||||
*/
|
||||
protected Object _clone(Object a) throws Exception {
|
||||
Class aClass = a.getClass();
|
||||
try {
|
||||
Method cloner = aClass.getMethod("clone", null);
|
||||
return cloner.invoke(a,null);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Constructor constructor = aClass.getConstructor(new Class[] {aClass});
|
||||
return constructor.newInstance(new Object[]{a});
|
||||
}
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
public static boolean verifySetsIdentical(AbstractTestLog here, UnicodeSet set1, UnicodeSet set2) {
|
||||
if (set1.equals(set2)) return true;
|
||||
here.errln("Sets differ:");
|
||||
here.errln("UnicodeMap - HashMap");
|
||||
here.errln(new UnicodeSet(set1).removeAll(set2).toPattern(true));
|
||||
here.errln("HashMap - UnicodeMap");
|
||||
here.errln(new UnicodeSet(set2).removeAll(set1).toPattern(true));
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean verifySetsIdentical(AbstractTestLog here, Set values1, Set values2) {
|
||||
if (values1.equals(values2)) return true;
|
||||
Set temp;
|
||||
here.errln("Values differ:");
|
||||
here.errln("UnicodeMap - HashMap");
|
||||
temp = new TreeSet(values1);
|
||||
temp.removeAll(values2);
|
||||
here.errln(show(temp));
|
||||
here.errln("HashMap - UnicodeMap");
|
||||
temp = new TreeSet(values2);
|
||||
temp.removeAll(values1);
|
||||
here.errln(show(temp));
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String show(Map m) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (Iterator it = m.keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
buffer.append(key + "=>" + m.get(key) + "\r\n");
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public static UnicodeSet getSet(Map m, Object value) {
|
||||
UnicodeSet result = new UnicodeSet();
|
||||
for (Iterator it = m.keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
Object val = m.get(key);
|
||||
if (!val.equals(value)) continue;
|
||||
result.add(((Integer)key).intValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String show(Collection c) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (Iterator it = c.iterator(); it.hasNext();) {
|
||||
buffer.append(it.next() + "\r\n");
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user