diff options
Diffstat (limited to 'src/main/java/org/mockito/internal')
57 files changed, 361 insertions, 1222 deletions
diff --git a/src/main/java/org/mockito/internal/MockitoCore.java b/src/main/java/org/mockito/internal/MockitoCore.java index 5d39d5e..68b580a 100644 --- a/src/main/java/org/mockito/internal/MockitoCore.java +++ b/src/main/java/org/mockito/internal/MockitoCore.java @@ -35,17 +35,24 @@ import org.mockito.verification.VerificationMode; import java.util.Arrays; import java.util.List; -import static org.mockito.internal.exceptions.Reporter.*; +import static org.mockito.internal.exceptions.Reporter.missingMethodInvocation; +import static org.mockito.internal.exceptions.Reporter.mocksHaveToBePassedToVerifyNoMoreInteractions; +import static org.mockito.internal.exceptions.Reporter.mocksHaveToBePassedWhenCreatingInOrder; +import static org.mockito.internal.exceptions.Reporter.notAMockPassedToVerify; +import static org.mockito.internal.exceptions.Reporter.notAMockPassedToVerifyNoMoreInteractions; +import static org.mockito.internal.exceptions.Reporter.notAMockPassedWhenCreatingInOrder; +import static org.mockito.internal.exceptions.Reporter.nullPassedToVerify; +import static org.mockito.internal.exceptions.Reporter.nullPassedToVerifyNoMoreInteractions; +import static org.mockito.internal.exceptions.Reporter.nullPassedWhenCreatingInOrder; +import static org.mockito.internal.exceptions.Reporter.stubPassedToVerify; import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress; import static org.mockito.internal.util.MockUtil.createMock; import static org.mockito.internal.util.MockUtil.getInvocationContainer; -import static org.mockito.internal.util.MockUtil.getMockHandler; import static org.mockito.internal.util.MockUtil.isMock; import static org.mockito.internal.util.MockUtil.resetMock; import static org.mockito.internal.util.MockUtil.typeMockabilityOf; import static org.mockito.internal.verification.VerificationModeFactory.noMoreInteractions; - @SuppressWarnings("unchecked") public class MockitoCore { @@ -84,8 +91,10 @@ public class MockitoCore { if (!mockingDetails.isMock()) { throw notAMockPassedToVerify(mock.getClass()); } - assertNotStubOnlyMock(mock); MockHandler handler = mockingDetails.getMockHandler(); + if (handler.getMockSettings().isStubOnly()) { + throw stubPassedToVerify(); + } mock = (T) VerificationStartedNotifier.notifyVerificationStarted( handler.getMockSettings().getVerificationStartedListeners(), mockingDetails); @@ -126,7 +135,6 @@ public class MockitoCore { throw nullPassedToVerifyNoMoreInteractions(); } InvocationContainerImpl invocations = getInvocationContainer(mock); - assertNotStubOnlyMock(mock); VerificationDataImpl data = new VerificationDataImpl(invocations, null); noMoreInteractions().verify(data); } catch (NotAMockException e) { @@ -147,12 +155,6 @@ public class MockitoCore { } } - private void assertNotStubOnlyMock(Object mock) { - if (getMockHandler(mock).getMockSettings().isStubOnly()) { - throw stubPassedToVerify(mock); - } - } - public InOrder inOrder(Object... mocks) { if (mocks == null || mocks.length == 0) { throw mocksHaveToBePassedWhenCreatingInOrder(); @@ -164,7 +166,6 @@ public class MockitoCore { if (!isMock(mock)) { throw notAMockPassedWhenCreatingInOrder(); } - assertNotStubOnlyMock(mock); } return new InOrderImpl(Arrays.asList(mocks)); } diff --git a/src/main/java/org/mockito/internal/configuration/InjectingAnnotationEngine.java b/src/main/java/org/mockito/internal/configuration/InjectingAnnotationEngine.java index 20d967d..6cb5fb1 100644 --- a/src/main/java/org/mockito/internal/configuration/InjectingAnnotationEngine.java +++ b/src/main/java/org/mockito/internal/configuration/InjectingAnnotationEngine.java @@ -39,7 +39,15 @@ public class InjectingAnnotationEngine implements AnnotationEngine, org.mockito. */ public void process(Class<?> clazz, Object testInstance) { processIndependentAnnotations(testInstance.getClass(), testInstance); - injectMocks(testInstance); + processInjectMocks(testInstance.getClass(), testInstance); + } + + private void processInjectMocks(final Class<?> clazz, final Object testInstance) { + Class<?> classContext = clazz; + while (classContext != Object.class) { + injectMocks(testInstance); + classContext = classContext.getSuperclass(); + } } private void processIndependentAnnotations(final Class<?> clazz, final Object testInstance) { diff --git a/src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java b/src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java index d99b348..91086d2 100644 --- a/src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java +++ b/src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java @@ -35,9 +35,6 @@ public class MockAnnotationProcessor implements FieldAnnotationProcessor<Mock> { if(annotation.stubOnly()){ mockSettings.stubOnly(); } - if(annotation.lenient()){ - mockSettings.lenient(); - } // see @Mock answer default value mockSettings.defaultAnswer(annotation.answer()); diff --git a/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java b/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java index e5aefd9..f80e7c4 100644 --- a/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java +++ b/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java @@ -9,7 +9,6 @@ import org.mockito.plugins.AnnotationEngine; import org.mockito.plugins.InstantiatorProvider; import org.mockito.plugins.InstantiatorProvider2; import org.mockito.plugins.MockMaker; -import org.mockito.plugins.MockitoLogger; import org.mockito.plugins.MockitoPlugins; import org.mockito.plugins.PluginSwitch; import org.mockito.plugins.StackTraceCleanerProvider; @@ -30,7 +29,6 @@ class DefaultMockitoPlugins implements MockitoPlugins { DEFAULT_PLUGINS.put(InstantiatorProvider2.class.getName(), "org.mockito.internal.creation.instance.DefaultInstantiatorProvider"); DEFAULT_PLUGINS.put(AnnotationEngine.class.getName(), "org.mockito.internal.configuration.InjectingAnnotationEngine"); DEFAULT_PLUGINS.put(INLINE_ALIAS, "org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker"); - DEFAULT_PLUGINS.put(MockitoLogger.class.getName(), "org.mockito.internal.util.ConsoleMockitoLogger"); } @Override diff --git a/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java b/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java index 2e5f069..02e5d66 100644 --- a/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java +++ b/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java @@ -9,7 +9,6 @@ import org.mockito.plugins.AnnotationEngine; import org.mockito.plugins.InstantiatorProvider; import org.mockito.plugins.InstantiatorProvider2; import org.mockito.plugins.MockMaker; -import org.mockito.plugins.MockitoLogger; import org.mockito.plugins.PluginSwitch; import org.mockito.plugins.StackTraceCleanerProvider; @@ -26,12 +25,9 @@ class PluginRegistry { private final InstantiatorProvider2 instantiatorProvider; - private final AnnotationEngine annotationEngine = new PluginLoader(pluginSwitch) + private AnnotationEngine annotationEngine = new PluginLoader(pluginSwitch) .loadPlugin(AnnotationEngine.class); - private final MockitoLogger mockitoLogger = new PluginLoader(pluginSwitch) - .loadPlugin(MockitoLogger.class); - PluginRegistry() { Object impl = new PluginLoader(pluginSwitch).loadPlugin(InstantiatorProvider2.class, InstantiatorProvider.class); if (impl instanceof InstantiatorProvider) { @@ -79,14 +75,4 @@ class PluginRegistry { AnnotationEngine getAnnotationEngine() { return annotationEngine; } - - /** - * Returns the logger available for the current runtime. - * - * <p>Returns {@link org.mockito.internal.util.ConsoleMockitoLogger} if no - * {@link org.mockito.plugins.MockitoLogger} extension exists or is visible in the current classpath.</p> - */ - MockitoLogger getMockitoLogger() { - return mockitoLogger; - } } diff --git a/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java b/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java index 84e3c0d..f65fe89 100644 --- a/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java +++ b/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java @@ -4,7 +4,6 @@ */ package org.mockito.internal.configuration.plugins; -import org.mockito.plugins.MockitoLogger; import org.mockito.plugins.AnnotationEngine; import org.mockito.plugins.InstantiatorProvider2; import org.mockito.plugins.MockMaker; @@ -57,16 +56,6 @@ public class Plugins { } /** - * Returns the logger available for the current runtime. - * - * <p>Returns {@link org.mockito.internal.util.ConsoleMockitoLogger} if no - * {@link org.mockito.plugins.MockitoLogger} extension exists or is visible in the current classpath.</p> - */ - public static MockitoLogger getMockitoLogger() { - return registry.getMockitoLogger(); - } - - /** * @return instance of mockito plugins type */ public static MockitoPlugins getPlugins() { diff --git a/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java b/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java index 50134b4..ca67730 100644 --- a/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java +++ b/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java @@ -11,7 +11,6 @@ import org.mockito.internal.util.Checks; import org.mockito.internal.util.MockCreationValidator; import org.mockito.internal.util.MockNameImpl; import org.mockito.listeners.InvocationListener; -import org.mockito.listeners.StubbingLookupListener; import org.mockito.listeners.VerificationStartedListener; import org.mockito.mock.MockCreationSettings; import org.mockito.mock.MockName; @@ -20,17 +19,17 @@ import org.mockito.stubbing.Answer; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; -import static java.util.Arrays.asList; import static org.mockito.internal.exceptions.Reporter.defaultAnswerDoesNotAcceptNullParameter; import static org.mockito.internal.exceptions.Reporter.extraInterfacesAcceptsOnlyInterfaces; import static org.mockito.internal.exceptions.Reporter.extraInterfacesDoesNotAcceptNullParameters; import static org.mockito.internal.exceptions.Reporter.extraInterfacesRequiresAtLeastOneInterface; +import static org.mockito.internal.exceptions.Reporter.invocationListenersRequiresAtLeastOneListener; import static org.mockito.internal.exceptions.Reporter.methodDoesNotAcceptParameter; -import static org.mockito.internal.exceptions.Reporter.requiresAtLeastOneListener; import static org.mockito.internal.util.collections.Sets.newSet; @SuppressWarnings("unchecked") @@ -155,7 +154,7 @@ public class MockSettingsImpl<T> extends CreationSettings<T> implements MockSett } List<Object> resultArgs = new ArrayList<Object>(constructorArgs.length + 1); resultArgs.add(outerClassInstance); - resultArgs.addAll(asList(constructorArgs)); + resultArgs.addAll(Arrays.asList(constructorArgs)); return resultArgs.toArray(new Object[constructorArgs.length + 1]); } @@ -174,23 +173,17 @@ public class MockSettingsImpl<T> extends CreationSettings<T> implements MockSett @Override public MockSettings invocationListeners(InvocationListener... listeners) { + if (listeners == null || listeners.length == 0) { + throw invocationListenersRequiresAtLeastOneListener(); + } addListeners(listeners, invocationListeners, "invocationListeners"); return this; } - @Override - public MockSettings stubbingLookupListeners(StubbingLookupListener... listeners) { - addListeners(listeners, stubbingLookupListeners, "stubbingLookupListeners"); - return this; - } - - static <T> void addListeners(T[] listeners, List<T> container, String method) { + private static <T> void addListeners(T[] listeners, List<T> container, String method) { if (listeners == null) { throw methodDoesNotAcceptParameter(method, "null vararg array."); } - if (listeners.length == 0) { - throw requiresAtLeastOneListener(method); - } for (T listener : listeners) { if (listener == null) { throw methodDoesNotAcceptParameter(method, "null listeners."); @@ -214,8 +207,13 @@ public class MockSettingsImpl<T> extends CreationSettings<T> implements MockSett return false; } + @Override + public List<InvocationListener> getInvocationListeners() { + return this.invocationListeners; + } + public boolean hasInvocationListeners() { - return !getInvocationListeners().isEmpty(); + return !invocationListeners.isEmpty(); } @Override diff --git a/src/main/java/org/mockito/internal/creation/SuspendMethod.java b/src/main/java/org/mockito/internal/creation/SuspendMethod.java index 42ceac6..018bc50 100644 --- a/src/main/java/org/mockito/internal/creation/SuspendMethod.java +++ b/src/main/java/org/mockito/internal/creation/SuspendMethod.java @@ -11,18 +11,12 @@ import java.util.Arrays; * See <a href="https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#continuation-passing-style">Design docs for details</a>. */ public class SuspendMethod { - private static final String KOTLIN_EXPERIMENTAL_CONTINUATION = "kotlin.coroutines.experimental.Continuation"; - private static final String KOTLIN_CONTINUATION = "kotlin.coroutines.Continuation"; + private static final String KOTLIN_CONTINUATION = "kotlin.coroutines.experimental.Continuation"; public static Class<?>[] trimSuspendParameterTypes(Class<?>[] parameterTypes) { int n = parameterTypes.length; - if (n > 0 && isContinuationType(parameterTypes[n - 1])) + if (n > 0 && parameterTypes[n - 1].getName().equals(KOTLIN_CONTINUATION)) return Arrays.copyOf(parameterTypes, n - 1); return parameterTypes; } - - private static boolean isContinuationType(Class<?> parameterType) { - String name = parameterType.getName(); - return name.equals(KOTLIN_CONTINUATION) || name.equals(KOTLIN_EXPERIMENTAL_CONTINUATION); - } } diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java index e99b915..42f10ce 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java @@ -14,7 +14,6 @@ import org.mockito.internal.util.Platform; import org.mockito.internal.util.concurrent.WeakConcurrentMap; import org.mockito.invocation.MockHandler; import org.mockito.mock.MockCreationSettings; -import org.mockito.plugins.InlineMockMaker; import java.io.File; import java.io.FileOutputStream; @@ -26,8 +25,6 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; -import javax.tools.ToolProvider; - import static org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.EXCLUDES; import static org.mockito.internal.util.StringUtil.join; @@ -90,7 +87,7 @@ import static org.mockito.internal.util.StringUtil.join; * support this feature. */ @Incubating -public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker, InlineMockMaker { +public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker { private static final Instrumentation INSTRUMENTATION; @@ -112,7 +109,7 @@ public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker, InlineM boot.deleteOnExit(); JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(boot)); try { - String source = "org/mockito/internal/creation/bytebuddy/inject/MockMethodDispatcher"; + String source = "org/mockito/internal/creation/bytebuddy/MockMethodDispatcher"; InputStream inputStream = InlineByteBuddyMockMaker.class.getClassLoader().getResourceAsStream(source + ".raw"); if (inputStream == null) { throw new IllegalStateException(join( @@ -137,7 +134,13 @@ public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker, InlineM } instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(boot)); try { - Class.forName("org.mockito.internal.creation.bytebuddy.inject.MockMethodDispatcher", false, null); + Class<?> dispatcher = Class.forName("org.mockito.internal.creation.bytebuddy.MockMethodDispatcher"); + if (dispatcher.getClassLoader() != null) { + throw new IllegalStateException(join( + "The MockMethodDispatcher must not be loaded manually but must be injected into the bootstrap class loader.", + "", + "The dispatcher class was already loaded by: " + dispatcher.getClassLoader())); + } } catch (ClassNotFoundException cnfe) { throw new IllegalStateException(join( "Mockito failed to inject the MockMethodDispatcher class into the bootstrap class loader", @@ -167,7 +170,7 @@ public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker, InlineM if (INITIALIZATION_ERROR != null) { throw new MockitoInitializationException(join( "Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)", - ToolProvider.getSystemJavaCompiler() == null ? "Are you running a JRE instead of a JDK? The inline mock maker needs to be run on a JDK.\n" : "", + "", Platform.describe()), INITIALIZATION_ERROR); } bytecodeGenerator = new TypeCachingBytecodeGenerator(new InlineBytecodeGenerator(INSTRUMENTATION, mocks), true); @@ -273,16 +276,6 @@ public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker, InlineM } @Override - public void clearMock(Object mock) { - mocks.remove(mock); - } - - @Override - public void clearAllMocks() { - mocks.clear(); - } - - @Override public TypeMockability isTypeMockable(final Class<?> type) { return new TypeMockability() { @Override diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java index e160e3c..64139c2 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java @@ -26,17 +26,17 @@ import net.bytebuddy.pool.TypePool; import net.bytebuddy.utility.OpenedClassReader; import net.bytebuddy.utility.RandomString; import org.mockito.exceptions.base.MockitoException; -import org.mockito.internal.creation.bytebuddy.inject.MockMethodDispatcher; import org.mockito.internal.util.concurrent.WeakConcurrentMap; import org.mockito.internal.util.concurrent.WeakConcurrentSet; import org.mockito.mock.SerializableMode; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.security.ProtectionDomain; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import static net.bytebuddy.implementation.MethodDelegation.withDefaultConfiguration; import static net.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder.ParameterBinder.ForFixedValue.OfConstant.of; @@ -60,12 +60,14 @@ public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTran String.class)); private final Instrumentation instrumentation; + private final ByteBuddy byteBuddy; + private final WeakConcurrentSet<Class<?>> mocked; + private final BytecodeGenerator subclassEngine; - private final AsmVisitorWrapper mockTransformer; - private final Method getModule, canRead, redefineModule; + private final AsmVisitorWrapper mockTransformer; private volatile Throwable lastException; @@ -96,20 +98,6 @@ public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTran Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForEquals.class)); - Method getModule, canRead, redefineModule; - try { - getModule = Class.class.getMethod("getModule"); - canRead = getModule.getReturnType().getMethod("canRead", getModule.getReturnType()); - redefineModule = Instrumentation.class.getMethod("redefineModule", - getModule.getReturnType(), Set.class, Map.class, Map.class, Set.class, Map.class); - } catch (Exception ignored) { - getModule = null; - canRead = null; - redefineModule = null; - } - this.getModule = getModule; - this.canRead = canRead; - this.redefineModule = redefineModule; MockMethodDispatcher.set(identifier, new MockMethodAdvice(mocks, identifier)); instrumentation.addTransformer(this, true); } @@ -170,7 +158,6 @@ public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTran } while (type != null); if (!types.isEmpty()) { try { - assureCanReadMockito(types); instrumentation.retransformClasses(types.toArray(new Class<?>[types.size()])); Throwable throwable = lastException; if (throwable != null) { @@ -191,32 +178,6 @@ public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTran } } - private void assureCanReadMockito(Set<Class<?>> types) { - if (redefineModule == null) { - return; - } - Set<Object> modules = new HashSet<Object>(); - try { - Object target = getModule.invoke(Class.forName("org.mockito.internal.creation.bytebuddy.inject.MockMethodDispatcher", false, null)); - for (Class<?> type : types) { - Object module = getModule.invoke(type); - if (!modules.contains(module) && !(Boolean) canRead.invoke(module, target)) { - modules.add(module); - } - } - for (Object module : modules) { - redefineModule.invoke(instrumentation, module, Collections.singleton(target), - Collections.emptyMap(), Collections.emptyMap(), Collections.emptySet(), Collections.emptyMap()); - } - } catch (Exception e) { - throw new IllegalStateException(join("Could not adjust module graph to make the mock instance dispatcher visible to some classes", - "", - "At least one of those modules: " + modules + " is not reading the unnamed module of the bootstrap loader", - "Without such a read edge, the classes that are redefined to become mocks cannot access the mock dispatcher.", - "To circumvent this, Mockito attempted to add a read edge to this module what failed for an unexpected reason"), e); - } - } - private <T> void checkSupportedCombination(boolean subclassingRequired, MockFeatures<T> features) { if (subclassingRequired && !features.mockedType.isArray() diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java index 828b848..f39a1a2 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java @@ -12,7 +12,6 @@ import net.bytebuddy.implementation.bind.annotation.Argument; import net.bytebuddy.implementation.bind.annotation.This; import net.bytebuddy.implementation.bytecode.assign.Assigner; import org.mockito.exceptions.base.MockitoException; -import org.mockito.internal.creation.bytebuddy.inject.MockMethodDispatcher; import org.mockito.internal.debugging.LocationImpl; import org.mockito.internal.exceptions.stacktrace.ConditionalStackTraceFilter; import org.mockito.internal.invocation.RealMethod; @@ -36,7 +35,7 @@ import java.util.concurrent.Callable; public class MockMethodAdvice extends MockMethodDispatcher { - private final WeakConcurrentMap<Object, MockMethodInterceptor> interceptors; + final WeakConcurrentMap<Object, MockMethodInterceptor> interceptors; private final String identifier; diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java index e57a82e..9066927 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java @@ -46,11 +46,13 @@ public class MockMethodInterceptor implements Serializable { Method invokedMethod, Object[] arguments, RealMethod realMethod) throws Throwable { - return doIntercept(mock, - invokedMethod, - arguments, - realMethod, - new LocationImpl()); + return doIntercept( + mock, + invokedMethod, + arguments, + realMethod, + new LocationImpl() + ); } Object doIntercept(Object mock, @@ -106,11 +108,11 @@ public class MockMethodInterceptor implements Serializable { return superCall.call(); } return interceptor.doIntercept( - mock, - invokedMethod, - arguments, - new RealMethod.FromCallable(superCall) - ); + mock, + invokedMethod, + arguments, + new RealMethod.FromCallable(superCall) + ); } @SuppressWarnings("unused") @@ -124,11 +126,11 @@ public class MockMethodInterceptor implements Serializable { return stubValue; } return interceptor.doIntercept( - mock, - invokedMethod, - arguments, - RealMethod.IsIllegal.INSTANCE - ); + mock, + invokedMethod, + arguments, + RealMethod.IsIllegal.INSTANCE + ); } } } diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/ModuleHandler.java b/src/main/java/org/mockito/internal/creation/bytebuddy/ModuleHandler.java deleted file mode 100644 index 5be0b95..0000000 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/ModuleHandler.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2016 Mockito contributors - * This program is made available under the terms of the MIT License. - */ -package org.mockito.internal.creation.bytebuddy; - -import net.bytebuddy.ByteBuddy; -import net.bytebuddy.description.modifier.Ownership; -import net.bytebuddy.description.modifier.Visibility; -import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; -import net.bytebuddy.implementation.Implementation; -import net.bytebuddy.implementation.MethodCall; -import net.bytebuddy.implementation.StubMethod; -import org.mockito.codegen.InjectionBase; -import org.mockito.exceptions.base.MockitoException; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Random; - -import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer; -import static org.mockito.internal.util.StringUtil.join; - -abstract class ModuleHandler { - - abstract boolean isOpened(Class<?> source, Class<?> target); - - abstract boolean canRead(Class<?> source, Class<?> target); - - abstract boolean isExported(Class<?> source); - - abstract boolean isExported(Class<?> source, Class<?> target); - - abstract Class<?> injectionBase(ClassLoader classLoader, String tyoeName); - - abstract void adjustModuleGraph(Class<?> source, Class<?> target, boolean export, boolean read); - - static ModuleHandler make(ByteBuddy byteBuddy, SubclassLoader loader, Random random) { - try { - return new ModuleSystemFound( - byteBuddy, loader, random - ); - } catch (Exception ignored) { - return new NoModuleSystemFound(); - } - } - - private static class ModuleSystemFound extends ModuleHandler { - - private final ByteBuddy byteBuddy; - private final SubclassLoader loader; - private final Random random; - - private final int injectonBaseSuffix; - - private final Method getModule, isOpen, isExported, isExportedUnqualified, canRead, addExports, addReads, addOpens, forName; - - private ModuleSystemFound(ByteBuddy byteBuddy, SubclassLoader loader, Random random) throws Exception { - this.byteBuddy = byteBuddy; - this.loader = loader; - this.random = random; - injectonBaseSuffix = Math.abs(random.nextInt()); - Class<?> moduleType = Class.forName("java.lang.Module"); - getModule = Class.class.getMethod("getModule"); - isOpen = moduleType.getMethod("isOpen", String.class, moduleType); - isExported = moduleType.getMethod("isExported", String.class, moduleType); - isExportedUnqualified = moduleType.getMethod("isExported", String.class); - canRead = moduleType.getMethod("canRead", moduleType); - addExports = moduleType.getMethod("addExports", String.class, moduleType); - addReads = moduleType.getMethod("addReads", moduleType); - addOpens = moduleType.getMethod("addOpens", String.class, moduleType); - forName = Class.class.getMethod("forName", String.class); - } - - @Override - boolean isOpened(Class<?> source, Class<?> target) { - if (source.getPackage() == null) { - return true; - } - return (Boolean) invoke(isOpen, invoke(getModule, source), source.getPackage().getName(), invoke(getModule, target)); - } - - @Override - boolean canRead(Class<?> source, Class<?> target) { - return (Boolean) invoke(canRead, invoke(getModule, source), invoke(getModule, target)); - } - - @Override - boolean isExported(Class<?> source) { - if (source.getPackage() == null) { - return true; - } - return (Boolean) invoke(isExportedUnqualified, invoke(getModule, source), source.getPackage().getName()); - } - - @Override - boolean isExported(Class<?> source, Class<?> target) { - if (source.getPackage() == null) { - return true; - } - return (Boolean) invoke(isExported, invoke(getModule, source), source.getPackage().getName(), invoke(getModule, target)); - } - - @Override - Class<?> injectionBase(ClassLoader classLoader, String typeName) { - String packageName = typeName.substring(0, typeName.lastIndexOf('.')); - if (classLoader == InjectionBase.class.getClassLoader() && InjectionBase.class.getPackage().getName().equals(packageName)) { - return InjectionBase.class; - } else { - synchronized (this) { - String name; - int suffix = injectonBaseSuffix; - do { - name = packageName + "." + InjectionBase.class.getSimpleName() + "$" + suffix++; - try { - Class<?> type = Class.forName(name, false, classLoader); - // The injected type must be defined in the class loader that is target of the injection. Otherwise, - // the class's unnamed module would differ from the intended module. To avoid conflicts, we increment - // the suffix until we hit a class with a known name and generate one if it does not exist. - if (type.getClassLoader() == classLoader) { - return type; - } - } catch (ClassNotFoundException ignored) { - break; - } - } while (true); - return byteBuddy.subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS) - .name(name) - .make() - .load(classLoader, loader.resolveStrategy(InjectionBase.class, classLoader, false)) - .getLoaded(); - } - } - } - - @Override - void adjustModuleGraph(Class<?> source, Class<?> target, boolean export, boolean read) { - boolean needsExport = export && !isExported(source, target); - boolean needsRead = read && !canRead(source, target); - if (!needsExport && !needsRead) { - return; - } - ClassLoader classLoader = source.getClassLoader(); - if (classLoader == null) { - throw new MockitoException(join("Cannot adjust module graph for modules in the bootstrap loader", - "", - source + " is declared by the bootstrap loader and cannot be adjusted", - "Requires package export to " + target + ": " + needsExport, - "Requires adjusted reading of " + target + ": " + needsRead)); - } - boolean targetVisible = classLoader == target.getClassLoader(); - while (!targetVisible && classLoader != null) { - classLoader = classLoader.getParent(); - targetVisible = classLoader == target.getClassLoader(); - } - MethodCall targetLookup; - Implementation.Composable implementation; - if (targetVisible) { - targetLookup = MethodCall.invoke(getModule).onMethodCall(MethodCall.invoke(forName).with(target.getName())); - implementation = StubMethod.INSTANCE; - } else { - Class<?> intermediate; - Field field; - try { - intermediate = byteBuddy.subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS) - .name(String.format("%s$%d", "org.mockito.codegen.MockitoTypeCarrier", Math.abs(random.nextInt()))) - .defineField("mockitoType", Class.class, Visibility.PUBLIC, Ownership.STATIC) - .make() - .load(source.getClassLoader(), loader.resolveStrategy(source, source.getClassLoader(), false)) - .getLoaded(); - field = intermediate.getField("mockitoType"); - field.set(null, target); - } catch (Exception e) { - throw new MockitoException(join("Could not create a carrier for making the Mockito type visible to " + source, - "", - "This is required to adjust the module graph to enable mock creation"), e); - } - targetLookup = MethodCall.invoke(getModule).onField(field); - implementation = MethodCall.invoke(getModule).onMethodCall(MethodCall.invoke(forName).with(intermediate.getName())); - } - MethodCall sourceLookup = MethodCall.invoke(getModule).onMethodCall(MethodCall.invoke(forName).with(source.getName())); - if (needsExport) { - implementation = implementation.andThen(MethodCall.invoke(addExports) - .onMethodCall(sourceLookup) - .with(target.getPackage().getName()) - .withMethodCall(targetLookup)); - } - if (needsRead) { - implementation = implementation.andThen(MethodCall.invoke(addReads) - .onMethodCall(sourceLookup) - .withMethodCall(targetLookup)); - } - try { - Class.forName(byteBuddy.subclass(Object.class) - .name(String.format("%s$%s$%d", source.getName(), "MockitoModuleProbe", Math.abs(random.nextInt()))) - .invokable(isTypeInitializer()).intercept(implementation) - .make() - .load(source.getClassLoader(), loader.resolveStrategy(source, source.getClassLoader(), false)) - .getLoaded() - .getName(), true, source.getClassLoader()); - } catch (Exception e) { - throw new MockitoException(join("Could not force module adjustment of the module of " + source, - "", - "This is required to adjust the module graph to enable mock creation"), e); - } - } - - private static Object invoke(Method method, Object target, Object... args) { - try { - return method.invoke(target, args); - } catch (Exception e) { - throw new MockitoException(join("Could not invoke " + method + " using reflection", - "", - "Mockito attempted to interact with the Java module system but an unexpected method behavior was encountered"), e); - } - } - } - - private static class NoModuleSystemFound extends ModuleHandler { - - @Override - boolean isOpened(Class<?> source, Class<?> target) { - return true; - } - - @Override - boolean canRead(Class<?> source, Class<?> target) { - return true; - } - - @Override - boolean isExported(Class<?> source) { - return true; - } - - @Override - boolean isExported(Class<?> source, Class<?> target) { - return true; - } - - @Override - Class<?> injectionBase(ClassLoader classLoader, String tyoeName) { - return InjectionBase.class; - } - - @Override - void adjustModuleGraph(Class<?> source, Class<?> target, boolean export, boolean read) { - // empty - } - } -} diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java index 093978d..b659c73 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java @@ -15,7 +15,6 @@ import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.attribute.MethodAttributeAppender; import net.bytebuddy.matcher.ElementMatcher; -import org.mockito.codegen.InjectionBase; import org.mockito.exceptions.base.MockitoException; import org.mockito.internal.creation.bytebuddy.ByteBuddyCrossClassLoaderSerializationSupport.CrossClassLoaderSerializableMock; import org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.DispatcherDefaultingToRealMethod; @@ -27,9 +26,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; import java.util.Random; import static java.lang.Thread.currentThread; @@ -45,9 +41,10 @@ class SubclassBytecodeGenerator implements BytecodeGenerator { private static final String CODEGEN_PACKAGE = "org.mockito.codegen."; private final SubclassLoader loader; - private final ModuleHandler handler; + private final ByteBuddy byteBuddy; private final Random random; + private final Implementation readReplace; private final ElementMatcher<? super MethodDescription> matcher; @@ -74,128 +71,95 @@ class SubclassBytecodeGenerator implements BytecodeGenerator { this.matcher = matcher; byteBuddy = new ByteBuddy().with(TypeValidation.DISABLED); random = new Random(); - handler = ModuleHandler.make(byteBuddy, loader, random); } @Override public <T> Class<? extends T> mockClass(MockFeatures<T> features) { - ClassLoader classLoader = new MultipleParentClassLoader.Builder() - .appendMostSpecific(getAllTypes(features.mockedType)) - .appendMostSpecific(features.interfaces) - .appendMostSpecific(currentThread().getContextClassLoader()) - .appendMostSpecific(MockAccess.class) - .build(); - - // If Mockito does not need to create a new class loader and if a mock is not based on a JDK type, we attempt - // to define the mock class in the user runtime package to allow for mocking package private types and methods. - // This also requires that we are able to access the package of the mocked class either by override or explicit - // privilege given by the target package being opened to Mockito. - boolean localMock = classLoader == features.mockedType.getClassLoader() - && features.serializableMode != SerializableMode.ACROSS_CLASSLOADERS - && !isComingFromJDK(features.mockedType) - && (loader.isDisrespectingOpenness() || handler.isOpened(features.mockedType, MockAccess.class)); - String typeName; - if (localMock || loader instanceof MultipleParentClassLoader && !isComingFromJDK(features.mockedType)) { - typeName = features.mockedType.getName(); - } else { - typeName = InjectionBase.class.getPackage().getName() + "." + features.mockedType.getSimpleName(); - } - String name = String.format("%s$%s$%d", typeName, "MockitoMock", Math.abs(random.nextInt())); - - if (localMock) { - handler.adjustModuleGraph(features.mockedType, MockAccess.class, false, true); - for (Class<?> iFace : features.interfaces) { - handler.adjustModuleGraph(iFace, features.mockedType, true, false); - handler.adjustModuleGraph(features.mockedType, iFace, false, true); - } - } else { - boolean exported = handler.isExported(features.mockedType); - Iterator<Class<?>> it = features.interfaces.iterator(); - while (exported && it.hasNext()) { - exported = handler.isExported(it.next()); - } - // We check if all mocked types are exported without qualification to avoid generating a hook type. - // unless this is necessary. We expect this to be the case for most mocked types what makes this a - // worthy performance optimization. - if (exported) { - assertVisibility(features.mockedType); - for (Class<?> iFace : features.interfaces) { - assertVisibility(iFace); - } - } else { - Class<?> hook = handler.injectionBase(classLoader, typeName); - assertVisibility(features.mockedType); - handler.adjustModuleGraph(features.mockedType, hook, true, false); - for (Class<?> iFace : features.interfaces) { - assertVisibility(iFace); - handler.adjustModuleGraph(iFace, hook, true, false); - } - } - } - - DynamicType.Builder<T> builder = byteBuddy.subclass(features.mockedType) - .name(name) - .ignoreAlso(isGroovyMethod()) - .annotateType(features.stripAnnotations - ? new Annotation[0] - : features.mockedType.getAnnotations()) - .implement(new ArrayList<Type>(features.interfaces)) - .method(matcher) - .intercept(dispatcher) - .transform(withModifiers(SynchronizationState.PLAIN)) - .attribute(features.stripAnnotations - ? MethodAttributeAppender.NoOp.INSTANCE - : INCLUDING_RECEIVER) - .method(isHashCode()) - .intercept(hashCode) - .method(isEquals()) - .intercept(equals) - .serialVersionUid(42L) - .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) - .implement(MockAccess.class) - .intercept(FieldAccessor.ofBeanProperty()); + String name = nameFor(features.mockedType); + DynamicType.Builder<T> builder = + byteBuddy.subclass(features.mockedType) + .name(name) + .ignoreAlso(isGroovyMethod()) + .annotateType(features.stripAnnotations + ? new Annotation[0] + : features.mockedType.getAnnotations()) + .implement(new ArrayList<Type>(features.interfaces)) + .method(matcher) + .intercept(dispatcher) + .transform(withModifiers(SynchronizationState.PLAIN)) + .attribute(features.stripAnnotations + ? MethodAttributeAppender.NoOp.INSTANCE + : INCLUDING_RECEIVER) + .method(isHashCode()) + .intercept(hashCode) + .method(isEquals()) + .intercept(equals) + .serialVersionUid(42L) + .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) + .implement(MockAccess.class) + .intercept(FieldAccessor.ofBeanProperty()); if (features.serializableMode == SerializableMode.ACROSS_CLASSLOADERS) { builder = builder.implement(CrossClassLoaderSerializableMock.class) - .intercept(writeReplace); + .intercept(writeReplace); } if (readReplace != null) { builder = builder.defineMethod("readObject", void.class, Visibility.PRIVATE) - .withParameters(ObjectInputStream.class) - .throwing(ClassNotFoundException.class, IOException.class) - .intercept(readReplace); + .withParameters(ObjectInputStream.class) + .throwing(ClassNotFoundException.class, IOException.class) + .intercept(readReplace); } - if (name.startsWith(CODEGEN_PACKAGE) || classLoader instanceof MultipleParentClassLoader) { + ClassLoader classLoader = new MultipleParentClassLoader.Builder() + .append(features.mockedType) + .append(features.interfaces) + .append(currentThread().getContextClassLoader()) + .append(MockAccess.class, DispatcherDefaultingToRealMethod.class) + .append(MockMethodInterceptor.class, + MockMethodInterceptor.ForHashCode.class, + MockMethodInterceptor.ForEquals.class).build(MockMethodInterceptor.class.getClassLoader()); + if (classLoader != features.mockedType.getClassLoader()) { + assertVisibility(features.mockedType); + for (Class<?> iFace : features.interfaces) { + assertVisibility(iFace); + } builder = builder.ignoreAlso(isPackagePrivate() .or(returns(isPackagePrivate())) .or(hasParameters(whereAny(hasType(isPackagePrivate()))))); } return builder.make() - .load(classLoader, loader.resolveStrategy(features.mockedType, classLoader, localMock)) - .getLoaded(); - } - - private <T> Collection<Class<? super T>> getAllTypes(Class<T> type) { - Collection<Class<? super T>> supertypes = new LinkedList<Class<? super T>>(); - supertypes.add(type); - Class<? super T> superType = type; - while (superType != null) { - supertypes.add(superType); - superType = superType.getSuperclass(); - } - return supertypes; + .load(classLoader, loader.resolveStrategy(features.mockedType, classLoader, name.startsWith(CODEGEN_PACKAGE))) + .getLoaded(); } private static ElementMatcher<MethodDescription> isGroovyMethod() { return isDeclaredBy(named("groovy.lang.GroovyObjectSupport")); } + // TODO inspect naming strategy (for OSGI, signed package, java.* (and bootstrap classes), etc...) + private String nameFor(Class<?> type) { + String typeName = type.getName(); + if (isComingFromJDK(type) + || isComingFromSignedJar(type) + || isComingFromSealedPackage(type)) { + typeName = CODEGEN_PACKAGE + type.getSimpleName(); + } + return String.format("%s$%s$%d", typeName, "MockitoMock", Math.abs(random.nextInt())); + } + private boolean isComingFromJDK(Class<?> type) { // Comes from the manifest entry : // Implementation-Title: Java Runtime Environment // This entry is not necessarily present in every jar of the JDK return type.getPackage() != null && "Java Runtime Environment".equalsIgnoreCase(type.getPackage().getImplementationTitle()) - || type.getName().startsWith("java.") - || type.getName().startsWith("javax."); + || type.getName().startsWith("java.") + || type.getName().startsWith("javax."); + } + + private boolean isComingFromSealedPackage(Class<?> type) { + return type.getPackage() != null && type.getPackage().isSealed(); + } + + private boolean isComingFromSignedJar(Class<?> type) { + return type.getSigners() != null; } private static void assertVisibility(Class<?> type) { diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java index 89b0a30..454dd8e 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java @@ -25,7 +25,7 @@ class SubclassInjectionLoader implements SubclassLoader { private final SubclassLoader loader; SubclassInjectionLoader() { - if (!Boolean.getBoolean("org.mockito.internal.noUnsafeInjection") && ClassInjector.UsingReflection.isAvailable()) { + if (!Boolean.getBoolean("org.mockito.internal.simulateJava11") && ClassInjector.UsingReflection.isAvailable()) { this.loader = new WithReflection(); } else if (ClassInjector.UsingLookup.isAvailable()) { this.loader = tryLookup(); @@ -49,13 +49,8 @@ class SubclassInjectionLoader implements SubclassLoader { private static class WithReflection implements SubclassLoader { @Override - public boolean isDisrespectingOpenness() { - return true; - } - - @Override - public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean localMock) { - return ClassLoadingStrategy.Default.INJECTION.with(localMock ? mockedType.getProtectionDomain() : InjectionBase.class.getProtectionDomain()); + public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen) { + return ClassLoadingStrategy.Default.INJECTION.with(codegen ? InjectionBase.class.getProtectionDomain() : mockedType.getProtectionDomain()); } } @@ -74,13 +69,12 @@ class SubclassInjectionLoader implements SubclassLoader { } @Override - public boolean isDisrespectingOpenness() { - return false; - } - - @Override - public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean localMock) { - if (localMock) { + public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen) { + if (codegen) { + return ClassLoadingStrategy.UsingLookup.of(codegenLookup); + } else if (classLoader != mockedType.getClassLoader()) { + return ClassLoadingStrategy.Default.WRAPPER.with(mockedType.getProtectionDomain()); + } else { try { Object privateLookup; try { @@ -102,21 +96,12 @@ class SubclassInjectionLoader implements SubclassLoader { exception )); } - } else if (classLoader == InjectionBase.class.getClassLoader()) { - return ClassLoadingStrategy.UsingLookup.of(codegenLookup); - } else { - return ClassLoadingStrategy.Default.WRAPPER.with(mockedType.getProtectionDomain()); } } } @Override - public boolean isDisrespectingOpenness() { - return loader.isDisrespectingOpenness(); - } - - @Override - public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean localMock) { - return loader.resolveStrategy(mockedType, classLoader, localMock); + public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen) { + return loader.resolveStrategy(mockedType, classLoader, codegen); } } diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java index 011504e..194c282 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java @@ -12,19 +12,12 @@ import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; public interface SubclassLoader { /** - * Checks if this loader does not require a module to be open. - * - * @return {@code true} if this loader is not constraint to a target module being opened for loading a class. - */ - boolean isDisrespectingOpenness(); - - /** * Resolves a class loading strategy. * * @param mockedType The type being mocked. * @param classLoader The class loader being used. - * @param localMock {@code true} if the mock is loaded within the runtime package of the mocked type. + * @param codegen {@code true} if the mock is loaded in the {@code org.mockito.codegen} package. * @return An appropriate class loading strategy. */ - ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean localMock); + ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen); } diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/inject/MockMethodDispatcher.java b/src/main/java/org/mockito/internal/creation/bytebuddy/inject/MockMethodDispatcher.java deleted file mode 100644 index 12e30db..0000000 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/inject/MockMethodDispatcher.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2016 Mockito contributors - * This program is made available under the terms of the MIT License. - */ -package org.mockito.internal.creation.bytebuddy.inject; - -import java.lang.reflect.Method; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -public abstract class MockMethodDispatcher { - - private static final ConcurrentMap<String, MockMethodDispatcher> INSTANCE = new ConcurrentHashMap<String, MockMethodDispatcher>(); - - public static MockMethodDispatcher get(String identifier, Object mock) { - if (mock == INSTANCE) { // Avoid endless loop if ConcurrentHashMap was redefined to check for being a mock. - return null; - } else { - return INSTANCE.get(identifier); - } - } - - public static void set(String identifier, MockMethodDispatcher dispatcher) { - INSTANCE.putIfAbsent(identifier, dispatcher); - } - - public abstract Callable<?> handle(Object instance, Method origin, Object[] arguments) throws Throwable; - - public abstract boolean isMock(Object instance); - - public abstract boolean isMocked(Object instance); - - public abstract boolean isOverridden(Object instance, Method origin); -} diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/inject/package-info.java b/src/main/java/org/mockito/internal/creation/bytebuddy/inject/package-info.java deleted file mode 100644 index 5abed05..0000000 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/inject/package-info.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2007 Mockito contributors - * This program is made available under the terms of the MIT License. - */ - -/** - * Internal classes, not to be used by clients. Intended for injection into the bootstrap class loader. - * - * Subject to change at any time without notice. - */ -package org.mockito.internal.creation.bytebuddy.inject; diff --git a/src/main/java/org/mockito/internal/creation/settings/CreationSettings.java b/src/main/java/org/mockito/internal/creation/settings/CreationSettings.java index 3b45592..03afd80 100644 --- a/src/main/java/org/mockito/internal/creation/settings/CreationSettings.java +++ b/src/main/java/org/mockito/internal/creation/settings/CreationSettings.java @@ -4,8 +4,8 @@ */ package org.mockito.internal.creation.settings; +import org.mockito.internal.listeners.StubbingLookupListener; import org.mockito.listeners.InvocationListener; -import org.mockito.listeners.StubbingLookupListener; import org.mockito.listeners.VerificationStartedListener; import org.mockito.mock.MockCreationSettings; import org.mockito.mock.MockName; @@ -18,7 +18,6 @@ import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; public class CreationSettings<T> implements MockCreationSettings<T>, Serializable { private static final long serialVersionUID = -6789800638070123629L; @@ -31,11 +30,7 @@ public class CreationSettings<T> implements MockCreationSettings<T>, Serializabl protected MockName mockName; protected SerializableMode serializableMode = SerializableMode.NONE; protected List<InvocationListener> invocationListeners = new ArrayList<InvocationListener>(); - - //Other listeners in this class may also need concurrency-safe implementation. However, no issue was reported about it. - // If we do it, we need to understand usage patterns and choose the right concurrent implementation. - protected List<StubbingLookupListener> stubbingLookupListeners = new CopyOnWriteArrayList<StubbingLookupListener>(); - + protected final List<StubbingLookupListener> stubbingLookupListeners = new ArrayList<StubbingLookupListener>(); protected List<VerificationStartedListener> verificationStartedListeners = new LinkedList<VerificationStartedListener>(); protected boolean stubOnly; protected boolean stripAnnotations; @@ -48,7 +43,6 @@ public class CreationSettings<T> implements MockCreationSettings<T>, Serializabl @SuppressWarnings("unchecked") public CreationSettings(CreationSettings copy) { - //TODO can we have a reflection test here? We had a couple of bugs here in the past. this.typeToMock = copy.typeToMock; this.extraInterfaces = copy.extraInterfaces; this.name = copy.name; @@ -57,14 +51,12 @@ public class CreationSettings<T> implements MockCreationSettings<T>, Serializabl this.mockName = copy.mockName; this.serializableMode = copy.serializableMode; this.invocationListeners = copy.invocationListeners; - this.stubbingLookupListeners = copy.stubbingLookupListeners; this.verificationStartedListeners = copy.verificationStartedListeners; this.stubOnly = copy.stubOnly; this.useConstructor = copy.isUsingConstructor(); this.outerClassInstance = copy.getOuterClassInstance(); this.constructorArgs = copy.getConstructorArgs(); this.lenient = copy.lenient; - this.stripAnnotations = copy.stripAnnotations; } @Override diff --git a/src/main/java/org/mockito/internal/debugging/LocationImpl.java b/src/main/java/org/mockito/internal/debugging/LocationImpl.java index f1d14a6..8561b62 100644 --- a/src/main/java/org/mockito/internal/debugging/LocationImpl.java +++ b/src/main/java/org/mockito/internal/debugging/LocationImpl.java @@ -16,7 +16,6 @@ public class LocationImpl implements Location, Serializable { private final Throwable stackTraceHolder; private final StackTraceFilter stackTraceFilter; - private final String sourceFile; public LocationImpl() { this(defaultStackTraceFilter); @@ -33,13 +32,6 @@ public class LocationImpl implements Location, Serializable { private LocationImpl(StackTraceFilter stackTraceFilter, Throwable stackTraceHolder) { this.stackTraceFilter = stackTraceFilter; this.stackTraceHolder = stackTraceHolder; - if (stackTraceHolder.getStackTrace() == null || stackTraceHolder.getStackTrace().length == 0) { - //there are corner cases where exception can have a null or empty stack trace - //for example, a custom exception can override getStackTrace() method - this.sourceFile = "<unknown source file>"; - } else { - this.sourceFile = stackTraceFilter.findSourceFile(stackTraceHolder.getStackTrace(), "<unknown source file>"); - } } @Override @@ -51,9 +43,4 @@ public class LocationImpl implements Location, Serializable { } return "-> at " + filtered[0].toString(); } - - @Override - public String getSourceFile() { - return sourceFile; - } } diff --git a/src/main/java/org/mockito/internal/exceptions/Reporter.java b/src/main/java/org/mockito/internal/exceptions/Reporter.java index 1b68fbb..2bc4445 100644 --- a/src/main/java/org/mockito/internal/exceptions/Reporter.java +++ b/src/main/java/org/mockito/internal/exceptions/Reporter.java @@ -26,6 +26,7 @@ import org.mockito.invocation.Invocation; import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.Location; import org.mockito.listeners.InvocationListener; +import org.mockito.mock.MockName; import org.mockito.mock.SerializableMode; import java.lang.reflect.Field; @@ -83,7 +84,7 @@ public class Reporter { "Hints:", " 1. missing thenReturn()", " 2. you are trying to stub a final method, which is not supported", - " 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed", + " 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed", "" )); } @@ -276,10 +277,10 @@ public class Reporter { )); } - public static MockitoException stubPassedToVerify(Object mock) { + public static MockitoException stubPassedToVerify() { return new CannotVerifyStubOnlyMock(join( - "Argument \"" + MockUtil.getMockName(mock) + "\" passed to verify is a stubOnly() mock which cannot be verified.", - "If you intend to verify invocations on this mock, don't use stubOnly() in its MockSettings." + "Argument passed to verify() is a stubOnly() mock, not a full blown mock!", + "If you intend to verify invocations on a mock, don't use stubOnly() in its MockSettings." )); } @@ -436,7 +437,7 @@ public class Reporter { return new NoInteractionsWanted(join( "No interactions wanted here:", new LocationImpl(), - "But found this interaction on mock '" + MockUtil.getMockName(undesired.getMock()) + "':", + "But found this interaction on mock '" + safelyGetMockName(undesired.getMock()) + "':", undesired.getLocation(), scenario )); @@ -446,7 +447,7 @@ public class Reporter { return new VerificationInOrderFailure(join( "No interactions wanted here:", new LocationImpl(), - "But found this interaction on mock '" + MockUtil.getMockName(undesired.getMock()) + "':", + "But found this interaction on mock '" + safelyGetMockName(undesired.getMock()) + "':", undesired.getLocation() )); } @@ -512,7 +513,7 @@ public class Reporter { actualType + " cannot be returned by " + methodName + "()", methodName + "() should return " + expectedType, "", - "The default answer of " + MockUtil.getMockName(mock) + " that was configured on the mock is probably incorrectly implemented.", + "The default answer of " + safelyGetMockName(mock) + " that was configured on the mock is probably incorrectly implemented.", "" )); } @@ -672,7 +673,7 @@ public class Reporter { } public static MockitoException fieldInitialisationThrewException(Field field, Throwable details) { - return new InjectMocksException(join( + return new MockitoException(join( "Cannot instantiate @InjectMocks field named '" + field.getName() + "' of type '" + field.getType() + "'.", "You haven't provided the instance at field declaration so I tried to construct the instance.", "However the constructor or the initialization block threw an exception : " + details.getMessage(), @@ -684,8 +685,8 @@ public class Reporter { return new MockitoException(method + "() does not accept " + parameter + " See the Javadoc."); } - public static MockitoException requiresAtLeastOneListener(String method) { - return new MockitoException(method + "() requires at least one listener"); + public static MockitoException invocationListenersRequiresAtLeastOneListener() { + return new MockitoException("invocationListeners() requires at least one listener"); } public static MockitoException invocationListenerThrewException(InvocationListener listener, Throwable listenerThrowable) { @@ -696,7 +697,7 @@ public class Reporter { public static MockitoException cannotInjectDependency(Field field, Object matchingMock, Exception details) { return new MockitoException(join( - "Mockito couldn't inject mock dependency '" + MockUtil.getMockName(matchingMock) + "' on field ", + "Mockito couldn't inject mock dependency '" + safelyGetMockName(matchingMock) + "' on field ", "'" + field + "'", "whose type '" + field.getDeclaringClass().getCanonicalName() + "' was annotated by @InjectMocks in your test.", "Also I failed because: " + exceptionCauseMessageIfAvailable(details), @@ -739,7 +740,7 @@ public class Reporter { public static MockitoException invalidArgumentPositionRangeAtInvocationTime(InvocationOnMock invocation, boolean willReturnLastParameter, int argumentIndex) { return new MockitoException(join( "Invalid argument index for the current invocation of method : ", - " -> " + MockUtil.getMockName(invocation.getMock()) + "." + invocation.getMethod().getName() + "()", + " -> " + safelyGetMockName(invocation.getMock()) + "." + invocation.getMethod().getName() + "()", "", (willReturnLastParameter ? "Last parameter wanted" : @@ -773,7 +774,7 @@ public class Reporter { return new WrongTypeOfReturnValue(join( "The argument of type '" + actualType.getSimpleName() + "' cannot be returned because the following ", "method should return the type '" + expectedType + "'", - " -> " + MockUtil.getMockName(invocation.getMock()) + "." + invocation.getMethod().getName() + "()", + " -> " + safelyGetMockName(invocation.getMock()) + "." + invocation.getMethod().getName() + "()", "", "The reason for this error can be :", "1. The wanted argument position is incorrect.", @@ -810,7 +811,7 @@ public class Reporter { public static MockitoException delegatedMethodHasWrongReturnType(Method mockMethod, Method delegateMethod, Object mock, Object delegate) { return new MockitoException(join( "Methods called on delegated instance must have compatible return types with the mock.", - "When calling: " + mockMethod + " on mock: " + MockUtil.getMockName(mock), + "When calling: " + mockMethod + " on mock: " + safelyGetMockName(mock), "return type should be: " + mockMethod.getReturnType().getSimpleName() + ", but was: " + delegateMethod.getReturnType().getSimpleName(), "Check that the instance passed to delegatesTo() is of the correct type or contains compatible methods", "(delegate instance had type: " + delegate.getClass().getSimpleName() + ")" @@ -820,7 +821,7 @@ public class Reporter { public static MockitoException delegatedMethodDoesNotExistOnDelegate(Method mockMethod, Object mock, Object delegate) { return new MockitoException(join( "Methods called on mock must exist in delegated instance.", - "When calling: " + mockMethod + " on mock: " + MockUtil.getMockName(mock), + "When calling: " + mockMethod + " on mock: " + safelyGetMockName(mock), "no such method was found.", "Check that the instance passed to delegatesTo() is of the correct type or contains compatible methods", "(delegate instance had type: " + delegate.getClass().getSimpleName() + ")" @@ -848,6 +849,10 @@ public class Reporter { "This may happen with doThrow(Class)|thenThrow(Class) family of methods if passing null parameter.")); } + private static MockName safelyGetMockName(Object mock) { + return MockUtil.getMockName(mock); + } + public static UnnecessaryStubbingException formatUnncessaryStubbingException(Class<?> testClass, Collection<Invocation> unnecessaryStubbings) { StringBuilder stubbings = new StringBuilder(); int count = 1; diff --git a/src/main/java/org/mockito/internal/exceptions/stacktrace/StackTraceFilter.java b/src/main/java/org/mockito/internal/exceptions/stacktrace/StackTraceFilter.java index bf11d4c..e8b0cb0 100644 --- a/src/main/java/org/mockito/internal/exceptions/stacktrace/StackTraceFilter.java +++ b/src/main/java/org/mockito/internal/exceptions/stacktrace/StackTraceFilter.java @@ -37,17 +37,4 @@ public class StackTraceFilter implements Serializable { StackTraceElement[] result = new StackTraceElement[filtered.size()]; return filtered.toArray(result); } - - /** - * Finds the source file of the target stack trace. - * Returns the default value if source file cannot be found. - */ - public String findSourceFile(StackTraceElement[] target, String defaultValue) { - for (StackTraceElement e : target) { - if (CLEANER.isIn(e)) { - return e.getFileName(); - } - } - return defaultValue; - } } diff --git a/src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java b/src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java index d92fc28..69a733c 100644 --- a/src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java +++ b/src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java @@ -10,8 +10,6 @@ import org.mockito.internal.invocation.DefaultInvocationFactory; import org.mockito.internal.util.Checks; import org.mockito.invocation.InvocationFactory; import org.mockito.listeners.MockitoListener; -import org.mockito.plugins.InlineMockMaker; -import org.mockito.plugins.MockMaker; import org.mockito.plugins.MockitoPlugins; import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress; @@ -39,25 +37,4 @@ public class DefaultMockitoFramework implements MockitoFramework { public InvocationFactory getInvocationFactory() { return new DefaultInvocationFactory(); } - - private InlineMockMaker getInlineMockMaker() { - MockMaker mockMaker = Plugins.getMockMaker(); - return (mockMaker instanceof InlineMockMaker) ? (InlineMockMaker) mockMaker : null; - } - - @Override - public void clearInlineMocks() { - InlineMockMaker mockMaker = getInlineMockMaker(); - if (mockMaker != null) { - mockMaker.clearAllMocks(); - } - } - - @Override - public void clearInlineMock(Object mock) { - InlineMockMaker mockMaker = getInlineMockMaker(); - if (mockMaker != null) { - mockMaker.clearMock(mock); - } - } } diff --git a/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java b/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java index 6483a1c..c900bf7 100644 --- a/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java +++ b/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java @@ -11,17 +11,19 @@ import org.mockito.exceptions.misusing.RedundantListenerException; import org.mockito.internal.exceptions.Reporter; import org.mockito.internal.junit.TestFinishedEvent; import org.mockito.internal.junit.UniversalTestListener; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.quality.Strictness; import java.util.List; public class DefaultMockitoSession implements MockitoSession { + private final List<Object> testClassInstances; private final String name; private final UniversalTestListener listener; public DefaultMockitoSession(List<Object> testClassInstances, String name, Strictness strictness, MockitoLogger logger) { + this.testClassInstances = testClassInstances; this.name = name; listener = new UniversalTestListener(strictness, logger); try { @@ -30,14 +32,8 @@ public class DefaultMockitoSession implements MockitoSession { } catch (RedundantListenerException e) { Reporter.unfinishedMockingSession(); } - try { - for (Object testClassInstance : testClassInstances) { - MockitoAnnotations.initMocks(testClassInstance); - } - } catch (RuntimeException e) { - //clean up in case 'initMocks' fails - listener.setListenerDirty(); - throw e; + for (Object testClassInstance : testClassInstances) { + MockitoAnnotations.initMocks(testClassInstance); } } diff --git a/src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java b/src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java index ec1fcba..b9cf072 100644 --- a/src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java +++ b/src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java @@ -4,7 +4,6 @@ */ package org.mockito.internal.invocation; -import org.mockito.ArgumentMatcher; import org.mockito.internal.invocation.mockref.MockReference; import org.mockito.internal.exceptions.VerificationAwareInvocation; import org.mockito.internal.reporting.PrintSettings; @@ -14,10 +13,8 @@ import org.mockito.invocation.StubInfo; import java.lang.reflect.Method; import java.util.Arrays; -import java.util.List; import static org.mockito.internal.exceptions.Reporter.cannotCallAbstractRealMethod; -import static org.mockito.internal.invocation.ArgumentsProcessor.argumentsToMatchers; public class InterceptedInvocation implements Invocation, VerificationAwareInvocation { @@ -122,28 +119,6 @@ public class InterceptedInvocation implements Invocation, VerificationAwareInvoc return (T) arguments[index]; } - public MockReference<Object> getMockRef() { - return mockRef; - } - - public MockitoMethod getMockitoMethod() { - return mockitoMethod; - } - - public RealMethod getRealMethod() { - return realMethod; - } - - @Override - public List<ArgumentMatcher> getArgumentsAsMatchers() { - return argumentsToMatchers(getArguments()); - } - - @Override - public <T> T getArgument(int index, Class<T> clazz) { - return clazz.cast(arguments[index]); - } - @Override public Object callRealMethod() throws Throwable { if (!realMethod.isInvokable()) { @@ -174,7 +149,7 @@ public class InterceptedInvocation implements Invocation, VerificationAwareInvoc } public String toString() { - return new PrintSettings().print(getArgumentsAsMatchers(), this); + return new PrintSettings().print(ArgumentsProcessor.argumentsToMatchers(getArguments()), this); } public final static RealMethod NO_OP = new RealMethod() { diff --git a/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java b/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java index bc14300..83a28ff 100644 --- a/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java +++ b/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java @@ -5,6 +5,7 @@ package org.mockito.internal.invocation; +import static org.mockito.internal.invocation.ArgumentsProcessor.argumentsToMatchers; import static org.mockito.internal.invocation.MatcherApplicationStrategy.getMatcherApplicationStrategyFor; import static org.mockito.internal.invocation.TypeSafeMatching.matchesTypeSafe; @@ -35,7 +36,7 @@ public class InvocationMatcher implements MatchableInvocation, DescribedInvocati public InvocationMatcher(Invocation invocation, List<ArgumentMatcher> matchers) { this.invocation = invocation; if (matchers.isEmpty()) { - this.matchers = (List) invocation.getArgumentsAsMatchers(); + this.matchers = (List) argumentsToMatchers(invocation.getArguments()); } else { this.matchers = (List) matchers; } diff --git a/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java b/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java index b5d2022..4885d63 100644 --- a/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java +++ b/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java @@ -5,14 +5,13 @@ package org.mockito.internal.junit; import org.mockito.internal.exceptions.Reporter; +import org.mockito.internal.listeners.StubbingLookupEvent; +import org.mockito.internal.listeners.StubbingLookupListener; import org.mockito.internal.stubbing.UnusedStubbingReporting; import org.mockito.invocation.Invocation; -import org.mockito.listeners.StubbingLookupEvent; -import org.mockito.listeners.StubbingLookupListener; import org.mockito.quality.Strictness; import org.mockito.stubbing.Stubbing; -import java.io.Serializable; import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -23,9 +22,7 @@ import static org.mockito.internal.stubbing.StrictnessSelector.determineStrictne * Default implementation of stubbing lookup listener. * Fails early if stub called with unexpected arguments, but only if current strictness is set to STRICT_STUBS. */ -class DefaultStubbingLookupListener implements StubbingLookupListener, Serializable { - - private static final long serialVersionUID = -6789800638070123629L; +class DefaultStubbingLookupListener implements StubbingLookupListener { private Strictness currentStrictness; private boolean mismatchesReported; @@ -60,11 +57,8 @@ class DefaultStubbingLookupListener implements StubbingLookupListener, Serializa List<Invocation> matchingStubbings = new LinkedList<Invocation>(); for (Stubbing s : stubbings) { if (UnusedStubbingReporting.shouldBeReported(s) - && s.getInvocation().getMethod().getName().equals(invocation.getMethod().getName()) - //If stubbing and invocation are in the same source file we assume they are in the test code, - // and we don't flag it as mismatch: - && !s.getInvocation().getLocation().getSourceFile().equals(invocation.getLocation().getSourceFile())) { - matchingStubbings.add(s.getInvocation()); + && s.getInvocation().getMethod().getName().equals(invocation.getMethod().getName())) { + matchingStubbings.add(s.getInvocation()); } } return matchingStubbings; diff --git a/src/main/java/org/mockito/internal/junit/ExceptionFactory.java b/src/main/java/org/mockito/internal/junit/ExceptionFactory.java index 5db296e..3664aea 100644 --- a/src/main/java/org/mockito/internal/junit/ExceptionFactory.java +++ b/src/main/java/org/mockito/internal/junit/ExceptionFactory.java @@ -4,58 +4,49 @@ */ package org.mockito.internal.junit; +import junit.framework.ComparisonFailure; import org.mockito.exceptions.verification.ArgumentsAreDifferent; public class ExceptionFactory { + private final static boolean hasJUnit = canLoadJunitClass(); + private ExceptionFactory() { } - private static interface ExceptionFactoryImpl { - AssertionError create(String message, String wanted, String actual); + /** + * If JUnit is used, an AssertionError is returned that extends from JUnit {@link ComparisonFailure} and hence provide a better IDE support as the comparison result is comparable + */ + public static AssertionError createArgumentsAreDifferentException(String message, String wanted, String actual) { + if (hasJUnit) { + return createJUnitArgumentsAreDifferent(message, wanted, actual); + } + return new ArgumentsAreDifferent(message); } - private final static ExceptionFactoryImpl factory; - - static { - ExceptionFactoryImpl theFactory = null; + private static AssertionError createJUnitArgumentsAreDifferent(String message, String wanted, String actual) { + return JUnitArgsAreDifferent.create(message, wanted, actual); + } + private static boolean canLoadJunitClass() { try { - theFactory = new ExceptionFactoryImpl() { - @Override - public AssertionError create(String message, String wanted, String actual) { - return new org.mockito.exceptions.verification.opentest4j.ArgumentsAreDifferent(message, wanted, actual); - } - }; - } catch (Throwable onlyIfOpenTestIsNotAvailable) { - try { - theFactory = new ExceptionFactoryImpl() { - @Override - public AssertionError create(String message, String wanted, String actual) { - return new org.mockito.exceptions.verification.junit.ArgumentsAreDifferent(message, wanted, actual); - } - }; - } catch (Throwable onlyIfJUnitIsNotAvailable) { - } + JUnitArgsAreDifferent.create("message", "wanted", "actual"); + } catch (NoClassDefFoundError onlyIfJUnitIsNotAvailable) { + return false; } - factory = (theFactory == null) ? new ExceptionFactoryImpl() { - @Override - public AssertionError create(String message, String wanted, String actual) { - return new ArgumentsAreDifferent(message, wanted, actual); - } - } : theFactory; + return true; } /** - * Returns an AssertionError that describes the fact that the arguments of an invocation are different. - * If {@link org.opentest4j.AssertionFailedError} is on the class path (used by JUnit 5 and others), - * it returns a class that extends it. Otherwise, if {@link junit.framework.ComparisonFailure} is on the - * class path (shipped with JUnit 3 and 4), it will return a class that extends that. This provides - * better IDE support as the comparison result can be opened in a visual diff. If neither are available, - * it returns an instance of - * {@link org.mockito.exceptions.verification.ArgumentsAreDifferent}. + * Don't inline this class! It allows create the JUnit-ArgumentsAreDifferent exception without the need to use reflection. + * <p> + * If JUnit is not available a call to {@link #create(String, String, String)} will throw a {@link NoClassDefFoundError}. + * The {@link NoClassDefFoundError} will be thrown by the class loader cause the JUnit class {@link ComparisonFailure} + * can't be loaded which is a upper class of ArgumentsAreDifferent. */ - public static AssertionError createArgumentsAreDifferentException(String message, String wanted, String actual) { - return factory.create(message, wanted, actual); + private static class JUnitArgsAreDifferent { + static AssertionError create(String message, String wanted, String actual) { + return new org.mockito.exceptions.verification.junit.ArgumentsAreDifferent(message, wanted, actual); + } } } diff --git a/src/main/java/org/mockito/internal/junit/JUnitRule.java b/src/main/java/org/mockito/internal/junit/JUnitRule.java index 3bd3dac..b825416 100644 --- a/src/main/java/org/mockito/internal/junit/JUnitRule.java +++ b/src/main/java/org/mockito/internal/junit/JUnitRule.java @@ -7,10 +7,9 @@ package org.mockito.internal.junit; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import org.mockito.internal.session.MockitoSessionLoggerAdapter; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.quality.Strictness; import org.mockito.junit.MockitoRule; @@ -35,16 +34,12 @@ public class JUnitRule implements MockitoRule { public Statement apply(final Statement base, final FrameworkMethod method, final Object target) { return new Statement() { public void evaluate() throws Throwable { - if (session == null) { - session = Mockito.mockitoSession() - .name(target.getClass().getSimpleName() + "." + method.getName()) - .strictness(strictness) - .logger(new MockitoSessionLoggerAdapter(logger)) - .initMocks(target) - .startMocking(); - } else { - MockitoAnnotations.initMocks(target); - } + session = Mockito.mockitoSession() + .name(target.getClass().getSimpleName() + "." + method.getName()) + .strictness(strictness) + .logger(new MockitoSessionLoggerAdapter(logger)) + .initMocks(target) + .startMocking(); Throwable testFailure = evaluateSafely(base); session.finishMocking(testFailure); if (testFailure != null) { diff --git a/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java b/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java index d705396..26d4e4e 100644 --- a/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java +++ b/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java @@ -4,7 +4,7 @@ */ package org.mockito.internal.junit; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.mock.MockCreationSettings; import java.util.Collection; diff --git a/src/main/java/org/mockito/internal/junit/StrictStubsRunnerTestListener.java b/src/main/java/org/mockito/internal/junit/StrictStubsRunnerTestListener.java index d23431b..9e60c31 100644 --- a/src/main/java/org/mockito/internal/junit/StrictStubsRunnerTestListener.java +++ b/src/main/java/org/mockito/internal/junit/StrictStubsRunnerTestListener.java @@ -4,6 +4,7 @@ */ package org.mockito.internal.junit; +import org.mockito.internal.creation.settings.CreationSettings; import org.mockito.mock.MockCreationSettings; import org.mockito.quality.Strictness; @@ -21,8 +22,8 @@ public class StrictStubsRunnerTestListener implements MockitoTestListener { public void onMockCreated(Object mock, MockCreationSettings settings) { //It is not ideal that we modify the state of MockCreationSettings object //MockCreationSettings is intended to be an immutable view of the creation settings - //However, we our previous listeners work this way and it hasn't backfired. - //Since it is simple and pragmatic, we'll keep it for now. - settings.getStubbingLookupListeners().add(stubbingLookupListener); + //In future, we should start passing MockSettings object to the creation listener + //TODO #793 - when completed, we should be able to get rid of the CreationSettings casting below + ((CreationSettings) settings).getStubbingLookupListeners().add(stubbingLookupListener); } } diff --git a/src/main/java/org/mockito/internal/junit/StubbingArgMismatches.java b/src/main/java/org/mockito/internal/junit/StubbingArgMismatches.java index f125f60..3d6342c 100644 --- a/src/main/java/org/mockito/internal/junit/StubbingArgMismatches.java +++ b/src/main/java/org/mockito/internal/junit/StubbingArgMismatches.java @@ -4,7 +4,7 @@ */ package org.mockito.internal.junit; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.invocation.Invocation; import java.util.LinkedHashMap; diff --git a/src/main/java/org/mockito/internal/junit/UniversalTestListener.java b/src/main/java/org/mockito/internal/junit/UniversalTestListener.java index d681823..66c9dee 100644 --- a/src/main/java/org/mockito/internal/junit/UniversalTestListener.java +++ b/src/main/java/org/mockito/internal/junit/UniversalTestListener.java @@ -5,8 +5,7 @@ package org.mockito.internal.junit; import org.mockito.internal.creation.settings.CreationSettings; -import org.mockito.internal.listeners.AutoCleanableListener; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.mock.MockCreationSettings; import org.mockito.quality.Strictness; @@ -19,14 +18,13 @@ import java.util.Map; * Will come handy when we offer tweaking strictness at the method level with annotation. * Should be relatively easy to improve and offer tweaking strictness per mock. */ -public class UniversalTestListener implements MockitoTestListener, AutoCleanableListener { +public class UniversalTestListener implements MockitoTestListener { private Strictness currentStrictness; private final MockitoLogger logger; private Map<Object, MockCreationSettings> mocks = new IdentityHashMap<Object, MockCreationSettings>(); private DefaultStubbingLookupListener stubbingLookupListener; - private boolean listenerDirty; public UniversalTestListener(Strictness initialStrictness, MockitoLogger logger) { this.currentStrictness = initialStrictness; @@ -87,19 +85,4 @@ public class UniversalTestListener implements MockitoTestListener, AutoCleanable this.currentStrictness = strictness; this.stubbingLookupListener.setCurrentStrictness(strictness); } - - /** - * See {@link AutoCleanableListener#isListenerDirty()} - */ - @Override - public boolean isListenerDirty() { - return listenerDirty; - } - - /** - * Marks listener as dirty, scheduled for cleanup when the next session starts - */ - public void setListenerDirty() { - this.listenerDirty = true; - } } diff --git a/src/main/java/org/mockito/internal/junit/UnusedStubbings.java b/src/main/java/org/mockito/internal/junit/UnusedStubbings.java index d45b13d..3505d2c 100644 --- a/src/main/java/org/mockito/internal/junit/UnusedStubbings.java +++ b/src/main/java/org/mockito/internal/junit/UnusedStubbings.java @@ -5,7 +5,7 @@ package org.mockito.internal.junit; import org.mockito.internal.exceptions.Reporter; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.invocation.Invocation; import org.mockito.stubbing.Stubbing; diff --git a/src/main/java/org/mockito/internal/junit/VerificationCollectorImpl.java b/src/main/java/org/mockito/internal/junit/VerificationCollectorImpl.java index e54d478..7c19d35 100644 --- a/src/main/java/org/mockito/internal/junit/VerificationCollectorImpl.java +++ b/src/main/java/org/mockito/internal/junit/VerificationCollectorImpl.java @@ -75,7 +75,7 @@ public class VerificationCollectorImpl implements VerificationCollector { this.numberOfFailures++; this.builder.append('\n') .append(this.numberOfFailures).append(". ") - .append(message.trim()).append('\n'); + .append(message.substring(1, message.length())); } private class VerificationWrapper implements VerificationMode { @@ -89,7 +89,7 @@ public class VerificationCollectorImpl implements VerificationCollector { public void verify(VerificationData data) { try { this.delegate.verify(data); - } catch (AssertionError error) { + } catch (MockitoAssertionError error) { VerificationCollectorImpl.this.append(error.getMessage()); } } diff --git a/src/main/java/org/mockito/internal/listeners/AutoCleanableListener.java b/src/main/java/org/mockito/internal/listeners/AutoCleanableListener.java deleted file mode 100644 index cfd2a53..0000000 --- a/src/main/java/org/mockito/internal/listeners/AutoCleanableListener.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2018 Mockito contributors - * This program is made available under the terms of the MIT License. - */ -package org.mockito.internal.listeners; - -/** - * Listener that is automatically cleaned up (removed from the the global list of subscribers). - * For now, we don't intend to make this interface public. - */ -public interface AutoCleanableListener { - - /** - * Indicates that the listener is dirty and should be removed from the subscribers - */ - boolean isListenerDirty(); -} diff --git a/src/main/java/org/mockito/internal/listeners/StubbingLookupNotifier.java b/src/main/java/org/mockito/internal/listeners/StubbingLookupNotifier.java index a0de0c3..3e55001 100644 --- a/src/main/java/org/mockito/internal/listeners/StubbingLookupNotifier.java +++ b/src/main/java/org/mockito/internal/listeners/StubbingLookupNotifier.java @@ -6,8 +6,6 @@ package org.mockito.internal.listeners; import org.mockito.internal.creation.settings.CreationSettings; import org.mockito.invocation.Invocation; -import org.mockito.listeners.StubbingLookupEvent; -import org.mockito.listeners.StubbingLookupListener; import org.mockito.mock.MockCreationSettings; import org.mockito.stubbing.Stubbing; diff --git a/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java b/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java index 5c4fbbc..2685ddf 100644 --- a/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java +++ b/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java @@ -9,7 +9,6 @@ import org.mockito.internal.configuration.GlobalConfiguration; import org.mockito.internal.debugging.Localized; import org.mockito.internal.debugging.LocationImpl; import org.mockito.internal.exceptions.Reporter; -import org.mockito.internal.listeners.AutoCleanableListener; import org.mockito.invocation.Location; import org.mockito.listeners.MockCreationListener; import org.mockito.listeners.MockitoListener; @@ -20,8 +19,6 @@ import org.mockito.verification.VerificationMode; import org.mockito.verification.VerificationStrategy; import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; import java.util.Set; import static org.mockito.internal.exceptions.Reporter.unfinishedStubbing; @@ -157,28 +154,12 @@ public class MockingProgressImpl implements MockingProgress { } public void addListener(MockitoListener listener) { - addListener(listener, listeners); - } - - static void addListener(MockitoListener listener, Set<MockitoListener> listeners) { - List<MockitoListener> delete = new LinkedList<MockitoListener>(); for (MockitoListener existing : listeners) { if (existing.getClass().equals(listener.getClass())) { - if (existing instanceof AutoCleanableListener && ((AutoCleanableListener) existing).isListenerDirty()) { - //dirty listener means that there was an exception even before the test started - //if we fail here with redundant mockito listener exception there will be multiple failures causing confusion - //so we simply remove the existing listener and move on - delete.add(existing); - } else { - Reporter.redundantMockitoListener(listener.getClass().getSimpleName()); - } + Reporter.redundantMockitoListener(listener.getClass().getSimpleName()); } } - //delete dirty listeners so they don't occupy state/memory and don't receive notifications - for (MockitoListener toDelete : delete) { - listeners.remove(toDelete); - } - listeners.add(listener); + this.listeners.add(listener); } public void removeListener(MockitoListener listener) { diff --git a/src/main/java/org/mockito/internal/reporting/PrintSettings.java b/src/main/java/org/mockito/internal/reporting/PrintSettings.java index 4fc5992..7986c35 100644 --- a/src/main/java/org/mockito/internal/reporting/PrintSettings.java +++ b/src/main/java/org/mockito/internal/reporting/PrintSettings.java @@ -5,6 +5,7 @@ package org.mockito.internal.reporting; import org.mockito.ArgumentMatcher; +import org.mockito.internal.invocation.ArgumentsProcessor; import org.mockito.internal.matchers.text.MatchersPrinter; import org.mockito.internal.util.MockUtil; import org.mockito.invocation.Invocation; @@ -54,7 +55,7 @@ public class PrintSettings { } public String print(Invocation invocation) { - return print(invocation.getArgumentsAsMatchers(), invocation); + return print(ArgumentsProcessor.argumentsToMatchers(invocation.getArguments()), invocation); } public String print(MatchableInvocation invocation) { diff --git a/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java b/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java index 93aa32d..2f26ff1 100644 --- a/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java +++ b/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java @@ -30,29 +30,34 @@ public class DefaultInternalRunner implements InternalRunner { public Object target; private MockitoTestListener mockitoTestListener; - protected Statement withBefores(FrameworkMethod method, final Object target, Statement statement) { + protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) { this.target = target; - final Statement base = super.withBefores(method, target, statement); - return new Statement() { - @Override - public void evaluate() throws Throwable { - // get new test listener and add it to the framework - mockitoTestListener = listenerSupplier.get(); - Mockito.framework().addListener(mockitoTestListener); - // init annotated mocks before tests - MockitoAnnotations.initMocks(target); - base.evaluate(); - } - }; + // get new test listener and add it to the framework + mockitoTestListener = listenerSupplier.get(); + Mockito.framework().addListener(mockitoTestListener); + // init annotated mocks before tests + MockitoAnnotations.initMocks(target); + return super.withBefores(method, target, statement); } public void run(final RunNotifier notifier) { RunListener listener = new RunListener() { + private boolean started; Throwable failure; @Override + public void testStarted(Description description) throws Exception { + started = true; + } + + @Override public void testFailure(Failure failure) throws Exception { this.failure = failure.getException(); + // If the test fails during the setup, `testFinished` is never invoked + // Therefore, if we have not started, cleanup the testlistener + if (!started && mockitoTestListener != null) { + Mockito.framework().removeListener(mockitoTestListener); + } } @Override diff --git a/src/main/java/org/mockito/internal/runners/RunnerFactory.java b/src/main/java/org/mockito/internal/runners/RunnerFactory.java index efdb6b2..61456dc 100644 --- a/src/main/java/org/mockito/internal/runners/RunnerFactory.java +++ b/src/main/java/org/mockito/internal/runners/RunnerFactory.java @@ -5,12 +5,12 @@ package org.mockito.internal.runners; import org.mockito.exceptions.base.MockitoException; -import org.mockito.internal.configuration.plugins.Plugins; import org.mockito.internal.junit.MismatchReportingTestListener; import org.mockito.internal.junit.MockitoTestListener; import org.mockito.internal.junit.NoOpTestListener; import org.mockito.internal.junit.StrictStubsRunnerTestListener; import org.mockito.internal.runners.util.RunnerProvider; +import org.mockito.internal.util.ConsoleMockitoLogger; import org.mockito.internal.util.Supplier; import java.lang.reflect.InvocationTargetException; @@ -39,7 +39,7 @@ public class RunnerFactory { public InternalRunner createStrict(Class<?> klass) throws InvocationTargetException { return create(klass, new Supplier<MockitoTestListener>() { public MockitoTestListener get() { - return new MismatchReportingTestListener(Plugins.getMockitoLogger()); + return new MismatchReportingTestListener(new ConsoleMockitoLogger()); } }); } diff --git a/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java b/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java index f47ee15..d9b21e5 100644 --- a/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java +++ b/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java @@ -5,9 +5,9 @@ package org.mockito.internal.session; import org.mockito.MockitoSession; -import org.mockito.internal.configuration.plugins.Plugins; import org.mockito.internal.framework.DefaultMockitoSession; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.ConsoleMockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.quality.Strictness; import org.mockito.session.MockitoSessionBuilder; import org.mockito.session.MockitoSessionLogger; @@ -74,7 +74,7 @@ public class DefaultMockitoSessionBuilder implements MockitoSessionBuilder { effectiveName = this.name == null ? lastTestClassInstance.getClass().getName() : this.name; } Strictness effectiveStrictness = this.strictness == null ? Strictness.STRICT_STUBS : this.strictness; - MockitoLogger logger = this.logger == null ? Plugins.getMockitoLogger() : new MockitoLoggerAdapter(this.logger); + MockitoLogger logger = this.logger == null ? new ConsoleMockitoLogger() : new MockitoLoggerAdapter(this.logger); return new DefaultMockitoSession(effectiveTestClassInstances, effectiveName, effectiveStrictness, logger); } } diff --git a/src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java b/src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java index 2197317..b7329e7 100644 --- a/src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java +++ b/src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java @@ -4,7 +4,7 @@ */ package org.mockito.internal.session; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.session.MockitoSessionLogger; class MockitoLoggerAdapter implements MockitoLogger { diff --git a/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java b/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java index f4770c5..2e8634b 100644 --- a/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java +++ b/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java @@ -4,7 +4,7 @@ */ package org.mockito.internal.session; -import org.mockito.plugins.MockitoLogger; +import org.mockito.internal.util.MockitoLogger; import org.mockito.session.MockitoSessionLogger; public class MockitoSessionLoggerAdapter implements MockitoSessionLogger { diff --git a/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java b/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java index 4c86cbd..6dd99cd 100644 --- a/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java +++ b/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java @@ -4,31 +4,17 @@ */ package org.mockito.internal.stubbing; +import static org.mockito.internal.exceptions.Reporter.notAnException; +import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress; +import static org.objenesis.ObjenesisHelper.newInstance; + import org.mockito.internal.stubbing.answers.CallsRealMethods; import org.mockito.internal.stubbing.answers.Returns; import org.mockito.internal.stubbing.answers.ThrowsException; -import org.mockito.stubbing.Answer; import org.mockito.stubbing.OngoingStubbing; -import static org.mockito.internal.exceptions.Reporter.notAnException; -import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress; -import static org.objenesis.ObjenesisHelper.newInstance; - public abstract class BaseStubbing<T> implements OngoingStubbing<T> { - - // Keep strong ref to mock preventing premature garbage collection when using 'One-liner stubs'. See #1541. - private final Object strongMockRef; - - BaseStubbing(Object mock) { - this.strongMockRef = mock; - } - - @Override - public OngoingStubbing<T> then(Answer<?> answer) { - return thenAnswer(answer); - } - @Override public OngoingStubbing<T> thenReturn(T value) { return thenAnswer(new Returns(value)); @@ -93,12 +79,6 @@ public abstract class BaseStubbing<T> implements OngoingStubbing<T> { public OngoingStubbing<T> thenCallRealMethod() { return thenAnswer(new CallsRealMethods()); } - - @Override - @SuppressWarnings("unchecked") - public <M> M getMock() { - return (M) this.strongMockRef; - } } diff --git a/src/main/java/org/mockito/internal/stubbing/ConsecutiveStubbing.java b/src/main/java/org/mockito/internal/stubbing/ConsecutiveStubbing.java index 32ef8ee..a5cdc04 100644 --- a/src/main/java/org/mockito/internal/stubbing/ConsecutiveStubbing.java +++ b/src/main/java/org/mockito/internal/stubbing/ConsecutiveStubbing.java @@ -8,17 +8,23 @@ import org.mockito.stubbing.Answer; import org.mockito.stubbing.OngoingStubbing; public class ConsecutiveStubbing<T> extends BaseStubbing<T> { + private final InvocationContainerImpl invocationContainerImpl; - private final InvocationContainerImpl invocationContainer; - - ConsecutiveStubbing(InvocationContainerImpl invocationContainer) { - super(invocationContainer.invokedMock()); - this.invocationContainer = invocationContainer; + public ConsecutiveStubbing(InvocationContainerImpl invocationContainerImpl) { + this.invocationContainerImpl = invocationContainerImpl; } public OngoingStubbing<T> thenAnswer(Answer<?> answer) { - invocationContainer.addConsecutiveAnswer(answer); + invocationContainerImpl.addConsecutiveAnswer(answer); return this; } + public OngoingStubbing<T> then(Answer<?> answer) { + return thenAnswer(answer); + } + + @SuppressWarnings("unchecked") + public <M> M getMock() { + return (M) invocationContainerImpl.invokedMock(); + } } diff --git a/src/main/java/org/mockito/internal/stubbing/OngoingStubbingImpl.java b/src/main/java/org/mockito/internal/stubbing/OngoingStubbingImpl.java index 4191604..cd27c39 100644 --- a/src/main/java/org/mockito/internal/stubbing/OngoingStubbingImpl.java +++ b/src/main/java/org/mockito/internal/stubbing/OngoingStubbingImpl.java @@ -19,7 +19,6 @@ public class OngoingStubbingImpl<T> extends BaseStubbing<T> { private Strictness strictness; public OngoingStubbingImpl(InvocationContainerImpl invocationContainer) { - super(invocationContainer.invokedMock()); this.invocationContainer = invocationContainer; } @@ -33,11 +32,22 @@ public class OngoingStubbingImpl<T> extends BaseStubbing<T> { return new ConsecutiveStubbing<T>(invocationContainer); } + @Override + public OngoingStubbing<T> then(Answer<?> answer) { + return thenAnswer(answer); + } + public List<Invocation> getRegisteredInvocations() { //TODO interface for tests return invocationContainer.getInvocations(); } + @Override + @SuppressWarnings("unchecked") + public <M> M getMock() { + return (M) invocationContainer.invokedMock(); + } + public void setStrictness(Strictness strictness) { this.strictness = strictness; } diff --git a/src/main/java/org/mockito/internal/stubbing/StubberImpl.java b/src/main/java/org/mockito/internal/stubbing/StubberImpl.java index 42795a7..2172809 100644 --- a/src/main/java/org/mockito/internal/stubbing/StubberImpl.java +++ b/src/main/java/org/mockito/internal/stubbing/StubberImpl.java @@ -87,16 +87,12 @@ public class StubberImpl implements Stubber { mockingProgress().reset(); throw notAnException(); } - Throwable e = null; + Throwable e; try { e = newInstance(toBeThrown); - } finally { - if (e == null) { - //this means that an exception or error was thrown when trying to create new instance - //we don't want 'catch' statement here because we want the exception to be thrown to the user - //however, we do want to clean up state (e.g. "stubbing started"). - mockingProgress().reset(); - } + } catch (RuntimeException instantiationError) { + mockingProgress().reset(); + throw instantiationError; } return doThrow(e); } diff --git a/src/main/java/org/mockito/internal/stubbing/answers/AnswerFunctionalInterfaces.java b/src/main/java/org/mockito/internal/stubbing/answers/AnswerFunctionalInterfaces.java index eaa6493..e1a92a4 100644 --- a/src/main/java/org/mockito/internal/stubbing/answers/AnswerFunctionalInterfaces.java +++ b/src/main/java/org/mockito/internal/stubbing/answers/AnswerFunctionalInterfaces.java @@ -11,13 +11,11 @@ import org.mockito.stubbing.Answer2; import org.mockito.stubbing.Answer3; import org.mockito.stubbing.Answer4; import org.mockito.stubbing.Answer5; -import org.mockito.stubbing.Answer6; import org.mockito.stubbing.VoidAnswer1; import org.mockito.stubbing.VoidAnswer2; import org.mockito.stubbing.VoidAnswer3; import org.mockito.stubbing.VoidAnswer4; import org.mockito.stubbing.VoidAnswer5; -import org.mockito.stubbing.VoidAnswer6; /** * Functional interfaces to make it easy to implement answers in Java 8 @@ -238,60 +236,4 @@ public class AnswerFunctionalInterfaces { } }; } - - /** - * Construct an answer from a six parameter answer interface - * - * @param answer answer interface - * @param <T> return type - * @param <A> input parameter 1 type - * @param <B> input parameter 2 type - * @param <C> input parameter 3 type - * @param <D> input parameter 4 type - * @param <E> input parameter 5 type - * @param <F> input parameter 6 type - * @return a new answer object - */ - public static <T, A, B, C, D, E, F> Answer<T> toAnswer(final Answer6<T, A, B, C, D, E, F> answer) { - return new Answer<T>() { - @SuppressWarnings("unchecked") - public T answer(InvocationOnMock invocation) throws Throwable { - return answer.answer( - (A)invocation.getArgument(0), - (B)invocation.getArgument(1), - (C)invocation.getArgument(2), - (D)invocation.getArgument(3), - (E)invocation.getArgument(4), - (F)invocation.getArgument(5)); - } - }; - } - - /** - * Construct an answer from a five parameter answer interface - - * @param answer answer interface - * @param <A> input parameter 1 type - * @param <B> input parameter 2 type - * @param <C> input parameter 3 type - * @param <D> input parameter 4 type - * @param <E> input parameter 5 type - * @param <F> input parameter 6 type - * @return a new answer object - */ - public static <A, B, C, D, E, F> Answer<Void> toAnswer(final VoidAnswer6<A, B, C, D, E, F> answer) { - return new Answer<Void>() { - @SuppressWarnings("unchecked") - public Void answer(InvocationOnMock invocation) throws Throwable { - answer.answer( - (A)invocation.getArgument(0), - (B)invocation.getArgument(1), - (C)invocation.getArgument(2), - (D)invocation.getArgument(3), - (E)invocation.getArgument(4), - (F)invocation.getArgument(5)); - return null; - } - }; - } } diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ForwardsInvocations.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ForwardsInvocations.java index 7ef283c..9165142 100644 --- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ForwardsInvocations.java +++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ForwardsInvocations.java @@ -40,11 +40,6 @@ public class ForwardsInvocations implements Answer<Object>, Serializable { } Object[] rawArguments = ((Invocation) invocation).getRawArguments(); - try { - delegateMethod.setAccessible(true); - } catch (SecurityException ignore) { - // try to invoke anyway - } return delegateMethod.invoke(delegatedObject, rawArguments); } catch (NoSuchMethodException e) { throw delegatedMethodDoesNotExistOnDelegate(mockMethod, invocation.getMock(), delegatedObject); diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java deleted file mode 100644 index 979c8f7..0000000 --- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2007 Mockito contributors - * This program is made available under the terms of the MIT License. - */ -package org.mockito.internal.stubbing.defaultanswers; - -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import org.mockito.internal.MockitoCore; -import org.mockito.internal.util.MockUtil; -import org.mockito.internal.util.reflection.GenericMetadataSupport; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.mock.MockCreationSettings; - -class RetrieveGenericsForDefaultAnswers { - - private static final MockitoCore MOCKITO_CORE = new MockitoCore(); - - static Object returnTypeForMockWithCorrectGenerics( - InvocationOnMock invocation, AnswerCallback answerCallback) { - Class<?> type = invocation.getMethod().getReturnType(); - - final Type returnType = invocation.getMethod().getGenericReturnType(); - - Object defaultReturnValue = null; - - if (returnType instanceof TypeVariable) { - type = findTypeFromGeneric(invocation, (TypeVariable) returnType); - if (type != null) { - defaultReturnValue = delegateChains(type); - } - } - - if (defaultReturnValue != null) { - return defaultReturnValue; - } - - if (type != null) { - if (!MOCKITO_CORE.isTypeMockable(type)) { - return null; - } - - return answerCallback.apply(type); - } - - return answerCallback.apply(null); - } - - /** - * Try to resolve the result value using {@link ReturnsEmptyValues} and {@link ReturnsMoreEmptyValues}. - * - * This will try to use all parent class (superclass & interfaces) to retrieve the value.. - * - * @param type the return type of the method - * @return a non-null instance if the type has been resolve. Null otherwise. - */ - private static Object delegateChains(final Class<?> type) { - final ReturnsEmptyValues returnsEmptyValues = new ReturnsEmptyValues(); - Object result = returnsEmptyValues.returnValueFor(type); - - if (result == null) { - Class<?> emptyValueForClass = type; - while (emptyValueForClass != null && result == null) { - final Class<?>[] classes = emptyValueForClass.getInterfaces(); - for (Class<?> clazz : classes) { - result = returnsEmptyValues.returnValueFor(clazz); - if (result != null) { - break; - } - } - emptyValueForClass = emptyValueForClass.getSuperclass(); - } - } - - if (result == null) { - result = new ReturnsMoreEmptyValues().returnValueFor(type); - } - - return result; - } - - /** - * Retrieve the expected type when it came from a primitive. If the type cannot be retrieve, return null. - * - * @param invocation the current invocation - * @param returnType the expected return type - * @return the type or null if not found - */ - private static Class<?> findTypeFromGeneric(final InvocationOnMock invocation, final TypeVariable returnType) { - // Class level - final MockCreationSettings mockSettings = MockUtil.getMockHandler(invocation.getMock()).getMockSettings(); - final GenericMetadataSupport returnTypeSupport = GenericMetadataSupport - .inferFrom(mockSettings.getTypeToMock()) - .resolveGenericReturnType(invocation.getMethod()); - final Class<?> rawType = returnTypeSupport.rawType(); - - // Method level - if (rawType == Object.class) { - return findTypeFromGenericInArguments(invocation, returnType); - } - return rawType; - } - - /** - * Find a return type using generic arguments provided by the calling method. - * - * @param invocation the current invocation - * @param returnType the expected return type - * @return the return type or null if the return type cannot be found - */ - private static Class<?> findTypeFromGenericInArguments(final InvocationOnMock invocation, final TypeVariable returnType) { - final Type[] parameterTypes = invocation.getMethod().getGenericParameterTypes(); - for (int i = 0; i < parameterTypes.length; i++) { - Type argType = parameterTypes[i]; - if (returnType.equals(argType)) { - Object argument = invocation.getArgument(i); - - if (argument == null) { - return null; - } - - return argument.getClass(); - } - if (argType instanceof GenericArrayType) { - argType = ((GenericArrayType) argType).getGenericComponentType(); - if (returnType.equals(argType)) { - return invocation.getArgument(i).getClass(); - } - } - } - return null; - } - - interface AnswerCallback { - Object apply(Class<?> type); - } -} diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java index 356b2e6..3909ff0 100644 --- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java +++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java @@ -25,7 +25,7 @@ import static org.mockito.Mockito.withSettings; /** * Returning deep stub implementation. * - * <p>Will return previously created mock if the invocation matches. + * Will return previously created mock if the invocation matches. * * <p>Supports nested generic information, with this answer you can write code like this : * @@ -37,8 +37,6 @@ import static org.mockito.Mockito.withSettings; * </code></pre> * </p> * - * <p>However this answer does not support generics information when the mock has been deserialized. - * * @see org.mockito.Mockito#RETURNS_DEEP_STUBS * @see org.mockito.Answers#RETURNS_DEEP_STUBS */ @@ -48,22 +46,13 @@ public class ReturnsDeepStubs implements Answer<Object>, Serializable { public Object answer(InvocationOnMock invocation) throws Throwable { GenericMetadataSupport returnTypeGenericMetadata = - actualParameterizedType(invocation.getMock()).resolveGenericReturnType(invocation.getMethod()); + actualParameterizedType(invocation.getMock()).resolveGenericReturnType(invocation.getMethod()); Class<?> rawType = returnTypeGenericMetadata.rawType(); if (!mockitoCore().isTypeMockable(rawType)) { return delegate().returnValueFor(rawType); } - // When dealing with erased generics, we only receive the Object type as rawType. At this - // point, there is nothing to salvage for Mockito. Instead of trying to be smart and generate - // a mock that would potentially match the return signature, instead return `null`. This - // is valid per the CheckCast JVM instruction and is better than causing a ClassCastException - // on runtime. - if (rawType.equals(Object.class) && !returnTypeGenericMetadata.hasRawExtraInterfaces()) { - return null; - } - return deepStub(invocation, returnTypeGenericMetadata); } @@ -80,9 +69,9 @@ public class ReturnsDeepStubs implements Answer<Object>, Serializable { // record deep stub answer StubbedInvocationMatcher stubbing = recordDeepStubAnswer( - newDeepStubMock(returnTypeGenericMetadata, invocation.getMock()), - container - ); + newDeepStubMock(returnTypeGenericMetadata, invocation.getMock()), + container + ); // deep stubbing creates a stubbing and immediately uses it // so the stubbing is actually used by the same invocation @@ -99,24 +88,24 @@ public class ReturnsDeepStubs implements Answer<Object>, Serializable { * {@link ReturnsDeepStubs} answer in which we will store the returned type generic metadata. * * @param returnTypeGenericMetadata The metadata to use to create the new mock. - * @param parentMock The parent of the current deep stub mock. + * @param parentMock The parent of the current deep stub mock. * @return The mock */ private Object newDeepStubMock(GenericMetadataSupport returnTypeGenericMetadata, Object parentMock) { MockCreationSettings parentMockSettings = MockUtil.getMockSettings(parentMock); return mockitoCore().mock( - returnTypeGenericMetadata.rawType(), - withSettingsUsing(returnTypeGenericMetadata, parentMockSettings) - ); + returnTypeGenericMetadata.rawType(), + withSettingsUsing(returnTypeGenericMetadata, parentMockSettings) + ); } private MockSettings withSettingsUsing(GenericMetadataSupport returnTypeGenericMetadata, MockCreationSettings parentMockSettings) { MockSettings mockSettings = returnTypeGenericMetadata.hasRawExtraInterfaces() ? - withSettings().extraInterfaces(returnTypeGenericMetadata.rawExtraInterfaces()) - : withSettings(); + withSettings().extraInterfaces(returnTypeGenericMetadata.rawExtraInterfaces()) + : withSettings(); return propagateSerializationSettings(mockSettings, parentMockSettings) - .defaultAnswer(returnsDeepStubsAnswerUsing(returnTypeGenericMetadata)); + .defaultAnswer(returnsDeepStubsAnswerUsing(returnTypeGenericMetadata)); } private MockSettings propagateSerializationSettings(MockSettings mockSettings, MockCreationSettings parentMockSettings) { @@ -150,15 +139,6 @@ public class ReturnsDeepStubs implements Answer<Object>, Serializable { protected GenericMetadataSupport actualParameterizedType(Object mock) { return returnTypeGenericMetadata; } - - /** - * Generics support and serialization with deep stubs don't work together. - * <p> - * The issue is that GenericMetadataSupport is not serializable because - * the type elements inferred via reflection are not serializable. Supporting - * serialization would require to replace all types coming from the Java reflection - * with our own and still managing type equality with the JDK ones. - */ private Object writeReplace() throws IOException { return Mockito.RETURNS_DEEP_STUBS; } @@ -172,7 +152,6 @@ public class ReturnsDeepStubs implements Answer<Object>, Serializable { DeeplyStubbedAnswer(Object mock) { this.mock = mock; } - public Object answer(InvocationOnMock invocation) throws Throwable { return mock; } diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsMocks.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsMocks.java index 5d4befe..302e4df 100755 --- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsMocks.java +++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsMocks.java @@ -4,36 +4,33 @@ */ package org.mockito.internal.stubbing.defaultanswers; -import java.io.Serializable; -import org.mockito.Mockito; +import org.mockito.internal.MockitoCore; import org.mockito.internal.creation.MockSettingsImpl; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.io.Serializable; + public class ReturnsMocks implements Answer<Object>, Serializable { private static final long serialVersionUID = -6755257986994634579L; + private final MockitoCore mockitoCore = new MockitoCore(); private final Answer<Object> delegate = new ReturnsMoreEmptyValues(); - @Override - public Object answer(final InvocationOnMock invocation) throws Throwable { - Object defaultReturnValue = delegate.answer(invocation); + public Object answer(InvocationOnMock invocation) throws Throwable { + Object ret = delegate.answer(invocation); + if (ret != null) { + return ret; + } + + return returnValueFor(invocation.getMethod().getReturnType()); + } - if (defaultReturnValue != null) { - return defaultReturnValue; + Object returnValueFor(Class<?> clazz) { + if (!mockitoCore.isTypeMockable(clazz)) { + return null; } - return RetrieveGenericsForDefaultAnswers.returnTypeForMockWithCorrectGenerics(invocation, - new RetrieveGenericsForDefaultAnswers.AnswerCallback() { - @Override - public Object apply(Class<?> type) { - if (type == null) { - type = invocation.getMethod().getReturnType(); - } - - return Mockito - .mock(type, new MockSettingsImpl<Object>().defaultAnswer(ReturnsMocks.this)); - } - }); + return mockitoCore.mock(clazz, new MockSettingsImpl().defaultAnswer(this)); } } diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsSmartNulls.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsSmartNulls.java index 6cf50c7..7487e89 100644 --- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsSmartNulls.java +++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsSmartNulls.java @@ -8,6 +8,8 @@ import static org.mockito.internal.exceptions.Reporter.smartNullPointerException import static org.mockito.internal.util.ObjectMethodsGuru.isToStringMethod; import java.io.Serializable; +import java.lang.reflect.Modifier; + import org.mockito.Mockito; import org.mockito.internal.debugging.LocationImpl; import org.mockito.invocation.InvocationOnMock; @@ -38,34 +40,24 @@ public class ReturnsSmartNulls implements Answer<Object>, Serializable { private final Answer<Object> delegate = new ReturnsMoreEmptyValues(); - @Override public Object answer(final InvocationOnMock invocation) throws Throwable { Object defaultReturnValue = delegate.answer(invocation); - if (defaultReturnValue != null) { return defaultReturnValue; } - - return RetrieveGenericsForDefaultAnswers.returnTypeForMockWithCorrectGenerics(invocation, - new RetrieveGenericsForDefaultAnswers.AnswerCallback() { - @Override - public Object apply(Class<?> type) { - if (type == null) { - return null; - } - - return Mockito.mock(type, new ThrowsSmartNullPointer(invocation, new LocationImpl())); - } - }); + Class<?> type = invocation.getMethod().getReturnType(); + if (!type.isPrimitive() && !Modifier.isFinal(type.getModifiers())) { + final Location location = new LocationImpl(); + return Mockito.mock(type, new ThrowsSmartNullPointer(invocation, location)); + } + return null; } private static class ThrowsSmartNullPointer implements Answer { - private final InvocationOnMock unstubbedInvocation; - private final Location location; - ThrowsSmartNullPointer(InvocationOnMock unstubbedInvocation, Location location) { + public ThrowsSmartNullPointer(InvocationOnMock unstubbedInvocation, Location location) { this.unstubbedInvocation = unstubbedInvocation; this.location = location; } @@ -73,7 +65,7 @@ public class ReturnsSmartNulls implements Answer<Object>, Serializable { public Object answer(InvocationOnMock currentInvocation) throws Throwable { if (isToStringMethod(currentInvocation.getMethod())) { return "SmartNull returned by this unstubbed method call on a mock:\n" + - unstubbedInvocation.toString(); + unstubbedInvocation.toString(); } throw smartNullPointerException(unstubbedInvocation.toString(), location); diff --git a/src/main/java/org/mockito/internal/util/ConsoleMockitoLogger.java b/src/main/java/org/mockito/internal/util/ConsoleMockitoLogger.java index 3eb8939..d8df8eb 100644 --- a/src/main/java/org/mockito/internal/util/ConsoleMockitoLogger.java +++ b/src/main/java/org/mockito/internal/util/ConsoleMockitoLogger.java @@ -4,8 +4,6 @@ */ package org.mockito.internal.util; -import org.mockito.plugins.MockitoLogger; - public class ConsoleMockitoLogger implements MockitoLogger { /* (non-Javadoc) diff --git a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java index 80cbf65..8efd384 100644 --- a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java +++ b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java @@ -8,23 +8,8 @@ package org.mockito.internal.util.reflection; import org.mockito.exceptions.base.MockitoException; import org.mockito.internal.util.Checks; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Set; +import java.lang.reflect.*; +import java.util.*; /** @@ -32,20 +17,20 @@ import java.util.Set; * and accessible members. * * <p> - * The main idea of this code is to create a Map that will help to resolve return types. - * In order to actually work with nested generics, this map will have to be passed along new instances - * as a type context. + * The main idea of this code is to create a Map that will help to resolve return types. + * In order to actually work with nested generics, this map will have to be passed along new instances + * as a type context. * </p> * * <p> - * Hence : - * <ul> - * <li>A new instance representing the metadata is created using the {@link #inferFrom(Type)} method from a real - * <code>Class</code> or from a <code>ParameterizedType</code>, other types are not yet supported.</li> + * Hence : + * <ul> + * <li>A new instance representing the metadata is created using the {@link #inferFrom(Type)} method from a real + * <code>Class</code> or from a <code>ParameterizedType</code>, other types are not yet supported.</li> * - * <li>Then from this metadata, we can extract meta-data for a generic return type of a method, using - * {@link #resolveGenericReturnType(Method)}.</li> - * </ul> + * <li>Then from this metadata, we can extract meta-data for a generic return type of a method, using + * {@link #resolveGenericReturnType(Method)}.</li> + * </ul> * </p> * * <p> @@ -112,9 +97,8 @@ public abstract class GenericMetadataSupport { } if (type instanceof TypeVariable) { /* - * If type is a TypeVariable, then it is needed to gather data elsewhere. - * Usually TypeVariables are declared on the class definition, such as such - * as List<E>. + * If type is a TypeVariable, then it is needed to gather data elsewhere. Usually TypeVariables are declared + * on the class definition, such as such as List<E>. */ return extractRawTypeOf(contextualActualTypeParameters.get(type)); } @@ -132,23 +116,6 @@ public abstract class GenericMetadataSupport { TypeVariable<?> typeParameter = typeParameters[i]; Type actualTypeArgument = actualTypeArguments[i]; - if (actualTypeArgument instanceof TypeVariable) { - /* - * If actualTypeArgument is a TypeVariable, and it is not present in - * the context map then it is needed to try harder to gather more data - * from the type argument itself. In some case the type argument do - * define upper bounds, this allow to look for them if not in the - * context map. - */ - registerTypeVariableIfNotPresent((TypeVariable<?>) actualTypeArgument); - - // Prevent registration of a cycle of TypeVariables. This can happen when we are processing - // type parameters in a Method, while we already processed the type parameters of a class. - if (contextualActualTypeParameters.containsKey(typeParameter)) { - continue; - } - } - if (actualTypeArgument instanceof WildcardType) { contextualActualTypeParameters.put(typeParameter, boundsOf((WildcardType) actualTypeArgument)); } else if (typeParameter != actualTypeArgument) { @@ -174,7 +141,7 @@ public abstract class GenericMetadataSupport { /** * @param typeParameter The TypeVariable parameter * @return A {@link BoundedType} for easy bound information, if first bound is a TypeVariable - * then retrieve BoundedType of this TypeVariable + * then retrieve BoundedType of this TypeVariable */ private BoundedType boundsOf(TypeVariable<?> typeParameter) { if (typeParameter.getBounds()[0] instanceof TypeVariable) { @@ -186,17 +153,13 @@ public abstract class GenericMetadataSupport { /** * @param wildCard The WildCard type * @return A {@link BoundedType} for easy bound information, if first bound is a TypeVariable - * then retrieve BoundedType of this TypeVariable + * then retrieve BoundedType of this TypeVariable */ private BoundedType boundsOf(WildcardType wildCard) { /* * According to JLS(http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.5.1): - * - Lower and upper can't coexist: (for instance, this is not allowed: - * <? extends List<String> & super MyInterface>) - * - Multiple concrete type bounds are not supported (for instance, this is not allowed: - * <? extends ArrayList<String> & MyInterface>) - * But the following form is possible where there is a single concrete tyep bound followed by interface type bounds - * <T extends List<String> & Comparable> + * - Lower and upper can't coexist: (for instance, this is not allowed: <? extends List<String> & super MyInterface>) + * - Multiple bounds are not supported (for instance, this is not allowed: <? extends List<String> & MyInterface>) */ WildCardBoundedType wildCardBoundedType = new WildCardBoundedType(wildCard); @@ -272,7 +235,7 @@ public abstract class GenericMetadataSupport { // logger.log("Method '" + method.toGenericString() + "' has return type : " + genericReturnType.getClass().getInterfaces()[0].getSimpleName() + " : " + genericReturnType); int arity = 0; - while (genericReturnType instanceof GenericArrayType) { + while(genericReturnType instanceof GenericArrayType) { arity++; genericReturnType = ((GenericArrayType) genericReturnType).getGenericComponentType(); } @@ -304,8 +267,8 @@ public abstract class GenericMetadataSupport { * Create an new instance of {@link GenericMetadataSupport} inferred from a {@link Type}. * * <p> - * At the moment <code>type</code> can only be a {@link Class} or a {@link ParameterizedType}, otherwise - * it'll throw a {@link MockitoException}. + * At the moment <code>type</code> can only be a {@link Class} or a {@link ParameterizedType}, otherwise + * it'll throw a {@link MockitoException}. * </p> * * @param type The class from which the {@link GenericMetadataSupport} should be built. @@ -331,7 +294,7 @@ public abstract class GenericMetadataSupport { /** * Generic metadata implementation for {@link Class}. - * <p> + * * Offer support to retrieve generic metadata on a {@link Class} by reading type parameters and type variables on * the class and its ancestors and interfaces. */ @@ -353,10 +316,10 @@ public abstract class GenericMetadataSupport { /** * Generic metadata implementation for "standalone" {@link ParameterizedType}. - * <p> + * * Offer support to retrieve generic metadata on a {@link ParameterizedType} by reading type variables of * the related raw type and declared type variable of this parameterized type. - * <p> + * * This class is not designed to work on ParameterizedType returned by {@link Method#getGenericReturnType()}, as * the ParameterizedType instance return in these cases could have Type Variables that refer to type declaration(s). * That's what meant the "standalone" word at the beginning of the Javadoc. @@ -418,7 +381,6 @@ public abstract class GenericMetadataSupport { private final TypeVariable<?> typeVariable; private final TypeVariable<?>[] typeParameters; private Class<?> rawType; - private List<Type> extraInterfaces; public TypeVariableReturnType(GenericMetadataSupport source, TypeVariable<?>[] typeParameters, TypeVariable<?> typeVariable) { this.typeParameters = typeParameters; @@ -437,7 +399,7 @@ public abstract class GenericMetadataSupport { for (Type type : typeVariable.getBounds()) { registerTypeVariablesOn(type); } - registerTypeParametersOn(new TypeVariable[]{typeVariable}); + registerTypeParametersOn(new TypeVariable[] { typeVariable }); registerTypeVariablesOn(getActualTypeArgumentFor(typeVariable)); } @@ -451,18 +413,15 @@ public abstract class GenericMetadataSupport { @Override public List<Type> extraInterfaces() { - if (extraInterfaces != null) { - return extraInterfaces; - } Type type = extractActualBoundedTypeOf(typeVariable); if (type instanceof BoundedType) { - return extraInterfaces = Arrays.asList(((BoundedType) type).interfaceBounds()); + return Arrays.asList(((BoundedType) type).interfaceBounds()); } if (type instanceof ParameterizedType) { - return extraInterfaces = Collections.singletonList(type); + return Collections.singletonList(type); } if (type instanceof Class) { - return extraInterfaces = Collections.emptyList(); + return Collections.emptyList(); } throw new MockitoException("Cannot extract extra-interfaces from '" + typeVariable + "' : '" + type + "'"); } @@ -477,7 +436,7 @@ public abstract class GenericMetadataSupport { for (Type extraInterface : extraInterfaces) { Class<?> rawInterface = extractRawTypeOf(extraInterface); // avoid interface collision with actual raw type (with typevariables, resolution ca be quite aggressive) - if (!rawType().equals(rawInterface)) { + if(!rawType().equals(rawInterface)) { rawExtraInterfaces.add(rawInterface); } } @@ -549,6 +508,7 @@ public abstract class GenericMetadataSupport { } + /** * Type representing bounds of a type * @@ -571,7 +531,7 @@ public abstract class GenericMetadataSupport { * * <p>If upper bounds are declared with SomeClass and additional interfaces, then firstBound will be SomeClass and * interfacesBound will be an array of the additional interfaces. - * <p> + * * i.e. <code>SomeClass</code>. * <pre class="code"><code class="java"> * interface UpperBoundedTypeWithClass<E extends Comparable<E> & Cloneable> { diff --git a/src/main/java/org/mockito/internal/verification/VerificationWrapperInOrderWrapper.java b/src/main/java/org/mockito/internal/verification/VerificationWrapperInOrderWrapper.java index 840efb7..eded985 100644 --- a/src/main/java/org/mockito/internal/verification/VerificationWrapperInOrderWrapper.java +++ b/src/main/java/org/mockito/internal/verification/VerificationWrapperInOrderWrapper.java @@ -47,7 +47,6 @@ public class VerificationWrapperInOrderWrapper implements VerificationMode { } } - //TODO ugly exception message!!! throw new MockitoException(verificationMode.getClass().getSimpleName() + " is not implemented to work with InOrder wrapped inside a " + verificationWrapper.getClass().getSimpleName()); |