ProxyBuilderTest.java revision a13e8e98b64e3f5271759dac44967f1c24c76995
1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2011 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
171977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilsonpackage com.google.dexmaker.stock;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilsonimport com.google.dexmaker.DexMakerTest;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.File;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException;
228d53a06d10c6e2b96be6857aede5e4661804611eAndrew Yousefimport java.lang.reflect.Field;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.InvocationHandler;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.Method;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.UndeclaredThrowableException;
261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.Arrays;
278d53a06d10c6e2b96be6857aede5e4661804611eAndrew Yousefimport java.util.Map;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Random;
291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.concurrent.Callable;
301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.concurrent.atomic.AtomicInteger;
311977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilsonimport junit.framework.AssertionFailedError;
321977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilsonimport junit.framework.TestCase;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic class ProxyBuilderTest extends TestCase {
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private FakeInvocationHandler fakeHandler = new FakeInvocationHandler();
36054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private File versionedDxDir = new File(DexMakerTest.getDataDirectory(), "v1");
37054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
38054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void setUp() throws Exception {
39054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        super.setUp();
40054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        versionedDxDir.mkdirs();
41054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        clearVersionedDxDir();
42054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
43054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
44054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
45054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void tearDown() throws Exception {
46054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
47054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        clearVersionedDxDir();
48054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        super.tearDown();
49054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
50054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
51054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void clearVersionedDxDir() {
52054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        for (File f : versionedDxDir.listFiles()) {
53054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            f.delete();
54054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
55054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class SimpleClass {
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String simpleMethod() {
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testExampleOperation() throws Throwable {
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult("expected");
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        SimpleClass proxy = proxyFor(SimpleClass.class).build();
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("expected", proxy.simpleMethod());
67054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
68054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
69054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
70054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testExampleOperation_DexMakerCaching() throws Throwable {
71054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        fakeHandler.setFakeResult("expected");
72054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        SimpleClass proxy = proxyFor(SimpleClass.class).build();
73054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
74054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("expected", proxy.simpleMethod());
75054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
76054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Force ProxyBuilder to create a DexMaker generator and call DexMaker.generateAndLoad().
77054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
78054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
79054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        proxy = proxyFor(SimpleClass.class).build();
80054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
81054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("expected", proxy.simpleMethod());
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ConstructorTakesArguments {
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final String argument;
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public ConstructorTakesArguments(String arg) {
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            argument = arg;
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String method() {
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testConstruction_SucceedsIfCorrectArgumentsProvided() throws Throwable {
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ConstructorTakesArguments proxy = proxyFor(ConstructorTakesArguments.class)
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(String.class)
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues("hello")
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("hello", proxy.argument);
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxy.method();
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testConstruction_FailsWithWrongNumberOfArguments() throws Throwable {
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(ConstructorTakesArguments.class).build();
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {}
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testClassIsNotAccessbile_FailsWithUnsupportedOperationException() throws Exception {
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        class MethodVisibilityClass {
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(MethodVisibilityClass.class).build();
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (UnsupportedOperationException expected) {}
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static class PrivateVisibilityClass {
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testPrivateClass_FailsWithUnsupportedOperationException() throws Exception {
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(PrivateVisibilityClass.class).build();
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (UnsupportedOperationException expected) {}
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected static class ProtectedVisibilityClass {
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String foo() {
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProtectedVisibility_WorksFine() throws Exception {
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(ProtectedVisibilityClass.class).build().foo());
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasFinalMethod {
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String nonFinalMethod() {
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "non-final method";
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public final String finalMethod() {
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "final method";
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCanProxyClassesWithFinalMethods_WillNotCallTheFinalMethod() throws Throwable {
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        HasFinalMethod proxy = proxyFor(HasFinalMethod.class).build();
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("final method", proxy.finalMethod());
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxy.nonFinalMethod());
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasPrivateMethod {
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private String result() {
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "expected";
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyingPrivateMethods_NotIntercepted() throws Throwable {
164a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        HasPrivateMethod proxy = proxyFor(HasPrivateMethod.class).build();
165a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
166a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.getClass().getDeclaredMethod("result");
167a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
168a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (NoSuchMethodException expected) {
169a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
170a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
171a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
172a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("expected", proxy.result());
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasPackagePrivateMethod {
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String result() {
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
181a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public void testProxyingPackagePrivateMethods_NotIntercepted()
182a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            throws Throwable {
183a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        HasPackagePrivateMethod proxy = proxyFor(HasPackagePrivateMethod.class)
184a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin                .build();
185a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
186a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.getClass().getDeclaredMethod("result");
187a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
188a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (NoSuchMethodException expected) {
189a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
190a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
191a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
192a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
193a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.result();
194a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
195a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (AssertionFailedError expected) {
196a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
197a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasProtectedMethod {
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        protected String result() {
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyingProtectedMethods_AreIntercepted() throws Throwable {
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(HasProtectedMethod.class).build().result());
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
210a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyParentClass {
211a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        String someMethod() {
212a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "package";
213a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
214a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
215a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
216a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyChildClassWithProtectedMethod extends MyParentClass {
217a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        @Override
218a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        protected String someMethod() {
219a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "protected";
220a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
221a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
222a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
223a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyChildClassWithPublicMethod extends MyParentClass {
224a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        @Override
225a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        public String someMethod() {
226a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "public";
227a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
228a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
229a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
230a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public void testProxying_ClassHierarchy() throws Throwable {
231a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("package", proxyFor(MyParentClass.class).build().someMethod());
232a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("fake result", proxyFor(MyChildClassWithProtectedMethod.class).build().someMethod());
233a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("fake result", proxyFor(MyChildClassWithPublicMethod.class).build().someMethod());
234a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
235a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasVoidMethod {
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void dangerousMethod() {
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testVoidMethod_ShouldNotThrowRuntimeException() throws Throwable {
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HasVoidMethod.class).build().dangerousMethod();
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testObjectMethodsAreAlsoProxied() throws Throwable {
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object proxy = proxyFor(Object.class).build();
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult("mystring");
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("mystring", proxy.toString());
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(-1);
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, proxy.hashCode());
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(false);
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.equals(proxy));
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2561af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class AllReturnTypes {
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean getBoolean() { return true; }
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int getInt() { return 1; }
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public byte getByte() { return 2; }
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long getLong() { return 3L; }
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public short getShort() { return 4; }
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public float getFloat() { return 5f; }
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getDouble() { return 6.0; }
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public char getChar() { return 'c'; }
2651af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public int[] getIntArray() { return new int[] { 8, 9 }; }
2661af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public String[] getStringArray() { return new String[] { "d", "e" }; }
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2691af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testAllReturnTypes() throws Throwable {
2701af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        AllReturnTypes proxy = proxyFor(AllReturnTypes.class).build();
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(false);
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.getBoolean());
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(8);
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(8, proxy.getInt());
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult((byte) 9);
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(9, proxy.getByte());
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(10L);
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10, proxy.getLong());
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult((short) 11);
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(11, proxy.getShort());
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(12f);
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(12f, proxy.getFloat());
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(13.0);
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(13.0, proxy.getDouble());
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult('z');
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('z', proxy.getChar());
2871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(new int[] { -1, -2 });
2881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("[-1, -2]", Arrays.toString(proxy.getIntArray()));
2891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(new String[] { "x", "y" });
2901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("[x, y]", Arrays.toString(proxy.getStringArray()));
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class PassThroughAllTypes {
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean getBoolean(boolean input) { return input; }
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int getInt(int input) { return input; }
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public byte getByte(byte input) { return input; }
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long getLong(long input) { return input; }
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public short getShort(short input) { return input; }
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public float getFloat(float input) { return input; }
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getDouble(double input) { return input; }
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public char getChar(char input) { return input; }
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getString(String input) { return input; }
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object getObject(Object input) { return input; }
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void getNothing() {}
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class InvokeSuperHandler implements InvocationHandler {
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return ProxyBuilder.callSuper(proxy, method, args);
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3131af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testPassThroughWorksForAllTypes() throws Exception {
3141af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        PassThroughAllTypes proxy = proxyFor(PassThroughAllTypes.class)
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(new InvokeSuperHandler())
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.getBoolean(false));
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(true, proxy.getBoolean(true));
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, proxy.getInt(0));
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, proxy.getInt(1));
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 2, proxy.getByte((byte) 2));
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 3, proxy.getByte((byte) 3));
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4L, proxy.getLong(4L));
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5L, proxy.getLong(5L));
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 6, proxy.getShort((short) 6));
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 7, proxy.getShort((short) 7));
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(8f, proxy.getFloat(8f));
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(9f, proxy.getFloat(9f));
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10.0, proxy.getDouble(10.0));
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(11.0, proxy.getDouble(11.0));
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('a', proxy.getChar('a'));
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('b', proxy.getChar('b'));
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("asdf", proxy.getString("asdf"));
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("qwer", proxy.getString("qwer"));
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, proxy.getString(null));
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object a = new Object();
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(a, proxy.getObject(a));
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, proxy.getObject(null));
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxy.getNothing();
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class ExtendsAllReturnTypes extends AllReturnTypes {
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int example() { return 0; }
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyWorksForSuperclassMethodsAlso() throws Throwable {
3471af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        ExtendsAllReturnTypes proxy = proxyFor(ExtendsAllReturnTypes.class).build();
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(99);
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.example());
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.getInt());
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.hashCode());
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasOddParams {
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long method(int first, Integer second) {
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testMixingBoxedAndUnboxedParams() throws Throwable {
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        HasOddParams proxy = proxyFor(HasOddParams.class).build();
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(99L);
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99L, proxy.method(1, Integer.valueOf(2)));
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class SingleInt {
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getString(int value) {
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSinglePrimitiveParameter() throws Throwable {
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        InvocationHandler handler = new InvocationHandler() {
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return "asdf" + ((Integer) args[0]).intValue();
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        };
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("asdf1", proxyFor(SingleInt.class).handler(handler).build().getString(1));
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class TwoConstructors {
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final String string;
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public TwoConstructors() {
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            string = "no-arg";
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public TwoConstructors(boolean unused) {
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            string = "one-arg";
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testNoConstructorArguments_CallsNoArgConstructor() throws Throwable {
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TwoConstructors twoConstructors = proxyFor(TwoConstructors.class).build();
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("no-arg", twoConstructors.string);
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testWithoutInvocationHandler_ThrowsIllegalArgumentException() throws Throwable {
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ProxyBuilder.forClass(TwoConstructors.class)
401ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson                    .dexCache(DexMakerTest.getDataDirectory())
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .build();
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {}
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HardToConstructCorrectly {
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly() { fail(); }
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Runnable ignored) { fail(); }
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Exception ignored) { fail(); }
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Boolean ignored) { /* safe */ }
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Integer ignored) { fail(); }
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_WorksIfYouSpecifyTheConstructorCorrectly() throws Throwable {
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HardToConstructCorrectly.class)
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(Boolean.class)
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues(true)
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_EvenWorksWhenArgsAreAmbiguous() throws Throwable {
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HardToConstructCorrectly.class)
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(Boolean.class)
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues(new Object[] { null })
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_DoesNotInferTypesFromValues() throws Throwable {
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(HardToConstructCorrectly.class)
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .constructorArgValues(true)
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .build();
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {}
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDefaultProxyHasSuperMethodToAccessOriginal() throws Exception {
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object objectProxy = proxyFor(Object.class).build();
4401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertNotNull(objectProxy.getClass().getMethod("super$hashCode$int"));
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class PrintsOddAndValue {
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String method(int value) {
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "odd " + value;
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSometimesDelegateToSuper() throws Exception {
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        InvocationHandler delegatesOddValues = new InvocationHandler() {
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (method.getName().equals("method")) {
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int intValue = ((Integer) args[0]).intValue();
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (intValue % 2 == 0) {
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        return "even " + intValue;
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return ProxyBuilder.callSuper(proxy, method, args);
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        };
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        PrintsOddAndValue proxy = proxyFor(PrintsOddAndValue.class)
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(delegatesOddValues)
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("even 0", proxy.method(0));
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("odd 1", proxy.method(1));
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("even 2", proxy.method(2));
467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("odd 3", proxy.method(3));
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
4691af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
4701af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testCallSuperThrows() throws Exception {
4711af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler handler = new InvocationHandler() {
4721af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
4731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return ProxyBuilder.callSuper(o, method, objects);
4741af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
4751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
4761af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
4771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooThrows fooThrows = proxyFor(FooThrows.class)
4781af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(handler)
4791af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
4801af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
4811af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
4821af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fooThrows.foo();
4831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
4841af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (IllegalStateException expected) {
4851af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            assertEquals("boom!", expected.getMessage());
4861af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
4871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
4881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
4891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class FooThrows {
4901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public void foo() {
4911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            throw new IllegalStateException("boom!");
4921af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
4931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class DoubleReturn {
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getValue() {
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 2.0;
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testUnboxedResult() throws Exception {
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.fakeResult = 2.0;
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(2.0, proxyFor(DoubleReturn.class).build().getValue());
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static void staticMethod() {
507579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDoesNotOverrideStaticMethods() throws Exception {
510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Method should exist on this test class itself.
511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ProxyBuilderTest.class.getDeclaredMethod("staticMethod");
512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Method should not exist on the subclass.
513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(ProxyBuilderTest.class).build().getClass().getDeclaredMethod("staticMethod");
515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (NoSuchMethodException expected) {}
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testIllegalCacheDirectory() throws Exception {
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
5212e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson          proxyFor(ProxyForIllegalCacheDirectory.class)
5222e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson                  .dexCache(new File("/poop/"))
5232e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson                  .build();
524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson          fail();
5251977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilson        } catch (IOException expected) {
5261977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilson        }
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
5292e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    public static class ProxyForIllegalCacheDirectory {
5302e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    }
5312e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testInvalidConstructorSpecification() throws Exception {
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(Object.class)
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .constructorArgTypes(String.class, Boolean.class)
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .constructorArgValues("asdf", true)
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .build();
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {}
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static abstract class AbstractClass {
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public abstract Object getValue();
544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testAbstractClassBehaviour() throws Exception {
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(AbstractClass.class).build().getValue());
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasDeclaredException {
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasDeclaredException() throws IOException {
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IOException();
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasRuntimeException {
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasRuntimeException() {
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException("my message");
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasError {
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasError() {
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new Error("my message again");
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testParentConstructorThrowsDeclaredException() throws Exception {
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasDeclaredException.class).build();
571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (UndeclaredThrowableException expected) {
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertTrue(expected.getCause() instanceof IOException);
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasRuntimeException.class).build();
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (RuntimeException expected) {
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals("my message", expected.getMessage());
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasError.class).build();
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (Error expected) {
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals("my message again", expected.getMessage());
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testGetInvocationHandler_NormalOperation() throws Exception {
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object proxy = proxyFor(Object.class).build();
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(fakeHandler, ProxyBuilder.getInvocationHandler(proxy));
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testGetInvocationHandler_NotAProxy() {
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ProxyBuilder.getInvocationHandler(new Object());
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {}
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ReturnsObject {
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object getValue() {
603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new Object();
604579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ReturnsString extends ReturnsObject {
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getValue() {
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "a string";
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCovariantReturnTypes_NormalBehaviour() throws Exception {
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String expected = "some string";
616579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(expected);
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(expected, proxyFor(ReturnsObject.class).build().getValue());
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(expected, proxyFor(ReturnsString.class).build().getValue());
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCovariantReturnTypes_WrongReturnType() throws Exception {
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fakeHandler.setFakeResult(new Object());
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(ReturnsString.class).build().getValue();
625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (ClassCastException expected) {}
627579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6292e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    public void testCaching() throws Exception {
63031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass a = proxyFor(SimpleClass.class).build();
63131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass b = proxyFor(SimpleClass.class).build();
63231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertSame(a.getClass(), b.getClass());
6332e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    }
6342e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
6352e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    public void testCachingWithMultipleConstructors() throws Exception {
63631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors a = ProxyBuilder.forClass(HasMultipleConstructors.class)
63731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes()
63831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues()
63931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
64031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
64131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("no args", a.calledConstructor);
64231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors b = ProxyBuilder.forClass(HasMultipleConstructors.class)
64331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes(int.class)
64431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues(2)
64531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
64631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
64731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("int 2", b.calledConstructor);
64831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(a.getClass(), b.getClass());
64931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
65031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors c = ProxyBuilder.forClass(HasMultipleConstructors.class)
65131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes(Integer.class)
65231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues(3)
65331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
65431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
65531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("Integer 3", c.calledConstructor);
65631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(a.getClass(), c.getClass());
6572e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    }
6582e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
65931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    public static class HasMultipleConstructors {
66031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        private final String calledConstructor;
66131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors() {
66231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "no args";
66331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
66431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors(int b) {
66531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "int " + b;
66631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
66731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors(Integer c) {
66831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "Integer " + c;
66931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
67031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    }
67131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
67231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    public void testClassNotCachedWithDifferentParentClassLoaders() throws Exception {
673b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        ClassLoader classLoaderA = newPathClassLoader();
67431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass a = proxyFor(SimpleClass.class)
67531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .parentClassLoader(classLoaderA)
67631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .build();
67731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(classLoaderA, a.getClass().getClassLoader().getParent());
67831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
679b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        ClassLoader classLoaderB = newPathClassLoader();
68031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass b = proxyFor(SimpleClass.class)
68131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .parentClassLoader(classLoaderB)
68231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .build();
68331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(classLoaderB, b.getClass().getClassLoader().getParent());
68431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
68531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertTrue(a.getClass() != b.getClass());
686579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
6871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
6881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testAbstractClassWithUndeclaredInterfaceMethod() throws Throwable {
6891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        DeclaresInterface declaresInterface = proxyFor(DeclaresInterface.class)
6901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
6911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", declaresInterface.call());
6921af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
6931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            ProxyBuilder.callSuper(declaresInterface, Callable.class.getMethod("call"));
6941af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
6951af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (AbstractMethodError expected) {
6961af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
6971af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
6981af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
6991af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static abstract class DeclaresInterface implements Callable<String> {
7001af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7011af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7021af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementingInterfaces() throws Throwable {
7031af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        SimpleClass simpleClass = proxyFor(SimpleClass.class)
7041af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7051af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Comparable.class)
7061af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7071af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", simpleClass.simpleMethod());
7081af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7091af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Callable<?> asCallable = (Callable<?>) simpleClass;
7101af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", asCallable.call());
7111af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7121af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Comparable<?> asComparable = (Comparable<?>) simpleClass;
7131af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.fakeResult = 3;
7141af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, asComparable.compareTo(null));
7151af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7161af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testCallSuperWithInterfaceMethod() throws Throwable {
7181af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        SimpleClass simpleClass = proxyFor(SimpleClass.class)
7191af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
7221af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            ProxyBuilder.callSuper(simpleClass, Callable.class.getMethod("call"));
7231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
7241af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (AbstractMethodError expected) {
7251af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (NoSuchMethodError expected) {
7261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
7271af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
728579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
7291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementInterfaceCallingThroughConcreteClass() throws Throwable {
7301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler invocationHandler = new InvocationHandler() {
7311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
7321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                assertEquals("a", ProxyBuilder.callSuper(o, method, objects));
7331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return "b";
7341af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
7351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
7361af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        ImplementsCallable proxy = proxyFor(ImplementsCallable.class)
7371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(invocationHandler)
7391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("b", proxy.call());
7411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", ProxyBuilder.callSuper(
7421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                proxy, ImplementsCallable.class.getMethod("call")));
7431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    /**
7461af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * This test is a bit unintuitive because it exercises the synthetic methods
7471af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * that support covariant return types. Calling 'Object call()' on the
7481af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * interface bridges to 'String call()', and so the super method appears to
7491af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * also be proxied.
7501af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     */
7511af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementInterfaceCallingThroughInterface() throws Throwable {
7521af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        final AtomicInteger count = new AtomicInteger();
7531af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7541af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler invocationHandler = new InvocationHandler() {
7551af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
7561af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                count.incrementAndGet();
7571af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return ProxyBuilder.callSuper(o, method, objects);
7581af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
7591af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
7601af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7611af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Callable<?> proxy = proxyFor(ImplementsCallable.class)
7621af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7631af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(invocationHandler)
7641af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7651af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7661af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        // the invocation handler is called twice!
7671af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", proxy.call());
7681af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(2, count.get());
7691af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7701af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        // the invocation handler is called, even though this is a callSuper() call!
7711af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", ProxyBuilder.callSuper(proxy, Callable.class.getMethod("call")));
7721af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, count.get());
7731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7741af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class ImplementsCallable implements Callable<String> {
7761af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public String call() throws Exception {
7771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            return "a";
7781af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
7791af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7801af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7811af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    /**
7821af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * This test shows that our generated proxies follow the bytecode convention
7831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * where methods can have the same name but unrelated return types. This is
7841af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * different from javac's convention where return types must be assignable
7851af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * in one direction or the other.
7861af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     */
7871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testInterfacesSameNamesDifferentReturnTypes() throws Throwable {
7881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler handler = new InvocationHandler() {
7891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
7901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                if (method.getReturnType() == void.class) {
7911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return null;
7921af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else if (method.getReturnType() == String.class) {
7931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return "X";
7941af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else if (method.getReturnType() == int.class) {
7951af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return 3;
7961af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else {
7971af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    throw new AssertionFailedError();
7981af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                }
7991af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
8001af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
8011af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8021af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Object o = proxyFor(Object.class)
8031af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(FooReturnsVoid.class, FooReturnsString.class, FooReturnsInt.class)
8041af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(handler)
8051af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
8061af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8071af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsVoid a = (FooReturnsVoid) o;
8081af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        a.foo();
8091af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8101af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsString b = (FooReturnsString) o;
8111af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("X", b.foo());
8121af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8131af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt c = (FooReturnsInt) o;
8141af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, c.foo());
8151af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8161af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testInterfacesSameNamesSameReturnType() throws Throwable {
8181af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Object o = proxyFor(Object.class)
8191af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(FooReturnsInt.class, FooReturnsInt2.class)
8201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
8211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8221af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(3);
8231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8241af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt a = (FooReturnsInt) o;
8251af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, a.foo());
8261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8271af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt2 b = (FooReturnsInt2) o;
8281af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, b.foo());
8291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsVoid {
8321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        void foo();
8331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8341af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsString {
8361af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        String foo();
8371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsInt {
8401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        int foo();
8411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsInt2 {
8441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        int foo();
8451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8461af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
847b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson    private ClassLoader newPathClassLoader() throws Exception {
848b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        return (ClassLoader) Class.forName("dalvik.system.PathClassLoader")
849b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson                .getConstructor(String.class, ClassLoader.class)
850b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson                .newInstance("", getClass().getClassLoader());
851b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson
852b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson    }
853b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson
854579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSubclassOfRandom() throws Exception {
855579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(Random.class)
856579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(new InvokeSuperHandler())
857579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
858579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
859579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
86095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    public static class FinalToString {
86195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        @Override public final String toString() {
86295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy            return "no proxy";
86395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        }
86495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    }
86595689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy
86695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    // https://code.google.com/p/dexmaker/issues/detail?id=12
86795689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    public void testFinalToString() throws Throwable {
86895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals("no proxy", proxyFor(FinalToString.class).build().toString());
86995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    }
87095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy
871ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public static class FinalInterfaceImpl implements FooReturnsString {
872ab38abdf175554643d40b889d58d283d358218c3Samuel Tan        @Override public final String foo() {
873ab38abdf175554643d40b889d58d283d358218c3Samuel Tan          return "no proxy";
874ab38abdf175554643d40b889d58d283d358218c3Samuel Tan        }
875ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
876ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
877ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public static class ExtenstionOfFinalInterfaceImpl extends FinalInterfaceImpl
878ab38abdf175554643d40b889d58d283d358218c3Samuel Tan            implements FooReturnsString {
879ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
880ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
881ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public void testFinalInterfaceImpl() throws Throwable {
882ab38abdf175554643d40b889d58d283d358218c3Samuel Tan        assertEquals("no proxy", proxyFor(ExtenstionOfFinalInterfaceImpl.class).build().foo());
883ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
884ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
885a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    // https://code.google.com/p/dexmaker/issues/detail?id=9
886a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public interface DeclaresMethodLate {
887a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        void thisIsTheMethod();
888a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
889a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
890a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MakesMethodFinalEarly {
891a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        public final void thisIsTheMethod() {}
892a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
893a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
894a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class YouDoNotChooseYourFamily
895a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            extends MakesMethodFinalEarly implements DeclaresMethodLate {}
896a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
897a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public void testInterfaceMethodMadeFinalBeforeActualInheritance() throws Exception {
898a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        proxyFor(YouDoNotChooseYourFamily.class).build();
899a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
900a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
901579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** Simple helper to add the most common args for this test to the proxy builder. */
902579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <T> ProxyBuilder<T> proxyFor(Class<T> clazz) throws Exception {
903579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return ProxyBuilder.forClass(clazz)
904579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(fakeHandler)
905ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson                .dexCache(DexMakerTest.getDataDirectory());
906579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
907579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
908579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static class FakeInvocationHandler implements InvocationHandler {
909579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private Object fakeResult = "fake result";
910579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
911579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
912579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return fakeResult;
913579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
914579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
915579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void setFakeResult(Object result) {
916579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fakeResult = result;
917579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
918579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
919054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
920054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class TestOrderingClass {
921054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int returnsInt() {
922054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 0;
923054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
924054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
925054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int returnsInt(int param1, int param2) {
926054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1;
927054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
928054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
929054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String returnsString() {
930054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "string";
931054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
932054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
933054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public boolean returnsBoolean() {
934054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return false;
935054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
936054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
937054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public double returnsDouble() {
938054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1.0;
939054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
940054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
941054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public Object returnsObject() {
942054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return new Object();
943054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
944054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
945054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
946054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    @SuppressWarnings("unchecked")
947054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testMethodsGeneratedInDeterministicOrder() throws Exception {
948054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Grab the static methods array from the original class.
949054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods1 = getMethodsForProxyClass(TestOrderingClass.class);
950054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(methods1);
951054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
952054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Clear ProxyBuilder's in-memory cache of classes. This will force
953054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // it to rebuild the class and reset the static methods field.
954054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Map<Class<?>, Class<?>> map = getGeneratedProxyClasses();
955054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(map);
956054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        map.clear();
957054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
958054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Grab the static methods array from the rebuilt class.
959054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods2 = getMethodsForProxyClass(TestOrderingClass.class);
960054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(methods2);
961054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
962054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Ensure that the two method arrays are equal.
963054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertTrue(Arrays.equals(methods1, methods2));
964054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
965054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
966054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testOrderingClassWithDexMakerCaching() throws Exception {
967054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        doTestOrderClassWithDexMakerCaching();
968054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
969054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Force ProxyBuilder to call DexMaker.generateAndLoad()
970054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
971054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
972054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        doTestOrderClassWithDexMakerCaching();
973054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
974054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
975054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void doTestOrderClassWithDexMakerCaching() throws Exception {
976054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        TestOrderingClass proxy = ProxyBuilder.forClass(TestOrderingClass.class)
977054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
978054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
979054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
980054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(0, proxy.returnsInt());
981054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(1, proxy.returnsInt(1, 1));
982054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("string", proxy.returnsString());
983054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertFalse(proxy.returnsBoolean());
984054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(1.0, proxy.returnsDouble());
985054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(proxy.returnsObject());
986054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
987054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
988054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
989054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    // Returns static methods array from a proxy class.
990054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private Method[] getMethodsForProxyClass(Class<?> parentClass) throws Exception {
991054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Class<?> proxyClass = proxyFor(parentClass).buildProxyClass();
992054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods = null;
993054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        for (Field f : proxyClass.getDeclaredFields()) {
994054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            if (Method[].class.isAssignableFrom(f.getType())) {
995054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                f.setAccessible(true);
996054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                methods = (Method[]) f.get(null);
997054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                break;
998054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            }
999054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1000054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1001054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        return methods;
1002054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1003054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1004054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private Map<Class<?>, Class<?>> getGeneratedProxyClasses() throws Exception {
1005054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Field mapField = ProxyBuilder.class
1006054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .getDeclaredField("generatedProxyClasses");
1007054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        mapField.setAccessible(true);
1008054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        return (Map<Class<?>, Class<?>>) mapField.get(null);
1009054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1010054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1011054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class ConcreteClassA implements FooReturnsInt {
1012054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // from FooReturnsInt
1013054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int foo() {
1014054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1;
1015054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1016054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1017054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // not from FooReturnsInt
1018054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String bar() {
1019054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "bar";
1020054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1021054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1022054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1023054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class ConcreteClassB implements FooReturnsInt {
1024054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // from FooReturnsInt
1025054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int foo() {
1026054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 0;
1027054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1028054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1029054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // not from FooReturnsInt
1030054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String bar() {
1031054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "bahhr";
1032054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1033054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1034054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1035054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testTwoClassesWithIdenticalMethodSignatures_DexMakerCaching() throws Exception {
1036054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        ConcreteClassA proxyA = ProxyBuilder.forClass(ConcreteClassA.class)
1037054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
1038054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
1039054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
1040054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(1, proxyA.foo());
1041054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("bar", proxyA.bar());
1042054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
1043054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1044054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        ConcreteClassB proxyB = ProxyBuilder.forClass(ConcreteClassB.class)
1045054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
1046054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
1047054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
1048054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(0, proxyB.foo());
1049054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("bahhr", proxyB.bar());
1050054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(4, versionedDxDir.listFiles().length);
1051054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1052579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
1053