From c8e1dd4c1418f6876ab47e6d698b0003cd0f651e Mon Sep 17 00:00:00 2001 From: Hugo Hudson Date: Wed, 18 Jan 2012 15:37:04 +0000 Subject: Cherry pick 'Update to r12 of LittleMock'. DO NOT MERGE Change-Id: I0899465493a1ebaaa587bb13f2f9ebf18f516037 --- .../testing/littlemock/AppDataDirGuesser.java | 12 ++++++- src/com/google/testing/littlemock/LittleMock.java | 37 +++++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) (limited to 'src/com/google/testing/littlemock') 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 @@ public class AppDataDirGuesser { 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); } @@ -113,6 +113,16 @@ public class AppDataDirGuesser { return results.toArray(new File[results.size()]); } + // @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 @@ public class LittleMock { 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 unsafeCreateInstance(Class 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"); + } } -- cgit v1.2.3