1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.core; 18 19 import android.test.suitebuilder.annotation.MediumTest; 20 import android.test.suitebuilder.annotation.SmallTest; 21 import android.widget.Button; 22 import junit.framework.TestCase; 23 24 import java.lang.reflect.Constructor; 25 import java.lang.reflect.Field; 26 import java.lang.reflect.Method; 27 import java.lang.reflect.Modifier; 28 import java.util.HashSet; 29 import java.util.Set; 30 31 32 class ClassWithPrivateConstructor { 33 private ClassWithPrivateConstructor() { 34 } 35 } 36 37 public class ClassTest extends TestCase { 38 39 @SmallTest 40 public void testClass() throws Exception { 41 // Now, never mind the fact that most of this stuff has to work 42 // for the test harness to get this far.... 43 44 //System.out.println("Class.forName()"); 45 Class helloClass = Class.forName(ClassTest.class.getName()); 46 47 //System.out.println("Class.newInstance()"); 48 Object instance = helloClass.newInstance(); 49 assertNotNull(instance); 50 51 //System.out.println("Class.forName() nonexisting class"); 52 try { 53 Class.forName("this.class.DoesNotExist"); 54 fail("unexpected success"); 55 } catch (ClassNotFoundException ex) { 56 // expected 57 } 58 59 //System.out.println("Class.newInstance() private constructor"); 60 try { 61 Class.forName("android.core.ClassWithPrivateConstructor").newInstance(); 62 fail("unexpected success"); 63 } catch (IllegalAccessException ex) { 64 // this is expected 65 } 66 67 //System.out.println("Class.getDeclaredMethod()"); 68 69 Method method = helloClass.getDeclaredMethod("method", (Class[]) null); 70 71 method.invoke(new ClassTest(), (Object[]) null); 72 73 //System.out.println("Class.getDeclaredMethod() w/ args"); 74 75 method = helloClass.getDeclaredMethod("methodWithArgs", Object.class); 76 77 Object invokeArgs[] = new Object[1]; 78 invokeArgs[0] = "Hello"; 79 Object ret = method.invoke(new ClassTest(), invokeArgs); 80 assertEquals(ret, invokeArgs[0]); 81 82 //System.out.println("Class.getDeclaredMethod() -- private"); 83 84 method = helloClass.getDeclaredMethod("privateMethod", (Class[]) null); 85 86 method.invoke(new ClassTest(), (Object[]) null); 87 //fail("unexpected success"); 88 // TODO: I think this actually *should* succeed, because the 89 // call to the private method is being made from the same class. 90 // This needs to be replaced with a private call to a different 91 // class. 92 93 //System.out.println("Class.getSuperclass"); 94 Class objectClass = Class.forName("java.lang.Object"); 95 assertEquals(helloClass.getSuperclass().getSuperclass().getSuperclass(), objectClass); 96 97 //System.out.println("Class.isAssignableFrom"); 98 assertTrue(objectClass.isAssignableFrom(helloClass)); 99 assertFalse(helloClass.isAssignableFrom(objectClass)); 100 101 //System.out.println("Class.getConstructor"); 102 103 Constructor constructor = helloClass.getConstructor((Class[]) null); 104 assertNotNull(constructor); 105 106 //System.out.println("Class.getModifiers"); 107 108 assertTrue(Modifier.isPublic(helloClass.getModifiers())); 109 //System.out.println("Modifiers: " + Modifier.toString(helloClass.getModifiers())); 110 111 //System.out.println("Class.getMethod"); 112 113 helloClass.getMethod("method", (Class[]) null); 114 115 try { 116 Class[] argTypes = new Class[1]; 117 argTypes[0] = helloClass; 118 helloClass.getMethod("method", argTypes); 119 fail("unexpected success"); 120 } catch (NoSuchMethodException ex) { 121 // exception expected 122 } 123 124 // Test for public tracker issue 14 125 SimpleClass obj = new SimpleClass(); 126 Field field = obj.getClass().getDeclaredField("str"); 127 field.set(obj, null); 128 } 129 130 public class SimpleClass { 131 public String str; 132 } 133 134 public Object methodWithArgs(Object o) { 135 return o; 136 } 137 138 boolean methodInvoked; 139 140 public void method() { 141 methodInvoked = true; 142 } 143 144 boolean privateMethodInvoked; 145 146 public void privateMethod() { 147 privateMethodInvoked = true; 148 } 149 150 // Regression for 1018067: Class.getMethods() returns the same method over 151 // and over again from all base classes 152 @MediumTest 153 public void testClassGetMethodsNoDupes() { 154 Method[] methods = Button.class.getMethods(); 155 Set<String> set = new HashSet<String>(); 156 157 for (int i = 0; i < methods.length; i++) { 158 String signature = methods[i].toString(); 159 160 int par = signature.indexOf('('); 161 int dot = signature.lastIndexOf('.', par); 162 163 signature = signature.substring(dot + 1); 164 165 assertFalse("Duplicate " + signature, set.contains(signature)); 166 set.add(signature); 167 } 168 } 169 170 interface MyInterface { 171 void foo(); 172 } 173 174 interface MyOtherInterface extends MyInterface { 175 void bar(); 176 } 177 178 abstract class MyClass implements MyOtherInterface { 179 public void gabba() { 180 } 181 182 public void hey() { 183 } 184 } 185 186 // Check if we also reflect methods from interfaces 187 @SmallTest 188 public void testGetMethodsInterfaces() { 189 Method[] methods = MyInterface.class.getMethods(); 190 assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); 191 192 methods = MyOtherInterface.class.getMethods(); 193 assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); 194 assertTrue("Interface method must be there", hasMethod(methods, ".bar(")); 195 196 methods = MyClass.class.getMethods(); 197 assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); 198 assertTrue("Interface method must be there", hasMethod(methods, ".bar(")); 199 200 assertTrue("Declared method must be there", hasMethod(methods, ".gabba(")); 201 assertTrue("Declared method must be there", hasMethod(methods, ".hey(")); 202 203 assertTrue("Inherited method must be there", hasMethod(methods, ".toString(")); 204 } 205 206 private boolean hasMethod(Method[] methods, String signature) { 207 for (int i = 0; i < methods.length; i++) { 208 if (methods[i].toString().contains(signature)) { 209 return true; 210 } 211 } 212 213 return false; 214 } 215 216 // Test for Class.getPackage(); 217 @SmallTest 218 public void testClassGetPackage() { 219 assertNotNull("Package must be non-null", getClass().getPackage()); 220 assertEquals("Package must have expected name", "android.core", getClass().getPackage().getName()); 221 assertEquals("Package must have expected title", "Unknown", getClass().getPackage().getSpecificationTitle()); 222 223 Package p = java.lang.Object.class.getPackage(); 224 assertNotNull("Package must be non-null", p); 225 assertEquals("Package must have expected name", "java.lang", p.getName()); 226 assertSame("Package object must be same for each call", p, java.lang.Object.class.getPackage()); 227 } 228 229 // Regression test for #1123708: Problem with getCanonicalName(), 230 // getSimpleName(), and getPackage(). 231 // 232 // A couple of interesting cases need to be checked: Top-level classes, 233 // member classes, local classes, and anonymous classes. Also, boundary 234 // cases with '$' in the class names are checked, since the '$' is used 235 // as the separator between outer and inner class, so this might lead 236 // to problems (it did in the previous implementation). 237 // 238 // Caution: Adding local or anonymous classes elsewhere in this 239 // file might affect the test. 240 private class MemberClass { 241 // This space intentionally left blank. 242 } 243 244 private class Mi$o$oup { 245 // This space intentionally left blank. 246 } 247 248 @SmallTest 249 public void testVariousClassNames() { 250 Class<?> clazz = this.getClass(); 251 String pkg = (clazz.getPackage() == null ? "" : clazz.getPackage().getName() + "."); 252 253 // Simple, top-level class 254 255 assertEquals("Top-level class name must be correct", pkg + "ClassTest", clazz.getName()); 256 assertEquals("Top-level class simple name must be correct", "ClassTest", clazz.getSimpleName()); 257 assertEquals("Top-level class canonical name must be correct", pkg + "ClassTest", clazz.getCanonicalName()); 258 259 clazz = MemberClass.class; 260 261 assertEquals("Member class name must be correct", pkg + "ClassTest$MemberClass", clazz.getName()); 262 assertEquals("Member class simple name must be correct", "MemberClass", clazz.getSimpleName()); 263 assertEquals("Member class canonical name must be correct", pkg + "ClassTest.MemberClass", clazz.getCanonicalName()); 264 265 class LocalClass { 266 // This space intentionally left blank. 267 } 268 269 clazz = LocalClass.class; 270 271 assertEquals("Local class name must be correct", pkg + "ClassTest$1LocalClass", clazz.getName()); 272 assertEquals("Local class simple name must be correct", "LocalClass", clazz.getSimpleName()); 273 assertNull("Local class canonical name must be null", clazz.getCanonicalName()); 274 275 clazz = new Object() { }.getClass(); 276 277 assertEquals("Anonymous class name must be correct", pkg + "ClassTest$1", clazz.getName()); 278 assertEquals("Anonymous class simple name must be empty", "", clazz.getSimpleName()); 279 assertNull("Anonymous class canonical name must be null", clazz.getCanonicalName()); 280 281 // Weird special cases with dollar in name. 282 283 clazz = Mou$$aka.class; 284 285 assertEquals("Top-level class name must be correct", pkg + "Mou$$aka", clazz.getName()); 286 assertEquals("Top-level class simple name must be correct", "Mou$$aka", clazz.getSimpleName()); 287 assertEquals("Top-level class canonical name must be correct", pkg + "Mou$$aka", clazz.getCanonicalName()); 288 289 clazz = Mi$o$oup.class; 290 291 assertEquals("Member class name must be correct", pkg + "ClassTest$Mi$o$oup", clazz.getName()); 292 assertEquals("Member class simple name must be correct", "Mi$o$oup", clazz.getSimpleName()); 293 assertEquals("Member class canonical name must be correct", pkg + "ClassTest.Mi$o$oup", clazz.getCanonicalName()); 294 295 class Ma$hedPotatoe$ { 296 // This space intentionally left blank. 297 } 298 299 clazz = Ma$hedPotatoe$.class; 300 301 assertEquals("Member class name must be correct", pkg + "ClassTest$1Ma$hedPotatoe$", clazz.getName()); 302 assertEquals("Member class simple name must be correct", "Ma$hedPotatoe$", clazz.getSimpleName()); 303 assertNull("Member class canonical name must be null", clazz.getCanonicalName()); 304 } 305 306 @SmallTest 307 public void testLocalMemberClass() { 308 Class<?> clazz = this.getClass(); 309 310 assertFalse("Class must not be member", clazz.isMemberClass()); 311 assertFalse("Class must not be local", clazz.isLocalClass()); 312 313 clazz = MemberClass.class; 314 315 assertTrue("Class must be member", clazz.isMemberClass()); 316 assertFalse("Class must not be local", clazz.isLocalClass()); 317 318 class OtherLocalClass { 319 // This space intentionally left blank. 320 } 321 322 clazz = OtherLocalClass.class; 323 324 assertFalse("Class must not be member", clazz.isMemberClass()); 325 assertTrue("Class must be local", clazz.isLocalClass()); 326 327 clazz = new Object() { }.getClass(); 328 329 assertFalse("Class must not be member", clazz.isMemberClass()); 330 assertFalse("Class must not be local", clazz.isLocalClass()); 331 } 332 333 } 334 335 class Mou$$aka { 336 // This space intentionally left blank. 337 } 338