Fix tests when running from the command line
When loading classes from the jar file, we can't just use the
URLClassLoader since it can not enumerate files in a jar directory.
Restoring the ModuleClassLoader and making all paths relative to the
system class loader (as opposed to relative to the class location).
Change-Id: Ib3f5d12dd5c964d0ba9cc6c5ec9cb556c989e653
(cherry picked from commit 2a4a6c81f8a103be5c48d8a0605a3e4416e8f7f1)
diff --git a/bridge/tests/Android.mk b/bridge/tests/Android.mk
index 8a81d0b..565feb6 100644
--- a/bridge/tests/Android.mk
+++ b/bridge/tests/Android.mk
@@ -17,7 +17,9 @@
include $(CLEAR_VARS)
# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-java-files-under, res/testApp/MyApplication/src/main/myapplication.widgets)
LOCAL_JAVA_RESOURCE_DIRS := res
LOCAL_MODULE := layoutlib-tests
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
index 8f9fa8a..d81b4ba 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
@@ -64,7 +64,7 @@
double scale = THUMBNAIL_SIZE / (double)maxDimension;
BufferedImage thumbnail = scale(image, scale, scale);
- InputStream is = ImageUtils.class.getResourceAsStream(relativePath);
+ InputStream is = ImageUtils.class.getClassLoader().getResourceAsStream(relativePath);
if (is == null) {
String message = "Unable to load golden thumbnail: " + relativePath + "\n";
message = saveImageAndAppendMessage(thumbnail, message, relativePath);
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 5423e87..24cbbca 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -121,7 +121,7 @@
private static final String PLATFORM_DIR;
private static final String TEST_RES_DIR;
/** Location of the app to test inside {@link #TEST_RES_DIR}*/
- private static final String APP_TEST_DIR = "/testApp/MyApplication";
+ private static final String APP_TEST_DIR = "testApp/MyApplication";
/** Location of the app's res dir inside {@link #TEST_RES_DIR}*/
private static final String APP_TEST_RES = APP_TEST_DIR + "/src/main/res";
private static final String APP_CLASSES_LOCATION =
@@ -138,8 +138,7 @@
// Default class loader with access to the app classes
private ClassLoader mDefaultClassLoader =
- new URLClassLoader(new URL[]{this.getClass().getResource(APP_CLASSES_LOCATION)},
- getClass().getClassLoader());
+ new ModuleClassLoader(APP_CLASSES_LOCATION, getClass().getClassLoader());
@Rule
public TestWatcher sRenderMessageWatcher = new TestWatcher() {
@@ -313,7 +312,8 @@
sFrameworkRepo.loadPublicResources(getLogger());
sProjectResources =
- new ResourceRepository(new FolderWrapper(TEST_RES_DIR + APP_TEST_RES), false) {
+ new ResourceRepository(new FolderWrapper(TEST_RES_DIR + "/" + APP_TEST_RES),
+ false) {
@NonNull
@Override
protected ResourceItem createResourceItem(@NonNull String name) {
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/ModuleClassLoader.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/ModuleClassLoader.java
new file mode 100644
index 0000000..3fac778
--- /dev/null
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/ModuleClassLoader.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 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 com.android.layoutlib.bridge.intensive;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import libcore.io.Streams;
+
+/**
+ * Module class loader that loads classes from the test project.
+ */
+public class ModuleClassLoader extends ClassLoader {
+ private final Map<String, Class<?>> mClasses = new HashMap<>();
+ private String myModuleRoot;
+
+ /**
+ * @param moduleRoot The path to the module root
+ * @param parent The parent class loader
+ */
+ public ModuleClassLoader(String moduleRoot, ClassLoader parent) {
+ super(parent);
+ myModuleRoot = moduleRoot + (moduleRoot.endsWith("/") ? "" : "/");
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ try {
+ return super.findClass(name);
+ } catch (ClassNotFoundException ignored) {
+ }
+
+ Class<?> clazz = mClasses.get(name);
+ if (clazz == null) {
+ String path = name.replace('.', '/').concat(".class");
+ try {
+ byte[] b = Streams.readFully(getResourceAsStream(myModuleRoot + path));
+ clazz = defineClass(name, b, 0, b.length);
+ mClasses.put(name, clazz);
+ } catch (IOException ignore) {
+ throw new ClassNotFoundException(name + " not found");
+ }
+ }
+
+ return clazz;
+ }
+}
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
index 1110494..bc8083f 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
@@ -42,9 +42,11 @@
* @param layoutPath Must start with '/' and be relative to test resources.
*/
public LayoutPullParser(String layoutPath) {
- assert layoutPath.startsWith("/");
+ if (layoutPath.startsWith("/")) {
+ layoutPath = layoutPath.substring(1);
+ }
try {
- init(getClass().getResourceAsStream(layoutPath));
+ init(getClass().getClassLoader().getResourceAsStream(layoutPath));
} catch (XmlPullParserException e) {
throw new IOError(e);
}