Cherry pick 'Update to r12 of LittleMock'.
DO NOT MERGE
Change-Id: I0899465493a1ebaaa587bb13f2f9ebf18f516037
diff --git a/src/com/google/testing/littlemock/AppDataDirGuesser.java b/src/com/google/testing/littlemock/AppDataDirGuesser.java
index 8dd556e..e661ed6 100644
--- a/src/com/google/testing/littlemock/AppDataDirGuesser.java
+++ b/src/com/google/testing/littlemock/AppDataDirGuesser.java
@@ -103,7 +103,7 @@
File dataDir = new File("/data/data/" + packageName);
if (isWriteableDirectory(dataDir)) {
File cacheDir = new File(dataDir, "cache");
- if ((cacheDir.exists()) || (cacheDir.mkdir())) {
+ if (fileOrDirExists(cacheDir) || makeDirectory(cacheDir)) {
if (isWriteableDirectory(cacheDir)) {
results.add(cacheDir);
}
@@ -114,6 +114,16 @@
}
// @VisibleForTesting
+ boolean fileOrDirExists(File file) {
+ return file.exists();
+ }
+
+ // @VisibleForTesting
+ boolean makeDirectory(File file) {
+ return file.mkdir();
+ }
+
+ // @VisibleForTesting
boolean isWriteableDirectory(File file) {
return file.isDirectory() && file.canWrite();
}
diff --git a/src/com/google/testing/littlemock/LittleMock.java b/src/com/google/testing/littlemock/LittleMock.java
index 50afeb1..fc6c527 100644
--- a/src/com/google/testing/littlemock/LittleMock.java
+++ b/src/com/google/testing/littlemock/LittleMock.java
@@ -17,6 +17,8 @@
package com.google.testing.littlemock;
import java.io.File;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
@@ -1060,15 +1062,42 @@
Class<?> proxyBuilder = Class.forName("com.google.dexmaker.stock.ProxyBuilder");
Method forClassMethod = proxyBuilder.getMethod("forClass", Class.class);
Object builder = forClassMethod.invoke(null, clazz);
- Method handlerMethod = builder.getClass().getMethod("handler", InvocationHandler.class);
- builder = handlerMethod.invoke(builder, handler);
Method dexCacheMethod = builder.getClass().getMethod("dexCache", File.class);
File directory = AppDataDirGuesser.getsInstance().guessSuitableDirectoryForGeneratedClasses();
builder = dexCacheMethod.invoke(builder, directory);
- Method buildMethod = builder.getClass().getMethod("build");
- return buildMethod.invoke(builder);
+ Method buildClassMethod = builder.getClass().getMethod("buildProxyClass");
+ Class<?> resultClass = (Class<?>) buildClassMethod.invoke(builder);
+ Object proxy = unsafeCreateInstance(resultClass);
+ Field handlerField = resultClass.getDeclaredField("$__handler");
+ handlerField.setAccessible(true);
+ handlerField.set(proxy, handler);
+ return proxy;
} catch (Exception e) {
throw new IllegalStateException("Could not mock this concrete class", e);
}
}
+
+ /** Attempt to construct an instance of the class using hacky methods to avoid calling super. */
+ @SuppressWarnings("unchecked")
+ private static <T> T unsafeCreateInstance(Class<T> clazz) {
+ // try dalvikvm, pre-gingerbread
+ try {
+ final Method newInstance = ObjectInputStream.class.getDeclaredMethod(
+ "newInstance", Class.class, Class.class);
+ newInstance.setAccessible(true);
+ return (T) newInstance.invoke(null, clazz, Object.class);
+ } catch (Exception ignored) {}
+ // try dalvikvm, post-gingerbread
+ try {
+ Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod(
+ "getConstructorId", Class.class);
+ getConstructorId.setAccessible(true);
+ final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
+ final Method newInstance = ObjectStreamClass.class.getDeclaredMethod(
+ "newInstance", Class.class, int.class);
+ newInstance.setAccessible(true);
+ return (T) newInstance.invoke(null, clazz, constructorId);
+ } catch (Exception ignored) {}
+ throw new IllegalStateException("unsafe create instance failed");
+ }
}
diff --git a/tests/com/google/testing/littlemock/AppDataDirGuesserTest.java b/tests/com/google/testing/littlemock/AppDataDirGuesserTest.java
index b537097..3ab38b2 100644
--- a/tests/com/google/testing/littlemock/AppDataDirGuesserTest.java
+++ b/tests/com/google/testing/littlemock/AppDataDirGuesserTest.java
@@ -82,6 +82,10 @@
public boolean isWriteableDirectory(File file) {
return !notWriteable.contains(file.getAbsolutePath());
}
+ @Override
+ boolean fileOrDirExists(File file) {
+ return true;
+ }
};
File[] results = guesser.guessPath(path);
assertNotNull("Null results for " + path, results);