/* Copyright (c) 2006, Sriram Srinivasan
*
* You may distribute this software under the terms of the license
* specified in the file "License"
*/
package kilim.test;
import kilim.analysis.IncompatibleTypesException;
import kilim.analysis.TypeDesc;
import junit.framework.TestCase;
import static kilim.Constants.*;
import java.lang.reflect.*;
import java.util.Arrays;
public class TestTypeDesc extends TestCase {
public void testInterning() throws Exception {
// Verify all strings in Constants that start with "D_"
// are indeed interned.
Class<?> c = Class.forName("kilim.Constants");
Field[] fields = c.getFields();
for (Field f:fields) {
if (f.getName().startsWith("D_")) {
String val = f.get(null).toString();
assertSame(TypeDesc.getInterned(new String(val)), val);
}
}
}
public void testComponentType() {
assertSame(TypeDesc.getComponentType("[J"), D_LONG);
assertSame(TypeDesc.getComponentType("[Ljava/lang/String;"), D_STRING);
}
public void testCommonSuperTypes() {
// Two interfaces => Object. Checking interning at the same time.
assertSame(TypeDesc.commonSuperType("Ljava/io/Serializable;", "Ljava/lang/Comparable;"),
D_OBJECT);
assertEquals(TypeDesc.commonSuperType("Lkilim/BasicBlock;",
"Lkilim/BasicBlock;"), "Lkilim/BasicBlock;");
assertSame(TypeDesc.commonSuperType("[Z", "[Z"), D_ARRAY_BOOLEAN);
// least upper bound of Field and Method is AccessibleObject
assertEquals("Ljava/lang/reflect/AccessibleObject;",
TypeDesc.commonSuperType("Ljava/lang/reflect/Field;",
"Ljava/lang/reflect/Method;"));
// least upper bound of Field and AccessibleObject is AccessibleObject
assertEquals("Ljava/lang/reflect/AccessibleObject;",
TypeDesc.commonSuperType("Ljava/lang/reflect/Field;",
"Ljava/lang/reflect/AccessibleObject;"));
// Same as above, but flip the order to see if it is sensitive.
assertEquals("Ljava/lang/reflect/AccessibleObject;",
TypeDesc.commonSuperType("Ljava/lang/reflect/Field;",
"Ljava/lang/reflect/AccessibleObject;"));
assertEquals("Lkilim/test/ex/ExA;",
TypeDesc.commonSuperType("Lkilim/test/ex/ExA;", "Lkilim/test/ex/ExD;"));
assertEquals("Lkilim/test/ex/ExA;",
TypeDesc.commonSuperType("Lkilim/test/ex/ExD;", "Lkilim/test/ex/ExA;"));
assertEquals("Lkilim/test/ex/ExA;",
TypeDesc.commonSuperType("Lkilim/test/ex/ExC;", "Lkilim/test/ex/ExD;"));
}
public void testArray() throws IncompatibleTypesException {
assertSame(D_OBJECT,
TypeDesc.mergeType("Lkilim/test/ex/ExC;", "[Z"));
assertSame(D_OBJECT,
TypeDesc.mergeType("[Z", "Lkilim/test/ex/ExC;"));
}
public void testNull() throws IncompatibleTypesException {
assertSame(D_NULL, TypeDesc.mergeType(D_NULL, D_NULL));
assertSame(D_OBJECT, TypeDesc.mergeType(D_OBJECT, D_NULL));
assertSame(D_OBJECT, TypeDesc.mergeType(D_NULL, D_OBJECT));
}
public void testNumArgs() throws IncompatibleTypesException {
assertTrue(TypeDesc.getNumArgumentTypes("()V") == 0);
assertTrue(TypeDesc.getNumArgumentTypes("(Ljava/lang/String;[[[ZZBCDSIJF)V") == 10);
}
public void testReturnType() throws IncompatibleTypesException {
assertTrue(TypeDesc.getReturnTypeDesc("()V") == D_VOID);
assertTrue(TypeDesc.getReturnTypeDesc("()[I") == D_ARRAY_INT);
assertTrue(TypeDesc.getReturnTypeDesc("(IIII)[Ljava/lang/Throwable;").equals("[Ljava/lang/Throwable;"));
}
public void testArgTypes() throws IncompatibleTypesException {
String[] types = TypeDesc.getArgumentTypes("([Ljava/lang/String;[[[ZZBCDSIJF)V");
String[] expected = new String[] {"[Ljava/lang/String;","[[[Z", D_BOOLEAN, D_BYTE,D_CHAR,
D_DOUBLE,D_SHORT,D_INT,D_LONG,D_FLOAT};
assertTrue(Arrays.equals(types, expected));
}
public void testMerge() throws IncompatibleTypesException {
// testCommonSuperTypes() has already checked many combinations of
// classes, arrays and interfaces. Handle null etc.
// Null + String => String
assertSame(D_STRING, TypeDesc.mergeType(D_NULL, D_STRING));
// Null + X == X (order of D_NULL flipped this time)
assertSame(D_ARRAY_DOUBLE, TypeDesc.mergeType("[D", D_NULL));
// primitive types should return the same
assertEquals(D_DOUBLE, TypeDesc.mergeType(D_DOUBLE, D_DOUBLE));
// Array + Object -> Array
assertSame(D_OBJECT, TypeDesc.mergeType("[I", D_OBJECT));
assertSame(D_OBJECT, TypeDesc.mergeType("[I", "[D"));
// common supertype of arrays
assertEquals("[Ljava/lang/reflect/AccessibleObject;",
TypeDesc.mergeType("[Ljava/lang/reflect/Field;","[Ljava/lang/reflect/Method;"));
// A inherits from B ==> merge(A[], B[]) = B[]
assertEquals("[Ljava/lang/reflect/AccessibleObject;",
TypeDesc.mergeType("[Ljava/lang/reflect/Method;", "[Ljava/lang/reflect/AccessibleObject;"));
// A inherits from B ==> merge(A[], B[]) = A[]
assertEquals("[Ljava/lang/reflect/AccessibleObject;",
TypeDesc.mergeType("[Ljava/lang/reflect/AccessibleObject;", "[Ljava/lang/reflect/Method;"));
}
public void testInvalidCombinations() {
assertInvalidCombo("I", D_OBJECT);
assertInvalidCombo(D_OBJECT, D_INT);
assertInvalidCombo("Meaningless", D_OBJECT);
}
private void assertInvalidCombo(String a, String b) {
try {
TypeDesc.mergeType(a,b);
fail("Types '" + a + "' and '" + b + "' aren't supposed to be compatible");
} catch (IncompatibleTypesException ignore) {
// Good. It is supposed to fail
}
}
}