Update to r16 of LittleMock.

Change-Id: Ia270375e8a549709d89a34021d33e22d883b1c25
diff --git a/src/com/google/testing/littlemock/LittleMock.java b/src/com/google/testing/littlemock/LittleMock.java
index d13150a..9d756dc 100644
--- a/src/com/google/testing/littlemock/LittleMock.java
+++ b/src/com/google/testing/littlemock/LittleMock.java
@@ -1099,6 +1099,13 @@
     }
   }
 
+  /** Helper method to throw an IllegalStateException if given condition is not met. */
+  private static void checkState(boolean condition) {
+    if (!condition) {
+      throw new IllegalStateException();
+    }
+  }
+
   /**
    * If the input object is one of our mocks, returns the {@link DefaultInvocationHandler}
    * we constructed it with.  Otherwise fails with {@link IllegalArgumentException}.
@@ -1118,14 +1125,92 @@
         return (DefaultInvocationHandler) invocationHandler;
       }
     } catch (Exception expectedIfNotAProxyBuilderMock) {}
+    try {
+      // Try with javassist.
+      Class<?> proxyObjectClass = Class.forName("javassist.util.proxy.ProxyObject");
+      Method getHandlerMethod = proxyObjectClass.getMethod("getHandler");
+      Object methodHandler = getHandlerMethod.invoke(mock);
+      InvocationHandler invocationHandler = Proxy.getInvocationHandler(methodHandler);
+      Method getOriginalMethod = invocationHandler.getClass().getMethod("$$getOriginal");
+      Object original = getOriginalMethod.invoke(invocationHandler);
+      if (original instanceof DefaultInvocationHandler) {
+        return (DefaultInvocationHandler) original;
+      }
+    } catch (Exception expectedIfNotJavassistProxy) {}
     throw new IllegalArgumentException("not a valid mock: " + mock);
   }
 
   /** Create a dynamic proxy for the given class, delegating to the given invocation handler. */
-  private static Object createProxy(Class<?> clazz, InvocationHandler handler) {
+  private static Object createProxy(Class<?> clazz, final InvocationHandler handler) {
+    // Interfaces are simple.  Just proxy them using java.lang.reflect.Proxy.
     if (clazz.isInterface()) {
       return Proxy.newProxyInstance(getClassLoader(), new Class<?>[] { clazz }, handler);
     }
+    // Try with javassist.
+    try {
+      Class<?> proxyFactoryClass = Class.forName("javassist.util.proxy.ProxyFactory");
+      Object proxyFactory = proxyFactoryClass.newInstance();
+      Method setSuperclassMethod = proxyFactoryClass.getMethod("setSuperclass", Class.class);
+      setSuperclassMethod.invoke(proxyFactory, clazz);
+      Class<?> methodFilterClass = Class.forName("javassist.util.proxy.MethodFilter");
+      InvocationHandler methodFilterHandler = new InvocationHandler() {
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+          checkState(method.getName().equals("isHandled"));
+          checkState(args.length == 1);
+          checkState(args[0] instanceof Method);
+          Method invokedMethod = (Method) args[0];
+          String methodName = invokedMethod.getName();
+          Class<?>[] params = invokedMethod.getParameterTypes();
+          if ("equals".equals(methodName) && params.length == 1
+              && Object.class.equals(params[0])) {
+            return false;
+          }
+          if ("hashCode".equals(methodName) && params.length == 0) {
+              return false;
+          }
+          if ("toString".equals(methodName) && params.length == 0) {
+              return false;
+          }
+          if ("finalize".equals(methodName) && params.length == 0) {
+              return false;
+          }
+          return true;
+        }
+      };
+      Object methodFilter = Proxy.newProxyInstance(getClassLoader(),
+          new Class<?>[] { methodFilterClass }, methodFilterHandler);
+      Method setFilterMethod = proxyFactoryClass.getMethod("setFilter", methodFilterClass);
+      setFilterMethod.invoke(proxyFactory, methodFilter);
+      Method createClassMethod = proxyFactoryClass.getMethod("createClass");
+      Class<?> createdClass = (Class<?>) createClassMethod.invoke(proxyFactory);
+      InvocationHandler methodHandlerHandler = new InvocationHandler() {
+        @SuppressWarnings("unused")
+        public InvocationHandler $$getOriginal() {
+          return handler;
+        }
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+          checkState(method.getName().equals("invoke"));
+          checkState(args.length == 4);
+          checkState(args[1] instanceof Method);
+          Method invokedMethod = (Method) args[1];
+          checkState(args[3] instanceof Object[]);
+          return handler.invoke(args[0], invokedMethod, (Object[]) args[3]);
+        }
+      };
+      Class<?> methodHandlerClass = Class.forName("javassist.util.proxy.MethodHandler");
+      Object methodHandler = Proxy.newProxyInstance(getClassLoader(),
+          new Class<?>[] { methodHandlerClass }, methodHandlerHandler);
+      Object proxy = unsafeCreateInstance(createdClass);
+      Class<?> proxyObjectClass = Class.forName("javassist.util.proxy.ProxyObject");
+      Method setHandlerMethod = proxyObjectClass.getMethod("setHandler", methodHandlerClass);
+      setHandlerMethod.invoke(proxy, methodHandler);
+      return proxy;
+    } catch (Exception e) {
+      // Not supported, i.e. javassist missing.  Fall through.
+    }
+    // So, this is a class.  First try using Android's ProxyBuilder from dexmaker.
     try {
       Class<?> proxyBuilder = Class.forName("com.google.dexmaker.stock.ProxyBuilder");
       Method forClassMethod = proxyBuilder.getMethod("forClass", Class.class);
@@ -1148,6 +1233,15 @@
   /** 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 jvm
+    try {
+      Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
+      Field f = unsafeClass.getDeclaredField("theUnsafe");
+      f.setAccessible(true);
+      final Object unsafe = f.get(null);
+      final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
+      return (T) allocateInstance.invoke(unsafe, clazz);
+    } catch (Exception ignored) {}
     // try dalvikvm, pre-gingerbread
     try {
       final Method newInstance = ObjectInputStream.class.getDeclaredMethod(
diff --git a/tests/com/google/testing/littlemock/LittleMockTest.java b/tests/com/google/testing/littlemock/LittleMockTest.java
index c9b36be..e7f9bca 100644
--- a/tests/com/google/testing/littlemock/LittleMockTest.java
+++ b/tests/com/google/testing/littlemock/LittleMockTest.java
@@ -1551,15 +1551,18 @@
   }
 
   public static class Jim {
-    public void bob() {
+    public int bob() {
       fail();
+      return 3;
     }
   }
 
   // Does not work on JVM, android only.
-  public void suppress_testMockingConcreteClasses() throws Exception {
+  public void testMockingConcreteClasses() throws Exception {
     Jim mock = mock(Jim.class);
-    mock.bob();
+    assertEquals(0, mock.bob());
+    doReturn(8).when(mock).bob();
+    assertEquals(8, mock.bob());
   }
 
   private Future<Void> invokeBarMethodAfterLatchAwait(final CountDownLatch countDownLatch) {
@@ -1576,17 +1579,6 @@
   // TODO(hugohudson): 5. Every method that throws exceptions could be improved by adding
   // test for the content of the error message.
 
-  // TODO(hugohudson): 5. Add InOrder class, so that we can check that the given methods on
-  // the given mocks happen in the right order.  It will be pretty easy to do.  The syntax
-  // looks like this:
-  // InOrder inOrder = inOrder(firstMock, secondMock);
-  // inOrder.verify(firstMock).firstMethod();
-  // inOrder.verify(secondMock).secondMethod();
-  // This allows us to verify that the calls happened in the desired order.
-  // By far the simplest way to do this is have a static AtomicInteger on the class which
-  // indicates exactly when every method call happened, and then just compare order based on
-  // that.
-
   // TODO(hugohudson): 5. Make the doReturn() method take variable arguments.
   // The syntax is:
   // doReturn(1, 2, 3).when(mFoo).anInt();