1/*
2 * Copyright (c) 2017 Mockito contributors
3 * This program is made available under the terms of the MIT License.
4 */
5package org.mockito.internal.creation.bytebuddy;
6
7import net.bytebuddy.ByteBuddy;
8import org.junit.Test;
9import org.mockito.Mockito;
10import org.mockito.internal.creation.MockSettingsImpl;
11import org.mockito.internal.handler.MockHandlerImpl;
12import org.mockito.invocation.InvocationContainer;
13import org.mockito.internal.stubbing.answers.CallsRealMethods;
14import org.mockito.invocation.Invocation;
15import org.mockito.invocation.MockHandler;
16import org.mockito.mock.MockCreationSettings;
17import org.mockito.mock.SerializableMode;
18import org.mockito.plugins.MockMaker;
19import org.mockito.stubbing.Answer;
20import org.mockitoutil.ClassLoaders;
21import org.mockitoutil.SimpleSerializationUtil;
22import org.objenesis.ObjenesisStd;
23
24import java.io.Serializable;
25import java.util.List;
26
27import static org.assertj.core.api.Assertions.assertThat;
28import static org.junit.Assert.fail;
29import static org.mockitoutil.ClassLoaders.coverageTool;
30
31public abstract class AbstractByteBuddyMockMakerTest<MM extends MockMaker> {
32
33    protected final MM mockMaker;
34
35    public AbstractByteBuddyMockMakerTest(MM mockMaker) {
36        this.mockMaker = mockMaker;
37    }
38
39    protected abstract Class<?> mockTypeOf(Class<?> type);
40
41    @Test
42    public void should_create_mock_from_interface() throws Exception {
43        SomeInterface proxy = mockMaker.createMock(settingsFor(SomeInterface.class), dummyHandler());
44
45        Class<?> superClass = proxy.getClass().getSuperclass();
46        assertThat(superClass).isEqualTo(Object.class);
47    }
48
49
50    @Test
51    public void should_create_mock_from_class() throws Exception {
52        ClassWithoutConstructor proxy = mockMaker.createMock(settingsFor(ClassWithoutConstructor.class), dummyHandler());
53
54        Class<?> superClass = mockTypeOf(proxy.getClass());
55        assertThat(superClass).isEqualTo(ClassWithoutConstructor.class);
56    }
57
58    @Test
59    public void should_create_mock_from_class_even_when_constructor_is_dodgy() throws Exception {
60        try {
61            new ClassWithDodgyConstructor();
62            fail();
63        } catch (Exception expected) {}
64
65        ClassWithDodgyConstructor mock = mockMaker.createMock(settingsFor(ClassWithDodgyConstructor.class), dummyHandler());
66        assertThat(mock).isNotNull();
67    }
68
69    @Test
70    public void should_mocks_have_different_interceptors() throws Exception {
71        SomeClass mockOne = mockMaker.createMock(settingsFor(SomeClass.class), dummyHandler());
72        SomeClass mockTwo = mockMaker.createMock(settingsFor(SomeClass.class), dummyHandler());
73
74        MockHandler handlerOne = mockMaker.getHandler(mockOne);
75        MockHandler handlerTwo = mockMaker.getHandler(mockTwo);
76
77
78        assertThat(handlerOne).isNotSameAs(handlerTwo);
79    }
80
81    @Test
82    public void should_use_ancillary_Types() {
83        SomeClass mock = mockMaker.createMock(settingsFor(SomeClass.class, SomeInterface.class), dummyHandler());
84
85        assertThat(mock).isInstanceOf(SomeInterface.class);
86    }
87
88    @Test
89    public void should_create_class_by_constructor() {
90        OtherClass mock = mockMaker.createMock(settingsWithConstructorFor(OtherClass.class), dummyHandler());
91        assertThat(mock).isNotNull();
92    }
93
94    @Test
95    public void should_allow_serialization() throws Exception {
96        SerializableClass proxy = mockMaker.createMock(serializableSettingsFor(SerializableClass.class, SerializableMode.BASIC), dummyHandler());
97
98        SerializableClass serialized = SimpleSerializationUtil.serializeAndBack(proxy);
99        assertThat(serialized).isNotNull();
100
101        MockHandler handlerOne = mockMaker.getHandler(proxy);
102        MockHandler handlerTwo = mockMaker.getHandler(serialized);
103
104        assertThat(handlerOne).isNotSameAs(handlerTwo);
105    }
106
107    @Test
108    public void should_create_mock_from_class_with_super_call_to_final_method() throws Exception {
109        MockCreationSettings<CallingSuperMethodClass> settings = settingsWithSuperCall(CallingSuperMethodClass.class);
110        SampleClass proxy = mockMaker.createMock(settings, new MockHandlerImpl<CallingSuperMethodClass>(settings));
111        assertThat(proxy.foo()).isEqualTo("foo");
112    }
113
114    @Test
115    public void should_reset_mock_and_set_new_handler() throws Throwable {
116        MockCreationSettings<SampleClass> settings = settingsWithSuperCall(SampleClass.class);
117        SampleClass proxy = mockMaker.createMock(settings, new MockHandlerImpl<SampleClass>(settings));
118
119        MockHandler handler = new MockHandlerImpl<SampleClass>(settings);
120        mockMaker.resetMock(proxy, handler, settings);
121        assertThat(mockMaker.getHandler(proxy)).isSameAs(handler);
122    }
123
124    class SomeClass {}
125    interface SomeInterface {}
126    static class OtherClass {}
127    static class SerializableClass implements Serializable {}
128
129    private class ClassWithoutConstructor {}
130
131    private class ClassWithDodgyConstructor {
132        public ClassWithDodgyConstructor() {
133            throw new RuntimeException();
134        }
135    }
136
137    @Test
138    public void instantiate_fine_when_objenesis_on_the_classpath() throws Exception {
139        // given
140        ClassLoader classpath_with_objenesis = ClassLoaders.excludingClassLoader()
141                .withCodeSourceUrlOf(Mockito.class, ByteBuddy.class, ObjenesisStd.class)
142                .withCodeSourceUrlOf(coverageTool())
143                .build();
144
145        Class<?> mock_maker_class_loaded_fine_until = Class.forName(
146                "org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker",
147                true,
148                classpath_with_objenesis
149        );
150
151        // when
152        mock_maker_class_loaded_fine_until.newInstance();
153
154        // then everything went fine
155    }
156
157    private static <T> MockCreationSettings<T> settingsFor(Class<T> type, Class<?>... extraInterfaces) {
158        MockSettingsImpl<T> mockSettings = new MockSettingsImpl<T>();
159        mockSettings.setTypeToMock(type);
160        if(extraInterfaces.length > 0) mockSettings.extraInterfaces(extraInterfaces);
161        return mockSettings;
162    }
163
164    private static <T> MockCreationSettings<T> serializableSettingsFor(Class<T> type, SerializableMode serializableMode) {
165        MockSettingsImpl<T> mockSettings = new MockSettingsImpl<T>();
166        mockSettings.serializable(serializableMode);
167        mockSettings.setTypeToMock(type);
168        return mockSettings;
169    }
170
171    private static <T> MockCreationSettings<T> settingsWithConstructorFor(Class<T> type) {
172        MockSettingsImpl<T> mockSettings = new MockSettingsImpl<T>();
173        mockSettings.setTypeToMock(type);
174        return mockSettings;
175    }
176
177    private static <T> MockCreationSettings<T> settingsWithSuperCall(Class<T> type) {
178        MockSettingsImpl<T> mockSettings = new MockSettingsImpl<T>();
179        mockSettings.setTypeToMock(type);
180        mockSettings.defaultAnswer(new CallsRealMethods());
181        return mockSettings;
182    }
183
184    protected static MockHandler dummyHandler() {
185        return new DummyMockHandler();
186    }
187
188    private static class DummyMockHandler implements MockHandler<Object> {
189        public Object handle(Invocation invocation) throws Throwable { return null; }
190        public MockCreationSettings<Object> getMockSettings() { return null; }
191        public InvocationContainer getInvocationContainer() { return null; }
192        public void setAnswersForStubbing(List<Answer<?>> list) { }
193    }
194
195    private static class SampleClass {
196        public String foo() {
197            return "foo";
198        }
199    }
200
201    private static class CallingSuperMethodClass extends SampleClass {
202        @Override
203        public String foo() {
204            return super.foo();
205        }
206    }
207}
208