summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2018-03-13 13:04:44 -0700
committerPhilip P. Moltmann <moltmann@google.com>2018-03-13 13:52:45 -0700
commitbf8c1ad2adfe37bae65749ebc46f76c72b475f32 (patch)
tree69aeac615e38207debf91d5bc92bd75b89130993
parent430a640b73cb58c17545e68711a25327c807a5ae (diff)
downloadmockito-bf8c1ad2adfe37bae65749ebc46f76c72b475f32.tar.gz
Test: atest CtsMockingTestCases CtsInlineMockingTestCases Bug: 74344734 Change-Id: I20ac20aebdb4d7a184d85ad3657585b415f03b7f
-rw-r--r--Android.bp4
-rw-r--r--README.version4
-rw-r--r--src/main/java/org/mockito/Mockito.java52
-rw-r--r--src/main/java/org/mockito/MockitoSession.java33
-rw-r--r--src/main/java/org/mockito/creation/instance/InstantiationException.java22
-rw-r--r--src/main/java/org/mockito/creation/instance/Instantiator.java22
-rw-r--r--src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java15
-rw-r--r--src/main/java/org/mockito/internal/configuration/plugins/PluginInitializer.java58
-rw-r--r--src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java91
-rw-r--r--src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java24
-rw-r--r--src/main/java/org/mockito/internal/configuration/plugins/Plugins.java7
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java4
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java45
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java29
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java4
-rw-r--r--src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java2
-rw-r--r--src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java5
-rw-r--r--src/main/java/org/mockito/internal/creation/instance/InstantiationException.java8
-rw-r--r--src/main/java/org/mockito/internal/creation/instance/Instantiator.java5
-rw-r--r--src/main/java/org/mockito/internal/creation/instance/InstantiatorProvider2Adapter.java34
-rw-r--r--src/main/java/org/mockito/internal/creation/instance/InstantiatorProviderAdapter.java36
-rw-r--r--src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java1
-rw-r--r--src/main/java/org/mockito/internal/debugging/LocationImpl.java7
-rw-r--r--src/main/java/org/mockito/internal/exceptions/MockitoLimitations.java11
-rw-r--r--src/main/java/org/mockito/internal/exceptions/Reporter.java14
-rw-r--r--src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java45
-rw-r--r--src/main/java/org/mockito/internal/handler/MockHandlerImpl.java11
-rw-r--r--src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java45
-rw-r--r--src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java (renamed from src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java)16
-rw-r--r--src/main/java/org/mockito/internal/invocation/RealMethod.java22
-rw-r--r--src/main/java/org/mockito/internal/invocation/mockref/MockReference.java16
-rw-r--r--src/main/java/org/mockito/internal/invocation/mockref/MockStrongReference.java32
-rw-r--r--src/main/java/org/mockito/internal/invocation/mockref/MockWeakReference.java44
-rw-r--r--src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java12
-rw-r--r--src/main/java/org/mockito/internal/junit/JUnitRule.java50
-rw-r--r--src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java6
-rw-r--r--src/main/java/org/mockito/internal/junit/TestFinishedEvent.java6
-rw-r--r--src/main/java/org/mockito/internal/junit/UniversalTestListener.java7
-rw-r--r--src/main/java/org/mockito/internal/junit/util/TestName.java17
-rw-r--r--src/main/java/org/mockito/internal/matchers/text/ArrayIterator.java46
-rw-r--r--src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java19
-rw-r--r--src/main/java/org/mockito/internal/progress/MockingProgressImpl.java6
-rw-r--r--src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java3
-rw-r--r--src/main/java/org/mockito/internal/runners/DefaultTestFinishedEvent.java35
-rw-r--r--src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java53
-rw-r--r--src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java22
-rw-r--r--src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java22
-rw-r--r--src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java14
-rw-r--r--src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java2
-rw-r--r--src/main/java/org/mockito/internal/util/collections/Sets.java4
-rw-r--r--src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java2
-rw-r--r--src/main/java/org/mockito/invocation/InvocationFactory.java36
-rw-r--r--src/main/java/org/mockito/junit/MockitoJUnitRunner.java6
-rw-r--r--src/main/java/org/mockito/plugins/InstantiatorProvider.java17
-rw-r--r--src/main/java/org/mockito/plugins/InstantiatorProvider2.java58
-rw-r--r--src/main/java/org/mockito/quality/Strictness.java3
-rw-r--r--src/main/java/org/mockito/session/MockitoSessionBuilder.java68
-rw-r--r--src/main/java/org/mockito/session/MockitoSessionLogger.java30
-rw-r--r--src/main/java/org/mockito/stubbing/OngoingStubbing.java16
-rw-r--r--src/test/java/org/mockito/InvocationFactoryTest.java81
-rw-r--r--src/test/java/org/mockito/StaticMockingExperimentTest.java6
-rw-r--r--src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java4
-rw-r--r--src/test/java/org/mockito/internal/configuration/plugins/PluginLoaderTest.java90
-rw-r--r--src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java4
-rw-r--r--src/test/java/org/mockito/internal/invocation/InvocationBuilder.java6
-rw-r--r--src/test/java/org/mockito/internal/invocation/mockref/MockWeakReferenceTest.java27
-rw-r--r--src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java74
-rw-r--r--src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java24
-rw-r--r--src/test/java/org/mockitousage/bugs/MockitoStubbedCallInAnswerTest.java107
-rw-r--r--src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java10
-rw-r--r--src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java4
-rw-r--r--src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java16
-rw-r--r--src/test/java/org/mockitousage/session/MockitoSessionTest.java81
-rw-r--r--src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java38
-rw-r--r--src/test/java/org/mockitoutil/TestBase.java8
-rw-r--r--stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java31
-rw-r--r--subprojects/inline/inline.gradle3
-rw-r--r--subprojects/inline/src/test/java/org/mockitoinline/RecursionTest.java21
-rw-r--r--subprojects/inline/src/test/java/org/mockitoinline/StressTest.java38
-rw-r--r--subprojects/inline/src/test/java/org/mockitoinline/SuperCallTest.java33
80 files changed, 1580 insertions, 454 deletions
diff --git a/Android.bp b/Android.bp
index 03d57ee..22e8cbf 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,11 +35,7 @@ java_library_static {
// dexmaker instead and including it causes conflicts.
exclude_srcs: [
"src/main/java/org/mockito/internal/creation/bytebuddy/**/*.java",
- "src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java",
],
- srcs: [
- "stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java",
- ]
},
host: {
static_libs: [
diff --git a/README.version b/README.version
index 64b0bed..bbabbe6 100644
--- a/README.version
+++ b/README.version
@@ -1,5 +1,5 @@
URL: https://github.com/mockito/mockito
-Version: v2.12.0
+Version: v2.16.0
License: Apache 2.0
Description: Mockito is a mocking framework with a clean and simple API.
@@ -9,4 +9,4 @@ Dexmaker module.
The source can be updated using the update_source.sh script.
Local Modifications:
- - Added dummy DefaultInvocationFactory to fix build
+ None
diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java
index 415df01..b25dae5 100644
--- a/src/main/java/org/mockito/Mockito.java
+++ b/src/main/java/org/mockito/Mockito.java
@@ -25,6 +25,7 @@ import org.mockito.plugins.MockitoPlugins;
import org.mockito.quality.MockitoHint;
import org.mockito.quality.Strictness;
import org.mockito.session.MockitoSessionBuilder;
+import org.mockito.session.MockitoSessionLogger;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.Answer1;
import org.mockito.stubbing.OngoingStubbing;
@@ -96,6 +97,8 @@ import org.mockito.verification.VerificationWithTimeout;
* <a href="#40">40. (*new*) Improved productivity and cleaner tests with "stricter" Mockito (Since 2.+)</a><br/>
* <a href="#41">41. (**new**) Advanced public API for framework integrations (Since 2.10.+)</a><br/>
* <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/>
* </b>
*
* <h3 id="0">0. <a class="meaningful_link" href="#mockito2" name="mockito2">Migrating to Mockito 2</a></h3>
@@ -1396,7 +1399,7 @@ import org.mockito.verification.VerificationWithTimeout;
* <a href="https://github.com/mockito/mockito/issues/769">issue 769</a>.
*
* <h3 id="41">41. <a class="meaningful_link" href="#framework_integrations_api" name="framework_integrations_api">
- * (**new**) Advanced public API for framework integrations (Since 2.10.+)</h3>
+ * (**new**) Advanced public API for framework integrations (Since 2.10.+)</a></h3>
*
* In Summer 2017 we decided that Mockito
* <a href="https://www.linkedin.com/pulse/mockito-vs-powermock-opinionated-dogmatic-static-mocking-faber">
@@ -1449,7 +1452,7 @@ import org.mockito.verification.VerificationWithTimeout;
* Do you have feedback? Please leave comment in <a href="https://github.com/mockito/mockito/issues/1110">issue 1110</a>.
*
* <h3 id="42">42. <a class="meaningful_link" href="#verifiation_started_listener" name="verifiation_started_listener">
- * (**new**) New API for integrations: listening on verification start events (Since 2.11.+)</h3>
+ * (**new**) New API for integrations: listening on verification start events (Since 2.11.+)</a></h3>
*
* Framework integrations such as <a href="https://projects.spring.io/spring-boot">Spring Boot</a> needs public API to tackle double-proxy use case
* (<a href="https://github.com/mockito/mockito/issues/1191">issue 1191</a>).
@@ -1467,6 +1470,42 @@ import org.mockito.verification.VerificationWithTimeout;
* We found this method useful during the implementation.
* </li>
* </ul>
+ *
+ * <h3 id="43">43. <a class="meaningful_link" href="#mockito_session_testing_frameworks" name="mockito_session_testing_frameworks">
+ * (**new**) New API for integrations: <code>MockitoSession</code> is usable by testing frameworks (Since 2.15.+)</a></h3>
+ *
+ * <p>{@link MockitoSessionBuilder} and {@link MockitoSession} were enhanced to enable reuse by testing framework
+ * integrations (e.g. {@link MockitoRule} for JUnit):</p>
+ * <ul>
+ * <li>{@link MockitoSessionBuilder#initMocks(Object...)} allows to pass in multiple test class instances for
+ * initialization of fields annotated with Mockito annotations like {@link org.mockito.Mock}.
+ * This method is useful for advanced framework integrations (e.g. JUnit Jupiter), when a test uses multiple,
+ * e.g. nested, test class instances.
+ * </li>
+ * <li>{@link MockitoSessionBuilder#name(String)} allows to pass a name from the testing framework to the
+ * {@link MockitoSession} that will be used for printing warnings when {@link Strictness#WARN} is used.
+ * </li>
+ * <li>{@link MockitoSessionBuilder#logger(MockitoSessionLogger)} makes it possible to customize the logger used
+ * for hints/warnings produced when finishing mocking (useful for testing and to connect reporting capabilities
+ * provided by testing frameworks such as JUnit Jupiter).
+ * </li>
+ * <li>{@link MockitoSession#setStrictness(Strictness)} allows to change the strictness of a {@link MockitoSession}
+ * for one-off scenarios, e.g. it enables configuring a default strictness for all tests in a class but makes it
+ * possible to change the strictness for a single or a few tests.
+ * </li>
+ * <li>{@link MockitoSession#finishMocking(Throwable)} was added to avoid confusion that may arise because
+ * there are multiple competing failures. It will disable certain checks when the supplied <em>failure</em>
+ * is not {@code null}.
+ * </li>
+ * </ul>
+ *
+ * <h3 id="44">44. <a class="meaningful_link" href="#mockito_instantiator_provider_deprecation" name="mockito_instantiator_provider_deprecation">
+ * 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)</a></h3>
+ *
+ * <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>
*/
@SuppressWarnings("unchecked")
public class Mockito extends ArgumentMatchers {
@@ -1643,11 +1682,15 @@ public class Mockito extends ArgumentMatchers {
* // this calls the real implementation of Foo.getSomething()
* value = mock.getSomething();
*
- * when(mock.getSomething()).thenReturn(fakeValue);
+ * doReturn(fakeValue).when(mock).getSomething();
*
* // now fakeValue is returned
* value = mock.getSomething();
* </code></pre>
+ *
+ * <p>
+ * <u>Note:</u> Stubbing partial mocks using <code>when(mock.getSomething()).thenReturn(fakeValue)</code>
+ * syntax will call the real method. For partial mock it's recommended to use <code>doReturn</code> syntax.
*/
public static final Answer<Object> CALLS_REAL_METHODS = Answers.CALLS_REAL_METHODS;
@@ -2119,6 +2162,9 @@ public class Mockito extends ArgumentMatchers {
* See also {@link Mockito#never()} - it is more explicit and communicates the intent well.
* <p>
* Stubbed invocations (if called) are also treated as interactions.
+ * If you want stubbed invocations automatically verified, check out {@link Strictness#STRICT_STUBS} feature
+ * introduced in Mockito 2.3.0.
+ * If you want to ignore stubs for verification, see {@link #ignoreStubs(Object...)}.
* <p>
* A word of <b>warning</b>:
* Some users who did a lot of classic, expect-run-verify mocking tend to use <code>verifyNoMoreInteractions()</code> very often, even in every test method.
diff --git a/src/main/java/org/mockito/MockitoSession.java b/src/main/java/org/mockito/MockitoSession.java
index 997a4fa..9e820f2 100644
--- a/src/main/java/org/mockito/MockitoSession.java
+++ b/src/main/java/org/mockito/MockitoSession.java
@@ -4,6 +4,7 @@
*/
package org.mockito;
+import org.mockito.exceptions.misusing.PotentialStubbingProblem;
import org.mockito.exceptions.misusing.UnfinishedMockingSessionException;
import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
import org.mockito.junit.MockitoJUnitRunner;
@@ -90,6 +91,20 @@ import org.mockito.session.MockitoSessionBuilder;
public interface MockitoSession {
/**
+ * Changes the strictness of this {@code MockitoSession}.
+ * The new strictness will be applied to operations on mocks and checks performed by {@link #finishMocking()}.
+ * This method is used behind the hood by {@link MockitoRule#strictness(Strictness)} method.
+ * In most healthy tests, this method is not needed.
+ * We keep it for edge cases and when you really need to change strictness in given test method.
+ * For use cases see Javadoc for {@link PotentialStubbingProblem} class.
+ *
+ * @param strictness new strictness for this session.
+ * @since 2.15.0
+ */
+ @Incubating
+ void setStrictness(Strictness strictness);
+
+ /**
* Must be invoked when the user is done with mocking for given session (test method).
* It detects unused stubbings and may throw {@link UnnecessaryStubbingException}
* or emit warnings ({@link MockitoHint}) depending on the {@link Strictness} level.
@@ -105,8 +120,26 @@ public interface MockitoSession {
* <p>
* For example, see javadoc for {@link MockitoSession}.
*
+ * @see #finishMocking(Throwable)
* @since 2.7.0
*/
@Incubating
void finishMocking();
+
+ /**
+ * Must be invoked when the user is done with mocking for given session (test method).
+ * When a {@linkplain Throwable failure} is specified, certain checks are disabled to avoid
+ * confusion that may arise because there are multiple competing failures. Other than that,
+ * this method behaves exactly like {@link #finishMocking()}.
+ * <p>
+ * This method is intended to be used by framework integrations. When using MockitoSession
+ * directly, most users should rather use {@link #finishMocking()}.
+ * {@link MockitoRule} uses this method behind the hood.
+ *
+ * @param failure the exception that caused the test to fail; passing {@code null} is permitted
+ * @see #finishMocking()
+ * @since 2.15.0
+ */
+ @Incubating
+ void finishMocking(Throwable failure);
}
diff --git a/src/main/java/org/mockito/creation/instance/InstantiationException.java b/src/main/java/org/mockito/creation/instance/InstantiationException.java
new file mode 100644
index 0000000..1cfbaba
--- /dev/null
+++ b/src/main/java/org/mockito/creation/instance/InstantiationException.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.creation.instance;
+
+import org.mockito.exceptions.base.MockitoException;
+
+/**
+ * Exception generated when {@link Instantiator#newInstance(Class)} failed.
+ *
+ * @since 2.15.4
+ */
+public class InstantiationException extends MockitoException {
+
+ /**
+ * @since 2.15.4
+ */
+ public InstantiationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/org/mockito/creation/instance/Instantiator.java b/src/main/java/org/mockito/creation/instance/Instantiator.java
new file mode 100644
index 0000000..9ce37b5
--- /dev/null
+++ b/src/main/java/org/mockito/creation/instance/Instantiator.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.creation.instance;
+
+/**
+ * Provides instances of classes.
+ * See more information about Mockito plugin {@link org.mockito.plugins.InstantiatorProvider2}
+ *
+ * @since 2.15.4
+ */
+public interface Instantiator {
+
+ /**
+ * Creates instance of given class
+ *
+ * @since 2.15.4
+ */
+ <T> T newInstance(Class<T> cls) throws InstantiationException;
+
+}
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 983e066..f80e7c4 100644
--- a/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java
+++ b/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java
@@ -4,8 +4,10 @@
*/
package org.mockito.internal.configuration.plugins;
+import org.mockito.internal.creation.instance.InstantiatorProvider2Adapter;
import org.mockito.plugins.AnnotationEngine;
import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
import org.mockito.plugins.MockMaker;
import org.mockito.plugins.MockitoPlugins;
import org.mockito.plugins.PluginSwitch;
@@ -24,15 +26,22 @@ class DefaultMockitoPlugins implements MockitoPlugins {
DEFAULT_PLUGINS.put(PluginSwitch.class.getName(), DefaultPluginSwitch.class.getName());
DEFAULT_PLUGINS.put(MockMaker.class.getName(), "org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker");
DEFAULT_PLUGINS.put(StackTraceCleanerProvider.class.getName(), "org.mockito.internal.exceptions.stacktrace.DefaultStackTraceCleanerProvider");
- DEFAULT_PLUGINS.put(InstantiatorProvider.class.getName(), "org.mockito.internal.creation.instance.DefaultInstantiatorProvider");
+ 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");
}
@Override
public <T> T getDefaultPlugin(Class<T> pluginType) {
- String className = DEFAULT_PLUGINS.get(pluginType.getName());
- return create(pluginType, className);
+ if (pluginType == InstantiatorProvider.class) {
+ //the implementation class is not configured via map so that we can reduce duplication
+ //(ensure that we are adapting the currently configured default implementation for InstantiatorProvider2)
+ String className = DEFAULT_PLUGINS.get(InstantiatorProvider2.class.getName());
+ return pluginType.cast(new InstantiatorProvider2Adapter(create(InstantiatorProvider2.class, className)));
+ } else {
+ String className = DEFAULT_PLUGINS.get(pluginType.getName());
+ return create(pluginType, className);
+ }
}
String getDefaultPluginClass(String classOrAlias) {
diff --git a/src/main/java/org/mockito/internal/configuration/plugins/PluginInitializer.java b/src/main/java/org/mockito/internal/configuration/plugins/PluginInitializer.java
new file mode 100644
index 0000000..0e28d91
--- /dev/null
+++ b/src/main/java/org/mockito/internal/configuration/plugins/PluginInitializer.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.configuration.plugins;
+
+import org.mockito.internal.util.collections.Iterables;
+import org.mockito.plugins.PluginSwitch;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+
+class PluginInitializer {
+
+ private final PluginSwitch pluginSwitch;
+ private final String alias;
+ private final DefaultMockitoPlugins plugins;
+
+ PluginInitializer(PluginSwitch pluginSwitch, String alias, DefaultMockitoPlugins plugins) {
+ this.pluginSwitch = pluginSwitch;
+ this.alias = alias;
+ this.plugins = plugins;
+ }
+
+ /**
+ * Equivalent to {@link java.util.ServiceLoader#load} but without requiring
+ * Java 6 / Android 2.3 (Gingerbread).
+ */
+ public <T> T loadImpl(Class<T> service) {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ if (loader == null) {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+ Enumeration<URL> resources;
+ try {
+ resources = loader.getResources("mockito-extensions/" + service.getName());
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to load " + service, e);
+ }
+
+ try {
+ String classOrAlias = new PluginFinder(pluginSwitch).findPluginClass(Iterables.toIterable(resources));
+ if (classOrAlias != null) {
+ if (classOrAlias.equals(alias)) {
+ classOrAlias = plugins.getDefaultPluginClass(alias);
+ }
+ Class<?> pluginClass = loader.loadClass(classOrAlias);
+ Object plugin = pluginClass.newInstance();
+ return service.cast(plugin);
+ }
+ return null;
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Failed to load " + service + " implementation declared in " + resources, e);
+ }
+ }
+}
diff --git a/src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java b/src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java
index 0132dca..a230d0c 100644
--- a/src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java
+++ b/src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java
@@ -4,26 +4,24 @@
*/
package org.mockito.internal.configuration.plugins;
-import org.mockito.internal.util.collections.Iterables;
import org.mockito.plugins.PluginSwitch;
-import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
-import java.net.URL;
-import java.util.Enumeration;
class PluginLoader {
- private final DefaultMockitoPlugins plugins = new DefaultMockitoPlugins();
+ private final DefaultMockitoPlugins plugins;
+ private final PluginInitializer initializer;
- private final PluginSwitch pluginSwitch;
-
- private String alias;
+ PluginLoader(DefaultMockitoPlugins plugins, PluginInitializer initializer) {
+ this.plugins = plugins;
+ this.initializer = initializer;
+ }
- public PluginLoader(PluginSwitch pluginSwitch) {
- this.pluginSwitch = pluginSwitch;
+ PluginLoader(PluginSwitch pluginSwitch) {
+ this(new DefaultMockitoPlugins(), new PluginInitializer(pluginSwitch, null, new DefaultMockitoPlugins()));
}
/**
@@ -34,9 +32,8 @@ class PluginLoader {
* the alias can be used as a convenience name for a known plugin.
*/
@Deprecated
- PluginLoader withAlias(String name) {
- alias = name;
- return this;
+ PluginLoader(PluginSwitch pluginSwitch, String alias) {
+ this(new DefaultMockitoPlugins(), new PluginInitializer(pluginSwitch, alias, new DefaultMockitoPlugins()));
}
/**
@@ -44,55 +41,39 @@ class PluginLoader {
*/
@SuppressWarnings("unchecked")
<T> T loadPlugin(final Class<T> pluginType) {
- try {
- T plugin = loadImpl(pluginType);
- if (plugin != null) {
- return plugin;
- }
-
- return plugins.getDefaultPlugin(pluginType);
- } catch (final Throwable t) {
- return (T) Proxy.newProxyInstance(pluginType.getClassLoader(),
- new Class<?>[]{pluginType},
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- throw new IllegalStateException("Could not initialize plugin: " + pluginType, t);
- }
- });
- }
+ return (T) loadPlugin(pluginType, null);
}
/**
- * Equivalent to {@link java.util.ServiceLoader#load} but without requiring
- * Java 6 / Android 2.3 (Gingerbread).
+ * Scans the classpath for given {@code preferredPluginType}. If not found scan for {@code
+ * alternatePluginType}. If neither a preferred or alternate plugin is found, default to default
+ * class of {@code preferredPluginType}.
+ *
+ * @return An object of either {@code preferredPluginType} or {@code alternatePluginType}
*/
- private <T> T loadImpl(Class<T> service) {
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- if (loader == null) {
- loader = ClassLoader.getSystemClassLoader();
- }
- Enumeration<URL> resources;
- try {
- resources = loader.getResources("mockito-extensions/" + service.getName());
- } catch (IOException e) {
- throw new IllegalStateException("Failed to load " + service, e);
- }
-
+ @SuppressWarnings("unchecked")
+ <PreferredType, AlternateType> Object loadPlugin(final Class<PreferredType> preferredPluginType, final Class<AlternateType> alternatePluginType) {
try {
- String classOrAlias = new PluginFinder(pluginSwitch).findPluginClass(Iterables.toIterable(resources));
- if (classOrAlias != null) {
- if (classOrAlias.equals(alias)) {
- classOrAlias = plugins.getDefaultPluginClass(alias);
+ PreferredType preferredPlugin = initializer.loadImpl(preferredPluginType);
+ if (preferredPlugin != null) {
+ return preferredPlugin;
+ } else if (alternatePluginType != null) {
+ AlternateType alternatePlugin = initializer.loadImpl(alternatePluginType);
+ if (alternatePlugin != null) {
+ return alternatePlugin;
}
- Class<?> pluginClass = loader.loadClass(classOrAlias);
- Object plugin = pluginClass.newInstance();
- return service.cast(plugin);
}
- return null;
- } catch (Exception e) {
- throw new IllegalStateException(
- "Failed to load " + service + " implementation declared in " + resources, e);
+
+ return plugins.getDefaultPlugin(preferredPluginType);
+ } catch (final Throwable t) {
+ return Proxy.newProxyInstance(preferredPluginType.getClassLoader(),
+ new Class<?>[]{preferredPluginType},
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ throw new IllegalStateException("Could not initialize plugin: " + preferredPluginType + " (alternate: " + alternatePluginType + ")", t);
+ }
+ });
}
}
}
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 d75242c..02e5d66 100644
--- a/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java
+++ b/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java
@@ -4,8 +4,10 @@
*/
package org.mockito.internal.configuration.plugins;
+import org.mockito.internal.creation.instance.InstantiatorProviderAdapter;
import org.mockito.plugins.AnnotationEngine;
import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
import org.mockito.plugins.MockMaker;
import org.mockito.plugins.PluginSwitch;
import org.mockito.plugins.StackTraceCleanerProvider;
@@ -15,19 +17,26 @@ class PluginRegistry {
private final PluginSwitch pluginSwitch = new PluginLoader(new DefaultPluginSwitch())
.loadPlugin(PluginSwitch.class);
- private final MockMaker mockMaker = new PluginLoader(pluginSwitch)
- .withAlias(DefaultMockitoPlugins.INLINE_ALIAS)
+ private final MockMaker mockMaker = new PluginLoader(pluginSwitch, DefaultMockitoPlugins.INLINE_ALIAS)
.loadPlugin(MockMaker.class);
private final StackTraceCleanerProvider stackTraceCleanerProvider = new PluginLoader(pluginSwitch)
.loadPlugin(StackTraceCleanerProvider.class);
- private final InstantiatorProvider instantiatorProvider = new PluginLoader(pluginSwitch)
- .loadPlugin(InstantiatorProvider.class);
+ private final InstantiatorProvider2 instantiatorProvider;
private AnnotationEngine annotationEngine = new PluginLoader(pluginSwitch)
.loadPlugin(AnnotationEngine.class);
+ PluginRegistry() {
+ Object impl = new PluginLoader(pluginSwitch).loadPlugin(InstantiatorProvider2.class, InstantiatorProvider.class);
+ if (impl instanceof InstantiatorProvider) {
+ instantiatorProvider = new InstantiatorProviderAdapter((InstantiatorProvider) impl);
+ } else {
+ instantiatorProvider = (InstantiatorProvider2) impl;
+ }
+ }
+
/**
* The implementation of the stack trace cleaner
*/
@@ -50,10 +59,11 @@ class PluginRegistry {
* Returns the instantiator provider available for the current runtime.
*
* <p>Returns {@link org.mockito.internal.creation.instance.DefaultInstantiatorProvider} if no
- * {@link org.mockito.plugins.InstantiatorProvider} extension exists or is visible in the current classpath.</p>
+ * {@link org.mockito.plugins.InstantiatorProvider2} extension exists or is visible in the
+ * current classpath.</p>
*/
- InstantiatorProvider getInstantiatorProvider() {
- return instantiatorProvider;
+ InstantiatorProvider2 getInstantiatorProvider() {
+ return instantiatorProvider;
}
/**
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 2c214c2..f65fe89 100644
--- a/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java
+++ b/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java
@@ -5,7 +5,7 @@
package org.mockito.internal.configuration.plugins;
import org.mockito.plugins.AnnotationEngine;
-import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
import org.mockito.plugins.MockMaker;
import org.mockito.plugins.MockitoPlugins;
import org.mockito.plugins.StackTraceCleanerProvider;
@@ -38,9 +38,10 @@ public class Plugins {
* Returns the instantiator provider available for the current runtime.
*
* <p>Returns {@link org.mockito.internal.creation.instance.DefaultInstantiatorProvider} if no
- * {@link org.mockito.plugins.InstantiatorProvider} extension exists or is visible in the current classpath.</p>
+ * {@link org.mockito.plugins.InstantiatorProvider2} extension exists or is visible in the
+ * current classpath.</p>
*/
- public static InstantiatorProvider getInstantiatorProvider() {
+ public static InstantiatorProvider2 getInstantiatorProvider() {
return registry.getInstantiatorProvider();
}
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 50d7851..42f10ce 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java
@@ -9,7 +9,7 @@ import org.mockito.Incubating;
import org.mockito.exceptions.base.MockitoException;
import org.mockito.exceptions.base.MockitoInitializationException;
import org.mockito.internal.configuration.plugins.Plugins;
-import org.mockito.internal.creation.instance.Instantiator;
+import org.mockito.creation.instance.Instantiator;
import org.mockito.internal.util.Platform;
import org.mockito.internal.util.concurrent.WeakConcurrentMap;
import org.mockito.invocation.MockHandler;
@@ -189,7 +189,7 @@ public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker {
((MockAccess) instance).setMockitoInterceptor(mockMethodInterceptor);
}
return instance;
- } catch (org.mockito.internal.creation.instance.InstantiationException e) {
+ } catch (org.mockito.creation.instance.InstantiationException e) {
throw new MockitoException("Unable to create mock instance of type '" + type.getSimpleName() + "'", e);
}
}
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 7d9f347..f39a1a2 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java
@@ -16,6 +16,8 @@ import org.mockito.internal.debugging.LocationImpl;
import org.mockito.internal.exceptions.stacktrace.ConditionalStackTraceFilter;
import org.mockito.internal.invocation.RealMethod;
import org.mockito.internal.invocation.SerializableMethod;
+import org.mockito.internal.invocation.mockref.MockReference;
+import org.mockito.internal.invocation.mockref.MockWeakReference;
import org.mockito.internal.util.concurrent.WeakConcurrentMap;
import java.io.IOException;
@@ -107,18 +109,20 @@ public class MockMethodAdvice extends MockMethodDispatcher {
return new ReturnValueWrapper(interceptor.doIntercept(instance,
origin,
arguments,
- realMethod,
+ realMethod,
new LocationImpl(t)));
}
@Override
public boolean isMock(Object instance) {
- return interceptors.containsKey(instance);
+ // We need to exclude 'interceptors.target' explicitly to avoid a recursive check on whether
+ // the map is a mock object what requires reading from the map.
+ return instance != interceptors.target && interceptors.containsKey(instance);
}
@Override
public boolean isMocked(Object instance) {
- return !selfCallInfo.isSelfInvocation(instance) && isMock(instance);
+ return selfCallInfo.checkSuperCall(instance) && isMock(instance);
}
@Override
@@ -139,14 +143,14 @@ public class MockMethodAdvice extends MockMethodDispatcher {
private final Method origin;
- private final Object instance;
+ private final MockWeakReference<Object> instanceRef;
private final Object[] arguments;
private RealMethodCall(SelfCallInfo selfCallInfo, Method origin, Object instance, Object[] arguments) {
this.selfCallInfo = selfCallInfo;
this.origin = origin;
- this.instance = instance;
+ this.instanceRef = new MockWeakReference<Object>(instance);
this.arguments = arguments;
}
@@ -160,12 +164,8 @@ public class MockMethodAdvice extends MockMethodDispatcher {
if (!Modifier.isPublic(origin.getDeclaringClass().getModifiers() & origin.getModifiers())) {
origin.setAccessible(true);
}
- Object previous = selfCallInfo.replace(instance);
- try {
- return tryInvoke(origin, instance, arguments);
- } finally {
- selfCallInfo.set(previous);
- }
+ selfCallInfo.set(instanceRef.get());
+ return tryInvoke(origin, instanceRef.get(), arguments);
}
}
@@ -176,14 +176,14 @@ public class MockMethodAdvice extends MockMethodDispatcher {
private final SerializableMethod origin;
- private final Object instance;
+ private final MockReference<Object> instanceRef;
private final Object[] arguments;
private SerializableRealMethodCall(String identifier, Method origin, Object instance, Object[] arguments) {
this.origin = new SerializableMethod(origin);
this.identifier = identifier;
- this.instance = instance;
+ this.instanceRef = new MockWeakReference<Object>(instance);
this.arguments = arguments;
}
@@ -198,13 +198,13 @@ public class MockMethodAdvice extends MockMethodDispatcher {
if (!Modifier.isPublic(method.getDeclaringClass().getModifiers() & method.getModifiers())) {
method.setAccessible(true);
}
- MockMethodDispatcher mockMethodDispatcher = MockMethodDispatcher.get(identifier, instance);
+ MockMethodDispatcher mockMethodDispatcher = MockMethodDispatcher.get(identifier, instanceRef.get());
if (!(mockMethodDispatcher instanceof MockMethodAdvice)) {
throw new MockitoException("Unexpected dispatcher for advice-based super call");
}
- Object previous = ((MockMethodAdvice) mockMethodDispatcher).selfCallInfo.replace(instance);
+ Object previous = ((MockMethodAdvice) mockMethodDispatcher).selfCallInfo.replace(instanceRef.get());
try {
- return tryInvoke(method, instance, arguments);
+ return tryInvoke(method, instanceRef.get(), arguments);
} finally {
((MockMethodAdvice) mockMethodDispatcher).selfCallInfo.set(previous);
}
@@ -252,14 +252,19 @@ public class MockMethodAdvice extends MockMethodDispatcher {
private static class SelfCallInfo extends ThreadLocal<Object> {
- Object replace(Object instance) {
+ Object replace(Object value) {
Object current = get();
- set(instance);
+ set(value);
return current;
}
- boolean isSelfInvocation(Object instance) {
- return get() == instance;
+ boolean checkSuperCall(Object value) {
+ if (value == get()) {
+ set(null);
+ return false;
+ } else {
+ return true;
+ }
}
}
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 7c2dec8..9066927 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java
@@ -13,12 +13,8 @@ import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.StubValue;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.implementation.bind.annotation.This;
-import org.mockito.internal.creation.DelegatingMethod;
import org.mockito.internal.debugging.LocationImpl;
-import org.mockito.internal.invocation.MockitoMethod;
import org.mockito.internal.invocation.RealMethod;
-import org.mockito.internal.invocation.SerializableMethod;
-import org.mockito.internal.progress.SequenceNumber;
import org.mockito.invocation.Location;
import org.mockito.invocation.MockHandler;
import org.mockito.mock.MockCreationSettings;
@@ -28,6 +24,8 @@ import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
+import static org.mockito.internal.invocation.DefaultInvocationFactory.createInvocation;
+
public class MockMethodInterceptor implements Serializable {
private static final long serialVersionUID = 7152947254057253027L;
@@ -65,29 +63,6 @@ public class MockMethodInterceptor implements Serializable {
return handler.handle(createInvocation(mock, invokedMethod, arguments, realMethod, mockCreationSettings, location));
}
- public static InterceptedInvocation createInvocation(Object mock, Method invokedMethod, Object[] arguments, RealMethod realMethod, MockCreationSettings settings, Location location) {
- return new InterceptedInvocation(
- mock,
- createMockitoMethod(invokedMethod, settings),
- arguments,
- realMethod,
- location,
- SequenceNumber.next()
- );
- }
-
- public static InterceptedInvocation createInvocation(Object mock, Method invokedMethod, Object[] arguments, RealMethod realMethod, MockCreationSettings settings) {
- return createInvocation(mock, invokedMethod, arguments, realMethod, settings, new LocationImpl());
- }
-
- private static MockitoMethod createMockitoMethod(Method method, MockCreationSettings settings) {
- if (settings.isSerializable()) {
- return new SerializableMethod(method);
- } else {
- return new DelegatingMethod(method);
- }
- }
-
public MockHandler getMockHandler() {
return handler;
}
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java
index e9a3ddf..79e89f2 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java
@@ -6,7 +6,7 @@ package org.mockito.internal.creation.bytebuddy;
import org.mockito.exceptions.base.MockitoException;
import org.mockito.internal.configuration.plugins.Plugins;
-import org.mockito.internal.creation.instance.Instantiator;
+import org.mockito.creation.instance.Instantiator;
import org.mockito.internal.util.Platform;
import org.mockito.invocation.MockHandler;
import org.mockito.mock.MockCreationSettings;
@@ -60,7 +60,7 @@ public class SubclassByteBuddyMockMaker implements ClassCreatingMockMaker {
"You might experience classloading issues, please ask the mockito mailing-list.",
""
), cce);
- } catch (org.mockito.internal.creation.instance.InstantiationException e) {
+ } catch (org.mockito.creation.instance.InstantiationException e) {
throw new MockitoException("Unable to create mock instance of type '" + mockedProxyType.getSuperclass().getSimpleName() + "'", e);
}
}
diff --git a/src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java b/src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java
index edf47c9..688526b 100644
--- a/src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java
+++ b/src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java
@@ -10,6 +10,8 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import org.mockito.creation.instance.Instantiator;
+import org.mockito.creation.instance.InstantiationException;
import org.mockito.internal.util.Primitives;
import org.mockito.internal.util.reflection.AccessibilityChanger;
diff --git a/src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java b/src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java
index 22d06d1..9c414f3 100644
--- a/src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java
+++ b/src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java
@@ -4,10 +4,11 @@
*/
package org.mockito.internal.creation.instance;
+import org.mockito.creation.instance.Instantiator;
import org.mockito.mock.MockCreationSettings;
-import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
-public class DefaultInstantiatorProvider implements InstantiatorProvider {
+public class DefaultInstantiatorProvider implements InstantiatorProvider2 {
private final static Instantiator INSTANCE = new ObjenesisInstantiator();
diff --git a/src/main/java/org/mockito/internal/creation/instance/InstantiationException.java b/src/main/java/org/mockito/internal/creation/instance/InstantiationException.java
index c0151f1..86b5463 100644
--- a/src/main/java/org/mockito/internal/creation/instance/InstantiationException.java
+++ b/src/main/java/org/mockito/internal/creation/instance/InstantiationException.java
@@ -6,6 +6,14 @@ package org.mockito.internal.creation.instance;
import org.mockito.exceptions.base.MockitoException;
+/**
+ * @deprecated since 2.15.4 because this internal class was leaking from the public API.
+ * For information why deprecated, see {@link org.mockito.plugins.InstantiatorProvider2}.
+ * Use {@link org.mockito.creation.instance.Instantiator} and {@link org.mockito.creation.instance.InstantiationException} types instead.
+ * <p>
+ * Exception generated when {@link Instantiator#newInstance(Class)} failed.
+ */
+@Deprecated
public class InstantiationException extends MockitoException {
public InstantiationException(String message, Throwable cause) {
diff --git a/src/main/java/org/mockito/internal/creation/instance/Instantiator.java b/src/main/java/org/mockito/internal/creation/instance/Instantiator.java
index b1ee67d..85b6b3d 100644
--- a/src/main/java/org/mockito/internal/creation/instance/Instantiator.java
+++ b/src/main/java/org/mockito/internal/creation/instance/Instantiator.java
@@ -5,8 +5,13 @@
package org.mockito.internal.creation.instance;
/**
+ * @deprecated since 2.15.4 because this internal class was leaking from the public API.
+ * For more information why deprecated, see {@link org.mockito.plugins.InstantiatorProvider2}.
+ * Use {@link org.mockito.creation.instance.Instantiator} instead.
+ * <p>
* Provides instances of classes.
*/
+@Deprecated
public interface Instantiator {
/**
diff --git a/src/main/java/org/mockito/internal/creation/instance/InstantiatorProvider2Adapter.java b/src/main/java/org/mockito/internal/creation/instance/InstantiatorProvider2Adapter.java
new file mode 100644
index 0000000..a1ab5d5
--- /dev/null
+++ b/src/main/java/org/mockito/internal/creation/instance/InstantiatorProvider2Adapter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.instance;
+
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
+
+/**
+ * Adapts new public API {@link InstantiatorProvider2} onto old, deprecated API {@link InstantiatorProvider}
+ */
+public class InstantiatorProvider2Adapter implements InstantiatorProvider {
+ private final InstantiatorProvider2 provider;
+
+ public InstantiatorProvider2Adapter(InstantiatorProvider2 provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public Instantiator getInstantiator(final MockCreationSettings<?> settings) {
+ return new Instantiator() {
+ @Override
+ public <T> T newInstance(Class<T> cls) throws InstantiationException {
+ try {
+ return provider.getInstantiator(settings).newInstance(cls);
+ } catch (org.mockito.creation.instance.InstantiationException e) {
+ throw new InstantiationException(e.getMessage(), e.getCause());
+ }
+ }
+ };
+ }
+}
diff --git a/src/main/java/org/mockito/internal/creation/instance/InstantiatorProviderAdapter.java b/src/main/java/org/mockito/internal/creation/instance/InstantiatorProviderAdapter.java
new file mode 100644
index 0000000..c807925
--- /dev/null
+++ b/src/main/java/org/mockito/internal/creation/instance/InstantiatorProviderAdapter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.instance;
+
+import org.mockito.creation.instance.InstantiationException;
+import org.mockito.creation.instance.Instantiator;
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
+
+/**
+ * Adapts old, deprecated {@link InstantiatorProvider} onto a new public {@link InstantiatorProvider2} API.
+ */
+public class InstantiatorProviderAdapter implements InstantiatorProvider2 {
+ private final InstantiatorProvider provider;
+
+ public InstantiatorProviderAdapter(InstantiatorProvider provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public Instantiator getInstantiator(final MockCreationSettings<?> settings) {
+ return new Instantiator() {
+ @Override
+ public <T> T newInstance(Class<T> cls) throws InstantiationException {
+ try {
+ return provider.getInstantiator(settings).newInstance(cls);
+ } catch (org.mockito.internal.creation.instance.InstantiationException e) {
+ throw new InstantiationException(e.getMessage(), e.getCause());
+ }
+ }
+ };
+ }
+}
diff --git a/src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java b/src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java
index a0f0980..7e41f68 100644
--- a/src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java
+++ b/src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java
@@ -4,6 +4,7 @@
*/
package org.mockito.internal.creation.instance;
+import org.mockito.creation.instance.Instantiator;
import org.mockito.internal.configuration.GlobalConfiguration;
import org.objenesis.ObjenesisStd;
diff --git a/src/main/java/org/mockito/internal/debugging/LocationImpl.java b/src/main/java/org/mockito/internal/debugging/LocationImpl.java
index ce3de04..8561b62 100644
--- a/src/main/java/org/mockito/internal/debugging/LocationImpl.java
+++ b/src/main/java/org/mockito/internal/debugging/LocationImpl.java
@@ -11,11 +11,14 @@ import org.mockito.invocation.Location;
public class LocationImpl implements Location, Serializable {
private static final long serialVersionUID = -9054861157390980624L;
+ //Limit the amount of objects being created, as this class is heavily instantiated:
+ private static final StackTraceFilter defaultStackTraceFilter = new StackTraceFilter();
+
private final Throwable stackTraceHolder;
private final StackTraceFilter stackTraceFilter;
public LocationImpl() {
- this(new StackTraceFilter());
+ this(defaultStackTraceFilter);
}
public LocationImpl(StackTraceFilter stackTraceFilter) {
@@ -23,7 +26,7 @@ public class LocationImpl implements Location, Serializable {
}
public LocationImpl(Throwable stackTraceHolder) {
- this(new StackTraceFilter(), stackTraceHolder);
+ this(defaultStackTraceFilter, stackTraceHolder);
}
private LocationImpl(StackTraceFilter stackTraceFilter, Throwable stackTraceHolder) {
diff --git a/src/main/java/org/mockito/internal/exceptions/MockitoLimitations.java b/src/main/java/org/mockito/internal/exceptions/MockitoLimitations.java
deleted file mode 100644
index c8edc79..0000000
--- a/src/main/java/org/mockito/internal/exceptions/MockitoLimitations.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright (c) 2016 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.exceptions;
-
-public class MockitoLimitations {
-
- public final static String NON_PUBLIC_PARENT = "Mocking methods declared on non-public parent classes is not supported.";
-
-}
diff --git a/src/main/java/org/mockito/internal/exceptions/Reporter.java b/src/main/java/org/mockito/internal/exceptions/Reporter.java
index cee97fd..57094c0 100644
--- a/src/main/java/org/mockito/internal/exceptions/Reporter.java
+++ b/src/main/java/org/mockito/internal/exceptions/Reporter.java
@@ -51,6 +51,8 @@ import static org.mockito.internal.util.StringUtil.join;
*/
public class Reporter {
+ private final static String NON_PUBLIC_PARENT = "Mocking methods declared on non-public parent classes is not supported.";
+
private Reporter() {
}
@@ -108,7 +110,7 @@ public class Reporter {
"Also, this error might show up because:",
"1. you stub either of: final/private/equals()/hashCode() methods.",
" Those methods *cannot* be stubbed/verified.",
- " " + MockitoLimitations.NON_PUBLIC_PARENT,
+ " " + NON_PUBLIC_PARENT,
"2. inside when() you don't call method on mock but on some other object.",
""
));
@@ -124,7 +126,7 @@ public class Reporter {
"",
"Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.",
"Those methods *cannot* be stubbed/verified.",
- MockitoLimitations.NON_PUBLIC_PARENT,
+ NON_PUBLIC_PARENT,
""
));
}
@@ -464,7 +466,7 @@ public class Reporter {
"2. Somewhere in your test you are stubbing *final methods*. Sorry, Mockito does not verify/stub final methods.",
"3. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - ",
" - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.",
- "4. " + MockitoLimitations.NON_PUBLIC_PARENT,
+ "4. " + NON_PUBLIC_PARENT,
""
));
}
@@ -531,7 +533,7 @@ public class Reporter {
"",
"Also, this error might show up because you use argument matchers with methods that cannot be mocked.",
"Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().",
- MockitoLimitations.NON_PUBLIC_PARENT,
+ NON_PUBLIC_PARENT,
""
));
}
@@ -857,7 +859,7 @@ public class Reporter {
heading,
"Clean & maintainable test code requires zero unnecessary code.",
"Following stubbings are unnecessary (click to navigate to relevant line of code):" + stubbings,
- "Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class."
+ "Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class."
));
}
@@ -888,7 +890,7 @@ public class Reporter {
" - stubbing the same method multiple times using 'given().will()' or 'when().then()' API",
" Please use 'will().given()' or 'doReturn().when()' API for stubbing.",
" - stubbed method is intentionally invoked with different arguments by code under test",
- " Please use 'default' or 'silent' JUnit Rule.",
+ " Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).",
"For more information see javadoc for PotentialStubbingProblem class."));
}
diff --git a/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java b/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java
index 40b24bb..c900bf7 100644
--- a/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java
+++ b/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.framework;
@@ -14,13 +14,17 @@ import org.mockito.internal.junit.UniversalTestListener;
import org.mockito.internal.util.MockitoLogger;
import org.mockito.quality.Strictness;
+import java.util.List;
+
public class DefaultMockitoSession implements MockitoSession {
- private final Object testClassInstance;
+ private final List<Object> testClassInstances;
+ private final String name;
private final UniversalTestListener listener;
- public DefaultMockitoSession(Object testClassInstance, Strictness strictness, MockitoLogger logger) {
- this.testClassInstance = testClassInstance;
+ public DefaultMockitoSession(List<Object> testClassInstances, String name, Strictness strictness, MockitoLogger logger) {
+ this.testClassInstances = testClassInstances;
+ this.name = name;
listener = new UniversalTestListener(strictness, logger);
try {
//So that the listener can capture mock creation events
@@ -28,10 +32,23 @@ public class DefaultMockitoSession implements MockitoSession {
} catch (RedundantListenerException e) {
Reporter.unfinishedMockingSession();
}
- MockitoAnnotations.initMocks(testClassInstance);
+ for (Object testClassInstance : testClassInstances) {
+ MockitoAnnotations.initMocks(testClassInstance);
+ }
+ }
+
+ @Override
+ public void setStrictness(Strictness strictness) {
+ listener.setStrictness(strictness);
}
+ @Override
public void finishMocking() {
+ finishMocking(null);
+ }
+
+ @Override
+ public void finishMocking(final Throwable failure) {
//Cleaning up the state, we no longer need the listener hooked up
//The listener implements MockCreationListener and at this point
//we no longer need to listen on mock creation events. We are wrapping up the session
@@ -39,18 +56,20 @@ public class DefaultMockitoSession implements MockitoSession {
//Emit test finished event so that validation such as strict stubbing can take place
listener.testFinished(new TestFinishedEvent() {
+ @Override
public Throwable getFailure() {
- return null;
+ return failure;
}
- public Object getTestClassInstance() {
- return testClassInstance;
- }
- public String getTestMethodName() {
- return null;
+ @Override
+ public String getTestName() {
+ return name;
}
});
- //Finally, validate user's misuse of Mockito framework.
- Mockito.validateMockitoUsage();
+ //Validate only when there is no test failure to avoid reporting multiple problems
+ if (failure == null) {
+ //Finally, validate user's misuse of Mockito framework.
+ Mockito.validateMockitoUsage();
+ }
}
}
diff --git a/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java b/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
index 38f18e9..57a9d43 100644
--- a/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
+++ b/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
@@ -8,7 +8,6 @@ import org.mockito.internal.creation.settings.CreationSettings;
import org.mockito.internal.invocation.InvocationMatcher;
import org.mockito.internal.invocation.MatchersBinder;
import org.mockito.internal.listeners.StubbingLookupListener;
-import org.mockito.invocation.InvocationContainer;
import org.mockito.internal.stubbing.InvocationContainerImpl;
import org.mockito.internal.stubbing.OngoingStubbingImpl;
import org.mockito.internal.stubbing.StubbedInvocationMatcher;
@@ -16,6 +15,7 @@ import org.mockito.internal.stubbing.answers.DefaultAnswerValidator;
import org.mockito.internal.verification.MockAwareVerificationMode;
import org.mockito.internal.verification.VerificationDataImpl;
import org.mockito.invocation.Invocation;
+import org.mockito.invocation.InvocationContainer;
import org.mockito.invocation.MockHandler;
import org.mockito.mock.MockCreationSettings;
import org.mockito.verification.VerificationMode;
@@ -92,7 +92,14 @@ public class MockHandlerImpl<T> implements MockHandler<T> {
if (stubbing != null) {
stubbing.captureArgumentsFrom(invocation);
- return stubbing.answer(invocation);
+
+ try {
+ return stubbing.answer(invocation);
+ } finally {
+ //Needed so that we correctly isolate stubbings in some scenarios
+ //see MockitoStubbedCallInAnswerTest or issue #1279
+ mockingProgress().reportOngoingStubbing(ongoingStubbing);
+ }
} else {
Object ret = mockSettings.getDefaultAnswer().answer(invocation);
DefaultAnswerValidator.validateReturnValueFor(invocation, ret);
diff --git a/src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java b/src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
index af8fd3d..d08f6b1 100644
--- a/src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
+++ b/src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
@@ -4,9 +4,13 @@
*/
package org.mockito.internal.invocation;
-import org.mockito.internal.creation.bytebuddy.MockMethodInterceptor;
+import org.mockito.internal.creation.DelegatingMethod;
+import org.mockito.internal.invocation.mockref.MockWeakReference;
+import org.mockito.internal.debugging.LocationImpl;
+import org.mockito.internal.progress.SequenceNumber;
import org.mockito.invocation.Invocation;
import org.mockito.invocation.InvocationFactory;
+import org.mockito.invocation.Location;
import org.mockito.mock.MockCreationSettings;
import java.lang.reflect.Method;
@@ -14,8 +18,41 @@ import java.util.concurrent.Callable;
public class DefaultInvocationFactory implements InvocationFactory {
- public Invocation createInvocation(Object target, MockCreationSettings settings, Method method, Callable realMethod, Object... args) {
- RealMethod.FromCallable superMethod = new RealMethod.FromCallable(realMethod);
- return MockMethodInterceptor.createInvocation(target, method, args, superMethod, settings);
+ public Invocation createInvocation(Object target, MockCreationSettings settings, Method method, final Callable realMethod, Object... args) {
+ RealMethod superMethod = new RealMethod.FromCallable(realMethod);
+ return createInvocation(target, settings, method, superMethod, args);
+ }
+
+ public Invocation createInvocation(Object target, MockCreationSettings settings, Method method, RealMethodBehavior realMethod, Object... args) {
+ RealMethod superMethod = new RealMethod.FromBehavior(realMethod);
+ return createInvocation(target, settings, method, superMethod, args);
+ }
+
+ private Invocation createInvocation(Object target, MockCreationSettings settings, Method method, RealMethod superMethod, Object[] args) {
+ return createInvocation(target, method, args, superMethod, settings);
+ }
+
+ public static InterceptedInvocation createInvocation(Object mock, Method invokedMethod, Object[] arguments, RealMethod realMethod, MockCreationSettings settings, Location location) {
+ return new InterceptedInvocation(
+ new MockWeakReference<Object>(mock),
+ createMockitoMethod(invokedMethod, settings),
+ arguments,
+ realMethod,
+ location,
+ SequenceNumber.next()
+ );
+ }
+
+ private static InterceptedInvocation createInvocation(Object mock, Method invokedMethod, Object[]
+ arguments, RealMethod realMethod, MockCreationSettings settings) {
+ return createInvocation(mock, invokedMethod, arguments, realMethod, settings, new LocationImpl());
+ }
+
+ private static MockitoMethod createMockitoMethod(Method method, MockCreationSettings settings) {
+ if (settings.isSerializable()) {
+ return new SerializableMethod(method);
+ } else {
+ return new DelegatingMethod(method);
+ }
}
}
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java b/src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java
index 9c7b49e..b9cf072 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java
+++ b/src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java
@@ -2,12 +2,10 @@
* Copyright (c) 2016 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
-package org.mockito.internal.creation.bytebuddy;
+package org.mockito.internal.invocation;
+import org.mockito.internal.invocation.mockref.MockReference;
import org.mockito.internal.exceptions.VerificationAwareInvocation;
-import org.mockito.internal.invocation.ArgumentsProcessor;
-import org.mockito.internal.invocation.MockitoMethod;
-import org.mockito.internal.invocation.RealMethod;
import org.mockito.internal.reporting.PrintSettings;
import org.mockito.invocation.Invocation;
import org.mockito.invocation.Location;
@@ -22,7 +20,7 @@ public class InterceptedInvocation implements Invocation, VerificationAwareInvoc
private static final long serialVersionUID = 475027563923510472L;
- private final Object mock;
+ private final MockReference<Object> mockRef;
private final MockitoMethod mockitoMethod;
private final Object[] arguments, rawArguments;
private final RealMethod realMethod;
@@ -35,13 +33,13 @@ public class InterceptedInvocation implements Invocation, VerificationAwareInvoc
private boolean isIgnoredForVerification;
private StubInfo stubInfo;
- public InterceptedInvocation(Object mock,
+ public InterceptedInvocation(MockReference<Object> mockRef,
MockitoMethod mockitoMethod,
Object[] arguments,
RealMethod realMethod,
Location location,
int sequenceNumber) {
- this.mock = mock;
+ this.mockRef = mockRef;
this.mockitoMethod = mockitoMethod;
this.arguments = ArgumentsProcessor.expandArgs(mockitoMethod, arguments);
this.rawArguments = arguments;
@@ -102,7 +100,7 @@ public class InterceptedInvocation implements Invocation, VerificationAwareInvoc
@Override
public Object getMock() {
- return mock;
+ return mockRef.get();
}
@Override
@@ -141,7 +139,7 @@ public class InterceptedInvocation implements Invocation, VerificationAwareInvoc
return false;
}
InterceptedInvocation other = (InterceptedInvocation) o;
- return this.mock.equals(other.mock)
+ return this.mockRef.get().equals(other.mockRef.get())
&& this.mockitoMethod.equals(other.mockitoMethod)
&& this.equalArguments(other.arguments);
}
diff --git a/src/main/java/org/mockito/internal/invocation/RealMethod.java b/src/main/java/org/mockito/internal/invocation/RealMethod.java
index cd74d3c..b7c8c17 100644
--- a/src/main/java/org/mockito/internal/invocation/RealMethod.java
+++ b/src/main/java/org/mockito/internal/invocation/RealMethod.java
@@ -5,6 +5,7 @@
package org.mockito.internal.invocation;
import org.mockito.internal.exceptions.stacktrace.ConditionalStackTraceFilter;
+import org.mockito.invocation.InvocationFactory;
import org.mockito.invocation.InvocationOnMock;
import java.io.Serializable;
@@ -31,14 +32,23 @@ public interface RealMethod extends Serializable {
}
}
- class FromCallable implements RealMethod {
+ class FromCallable extends FromBehavior implements RealMethod {
+ public FromCallable(final Callable<?> callable) {
+ super(new InvocationFactory.RealMethodBehavior() {
+ @Override
+ public Object call() throws Throwable {
+ return callable.call();
+ }
+ });
+ }
+ }
- private static final long serialVersionUID = 47957363950483625L;
+ class FromBehavior implements RealMethod {
- private final Callable<?> callable;
+ private final InvocationFactory.RealMethodBehavior<?> behavior;
- public FromCallable(Callable<?> callable) {
- this.callable = callable;
+ FromBehavior(InvocationFactory.RealMethodBehavior<?> behavior) {
+ this.behavior = behavior;
}
@Override
@@ -49,7 +59,7 @@ public interface RealMethod extends Serializable {
@Override
public Object invoke() throws Throwable {
try {
- return callable.call();
+ return behavior.call();
} catch (Throwable t) {
new ConditionalStackTraceFilter().filter(t);
throw t;
diff --git a/src/main/java/org/mockito/internal/invocation/mockref/MockReference.java b/src/main/java/org/mockito/internal/invocation/mockref/MockReference.java
new file mode 100644
index 0000000..0dac2ea
--- /dev/null
+++ b/src/main/java/org/mockito/internal/invocation/mockref/MockReference.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.internal.invocation.mockref;
+
+import java.io.Serializable;
+
+/**
+ * To avoid memory leaks for certain implementations of MockMaker,
+ * we need to use weak mock references internally. See #1313
+ */
+public interface MockReference<T> extends Serializable {
+ T get();
+}
diff --git a/src/main/java/org/mockito/internal/invocation/mockref/MockStrongReference.java b/src/main/java/org/mockito/internal/invocation/mockref/MockStrongReference.java
new file mode 100644
index 0000000..3b20ee5
--- /dev/null
+++ b/src/main/java/org/mockito/internal/invocation/mockref/MockStrongReference.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.internal.invocation.mockref;
+
+import java.io.ObjectStreamException;
+
+public class MockStrongReference<T> implements MockReference<T> {
+
+ private final T ref;
+ private final boolean deserializeAsWeakRef;
+
+ public MockStrongReference(T ref, boolean deserializeAsWeakRef) {
+ this.ref = ref;
+ this.deserializeAsWeakRef = deserializeAsWeakRef;
+ }
+
+ @Override
+ public T get() {
+ return ref;
+ }
+
+ private Object readResolve() throws ObjectStreamException {
+ if (deserializeAsWeakRef) {
+ return new MockWeakReference<T>(ref);
+ } else {
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/org/mockito/internal/invocation/mockref/MockWeakReference.java b/src/main/java/org/mockito/internal/invocation/mockref/MockWeakReference.java
new file mode 100644
index 0000000..256745b
--- /dev/null
+++ b/src/main/java/org/mockito/internal/invocation/mockref/MockWeakReference.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.internal.invocation.mockref;
+
+import java.io.ObjectStreamException;
+import java.lang.ref.WeakReference;
+
+/**
+ * A weak reference that is converted into a strong reference when serialized.
+ * See {@link MockReference}.
+ */
+public class MockWeakReference<T> implements MockReference<T> {
+
+ private final WeakReference<T> ref;
+
+ public MockWeakReference(T t) {
+ this.ref = new WeakReference<T>(t);
+ }
+
+ private Object writeReplace() throws ObjectStreamException {
+ return new MockStrongReference<T>(get(), true);
+ }
+
+ @Override
+ public T get() {
+ T ref = this.ref.get();
+
+ if (ref == null) {
+ throw new IllegalStateException("The mock object was garbage collected. " +
+ "This should not happen in normal circumstances when using public API. " +
+ "Typically, the test class keeps strong reference to the mock object " +
+ "and it prevents getting the mock collected. Mockito internally needs " +
+ "to keep weak references to mock objects to avoid memory leaks for " +
+ "certain types of MockMaker implementations. If you see this exception " +
+ "using Mockito public API, please file a bug. For more information see " +
+ "issue #1313.");
+ }
+
+ return ref;
+ }
+}
diff --git a/src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java b/src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java
index 172868c..c3b348b 100644
--- a/src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java
+++ b/src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.junit;
@@ -15,15 +15,13 @@ public class DefaultTestFinishedEvent implements TestFinishedEvent {
this.testFailure = testFailure;
}
+ @Override
public Throwable getFailure() {
return testFailure;
}
- public Object getTestClassInstance() {
- return testClassInstance;
- }
-
- public String getTestMethodName() {
- return testMethodName;
+ @Override
+ public String getTestName() {
+ return testClassInstance.getClass().getSimpleName() + "." + testMethodName;
}
}
diff --git a/src/main/java/org/mockito/internal/junit/JUnitRule.java b/src/main/java/org/mockito/internal/junit/JUnitRule.java
index 8763354..b825416 100644
--- a/src/main/java/org/mockito/internal/junit/JUnitRule.java
+++ b/src/main/java/org/mockito/internal/junit/JUnitRule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.junit;
@@ -7,9 +7,10 @@ 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.quality.Strictness;
+import org.mockito.MockitoSession;
+import org.mockito.internal.session.MockitoSessionLoggerAdapter;
import org.mockito.internal.util.MockitoLogger;
+import org.mockito.quality.Strictness;
import org.mockito.junit.MockitoRule;
/**
@@ -18,44 +19,32 @@ import org.mockito.junit.MockitoRule;
public class JUnitRule implements MockitoRule {
private final MockitoLogger logger;
- private final UniversalTestListener listener;
+ private Strictness strictness;
+ private MockitoSession session;
/**
- * @param logger target for the stubbing warnings
* @param strictness how strict mocking / stubbing is concerned
*/
public JUnitRule(MockitoLogger logger, Strictness strictness) {
this.logger = logger;
- this.listener = new UniversalTestListener(strictness, logger);
+ this.strictness = strictness;
}
@Override
public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
return new Statement() {
public void evaluate() throws Throwable {
- //Ideally, JUnit rule should use MockitoSession API so that it dogfoods our public API.
- //See https://github.com/mockito/mockito/issues/898
- Mockito.framework().addListener(listener);
- Throwable testFailure;
- try {
- //mock initialization could be part of listeners but to avoid duplication I left it here:
- MockitoAnnotations.initMocks(target);
- testFailure = evaluateSafely(base);
- } finally {
- Mockito.framework().removeListener(listener);
- }
-
- //If the 'testFinished' fails below, we don't see the original failure, thrown later
- DefaultTestFinishedEvent event = new DefaultTestFinishedEvent(target, method.getName(), testFailure);
- listener.testFinished(event);
-
+ 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) {
throw testFailure;
}
-
- //Validate only when there is no test failure to avoid reporting multiple problems
- //This could be part of the listener but to avoid duplication I left it here:
- Mockito.validateMockitoUsage();
}
private Throwable evaluateSafely(Statement base) {
@@ -70,11 +59,16 @@ public class JUnitRule implements MockitoRule {
}
public MockitoRule silent() {
- return new JUnitRule(logger, Strictness.LENIENT);
+ return strictness(Strictness.LENIENT);
}
public MockitoRule strictness(Strictness strictness) {
- this.listener.setStrictness(strictness);
+ this.strictness = strictness;
+ // session is null when this method is called during initialization of
+ // the @Rule field of the test class
+ if (session != null) {
+ session.setStrictness(strictness);
+ }
return this;
}
}
diff --git a/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java b/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java
index 408c581..26d4e4e 100644
--- a/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java
+++ b/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java
@@ -1,10 +1,9 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.junit;
-import org.mockito.internal.junit.util.TestName;
import org.mockito.internal.util.MockitoLogger;
import org.mockito.mock.MockCreationSettings;
@@ -30,10 +29,9 @@ public class MismatchReportingTestListener implements MockitoTestListener {
//TODO make it better, it's easy to forget to clean up mocks and we still create new instance of list that nobody will read, it's also duplicated
mocks = new LinkedList<Object>();
- String testName = TestName.getTestName(event);
if (event.getFailure() != null) {
//print unused stubbings only when test succeeds to avoid reporting multiple problems and confusing users
- new ArgMismatchFinder().getStubbingArgMismatches(createdMocks).format(testName, logger);
+ new ArgMismatchFinder().getStubbingArgMismatches(createdMocks).format(event.getTestName(), logger);
}
}
diff --git a/src/main/java/org/mockito/internal/junit/TestFinishedEvent.java b/src/main/java/org/mockito/internal/junit/TestFinishedEvent.java
index 18b099a..43b373a 100644
--- a/src/main/java/org/mockito/internal/junit/TestFinishedEvent.java
+++ b/src/main/java/org/mockito/internal/junit/TestFinishedEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.junit;
@@ -8,8 +8,6 @@ public interface TestFinishedEvent {
Throwable getFailure();
- Object getTestClassInstance();
-
- String getTestMethodName();
+ String getTestName();
}
diff --git a/src/main/java/org/mockito/internal/junit/UniversalTestListener.java b/src/main/java/org/mockito/internal/junit/UniversalTestListener.java
index 8db020b..66c9dee 100644
--- a/src/main/java/org/mockito/internal/junit/UniversalTestListener.java
+++ b/src/main/java/org/mockito/internal/junit/UniversalTestListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.junit;
@@ -60,14 +60,13 @@ public class UniversalTestListener implements MockitoTestListener {
}
private static void emitWarnings(MockitoLogger logger, TestFinishedEvent event, Collection<Object> mocks) {
- String testName = event.getTestClassInstance().getClass().getSimpleName() + "." + event.getTestMethodName();
if (event.getFailure() != null) {
//print stubbing mismatches only when there is a test failure
//to avoid false negatives. Give hint only when test fails.
- new ArgMismatchFinder().getStubbingArgMismatches(mocks).format(testName, logger);
+ new ArgMismatchFinder().getStubbingArgMismatches(mocks).format(event.getTestName(), logger);
} else {
//print unused stubbings only when test succeeds to avoid reporting multiple problems and confusing users
- new UnusedStubbingsFinder().getUnusedStubbings(mocks).format(testName, logger);
+ new UnusedStubbingsFinder().getUnusedStubbings(mocks).format(event.getTestName(), logger);
}
}
diff --git a/src/main/java/org/mockito/internal/junit/util/TestName.java b/src/main/java/org/mockito/internal/junit/util/TestName.java
deleted file mode 100644
index 6f09937..0000000
--- a/src/main/java/org/mockito/internal/junit/util/TestName.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2017 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.junit.util;
-
-import org.mockito.internal.junit.TestFinishedEvent;
-
-/**
- * Provides test name
- */
-public class TestName {
-
- public static String getTestName(TestFinishedEvent event) {
- return event.getTestClassInstance().getClass().getSimpleName() + "." + event.getTestMethodName();
- }
-}
diff --git a/src/main/java/org/mockito/internal/matchers/text/ArrayIterator.java b/src/main/java/org/mockito/internal/matchers/text/ArrayIterator.java
deleted file mode 100644
index 32d3c66..0000000
--- a/src/main/java/org/mockito/internal/matchers/text/ArrayIterator.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2016 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.matchers.text;
-
-import java.lang.reflect.Array;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * Inspired on hamcrest, internal package class,
- * TODO add specific unit tests instead of relying on higher level unit tests
- */
-class ArrayIterator implements Iterator<Object> {
-
- private final Object array;
- private int currentIndex = 0;
-
- public ArrayIterator(Object array) {
- if (array == null) {
- //TODO extract a small utility for null-checking
- throw new IllegalArgumentException("Expected array instance but got null");
- }
- if (!array.getClass().isArray()) {
- throw new IllegalArgumentException("Expected array but got object of type: "
- + array.getClass() + ", the object: " + array.toString());
- }
- this.array = array;
- }
-
- public boolean hasNext() {
- return currentIndex < Array.getLength(array);
- }
-
- public Object next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- return Array.get(array, currentIndex++);
- }
-
- public void remove() {
- throw new UnsupportedOperationException("cannot remove items from an array");
- }
-}
diff --git a/src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java b/src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java
index f741cbc..6f5882f 100644
--- a/src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java
+++ b/src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java
@@ -4,6 +4,7 @@
*/
package org.mockito.internal.matchers.text;
+import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.Map;
@@ -21,7 +22,7 @@ public class ValuePrinter {
* Prints given value so that it is neatly readable by humans.
* Handles explosive toString() implementations.
*/
- public static String print(Object value) {
+ public static String print(final Object value) {
if (value == null) {
return "null";
}
@@ -50,7 +51,21 @@ public class ValuePrinter {
return printMap((Map<?, ?>) value);
}
if (value.getClass().isArray()) {
- return printValues("[", ", ", "]", new ArrayIterator(value));
+ return printValues("[", ", ", "]", new Iterator<Object>() {
+ private int currentIndex = 0;
+
+ public boolean hasNext() {
+ return currentIndex < Array.getLength(value);
+ }
+
+ public Object next() {
+ return Array.get(value, currentIndex++);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("cannot remove items from an array");
+ }
+ });
}
if (value instanceof FormattedText) {
return (((FormattedText) value).getText());
diff --git a/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java b/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java
index a0f8c66..2685ddf 100644
--- a/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java
+++ b/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java
@@ -47,8 +47,8 @@ public class MockingProgressImpl implements MockingProgress {
};
}
- public void reportOngoingStubbing(OngoingStubbing iOngoingStubbing) {
- this.ongoingStubbing = iOngoingStubbing;
+ public void reportOngoingStubbing(OngoingStubbing ongoingStubbing) {
+ this.ongoingStubbing = ongoingStubbing;
}
public OngoingStubbing<?> pullOngoingStubbing() {
@@ -129,7 +129,7 @@ public class MockingProgressImpl implements MockingProgress {
}
public String toString() {
- return "iOngoingStubbing: " + ongoingStubbing +
+ return "ongoingStubbing: " + ongoingStubbing +
", verificationMode: " + verificationMode +
", stubbingInProgress: " + stubbingInProgress;
}
diff --git a/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java b/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java
index 897e613..2f26ff1 100644
--- a/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java
+++ b/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.runners;
@@ -16,6 +16,7 @@ import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.internal.junit.DefaultTestFinishedEvent;
import org.mockito.internal.junit.MockitoTestListener;
import org.mockito.internal.util.Supplier;
diff --git a/src/main/java/org/mockito/internal/runners/DefaultTestFinishedEvent.java b/src/main/java/org/mockito/internal/runners/DefaultTestFinishedEvent.java
deleted file mode 100644
index 2eee23f..0000000
--- a/src/main/java/org/mockito/internal/runners/DefaultTestFinishedEvent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2017 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.runners;
-
-import org.mockito.internal.junit.TestFinishedEvent;
-
-class DefaultTestFinishedEvent implements TestFinishedEvent {
-
- private final Object testClassInstance;
- private final String testMethodName;
- private final Throwable failure;
-
- DefaultTestFinishedEvent(Object testClassInstance, String testMethodName, Throwable failure) {
- this.testClassInstance = testClassInstance;
- this.testMethodName = testMethodName;
- this.failure = failure;
- }
-
- @Override
- public Object getTestClassInstance() {
- return testClassInstance;
- }
-
- @Override
- public String getTestMethodName() {
- return testMethodName;
- }
-
- @Override
- public Throwable getFailure() {
- return failure;
- }
-}
diff --git a/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java b/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java
index bfd6be8..d9b21e5 100644
--- a/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java
+++ b/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.session;
@@ -7,17 +7,44 @@ package org.mockito.internal.session;
import org.mockito.MockitoSession;
import org.mockito.internal.framework.DefaultMockitoSession;
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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.Collections.emptyList;
public class DefaultMockitoSessionBuilder implements MockitoSessionBuilder {
- private Object testClassInstance;
+ private List<Object> testClassInstances = new ArrayList<Object>();
+ private String name;
private Strictness strictness;
+ private MockitoSessionLogger logger;
@Override
public MockitoSessionBuilder initMocks(Object testClassInstance) {
- this.testClassInstance = testClassInstance;
+ if (testClassInstance != null) {
+ this.testClassInstances.add(testClassInstance);
+ }
+ return this;
+ }
+
+ @Override
+ public MockitoSessionBuilder initMocks(Object... testClassInstances) {
+ if (testClassInstances != null) {
+ for (Object instance : testClassInstances) {
+ initMocks(instance);
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public MockitoSessionBuilder name(String name) {
+ this.name = name;
return this;
}
@@ -28,10 +55,26 @@ public class DefaultMockitoSessionBuilder implements MockitoSessionBuilder {
}
@Override
+ public MockitoSessionBuilder logger(MockitoSessionLogger logger) {
+ this.logger = logger;
+ return this;
+ }
+
+ @Override
public MockitoSession startMocking() {
//Configure default values
- Object effectiveTest = this.testClassInstance == null ? new Object() : this.testClassInstance;
+ List<Object> effectiveTestClassInstances;
+ String effectiveName;
+ if (testClassInstances.isEmpty()) {
+ effectiveTestClassInstances = emptyList();
+ effectiveName = this.name == null ? "<Unnamed Session>" : this.name;
+ } else {
+ effectiveTestClassInstances = new ArrayList<Object>(testClassInstances);
+ Object lastTestClassInstance = testClassInstances.get(testClassInstances.size() - 1);
+ effectiveName = this.name == null ? lastTestClassInstance.getClass().getName() : this.name;
+ }
Strictness effectiveStrictness = this.strictness == null ? Strictness.STRICT_STUBS : this.strictness;
- return new DefaultMockitoSession(effectiveTest, effectiveStrictness, new ConsoleMockitoLogger());
+ 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
new file mode 100644
index 0000000..b7329e7
--- /dev/null
+++ b/src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.session;
+
+import org.mockito.internal.util.MockitoLogger;
+import org.mockito.session.MockitoSessionLogger;
+
+class MockitoLoggerAdapter implements MockitoLogger {
+
+ private final MockitoSessionLogger logger;
+
+ MockitoLoggerAdapter(MockitoSessionLogger logger) {
+ this.logger = logger;
+ }
+
+ @Override
+ public void log(Object what) {
+ logger.log(String.valueOf(what));
+ }
+}
diff --git a/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java b/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java
new file mode 100644
index 0000000..2e8634b
--- /dev/null
+++ b/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.session;
+
+import org.mockito.internal.util.MockitoLogger;
+import org.mockito.session.MockitoSessionLogger;
+
+public class MockitoSessionLoggerAdapter implements MockitoSessionLogger {
+
+ private final MockitoLogger logger;
+
+ public MockitoSessionLoggerAdapter(MockitoLogger logger) {
+ this.logger = logger;
+ }
+
+ @Override
+ public void log(String hint) {
+ logger.log(hint);
+ }
+}
diff --git a/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java b/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
index f88fc03..120320b 100644
--- a/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
+++ b/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
@@ -4,11 +4,6 @@
*/
package org.mockito.internal.stubbing;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
import org.mockito.internal.invocation.StubInfoImpl;
import org.mockito.internal.verification.DefaultRegisteredInvocations;
import org.mockito.internal.verification.RegisteredInvocations;
@@ -21,6 +16,11 @@ import org.mockito.stubbing.Answer;
import org.mockito.stubbing.Stubbing;
import org.mockito.stubbing.ValidableAnswer;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
@SuppressWarnings("unchecked")
@@ -93,10 +93,6 @@ public class InvocationContainerImpl implements InvocationContainer, Serializabl
return null;
}
- public void addAnswerForVoidMethod(Answer answer) {
- answersForStubbing.add(answer);
- }
-
public void setAnswersForStubbing(List<Answer<?>> answers) {
answersForStubbing.addAll(answers);
}
diff --git a/src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java b/src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java
index 7296095..25e8be7 100644
--- a/src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java
+++ b/src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java
@@ -5,7 +5,7 @@
package org.mockito.internal.stubbing.answers;
import org.mockito.internal.configuration.plugins.Plugins;
-import org.mockito.internal.creation.instance.Instantiator;
+import org.mockito.creation.instance.Instantiator;
import org.mockito.internal.stubbing.defaultanswers.ReturnsEmptyValues;
import org.mockito.internal.util.reflection.LenientCopyTool;
import org.mockito.invocation.InvocationOnMock;
diff --git a/src/main/java/org/mockito/internal/util/collections/Sets.java b/src/main/java/org/mockito/internal/util/collections/Sets.java
index a5a80f1..f1972e9 100644
--- a/src/main/java/org/mockito/internal/util/collections/Sets.java
+++ b/src/main/java/org/mockito/internal/util/collections/Sets.java
@@ -18,10 +18,6 @@ public abstract class Sets {
return HashCodeAndEqualsSafeSet.of(mocks);
}
- public static IdentitySet newIdentitySet() {
- return new IdentitySet();
- }
-
public static <T> Set<T> newSet(T ... elements) {
if (elements == null) {
throw new IllegalArgumentException("Expected an array of elements (or empty array) but received a null.");
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 c147693..b411a73 100644
--- a/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
+++ b/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
@@ -26,7 +26,7 @@ public class WeakConcurrentMap<K, V> extends ReferenceQueue<K> implements Runnab
private static final AtomicLong ID = new AtomicLong();
- final ConcurrentMap<WeakKey<K>, V> target;
+ public final ConcurrentMap<WeakKey<K>, V> target;
private final Thread thread;
diff --git a/src/main/java/org/mockito/invocation/InvocationFactory.java b/src/main/java/org/mockito/invocation/InvocationFactory.java
index 8339642..1803718 100644
--- a/src/main/java/org/mockito/invocation/InvocationFactory.java
+++ b/src/main/java/org/mockito/invocation/InvocationFactory.java
@@ -8,6 +8,7 @@ import org.mockito.Incubating;
import org.mockito.MockitoFramework;
import org.mockito.mock.MockCreationSettings;
+import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
@@ -19,7 +20,7 @@ import java.util.concurrent.Callable;
* <p>
* Please don't provide your own implementation of {@link Invocation} type.
* Mockito team needs flexibility to add new methods to this interface if we need to.
- * If you integrate Mockito framework and you need an instance of {@link Invocation}, use {@link #createInvocation(Object, MockCreationSettings, Method, Callable, Object...)}.
+ * If you integrate Mockito framework and you need an instance of {@link Invocation}, use {@link #createInvocation(Object, MockCreationSettings, Method, RealMethodBehavior, Object...)}.
*
* @since 2.10.0
*/
@@ -27,6 +28,11 @@ import java.util.concurrent.Callable;
public interface InvocationFactory {
/**
+ * @deprecated Use {@link #createInvocation(Object, MockCreationSettings, Method, RealMethodBehavior, Object...)} instead.
+ *
+ * Why deprecated? We found use cases where we need to handle Throwable and ensure correct stack trace filtering
+ * (removing Mockito internals from the stack trace). Hence the introduction of {@link RealMethodBehavior}.
+ *
* Creates instance of an {@link Invocation} object.
* This method is useful for framework integrators to programmatically simulate method calls on mocks using {@link MockHandler}.
* It enables advanced framework integrations.
@@ -40,6 +46,32 @@ public interface InvocationFactory {
* @return invocation instance
* @since 2.10.0
*/
- @Incubating
+ @Deprecated
Invocation createInvocation(Object target, MockCreationSettings settings, Method method, Callable realMethod, Object... args);
+
+ /**
+ * Behavior of the real method.
+ *
+ * @since 2.14.0
+ */
+ interface RealMethodBehavior<R> extends Serializable {
+ R call() throws Throwable;
+ }
+
+ /**
+ * Creates instance of an {@link Invocation} object.
+ * This method is useful for framework integrators to programmatically simulate method calls on mocks using {@link MockHandler}.
+ * It enables advanced framework integrations.
+ *
+ * @param target the mock object the method is invoked on.
+ * @param settings creation settings of the mock object.
+ * @param method java method invoked on mock.
+ * @param realMethod real method behavior. Needed for spying / invoking real behavior on mock objects.
+ * @param args the java method arguments
+ *
+ * @return invocation instance
+ * @since 2.14.0
+ */
+ @Incubating
+ Invocation createInvocation(Object target, MockCreationSettings settings, Method method, RealMethodBehavior realMethod, Object... args);
}
diff --git a/src/main/java/org/mockito/junit/MockitoJUnitRunner.java b/src/main/java/org/mockito/junit/MockitoJUnitRunner.java
index 2a15587..59bc92b 100644
--- a/src/main/java/org/mockito/junit/MockitoJUnitRunner.java
+++ b/src/main/java/org/mockito/junit/MockitoJUnitRunner.java
@@ -4,7 +4,6 @@
*/
package org.mockito.junit;
-import java.lang.reflect.InvocationTargetException;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.manipulation.Filter;
@@ -16,12 +15,14 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
-import org.mockito.internal.runners.RunnerFactory;
import org.mockito.internal.runners.InternalRunner;
+import org.mockito.internal.runners.RunnerFactory;
import org.mockito.internal.runners.StrictRunner;
import org.mockito.quality.MockitoHint;
import org.mockito.quality.Strictness;
+import java.lang.reflect.InvocationTargetException;
+
/**
* Mockito JUnit Runner keeps tests clean and improves debugging experience.
@@ -80,6 +81,7 @@ public class MockitoJUnitRunner extends Runner implements Filterable {
* stubbing argument mismatches ({@link MockitoJUnitRunner.StrictStubs})
* and *does not detect* unused stubbings.
* The runner remains 'silent' even if incorrect stubbing is present.
+ * It is an equivalent of {@link Strictness#LENIENT}.
* This was the behavior of Mockito JUnit runner in versions 1.x.
* Using this implementation of the runner is not recommended.
* Engineers should care for removing unused stubbings because they are dead code,
diff --git a/src/main/java/org/mockito/plugins/InstantiatorProvider.java b/src/main/java/org/mockito/plugins/InstantiatorProvider.java
index b776f6e..354b87b 100644
--- a/src/main/java/org/mockito/plugins/InstantiatorProvider.java
+++ b/src/main/java/org/mockito/plugins/InstantiatorProvider.java
@@ -8,6 +8,10 @@ import org.mockito.internal.creation.instance.Instantiator;
import org.mockito.mock.MockCreationSettings;
/**
+ * @deprecated since 2.15.4 because this internal class was leaking from the public API.
+ * For more information why deprecated, see {@link org.mockito.plugins.InstantiatorProvider2} and
+ * <a href="https://github.com/mockito/mockito/issues/1303">Issue 1303</a>
+ *
* <p>
* Mockito will invoke this interface in order to fetch an instance instantiator provider.
* </p>
@@ -44,13 +48,24 @@ import org.mockito.mock.MockCreationSettings;
* qualified name in the following file
* <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider</code>.
* </p>
+ * <p>
+ * This class is deprecated and was replaced by
+ * {@link org.mockito.plugins.InstantiatorProvider2}. Hence if there is both a
+ * <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider</code> and
+ * <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider2</code> the second one
+ * takes preference.
+ * </p>
*
- * @since 21.10.15
+ * @since 2.0.31
*/
+@Deprecated
public interface InstantiatorProvider {
/**
+ * @deprecated, see {@link InstantiatorProvider}.
+ *
* Returns an instantiator, used to create new class instances.
*/
+ @Deprecated
Instantiator getInstantiator(MockCreationSettings<?> settings);
}
diff --git a/src/main/java/org/mockito/plugins/InstantiatorProvider2.java b/src/main/java/org/mockito/plugins/InstantiatorProvider2.java
new file mode 100644
index 0000000..3bc1f32
--- /dev/null
+++ b/src/main/java/org/mockito/plugins/InstantiatorProvider2.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.plugins;
+
+import org.mockito.creation.instance.Instantiator;
+import org.mockito.mock.MockCreationSettings;
+
+/**
+ * <p>
+ * Mockito will invoke this interface in order to fetch an instance instantiator provider.
+ * </p>
+ *
+ * <p>
+ * By default, an internal byte-buddy/asm/objenesis based implementation is used.
+ * </p>
+ *
+ * <h3>Using the extension point</h3>
+ *
+ * <p>
+ * The plugin mechanism of mockito works in a similar way as the
+ * {@link java.util.ServiceLoader}, however instead of looking in the <code>META-INF</code>
+ * directory, Mockito will look in <code>mockito-extensions</code> directory.
+ * <em>The reason for that is that Android SDK strips jar from the <code>META-INF</code>
+ * directory when creating an APK.</em>
+ * </p>
+ *
+ * <ol style="list-style-type: lower-alpha">
+ * <li>The implementation itself, for example
+ * <code>org.awesome.mockito.AwesomeInstantiatorProvider2</code> that implements the
+ * <code>InstantiatorProvider2</code>.</li>
+ * <li>A file "<code>mockito-extensions/org.mockito.plugins.InstantiatorProvider2</code>".
+ * The content of this file is exactly a <strong>one</strong> line with the qualified
+ * name: <code>org.awesome.mockito.AwesomeInstantiatorProvider</code>.</li>
+ * </ol></p>
+ *
+ * <p>
+ * Note that if several <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider2</code>
+ * files exists in the classpath, Mockito will only use the first returned by the standard
+ * {@link ClassLoader#getResource} mechanism.
+ * <p>
+ * So just create a custom implementation of {@link InstantiatorProvider2} and place the
+ * qualified name in the following file
+ * <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider2</code>.
+ * </p>
+ *
+ * @since 2.15.4
+ */
+public interface InstantiatorProvider2 {
+
+ /**
+ * Returns an instantiator, used to create new class instances.
+ *
+ * @since 2.15.4
+ */
+ Instantiator getInstantiator(MockCreationSettings<?> settings);
+}
diff --git a/src/main/java/org/mockito/quality/Strictness.java b/src/main/java/org/mockito/quality/Strictness.java
index 4e1126a..c9da8d3 100644
--- a/src/main/java/org/mockito/quality/Strictness.java
+++ b/src/main/java/org/mockito/quality/Strictness.java
@@ -80,7 +80,8 @@ public enum Strictness {
* <li>Cleaner, more DRY tests ("Don't Repeat Yourself"):
* If you use {@link org.mockito.Mockito#verifyNoMoreInteractions(Object...)}
* you no longer need to explicitly verify stubbed invocations.
- * They are automatically verified for you.</li>
+ * They are automatically verified for you. However if you have more invocations,
+ * the test won't fail since it won't check that there are no more interactions on that stub.</li>
* </ul>
*
* For more information see {@link Strictness}.
diff --git a/src/main/java/org/mockito/session/MockitoSessionBuilder.java b/src/main/java/org/mockito/session/MockitoSessionBuilder.java
index b13062b..474b7f9 100644
--- a/src/main/java/org/mockito/session/MockitoSessionBuilder.java
+++ b/src/main/java/org/mockito/session/MockitoSessionBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.session;
@@ -20,7 +20,7 @@ import org.mockito.quality.Strictness;
public interface MockitoSessionBuilder {
/**
- * Configures the test class instance for initialization of fields annotated with Mockito annotations
+ * Adds the test class instance for initialization of fields annotated with Mockito annotations
* like {@link org.mockito.Mock}.
* When this method is invoked it <strong>does not perform</strong> initialization of mocks on the spot!
* Only when {@link #startMocking()} is invoked then annotated fields will be initialized.
@@ -30,11 +30,12 @@ public interface MockitoSessionBuilder {
* Migrate from {@link MockitoAnnotations#initMocks(Object)}
* to {@link MockitoSession}!
* <p>
+ * This method may be called multiple times to add multiple, e.g. nested, test class instances.
+ * <p>
* See code sample in {@link MockitoSession}.
*
* @param testClassInstance test class instance that contains fields with Mockito annotations to be initialized.
- * Passing {@code null} is permitted and will make the session use a default value.
- * The current default is '{@code new Object()}'.
+ * Passing {@code null} is permitted but will be ignored.
* @return the same builder instance for fluent configuration of {@code MockitoSession}.
* @since 2.7.0
*/
@@ -42,6 +43,46 @@ public interface MockitoSessionBuilder {
MockitoSessionBuilder initMocks(Object testClassInstance);
/**
+ * Adds the test class instances for initialization of fields annotated with Mockito annotations
+ * 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.
+ * <p>
+ * This method calls {@link #initMocks(Object)} for each passed test class instance.
+ *
+ * @param testClassInstances test class instances that contains fields with Mockito annotations to be initialized.
+ * Passing {@code null} or an empty array is permitted but will be ignored.
+ * @return the same builder instance for fluent configuration of {@code MockitoSession}.
+ * @see #initMocks(Object)
+ * @since 2.15.0
+ */
+ @Incubating
+ MockitoSessionBuilder initMocks(Object... testClassInstances);
+
+ /**
+ * Configures the name of the {@code MockitoSession} instance.
+ * <p>
+ * The name is used to output {@linkplain org.mockito.quality.MockitoHint hints} when
+ * {@linkplain MockitoSession#finishMocking() finishing} a session.
+ * <p>
+ * This method is intended to be used by framework integrations, e.g. JUnit. When building
+ * a {@code MockitoSession} for direct use, users are not expected to call it.
+ *
+ * @param name of {@code MockitoSession} instance.
+ * Passing {@code null} is permitted and will make the session use a default value.
+ * The current default is the name of the last test class instance passed to
+ * {@link #initMocks(Object)} or {@link #initMocks(Object...)}, if available;
+ * otherwise, {@code "<Unnamed Session>"} is used.
+ *
+ * @return the same builder instance for fluent configuration of {@code MockitoSession}.
+ * @see org.mockito.quality.MockitoHint
+ * @since 2.15.0
+ */
+ @Incubating
+ MockitoSessionBuilder name(String name);
+
+ /**
* Configures strictness of {@code MockitoSession} instance.
* See examples in {@link MockitoSession}.
*
@@ -56,6 +97,25 @@ public interface MockitoSessionBuilder {
MockitoSessionBuilder strictness(Strictness strictness);
/**
+ * Configures logger used by {@code MockitoSession} for emitting
+ * {@linkplain org.mockito.quality.MockitoHint warnings} when finishing the session.
+ * <p>
+ * Please note that the use of {@linkplain Strictness#STRICT_STUBS strict stubs} is
+ * recommended over emitting warnings because warnings are easily ignored and spoil the log output.
+ * Instead of using this method, please consider setting strictness with {@link #strictness(Strictness)}.
+ *
+ * @param logger for warnings emitted when finishing {@code MockitoSession}.
+ * Passing {@code null} is permitted and will make the session use a default value.
+ * By default, warnings will be logged to the console.
+ *
+ * @return the same builder instance for fluent configuration of {@code MockitoSession}.
+ * @see org.mockito.quality.MockitoHint
+ * @since 2.15.0
+ */
+ @Incubating
+ MockitoSessionBuilder logger(MockitoSessionLogger logger);
+
+ /**
* Starts new mocking session! Creates new {@code MockitoSession} instance to initialize the session.
* At this point annotated fields are initialized per {@link #initMocks(Object)} method.
* When you are done with the session it is required to invoke {@link MockitoSession#finishMocking()}.
diff --git a/src/main/java/org/mockito/session/MockitoSessionLogger.java b/src/main/java/org/mockito/session/MockitoSessionLogger.java
new file mode 100644
index 0000000..e5f40ad
--- /dev/null
+++ b/src/main/java/org/mockito/session/MockitoSessionLogger.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.session;
+
+import org.mockito.Incubating;
+import org.mockito.MockitoSession;
+
+/**
+ * Logger for {@linkplain org.mockito.quality.MockitoHint hints} emitted when
+ * finishing mocking for a {@link MockitoSession}.
+ * <p>
+ * This class is intended to be used by framework integrations, e.g. JUnit. When using
+ * {@link MockitoSession} directly, you'll probably not need it.
+ *
+ * @since 2.15.0
+ */
+@Incubating
+public interface MockitoSessionLogger {
+
+ /**
+ * Logs the hint.
+ *
+ * @param hint to log; never {@code null}
+ */
+ @Incubating
+ void log(String hint);
+
+}
diff --git a/src/main/java/org/mockito/stubbing/OngoingStubbing.java b/src/main/java/org/mockito/stubbing/OngoingStubbing.java
index bc768d2..e2d298b 100644
--- a/src/main/java/org/mockito/stubbing/OngoingStubbing.java
+++ b/src/main/java/org/mockito/stubbing/OngoingStubbing.java
@@ -43,7 +43,7 @@ public interface OngoingStubbing<T> {
*
* @param value return value
*
- * @return iOngoingStubbing object that allows stubbing consecutive calls
+ * @return object that allows stubbing consecutive calls
*/
OngoingStubbing<T> thenReturn(T value);
@@ -60,7 +60,7 @@ public interface OngoingStubbing<T> {
* @param value first return value
* @param values next return values
*
- * @return iOngoingStubbing object that allows stubbing consecutive calls
+ * @return object that allows stubbing consecutive calls
*/
// Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation warnings (on call site)
@SuppressWarnings ({"unchecked", "varargs"})
@@ -84,7 +84,7 @@ public interface OngoingStubbing<T> {
*
* @param throwables to be thrown on method invocation
*
- * @return iOngoingStubbing object that allows stubbing consecutive calls
+ * @return object that allows stubbing consecutive calls
*/
OngoingStubbing<T> thenThrow(Throwable... throwables);
@@ -108,7 +108,7 @@ public interface OngoingStubbing<T> {
*
* @param throwableType to be thrown on method invocation
*
- * @return iOngoingStubbing object that allows stubbing consecutive calls
+ * @return object that allows stubbing consecutive calls
* @since 2.1.0
*/
OngoingStubbing<T> thenThrow(Class<? extends Throwable> throwableType);
@@ -141,7 +141,7 @@ public interface OngoingStubbing<T> {
* @param toBeThrown to be thrown on method invocation
* @param nextToBeThrown next to be thrown on method invocation
*
- * @return iOngoingStubbing object that allows stubbing consecutive calls
+ * @return object that allows stubbing consecutive calls
* @since 2.1.0
*/
// Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation warnings (on call site)
@@ -175,7 +175,7 @@ public interface OngoingStubbing<T> {
* <p>
* See examples in javadoc for {@link Mockito#when}
*
- * @return iOngoingStubbing object that allows stubbing consecutive calls
+ * @return object that allows stubbing consecutive calls
*/
OngoingStubbing<T> thenCallRealMethod();
@@ -191,7 +191,7 @@ public interface OngoingStubbing<T> {
*
* @param answer the custom answer to execute.
*
- * @return iOngoingStubbing object that allows stubbing consecutive calls
+ * @return object that allows stubbing consecutive calls
*/
OngoingStubbing<T> thenAnswer(Answer<?> answer);
@@ -209,7 +209,7 @@ public interface OngoingStubbing<T> {
* </code></pre>
*
* @param answer the custom answer to execute.
- * @return iOngoingStubbing object that allows stubbing consecutive calls
+ * @return object that allows stubbing consecutive calls
*
* @see #thenAnswer(Answer)
* @since 1.9.0
diff --git a/src/test/java/org/mockito/InvocationFactoryTest.java b/src/test/java/org/mockito/InvocationFactoryTest.java
new file mode 100644
index 0000000..893f95f
--- /dev/null
+++ b/src/test/java/org/mockito/InvocationFactoryTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito;
+
+import org.junit.Test;
+import org.mockito.invocation.Invocation;
+import org.mockito.invocation.InvocationFactory;
+import org.mockitoutil.TestBase;
+
+import java.util.concurrent.Callable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.withSettings;
+
+public class InvocationFactoryTest extends TestBase {
+ static class TestClass {
+ public String testMethod() throws Throwable {
+ return "un-mocked";
+ }
+ }
+
+ final TestClass mock = spy(TestClass.class);
+
+ @Test
+ public void call_method_that_throws_a_throwable() throws Throwable {
+ Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock,
+ withSettings().build(TestClass.class),
+ TestClass.class.getDeclaredMethod("testMethod"),
+ new InvocationFactory.RealMethodBehavior() {
+ @Override
+ public Object call() throws Throwable {
+ throw new Throwable("mocked");
+ }
+ });
+
+ try {
+ Mockito.mockingDetails(mock).getMockHandler().handle(invocation);
+ } catch (Throwable t) {
+ assertEquals("mocked", t.getMessage());
+ return;
+ }
+
+ fail();
+ }
+
+ @Test
+ public void call_method_that_returns_a_string() throws Throwable {
+ Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock,
+ withSettings().build(TestClass.class),
+ TestClass.class.getDeclaredMethod("testMethod"),
+ new InvocationFactory.RealMethodBehavior() {
+ @Override
+ public Object call() throws Throwable {
+ return "mocked";
+ }
+ });
+
+ Object ret = Mockito.mockingDetails(mock).getMockHandler().handle(invocation);
+ assertEquals("mocked", ret);
+ }
+
+ @Test
+ public void deprecated_api_still_works() throws Throwable {
+ Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock,
+ withSettings().build(TestClass.class),
+ TestClass.class.getDeclaredMethod("testMethod"),
+ new Callable() {
+ public Object call() throws Exception {
+ return "mocked";
+ }
+ });
+
+ Object ret = Mockito.mockingDetails(mock).getMockHandler().handle(invocation);
+ assertEquals("mocked", ret);
+ }
+}
diff --git a/src/test/java/org/mockito/StaticMockingExperimentTest.java b/src/test/java/org/mockito/StaticMockingExperimentTest.java
index a74d5eb..bb5e225 100644
--- a/src/test/java/org/mockito/StaticMockingExperimentTest.java
+++ b/src/test/java/org/mockito/StaticMockingExperimentTest.java
@@ -10,12 +10,12 @@ import org.mockito.exceptions.verification.NoInteractionsWanted;
import org.mockito.exceptions.verification.WantedButNotInvoked;
import org.mockito.exceptions.verification.junit.ArgumentsAreDifferent;
import org.mockito.invocation.Invocation;
+import org.mockito.invocation.InvocationFactory;
import org.mockito.invocation.MockHandler;
import org.mockitoutil.TestBase;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
-import java.util.concurrent.Callable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
@@ -43,9 +43,9 @@ public class StaticMockingExperimentTest extends TestBase {
Foo mock = Mockito.mock(Foo.class);
MockHandler handler = Mockito.mockingDetails(mock).getMockHandler();
Method staticMethod;
- Callable realMethod = new Callable() {
+ InvocationFactory.RealMethodBehavior realMethod = new InvocationFactory.RealMethodBehavior() {
@Override
- public Object call() throws Exception {
+ public Object call() throws Throwable {
return null;
}
};
diff --git a/src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java b/src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java
index 41fe3cc..5935eae 100644
--- a/src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java
+++ b/src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java
@@ -7,6 +7,8 @@ package org.mockito.internal.configuration.plugins;
import org.junit.Test;
import org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker;
import org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker;
+import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
import org.mockito.plugins.MockMaker;
import org.mockitoutil.TestBase;
@@ -23,5 +25,7 @@ public class DefaultMockitoPluginsTest extends TestBase {
plugins.getDefaultPluginClass(INLINE_ALIAS));
assertEquals(InlineByteBuddyMockMaker.class, plugins.getInlineMockMaker().getClass());
assertEquals(ByteBuddyMockMaker.class, plugins.getDefaultPlugin(MockMaker.class).getClass());
+ assertNotNull(plugins.getDefaultPlugin(InstantiatorProvider.class));
+ assertNotNull(plugins.getDefaultPlugin(InstantiatorProvider2.class));
}
}
diff --git a/src/test/java/org/mockito/internal/configuration/plugins/PluginLoaderTest.java b/src/test/java/org/mockito/internal/configuration/plugins/PluginLoaderTest.java
new file mode 100644
index 0000000..ab01858
--- /dev/null
+++ b/src/test/java/org/mockito/internal/configuration/plugins/PluginLoaderTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.configuration.plugins;
+
+import org.assertj.core.api.Assertions;
+import org.assertj.core.api.ThrowableAssert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.BDDMockito.willReturn;
+import static org.mockito.Mockito.when;
+
+public class PluginLoaderTest {
+
+ @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+
+ @Mock PluginInitializer initializer;
+ @Mock DefaultMockitoPlugins plugins;
+ @InjectMocks PluginLoader loader;
+
+ @Test
+ public void loads_plugin() {
+ when(initializer.loadImpl(FooPlugin.class)).thenReturn(new FooPlugin());
+
+ //when
+ FooPlugin plugin = loader.loadPlugin(FooPlugin.class);
+
+ //then
+ assertNotNull(plugin);
+ }
+
+ @Test
+ public void loads_alternative_plugin() {
+ willReturn(null).given(initializer).loadImpl(FooPlugin.class);
+ BarPlugin expected = new BarPlugin();
+ willReturn(expected).given(initializer).loadImpl(BarPlugin.class);
+
+ //when
+ Object plugin = loader.loadPlugin(FooPlugin.class, BarPlugin.class);
+
+ //then
+ assertSame(plugin, expected);
+ }
+
+ @Test
+ public void loads_default_plugin() {
+ willReturn(null).given(initializer).loadImpl(FooPlugin.class);
+ willReturn(null).given(initializer).loadImpl(BarPlugin.class);
+ FooPlugin expected = new FooPlugin();
+ willReturn(expected).given(plugins).getDefaultPlugin(FooPlugin.class);
+
+ //when
+ Object plugin = loader.loadPlugin(FooPlugin.class, BarPlugin.class);
+
+ //then
+ assertSame(plugin, expected);
+ }
+
+ @Test
+ public void fails_to_load_plugin() {
+ RuntimeException cause = new RuntimeException("Boo!");
+ when(initializer.loadImpl(Foo.class)).thenThrow(cause);
+
+ //when
+ final Foo plugin = loader.loadPlugin(Foo.class);
+
+ //then
+ Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+ @Override
+ public void call() throws Throwable {
+ plugin.toString(); //call any method on the plugin
+ }
+ }).isInstanceOf(IllegalStateException.class)
+ .hasMessage("Could not initialize plugin: interface org.mockito.internal.configuration.plugins.PluginLoaderTest$Foo (alternate: null)")
+ .hasCause(cause);
+ }
+
+ static class FooPlugin {}
+ static class BarPlugin {}
+ static interface Foo {}
+}
diff --git a/src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java b/src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java
index 50030df..320287c 100644
--- a/src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java
+++ b/src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java
@@ -65,7 +65,7 @@ public class ConstructorInstantiatorTest extends TestBase {
assertEquals(new ConstructorInstantiator(false, 123).newInstance(SomeClass3.class).getClass(), SomeClass3.class);
}
- @Test(expected = InstantiationException.class)
+ @Test(expected = org.mockito.creation.instance.InstantiationException.class)
public void fails_when_null_is_passed_for_a_primitive() {
assertEquals(new ConstructorInstantiator(false, new Object[]{null}).newInstance(SomeClass3.class).getClass(), SomeClass3.class);
}
@@ -75,7 +75,7 @@ public class ConstructorInstantiatorTest extends TestBase {
try {
new ConstructorInstantiator(false, new Object[0]).newInstance(SomeClass2.class);
fail();
- } catch (InstantiationException e) {
+ } catch (org.mockito.creation.instance.InstantiationException e) {
assertThat(e).hasMessageContaining("Unable to create instance of 'SomeClass2'.\n" +
"Please ensure that the target class has a 0-arg constructor.");
}
diff --git a/src/test/java/org/mockito/internal/invocation/InvocationBuilder.java b/src/test/java/org/mockito/internal/invocation/InvocationBuilder.java
index 696d34a..b3106a6 100644
--- a/src/test/java/org/mockito/internal/invocation/InvocationBuilder.java
+++ b/src/test/java/org/mockito/internal/invocation/InvocationBuilder.java
@@ -6,7 +6,7 @@
package org.mockito.internal.invocation;
import org.mockito.Mockito;
-import org.mockito.internal.creation.bytebuddy.InterceptedInvocation;
+import org.mockito.internal.invocation.mockref.MockStrongReference;
import org.mockito.internal.debugging.LocationImpl;
import org.mockito.invocation.Invocation;
import org.mockito.invocation.Location;
@@ -17,7 +17,7 @@ import java.util.LinkedList;
import java.util.List;
import static java.util.Arrays.asList;
-import static org.mockito.internal.creation.bytebuddy.InterceptedInvocation.NO_OP;
+import static org.mockito.internal.invocation.InterceptedInvocation.NO_OP;
/**
* Build an invocation.
@@ -61,7 +61,7 @@ public class InvocationBuilder {
}
}
- Invocation i = new InterceptedInvocation(mock,
+ Invocation i = new InterceptedInvocation(new MockStrongReference<Object>(mock, false),
new SerializableMethod(method),
args,
NO_OP,
diff --git a/src/test/java/org/mockito/internal/invocation/mockref/MockWeakReferenceTest.java b/src/test/java/org/mockito/internal/invocation/mockref/MockWeakReferenceTest.java
new file mode 100644
index 0000000..1e3d8e9
--- /dev/null
+++ b/src/test/java/org/mockito/internal/invocation/mockref/MockWeakReferenceTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.invocation.mockref;
+
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.mockito.internal.invocation.mockref.MockWeakReference;
+import org.mockitoutil.TestBase;
+
+import static org.junit.Assert.fail;
+
+public class MockWeakReferenceTest extends TestBase {
+
+ @Test
+ public void descriptive_exception_when_mock_was_collected() {
+ try {
+ //when
+ new MockWeakReference(null).get();
+ //then
+ fail();
+ } catch (Exception e) {
+ Assertions.assertThat(e).hasMessageContaining("The mock object was garbage collected");
+ }
+ }
+}
diff --git a/src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java b/src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java
index f519186..855afb0 100644
--- a/src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java
+++ b/src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java
@@ -1,29 +1,42 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.session;
import org.junit.After;
import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
import org.mockito.StateMaster;
import org.mockito.exceptions.misusing.UnfinishedMockingSessionException;
import org.mockito.quality.Strictness;
+import org.mockito.session.MockitoSessionLogger;
import org.mockitoutil.ThrowableAssert;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.when;
+import static org.mockito.quality.Strictness.WARN;
+
public class DefaultMockitoSessionBuilderTest {
@After public void after() {
new StateMaster().clearMockitoListeners();
}
- @Test public void creates_sessions() throws Exception {
+ @Test public void creates_sessions() {
//no configuration is legal
new DefaultMockitoSessionBuilder().startMocking().finishMocking();
//passing null to configuration is legal, default value will be used
- new DefaultMockitoSessionBuilder().initMocks(null).startMocking().finishMocking();
- new DefaultMockitoSessionBuilder().initMocks(null).strictness(null).startMocking().finishMocking();
+ new DefaultMockitoSessionBuilder().initMocks((Object) null).startMocking().finishMocking();
+ new DefaultMockitoSessionBuilder().initMocks((Object[]) null).startMocking().finishMocking();
+ new DefaultMockitoSessionBuilder().initMocks(null, null).strictness(null).startMocking().finishMocking();
new DefaultMockitoSessionBuilder().strictness(null).startMocking().finishMocking();
//happy path
@@ -32,7 +45,49 @@ public class DefaultMockitoSessionBuilderTest {
new DefaultMockitoSessionBuilder().strictness(Strictness.LENIENT).startMocking().finishMocking();
}
- @Test public void requires_finish_mocking() throws Exception {
+ @Test public void creates_sessions_for_multiple_test_class_instances_for_repeated_calls() {
+ TestClass testClass = new TestClass();
+ TestClass.NestedTestClass nestedTestClass = testClass.new NestedTestClass();
+
+ new DefaultMockitoSessionBuilder().initMocks(testClass).initMocks(nestedTestClass).startMocking().finishMocking();
+
+ assertNotNull(testClass.set);
+ assertNotNull(nestedTestClass.list);
+ }
+
+ @Test public void creates_sessions_for_multiple_test_class_instances_for_varargs_call() {
+ TestClass testClass = new TestClass();
+ TestClass.NestedTestClass nestedTestClass = testClass.new NestedTestClass();
+
+ new DefaultMockitoSessionBuilder().initMocks(testClass, nestedTestClass).startMocking().finishMocking();
+
+ assertNotNull(testClass.set);
+ assertNotNull(nestedTestClass.list);
+ }
+
+ @Test public void uses_logger_and_strictness() {
+ TestClass testClass = new TestClass();
+
+ final List<String> hints = new ArrayList<String>();
+ MockitoSession session = new DefaultMockitoSessionBuilder()
+ .initMocks(testClass)
+ .strictness(WARN)
+ .logger(new MockitoSessionLogger() {
+ @Override
+ public void log(String hint) {
+ hints.add(hint);
+ }
+ })
+ .startMocking();
+
+ when(testClass.set.add(1)).thenReturn(true);
+
+ session.finishMocking();
+
+ assertFalse(hints.isEmpty());
+ }
+
+ @Test public void requires_finish_mocking() {
new DefaultMockitoSessionBuilder().startMocking();
ThrowableAssert.assertThat(new Runnable() {
@@ -41,4 +96,13 @@ public class DefaultMockitoSessionBuilderTest {
}
}).throwsException(UnfinishedMockingSessionException.class);
}
+
+ class TestClass {
+
+ @Mock public Set<Object> set;
+
+ class NestedTestClass {
+ @Mock public List<Object> list;
+ }
+ }
}
diff --git a/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java b/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
index 0e77824..de5eb13 100644
--- a/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
@@ -5,8 +5,6 @@
package org.mockito.internal.stubbing;
-import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.exceptions.base.MockitoException;
@@ -21,6 +19,7 @@ import org.mockitoutil.TestBase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
public class InvocationContainerImplStubbingTest extends TestBase {
@@ -96,27 +95,6 @@ public class InvocationContainerImplStubbingTest extends TestBase {
}
@Test
- public void should_add_throwable_for_void_method() throws Throwable {
- invocationContainerImpl.addAnswerForVoidMethod(new ThrowsException(new MyException()));
- invocationContainerImpl.setMethodForStubbing(new InvocationMatcher(simpleMethod));
-
- try {
- invocationContainerImpl.answerTo(simpleMethod);
- fail();
- } catch (MyException e) {}
- }
-
- @Test
- public void should_validate_throwable_for_void_method() throws Throwable {
- invocationContainerImpl.addAnswerForVoidMethod(new ThrowsException(new Exception()));
-
- try {
- invocationContainerImpl.setMethodForStubbing(new InvocationMatcher(simpleMethod));
- fail();
- } catch (MockitoException e) {}
- }
-
- @Test
public void should_validate_throwable() throws Throwable {
try {
invocationContainerImpl.addAnswer(new ThrowsException(null));
diff --git a/src/test/java/org/mockitousage/bugs/MockitoStubbedCallInAnswerTest.java b/src/test/java/org/mockitousage/bugs/MockitoStubbedCallInAnswerTest.java
new file mode 100644
index 0000000..d9720f9
--- /dev/null
+++ b/src/test/java/org/mockitousage/bugs/MockitoStubbedCallInAnswerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitousage.bugs;
+
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.mockitoutil.TestBase;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+/**
+ * @see <a href="https://github.com/mockito/mockito/issues/1279">Issue #1279</a>
+ */
+public class MockitoStubbedCallInAnswerTest extends TestBase {
+
+ @Mock Foo foo;
+ @Mock Bar bar;
+
+ @Test
+ public void stubbing_the_right_mock() throws Exception {
+ //stubbing on different mock should not be altered
+ when(bar.doInt()).thenReturn(0);
+ when(foo.doInt()).thenAnswer(new Answer<Integer>() {
+ @Override
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ return bar.doInt();
+ }
+ });
+ assertEquals(0, foo.doInt());
+ assertEquals(0, bar.doInt());
+
+ //when we override the stubbing
+ when(foo.doInt()).thenReturn(1);
+
+ //we expect it to be reflected:
+ assertEquals(1, foo.doInt());
+
+ //but the stubbing on a different mock should not be altered:
+ assertEquals(0, bar.doInt());
+ }
+
+ @Test
+ public void return_type_validation() throws Exception {
+ when(foo.doString()).thenAnswer(new Answer<String>() {
+ public String answer(InvocationOnMock invocation) throws Throwable {
+ //invoking a method on a different mock, with different return type
+ return String.valueOf(bar.doInt());
+ }
+ });
+ assertEquals("0", foo.doString());
+
+ //we can override stubbing without misleading return type validation errors:
+ when(foo.doString()).thenReturn("");
+ assertEquals("", foo.doString());
+ }
+
+ @Test
+ public void prevents_stack_overflow() throws Exception {
+ when(foo.doInt()).thenAnswer(new Answer<Integer>() {
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ return bar.doInt();
+ }
+ });
+ assertEquals(0, foo.doInt());
+
+ when(foo.doInt()).thenAnswer(new Answer<Integer>() {
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ return bar.doInt() + 1;
+ }
+ });
+
+ //calling below used to cause SO error
+ assertEquals(1, foo.doInt());
+ }
+
+ @Test
+ public void overriding_stubbing() throws Exception {
+ when(bar.doInt()).thenReturn(10);
+ when(foo.doInt()).thenAnswer(new Answer<Integer>() {
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ return bar.doInt() + 1;
+ }
+ });
+
+ assertEquals(11, foo.doInt());
+
+ //when we override the stubbing with a different one
+ when(foo.doInt()).thenReturn(100);
+
+ //we expect it to be reflected:
+ assertEquals(100, foo.doInt());
+ }
+
+ interface Foo {
+ String doString();
+ int doInt();
+ }
+
+ interface Bar {
+ int doInt();
+ }
+}
diff --git a/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java b/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
index 59e5999..f4e3e95 100644
--- a/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
+++ b/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
@@ -8,18 +8,20 @@ import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
-import org.mockito.quality.Strictness;
import org.mockito.exceptions.misusing.PotentialStubbingProblem;
import org.mockito.exceptions.misusing.UnfinishedVerificationException;
import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
import org.mockito.junit.MockitoJUnit;
+import org.mockito.quality.Strictness;
import org.mockitousage.IMethods;
import org.mockitoutil.SafeJUnitRule;
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willReturn;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
import static org.mockitoutil.TestBase.filterLineNo;
public class StrictJUnitRuleTest {
@@ -97,7 +99,7 @@ public class StrictJUnitRuleTest {
" - stubbing the same method multiple times using 'given().will()' or 'when().then()' API\n" +
" Please use 'will().given()' or 'doReturn().when()' API for stubbing.\n" +
" - stubbed method is intentionally invoked with different arguments by code under test\n" +
- " Please use 'default' or 'silent' JUnit Rule.\n" +
+ " Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).\n" +
"For more information see javadoc for PotentialStubbingProblem class."),
filterLineNo(t.getMessage()));
}
@@ -140,7 +142,7 @@ public class StrictJUnitRuleTest {
"Following stubbings are unnecessary (click to navigate to relevant line of code):\n" +
" 1. -> at org.mockitousage.junitrule.StrictJUnitRuleTest.unused_stubs_with_multiple_mocks(StrictJUnitRuleTest.java:0)\n" +
" 2. -> at org.mockitousage.junitrule.StrictJUnitRuleTest.unused_stubs_with_multiple_mocks(StrictJUnitRuleTest.java:0)\n" +
- "Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class."), filterLineNo(t.getMessage()));
+ "Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class."), filterLineNo(t.getMessage()));
}
});
diff --git a/src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java b/src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java
index 0d8cead..6b6017a 100644
--- a/src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java
+++ b/src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java
@@ -53,7 +53,7 @@ public class UnusedStubsExceptionMessageTest extends TestBase {
"Following stubbings are unnecessary (click to navigate to relevant line of code):\n" +
" 1. -> at org.mockitousage.junitrunner.UnusedStubsExceptionMessageTest$HasUnnecessaryStubs.<init>(UnusedStubsExceptionMessageTest.java:0)\n" +
" 2. -> at org.mockitousage.junitrunner.UnusedStubsExceptionMessageTest$HasUnnecessaryStubs.<init>(UnusedStubsExceptionMessageTest.java:0)\n" +
- "Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.",
- filterLineNo(failure.getException().getMessage()));
+ "Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.",
+ filterLineNo(failure.getException().getMessage()));
}
}
diff --git a/src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java b/src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java
index 0d164c6..a1a3500 100644
--- a/src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java
+++ b/src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java
@@ -6,8 +6,10 @@ package org.mockitousage.plugins;
import org.junit.Test;
import org.mockito.Mockito;
+import org.mockito.internal.creation.instance.Instantiator;
import org.mockito.plugins.AnnotationEngine;
import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
import org.mockito.plugins.MockMaker;
import org.mockito.plugins.MockitoPlugins;
import org.mockito.plugins.PluginSwitch;
@@ -15,17 +17,29 @@ import org.mockito.plugins.StackTraceCleanerProvider;
import org.mockitoutil.TestBase;
import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.withSettings;
public class MockitoPluginsTest extends TestBase {
private final MockitoPlugins plugins = Mockito.framework().getPlugins();
- @Test public void provides_built_in_plugins() {
+ @Test
+ public void provides_built_in_plugins() {
assertNotNull(plugins.getInlineMockMaker());
assertNotNull(plugins.getDefaultPlugin(MockMaker.class));
assertNotNull(plugins.getDefaultPlugin(StackTraceCleanerProvider.class));
assertNotNull(plugins.getDefaultPlugin(PluginSwitch.class));
assertNotNull(plugins.getDefaultPlugin(InstantiatorProvider.class));
+ assertNotNull(plugins.getDefaultPlugin(InstantiatorProvider2.class));
assertNotNull(plugins.getDefaultPlugin(AnnotationEngine.class));
}
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void instantiator_provider_backwards_compatibility() {
+ InstantiatorProvider provider = plugins.getDefaultPlugin(InstantiatorProvider.class);
+ Instantiator instantiator = provider.getInstantiator(withSettings().build(MockitoPluginsTest.class));
+
+ assertNotNull(instantiator.newInstance(MockitoPluginsTest.class));
+ }
}
diff --git a/src/test/java/org/mockitousage/session/MockitoSessionTest.java b/src/test/java/org/mockitousage/session/MockitoSessionTest.java
index e992f83..960d888 100644
--- a/src/test/java/org/mockitousage/session/MockitoSessionTest.java
+++ b/src/test/java/org/mockitousage/session/MockitoSessionTest.java
@@ -15,13 +15,17 @@ import org.mockito.exceptions.misusing.UnfinishedStubbingException;
import org.mockito.quality.Strictness;
import org.mockitousage.IMethods;
import org.mockitoutil.JUnitResultAssert;
+import org.mockitoutil.TestBase;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mockingDetails;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-public class MockitoSessionTest {
+public class MockitoSessionTest extends TestBase {
private JUnitCore junit = new JUnitCore();
@@ -66,6 +70,33 @@ public class MockitoSessionTest {
.failsExactly(AssertionError.class, UnfinishedStubbingException.class);
}
+ @Test public void allows_initializing_mocks_manually() {
+ //when
+ Result result = junit.run(MockitoSessionTest.SessionWithManuallyInitializedMock.class);
+
+ //expect
+ JUnitResultAssert.assertThat(result).succeeds(1);
+ }
+
+ @Test public void allows_updating_strictness() {
+ //when
+ Result result = junit.run(MockitoSessionTest.SessionWithUpdatedStrictness.class);
+
+ //expect
+ JUnitResultAssert.assertThat(result).succeeds(1);
+ }
+
+ @Test public void allows_overriding_failure() {
+ //when
+ Result result = junit.run(MockitoSessionTest.SessionWithOverriddenFailure.class);
+
+ //expect
+ JUnitResultAssert.assertThat(result).isSuccessful();
+
+ //in order to demonstrate feature, we intentionally misuse Mockito and need to clean up state
+ resetState();
+ }
+
public static class SessionWithoutAnyConfiguration {
@Mock IMethods mock;
@@ -139,4 +170,52 @@ public class MockitoSessionTest {
assertTrue(false);
}
}
+
+ public static class SessionWithManuallyInitializedMock {
+ @Mock IMethods mock;
+ IMethods mock2 = Mockito.mock(IMethods.class, "manual mock");
+
+ MockitoSession mockito = Mockito.mockitoSession().initMocks(this).startMocking();
+
+ @After public void after() {
+ mockito.finishMocking();
+ }
+
+ @Test public void manual_mock_preserves_its_settings() {
+ assertEquals("mock", mockingDetails(mock).getMockCreationSettings().getMockName().toString());
+ assertEquals("manual mock", mockingDetails(mock2).getMockCreationSettings().getMockName().toString());
+ }
+ }
+
+ public static class SessionWithUpdatedStrictness {
+ @Mock IMethods mock;
+ MockitoSession mockito = Mockito.mockitoSession().initMocks(this).strictness(Strictness.STRICT_STUBS).startMocking();
+
+ @After public void after() {
+ mockito.finishMocking();
+ }
+
+ @Test public void manual_mock_preserves_its_settings() {
+ when(mock.simpleMethod(1)).thenReturn("foo");
+
+ //when
+ mockito.setStrictness(Strictness.LENIENT);
+
+ //then no exception is thrown, even though the arg is different
+ mock.simpleMethod(2);
+ }
+ }
+
+ public static class SessionWithOverriddenFailure {
+ @Mock IMethods mock;
+ MockitoSession mockito = Mockito.mockitoSession().initMocks(this).startMocking();
+
+ @After public void after() {
+ mockito.finishMocking(new RuntimeException("Boo!"));
+ }
+
+ @Test public void invalid_mockito_usage() {
+ verify(mock);
+ }
+ }
}
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java b/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
index 74acd78..754b7dc 100644
--- a/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
+++ b/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
@@ -1,27 +1,40 @@
/*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockitousage.stubbing;
+import org.junit.After;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoSession;
+import org.mockito.StateMaster;
+import org.mockito.exceptions.base.MockitoException;
import org.mockito.internal.framework.DefaultMockitoSession;
import org.mockito.internal.util.SimpleMockitoLogger;
import org.mockito.quality.Strictness;
import org.mockitousage.IMethods;
+import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.verify;
import static org.mockitoutil.TestBase.filterLineNo;
public class StubbingWarningsTest {
+ private static final String TEST_NAME = "test.name";
+
@Mock IMethods mock;
SimpleMockitoLogger logger = new SimpleMockitoLogger();
- MockitoSession mockito = new DefaultMockitoSession(this, Strictness.WARN, logger);
+ MockitoSession mockito = new DefaultMockitoSession(singletonList((Object) this), TEST_NAME, Strictness.WARN, logger);
+
+ @After public void after() {
+ StateMaster stateMaster = new StateMaster();
+ stateMaster.reset();
+ stateMaster.clearMockitoListeners();
+ }
@Test public void few_interactions() throws Throwable {
//when
@@ -65,7 +78,7 @@ public class StubbingWarningsTest {
//because it was simpler to implement. This can be improved given we put priority to improve the warnings.
//then
assertEquals(filterLineNo(
- "[MockitoHint] StubbingWarningsTest.null (see javadoc for MockitoHint):\n" +
+ "[MockitoHint] " + TEST_NAME + " (see javadoc for MockitoHint):\n" +
"[MockitoHint] 1. Unused -> at org.mockitousage.stubbing.StubbingWarningsTest.stubbing_argument_mismatch(StubbingWarningsTest.java:0)\n"),
filterLineNo(logger.getLoggedInfo()));
}
@@ -78,8 +91,25 @@ public class StubbingWarningsTest {
//then
assertEquals(filterLineNo(
- "[MockitoHint] StubbingWarningsTest.null (see javadoc for MockitoHint):\n" +
+ "[MockitoHint] " + TEST_NAME + " (see javadoc for MockitoHint):\n" +
"[MockitoHint] 1. Unused -> at org.mockitousage.stubbing.StubbingWarningsTest.unused_stubbing(StubbingWarningsTest.java:0)\n"),
filterLineNo(logger.getLoggedInfo()));
}
+
+ @Test(expected = MockitoException.class) public void unfinished_verification_without_throwable() throws Throwable {
+ //when
+ verify(mock);
+
+ mockito.finishMocking();
+ }
+
+ @Test public void unfinished_verification_with_throwable() throws Throwable {
+ //when
+ verify(mock);
+
+ mockito.finishMocking(new AssertionError());
+
+ // then
+ logger.assertEmpty();
+ }
}
diff --git a/src/test/java/org/mockitoutil/TestBase.java b/src/test/java/org/mockitoutil/TestBase.java
index 2971ee5..ca3d7b8 100644
--- a/src/test/java/org/mockitoutil/TestBase.java
+++ b/src/test/java/org/mockitoutil/TestBase.java
@@ -11,7 +11,8 @@ import org.mockito.MockitoAnnotations;
import org.mockito.StateMaster;
import org.mockito.internal.MockitoCore;
import org.mockito.internal.configuration.ConfigurationAccess;
-import org.mockito.internal.creation.bytebuddy.InterceptedInvocation;
+import org.mockito.internal.invocation.mockref.MockStrongReference;
+import org.mockito.internal.invocation.InterceptedInvocation;
import org.mockito.internal.debugging.LocationImpl;
import org.mockito.internal.invocation.InvocationBuilder;
import org.mockito.internal.invocation.InvocationMatcher;
@@ -64,8 +65,9 @@ public class TestBase {
for (int i = 0; i < args.length; i++) {
types[i] = args[i].getClass();
}
- return new InterceptedInvocation(mock(type), new SerializableMethod(type.getMethod(methodName,
- types)), args, InterceptedInvocation.NO_OP, new LocationImpl(), 1);
+ return new InterceptedInvocation(new MockStrongReference<Object>(mock(type), false),
+ new SerializableMethod(type.getMethod(methodName, types)), args, InterceptedInvocation.NO_OP,
+ new LocationImpl(), 1);
}
protected static Invocation invocationAt(String location) {
diff --git a/stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java b/stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
deleted file mode 100644
index c9b8a7c..0000000
--- a/stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.mockito.internal.invocation;
-
-import org.mockito.invocation.Invocation;
-import org.mockito.invocation.InvocationFactory;
-import org.mockito.mock.MockCreationSettings;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.Callable;
-
-public class DefaultInvocationFactory implements InvocationFactory {
-
- public Invocation createInvocation(Object target, MockCreationSettings settings, Method method, Callable realMethod, Object... args) {
- throw new RuntimeException("Not implemented");
- }
-}
diff --git a/subprojects/inline/inline.gradle b/subprojects/inline/inline.gradle
index be10361..b8d2577 100644
--- a/subprojects/inline/inline.gradle
+++ b/subprojects/inline/inline.gradle
@@ -8,3 +8,6 @@ dependencies {
}
tasks.javadoc.enabled = false
+
+//required by the "StressTest.java"
+test.maxHeapSize = "256m"
diff --git a/subprojects/inline/src/test/java/org/mockitoinline/RecursionTest.java b/subprojects/inline/src/test/java/org/mockitoinline/RecursionTest.java
new file mode 100644
index 0000000..2a4494e
--- /dev/null
+++ b/subprojects/inline/src/test/java/org/mockitoinline/RecursionTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitoinline;
+
+import org.junit.Test;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.mockito.Mockito.spy;
+
+public class RecursionTest {
+
+ @Test
+ public void testMockConcurrentHashMap() {
+ ConcurrentMap<String, String> map = spy(new ConcurrentHashMap<String, String>());
+ map.putIfAbsent("a", "b");
+ }
+}
diff --git a/subprojects/inline/src/test/java/org/mockitoinline/StressTest.java b/subprojects/inline/src/test/java/org/mockitoinline/StressTest.java
new file mode 100644
index 0000000..c6a5506
--- /dev/null
+++ b/subprojects/inline/src/test/java/org/mockitoinline/StressTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitoinline;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+public class StressTest {
+ public class TestClass {
+ public String getStuff() {
+ return "A";
+ }
+ }
+
+ @Test
+ public void call_a_lot_of_mocks() {
+ //This requires smaller heap set for the test process, see "inline.gradle"
+ for (int i = 0; i < 40000; i++) {
+ TestClass mock = mock(TestClass.class);
+ when(mock.getStuff()).thenReturn("B");
+ assertEquals("B", mock.getStuff());
+
+ TestClass serializableMock = mock(TestClass.class, withSettings().serializable());
+ when(serializableMock.getStuff()).thenReturn("C");
+ assertEquals("C", serializableMock.getStuff());
+
+ if (i % 1024 == 0) {
+ System.out.println(i + "/40000 mocks called");
+ }
+ }
+ }
+}
diff --git a/subprojects/inline/src/test/java/org/mockitoinline/SuperCallTest.java b/subprojects/inline/src/test/java/org/mockitoinline/SuperCallTest.java
new file mode 100644
index 0000000..1fe8196
--- /dev/null
+++ b/subprojects/inline/src/test/java/org/mockitoinline/SuperCallTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitoinline;
+
+import org.junit.Test;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+public final class SuperCallTest {
+
+ @Test
+ public void testSuperMethodCall() {
+ Dummy d = spy(new Dummy());
+ d.foo();
+ verify(d).bar(eq("baz"));
+ }
+
+ static class Dummy {
+
+ public void foo() {
+ bar("baz");
+ }
+
+ // Also fails if public.
+ void bar(String s) {
+ return;
+ }
+ }
+}