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
17b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinpackage com.android.dx.stock;
18b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
19b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport com.android.dx.DexMakerTest;
20b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport junit.framework.AssertionFailedError;
21b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport org.junit.After;
22b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport org.junit.Before;
23b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport org.junit.Test;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.File;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException;
278d53a06d10c6e2b96be6857aede5e4661804611eAndrew Yousefimport java.lang.reflect.Field;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.InvocationHandler;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.Method;
30171f097997993b84053f643dc275ce66364315caPhilip P. Moltmannimport java.lang.reflect.Modifier;
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.UndeclaredThrowableException;
32171f097997993b84053f643dc275ce66364315caPhilip P. Moltmannimport java.util.ArrayList;
331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.Arrays;
348d53a06d10c6e2b96be6857aede5e4661804611eAndrew Yousefimport java.util.Map;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Random;
361af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.concurrent.Callable;
371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.concurrent.atomic.AtomicInteger;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
39b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.util.TestUtil.DELTA_DOUBLE;
40b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.util.TestUtil.DELTA_FLOAT;
41b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.assertFalse;
42b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.assertNotNull;
43b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.assertSame;
44b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.assertTrue;
45b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.fail;
46b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static org.junit.Assert.assertEquals;
47b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
48b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinpublic class ProxyBuilderTest {
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private FakeInvocationHandler fakeHandler = new FakeInvocationHandler();
50054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private File versionedDxDir = new File(DexMakerTest.getDataDirectory(), "v1");
51054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
52b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Before
53054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void setUp() throws Exception {
54b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        versionedDxDir.mkdirs();
55054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        clearVersionedDxDir();
56054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
57054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
58054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
59b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @After
60054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void tearDown() throws Exception {
61054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
62054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        clearVersionedDxDir();
63054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
64054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
65054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void clearVersionedDxDir() {
66b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        for (File file : versionedDxDir.listFiles()) {
67b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin            file.delete();
68054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
69054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class SimpleClass {
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String simpleMethod() {
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
77b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static class ExampleClass {
78b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        public String exampleMethod() {
79b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin            throw new AssertionFailedError();
80b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        }
81b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    }
82b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
83b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static class ExampleOperationClass {
84b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        public String exampleMethod() {
85b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin            throw new AssertionFailedError();
86b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        }
87b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    }
88b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
89b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testExampleOperation() throws Throwable {
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult("expected");
92b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        ExampleClass proxy = proxyFor(ExampleClass.class).build();
93b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals("expected", proxy.exampleMethod());
94054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
95054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
96054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
97b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
98054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testExampleOperation_DexMakerCaching() throws Throwable {
99054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        fakeHandler.setFakeResult("expected");
100b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        ExampleOperationClass proxy = proxyFor(ExampleOperationClass.class).build();
101054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
102b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals("expected", proxy.exampleMethod());
103054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
104054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Force ProxyBuilder to create a DexMaker generator and call DexMaker.generateAndLoad().
105054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
106054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
107b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxy = proxyFor(ExampleOperationClass.class).build();
108054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
109b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals("expected", proxy.exampleMethod());
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ConstructorTakesArguments {
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final String argument;
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public ConstructorTakesArguments(String arg) {
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            argument = arg;
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String method() {
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
124b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testConstruction_SucceedsIfCorrectArgumentsProvided() throws Throwable {
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ConstructorTakesArguments proxy = proxyFor(ConstructorTakesArguments.class)
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(String.class)
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues("hello")
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("hello", proxy.argument);
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxy.method();
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
134b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IllegalArgumentException.class)
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testConstruction_FailsWithWrongNumberOfArguments() throws Throwable {
136b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(ConstructorTakesArguments.class).build();
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
139b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = UnsupportedOperationException.class)
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testClassIsNotAccessbile_FailsWithUnsupportedOperationException() throws Exception {
141b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        class MethodVisibilityClass {}
142b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(MethodVisibilityClass.class).build();
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
145b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    private static class PrivateVisibilityClass {}
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
147b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = UnsupportedOperationException.class)
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testPrivateClass_FailsWithUnsupportedOperationException() throws Exception {
149b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(PrivateVisibilityClass.class).build();
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected static class ProtectedVisibilityClass {
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String foo() {
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
158b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProtectedVisibility_WorksFine() throws Exception {
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(ProtectedVisibilityClass.class).build().foo());
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasFinalMethod {
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String nonFinalMethod() {
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "non-final method";
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public final String finalMethod() {
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "final method";
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
173b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCanProxyClassesWithFinalMethods_WillNotCallTheFinalMethod() throws Throwable {
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        HasFinalMethod proxy = proxyFor(HasFinalMethod.class).build();
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("final method", proxy.finalMethod());
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxy.nonFinalMethod());
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasPrivateMethod {
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private String result() {
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "expected";
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
186b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyingPrivateMethods_NotIntercepted() throws Throwable {
188a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        HasPrivateMethod proxy = proxyFor(HasPrivateMethod.class).build();
189a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
190a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.getClass().getDeclaredMethod("result");
191a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
192a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (NoSuchMethodException expected) {
193a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
194a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
195a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
196a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("expected", proxy.result());
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasPackagePrivateMethod {
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String result() {
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
205a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public void testProxyingPackagePrivateMethods_NotIntercepted()
206a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            throws Throwable {
207a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        HasPackagePrivateMethod proxy = proxyFor(HasPackagePrivateMethod.class)
208a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin                .build();
209a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
210a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.getClass().getDeclaredMethod("result");
211a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
212a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (NoSuchMethodException expected) {
213a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
214a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
215a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
216a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
217a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.result();
218a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
219a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (AssertionFailedError expected) {
220a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
221a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasProtectedMethod {
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        protected String result() {
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
230b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyingProtectedMethods_AreIntercepted() throws Throwable {
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(HasProtectedMethod.class).build().result());
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
235a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyParentClass {
236a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        String someMethod() {
237a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "package";
238a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
239a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
240a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
241a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyChildClassWithProtectedMethod extends MyParentClass {
242a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        @Override
243a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        protected String someMethod() {
244a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "protected";
245a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
246a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
247a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
248a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyChildClassWithPublicMethod extends MyParentClass {
249a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        @Override
250a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        public String someMethod() {
251a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "public";
252a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
253a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
254a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
255b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
256a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public void testProxying_ClassHierarchy() throws Throwable {
257a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("package", proxyFor(MyParentClass.class).build().someMethod());
258a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("fake result", proxyFor(MyChildClassWithProtectedMethod.class).build().someMethod());
259a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("fake result", proxyFor(MyChildClassWithPublicMethod.class).build().someMethod());
260a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
261a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasVoidMethod {
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void dangerousMethod() {
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
268b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testVoidMethod_ShouldNotThrowRuntimeException() throws Throwable {
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HasVoidMethod.class).build().dangerousMethod();
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
273b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
274b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @SuppressWarnings("EqualsWithItself")
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testObjectMethodsAreAlsoProxied() throws Throwable {
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object proxy = proxyFor(Object.class).build();
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult("mystring");
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("mystring", proxy.toString());
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(-1);
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, proxy.hashCode());
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(false);
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.equals(proxy));
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2851af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class AllReturnTypes {
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean getBoolean() { return true; }
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int getInt() { return 1; }
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public byte getByte() { return 2; }
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long getLong() { return 3L; }
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public short getShort() { return 4; }
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public float getFloat() { return 5f; }
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getDouble() { return 6.0; }
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public char getChar() { return 'c'; }
2941af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public int[] getIntArray() { return new int[] { 8, 9 }; }
2951af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public String[] getStringArray() { return new String[] { "d", "e" }; }
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
298b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
2991af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testAllReturnTypes() throws Throwable {
3001af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        AllReturnTypes proxy = proxyFor(AllReturnTypes.class).build();
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(false);
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.getBoolean());
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(8);
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(8, proxy.getInt());
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult((byte) 9);
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(9, proxy.getByte());
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(10L);
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10, proxy.getLong());
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult((short) 11);
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(11, proxy.getShort());
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(12f);
312b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(12f, proxy.getFloat(), DELTA_FLOAT);
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(13.0);
314b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(13.0, proxy.getDouble(), DELTA_FLOAT);
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult('z');
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('z', proxy.getChar());
3171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(new int[] { -1, -2 });
3181af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("[-1, -2]", Arrays.toString(proxy.getIntArray()));
3191af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(new String[] { "x", "y" });
3201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("[x, y]", Arrays.toString(proxy.getStringArray()));
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class PassThroughAllTypes {
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean getBoolean(boolean input) { return input; }
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int getInt(int input) { return input; }
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public byte getByte(byte input) { return input; }
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long getLong(long input) { return input; }
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public short getShort(short input) { return input; }
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public float getFloat(float input) { return input; }
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getDouble(double input) { return input; }
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public char getChar(char input) { return input; }
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getString(String input) { return input; }
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object getObject(Object input) { return input; }
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void getNothing() {}
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class InvokeSuperHandler implements InvocationHandler {
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return ProxyBuilder.callSuper(proxy, method, args);
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
343b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
3441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testPassThroughWorksForAllTypes() throws Exception {
3451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        PassThroughAllTypes proxy = proxyFor(PassThroughAllTypes.class)
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(new InvokeSuperHandler())
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.getBoolean(false));
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(true, proxy.getBoolean(true));
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, proxy.getInt(0));
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, proxy.getInt(1));
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 2, proxy.getByte((byte) 2));
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 3, proxy.getByte((byte) 3));
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4L, proxy.getLong(4L));
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5L, proxy.getLong(5L));
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 6, proxy.getShort((short) 6));
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 7, proxy.getShort((short) 7));
358b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(8f, proxy.getFloat(8f), DELTA_FLOAT);
359b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(9f, proxy.getFloat(9f), DELTA_FLOAT);
360b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(10.0, proxy.getDouble(10.0), DELTA_DOUBLE);
361b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(11.0, proxy.getDouble(11.0), DELTA_DOUBLE);
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('a', proxy.getChar('a'));
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('b', proxy.getChar('b'));
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("asdf", proxy.getString("asdf"));
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("qwer", proxy.getString("qwer"));
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, proxy.getString(null));
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object a = new Object();
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(a, proxy.getObject(a));
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, proxy.getObject(null));
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxy.getNothing();
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class ExtendsAllReturnTypes extends AllReturnTypes {
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int example() { return 0; }
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
377b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyWorksForSuperclassMethodsAlso() throws Throwable {
3791af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        ExtendsAllReturnTypes proxy = proxyFor(ExtendsAllReturnTypes.class).build();
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(99);
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.example());
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.getInt());
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.hashCode());
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasOddParams {
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long method(int first, Integer second) {
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
392b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testMixingBoxedAndUnboxedParams() throws Throwable {
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        HasOddParams proxy = proxyFor(HasOddParams.class).build();
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(99L);
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99L, proxy.method(1, Integer.valueOf(2)));
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class SingleInt {
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getString(int value) {
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
405b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSinglePrimitiveParameter() throws Throwable {
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        InvocationHandler handler = new InvocationHandler() {
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return "asdf" + ((Integer) args[0]).intValue();
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        };
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("asdf1", proxyFor(SingleInt.class).handler(handler).build().getString(1));
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class TwoConstructors {
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final String string;
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public TwoConstructors() {
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            string = "no-arg";
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public TwoConstructors(boolean unused) {
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            string = "one-arg";
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
427b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testNoConstructorArguments_CallsNoArgConstructor() throws Throwable {
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TwoConstructors twoConstructors = proxyFor(TwoConstructors.class).build();
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("no-arg", twoConstructors.string);
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
433b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testWithoutInvocationHandler_ThrowsIllegalArgumentException() throws Throwable {
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ProxyBuilder.forClass(TwoConstructors.class)
437ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson                    .dexCache(DexMakerTest.getDataDirectory())
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .build();
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {}
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HardToConstructCorrectly {
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly() { fail(); }
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Runnable ignored) { fail(); }
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Exception ignored) { fail(); }
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Boolean ignored) { /* safe */ }
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Integer ignored) { fail(); }
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
451b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_WorksIfYouSpecifyTheConstructorCorrectly() throws Throwable {
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HardToConstructCorrectly.class)
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(Boolean.class)
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues(true)
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
459b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_EvenWorksWhenArgsAreAmbiguous() throws Throwable {
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HardToConstructCorrectly.class)
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(Boolean.class)
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues(new Object[] { null })
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
467b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IllegalArgumentException.class)
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_DoesNotInferTypesFromValues() throws Throwable {
469b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(HardToConstructCorrectly.class)
470b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .constructorArgValues(true)
471b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .build();
472579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
474b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDefaultProxyHasSuperMethodToAccessOriginal() throws Exception {
476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object objectProxy = proxyFor(Object.class).build();
4771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertNotNull(objectProxy.getClass().getMethod("super$hashCode$int"));
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class PrintsOddAndValue {
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String method(int value) {
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "odd " + value;
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
486b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSometimesDelegateToSuper() throws Exception {
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        InvocationHandler delegatesOddValues = new InvocationHandler() {
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (method.getName().equals("method")) {
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int intValue = ((Integer) args[0]).intValue();
492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (intValue % 2 == 0) {
493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        return "even " + intValue;
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return ProxyBuilder.callSuper(proxy, method, args);
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        };
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        PrintsOddAndValue proxy = proxyFor(PrintsOddAndValue.class)
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(delegatesOddValues)
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("even 0", proxy.method(0));
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("odd 1", proxy.method(1));
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("even 2", proxy.method(2));
505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("odd 3", proxy.method(3));
506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
507b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
508b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
5091af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testCallSuperThrows() throws Exception {
5101af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler handler = new InvocationHandler() {
5111af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
5121af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return ProxyBuilder.callSuper(o, method, objects);
5131af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
5141af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
5151af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
5161af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooThrows fooThrows = proxyFor(FooThrows.class)
5171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(handler)
5181af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
5191af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
5201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
5211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fooThrows.foo();
5221af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
5231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (IllegalStateException expected) {
5241af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            assertEquals("boom!", expected.getMessage());
5251af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
5261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
527b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
5281af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class FooThrows {
5291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public void foo() {
5301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            throw new IllegalStateException("boom!");
5311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
5321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class DoubleReturn {
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getValue() {
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 2.0;
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
540b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testUnboxedResult() throws Exception {
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.fakeResult = 2.0;
543b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(2.0, proxyFor(DoubleReturn.class).build().getValue(), DELTA_DOUBLE);
544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
546b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static void staticMethod() {}
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
548b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDoesNotOverrideStaticMethods() throws Exception {
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Method should exist on this test class itself.
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ProxyBuilderTest.class.getDeclaredMethod("staticMethod");
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Method should not exist on the subclass.
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(ProxyBuilderTest.class).build().getClass().getDeclaredMethod("staticMethod");
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (NoSuchMethodException expected) {}
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
559b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IOException.class)
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testIllegalCacheDirectory() throws Exception {
561b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(ProxyForIllegalCacheDirectory.class)
562b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .dexCache(new File("/poop/"))
563b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .build();
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
566b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static class ProxyForIllegalCacheDirectory {}
5672e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
568b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IllegalArgumentException.class)
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testInvalidConstructorSpecification() throws Exception {
570b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(Object.class)
571b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .constructorArgTypes(String.class, Boolean.class)
572b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .constructorArgValues("asdf", true)
573b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .build();
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static abstract class AbstractClass {
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public abstract Object getValue();
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
580b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testAbstractClassBehaviour() throws Exception {
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(AbstractClass.class).build().getValue());
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasDeclaredException {
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasDeclaredException() throws IOException {
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IOException();
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasRuntimeException {
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasRuntimeException() {
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException("my message");
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasError {
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasError() {
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new Error("my message again");
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
603b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
604579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testParentConstructorThrowsDeclaredException() throws Exception {
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasDeclaredException.class).build();
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (UndeclaredThrowableException expected) {
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertTrue(expected.getCause() instanceof IOException);
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasRuntimeException.class).build();
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (RuntimeException expected) {
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals("my message", expected.getMessage());
616579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasError.class).build();
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (Error expected) {
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals("my message again", expected.getMessage());
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
625b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testGetInvocationHandler_NormalOperation() throws Exception {
627579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object proxy = proxyFor(Object.class).build();
628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(fakeHandler, ProxyBuilder.getInvocationHandler(proxy));
629579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
630579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
631b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IllegalArgumentException.class)
632579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testGetInvocationHandler_NotAProxy() {
633b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        ProxyBuilder.getInvocationHandler(new Object());
634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ReturnsObject {
637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object getValue() {
638579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new Object();
639579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
640579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
641579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
642579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ReturnsString extends ReturnsObject {
643579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
644579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getValue() {
645579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "a string";
646579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
647579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
648579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
649b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCovariantReturnTypes_NormalBehaviour() throws Exception {
651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String expected = "some string";
652579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(expected);
653579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(expected, proxyFor(ReturnsObject.class).build().getValue());
654579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(expected, proxyFor(ReturnsString.class).build().getValue());
655579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
656579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
657b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
658579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCovariantReturnTypes_WrongReturnType() throws Exception {
659579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
660579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fakeHandler.setFakeResult(new Object());
661579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(ReturnsString.class).build().getValue();
662579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
663579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (ClassCastException expected) {}
664579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
665579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
666b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
6672e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    public void testCaching() throws Exception {
66831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass a = proxyFor(SimpleClass.class).build();
66931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass b = proxyFor(SimpleClass.class).build();
67031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertSame(a.getClass(), b.getClass());
6712e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    }
6722e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
673b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
6742e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    public void testCachingWithMultipleConstructors() throws Exception {
67531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors a = ProxyBuilder.forClass(HasMultipleConstructors.class)
67631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes()
67731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues()
67831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
67931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
68031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("no args", a.calledConstructor);
68131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors b = ProxyBuilder.forClass(HasMultipleConstructors.class)
68231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes(int.class)
68331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues(2)
68431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
68531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
68631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("int 2", b.calledConstructor);
68731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(a.getClass(), b.getClass());
68831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
68931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors c = ProxyBuilder.forClass(HasMultipleConstructors.class)
69031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes(Integer.class)
69131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues(3)
69231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
69331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
69431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("Integer 3", c.calledConstructor);
69531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(a.getClass(), c.getClass());
6962e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    }
6972e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
69831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    public static class HasMultipleConstructors {
69931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        private final String calledConstructor;
70031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors() {
70131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "no args";
70231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
70331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors(int b) {
70431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "int " + b;
70531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
70631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors(Integer c) {
70731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "Integer " + c;
70831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
70931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    }
71031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
711b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
71231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    public void testClassNotCachedWithDifferentParentClassLoaders() throws Exception {
713b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        ClassLoader classLoaderA = newPathClassLoader();
71431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass a = proxyFor(SimpleClass.class)
71531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .parentClassLoader(classLoaderA)
71631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .build();
71731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(classLoaderA, a.getClass().getClassLoader().getParent());
71831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
719b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        ClassLoader classLoaderB = newPathClassLoader();
72031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass b = proxyFor(SimpleClass.class)
72131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .parentClassLoader(classLoaderB)
72231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .build();
72331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(classLoaderB, b.getClass().getClassLoader().getParent());
72431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
72531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertTrue(a.getClass() != b.getClass());
726579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
727b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
728b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testAbstractClassWithUndeclaredInterfaceMethod() throws Throwable {
7301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        DeclaresInterface declaresInterface = proxyFor(DeclaresInterface.class)
7311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", declaresInterface.call());
7331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
7341af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            ProxyBuilder.callSuper(declaresInterface, Callable.class.getMethod("call"));
7351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
736b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        } catch (IncompatibleClassChangeError expected) {
7371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
7381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
740b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static abstract class DeclaresInterface implements Callable<String> {}
741b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
742b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementingInterfaces() throws Throwable {
7441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        SimpleClass simpleClass = proxyFor(SimpleClass.class)
7451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7461af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Comparable.class)
7471af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7481af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", simpleClass.simpleMethod());
7491af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7501af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Callable<?> asCallable = (Callable<?>) simpleClass;
7511af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", asCallable.call());
7521af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7531af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Comparable<?> asComparable = (Comparable<?>) simpleClass;
7541af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.fakeResult = 3;
7551af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, asComparable.compareTo(null));
7561af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7571af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
758b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7591af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testCallSuperWithInterfaceMethod() throws Throwable {
7601af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        SimpleClass simpleClass = proxyFor(SimpleClass.class)
7611af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7621af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7631af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
7641af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            ProxyBuilder.callSuper(simpleClass, Callable.class.getMethod("call"));
7651af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
7661af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (AbstractMethodError expected) {
7671af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (NoSuchMethodError expected) {
7681af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
7691af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
770579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
771b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7721af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementInterfaceCallingThroughConcreteClass() throws Throwable {
7731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler invocationHandler = new InvocationHandler() {
7741af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
7751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                assertEquals("a", ProxyBuilder.callSuper(o, method, objects));
7761af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return "b";
7771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
7781af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
7791af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        ImplementsCallable proxy = proxyFor(ImplementsCallable.class)
7801af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7811af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(invocationHandler)
7821af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("b", proxy.call());
7841af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", ProxyBuilder.callSuper(
7851af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                proxy, ImplementsCallable.class.getMethod("call")));
7861af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
787b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
7881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    /**
7891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * This test is a bit unintuitive because it exercises the synthetic methods
7901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * that support covariant return types. Calling 'Object call()' on the
7911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * interface bridges to 'String call()', and so the super method appears to
7921af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * also be proxied.
7931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     */
794b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7951af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementInterfaceCallingThroughInterface() throws Throwable {
7961af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        final AtomicInteger count = new AtomicInteger();
7971af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7981af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler invocationHandler = new InvocationHandler() {
7991af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
8001af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                count.incrementAndGet();
8011af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return ProxyBuilder.callSuper(o, method, objects);
8021af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
8031af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
8041af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8051af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Callable<?> proxy = proxyFor(ImplementsCallable.class)
8061af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
8071af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(invocationHandler)
8081af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
8091af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8101af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        // the invocation handler is called twice!
8111af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", proxy.call());
8121af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(2, count.get());
8131af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8141af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        // the invocation handler is called, even though this is a callSuper() call!
8151af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", ProxyBuilder.callSuper(proxy, Callable.class.getMethod("call")));
8161af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, count.get());
8171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
818b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8191af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class ImplementsCallable implements Callable<String> {
8201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public String call() throws Exception {
8211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            return "a";
8221af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
8231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8241af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8251af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    /**
8261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * This test shows that our generated proxies follow the bytecode convention
8271af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * where methods can have the same name but unrelated return types. This is
8281af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * different from javac's convention where return types must be assignable
8291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * in one direction or the other.
8301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     */
831b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
8321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testInterfacesSameNamesDifferentReturnTypes() throws Throwable {
8331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler handler = new InvocationHandler() {
8341af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
8351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                if (method.getReturnType() == void.class) {
8361af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return null;
8371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else if (method.getReturnType() == String.class) {
8381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return "X";
8391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else if (method.getReturnType() == int.class) {
8401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return 3;
8411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else {
8421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    throw new AssertionFailedError();
8431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                }
8441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
8451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
846b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8471af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Object o = proxyFor(Object.class)
8481af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(FooReturnsVoid.class, FooReturnsString.class, FooReturnsInt.class)
8491af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(handler)
8501af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
851b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8521af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsVoid a = (FooReturnsVoid) o;
8531af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        a.foo();
854b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8551af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsString b = (FooReturnsString) o;
8561af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("X", b.foo());
857b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8581af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt c = (FooReturnsInt) o;
8591af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, c.foo());
8601af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
861b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
862b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
8631af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testInterfacesSameNamesSameReturnType() throws Throwable {
8641af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Object o = proxyFor(Object.class)
8651af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(FooReturnsInt.class, FooReturnsInt2.class)
8661af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
867b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8681af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(3);
8691af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8701af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt a = (FooReturnsInt) o;
8711af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, a.foo());
8721af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt2 b = (FooReturnsInt2) o;
8741af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, b.foo());
8751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
876b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsVoid {
8781af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        void foo();
8791af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8801af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8811af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsString {
8821af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        String foo();
8831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8841af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8851af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsInt {
8861af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        int foo();
8871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
888b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsInt2 {
8901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        int foo();
8911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
892b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
893b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson    private ClassLoader newPathClassLoader() throws Exception {
894b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        return (ClassLoader) Class.forName("dalvik.system.PathClassLoader")
895b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson                .getConstructor(String.class, ClassLoader.class)
896b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson                .newInstance("", getClass().getClassLoader());
897b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson
898b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson    }
899b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson
900b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
901579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSubclassOfRandom() throws Exception {
902579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(Random.class)
903579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(new InvokeSuperHandler())
904579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
905579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
906579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
90795689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    public static class FinalToString {
908b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        @Override
909b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        public final String toString() {
91095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy            return "no proxy";
91195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        }
91295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    }
91395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy
91495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    // https://code.google.com/p/dexmaker/issues/detail?id=12
915b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
91695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    public void testFinalToString() throws Throwable {
91795689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals("no proxy", proxyFor(FinalToString.class).build().toString());
91895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    }
91995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy
920ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public static class FinalInterfaceImpl implements FooReturnsString {
921b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        @Override
922b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        public final String foo() {
923ab38abdf175554643d40b889d58d283d358218c3Samuel Tan          return "no proxy";
924ab38abdf175554643d40b889d58d283d358218c3Samuel Tan        }
925ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
926ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
927ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public static class ExtenstionOfFinalInterfaceImpl extends FinalInterfaceImpl
928ab38abdf175554643d40b889d58d283d358218c3Samuel Tan            implements FooReturnsString {
929ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
930ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
931b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
932ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public void testFinalInterfaceImpl() throws Throwable {
933ab38abdf175554643d40b889d58d283d358218c3Samuel Tan        assertEquals("no proxy", proxyFor(ExtenstionOfFinalInterfaceImpl.class).build().foo());
934ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
935ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
936cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    // https://code.google.com/p/dexmaker/issues/detail?id=9
937cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    public interface DeclaresMethodLate {
938cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin        void thisIsTheMethod();
939cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    }
940cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin
941cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    public static class MakesMethodFinalEarly {
942cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin        public final void thisIsTheMethod() {}
943cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    }
944cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin
945cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    public static class YouDoNotChooseYourFamily
946cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin            extends MakesMethodFinalEarly implements DeclaresMethodLate {}
947cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin
948b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
949cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    public void testInterfaceMethodMadeFinalBeforeActualInheritance() throws Exception {
950cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin        proxyFor(YouDoNotChooseYourFamily.class).build();
951cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    }
952cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin
953309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    public interface ExtendsAnotherInterface extends FooReturnsString {
954309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin
955309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    }
956309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin
957309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    @Test
958309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    public void testExtraInterfaceExtendsInterface() throws Exception {
959309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin        ExtendsAnotherInterface proxy = (ExtendsAnotherInterface)
960309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin                proxyFor(SimpleClass.class)
961309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin                        .implementing(ExtendsAnotherInterface.class)
962309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin                        .build();
963309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin        fakeHandler.setFakeResult(ExtendsAnotherInterface.class.getName());
964309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin        assertEquals(ExtendsAnotherInterface.class.getName(), proxy.foo());
965309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    }
966309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin
967579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** Simple helper to add the most common args for this test to the proxy builder. */
968579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <T> ProxyBuilder<T> proxyFor(Class<T> clazz) throws Exception {
969579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return ProxyBuilder.forClass(clazz)
970579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(fakeHandler)
971ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson                .dexCache(DexMakerTest.getDataDirectory());
972579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
973579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
974579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static class FakeInvocationHandler implements InvocationHandler {
975579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private Object fakeResult = "fake result";
976579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
977579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
978579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return fakeResult;
979579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
980579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
981579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void setFakeResult(Object result) {
982579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fakeResult = result;
983579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
984579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
985054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
986054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class TestOrderingClass {
987054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int returnsInt() {
988054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 0;
989054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
990054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
991054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int returnsInt(int param1, int param2) {
992054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1;
993054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
994054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
995054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String returnsString() {
996054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "string";
997054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
998054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
999054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public boolean returnsBoolean() {
1000054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return false;
1001054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1002054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1003054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public double returnsDouble() {
1004054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1.0;
1005054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1006054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1007054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public Object returnsObject() {
1008054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return new Object();
1009054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1010054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1011054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1012b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
1013054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    @SuppressWarnings("unchecked")
1014054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testMethodsGeneratedInDeterministicOrder() throws Exception {
1015054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Grab the static methods array from the original class.
1016054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods1 = getMethodsForProxyClass(TestOrderingClass.class);
1017054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(methods1);
1018054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1019054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Clear ProxyBuilder's in-memory cache of classes. This will force
1020054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // it to rebuild the class and reset the static methods field.
1021054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Map<Class<?>, Class<?>> map = getGeneratedProxyClasses();
1022054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(map);
1023054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        map.clear();
1024054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1025054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Grab the static methods array from the rebuilt class.
1026054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods2 = getMethodsForProxyClass(TestOrderingClass.class);
1027054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(methods2);
1028054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1029054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Ensure that the two method arrays are equal.
1030054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertTrue(Arrays.equals(methods1, methods2));
1031054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1032054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1033b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
1034054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testOrderingClassWithDexMakerCaching() throws Exception {
1035054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        doTestOrderClassWithDexMakerCaching();
1036054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1037054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Force ProxyBuilder to call DexMaker.generateAndLoad()
1038054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
1039054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1040054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        doTestOrderClassWithDexMakerCaching();
1041054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1042054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1043054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void doTestOrderClassWithDexMakerCaching() throws Exception {
1044054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        TestOrderingClass proxy = ProxyBuilder.forClass(TestOrderingClass.class)
1045054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
1046054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
1047054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
1048054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(0, proxy.returnsInt());
1049054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(1, proxy.returnsInt(1, 1));
1050054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("string", proxy.returnsString());
1051054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertFalse(proxy.returnsBoolean());
1052b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(1.0, proxy.returnsDouble(), DELTA_DOUBLE);
1053054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(proxy.returnsObject());
1054b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertTrue(versionedDxDir.listFiles().length != 0);
1055054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1056054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1057054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    // Returns static methods array from a proxy class.
1058054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private Method[] getMethodsForProxyClass(Class<?> parentClass) throws Exception {
1059054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Class<?> proxyClass = proxyFor(parentClass).buildProxyClass();
1060054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods = null;
1061054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        for (Field f : proxyClass.getDeclaredFields()) {
1062054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            if (Method[].class.isAssignableFrom(f.getType())) {
1063054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                f.setAccessible(true);
1064054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                methods = (Method[]) f.get(null);
1065054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                break;
1066054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            }
1067054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1068054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1069054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        return methods;
1070054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1071054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1072054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private Map<Class<?>, Class<?>> getGeneratedProxyClasses() throws Exception {
1073054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Field mapField = ProxyBuilder.class
1074054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .getDeclaredField("generatedProxyClasses");
1075054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        mapField.setAccessible(true);
1076054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        return (Map<Class<?>, Class<?>>) mapField.get(null);
1077054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1078054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1079054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class ConcreteClassA implements FooReturnsInt {
1080054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // from FooReturnsInt
1081054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int foo() {
1082054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1;
1083054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1084054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1085054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // not from FooReturnsInt
1086054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String bar() {
1087054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "bar";
1088054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1089054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1090054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1091054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class ConcreteClassB implements FooReturnsInt {
1092054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // from FooReturnsInt
1093054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int foo() {
1094054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 0;
1095054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1096054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1097054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // not from FooReturnsInt
1098054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String bar() {
1099054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "bahhr";
1100054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1101054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1102054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1103b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
1104054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testTwoClassesWithIdenticalMethodSignatures_DexMakerCaching() throws Exception {
1105054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        ConcreteClassA proxyA = ProxyBuilder.forClass(ConcreteClassA.class)
1106054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
1107054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
1108054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
1109054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(1, proxyA.foo());
1110054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("bar", proxyA.bar());
1111171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        int numFiles = versionedDxDir.listFiles().length;
1112171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        assertTrue(numFiles > 0);
1113054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1114054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        ConcreteClassB proxyB = ProxyBuilder.forClass(ConcreteClassB.class)
1115054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
1116054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
1117054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
1118054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(0, proxyB.foo());
1119054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("bahhr", proxyB.bar());
1120171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        assertTrue(numFiles < versionedDxDir.listFiles().length);
1121171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    }
1122171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1123171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    public static abstract class PartiallyFinalClass {
1124171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        public String returnA() {
1125171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            return "A";
1126171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        }
1127171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1128171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        public String returnB() {
1129171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            return "B";
1130171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        }
1131171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1132171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        public String returnC() {
1133171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            return "C";
1134171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        }
1135171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1136171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        public final String returnD() {
1137171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            return "D";
1138171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        }
1139171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1140171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        public abstract String returnE();
1141171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    }
1142171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1143171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    @Test
1144171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    public void testProxyingSomeMethods() throws Throwable {
1145171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        ArrayList<Method> methodsToOverride = new ArrayList<>();
1146171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        for (Method method : PartiallyFinalClass.class.getDeclaredMethods()) {
1147171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            if (!Modifier.isFinal(method.getModifiers()) && !method.getName().equals("returnC")) {
1148171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                methodsToOverride.add(method);
1149171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            }
1150171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        }
1151171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1152171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        InvocationHandler handler = new InvokeSuperHandler() {
1153171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
1154171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                if (method.getName().equals("returnA")) {
1155171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                    return "fake A";
1156171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                } else if (method.getName().equals("returnC")) {
1157171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                    // This will never trigger as "returnC" is not overridden
1158171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                    return "fake C";
1159171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                } else if (method.getName().equals("returnE")) {
1160171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                    return "fake E";
1161171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                } else {
1162171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                    return super.invoke(proxy, method, args);
1163171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                }
1164171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            }
1165171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        };
1166171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1167171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        PartiallyFinalClass proxy = ProxyBuilder.forClass(PartiallyFinalClass.class)
1168171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                .handler(handler).onlyMethods(methodsToOverride.toArray(new Method[]{})).build();
1169171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1170171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        assertEquals("fake A", proxy.returnA());
1171171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        assertEquals("B", proxy.returnB());
1172171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        assertEquals("C", proxy.returnC());
1173171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        assertEquals("D", proxy.returnD());
1174171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        assertEquals("fake E", proxy.returnE());
1175171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
1176054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
1178