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