DexmakerMockMaker.java revision 5a7820356e68a977711afc854d6cd71296c56391
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.dexmaker.mockito;
18
19import com.google.dexmaker.stock.ProxyBuilder;
20import java.lang.reflect.Field;
21import java.lang.reflect.InvocationHandler;
22import java.lang.reflect.Proxy;
23import org.mockito.exceptions.base.MockitoException;
24import org.mockito.plugins.MockMaker;
25import org.mockito.plugins.MockSettingsInfo;
26import org.mockito.plugins.MockitoInvocationHandler;
27
28/**
29 * Generates mock instances on Android's runtime.
30 */
31public final class DexmakerMockMaker implements MockMaker {
32    private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
33
34    public <T> T createMock(Class<T> typeToMock, Class<?>[] extraInterfaces,
35            MockitoInvocationHandler handler, MockSettingsInfo settings) {
36        // TODO
37        System.setProperty("dexmaker.dexcache", "/data/vogar"); // TODO
38        // TODO
39
40        InvocationHandler invocationHandler = new InvocationHandlerAdapter(handler);
41
42        if (typeToMock.isInterface()) {
43            // support interfaces via java.lang.reflect.Proxy
44            Class[] classesToMock = new Class[extraInterfaces.length + 1];
45            classesToMock[0] = typeToMock;
46            System.arraycopy(extraInterfaces, 0, classesToMock, 1, extraInterfaces.length);
47            @SuppressWarnings("unchecked") // newProxyInstance returns the type of typeToMock
48            T mock = (T) Proxy.newProxyInstance(typeToMock.getClassLoader(),
49                    classesToMock, invocationHandler);
50            return mock;
51
52        } else {
53            // support concrete classes via dexmaker's ProxyBuilder
54            try {
55                Class<? extends T> proxyClass = ProxyBuilder.forClass(typeToMock)
56                        .implementing(extraInterfaces)
57                        .buildProxyClass();
58                T mock = unsafeAllocator.newInstance(proxyClass);
59                Field handlerField = proxyClass.getDeclaredField("$__handler");
60                handlerField.setAccessible(true);
61                handlerField.set(mock, invocationHandler);
62                return mock;
63            } catch (RuntimeException e) {
64                throw e;
65            } catch (Exception e) {
66                throw new MockitoException("Failed to mock " + typeToMock, e);
67            }
68        }
69    }
70
71    public void resetMock(Object mock, MockitoInvocationHandler newHandler, MockSettingsInfo settings) {
72        InvocationHandlerAdapter adapter = getInvocationHandlerAdapter(mock);
73        adapter.setHandler(newHandler);
74    }
75
76    public MockitoInvocationHandler getHandler(Object mock) {
77        InvocationHandlerAdapter adapter = getInvocationHandlerAdapter(mock);
78        return adapter != null ? adapter.getHandler() : null;
79    }
80
81    private InvocationHandlerAdapter getInvocationHandlerAdapter(Object mock) {
82        if (Proxy.isProxyClass(mock.getClass())) {
83            InvocationHandler invocationHandler = Proxy.getInvocationHandler(mock);
84            return invocationHandler instanceof InvocationHandlerAdapter
85                    ? (InvocationHandlerAdapter) invocationHandler
86                    : null;
87        }
88
89        if (ProxyBuilder.isProxyClass(mock.getClass())) {
90            InvocationHandler invocationHandler = ProxyBuilder.getInvocationHandler(mock);
91            return invocationHandler instanceof InvocationHandlerAdapter
92                    ? (InvocationHandlerAdapter) invocationHandler
93                    : null;
94        }
95
96        return null;
97    }
98}
99