blob: efc9c295139175bd8bf0bfe1119e00ca4402c398 [file] [log] [blame]
/*
* Copyright (C) 2011 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.dalvik.system;
import java.lang.reflect.Method;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import libcore.io.Streams;
import junit.framework.TestCase;
import dalvik.system.DexClassLoader;
/**
* Tests for the class {@link DexClassLoader}.
*/
public class DexClassLoaderTest extends TestCase {
private File dex1;
private File dex2;
private File jar1;
private File jar2;
private File nativeLib1;
private Map<String, File> resourcesMap;
protected void setUp() throws Exception {
resourcesMap = ClassLoaderTestSupport.setupAndCopyResources(Arrays.asList(
"loading-test.dex", "loading-test2.dex", "loading-test.jar", "loading-test2.jar",
"libfake.so"));
dex1 = resourcesMap.get("loading-test.dex");
assertNotNull(dex1);
dex2 = resourcesMap.get("loading-test2.dex");
assertNotNull(dex2);
jar1 = resourcesMap.get("loading-test.jar");
assertNotNull(jar1);
jar2 = resourcesMap.get("loading-test2.jar");
assertNotNull(jar2);
nativeLib1 = resourcesMap.get("libfake.so");
assertNotNull(nativeLib1);
}
protected void tearDown() {
ClassLoaderTestSupport.cleanUpResources(resourcesMap);
}
/**
* Helper to construct a DexClassLoader instance to test.
*
* @param files The .dex or .jar files to use for the class path.
*/
private ClassLoader createLoader(File... files) {
assertNotNull(files);
assertTrue(files.length > 0);
String path = files[0].getAbsolutePath();
for (int i = 1; i < files.length; i++) {
path += File.pathSeparator + files[i].getAbsolutePath();
}
return new DexClassLoader(path, null, null,
ClassLoader.getSystemClassLoader());
}
/**
* Helper to construct a new DexClassLoader instance to test, using the
* given files as the class path, and call a named no-argument static
* method on a named class.
*
* @param className The name of the class of the method to call.
* @param methodName The name of the method to call.
* @param files The .dex or .jar files to use for the class path.
*/
public Object createLoaderAndCallMethod(
String className, String methodName, File... files)
throws ReflectiveOperationException {
ClassLoader cl = createLoader(files);
Class c = cl.loadClass(className);
Method m = c.getMethod(methodName, (Class[]) null);
return m.invoke(null, (Object[]) null);
}
/**
* Helper to construct a new DexClassLoader instance to test, using the
* given files as the class path, and read the contents of the named
* resource as a String.
*
* @param resourceName The name of the resource to get.
* @param files The .dex or .jar files to use for the class path.
*/
private String createLoaderAndGetResource(String resourceName, File... files) throws Exception {
ClassLoader cl = createLoader(files);
InputStream in = cl.getResourceAsStream(resourceName);
if (in == null) {
throw new IllegalStateException("Resource not found: " + resourceName);
}
byte[] contents = Streams.readFully(in);
return new String(contents, "UTF-8");
}
// ONE_JAR
/**
* Just a trivial test of construction. This one merely makes
* sure that a valid construction doesn't fail. It doesn't try
* to verify anything about the constructed instance, other than
* checking for the existence of optimized dex files.
*/
public void test_oneJar_init() throws Exception {
ClassLoader cl = createLoader(jar1);
}
/**
* Check that a class in the jar/dex file may be used successfully. In this
* case, a trivial static method is called.
*/
public void test_oneJar_simpleUse() throws Exception {
String result = (String) createLoaderAndCallMethod("test.Test1", "test", jar1);
assertSame("blort", result);
}
/*
* All the following tests are just pass-throughs to test code
* that lives inside the loading-test dex/jar file.
*/
public void test_oneJar_constructor() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_constructor", jar1);
}
public void test_oneJar_callStaticMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", jar1);
}
public void test_oneJar_getStaticVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", jar1);
}
public void test_oneJar_callInstanceMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", jar1);
}
public void test_oneJar_getInstanceVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", jar1);
}
// ONE_DEX
public void test_oneDex_init() throws Exception {
ClassLoader cl = createLoader(dex1);
}
public void test_oneDex_simpleUse() throws Exception {
String result = (String) createLoaderAndCallMethod("test.Test1", "test", dex1);
assertSame("blort", result);
}
public void test_oneDex_constructor() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_constructor", dex1);
}
public void test_oneDex_callStaticMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1);
}
public void test_oneDex_getStaticVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1);
}
public void test_oneDex_callInstanceMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1);
}
public void test_oneDex_getInstanceVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", dex1);
}
// TWO_JAR
public void test_twoJar_init() throws Exception {
ClassLoader cl = createLoader(jar1, jar2);
}
public void test_twoJar_simpleUse() throws Exception {
String result = (String) createLoaderAndCallMethod("test.Test1", "test", jar1, jar2);
assertSame("blort", result);
}
public void test_twoJar_constructor() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_constructor", jar1, jar2);
}
public void test_twoJar_callStaticMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", jar1, jar2);
}
public void test_twoJar_getStaticVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", jar1, jar2);
}
public void test_twoJar_callInstanceMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", jar1, jar2);
}
public void test_twoJar_getInstanceVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", jar1, jar2);
}
public void test_twoJar_diff_constructor() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_constructor", jar1, jar2);
}
public void test_twoJar_diff_callStaticMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_callStaticMethod", jar1, jar2);
}
public void test_twoJar_diff_getStaticVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_getStaticVariable", jar1, jar2);
}
public void test_twoJar_diff_callInstanceMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_callInstanceMethod", jar1, jar2);
}
public void test_twoJar_diff_getInstanceVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_getInstanceVariable", jar1, jar2);
}
// TWO_DEX
public void test_twoDex_init() throws Exception {
ClassLoader cl = createLoader(dex1, dex2);
}
public void test_twoDex_simpleUse() throws Exception {
String result = (String) createLoaderAndCallMethod("test.Test1", "test", dex1, dex2);
assertSame("blort", result);
}
public void test_twoDex_constructor() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_constructor", dex1, dex2);
}
public void test_twoDex_callStaticMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1, dex2);
}
public void test_twoDex_getStaticVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1, dex2);
}
public void test_twoDex_callInstanceMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1, dex2);
}
public void test_twoDex_getInstanceVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", dex1, dex2);
}
public void test_twoDex_diff_constructor() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_constructor", dex1, dex2);
}
public void test_twoDex_diff_callStaticMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_callStaticMethod", dex1, dex2);
}
public void test_twoDex_diff_getStaticVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_getStaticVariable", dex1, dex2);
}
public void test_twoDex_diff_callInstanceMethod() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_callInstanceMethod", dex1, dex2);
}
public void test_twoDex_diff_getInstanceVariable() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_getInstanceVariable", dex1, dex2);
}
/*
* Tests specifically for resource-related functionality. Since
* raw dex files don't contain resources, these test only work
* with jar files.
*/
/**
* Check that a resource in the jar file is retrievable and contains
* the expected contents.
*/
public void test_oneJar_directGetResourceAsStream() throws Exception {
String result = createLoaderAndGetResource("test/Resource1.txt", jar1);
assertEquals("Muffins are tasty!\n", result);
}
/**
* Check that a resource in the jar file can be retrieved from
* a class within that jar file.
*/
public void test_oneJar_getResourceAsStream() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getResourceAsStream", jar1);
}
public void test_twoJar_directGetResourceAsStream() throws Exception {
String result = createLoaderAndGetResource("test/Resource1.txt", jar1, jar2);
assertEquals("Muffins are tasty!\n", result);
}
public void test_twoJar_getResourceAsStream() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_getResourceAsStream", jar1, jar2);
}
/**
* Check that a resource in the second jar file is retrievable and
* contains the expected contents.
*/
public void test_twoJar_diff_directGetResourceAsStream() throws Exception {
String result = createLoaderAndGetResource("test2/Resource2.txt", jar1, jar2);
assertEquals("Who doesn't like a good biscuit?\n", result);
}
/**
* Check that a resource in a jar file can be retrieved from
* a class within the other jar file.
*/
public void test_twoJar_diff_getResourceAsStream() throws Exception {
createLoaderAndCallMethod("test.TestMethods", "test_diff_getResourceAsStream", jar1, jar2);
}
/*
* Tests native modification behaviors
*/
/**
* Checks that a adding a native library to an existing class loader makes it visible for
* subsequent calls.
* @throws Exception
*/
public void test_oneDex_addNative_findsLibrary() throws Exception {
String path = nativeLib1.getParentFile().getAbsolutePath();
DexClassLoader classLoader = (DexClassLoader) createLoader(dex1);
assertNull("findLibrary should not find un-added path",
classLoader.findLibrary("fake"));
classLoader.addNativePath(Collections.singletonList(path));
assertNotNull("findLibrary should find newly added path",
classLoader.findLibrary("fake"));
}
}