Update to latest dexmaker.
This fixes the bug below which prevented mocking of any ViewGroup
extension.
https://code.google.com/p/dexmaker/issues/detail?id=12
Change-Id: I459fb259244476b89b9a4b50c6a6cf88f2e1f2f6
diff --git a/README b/README
index a32a9a1..82f57a4 100644
--- a/README
+++ b/README
@@ -3,7 +3,7 @@
The latest version of dexmaker can be found at this url:
http://code.google.com/p/dexmaker/
-Version: b4fdb175545f
+Version: f54f6eac0c81120f53265b30adf9ce602e8dfc41
License: Apache 2.0
Description:
diff --git a/src/main/java/com/google/dexmaker/AppDataDirGuesser.java b/src/main/java/com/google/dexmaker/AppDataDirGuesser.java
index b59670e..86f34a1 100644
--- a/src/main/java/com/google/dexmaker/AppDataDirGuesser.java
+++ b/src/main/java/com/google/dexmaker/AppDataDirGuesser.java
@@ -61,7 +61,7 @@
}
// Parsing toString() method: yuck. But no other way to get the path.
- // Strip out the bit between angle brackets, that's our path.
+ // Strip out the bit between square brackets, that's our path.
String result = classLoader.toString();
int index = result.lastIndexOf('[');
result = (index == -1) ? result : result.substring(index + 1);
@@ -71,13 +71,7 @@
File[] guessPath(String input) {
List<File> results = new ArrayList<File>();
- // Post JB, the system property is set to the applications private data cache
- // directory.
- File tmpDir = new File(System.getProperty("java.io.tmpdir"));
- if (isWriteableDirectory(tmpDir)) {
- results.add(tmpDir);
- }
- for (String potential : input.split(":")) {
+ for (String potential : splitPathList(input)) {
if (!potential.startsWith("/data/app/")) {
continue;
}
@@ -105,6 +99,18 @@
return results.toArray(new File[results.size()]);
}
+ static String[] splitPathList(String input) {
+ String trimmed = input;
+ if (input.startsWith("dexPath=")) {
+ int start = "dexPath=".length();
+ int end = input.indexOf(',');
+
+ trimmed = (end == -1) ? input.substring(start) : input.substring(start, end);
+ }
+
+ return trimmed.split(":");
+ }
+
boolean fileOrDirExists(File file) {
return file.exists();
}
diff --git a/src/main/java/com/google/dexmaker/Code.java b/src/main/java/com/google/dexmaker/Code.java
index 4ea5e67..54409a5 100644
--- a/src/main/java/com/google/dexmaker/Code.java
+++ b/src/main/java/com/google/dexmaker/Code.java
@@ -100,7 +100,7 @@
* unconditionally with {@link #jump jump(Label)} or conditionally based on a
* comparison using {@link #compare compare()}.
*
- * <p>Most methods should contain either a return instruction. Void methods
+ * <p>Most methods should contain a return instruction. Void methods
* should use {@link #returnVoid()}; non-void methods should use {@link
* #returnValue returnValue()} with a local whose return type matches the
* method's return type. Constructors are considered void methods and should
@@ -506,9 +506,12 @@
}
/**
- * Executes {@code op} and sets {@code target} to the result.
+ * Executes {@code op} and sets {@code target} to the result. For most
+ * binary operations, the types of {@code a} and {@code b} must be the same.
+ * Shift operations (like {@link BinaryOp#SHIFT_LEFT}) require {@code b} to
+ * be an {@code int}, even when {@code a} is a {@code long}.
*/
- public <T> void op(BinaryOp op, Local<T> target, Local<T> a, Local<T> b) {
+ public <T1, T2> void op(BinaryOp op, Local<T1> target, Local<T1> a, Local<T2> b) {
Rop rop = op.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
RegisterSpecList sources = RegisterSpecList.make(a.spec(), b.spec());
diff --git a/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java b/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java
index 639b3dc..774c5da 100644
--- a/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java
+++ b/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java
@@ -595,11 +595,12 @@
*/
private Method[] getMethodsToProxyRecursive() {
Set<MethodSetEntry> methodsToProxy = new HashSet<MethodSetEntry>();
+ Set<MethodSetEntry> seenFinalMethods = new HashSet<MethodSetEntry>();
for (Class<?> c = baseClass; c != null; c = c.getSuperclass()) {
- getMethodsToProxy(methodsToProxy, c);
+ getMethodsToProxy(methodsToProxy, seenFinalMethods, c);
}
for (Class<?> c : interfaces) {
- getMethodsToProxy(methodsToProxy, c);
+ getMethodsToProxy(methodsToProxy, seenFinalMethods, c);
}
Method[] results = new Method[methodsToProxy.size()];
@@ -610,10 +611,14 @@
return results;
}
- private void getMethodsToProxy(Set<MethodSetEntry> sink, Class<?> c) {
+ private void getMethodsToProxy(Set<MethodSetEntry> sink, Set<MethodSetEntry> seenFinalMethods,
+ Class<?> c) {
for (Method method : c.getDeclaredMethods()) {
if ((method.getModifiers() & Modifier.FINAL) != 0) {
- // Skip final methods, we can't override them.
+ // Skip final methods, we can't override them. We
+ // also need to remember them, in case the same
+ // method exists in a parent class.
+ seenFinalMethods.add(new MethodSetEntry(method));
continue;
}
if ((method.getModifiers() & STATIC) != 0) {
@@ -624,11 +629,17 @@
// Skip finalize method, it's likely important that it execute as normal.
continue;
}
- sink.add(new MethodSetEntry(method));
+ MethodSetEntry entry = new MethodSetEntry(method);
+ if (seenFinalMethods.contains(entry)) {
+ // This method is final in a child class.
+ // We can't override it.
+ continue;
+ }
+ sink.add(entry);
}
-
+
for (Class<?> i : c.getInterfaces()) {
- getMethodsToProxy(sink, i);
+ getMethodsToProxy(sink, seenFinalMethods, i);
}
}
diff --git a/src/mockito/java/com/google/dexmaker/mockito/DexmakerMockMaker.java b/src/mockito/java/com/google/dexmaker/mockito/DexmakerMockMaker.java
index bf33342..b29c267 100644
--- a/src/mockito/java/com/google/dexmaker/mockito/DexmakerMockMaker.java
+++ b/src/mockito/java/com/google/dexmaker/mockito/DexmakerMockMaker.java
@@ -22,14 +22,16 @@
import java.lang.reflect.Proxy;
import java.util.Set;
import org.mockito.exceptions.base.MockitoException;
+import org.mockito.exceptions.stacktrace.StackTraceCleaner;
import org.mockito.invocation.MockHandler;
import org.mockito.mock.MockCreationSettings;
import org.mockito.plugins.MockMaker;
+import org.mockito.plugins.StackTraceCleanerProvider;
/**
* Generates mock instances on Android's runtime.
*/
-public final class DexmakerMockMaker implements MockMaker {
+public final class DexmakerMockMaker implements MockMaker, StackTraceCleanerProvider {
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) {
@@ -94,4 +96,15 @@
return null;
}
+
+ public StackTraceCleaner getStackTraceCleaner(final StackTraceCleaner defaultCleaner) {
+ return new StackTraceCleaner() {
+ public boolean isOut(StackTraceElement candidate) {
+ return defaultCleaner.isOut(candidate)
+ || candidate.getClassName().endsWith("_Proxy") // dexmaker class proxies
+ || candidate.getClassName().startsWith("$Proxy") // dalvik interface proxies
+ || candidate.getClassName().startsWith("com.google.dexmaker.mockito.");
+ }
+ };
+ }
}
diff --git a/src/mockito/resources/mockito-extensions/org.mockito.plugins.StackTraceCleanerProvider b/src/mockito/resources/mockito-extensions/org.mockito.plugins.StackTraceCleanerProvider
new file mode 100644
index 0000000..9f6df44
--- /dev/null
+++ b/src/mockito/resources/mockito-extensions/org.mockito.plugins.StackTraceCleanerProvider
@@ -0,0 +1 @@
+com.google.dexmaker.mockito.DexmakerMockMaker
diff --git a/src/test/java/com/google/dexmaker/AppDataDirGuesserTest.java b/src/test/java/com/google/dexmaker/AppDataDirGuesserTest.java
index 36ac383..bbceaa3 100644
--- a/src/test/java/com/google/dexmaker/AppDataDirGuesserTest.java
+++ b/src/test/java/com/google/dexmaker/AppDataDirGuesserTest.java
@@ -66,6 +66,15 @@
.shouldGive("/data/data/com.google.android.voicesearch/cache");
}
+ public void testSplitPathList() {
+ final String[] expected = { "foo", "bar" };
+ assertTrue(Arrays.equals(expected, AppDataDirGuesser.splitPathList("foo:bar")));
+ assertTrue(Arrays.equals(expected,
+ AppDataDirGuesser.splitPathList("dexPath=foo:bar")));
+ assertTrue(Arrays.equals(expected,
+ AppDataDirGuesser.splitPathList("dexPath=foo:bar,bazPath=bar:bar2")));
+ }
+
private interface TestCondition {
TestCondition withNonWriteable(String... files);
void shouldGive(String... files);
diff --git a/src/test/java/com/google/dexmaker/DexMakerTest.java b/src/test/java/com/google/dexmaker/DexMakerTest.java
index 2355916..47fb340 100644
--- a/src/test/java/com/google/dexmaker/DexMakerTest.java
+++ b/src/test/java/com/google/dexmaker/DexMakerTest.java
@@ -730,16 +730,16 @@
}
public void testIntBinaryOps() throws Exception {
- Method add = binaryOpMethod(int.class, BinaryOp.ADD);
+ Method add = binaryOpMethod(int.class, int.class, BinaryOp.ADD);
assertEquals(79, add.invoke(null, 75, 4));
- Method subtract = binaryOpMethod(int.class, BinaryOp.SUBTRACT);
+ Method subtract = binaryOpMethod(int.class, int.class, BinaryOp.SUBTRACT);
assertEquals(71, subtract.invoke(null, 75, 4));
- Method multiply = binaryOpMethod(int.class, BinaryOp.MULTIPLY);
+ Method multiply = binaryOpMethod(int.class, int.class, BinaryOp.MULTIPLY);
assertEquals(300, multiply.invoke(null, 75, 4));
- Method divide = binaryOpMethod(int.class, BinaryOp.DIVIDE);
+ Method divide = binaryOpMethod(int.class, int.class, BinaryOp.DIVIDE);
assertEquals(18, divide.invoke(null, 75, 4));
try {
divide.invoke(null, 75, 0);
@@ -748,7 +748,7 @@
assertEquals(ArithmeticException.class, expected.getCause().getClass());
}
- Method remainder = binaryOpMethod(int.class, BinaryOp.REMAINDER);
+ Method remainder = binaryOpMethod(int.class, int.class, BinaryOp.REMAINDER);
assertEquals(3, remainder.invoke(null, 75, 4));
try {
remainder.invoke(null, 75, 0);
@@ -757,117 +757,117 @@
assertEquals(ArithmeticException.class, expected.getCause().getClass());
}
- Method and = binaryOpMethod(int.class, BinaryOp.AND);
+ Method and = binaryOpMethod(int.class, int.class, BinaryOp.AND);
assertEquals(0xff000000, and.invoke(null, 0xff00ff00, 0xffff0000));
- Method or = binaryOpMethod(int.class, BinaryOp.OR);
+ Method or = binaryOpMethod(int.class, int.class, BinaryOp.OR);
assertEquals(0xffffff00, or.invoke(null, 0xff00ff00, 0xffff0000));
- Method xor = binaryOpMethod(int.class, BinaryOp.XOR);
+ Method xor = binaryOpMethod(int.class, int.class, BinaryOp.XOR);
assertEquals(0x00ffff00, xor.invoke(null, 0xff00ff00, 0xffff0000));
- Method shiftLeft = binaryOpMethod(int.class, BinaryOp.SHIFT_LEFT);
+ Method shiftLeft = binaryOpMethod(int.class, int.class, BinaryOp.SHIFT_LEFT);
assertEquals(0xcd123400, shiftLeft.invoke(null, 0xabcd1234, 8));
- Method shiftRight = binaryOpMethod(int.class, BinaryOp.SHIFT_RIGHT);
+ Method shiftRight = binaryOpMethod(int.class, int.class, BinaryOp.SHIFT_RIGHT);
assertEquals(0xffabcd12, shiftRight.invoke(null, 0xabcd1234, 8));
Method unsignedShiftRight = binaryOpMethod(int.class,
- BinaryOp.UNSIGNED_SHIFT_RIGHT);
+ int.class, BinaryOp.UNSIGNED_SHIFT_RIGHT);
assertEquals(0x00abcd12, unsignedShiftRight.invoke(null, 0xabcd1234, 8));
}
public void testLongBinaryOps() throws Exception {
- Method add = binaryOpMethod(long.class, BinaryOp.ADD);
- assertEquals(79L, add.invoke(null, 75L, 4L));
+ Method add = binaryOpMethod(long.class, long.class, BinaryOp.ADD);
+ assertEquals(30000000079L, add.invoke(null, 10000000075L, 20000000004L));
- Method subtract = binaryOpMethod(long.class, BinaryOp.SUBTRACT);
- assertEquals(71L, subtract.invoke(null, 75L, 4L));
+ Method subtract = binaryOpMethod(long.class, long.class, BinaryOp.SUBTRACT);
+ assertEquals(20000000071L, subtract.invoke(null, 30000000075L, 10000000004L));
- Method multiply = binaryOpMethod(long.class, BinaryOp.MULTIPLY);
- assertEquals(300L, multiply.invoke(null, 75L, 4L));
+ Method multiply = binaryOpMethod(long.class, long.class, BinaryOp.MULTIPLY);
+ assertEquals(-8742552812415203028L, multiply.invoke(null, 30000000075L, 20000000004L));
- Method divide = binaryOpMethod(long.class, BinaryOp.DIVIDE);
- assertEquals(18L, divide.invoke(null, 75L, 4L));
+ Method divide = binaryOpMethod(long.class, long.class, BinaryOp.DIVIDE);
+ assertEquals(-2L, divide.invoke(null, -8742552812415203028L, 4142552812415203028L));
try {
- divide.invoke(null, 75L, 0L);
+ divide.invoke(null, -8742552812415203028L, 0L);
fail();
} catch (InvocationTargetException expected) {
assertEquals(ArithmeticException.class, expected.getCause().getClass());
}
- Method remainder = binaryOpMethod(long.class, BinaryOp.REMAINDER);
- assertEquals(3L, remainder.invoke(null, 75L, 4L));
+ Method remainder = binaryOpMethod(long.class, long.class, BinaryOp.REMAINDER);
+ assertEquals(10000000004L, remainder.invoke(null, 30000000079L, 20000000075L));
try {
- remainder.invoke(null, 75L, 0L);
+ remainder.invoke(null, 30000000079L, 0L);
fail();
} catch (InvocationTargetException expected) {
assertEquals(ArithmeticException.class, expected.getCause().getClass());
}
- Method and = binaryOpMethod(long.class, BinaryOp.AND);
+ Method and = binaryOpMethod(long.class, long.class, BinaryOp.AND);
assertEquals(0xff00ff0000000000L,
and.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
- Method or = binaryOpMethod(long.class, BinaryOp.OR);
+ Method or = binaryOpMethod(long.class, long.class, BinaryOp.OR);
assertEquals(0xffffffffff00ff00L,
or.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
- Method xor = binaryOpMethod(long.class, BinaryOp.XOR);
+ Method xor = binaryOpMethod(long.class, long.class, BinaryOp.XOR);
assertEquals(0x00ff00ffff00ff00L,
xor.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
- Method shiftLeft = binaryOpMethod(long.class, BinaryOp.SHIFT_LEFT);
- assertEquals(0xcdef012345678900L, shiftLeft.invoke(null, 0xabcdef0123456789L, 8L));
+ Method shiftLeft = binaryOpMethod(long.class, int.class, BinaryOp.SHIFT_LEFT);
+ assertEquals(0xcdef012345678900L, shiftLeft.invoke(null, 0xabcdef0123456789L, 8));
- Method shiftRight = binaryOpMethod(long.class, BinaryOp.SHIFT_RIGHT);
- assertEquals(0xffabcdef01234567L, shiftRight.invoke(null, 0xabcdef0123456789L, 8L));
+ Method shiftRight = binaryOpMethod(long.class, int.class, BinaryOp.SHIFT_RIGHT);
+ assertEquals(0xffabcdef01234567L, shiftRight.invoke(null, 0xabcdef0123456789L, 8));
- Method unsignedShiftRight = binaryOpMethod(long.class,
- BinaryOp.UNSIGNED_SHIFT_RIGHT);
- assertEquals(0x00abcdef01234567L, unsignedShiftRight.invoke(null, 0xabcdef0123456789L, 8L));
+ Method unsignedShiftRight = binaryOpMethod(
+ long.class, int.class, BinaryOp.UNSIGNED_SHIFT_RIGHT);
+ assertEquals(0x00abcdef01234567L, unsignedShiftRight.invoke(null, 0xabcdef0123456789L, 8));
}
public void testFloatBinaryOps() throws Exception {
- Method add = binaryOpMethod(float.class, BinaryOp.ADD);
+ Method add = binaryOpMethod(float.class, float.class, BinaryOp.ADD);
assertEquals(6.75f, add.invoke(null, 5.5f, 1.25f));
- Method subtract = binaryOpMethod(float.class, BinaryOp.SUBTRACT);
+ Method subtract = binaryOpMethod(float.class, float.class, BinaryOp.SUBTRACT);
assertEquals(4.25f, subtract.invoke(null, 5.5f, 1.25f));
- Method multiply = binaryOpMethod(float.class, BinaryOp.MULTIPLY);
+ Method multiply = binaryOpMethod(float.class, float.class, BinaryOp.MULTIPLY);
assertEquals(6.875f, multiply.invoke(null, 5.5f, 1.25f));
- Method divide = binaryOpMethod(float.class, BinaryOp.DIVIDE);
+ Method divide = binaryOpMethod(float.class, float.class, BinaryOp.DIVIDE);
assertEquals(4.4f, divide.invoke(null, 5.5f, 1.25f));
assertEquals(Float.POSITIVE_INFINITY, divide.invoke(null, 5.5f, 0.0f));
- Method remainder = binaryOpMethod(float.class, BinaryOp.REMAINDER);
+ Method remainder = binaryOpMethod(float.class, float.class, BinaryOp.REMAINDER);
assertEquals(0.5f, remainder.invoke(null, 5.5f, 1.25f));
assertEquals(Float.NaN, remainder.invoke(null, 5.5f, 0.0f));
}
public void testDoubleBinaryOps() throws Exception {
- Method add = binaryOpMethod(double.class, BinaryOp.ADD);
+ Method add = binaryOpMethod(double.class, double.class, BinaryOp.ADD);
assertEquals(6.75, add.invoke(null, 5.5, 1.25));
- Method subtract = binaryOpMethod(double.class, BinaryOp.SUBTRACT);
+ Method subtract = binaryOpMethod(double.class, double.class, BinaryOp.SUBTRACT);
assertEquals(4.25, subtract.invoke(null, 5.5, 1.25));
- Method multiply = binaryOpMethod(double.class, BinaryOp.MULTIPLY);
+ Method multiply = binaryOpMethod(double.class, double.class, BinaryOp.MULTIPLY);
assertEquals(6.875, multiply.invoke(null, 5.5, 1.25));
- Method divide = binaryOpMethod(double.class, BinaryOp.DIVIDE);
+ Method divide = binaryOpMethod(double.class, double.class, BinaryOp.DIVIDE);
assertEquals(4.4, divide.invoke(null, 5.5, 1.25));
assertEquals(Double.POSITIVE_INFINITY, divide.invoke(null, 5.5, 0.0));
- Method remainder = binaryOpMethod(double.class, BinaryOp.REMAINDER);
+ Method remainder = binaryOpMethod(double.class, double.class, BinaryOp.REMAINDER);
assertEquals(0.5, remainder.invoke(null, 5.5, 1.25));
assertEquals(Double.NaN, remainder.invoke(null, 5.5, 0.0));
}
- private <T> Method binaryOpMethod(Class<T> valueClass, BinaryOp op)
- throws Exception {
+ private <T1, T2> Method binaryOpMethod(
+ Class<T1> valueAClass, Class<T2> valueBClass, BinaryOp op) throws Exception {
/*
* public static int binaryOp(int a, int b) {
* int result = a + b;
@@ -875,12 +875,13 @@
* }
*/
reset();
- TypeId<T> valueType = TypeId.get(valueClass);
- MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType, valueType);
+ TypeId<T1> valueAType = TypeId.get(valueAClass);
+ TypeId<T2> valueBType = TypeId.get(valueBClass);
+ MethodId<?, T1> methodId = GENERATED.getMethod(valueAType, "call", valueAType, valueBType);
Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
- Local<T> localA = code.getParameter(0, valueType);
- Local<T> localB = code.getParameter(1, valueType);
- Local<T> localResult = code.newLocal(valueType);
+ Local<T1> localA = code.getParameter(0, valueAType);
+ Local<T2> localB = code.getParameter(1, valueBType);
+ Local<T1> localResult = code.newLocal(valueAType);
code.op(op, localResult, localA, localB);
code.returnValue(localResult);
return getMethod();
diff --git a/src/test/java/com/google/dexmaker/stock/ProxyBuilderTest.java b/src/test/java/com/google/dexmaker/stock/ProxyBuilderTest.java
index 1b65ea8..62e0e6c 100644
--- a/src/test/java/com/google/dexmaker/stock/ProxyBuilderTest.java
+++ b/src/test/java/com/google/dexmaker/stock/ProxyBuilderTest.java
@@ -771,6 +771,17 @@
.build();
}
+ public static class FinalToString {
+ @Override public final String toString() {
+ return "no proxy";
+ }
+ }
+
+ // https://code.google.com/p/dexmaker/issues/detail?id=12
+ public void testFinalToString() throws Throwable {
+ assertEquals("no proxy", proxyFor(FinalToString.class).build().toString());
+ }
+
/** Simple helper to add the most common args for this test to the proxy builder. */
private <T> ProxyBuilder<T> proxyFor(Class<T> clazz) throws Exception {
return ProxyBuilder.forClass(clazz)