changeset 9806:21b8cd853b2b

cleaned up api.meta tests (GRAAL-59)
author Doug Simon <doug.simon@oracle.com>
date Thu, 23 May 2013 18:14:59 +0200
parents 53bc0557baaf
children d552919fbb05
files graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/MethodUniverse.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestBytecodeDisassemblerProvider.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaMethod.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaType.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TypeUniverse.java
diffstat 8 files changed, 393 insertions(+), 188 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/MethodUniverse.java	Thu May 23 18:14:59 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta.test;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Context for method related api.meta tests.
+ */
+public class MethodUniverse extends TypeUniverse {
+
+    public final Map<Method, ResolvedJavaMethod> methods = new HashMap<>();
+    public final Map<Constructor, ResolvedJavaMethod> constructors = new HashMap<>();
+
+    public MethodUniverse() {
+        for (Class c : classes) {
+            for (Method m : c.getDeclaredMethods()) {
+                ResolvedJavaMethod method = runtime.lookupJavaMethod(m);
+                methods.put(m, method);
+            }
+            for (Constructor m : c.getDeclaredConstructors()) {
+                constructors.put(m, runtime.lookupJavaConstructor(m));
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestBytecodeDisassemblerProvider.java	Thu May 23 18:13:32 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestBytecodeDisassemblerProvider.java	Thu May 23 18:14:59 2013 +0200
@@ -30,7 +30,7 @@
 /**
  * Tests for {@link BytecodeDisassemblerProvider}.
  */
-public class TestBytecodeDisassemblerProvider {
+public class TestBytecodeDisassemblerProvider extends MethodUniverse {
 
     public TestBytecodeDisassemblerProvider() {
     }
@@ -43,7 +43,7 @@
         BytecodeDisassemblerProvider dis = Graal.getRuntime().getCapability(BytecodeDisassemblerProvider.class);
         if (dis != null) {
             int count = 0;
-            for (ResolvedJavaMethod m : TestJavaMethod.methods.values()) {
+            for (ResolvedJavaMethod m : methods.values()) {
                 String disasm1 = dis.disassemble(m);
                 String disasm2 = dis.disassemble(m);
                 if (disasm1 == null) {
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaMethod.java	Thu May 23 18:13:32 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaMethod.java	Thu May 23 18:14:59 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.meta.test;
 
-import static com.oracle.graal.api.meta.test.TestMetaAccessProvider.*;
 import static org.junit.Assert.*;
 
 import java.lang.reflect.*;
@@ -35,24 +34,7 @@
 /**
  * Tests for {@link JavaMethod}.
  */
-public class TestJavaMethod {
-
-    public TestJavaMethod() {
-    }
-
-    public static final Map<Method, ResolvedJavaMethod> methods = new HashMap<>();
-    public static final Map<Constructor, ResolvedJavaMethod> constructors = new HashMap<>();
-    static {
-        for (Class c : classes) {
-            for (Method m : c.getDeclaredMethods()) {
-                ResolvedJavaMethod method = runtime.lookupJavaMethod(m);
-                methods.put(m, method);
-            }
-            for (Constructor m : c.getDeclaredConstructors()) {
-                constructors.put(m, runtime.lookupJavaConstructor(m));
-            }
-        }
-    }
+public class TestJavaMethod extends MethodUniverse {
 
     @Test
     public void getNameTest() {
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaType.java	Thu May 23 18:13:32 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaType.java	Thu May 23 18:14:59 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.meta.test;
 
-import static com.oracle.graal.api.meta.test.TestMetaAccessProvider.*;
 import static org.junit.Assert.*;
 
 import org.junit.*;
@@ -32,7 +31,7 @@
 /**
  * Tests for {@link JavaType}.
  */
-public class TestJavaType {
+public class TestJavaType extends TypeUniverse {
 
     public TestJavaType() {
     }
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Thu May 23 18:13:32 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java	Thu May 23 18:14:59 2013 +0200
@@ -25,125 +25,16 @@
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static org.junit.Assert.*;
 
-import java.io.*;
 import java.lang.reflect.*;
-import java.util.*;
 
 import org.junit.*;
 
-import sun.misc.Unsafe;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.runtime.*;
 
 /**
  * Tests for {@link MetaAccessProvider}.
  */
-public class TestMetaAccessProvider {
-
-    public static final Unsafe unsafe;
-    static {
-        Unsafe theUnsafe = null;
-        try {
-            theUnsafe = Unsafe.getUnsafe();
-        } catch (Exception e) {
-            try {
-                Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafeField.setAccessible(true);
-                theUnsafe = (Unsafe) theUnsafeField.get(null);
-            } catch (Exception e1) {
-                throw (InternalError) new InternalError("unable to initialize unsafe").initCause(e1);
-            }
-        }
-        unsafe = theUnsafe;
-    }
-
-    public TestMetaAccessProvider() {
-    }
-
-    public static final MetaAccessProvider runtime = Graal.getRequiredCapability(MetaAccessProvider.class);
-    public static final Collection<Class<?>> classes = new HashSet<>();
-    public static final Map<Class<?>, Class<?>> arrayClasses = new HashMap<>();
-
-    public static synchronized Class<?> getArrayClass(Class componentType) {
-        Class<?> arrayClass = arrayClasses.get(componentType);
-        if (arrayClass == null) {
-            arrayClass = Array.newInstance(componentType, 0).getClass();
-            arrayClasses.put(componentType, arrayClass);
-        }
-        return arrayClass;
-    }
-
-    public static int dimensions(Class c) {
-        if (c.getComponentType() != null) {
-            return 1 + dimensions(c.getComponentType());
-        }
-        return 0;
-    }
-
-    private static void addClass(Class c) {
-        if (classes.add(c)) {
-            if (c.getSuperclass() != null) {
-                addClass(c.getSuperclass());
-            }
-            for (Class sc : c.getInterfaces()) {
-                addClass(sc);
-            }
-            for (Class dc : c.getDeclaredClasses()) {
-                addClass(dc);
-            }
-            for (Method m : c.getDeclaredMethods()) {
-                addClass(m.getReturnType());
-                for (Class p : m.getParameterTypes()) {
-                    addClass(p);
-                }
-            }
-
-            if (c != void.class && dimensions(c) < 2) {
-                Class<?> arrayClass = Array.newInstance(c, 0).getClass();
-                arrayClasses.put(c, arrayClass);
-                addClass(arrayClass);
-            }
-        }
-    }
-
-    static {
-        Class[] initialClasses = {void.class, boolean.class, byte.class, short.class, char.class, int.class, float.class, long.class, double.class, Object.class, Class.class, ClassLoader.class,
-                        String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class, HashMap.class,
-                        LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class};
-        for (Class c : initialClasses) {
-            addClass(c);
-        }
-    }
-
-    public static final List<Constant> constants = new ArrayList<>();
-    static {
-        for (Field f : Constant.class.getDeclaredFields()) {
-            int mods = f.getModifiers();
-            if (f.getType() == Constant.class && Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
-                try {
-                    Constant c = (Constant) f.get(null);
-                    if (c != null) {
-                        constants.add(c);
-                    }
-                } catch (Exception e) {
-                }
-            }
-        }
-        for (Class c : classes) {
-            if (c != void.class && !c.isArray()) {
-                constants.add(Constant.forObject(Array.newInstance(c, 42)));
-            }
-        }
-        constants.add(Constant.forObject(new ArrayList<>()));
-        constants.add(Constant.forObject(new IdentityHashMap<>()));
-        constants.add(Constant.forObject(new LinkedHashMap<>()));
-        constants.add(Constant.forObject(new TreeMap<>()));
-        constants.add(Constant.forObject(new ArrayDeque<>()));
-        constants.add(Constant.forObject(new LinkedList<>()));
-        constants.add(Constant.forObject("a string"));
-        constants.add(Constant.forObject(42));
-    }
+public class TestMetaAccessProvider extends TypeUniverse {
 
     @Test
     public void lookupJavaTypeTest() {
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Thu May 23 18:13:32 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Thu May 23 18:14:59 2013 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.api.meta.test;
 
-import static com.oracle.graal.api.meta.test.TestJavaMethod.*;
 import static java.lang.reflect.Modifier.*;
 import static org.junit.Assert.*;
 
+import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.util.*;
 
@@ -36,7 +36,7 @@
 /**
  * Tests for {@link ResolvedJavaMethod}.
  */
-public class TestResolvedJavaMethod {
+public class TestResolvedJavaMethod extends MethodUniverse {
 
     public TestResolvedJavaMethod() {
     }
@@ -94,21 +94,6 @@
     }
 
     @Test
-    public void getCompilationComplexityTest() {
-        // TODO
-    }
-
-    @Test
-    public void getMaxLocalsTest() {
-        // TODO
-    }
-
-    @Test
-    public void getMaxStackSizeTest() {
-        // TODO
-    }
-
-    @Test
     public void getModifiersTest() {
         for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
             ResolvedJavaMethod m = e.getValue();
@@ -148,52 +133,167 @@
 
     @Test
     public void canBeStaticallyBoundTest() {
-        // TODO
+        for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey().getModifiers()));
+        }
+        for (Map.Entry<Constructor, ResolvedJavaMethod> e : constructors.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey().getModifiers()));
+        }
     }
 
-    @Test
-    public void getExceptionHandlersTest() {
-        // TODO
+    private static boolean canBeStaticallyBound(int modifiers) {
+        return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers)) && !Modifier.isAbstract(modifiers);
+    }
+
+    private static String methodWithExceptionHandlers(String p1, Object o2) {
+        try {
+            return p1.substring(100) + o2.toString();
+        } catch (IndexOutOfBoundsException e) {
+            e.printStackTrace();
+        } catch (NullPointerException e) {
+            e.printStackTrace();
+        } catch (RuntimeException e) {
+            e.printStackTrace();
+        }
+        return null;
     }
 
     @Test
-    public void asStackTraceElementTest() {
-        // TODO
+    public void getExceptionHandlersTest() throws NoSuchMethodException {
+        ResolvedJavaMethod method = runtime.lookupJavaMethod(getClass().getDeclaredMethod("methodWithExceptionHandlers", String.class, Object.class));
+        ExceptionHandler[] handlers = method.getExceptionHandlers();
+        assertNotNull(handlers);
+        assertEquals(handlers.length, 3);
+        handlers[0].getCatchType().equals(runtime.lookupJavaType(IndexOutOfBoundsException.class));
+        handlers[1].getCatchType().equals(runtime.lookupJavaType(NullPointerException.class));
+        handlers[2].getCatchType().equals(runtime.lookupJavaType(RuntimeException.class));
+    }
+
+    private static String nullPointerExceptionOnFirstLine(Object o, String ignored) {
+        return o.toString() + ignored;
     }
 
     @Test
-    public void getProfilingInfoTest() {
-        // TODO
-    }
-
-    @Test
-    public void getCompilerStorageTest() {
-        // TODO
+    public void asStackTraceElementTest() throws NoSuchMethodException {
+        try {
+            nullPointerExceptionOnFirstLine(null, "ignored");
+            Assert.fail("should not reach here");
+        } catch (NullPointerException e) {
+            StackTraceElement expected = e.getStackTrace()[0];
+            ResolvedJavaMethod method = runtime.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class));
+            StackTraceElement actual = method.asStackTraceElement(0);
+            assertEquals(expected, actual);
+        }
     }
 
     @Test
     public void getConstantPoolTest() {
-        // TODO
+        for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            ConstantPool cp = m.getConstantPool();
+            assertTrue(cp.length() > 0);
+        }
+    }
+
+    @Test(timeout = 1000L)
+    public void getAnnotationTest() throws NoSuchMethodException {
+        ResolvedJavaMethod method = runtime.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationTest"));
+        Test annotation = method.getAnnotation(Test.class);
+        assertNotNull(annotation);
+        assertEquals(1000L, annotation.timeout());
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.PARAMETER)
+    @interface NonNull {
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.PARAMETER)
+    @interface Special {
+    }
+
+    private static native void methodWithAnnotatedParameters(@NonNull HashMap<String, String> p1, @Special @NonNull Class<? extends Annotation> p2);
+
+    @Test
+    public void getParameterAnnotationsTest() throws NoSuchMethodException {
+        ResolvedJavaMethod method = runtime.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class));
+        Annotation[][] annotations = method.getParameterAnnotations();
+        assertEquals(2, annotations.length);
+        assertEquals(1, annotations[0].length);
+        assertEquals(NonNull.class, annotations[0][0].annotationType());
+        assertEquals(2, annotations[1].length);
+        assertEquals(Special.class, annotations[1][0].annotationType());
+        assertEquals(NonNull.class, annotations[1][1].annotationType());
     }
 
     @Test
-    public void getAnnotationTest() {
-        // TODO
+    public void getGenericParameterTypesTest() throws NoSuchMethodException {
+        ResolvedJavaMethod method = runtime.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class));
+        Type[] genericParameterTypes = method.getGenericParameterTypes();
+        assertEquals(2, genericParameterTypes.length);
+        assertEquals("java.util.HashMap<java.lang.String, java.lang.String>", genericParameterTypes[0].toString());
+        assertEquals("java.lang.Class<? extends java.lang.annotation.Annotation>", genericParameterTypes[1].toString());
     }
 
     @Test
-    public void getParameterAnnotationsTest() {
-        // TODO
-    }
-
-    @Test
-    public void getGenericParameterTypesTest() {
-        // TODO
+    public void getMaxLocalsTest() throws NoSuchMethodException {
+        ResolvedJavaMethod method1 = runtime.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class));
+        ResolvedJavaMethod method2 = runtime.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class));
+        assertEquals(0, method1.getMaxLocals());
+        assertEquals(2, method2.getMaxLocals());
 
     }
 
     @Test
-    public void canBeInlinedTest() {
-        // TODO
+    public void getMaxStackSizeTest() throws NoSuchMethodException {
+        ResolvedJavaMethod method1 = runtime.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class));
+        ResolvedJavaMethod method2 = runtime.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class));
+        assertEquals(0, method1.getMaxStackSize());
+        assertEquals(3, method2.getMaxStackSize());
+    }
+
+    private Method findTestMethod(Method apiMethod) {
+        String testName = apiMethod.getName() + "Test";
+        for (Method m : getClass().getDeclaredMethods()) {
+            if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) {
+                return m;
+            }
+        }
+        return null;
+    }
+
+    // @formatter:off
+    private static final String[] untestedApiMethods = {
+        "invoke",
+        "newInstance",
+        "getDeclaringClass",
+        "getEncoding",
+        "getProfilingInfo",
+        "reprofile",
+        "getCompilerStorage",
+        "canBeInlined",
+        "getLineNumberTable",
+        "getLocalVariableTable",
+        "isInVirtualMethodTable"
+    };
+    // @formatter:on
+
+    /**
+     * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written
+     * for them or are added to {@link #untestedApiMethods}.
+     */
+    @Test
+    public void testCoverage() {
+        Set<String> known = new HashSet<>(Arrays.asList(untestedApiMethods));
+        for (Method m : ResolvedJavaMethod.class.getDeclaredMethods()) {
+            if (findTestMethod(m) == null) {
+                assertTrue("test missing for " + m, known.contains(m.getName()));
+            } else {
+                assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName()));
+            }
+        }
     }
 }
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Thu May 23 18:13:32 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Thu May 23 18:14:59 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.meta.test;
 
-import static com.oracle.graal.api.meta.test.TestMetaAccessProvider.*;
 import static java.lang.Integer.*;
 import static java.lang.reflect.Modifier.*;
 import static org.junit.Assert.*;
@@ -41,7 +40,7 @@
 /**
  * Tests for {@link ResolvedJavaType}.
  */
-public class TestResolvedJavaType {
+public class TestResolvedJavaType extends TypeUniverse {
 
     public TestResolvedJavaType() {
     }
@@ -83,7 +82,7 @@
     }
 
     @Test
-    public void isArrayClassTest() {
+    public void isArrayTest() {
         for (Class c : classes) {
             ResolvedJavaType type = runtime.lookupJavaType(c);
             boolean expected = c.isArray();
@@ -103,7 +102,7 @@
     }
 
     @Test
-    public void isAssignableToTest() {
+    public void isAssignableFromTest() {
         Class[] all = classes.toArray(new Class[classes.size()]);
         for (int i = 0; i < all.length; i++) {
             Class<?> c1 = all[i];
@@ -194,7 +193,7 @@
         }
     }
 
-    public static Class getSupertype(Class c) {
+    public Class getSupertype(Class c) {
         assert !c.isPrimitive();
         if (c.isArray()) {
             Class componentType = c.getComponentType();
@@ -209,7 +208,7 @@
         return c.getSuperclass();
     }
 
-    public static Class findLeastCommonAncestor(Class<?> c1Initial, Class<?> c2Initial) {
+    public Class findLeastCommonAncestor(Class<?> c1Initial, Class<?> c2Initial) {
         if (c1Initial.isPrimitive() || c2Initial.isPrimitive()) {
             return null;
         } else {
@@ -270,7 +269,7 @@
     abstract static class Abstract4 extends Concrete3 {
     }
 
-    static void checkConcreteSubtype(ResolvedJavaType type, Class expected) {
+    void checkConcreteSubtype(ResolvedJavaType type, Class expected) {
         ResolvedJavaType subtype = type.findUniqueConcreteSubtype();
         if (subtype == null) {
             // findUniqueConcreteSubtype() is conservative
@@ -455,8 +454,10 @@
     }
 
     @Test
-    public void findUniqueConcreteMethodTest() {
-        // TODO
+    public void findUniqueConcreteMethodTest() throws NoSuchMethodException {
+        ResolvedJavaMethod thisMethod = runtime.lookupJavaMethod(getClass().getDeclaredMethod("findUniqueConcreteMethodTest"));
+        ResolvedJavaMethod ucm = runtime.lookupJavaType(getClass()).findUniqueConcreteMethod(thisMethod);
+        assertEquals(thisMethod, ucm);
     }
 
     public static Set<Field> getInstanceFields(Class c, boolean includeSuperclasses) {
@@ -475,12 +476,12 @@
         return result;
     }
 
-    public static boolean fieldsEqual(Field f, ResolvedJavaField rjf) {
+    public boolean fieldsEqual(Field f, ResolvedJavaField rjf) {
         return rjf.getDeclaringClass().equals(runtime.lookupJavaType(f.getDeclaringClass())) && rjf.getName().equals(f.getName()) &&
                         rjf.getType().resolve(rjf.getDeclaringClass()).equals(runtime.lookupJavaType(f.getType()));
     }
 
-    public static ResolvedJavaField lookupField(ResolvedJavaField[] fields, Field key) {
+    public ResolvedJavaField lookupField(ResolvedJavaField[] fields, Field key) {
         for (ResolvedJavaField rf : fields) {
             if (fieldsEqual(key, rf)) {
                 assert (fieldModifiers() & key.getModifiers()) == rf.getModifiers() : key + ": " + toHexString(key.getModifiers()) + " != " + toHexString(rf.getModifiers());
@@ -490,7 +491,7 @@
         return null;
     }
 
-    public static Field lookupField(Set<Field> fields, ResolvedJavaField key) {
+    public Field lookupField(Set<Field> fields, ResolvedJavaField key) {
         for (Field f : fields) {
             if (fieldsEqual(f, key)) {
                 assert key.getModifiers() == (fieldModifiers() & f.getModifiers()) : key + ": " + toHexString(key.getModifiers()) + " != " + toHexString(f.getModifiers());
@@ -500,7 +501,7 @@
         return null;
     }
 
-    private static boolean isHiddenFromReflection(ResolvedJavaField f) {
+    private boolean isHiddenFromReflection(ResolvedJavaField f) {
         if (f.getDeclaringClass().equals(runtime.lookupJavaType(Throwable.class)) && f.getName().equals("backtrace")) {
             return true;
         }
@@ -574,4 +575,50 @@
             }
         }
     }
+
+    private Method findTestMethod(Method apiMethod) {
+        String testName = apiMethod.getName() + "Test";
+        for (Method m : getClass().getDeclaredMethods()) {
+            if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) {
+                return m;
+            }
+        }
+        return null;
+    }
+
+    // @formatter:off
+    private static final String[] untestedApiMethods = {
+        "initialize",
+        "isPrimitive",
+        "newArray",
+        "getDeclaredMethods",
+        "getDeclaredConstructors",
+        "isInitialized",
+        "getEncoding",
+        "hasFinalizableSubclass",
+        "hasFinalizer",
+        "getSourceFileName",
+        "getClassFilePath",
+        "isLocal",
+        "isMember",
+        "getEnclosingType"
+    };
+    // @formatter:on
+
+    /**
+     * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written
+     * for them or are added to {@link #untestedApiMethods}.
+     */
+    @Test
+    public void testCoverage() {
+        Set<String> known = new HashSet<>(Arrays.asList(untestedApiMethods));
+        for (Method m : ResolvedJavaType.class.getDeclaredMethods()) {
+            if (findTestMethod(m) == null) {
+                assertTrue("test missing for " + m, known.contains(m.getName()));
+            } else {
+                assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName()));
+            }
+        }
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TypeUniverse.java	Thu May 23 18:14:59 2013 +0200
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta.test;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Queue;
+
+import org.junit.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+
+/**
+ * Context for type related api.meta tests.
+ */
+public class TypeUniverse {
+
+    public final Unsafe unsafe;
+    public final MetaAccessProvider runtime = Graal.getRequiredCapability(MetaAccessProvider.class);
+    public final Collection<Class<?>> classes = new HashSet<>();
+    public final Map<Class<?>, Class<?>> arrayClasses = new HashMap<>();
+    public final List<Constant> constants = new ArrayList<>();
+
+    public TypeUniverse() {
+        Unsafe theUnsafe = null;
+        try {
+            theUnsafe = Unsafe.getUnsafe();
+        } catch (Exception e) {
+            try {
+                Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafeField.setAccessible(true);
+                theUnsafe = (Unsafe) theUnsafeField.get(null);
+            } catch (Exception e1) {
+                throw (InternalError) new InternalError("unable to initialize unsafe").initCause(e1);
+            }
+        }
+        unsafe = theUnsafe;
+
+        Class[] initialClasses = {void.class, boolean.class, byte.class, short.class, char.class, int.class, float.class, long.class, double.class, Object.class, Class.class, ClassLoader.class,
+                        String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class, HashMap.class,
+                        LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class};
+        for (Class c : initialClasses) {
+            addClass(c);
+        }
+        for (Field f : Constant.class.getDeclaredFields()) {
+            int mods = f.getModifiers();
+            if (f.getType() == Constant.class && Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
+                try {
+                    Constant c = (Constant) f.get(null);
+                    if (c != null) {
+                        constants.add(c);
+                    }
+                } catch (Exception e) {
+                }
+            }
+        }
+        for (Class c : classes) {
+            if (c != void.class && !c.isArray()) {
+                constants.add(Constant.forObject(Array.newInstance(c, 42)));
+            }
+        }
+        constants.add(Constant.forObject(new ArrayList<>()));
+        constants.add(Constant.forObject(new IdentityHashMap<>()));
+        constants.add(Constant.forObject(new LinkedHashMap<>()));
+        constants.add(Constant.forObject(new TreeMap<>()));
+        constants.add(Constant.forObject(new ArrayDeque<>()));
+        constants.add(Constant.forObject(new LinkedList<>()));
+        constants.add(Constant.forObject("a string"));
+        constants.add(Constant.forObject(42));
+    }
+
+    public synchronized Class<?> getArrayClass(Class componentType) {
+        Class<?> arrayClass = arrayClasses.get(componentType);
+        if (arrayClass == null) {
+            arrayClass = Array.newInstance(componentType, 0).getClass();
+            arrayClasses.put(componentType, arrayClass);
+        }
+        return arrayClass;
+    }
+
+    public static int dimensions(Class c) {
+        if (c.getComponentType() != null) {
+            return 1 + dimensions(c.getComponentType());
+        }
+        return 0;
+    }
+
+    private void addClass(Class c) {
+        if (classes.add(c)) {
+            if (c.getSuperclass() != null) {
+                addClass(c.getSuperclass());
+            }
+            for (Class sc : c.getInterfaces()) {
+                addClass(sc);
+            }
+            for (Class dc : c.getDeclaredClasses()) {
+                addClass(dc);
+            }
+            for (Method m : c.getDeclaredMethods()) {
+                addClass(m.getReturnType());
+                for (Class p : m.getParameterTypes()) {
+                    addClass(p);
+                }
+            }
+
+            if (c != void.class && dimensions(c) < 2) {
+                Class<?> arrayClass = Array.newInstance(c, 0).getClass();
+                arrayClasses.put(c, arrayClass);
+                addClass(arrayClass);
+            }
+        }
+    }
+}