DexClassLoaderTest.java revision 6bfc6b199a14f8eb893426b7d48bcf06a3a32015
1/* 2 * Copyright (C) 2011 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 17package dalvik.system; 18 19import java.lang.reflect.InvocationTargetException; 20import java.lang.reflect.Method; 21import java.io.File; 22import java.io.FileOutputStream; 23import java.io.IOException; 24import java.io.InputStream; 25import java.io.UnsupportedEncodingException; 26import libcore.base.Streams; 27import junit.framework.TestCase; 28 29/** 30 * Tests for the class {@link DexClassLoader}. 31 */ 32public class DexClassLoaderTest extends TestCase { 33 private static final File TMP_DIR = 34 new File(System.getProperty("java.io.tmpdir"), "loading-test"); 35 private static final String PACKAGE_PATH = "dalvik/system/"; 36 private static final String JAR_NAME = "loading-test.jar"; 37 private static final String DEX_NAME = "loading-test.dex"; 38 private static final String JAR2_NAME = "loading-test2.jar"; 39 private static final String DEX2_NAME = "loading-test2.dex"; 40 private static final File JAR_FILE = new File(TMP_DIR, JAR_NAME); 41 private static final File DEX_FILE = new File(TMP_DIR, DEX_NAME); 42 private static final File JAR2_FILE = new File(TMP_DIR, JAR2_NAME); 43 private static final File DEX2_FILE = new File(TMP_DIR, DEX2_NAME); 44 45 private static enum Configuration { 46 /** just one classpath element, a raw dex file */ 47 ONE_DEX, 48 49 /** just one classpath element, a jar file */ 50 ONE_JAR, 51 52 /** two classpath elements, both raw dex files */ 53 TWO_DEX, 54 55 /** two classpath elements, both jar files */ 56 TWO_JAR; 57 } 58 59 protected void setUp() throws IOException { 60 TMP_DIR.mkdirs(); 61 62 ClassLoader cl = DexClassLoaderTest.class.getClassLoader(); 63 copyResource(cl, JAR_NAME, JAR_FILE); 64 copyResource(cl, DEX_NAME, DEX_FILE); 65 copyResource(cl, JAR2_NAME, JAR2_FILE); 66 copyResource(cl, DEX2_NAME, DEX2_FILE); 67 } 68 69 /** 70 * Copy a resource in the package directory to the indicated file. 71 */ 72 private static void copyResource(ClassLoader loader, String resourceName, 73 File destination) throws IOException { 74 InputStream in = 75 loader.getResourceAsStream(PACKAGE_PATH + resourceName); 76 FileOutputStream out = new FileOutputStream(destination); 77 Streams.copy(in, out); 78 in.close(); 79 out.close(); 80 } 81 82 /** 83 * Helper to construct an instance to test. 84 * 85 * @param config how to configure the classpath 86 */ 87 private static DexClassLoader createInstance(Configuration config) { 88 File file1; 89 File file2; 90 91 switch (config) { 92 case ONE_DEX: file1 = DEX_FILE; file2 = null; break; 93 case ONE_JAR: file1 = JAR_FILE; file2 = null; break; 94 case TWO_DEX: file1 = DEX_FILE; file2 = DEX2_FILE; break; 95 case TWO_JAR: file1 = JAR_FILE; file2 = JAR2_FILE; break; 96 default: throw new AssertionError("shouldn't happen"); 97 } 98 99 String path = file1.getAbsolutePath(); 100 if (file2 != null) { 101 path += File.pathSeparator + file2.getAbsolutePath(); 102 } 103 104 return new DexClassLoader( 105 path, TMP_DIR.getAbsolutePath(), null, 106 ClassLoader.getSystemClassLoader()); 107 } 108 109 /** 110 * Helper to construct an instance to test, using the jar file as 111 * the source, and call a named no-argument static method on a 112 * named class. 113 * 114 * @param config how to configure the classpath 115 */ 116 public static Object createInstanceAndCallStaticMethod( 117 Configuration config, String className, String methodName) 118 throws ClassNotFoundException, NoSuchMethodException, 119 IllegalAccessException, InvocationTargetException { 120 DexClassLoader dcl = createInstance(config); 121 Class c = dcl.loadClass(className); 122 Method m = c.getMethod(methodName, (Class[]) null); 123 return m.invoke(null, (Object[]) null); 124 } 125 126 /* 127 * Tests that are parametric with respect to whether to use a jar 128 * file or a dex file as the source of the code 129 */ 130 131 /** 132 * Just a trivial test of construction. This one merely makes 133 * sure that a valid construction doesn't fail; it doesn't try 134 * to verify anything about the constructed instance. (Other 135 * tests will do that.) 136 */ 137 public static void test_init(Configuration config) { 138 createInstance(config); 139 } 140 141 /** 142 * Check that a class in the jar/dex file may be used successfully. In this 143 * case, a trivial static method is called. 144 */ 145 public static void test_simpleUse(Configuration config) throws Exception { 146 String result = (String) 147 createInstanceAndCallStaticMethod(config, "test.Test1", "test"); 148 149 assertSame("blort", result); 150 } 151 152 /* 153 * All the following tests are just pass-throughs to test code 154 * that lives inside the loading-test dex/jar file. 155 */ 156 157 public static void test_constructor(Configuration config) 158 throws Exception { 159 createInstanceAndCallStaticMethod( 160 config, "test.TestMethods", "test_constructor"); 161 } 162 163 public static void test_callStaticMethod(Configuration config) 164 throws Exception { 165 createInstanceAndCallStaticMethod( 166 config, "test.TestMethods", "test_callStaticMethod"); 167 } 168 169 public static void test_getStaticVariable(Configuration config) 170 throws Exception { 171 createInstanceAndCallStaticMethod( 172 config, "test.TestMethods", "test_getStaticVariable"); 173 } 174 175 public static void test_callInstanceMethod(Configuration config) 176 throws Exception { 177 createInstanceAndCallStaticMethod( 178 config, "test.TestMethods", "test_callInstanceMethod"); 179 } 180 181 public static void test_getInstanceVariable(Configuration config) 182 throws Exception { 183 createInstanceAndCallStaticMethod( 184 config, "test.TestMethods", "test_getInstanceVariable"); 185 } 186 187 public static void test_diff_constructor(Configuration config) 188 throws Exception { 189 createInstanceAndCallStaticMethod( 190 config, "test.TestMethods", "test_diff_constructor"); 191 } 192 193 public static void test_diff_callStaticMethod(Configuration config) 194 throws Exception { 195 createInstanceAndCallStaticMethod( 196 config, "test.TestMethods", "test_diff_callStaticMethod"); 197 } 198 199 public static void test_diff_getStaticVariable(Configuration config) 200 throws Exception { 201 createInstanceAndCallStaticMethod( 202 config, "test.TestMethods", "test_diff_getStaticVariable"); 203 } 204 205 public static void test_diff_callInstanceMethod(Configuration config) 206 throws Exception { 207 createInstanceAndCallStaticMethod( 208 config, "test.TestMethods", "test_diff_callInstanceMethod"); 209 } 210 211 public static void test_diff_getInstanceVariable(Configuration config) 212 throws Exception { 213 createInstanceAndCallStaticMethod( 214 config, "test.TestMethods", "test_diff_getInstanceVariable"); 215 } 216 217 /* 218 * These methods are all essentially just calls to the 219 * parametrically-defined tests above. 220 */ 221 222 // ONE_JAR 223 224 public void test_oneJar_init() throws Exception { 225 test_init(Configuration.ONE_JAR); 226 } 227 228 public void test_oneJar_simpleUse() throws Exception { 229 test_simpleUse(Configuration.ONE_JAR); 230 } 231 232 public void test_oneJar_constructor() throws Exception { 233 test_constructor(Configuration.ONE_JAR); 234 } 235 236 public void test_oneJar_callStaticMethod() throws Exception { 237 test_callStaticMethod(Configuration.ONE_JAR); 238 } 239 240 public void test_oneJar_getStaticVariable() throws Exception { 241 test_getStaticVariable(Configuration.ONE_JAR); 242 } 243 244 public void test_oneJar_callInstanceMethod() throws Exception { 245 test_callInstanceMethod(Configuration.ONE_JAR); 246 } 247 248 public void test_oneJar_getInstanceVariable() throws Exception { 249 test_getInstanceVariable(Configuration.ONE_JAR); 250 } 251 252 // ONE_DEX 253 254 public void test_oneDex_init() throws Exception { 255 test_init(Configuration.ONE_DEX); 256 } 257 258 public void test_oneDex_simpleUse() throws Exception { 259 test_simpleUse(Configuration.ONE_DEX); 260 } 261 262 public void test_oneDex_constructor() throws Exception { 263 test_constructor(Configuration.ONE_DEX); 264 } 265 266 public void test_oneDex_callStaticMethod() throws Exception { 267 test_callStaticMethod(Configuration.ONE_DEX); 268 } 269 270 public void test_oneDex_getStaticVariable() throws Exception { 271 test_getStaticVariable(Configuration.ONE_DEX); 272 } 273 274 public void test_oneDex_callInstanceMethod() throws Exception { 275 test_callInstanceMethod(Configuration.ONE_DEX); 276 } 277 278 public void test_oneDex_getInstanceVariable() throws Exception { 279 test_getInstanceVariable(Configuration.ONE_DEX); 280 } 281 282 // TWO_JAR 283 284 public void test_twoJar_init() throws Exception { 285 test_init(Configuration.TWO_JAR); 286 } 287 288 public void test_twoJar_simpleUse() throws Exception { 289 test_simpleUse(Configuration.TWO_JAR); 290 } 291 292 public void test_twoJar_constructor() throws Exception { 293 test_constructor(Configuration.TWO_JAR); 294 } 295 296 public void test_twoJar_callStaticMethod() throws Exception { 297 test_callStaticMethod(Configuration.TWO_JAR); 298 } 299 300 public void test_twoJar_getStaticVariable() throws Exception { 301 test_getStaticVariable(Configuration.TWO_JAR); 302 } 303 304 public void test_twoJar_callInstanceMethod() throws Exception { 305 test_callInstanceMethod(Configuration.TWO_JAR); 306 } 307 308 public void test_twoJar_getInstanceVariable() throws Exception { 309 test_getInstanceVariable(Configuration.TWO_JAR); 310 } 311 312 public static void test_twoJar_diff_constructor() throws Exception { 313 test_diff_constructor(Configuration.TWO_JAR); 314 } 315 316 public static void test_twoJar_diff_callStaticMethod() throws Exception { 317 test_diff_callStaticMethod(Configuration.TWO_JAR); 318 } 319 320 public static void test_twoJar_diff_getStaticVariable() throws Exception { 321 test_diff_getStaticVariable(Configuration.TWO_JAR); 322 } 323 324 public static void test_twoJar_diff_callInstanceMethod() 325 throws Exception { 326 test_diff_callInstanceMethod(Configuration.TWO_JAR); 327 } 328 329 public static void test_twoJar_diff_getInstanceVariable() 330 throws Exception { 331 test_diff_getInstanceVariable(Configuration.TWO_JAR); 332 } 333 334 // TWO_DEX 335 336 public void test_twoDex_init() throws Exception { 337 test_init(Configuration.TWO_DEX); 338 } 339 340 public void test_twoDex_simpleUse() throws Exception { 341 test_simpleUse(Configuration.TWO_DEX); 342 } 343 344 public void test_twoDex_constructor() throws Exception { 345 test_constructor(Configuration.TWO_DEX); 346 } 347 348 public void test_twoDex_callStaticMethod() throws Exception { 349 test_callStaticMethod(Configuration.TWO_DEX); 350 } 351 352 public void test_twoDex_getStaticVariable() throws Exception { 353 test_getStaticVariable(Configuration.TWO_DEX); 354 } 355 356 public void test_twoDex_callInstanceMethod() throws Exception { 357 test_callInstanceMethod(Configuration.TWO_DEX); 358 } 359 360 public void test_twoDex_getInstanceVariable() throws Exception { 361 test_getInstanceVariable(Configuration.TWO_DEX); 362 } 363 364 public static void test_twoDex_diff_constructor() throws Exception { 365 test_diff_constructor(Configuration.TWO_DEX); 366 } 367 368 public static void test_twoDex_diff_callStaticMethod() throws Exception { 369 test_diff_callStaticMethod(Configuration.TWO_DEX); 370 } 371 372 public static void test_twoDex_diff_getStaticVariable() throws Exception { 373 test_diff_getStaticVariable(Configuration.TWO_DEX); 374 } 375 376 public static void test_twoDex_diff_callInstanceMethod() 377 throws Exception { 378 test_diff_callInstanceMethod(Configuration.TWO_DEX); 379 } 380 381 public static void test_twoDex_diff_getInstanceVariable() 382 throws Exception { 383 test_diff_getInstanceVariable(Configuration.TWO_DEX); 384 } 385 386 /* 387 * Tests specifically for resource-related functionality. Since 388 * raw dex files don't contain resources, these test only work 389 * with jar files. The first couple methods here are helpers, 390 * and they are followed by the tests per se. 391 */ 392 393 /** 394 * Check that a given resource (by name) is retrievable and contains 395 * the given expected contents. 396 */ 397 public static void test_directGetResourceAsStream(Configuration config, 398 String resourceName, String expectedContents) 399 throws Exception { 400 DexClassLoader dcl = createInstance(config); 401 InputStream in = dcl.getResourceAsStream(resourceName); 402 byte[] contents = Streams.readFully(in); 403 String s = new String(contents, "UTF-8"); 404 405 assertEquals(expectedContents, s); 406 } 407 408 /** 409 * Check that a resource in the jar file is retrievable and contains 410 * the expected contents. 411 */ 412 public static void test_directGetResourceAsStream(Configuration config) 413 throws Exception { 414 test_directGetResourceAsStream( 415 config, "test/Resource1.txt", "Muffins are tasty!\n"); 416 } 417 418 /** 419 * Check that a resource in the jar file can be retrieved from 420 * a class within that jar file. 421 */ 422 public static void test_getResourceAsStream(Configuration config) 423 throws Exception { 424 createInstanceAndCallStaticMethod( 425 config, "test.TestMethods", "test_getResourceAsStream"); 426 } 427 428 public void test_oneJar_directGetResourceAsStream() throws Exception { 429 test_directGetResourceAsStream(Configuration.ONE_JAR); 430 } 431 432 public void test_oneJar_getResourceAsStream() throws Exception { 433 test_getResourceAsStream(Configuration.ONE_JAR); 434 } 435 436 public void test_twoJar_directGetResourceAsStream() throws Exception { 437 test_directGetResourceAsStream(Configuration.TWO_JAR); 438 } 439 440 public void test_twoJar_getResourceAsStream() throws Exception { 441 test_getResourceAsStream(Configuration.TWO_JAR); 442 } 443 444 /** 445 * Check that a resource in the second jar file is retrievable and 446 * contains the expected contents. 447 */ 448 public static void test_twoJar_diff_directGetResourceAsStream() 449 throws Exception { 450 test_directGetResourceAsStream( 451 Configuration.TWO_JAR, "test2/Resource2.txt", 452 "Who doesn't like a good biscuit?\n"); 453 } 454 455 /** 456 * Check that a resource in a jar file can be retrieved from 457 * a class within the other jar file. 458 */ 459 public static void test_twoJar_diff_getResourceAsStream() 460 throws Exception { 461 createInstanceAndCallStaticMethod( 462 Configuration.TWO_JAR, "test.TestMethods", 463 "test_diff_getResourceAsStream"); 464 } 465} 466