summaryrefslogtreecommitdiff
path: root/src/main/java/org/mockito
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2018-08-28 16:57:29 +0000
committerPhilip P. Moltmann <moltmann@google.com>2018-08-28 10:00:13 -0700
commit6f5cb4c4a4fd579706cc1bd087a1123f867ca54c (patch)
tree8cf99ff02592dbd8053b56f31fc604500444699c /src/main/java/org/mockito
parent8acd6838f3ab6ae10e6dde6977970735f3767810 (diff)
downloadmockito-6f5cb4c4a4fd579706cc1bd087a1123f867ca54c.tar.gz
Revert "Revert "Update mockito on AOSP to same version as on internal master""
This reverts commit 0a0255ce0b22e9660bef08a4c5041c7f6a9667c7. Reason for revert: Fix in I5094fa145fc5f6d5c5d9426b07d764c07e545819 Change-Id: Id2ee88e07c439d2ef7b6a876d3c68b50bd37d157
Diffstat (limited to 'src/main/java/org/mockito')
-rw-r--r--src/main/java/org/mockito/Mockito.java32
-rw-r--r--src/main/java/org/mockito/codegen/InjectionBase.java16
-rw-r--r--src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java2
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java99
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java22
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java96
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java14
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java2
-rw-r--r--src/main/java/org/mockito/internal/exceptions/Reporter.java72
-rw-r--r--src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java5
-rw-r--r--src/main/java/org/mockito/internal/invocation/InvocationsFinder.java8
-rw-r--r--src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java11
-rw-r--r--src/main/java/org/mockito/internal/stubbing/BaseStubbing.java5
-rw-r--r--src/main/java/org/mockito/internal/stubbing/StubberImpl.java4
-rw-r--r--src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java13
-rw-r--r--src/main/java/org/mockito/internal/util/Primitives.java2
-rw-r--r--src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java3
-rw-r--r--src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java10
-rw-r--r--src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java22
-rw-r--r--src/main/java/org/mockito/session/MockitoSessionBuilder.java2
20 files changed, 338 insertions, 102 deletions
diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java
index b25dae5..620b7d4 100644
--- a/src/main/java/org/mockito/Mockito.java
+++ b/src/main/java/org/mockito/Mockito.java
@@ -99,6 +99,7 @@ import org.mockito.verification.VerificationWithTimeout;
* <a href="#42">42. (**new**) New API for integrations: listening on verification start events (Since 2.11.+)</a><br/>
* <a href="#43">43. (**new**) New API for integrations: <code>MockitoSession</code> is usable by testing frameworks (Since 2.15.+)</a><br/>
* <a href="#44">44. Deprecated <code>org.mockito.plugins.InstantiatorProvider</code> as it was leaking internal API. it was replaced by <code>org.mockito.plugins.InstantiatorProvider2 (Since 2.15.4)</code></a><br/>
+ * <a href="#45">45. (**new**) New JUnit Jupiter (JUnit5+) extension</a><br/>
* </b>
*
* <h3 id="0">0. <a class="meaningful_link" href="#mockito2" name="mockito2">Migrating to Mockito 2</a></h3>
@@ -1325,10 +1326,6 @@ import org.mockito.verification.VerificationWithTimeout;
* Currently, the feature is still optional as we wait for more feedback from the community.
*
* <p>
- * This feature is turned off by default because it is based on completely different mocking mechanism
- * that requires more feedback from the community.
- *
- * <p>
* This alternative mock maker which uses
* a combination of both Java instrumentation API and sub-classing rather than creating a new class to represent
* a mock. This way, it becomes possible to mock final types and methods.
@@ -1506,6 +1503,11 @@ import org.mockito.verification.VerificationWithTimeout;
* <p>{@link org.mockito.plugins.InstantiatorProvider} returned an internal API. Hence it was deprecated and replaced
* by {@link org.mockito.plugins.InstantiatorProvider2}. Old {@link org.mockito.plugins.InstantiatorProvider
* instantiator providers} will continue to work, but it is recommended to switch to the new API.</p>
+ *
+ * <h3 id="45">45. (**new**) <a class="meaningful_link" href="#junit5_mockito" name="junit5_mockito">New JUnit Jupiter (JUnit5+) extension</a></h3>
+ *
+ * For integration with JUnit Jupiter (JUnit5+), use the `org.mockito:mockito-junit-jupiter` artifact.
+ * For more information about the usage of the integration, see <a href="http://javadoc.io/page/org.mockito/mockito-junit-jupiter/latest/org/mockito/junit/jupiter/MockitoExtension.html">the JavaDoc of <code>MockitoExtension</code></a>.
*/
@SuppressWarnings("unchecked")
public class Mockito extends ArgumentMatchers {
@@ -1773,6 +1775,7 @@ public class Mockito extends ArgumentMatchers {
* @param classToMock class or interface to mock
* @return mock object
*/
+ @CheckReturnValue
public static <T> T mock(Class<T> classToMock) {
return mock(classToMock, withSettings());
}
@@ -1792,6 +1795,7 @@ public class Mockito extends ArgumentMatchers {
* @param name of the mock
* @return mock object
*/
+ @CheckReturnValue
public static <T> T mock(Class<T> classToMock, String name) {
return mock(classToMock, withSettings()
.name(name)
@@ -1810,6 +1814,7 @@ public class Mockito extends ArgumentMatchers {
* @return A {@link org.mockito.MockingDetails} instance.
* @since 1.9.5
*/
+ @CheckReturnValue
public static MockingDetails mockingDetails(Object toInspect) {
return MOCKITO_CORE.mockingDetails(toInspect);
}
@@ -1833,6 +1838,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return mock object
*/
+ @CheckReturnValue
public static <T> T mock(Class<T> classToMock, Answer defaultAnswer) {
return mock(classToMock, withSettings().defaultAnswer(defaultAnswer));
}
@@ -1860,6 +1866,7 @@ public class Mockito extends ArgumentMatchers {
* @param mockSettings additional mock settings
* @return mock object
*/
+ @CheckReturnValue
public static <T> T mock(Class<T> classToMock, MockSettings mockSettings) {
return MOCKITO_CORE.mock(classToMock, mockSettings);
}
@@ -1943,6 +1950,7 @@ public class Mockito extends ArgumentMatchers {
* to spy on
* @return a spy of the real object
*/
+ @CheckReturnValue
public static <T> T spy(T object) {
return MOCKITO_CORE.mock((Class<T>) object.getClass(), withSettings()
.spiedInstance(object)
@@ -1977,6 +1985,7 @@ public class Mockito extends ArgumentMatchers {
* @since 1.10.12
*/
@Incubating
+ @CheckReturnValue
public static <T> T spy(Class<T> classToSpy) {
return MOCKITO_CORE.mock(classToSpy, withSettings()
.useConstructor()
@@ -2521,6 +2530,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return InOrder object to be used to verify in order
*/
+ @CheckReturnValue
public static InOrder inOrder(Object... mocks) {
return MOCKITO_CORE.inOrder(mocks);
}
@@ -2604,6 +2614,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationMode times(int wantedNumberOfInvocations) {
return VerificationModeFactory.times(wantedNumberOfInvocations);
}
@@ -2625,6 +2636,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationMode never() {
return times(0);
}
@@ -2640,6 +2652,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationMode atLeastOnce() {
return VerificationModeFactory.atLeastOnce();
}
@@ -2656,6 +2669,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationMode atLeast(int minNumberOfInvocations) {
return VerificationModeFactory.atLeast(minNumberOfInvocations);
}
@@ -2672,6 +2686,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationMode atMost(int maxNumberOfInvocations) {
return VerificationModeFactory.atMost(maxNumberOfInvocations);
}
@@ -2689,6 +2704,7 @@ public class Mockito extends ArgumentMatchers {
* @param wantedNumberOfInvocations number of invocations to verify
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationMode calls( int wantedNumberOfInvocations ){
return VerificationModeFactory.calls( wantedNumberOfInvocations );
}
@@ -2709,6 +2725,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationMode only() {
return VerificationModeFactory.only();
}
@@ -2748,6 +2765,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationWithTimeout timeout(long millis) {
return new Timeout(millis, VerificationModeFactory.times(1));
}
@@ -2788,6 +2806,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return verification mode
*/
+ @CheckReturnValue
public static VerificationAfterDelay after(long millis) {
return new After(millis, VerificationModeFactory.times(1));
}
@@ -2871,6 +2890,7 @@ public class Mockito extends ArgumentMatchers {
*
* @return mock settings instance with defaults.
*/
+ @CheckReturnValue
public static MockSettings withSettings() {
return new MockSettingsImpl().defaultAnswer(RETURNS_DEFAULTS);
}
@@ -2884,6 +2904,7 @@ public class Mockito extends ArgumentMatchers {
* @return verification mode
* @since 2.1.0
*/
+ @CheckReturnValue
public static VerificationMode description(String description) {
return times(1).description(description);
}
@@ -2893,6 +2914,7 @@ public class Mockito extends ArgumentMatchers {
* An instance of {@code MockingDetails} can be retrieved via {@link #mockingDetails(Object)}.
*/
@Deprecated
+ @CheckReturnValue
static MockitoDebugger debug() {
return new MockitoDebuggerImpl();
}
@@ -2903,6 +2925,7 @@ public class Mockito extends ArgumentMatchers {
* @since 2.1.0
*/
@Incubating
+ @CheckReturnValue
public static MockitoFramework framework() {
return new DefaultMockitoFramework();
}
@@ -2916,6 +2939,7 @@ public class Mockito extends ArgumentMatchers {
* @since 2.7.0
*/
@Incubating
+ @CheckReturnValue
public static MockitoSessionBuilder mockitoSession() {
return new DefaultMockitoSessionBuilder();
}
diff --git a/src/main/java/org/mockito/codegen/InjectionBase.java b/src/main/java/org/mockito/codegen/InjectionBase.java
new file mode 100644
index 0000000..b582c3b
--- /dev/null
+++ b/src/main/java/org/mockito/codegen/InjectionBase.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.codegen;
+
+/**
+ * This class is required to resolve a method handle lookup for the {@code org.mockito.codegen} package what requires a preexisting class for the package.
+ * By defining this class, the JVM (starting from Java 9) assures that this package is a part of the Mockito module such that we gain full access rights.
+ */
+public class InjectionBase {
+
+ private InjectionBase() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java b/src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java
index a80efbe..92d045d 100644
--- a/src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java
+++ b/src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java
@@ -140,7 +140,7 @@ public class SpyAnnotationEngine implements AnnotationEngine, org.mockito.config
for (Class<? extends Annotation> u : undesiredAnnotations) {
if (field.isAnnotationPresent(u)) {
throw unsupportedCombinationOfAnnotations(annotation.getSimpleName(),
- annotation.getClass().getSimpleName());
+ u.getSimpleName());
}
}
}
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 7d60f6c..71ae6a6 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
@@ -15,6 +15,7 @@ import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.ClassFileLocator;
+import net.bytebuddy.dynamic.scaffold.MethodGraph;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.jar.asm.ClassVisitor;
@@ -29,7 +30,6 @@ import org.mockito.internal.util.concurrent.WeakConcurrentSet;
import org.mockito.mock.SerializableMode;
import java.lang.instrument.ClassFileTransformer;
-import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
@@ -44,6 +44,8 @@ import static org.mockito.internal.util.StringUtil.join;
public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTransformer {
+ private static final String PRELOAD = "org.mockito.inline.preload";
+
@SuppressWarnings("unchecked")
static final Set<Class<?>> EXCLUDES = new HashSet<Class<?>>(Arrays.asList(Class.class,
Boolean.class,
@@ -62,34 +64,75 @@ public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTran
private final WeakConcurrentSet<Class<?>> mocked;
- private final String identifier;
-
- private final MockMethodAdvice advice;
-
private final BytecodeGenerator subclassEngine;
+ private final AsmVisitorWrapper mockTransformer;
+
private volatile Throwable lastException;
public InlineBytecodeGenerator(Instrumentation instrumentation, WeakConcurrentMap<Object, MockMethodInterceptor> mocks) {
+ preload();
this.instrumentation = instrumentation;
byteBuddy = new ByteBuddy()
- .with(TypeValidation.DISABLED)
- .with(Implementation.Context.Disabled.Factory.INSTANCE);
+ .with(TypeValidation.DISABLED)
+ .with(Implementation.Context.Disabled.Factory.INSTANCE)
+ .with(MethodGraph.Compiler.ForDeclaredMethods.INSTANCE);
mocked = new WeakConcurrentSet<Class<?>>(WeakConcurrentSet.Cleaner.INLINE);
- identifier = RandomString.make();
- advice = new MockMethodAdvice(mocks, identifier);
+ String identifier = RandomString.make();
subclassEngine = new TypeCachingBytecodeGenerator(new SubclassBytecodeGenerator(withDefaultConfiguration()
- .withBinders(of(MockMethodAdvice.Identifier.class, identifier))
- .to(MockMethodAdvice.ForReadObject.class), isAbstract().or(isNative()).or(isToString())), false);
- MockMethodDispatcher.set(identifier, advice);
+ .withBinders(of(MockMethodAdvice.Identifier.class, identifier))
+ .to(MockMethodAdvice.ForReadObject.class), isAbstract().or(isNative()).or(isToString())), false);
+ mockTransformer = new AsmVisitorWrapper.ForDeclaredMethods()
+ .method(isVirtual()
+ .and(not(isBridge().or(isHashCode()).or(isEquals()).or(isDefaultFinalizer())))
+ .and(not(isDeclaredBy(nameStartsWith("java.")).<MethodDescription>and(isPackagePrivate()))),
+ Advice.withCustomMapping()
+ .bind(MockMethodAdvice.Identifier.class, identifier)
+ .to(MockMethodAdvice.class))
+ .method(isHashCode(),
+ Advice.withCustomMapping()
+ .bind(MockMethodAdvice.Identifier.class, identifier)
+ .to(MockMethodAdvice.ForHashCode.class))
+ .method(isEquals(),
+ Advice.withCustomMapping()
+ .bind(MockMethodAdvice.Identifier.class, identifier)
+ .to(MockMethodAdvice.ForEquals.class));
+ MockMethodDispatcher.set(identifier, new MockMethodAdvice(mocks, identifier));
instrumentation.addTransformer(this, true);
}
+ /**
+ * Mockito allows to mock about any type, including such types that we are relying on ourselves. This can cause a circularity:
+ * In order to check if an instance is a mock we need to look up if this instance is registered in the {@code mocked} set. But to look
+ * up this instance, we need to create key instances that rely on weak reference properties. Loading the later classes will happen before
+ * the key instances are completed what will cause Mockito to check if those key instances are themselves mocks what causes a loop which
+ * results in a circularity error. This is not normally a problem as we explicitly check if the instance that we investigate is one of
+ * our instance of which we hold a reference by reference equality what does not cause any code execution. But it seems like the load
+ * order plays a role here with unloaded types being loaded before we even get to check the mock instance property. To avoid this, we are
+ * making sure that crucuial JVM types are loaded before we create the first inline mock. Unfortunately, these types dependant on a JVM's
+ * implementation and we can only maintain types that we know of from well-known JVM implementations such as HotSpot and extend this list
+ * once we learn of further problematic types for future Java versions. To allow users to whitelist their own types, we do not also offer
+ * a property that allows running problematic tests before a new Mockito version can be released and that allows us to ask users to
+ * easily validate that whitelisting actually solves a problem as circularities could also be caused by other problems.
+ */
+ private static void preload() {
+ String preloads = System.getProperty(PRELOAD);
+ if (preloads == null) {
+ preloads = "java.lang.WeakPairMap,java.lang.WeakPairMap$Pair,java.lang.WeakPairMap$Pair$Weak";
+ }
+ for (String preload : preloads.split(",")) {
+ try {
+ Class.forName(preload, false, null);
+ } catch (ClassNotFoundException ignored) {
+ }
+ }
+ }
+
@Override
public <T> Class<? extends T> mockClass(MockFeatures<T> features) {
boolean subclassingRequired = !features.interfaces.isEmpty()
- || features.serializableMode != SerializableMode.NONE
- || Modifier.isAbstract(features.mockedType.getModifiers());
+ || features.serializableMode != SerializableMode.NONE
+ || Modifier.isAbstract(features.mockedType.getModifiers());
checkSupportedCombination(subclassingRequired, features);
@@ -157,29 +200,19 @@ public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTran
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
- byte[] classfileBuffer) throws IllegalClassFormatException {
+ byte[] classfileBuffer) {
if (classBeingRedefined == null
- || !mocked.contains(classBeingRedefined)
- || EXCLUDES.contains(classBeingRedefined)) {
+ || !mocked.contains(classBeingRedefined)
+ || EXCLUDES.contains(classBeingRedefined)) {
return null;
} else {
try {
return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer))
- // Note: The VM erases parameter meta data from the provided class file (bug). We just add this information manually.
- .visit(new ParameterWritingVisitorWrapper(classBeingRedefined))
- .visit(Advice.withCustomMapping()
- .bind(MockMethodAdvice.Identifier.class, identifier)
- .to(MockMethodAdvice.class).on(isVirtual()
- .and(not(isBridge().or(isHashCode()).or(isEquals()).or(isDefaultFinalizer())))
- .and(not(isDeclaredBy(nameStartsWith("java.")).<MethodDescription>and(isPackagePrivate())))))
- .visit(Advice.withCustomMapping()
- .bind(MockMethodAdvice.Identifier.class, identifier)
- .to(MockMethodAdvice.ForHashCode.class).on(isHashCode()))
- .visit(Advice.withCustomMapping()
- .bind(MockMethodAdvice.Identifier.class, identifier)
- .to(MockMethodAdvice.ForEquals.class).on(isEquals()))
- .make()
- .getBytes();
+ // Note: The VM erases parameter meta data from the provided class file (bug). We just add this information manually.
+ .visit(new ParameterWritingVisitorWrapper(classBeingRedefined))
+ .visit(mockTransformer)
+ .make()
+ .getBytes();
} catch (Throwable throwable) {
lastException = throwable;
return null;
@@ -214,7 +247,7 @@ public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTran
private final TypeDescription typeDescription;
private ParameterAddingClassVisitor(ClassVisitor cv, TypeDescription typeDescription) {
- super(Opcodes.ASM5, cv);
+ super(Opcodes.ASM6, cv);
this.typeDescription = typeDescription;
}
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 dc5c6e5..b659c73 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
@@ -38,6 +38,8 @@ import static org.mockito.internal.util.StringUtil.join;
class SubclassBytecodeGenerator implements BytecodeGenerator {
+ private static final String CODEGEN_PACKAGE = "org.mockito.codegen.";
+
private final SubclassLoader loader;
private final ByteBuddy byteBuddy;
@@ -46,6 +48,11 @@ class SubclassBytecodeGenerator implements BytecodeGenerator {
private final Implementation readReplace;
private final ElementMatcher<? super MethodDescription> matcher;
+ private final Implementation dispatcher = to(DispatcherDefaultingToRealMethod.class);
+ private final Implementation hashCode = to(MockMethodInterceptor.ForHashCode.class);
+ private final Implementation equals = to(MockMethodInterceptor.ForEquals.class);
+ private final Implementation writeReplace = to(MockMethodInterceptor.ForWriteReplace.class);
+
public SubclassBytecodeGenerator() {
this(new SubclassInjectionLoader());
}
@@ -68,31 +75,32 @@ class SubclassBytecodeGenerator implements BytecodeGenerator {
@Override
public <T> Class<? extends T> mockClass(MockFeatures<T> features) {
+ String name = nameFor(features.mockedType);
DynamicType.Builder<T> builder =
byteBuddy.subclass(features.mockedType)
- .name(nameFor(features.mockedType))
+ .name(name)
.ignoreAlso(isGroovyMethod())
.annotateType(features.stripAnnotations
? new Annotation[0]
: features.mockedType.getAnnotations())
.implement(new ArrayList<Type>(features.interfaces))
.method(matcher)
- .intercept(to(DispatcherDefaultingToRealMethod.class))
+ .intercept(dispatcher)
.transform(withModifiers(SynchronizationState.PLAIN))
.attribute(features.stripAnnotations
? MethodAttributeAppender.NoOp.INSTANCE
: INCLUDING_RECEIVER)
.method(isHashCode())
- .intercept(to(MockMethodInterceptor.ForHashCode.class))
+ .intercept(hashCode)
.method(isEquals())
- .intercept(to(MockMethodInterceptor.ForEquals.class))
+ .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(to(MockMethodInterceptor.ForWriteReplace.class));
+ .intercept(writeReplace);
}
if (readReplace != null) {
builder = builder.defineMethod("readObject", void.class, Visibility.PRIVATE)
@@ -118,7 +126,7 @@ class SubclassBytecodeGenerator implements BytecodeGenerator {
.or(hasParameters(whereAny(hasType(isPackagePrivate())))));
}
return builder.make()
- .load(classLoader, loader.getStrategy(features.mockedType))
+ .load(classLoader, loader.resolveStrategy(features.mockedType, classLoader, name.startsWith(CODEGEN_PACKAGE)))
.getLoaded();
}
@@ -132,7 +140,7 @@ class SubclassBytecodeGenerator implements BytecodeGenerator {
if (isComingFromJDK(type)
|| isComingFromSignedJar(type)
|| isComingFromSealedPackage(type)) {
- typeName = "codegen." + typeName;
+ typeName = CODEGEN_PACKAGE + type.getSimpleName();
}
return String.format("%s$%s$%d", typeName, "MockitoMock", Math.abs(random.nextInt()));
}
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 20125f1..454dd8e 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java
@@ -4,12 +4,104 @@
*/
package org.mockito.internal.creation.bytebuddy;
+import net.bytebuddy.dynamic.loading.ClassInjector;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
+import org.mockito.codegen.InjectionBase;
+import org.mockito.exceptions.base.MockitoException;
+import org.mockito.internal.util.Platform;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import static org.mockito.internal.util.StringUtil.join;
class SubclassInjectionLoader implements SubclassLoader {
+ private static final String ERROR_MESSAGE = join("The current JVM does not support any class injection mechanism.",
+ "",
+ "Currently, Mockito supports injection via neither by method handle lookups or using sun.misc.Unsafe",
+ "Neither seems to be available on your current JVM.");
+
+ private final SubclassLoader loader;
+
+ SubclassInjectionLoader() {
+ if (!Boolean.getBoolean("org.mockito.internal.simulateJava11") && ClassInjector.UsingReflection.isAvailable()) {
+ this.loader = new WithReflection();
+ } else if (ClassInjector.UsingLookup.isAvailable()) {
+ this.loader = tryLookup();
+ } else {
+ throw new MockitoException(join(ERROR_MESSAGE, "", Platform.describe()));
+ }
+ }
+
+ private static SubclassLoader tryLookup() {
+ try {
+ Class<?> methodHandles = Class.forName("java.lang.invoke.MethodHandles");
+ Object lookup = methodHandles.getMethod("lookup").invoke(null);
+ Method privateLookupIn = methodHandles.getMethod("privateLookupIn", Class.class, Class.forName("java.lang.invoke.MethodHandles$Lookup"));
+ Object codegenLookup = privateLookupIn.invoke(null, InjectionBase.class, lookup);
+ return new WithLookup(lookup, codegenLookup, privateLookupIn);
+ } catch (Exception exception) {
+ throw new MockitoException(join(ERROR_MESSAGE, "", Platform.describe()), exception);
+ }
+ }
+
+ private static class WithReflection implements SubclassLoader {
+
+ @Override
+ public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen) {
+ return ClassLoadingStrategy.Default.INJECTION.with(codegen ? InjectionBase.class.getProtectionDomain() : mockedType.getProtectionDomain());
+ }
+ }
+
+ private static class WithLookup implements SubclassLoader {
+
+ private final Object lookup;
+
+ private final Object codegenLookup;
+
+ private final Method privateLookupIn;
+
+ WithLookup(Object lookup, Object codegenLookup, Method privateLookupIn) {
+ this.lookup = lookup;
+ this.codegenLookup = codegenLookup;
+ this.privateLookupIn = privateLookupIn;
+ }
+
+ @Override
+ 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 {
+ privateLookup = privateLookupIn.invoke(null, mockedType, lookup);
+ } catch (InvocationTargetException exception) {
+ if (exception.getCause() instanceof IllegalAccessException) {
+ return ClassLoadingStrategy.Default.WRAPPER.with(mockedType.getProtectionDomain());
+ } else {
+ throw exception.getCause();
+ }
+ }
+ return ClassLoadingStrategy.UsingLookup.of(privateLookup);
+ } catch (Throwable exception) {
+ throw new MockitoException(join(
+ "The Java module system prevents Mockito from defining a mock class in the same package as " + mockedType,
+ "",
+ "To overcome this, you must open and export the mocked type to Mockito.",
+ "Remember that you can also do so programmatically if the mocked class is defined by the same module as your test code",
+ exception
+ ));
+ }
+ }
+ }
+ }
+
@Override
- public ClassLoadingStrategy<ClassLoader> getStrategy(Class<?> mockedType) {
- return ClassLoadingStrategy.Default.INJECTION.with(mockedType.getProtectionDomain());
+ 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 80b17ac..194c282 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java
@@ -6,8 +6,18 @@ package org.mockito.internal.creation.bytebuddy;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
+/**
+ * A subclass loader is responsible for resolving a class loading strategy for a mock that is implemented as a subclass.
+ */
public interface SubclassLoader {
- ClassLoadingStrategy<ClassLoader> getStrategy(Class<?> mockedType);
-
+ /**
+ * Resolves a class loading strategy.
+ *
+ * @param mockedType The type being mocked.
+ * @param classLoader The class loader being used.
+ * @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 codegen);
}
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java
index 34c31fe..ea51edf 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java
@@ -36,7 +36,7 @@ class TypeCachingBytecodeGenerator extends ReferenceQueue<ClassLoader> implement
public Class<?> call() throws Exception {
return bytecodeGenerator.mockClass(params);
}
- }, classLoader == null ? BOOTSTRAP_LOCK : classLoader);
+ }, BOOTSTRAP_LOCK);
} catch (IllegalArgumentException exception) {
Throwable cause = exception.getCause();
if (cause instanceof RuntimeException) {
diff --git a/src/main/java/org/mockito/internal/exceptions/Reporter.java b/src/main/java/org/mockito/internal/exceptions/Reporter.java
index 57094c0..17823ff 100644
--- a/src/main/java/org/mockito/internal/exceptions/Reporter.java
+++ b/src/main/java/org/mockito/internal/exceptions/Reporter.java
@@ -5,9 +5,27 @@
package org.mockito.internal.exceptions;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import org.mockito.exceptions.base.MockitoAssertionError;
import org.mockito.exceptions.base.MockitoException;
-import org.mockito.exceptions.misusing.*;
+import org.mockito.exceptions.misusing.CannotStubVoidMethodWithReturnValue;
+import org.mockito.exceptions.misusing.CannotVerifyStubOnlyMock;
+import org.mockito.exceptions.misusing.FriendlyReminderException;
+import org.mockito.exceptions.misusing.InvalidUseOfMatchersException;
+import org.mockito.exceptions.misusing.MissingMethodInvocationException;
+import org.mockito.exceptions.misusing.NotAMockException;
+import org.mockito.exceptions.misusing.NullInsteadOfMockException;
+import org.mockito.exceptions.misusing.PotentialStubbingProblem;
+import org.mockito.exceptions.misusing.RedundantListenerException;
+import org.mockito.exceptions.misusing.UnfinishedMockingSessionException;
+import org.mockito.exceptions.misusing.UnfinishedStubbingException;
+import org.mockito.exceptions.misusing.UnfinishedVerificationException;
+import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
+import org.mockito.exceptions.misusing.WrongTypeOfReturnValue;
import org.mockito.exceptions.verification.NeverWantedButInvoked;
import org.mockito.exceptions.verification.NoInteractionsWanted;
import org.mockito.exceptions.verification.SmartNullPointerException;
@@ -28,12 +46,6 @@ import org.mockito.listeners.InvocationListener;
import org.mockito.mock.MockName;
import org.mockito.mock.SerializableMode;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
import static org.mockito.internal.reporting.Pluralizer.pluralize;
import static org.mockito.internal.reporting.Pluralizer.were_exactly_x_interactions;
import static org.mockito.internal.util.StringUtil.join;
@@ -358,63 +370,71 @@ public class Reporter {
));
}
- public static MockitoAssertionError tooManyActualInvocations(int wantedCount, int actualCount, DescribedInvocation wanted, Location firstUndesired) {
- String message = createTooManyInvocationsMessage(wantedCount, actualCount, wanted, firstUndesired);
+ public static MockitoAssertionError tooManyActualInvocations(int wantedCount, int actualCount, DescribedInvocation wanted, List<Location> locations) {
+ String message = createTooManyInvocationsMessage(wantedCount, actualCount, wanted, locations);
return new TooManyActualInvocations(message);
}
private static String createTooManyInvocationsMessage(int wantedCount, int actualCount, DescribedInvocation wanted,
- Location firstUndesired) {
+ List<Location> invocations) {
return join(
wanted.toString(),
"Wanted " + pluralize(wantedCount) + ":",
new LocationImpl(),
- "But was " + pluralize(actualCount) + ". Undesired invocation:",
- firstUndesired,
+ "But was " + pluralize(actualCount) + ":",
+ createAllLocationsMessage(invocations),
""
);
}
- public static MockitoAssertionError neverWantedButInvoked(DescribedInvocation wanted, Location firstUndesired) {
+ public static MockitoAssertionError neverWantedButInvoked(DescribedInvocation wanted, List<Location> invocations) {
return new NeverWantedButInvoked(join(
wanted.toString(),
"Never wanted here:",
new LocationImpl(),
"But invoked here:",
- firstUndesired,
- ""
+ createAllLocationsMessage(invocations)
));
}
- public static MockitoAssertionError tooManyActualInvocationsInOrder(int wantedCount, int actualCount, DescribedInvocation wanted, Location firstUndesired) {
- String message = createTooManyInvocationsMessage(wantedCount, actualCount, wanted, firstUndesired);
+ public static MockitoAssertionError tooManyActualInvocationsInOrder(int wantedCount, int actualCount, DescribedInvocation wanted, List<Location> invocations) {
+ String message = createTooManyInvocationsMessage(wantedCount, actualCount, wanted, invocations);
return new VerificationInOrderFailure(join(
"Verification in order failure:" + message
));
}
- private static String createTooLittleInvocationsMessage(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted,
- Location lastActualInvocation) {
- String ending =
- (lastActualInvocation != null) ? lastActualInvocation + "\n" : "\n";
+ private static String createAllLocationsMessage(List<Location> locations) {
+ if (locations == null) {
+ return "\n";
+ }
+ StringBuilder sb = new StringBuilder();
+ for (Location location : locations) {
+ sb.append(location).append("\n");
+ }
+ return sb.toString();
+ }
+ private static String createTooLittleInvocationsMessage(org.mockito.internal.reporting.Discrepancy discrepancy,
+ DescribedInvocation wanted,
+ List<Location> locations) {
return join(
wanted.toString(),
"Wanted " + discrepancy.getPluralizedWantedCount() + (discrepancy.getWantedCount() == 0 ? "." : ":"),
new LocationImpl(),
"But was " + discrepancy.getPluralizedActualCount() + (discrepancy.getActualCount() == 0 ? "." : ":"),
- ending
+ createAllLocationsMessage(locations)
);
}
- public static MockitoAssertionError tooLittleActualInvocations(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted, Location lastActualLocation) {
- String message = createTooLittleInvocationsMessage(discrepancy, wanted, lastActualLocation);
+ public static MockitoAssertionError tooLittleActualInvocations(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted, List<Location> allLocations) {
+ String message = createTooLittleInvocationsMessage(discrepancy, wanted, allLocations);
return new TooLittleActualInvocations(message);
}
- public static MockitoAssertionError tooLittleActualInvocationsInOrder(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted, Location lastActualLocation) {
- String message = createTooLittleInvocationsMessage(discrepancy, wanted, lastActualLocation);
+ public static MockitoAssertionError tooLittleActualInvocationsInOrder(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted, List<Location> locations) {
+ String message = createTooLittleInvocationsMessage(discrepancy, wanted, locations);
return new VerificationInOrderFailure(join(
"Verification in order failure:" + message
diff --git a/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java b/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
index f5216ee..9892422 100644
--- a/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
+++ b/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
@@ -7,6 +7,7 @@ package org.mockito.internal.hamcrest;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import org.mockito.ArgumentMatcher;
+import org.mockito.internal.matchers.VarargMatcher;
public class HamcrestArgumentMatcher<T> implements ArgumentMatcher<T> {
@@ -20,6 +21,10 @@ public class HamcrestArgumentMatcher<T> implements ArgumentMatcher<T> {
return this.matcher.matches(argument);
}
+ public boolean isVarargMatcher() {
+ return matcher instanceof VarargMatcher;
+ }
+
public String toString() {
//TODO SF add unit tests and integ test coverage for describeTo()
return StringDescription.toString(matcher);
diff --git a/src/main/java/org/mockito/internal/invocation/InvocationsFinder.java b/src/main/java/org/mockito/internal/invocation/InvocationsFinder.java
index 57c335f..260321b 100644
--- a/src/main/java/org/mockito/internal/invocation/InvocationsFinder.java
+++ b/src/main/java/org/mockito/internal/invocation/InvocationsFinder.java
@@ -138,6 +138,14 @@ public class InvocationsFinder {
return unverified;
}
+ public static List<Location> getAllLocations(List<Invocation> invocations) {
+ List<Location> locations = new LinkedList<Location>();
+ for (Invocation invocation : invocations) {
+ locations.add(invocation.getLocation());
+ }
+ return locations;
+ }
+
private static class RemoveNotMatching implements Filter<Invocation> {
private final MatchableInvocation wanted;
diff --git a/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java b/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
index e085c25..e47156f 100644
--- a/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
+++ b/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
@@ -12,6 +12,7 @@ import java.util.ArrayList;
import java.util.List;
import org.mockito.ArgumentMatcher;
+import org.mockito.internal.hamcrest.HamcrestArgumentMatcher;
import org.mockito.internal.matchers.CapturingMatcher;
import org.mockito.internal.matchers.VarargMatcher;
import org.mockito.invocation.Invocation;
@@ -95,15 +96,19 @@ public class MatcherApplicationStrategy {
return ONE_MATCHER_PER_ARGUMENT;
}
- if (rawArguments == matcherCount && isLastMatcherVargargMatcher(matchers)) {
+ if (rawArguments == matcherCount && isLastMatcherVarargMatcher(matchers)) {
return MATCH_EACH_VARARGS_WITH_LAST_MATCHER;
}
return ERROR_UNSUPPORTED_NUMBER_OF_MATCHERS;
}
- private static boolean isLastMatcherVargargMatcher(final List<ArgumentMatcher<?>> matchers) {
- return lastMatcher(matchers) instanceof VarargMatcher;
+ private static boolean isLastMatcherVarargMatcher(final List<ArgumentMatcher<?>> matchers) {
+ ArgumentMatcher<?> argumentMatcher = lastMatcher(matchers);
+ if (argumentMatcher instanceof HamcrestArgumentMatcher<?>) {
+ return ((HamcrestArgumentMatcher<?>) argumentMatcher).isVarargMatcher();
+ }
+ return argumentMatcher instanceof VarargMatcher;
}
private static List<ArgumentMatcher<?>> appendLastMatcherNTimes(List<ArgumentMatcher<?>> matchers, int timesToAppendLastMatcher) {
diff --git a/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java b/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java
index ddb9a8d..6dd99cd 100644
--- a/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java
+++ b/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java
@@ -24,7 +24,8 @@ public abstract class BaseStubbing<T> implements OngoingStubbing<T> {
public OngoingStubbing<T> thenReturn(T value, T... values) {
OngoingStubbing<T> stubbing = thenReturn(value);
if (values == null) {
- // TODO below does not seem right
+ // For no good reason we're configuring null answer here
+ // This has been like that since forever, so let's keep it for compatibility (unless users complain)
return stubbing.thenReturn(null);
}
for (T v : values) {
@@ -65,7 +66,7 @@ public abstract class BaseStubbing<T> implements OngoingStubbing<T> {
@Override
public OngoingStubbing<T> thenThrow(Class<? extends Throwable> toBeThrown, Class<? extends Throwable>... nextToBeThrown) {
if (nextToBeThrown == null) {
- thenThrow((Class<Throwable>) null);
+ return thenThrow((Class<Throwable>) null);
}
OngoingStubbing<T> stubbing = thenThrow(toBeThrown);
for (Class<? extends Throwable> t : nextToBeThrown) {
diff --git a/src/main/java/org/mockito/internal/stubbing/StubberImpl.java b/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
index b18d05d..7771c04 100644
--- a/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
+++ b/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
@@ -83,9 +83,9 @@ public class StubberImpl implements Stubber {
Throwable e;
try {
e = newInstance(toBeThrown);
- } catch (RuntimeException instanciationError) {
+ } catch (RuntimeException instantiationError) {
mockingProgress().reset();
- throw instanciationError;
+ throw instantiationError;
}
return doThrow(e);
}
diff --git a/src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java b/src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java
index 037520f..502e359 100644
--- a/src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java
+++ b/src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java
@@ -14,23 +14,36 @@ import org.mockito.stubbing.ValidableAnswer;
import static org.mockito.internal.exceptions.Reporter.cannotStubWithNullThrowable;
import static org.mockito.internal.exceptions.Reporter.checkedExceptionInvalid;
+/**
+ * An answer that always throws the same throwable.
+ */
public class ThrowsException implements Answer<Object>, ValidableAnswer, Serializable {
private static final long serialVersionUID = 1128820328555183980L;
private final Throwable throwable;
private final ConditionalStackTraceFilter filter = new ConditionalStackTraceFilter();
+ /**
+ * Creates a new answer always throwing the given throwable. If it is null,
+ * {@linkplain ValidableAnswer#validateFor(InvocationOnMock) answer validation}
+ * will fail.
+ */
public ThrowsException(Throwable throwable) {
this.throwable = throwable;
}
public Object answer(InvocationOnMock invocation) throws Throwable {
+ if (throwable == null) {
+ throw new IllegalStateException("throwable is null: " +
+ "you shall not call #answer if #validateFor fails!");
+ }
if (MockUtil.isMock(throwable)) {
throw throwable;
}
Throwable t = throwable.fillInStackTrace();
if (t == null) {
+ //Custom exceptions sometimes return null, see #866
throw throwable;
}
filter.filter(t);
diff --git a/src/main/java/org/mockito/internal/util/Primitives.java b/src/main/java/org/mockito/internal/util/Primitives.java
index 4d813e3..80dd0af 100644
--- a/src/main/java/org/mockito/internal/util/Primitives.java
+++ b/src/main/java/org/mockito/internal/util/Primitives.java
@@ -44,7 +44,7 @@ public class Primitives {
public static boolean isAssignableFromWrapper(Class<?> valueClass, Class<?> referenceType) {
if(isPrimitiveOrWrapper(valueClass) && isPrimitiveOrWrapper(referenceType)) {
- return Primitives.primitiveTypeOf(valueClass).isAssignableFrom(referenceType);
+ return Primitives.primitiveTypeOf(valueClass).isAssignableFrom(Primitives.primitiveTypeOf(referenceType));
}
return false;
}
diff --git a/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java b/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
index b411a73..487d223 100644
--- a/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
+++ b/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
@@ -50,6 +50,7 @@ public class WeakConcurrentMap<K, V> extends ReferenceQueue<K> implements Runnab
* @param key The key of the entry.
* @return The value of the entry or the default value if it did not exist.
*/
+ @SuppressWarnings("CollectionIncompatibleType")
public V get(K key) {
if (key == null) throw new NullPointerException();
V value = target.get(new LatentKey<K>(key));
@@ -69,6 +70,7 @@ public class WeakConcurrentMap<K, V> extends ReferenceQueue<K> implements Runnab
* @param key The key of the entry.
* @return {@code true} if the key already defines a value.
*/
+ @SuppressWarnings("CollectionIncompatibleType")
public boolean containsKey(K key) {
if (key == null) throw new NullPointerException();
return target.containsKey(new LatentKey<K>(key));
@@ -88,6 +90,7 @@ public class WeakConcurrentMap<K, V> extends ReferenceQueue<K> implements Runnab
* @param key The key of the entry.
* @return The removed entry or {@code null} if it does not exist.
*/
+ @SuppressWarnings("CollectionIncompatibleType")
public V remove(K key) {
if (key == null) throw new NullPointerException();
return target.remove(new LatentKey<K>(key));
diff --git a/src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java b/src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java
index 36e35a3..d0eb0b5 100644
--- a/src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java
+++ b/src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java
@@ -17,7 +17,7 @@ import static org.mockito.internal.invocation.InvocationMarker.markVerified;
import static org.mockito.internal.invocation.InvocationMarker.markVerifiedInOrder;
import static org.mockito.internal.invocation.InvocationsFinder.findAllMatchingUnverifiedChunks;
import static org.mockito.internal.invocation.InvocationsFinder.findInvocations;
-import static org.mockito.internal.invocation.InvocationsFinder.getLastLocation;
+import static org.mockito.internal.invocation.InvocationsFinder.getAllLocations;
public class AtLeastXNumberOfInvocationsChecker {
@@ -26,8 +26,8 @@ public class AtLeastXNumberOfInvocationsChecker {
int actualCount = actualInvocations.size();
if (wantedCount > actualCount) {
- Location lastLocation = getLastLocation(actualInvocations);
- throw tooLittleActualInvocations(new AtLeastDiscrepancy(wantedCount, actualCount), wanted, lastLocation);
+ List<Location> allLocations = getAllLocations(actualInvocations);
+ throw tooLittleActualInvocations(new AtLeastDiscrepancy(wantedCount, actualCount), wanted, allLocations);
}
markVerified(actualInvocations, wanted);
@@ -39,8 +39,8 @@ public class AtLeastXNumberOfInvocationsChecker {
int actualCount = chunk.size();
if (wantedCount > actualCount) {
- Location lastLocation = getLastLocation(chunk);
- throw tooLittleActualInvocationsInOrder(new AtLeastDiscrepancy(wantedCount, actualCount), wanted, lastLocation);
+ List<Location> allLocations = getAllLocations(chunk);
+ throw tooLittleActualInvocationsInOrder(new AtLeastDiscrepancy(wantedCount, actualCount), wanted, allLocations);
}
markVerifiedInOrder(chunk, wanted, orderingContext);
diff --git a/src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java b/src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java
index 3fa340f..1dfc2f1 100644
--- a/src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java
+++ b/src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java
@@ -5,6 +5,7 @@
package org.mockito.internal.verification.checkers;
+import java.util.Arrays;
import java.util.List;
import org.mockito.internal.reporting.Discrepancy;
import org.mockito.internal.verification.api.InOrderContext;
@@ -22,7 +23,7 @@ import static org.mockito.internal.invocation.InvocationMarker.markVerifiedInOrd
import static org.mockito.internal.invocation.InvocationsFinder.findFirstMatchingUnverifiedInvocation;
import static org.mockito.internal.invocation.InvocationsFinder.findInvocations;
import static org.mockito.internal.invocation.InvocationsFinder.findMatchingChunk;
-import static org.mockito.internal.invocation.InvocationsFinder.getLastLocation;
+import static org.mockito.internal.invocation.InvocationsFinder.getAllLocations;
public class NumberOfInvocationsChecker {
@@ -34,16 +35,14 @@ public class NumberOfInvocationsChecker {
int actualCount = actualInvocations.size();
if (wantedCount > actualCount) {
- Location lastInvocation = getLastLocation(actualInvocations);
- throw tooLittleActualInvocations(new Discrepancy(wantedCount, actualCount), wanted, lastInvocation);
+ List<Location> allLocations = getAllLocations(actualInvocations);
+ throw tooLittleActualInvocations(new Discrepancy(wantedCount, actualCount), wanted, allLocations);
}
if (wantedCount == 0 && actualCount > 0) {
- Location firstUndesired = actualInvocations.get(wantedCount).getLocation();
- throw neverWantedButInvoked(wanted, firstUndesired);
+ throw neverWantedButInvoked(wanted, getAllLocations(actualInvocations));
}
if (wantedCount < actualCount) {
- Location firstUndesired = actualInvocations.get(wantedCount).getLocation();
- throw tooManyActualInvocations(wantedCount, actualCount, wanted, firstUndesired);
+ throw tooManyActualInvocations(wantedCount, actualCount, wanted, getAllLocations(actualInvocations));
}
markVerified(actualInvocations, wanted);
@@ -55,12 +54,11 @@ public class NumberOfInvocationsChecker {
int actualCount = chunk.size();
if (wantedCount > actualCount) {
- Location lastInvocation = getLastLocation(chunk);
- throw tooLittleActualInvocationsInOrder(new Discrepancy(wantedCount, actualCount), wanted, lastInvocation);
+ List<Location> allLocations = getAllLocations(chunk);
+ throw tooLittleActualInvocationsInOrder(new Discrepancy(wantedCount, actualCount), wanted, allLocations);
}
if (wantedCount < actualCount) {
- Location firstUndesired = chunk.get(wantedCount).getLocation();
- throw tooManyActualInvocationsInOrder(wantedCount, actualCount, wanted, firstUndesired);
+ throw tooManyActualInvocationsInOrder(wantedCount, actualCount, wanted, getAllLocations(chunk));
}
markVerifiedInOrder(chunk, wanted, context);
@@ -72,7 +70,7 @@ public class NumberOfInvocationsChecker {
while( actualCount < wantedCount ){
Invocation next = findFirstMatchingUnverifiedInvocation(invocations, wanted, context );
if( next == null ){
- throw tooLittleActualInvocationsInOrder(new Discrepancy(wantedCount, actualCount), wanted, lastLocation );
+ throw tooLittleActualInvocationsInOrder(new Discrepancy(wantedCount, actualCount), wanted, Arrays.asList(lastLocation));
}
markVerified( next, wanted );
context.markVerified( next );
diff --git a/src/main/java/org/mockito/session/MockitoSessionBuilder.java b/src/main/java/org/mockito/session/MockitoSessionBuilder.java
index 474b7f9..b3a758b 100644
--- a/src/main/java/org/mockito/session/MockitoSessionBuilder.java
+++ b/src/main/java/org/mockito/session/MockitoSessionBuilder.java
@@ -47,7 +47,7 @@ public interface MockitoSessionBuilder {
* like {@link org.mockito.Mock}.
* <p>
* In most scenarios, you only need to init mocks on a single test class instance.
- * This method is useful for advanced framework integrations (like JUnit5), when a test uses multiple, e.g. nested, test class instances.
+ * This method is useful for advanced framework integrations (like JUnit Jupiter), when a test uses multiple, e.g. nested, test class instances.
* <p>
* This method calls {@link #initMocks(Object)} for each passed test class instance.
*