summaryrefslogtreecommitdiffstats
path: root/luni
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2011-12-13 12:51:28 -0500
committerJesse Wilson <jessewilson@google.com>2011-12-13 12:51:28 -0500
commita0ee76b0850774edeb0c67204070b89d117573bc (patch)
tree4fc399b5bc4bc27b703cfa0cb74292095259527a /luni
parent56de8e10ca290d46c26831d298d5cc7673a168ff (diff)
downloadlibcore-a0ee76b0850774edeb0c67204070b89d117573bc.zip
libcore-a0ee76b0850774edeb0c67204070b89d117573bc.tar.gz
libcore-a0ee76b0850774edeb0c67204070b89d117573bc.tar.bz2
Migrate some reflection tests from frameworks/base/tests/CoreTests
This found a problem where Method.toString() was returning "[C" for char arrays rather than "char[]". Sadly the RI doesn't use either getName() or getCanonicalName(). That problem was introduced with the fix for http://b/3073292 Bug: http://b/3073226 Change-Id: I7c2b0ebfc1718f7f0e8da55bdefd13a8e4032a45
Diffstat (limited to 'luni')
-rw-r--r--luni/src/main/java/java/lang/reflect/AccessibleObject.java26
-rw-r--r--luni/src/main/java/java/lang/reflect/Constructor.java2
-rw-r--r--luni/src/main/java/java/lang/reflect/Field.java4
-rw-r--r--luni/src/main/java/java/lang/reflect/Method.java2
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/MethodTest.java18
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/OldAndroidClassTest.java318
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java24
7 files changed, 375 insertions, 19 deletions
diff --git a/luni/src/main/java/java/lang/reflect/AccessibleObject.java b/luni/src/main/java/java/lang/reflect/AccessibleObject.java
index 6dde0c2..9c6b8c7 100644
--- a/luni/src/main/java/java/lang/reflect/AccessibleObject.java
+++ b/luni/src/main/java/java/lang/reflect/AccessibleObject.java
@@ -183,10 +183,10 @@ public class AccessibleObject implements AnnotatedElement {
StringBuilder result = new StringBuilder();
if (types.length != 0) {
- result.append(types[0].getName());
+ appendTypeName(result, types[0]);
for (int i = 1; i < types.length; i++) {
result.append(',');
- result.append(types[i].getName());
+ appendTypeName(result, types[i]);
}
}
@@ -228,23 +228,21 @@ public class AccessibleObject implements AnnotatedElement {
private static native Object[] getClassSignatureAnnotation(Class clazz);
/**
- * Appends the specified class name to the buffer. The class may represent
- * a simple type, a reference type or an array type.
- *
- * @param sb buffer
- * @param obj the class which name should be appended to the buffer
- *
- * @throws NullPointerException if any of the arguments is null
+ * Appends the best {@link #toString} name for {@code c} to {@code out}.
+ * This works around the fact that {@link Class#getName} is lousy for
+ * primitive arrays (it writes "[C" instead of "char[]") and {@link
+ * Class#getCanonicalName()} is lousy for nested classes (it uses a "."
+ * separator rather than a "$" separator).
*/
- void appendArrayType(StringBuilder sb, Class<?> obj) {
+ void appendTypeName(StringBuilder out, Class<?> c) {
int dimensions = 0;
- while (obj.isArray()) {
- obj = obj.getComponentType();
+ while (c.isArray()) {
+ c = c.getComponentType();
dimensions++;
}
- sb.append(obj.getName());
+ out.append(c.getName());
for (int d = 0; d < dimensions; d++) {
- sb.append("[]");
+ out.append("[]");
}
}
diff --git a/luni/src/main/java/java/lang/reflect/Constructor.java b/luni/src/main/java/java/lang/reflect/Constructor.java
index b03e28b..9a0e03c 100644
--- a/luni/src/main/java/java/lang/reflect/Constructor.java
+++ b/luni/src/main/java/java/lang/reflect/Constructor.java
@@ -142,7 +142,7 @@ public final class Constructor<T> extends AccessibleObject implements GenericDec
sb.append("> ");
}
// append constructor name
- appendArrayType(sb, getDeclaringClass());
+ appendTypeName(sb, getDeclaringClass());
// append parameters
sb.append('(');
appendArrayGenericType(sb,
diff --git a/luni/src/main/java/java/lang/reflect/Field.java b/luni/src/main/java/java/lang/reflect/Field.java
index 87c955a..0aacb11 100644
--- a/luni/src/main/java/java/lang/reflect/Field.java
+++ b/luni/src/main/java/java/lang/reflect/Field.java
@@ -869,9 +869,9 @@ public final class Field extends AccessibleObject implements Member {
if (result.length() != 0) {
result.append(' ');
}
- appendArrayType(result, type);
+ appendTypeName(result, type);
result.append(' ');
- result.append(declaringClass.getName());
+ appendTypeName(result, declaringClass);
result.append('.');
result.append(name);
return result.toString();
diff --git a/luni/src/main/java/java/lang/reflect/Method.java b/luni/src/main/java/java/lang/reflect/Method.java
index 8a9c0f1..044dbff 100644
--- a/luni/src/main/java/java/lang/reflect/Method.java
+++ b/luni/src/main/java/java/lang/reflect/Method.java
@@ -188,7 +188,7 @@ public final class Method extends AccessibleObject implements GenericDeclaration
appendGenericType(sb, Types.getType(genericReturnType));
sb.append(' ');
// append method name
- appendArrayType(sb, getDeclaringClass());
+ appendTypeName(sb, getDeclaringClass());
sb.append(".").append(getName());
// append parameters
sb.append('(');
diff --git a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
index a059d96..ef30eb8 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
@@ -197,6 +197,24 @@ public final class MethodTest extends TestCase {
assertEquals(anonymous.getClass(), method.getDeclaringClass());
}
+ // http://b/1045939
+ public void testMethodToString() throws Exception {
+ assertEquals("public final native void java.lang.Object.notify()",
+ Object.class.getMethod("notify", new Class[] { }).toString());
+ assertEquals("public java.lang.String java.lang.Object.toString()",
+ Object.class.getMethod("toString", new Class[] { }).toString());
+ assertEquals("public final native void java.lang.Object.wait(long,int)"
+ + " throws java.lang.InterruptedException",
+ Object.class.getMethod("wait", new Class[] { long.class, int.class }).toString());
+ assertEquals("public boolean java.lang.Object.equals(java.lang.Object)",
+ Object.class.getMethod("equals", new Class[] { Object.class }).toString());
+ assertEquals("public static java.lang.String java.lang.String.valueOf(char[])",
+ String.class.getMethod("valueOf", new Class[] { char[].class }).toString());
+ assertEquals( "public java.lang.Process java.lang.Runtime.exec(java.lang.String[])"
+ + " throws java.io.IOException",
+ Runtime.class.getMethod("exec", new Class[] { String[].class }).toString());
+ }
+
public static class MethodTestHelper {
public void m1() throws IndexOutOfBoundsException { }
public void m2(Object o) { }
diff --git a/luni/src/test/java/libcore/java/lang/reflect/OldAndroidClassTest.java b/luni/src/test/java/libcore/java/lang/reflect/OldAndroidClassTest.java
new file mode 100644
index 0000000..0a95bbf
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/OldAndroidClassTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.java.lang.reflect;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import junit.framework.TestCase;
+
+public final class OldAndroidClassTest extends TestCase {
+ private static final String packageName = "libcore.java.lang.reflect";
+
+ public void testNewInstance() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Object instance = helloClass.newInstance();
+ assertNotNull(instance);
+ }
+
+ public void testForName() throws Exception {
+ try {
+ Class.forName("this.class.DoesNotExist");
+ fail();
+ } catch (ClassNotFoundException expected) {
+ }
+ }
+
+ public void testNewInstancePrivateConstructor() throws Exception {
+ try {
+ Class.forName(packageName + ".ClassWithPrivateConstructor").newInstance();
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+ }
+
+ public void testGetDeclaredMethod() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Method method = helloClass.getDeclaredMethod("method", (Class[]) null);
+ method.invoke(new OldAndroidClassTest(), (Object[]) null);
+ }
+
+ public void testGetDeclaredMethodWithArgs() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Method method = helloClass.getDeclaredMethod("methodWithArgs", Object.class);
+
+ Object invokeArgs[] = new Object[1];
+ invokeArgs[0] = "Hello";
+ Object ret = method.invoke(new OldAndroidClassTest(), invokeArgs);
+ assertEquals(ret, invokeArgs[0]);
+ }
+
+ public void testGetDeclaredMethodPrivate() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Method method = helloClass.getDeclaredMethod("privateMethod", (Class[]) null);
+ method.invoke(new OldAndroidClassTest(), (Object[]) null);
+ }
+
+ public void testGetSuperclass() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Class objectClass = Class.forName("java.lang.Object");
+ assertEquals(helloClass.getSuperclass().getSuperclass().getSuperclass(), objectClass);
+ }
+
+ public void testIsAssignableFrom() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Class objectClass = Class.forName("java.lang.Object");
+ assertTrue(objectClass.isAssignableFrom(helloClass));
+ assertFalse(helloClass.isAssignableFrom(objectClass));
+ }
+
+ public void testGetConstructor() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Constructor constructor = helloClass.getConstructor((Class[]) null);
+ assertNotNull(constructor);
+ }
+
+ public void testGetModifiers() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ assertTrue(Modifier.isPublic(helloClass.getModifiers()));
+ }
+
+ public void testGetMethod() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ helloClass.getMethod("method", (Class[]) null);
+ try {
+ Class[] argTypes = new Class[1];
+ argTypes[0] = helloClass;
+ helloClass.getMethod("method", argTypes);
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=14
+ public void testFieldSet() throws Exception {
+ OldAndroidClassTest.SimpleClass obj = new OldAndroidClassTest.SimpleClass();
+ Field field = obj.getClass().getDeclaredField("str");
+ field.set(obj, null);
+ }
+
+ public class SimpleClass {
+ public String str;
+ }
+
+ public Object methodWithArgs(Object o) {
+ return o;
+ }
+
+ boolean methodInvoked;
+
+ public void method() {
+ methodInvoked = true;
+ }
+
+ boolean privateMethodInvoked;
+
+ public void privateMethod() {
+ privateMethodInvoked = true;
+ }
+
+ // Regression for 1018067: Class.getMethods() returns the same method over
+ // and over again from all base classes
+ public void testClassGetMethodsNoDupes() {
+ Method[] methods = ArrayList.class.getMethods();
+ Set<String> set = new HashSet<String>();
+
+ for (Method method : methods) {
+ String signature = method.toString();
+
+ int par = signature.indexOf('(');
+ int dot = signature.lastIndexOf('.', par);
+
+ signature = signature.substring(dot + 1);
+
+ assertFalse("Duplicate " + signature, set.contains(signature));
+ set.add(signature);
+ }
+ }
+
+ interface MyInterface {
+ void foo();
+ }
+
+ interface MyOtherInterface extends MyInterface {
+ void bar();
+ }
+
+ abstract class MyClass implements MyOtherInterface {
+ public void gabba() {
+ }
+
+ public void hey() {
+ }
+ }
+
+ // Check if we also reflect methods from interfaces
+ public void testGetMethodsInterfaces() {
+ Method[] methods = MyInterface.class.getMethods();
+ assertTrue(hasMethod(methods, ".foo("));
+
+ methods = MyOtherInterface.class.getMethods();
+ assertTrue(hasMethod(methods, ".foo("));
+ assertTrue(hasMethod(methods, ".bar("));
+
+ methods = MyClass.class.getMethods();
+ assertTrue(hasMethod(methods, ".foo("));
+ assertTrue(hasMethod(methods, ".bar("));
+
+ assertTrue(hasMethod(methods, ".gabba("));
+ assertTrue(hasMethod(methods, ".hey("));
+
+ assertTrue(hasMethod(methods, ".toString("));
+ }
+
+ private boolean hasMethod(Method[] methods, String signature) {
+ for (Method method : methods) {
+ if (method.toString().contains(signature)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Test for Class.getPackage();
+ public void testClassGetPackage() {
+ assertNotNull(getClass().getPackage());
+ assertEquals(packageName, getClass().getPackage().getName());
+ assertEquals("Unknown", getClass().getPackage().getSpecificationTitle());
+
+ Package p = Object.class.getPackage();
+ assertNotNull(p);
+ assertEquals("java.lang", p.getName());
+ assertSame(p, Object.class.getPackage());
+ }
+
+ // Regression test for #1123708: Problem with getCanonicalName(),
+ // getSimpleName(), and getPackage().
+ //
+ // A couple of interesting cases need to be checked: Top-level classes,
+ // member classes, local classes, and anonymous classes. Also, boundary
+ // cases with '$' in the class names are checked, since the '$' is used
+ // as the separator between outer and inner class, so this might lead
+ // to problems (it did in the previous implementation).
+ //
+ // Caution: Adding local or anonymous classes elsewhere in this
+ // file might affect the test.
+ private class MemberClass {
+ }
+
+ private class Mi$o$oup {
+ }
+
+ public void testVariousClassNames() {
+ Class<?> clazz = this.getClass();
+ String pkg = (clazz.getPackage() == null ? "" : clazz.getPackage().getName() + ".");
+
+ // Simple, top-level class
+
+ assertEquals(pkg + "OldAndroidClassTest", clazz.getName());
+ assertEquals("OldAndroidClassTest", clazz.getSimpleName());
+ assertEquals(pkg + "OldAndroidClassTest", clazz.getCanonicalName());
+
+ clazz = MemberClass.class;
+
+ assertEquals(pkg + "OldAndroidClassTest$MemberClass", clazz.getName());
+ assertEquals("MemberClass", clazz.getSimpleName());
+ assertEquals(pkg + "OldAndroidClassTest.MemberClass", clazz.getCanonicalName());
+
+ class LocalClass {
+ // This space intentionally left blank.
+ }
+
+ clazz = LocalClass.class;
+
+ assertEquals(pkg + "OldAndroidClassTest$1LocalClass", clazz.getName());
+ assertEquals("LocalClass", clazz.getSimpleName());
+ assertNull(clazz.getCanonicalName());
+
+ clazz = new Object() { }.getClass();
+
+ assertEquals(pkg + "OldAndroidClassTest$1", clazz.getName());
+ assertEquals("", clazz.getSimpleName());
+ assertNull(clazz.getCanonicalName());
+
+ // Weird special cases with dollar in name.
+
+ clazz = Mou$$aka.class;
+
+ assertEquals(pkg + "Mou$$aka", clazz.getName());
+ assertEquals("Mou$$aka", clazz.getSimpleName());
+ assertEquals(pkg + "Mou$$aka", clazz.getCanonicalName());
+
+ clazz = Mi$o$oup.class;
+
+ assertEquals(pkg + "OldAndroidClassTest$Mi$o$oup", clazz.getName());
+ assertEquals("Mi$o$oup", clazz.getSimpleName());
+ assertEquals(pkg + "OldAndroidClassTest.Mi$o$oup", clazz.getCanonicalName());
+
+ class Ma$hedPotatoe$ {
+ }
+
+ clazz = Ma$hedPotatoe$.class;
+
+ assertEquals(pkg + "OldAndroidClassTest$1Ma$hedPotatoe$", clazz.getName());
+ assertEquals("Ma$hedPotatoe$", clazz.getSimpleName());
+ assertNull(clazz.getCanonicalName());
+ }
+
+ public void testLocalMemberClass() {
+ Class<?> clazz = this.getClass();
+
+ assertFalse(clazz.isMemberClass());
+ assertFalse(clazz.isLocalClass());
+
+ clazz = MemberClass.class;
+
+ assertTrue(clazz.isMemberClass());
+ assertFalse(clazz.isLocalClass());
+
+ class OtherLocalClass {
+ }
+
+ clazz = OtherLocalClass.class;
+
+ assertFalse(clazz.isMemberClass());
+ assertTrue(clazz.isLocalClass());
+
+ clazz = new Object() { }.getClass();
+
+ assertFalse(clazz.isMemberClass());
+ assertFalse(clazz.isLocalClass());
+ }
+}
+
+class ClassWithPrivateConstructor {
+ private ClassWithPrivateConstructor() {
+ }
+}
+
+class Mou$$aka {
+}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java b/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java
index 3b092e5..8d7546a 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java
@@ -32,7 +32,6 @@ import java.util.Set;
import junit.framework.TestCase;
public final class ReflectionTest extends TestCase {
-
String classA = "libcore.java.lang.reflect.ReflectionTest$A";
String classB = "libcore.java.lang.reflect.ReflectionTest$B";
String classC = "libcore.java.lang.reflect.ReflectionTest$C";
@@ -45,6 +44,29 @@ public final class ReflectionTest extends TestCase {
AList.class.getGenericSuperclass().toString());
}
+ public void testClassGetName() {
+ assertEquals("int", int.class.getName());
+ assertEquals("[I", int[].class.getName());
+ assertEquals("java.lang.String", String.class.getName());
+ assertEquals("[Ljava.lang.String;", String[].class.getName());
+ assertEquals("libcore.java.lang.reflect.ReflectionTest", getClass().getName());
+ assertEquals(getClass().getName() + "$A", A.class.getName());
+ assertEquals(getClass().getName() + "$B", B.class.getName());
+ assertEquals(getClass().getName() + "$DefinesMember", DefinesMember.class.getName());
+ }
+
+ public void testClassGetCanonicalName() {
+ assertEquals("int", int.class.getCanonicalName());
+ assertEquals("int[]", int[].class.getCanonicalName());
+ assertEquals("java.lang.String", String.class.getCanonicalName());
+ assertEquals("java.lang.String[]", String[].class.getCanonicalName());
+ assertEquals("libcore.java.lang.reflect.ReflectionTest", getClass().getCanonicalName());
+ assertEquals(getClass().getName() + ".A", A.class.getCanonicalName());
+ assertEquals(getClass().getName() + ".B", B.class.getCanonicalName());
+ assertEquals(getClass().getName() + ".DefinesMember",
+ DefinesMember.class.getCanonicalName());
+ }
+
public void testFieldToString() throws Exception {
Field fieldOne = C.class.getDeclaredField("fieldOne");
String fieldOneRaw = "public static " + classA + " " + classC + ".fieldOne";