• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockito.internal.util;
6 
7 import org.mockito.MockedConstruction;
8 import org.mockito.Mockito;
9 import org.mockito.exceptions.misusing.NotAMockException;
10 import org.mockito.internal.configuration.plugins.Plugins;
11 import org.mockito.internal.creation.settings.CreationSettings;
12 import org.mockito.internal.stubbing.InvocationContainerImpl;
13 import org.mockito.internal.util.reflection.LenientCopyTool;
14 import org.mockito.invocation.MockHandler;
15 import org.mockito.mock.MockCreationSettings;
16 import org.mockito.mock.MockName;
17 import org.mockito.plugins.MockMaker;
18 import org.mockito.plugins.MockMaker.TypeMockability;
19 import org.mockito.plugins.MockResolver;
20 
21 import java.util.function.Function;
22 
23 import static org.mockito.internal.handler.MockHandlerFactory.createMockHandler;
24 
25 @SuppressWarnings("unchecked")
26 public class MockUtil {
27 
28     private static final MockMaker mockMaker = Plugins.getMockMaker();
29 
MockUtil()30     private MockUtil() {}
31 
typeMockabilityOf(Class<?> type)32     public static TypeMockability typeMockabilityOf(Class<?> type) {
33         return mockMaker.isTypeMockable(type);
34     }
35 
createMock(MockCreationSettings<T> settings)36     public static <T> T createMock(MockCreationSettings<T> settings) {
37         MockHandler mockHandler = createMockHandler(settings);
38 
39         Object spiedInstance = settings.getSpiedInstance();
40 
41         T mock;
42         if (spiedInstance != null) {
43             mock =
44                     mockMaker
45                             .createSpy(settings, mockHandler, (T) spiedInstance)
46                             .orElseGet(
47                                     () -> {
48                                         T instance = mockMaker.createMock(settings, mockHandler);
49                                         new LenientCopyTool().copyToMock(spiedInstance, instance);
50                                         return instance;
51                                     });
52         } else {
53             mock = mockMaker.createMock(settings, mockHandler);
54         }
55 
56         return mock;
57     }
58 
resetMock(Object mock)59     public static void resetMock(Object mock) {
60         MockHandler oldHandler = getMockHandler(mock);
61         MockCreationSettings settings = oldHandler.getMockSettings();
62         MockHandler newHandler = createMockHandler(settings);
63 
64         mock = resolve(mock);
65         mockMaker.resetMock(mock, newHandler, settings);
66     }
67 
getMockHandler(Object mock)68     public static MockHandler<?> getMockHandler(Object mock) {
69         if (mock == null) {
70             throw new NotAMockException("Argument should be a mock, but is null!");
71         }
72 
73         mock = resolve(mock);
74 
75         MockHandler handler = mockMaker.getHandler(mock);
76         if (handler != null) {
77             return handler;
78         } else {
79             throw new NotAMockException("Argument should be a mock, but is: " + mock.getClass());
80         }
81     }
82 
getInvocationContainer(Object mock)83     public static InvocationContainerImpl getInvocationContainer(Object mock) {
84         return (InvocationContainerImpl) getMockHandler(mock).getInvocationContainer();
85     }
86 
isSpy(Object mock)87     public static boolean isSpy(Object mock) {
88         return isMock(mock)
89                 && getMockSettings(mock).getDefaultAnswer() == Mockito.CALLS_REAL_METHODS;
90     }
91 
isMock(Object mock)92     public static boolean isMock(Object mock) {
93         // TODO SF (perf tweak) in our codebase we call mockMaker.getHandler() multiple times
94         // unnecessarily
95         // This is not ideal because getHandler() can be expensive (reflective calls inside mock
96         // maker)
97         // The frequent pattern in the codebase are separate calls to: 1) isMock(mock) then 2)
98         // getMockHandler(mock)
99         // We could replace it with using mockingDetails().isMock()
100         // Let's refactor the codebase and use new mockingDetails() in all relevant places.
101         // Potentially we could also move other methods to MockitoMock, some other candidates:
102         // getInvocationContainer, isSpy, etc.
103         // This also allows us to reuse our public API MockingDetails
104         if (mock == null) {
105             return false;
106         }
107 
108         mock = resolve(mock);
109 
110         return mockMaker.getHandler(mock) != null;
111     }
112 
resolve(Object mock)113     private static Object resolve(Object mock) {
114         if (mock instanceof Class<?>) { // static mocks are resolved by definition
115             return mock;
116         }
117         for (MockResolver mockResolver : Plugins.getMockResolvers()) {
118             mock = mockResolver.resolve(mock);
119         }
120         return mock;
121     }
122 
areSameMocks(Object mockA, Object mockB)123     public static boolean areSameMocks(Object mockA, Object mockB) {
124         return mockA == mockB || resolve(mockA) == resolve(mockB);
125     }
126 
getMockName(Object mock)127     public static MockName getMockName(Object mock) {
128         return getMockHandler(mock).getMockSettings().getMockName();
129     }
130 
maybeRedefineMockName(Object mock, String newName)131     public static void maybeRedefineMockName(Object mock, String newName) {
132         MockName mockName = getMockName(mock);
133         // TODO SF hacky...
134         MockCreationSettings mockSettings = getMockHandler(mock).getMockSettings();
135         if (mockName.isDefault() && mockSettings instanceof CreationSettings) {
136             ((CreationSettings) mockSettings).setMockName(new MockNameImpl(newName));
137         }
138     }
139 
getMockSettings(Object mock)140     public static MockCreationSettings getMockSettings(Object mock) {
141         return getMockHandler(mock).getMockSettings();
142     }
143 
createStaticMock( Class<T> type, MockCreationSettings<T> settings)144     public static <T> MockMaker.StaticMockControl<T> createStaticMock(
145             Class<T> type, MockCreationSettings<T> settings) {
146         MockHandler<T> handler = createMockHandler(settings);
147         return mockMaker.createStaticMock(type, settings, handler);
148     }
149 
createConstructionMock( Class<T> type, Function<MockedConstruction.Context, MockCreationSettings<T>> settingsFactory, MockedConstruction.MockInitializer<T> mockInitializer)150     public static <T> MockMaker.ConstructionMockControl<T> createConstructionMock(
151             Class<T> type,
152             Function<MockedConstruction.Context, MockCreationSettings<T>> settingsFactory,
153             MockedConstruction.MockInitializer<T> mockInitializer) {
154         Function<MockedConstruction.Context, MockHandler<T>> handlerFactory =
155                 context -> createMockHandler(settingsFactory.apply(context));
156         return mockMaker.createConstructionMock(
157                 type, settingsFactory, handlerFactory, mockInitializer);
158     }
159 
clearAllCaches()160     public static void clearAllCaches() {
161         mockMaker.clearAllCaches();
162     }
163 }
164