From faeae6ac604e0103229a2ef23e35f88e10e026dd Mon Sep 17 00:00:00 2001
From: Tim van der Lippe
Date: Mon, 11 Feb 2019 17:46:03 +0000
Subject: [PATCH 01/42] Fix issue with mocking of java.util.* classes (#1617)
* Fix issue with mocking of java.util.* classes
Fixes #1615
* Fix other broken test
---
.../bytebuddy/SubclassBytecodeGenerator.java | 2 +-
.../AcrossClassLoaderSerializationTest.java | 2 +-
.../moduletest/ModuleHandlingTest.java | 29 +++++++++++++++++++
3 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
index 8968b9e8e4..093978dd22 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
@@ -98,7 +98,7 @@ public Class extends T> mockClass(MockFeatures features) {
if (localMock || loader instanceof MultipleParentClassLoader && !isComingFromJDK(features.mockedType)) {
typeName = features.mockedType.getName();
} else {
- typeName = InjectionBase.class.getPackage().getName() + features.mockedType.getSimpleName();
+ typeName = InjectionBase.class.getPackage().getName() + "." + features.mockedType.getSimpleName();
}
String name = String.format("%s$%s$%d", typeName, "MockitoMock", Math.abs(random.nextInt()));
diff --git a/src/test/java/org/mockitousage/serialization/AcrossClassLoaderSerializationTest.java b/src/test/java/org/mockitousage/serialization/AcrossClassLoaderSerializationTest.java
index 240cf7d027..f8a262d15d 100644
--- a/src/test/java/org/mockitousage/serialization/AcrossClassLoaderSerializationTest.java
+++ b/src/test/java/org/mockitousage/serialization/AcrossClassLoaderSerializationTest.java
@@ -33,7 +33,7 @@ public void check_that_mock_can_be_serialized_in_a_classloader_and_deserialized_
byte[] bytes = create_mock_and_serialize_it_in_class_loader_A();
Object the_deserialized_mock = read_stream_and_deserialize_it_in_class_loader_B(bytes);
- assertThat(the_deserialized_mock.getClass().getName()).startsWith("org.mockito.codegenAClassToBeMockedInThisTestOnlyAndInCallablesOnly");
+ assertThat(the_deserialized_mock.getClass().getName()).startsWith("org.mockito.codegen.AClassToBeMockedInThisTestOnlyAndInCallablesOnly");
}
private Object read_stream_and_deserialize_it_in_class_loader_B(byte[] bytes) throws Exception {
diff --git a/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java b/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java
index 6ec32893a6..ed732c8089 100644
--- a/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java
+++ b/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java
@@ -4,6 +4,7 @@
*/
package org.mockito.moduletest;
+import java.util.concurrent.locks.Lock;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.loading.ClassInjector;
@@ -91,6 +92,34 @@ public void can_define_class_in_open_reading_module() throws Exception {
}
}
+ @Test
+ public void can_define_class_in_open_java_util_module() throws Exception {
+ assumeThat(Plugins.getMockMaker() instanceof InlineByteBuddyMockMaker, is(false));
+
+ Path jar = modularJar(true, true, true);
+ ModuleLayer layer = layer(jar, true);
+
+ ClassLoader loader = layer.findLoader("mockito.test");
+ Class> type = loader.loadClass("java.util.concurrent.locks.Lock");
+
+ ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(loader);
+ try {
+ Class> mockito = loader.loadClass(Mockito.class.getName());
+ @SuppressWarnings("unchecked")
+ Lock mock = (Lock) mockito.getMethod("mock", Class.class).invoke(null, type);
+ Object stubbing = mockito.getMethod("when", Object.class).invoke(null, mock.tryLock());
+ loader.loadClass(OngoingStubbing.class.getName()).getMethod("thenReturn", Object.class).invoke(stubbing, true);
+
+ boolean relocated = !Boolean.getBoolean("org.mockito.internal.noUnsafeInjection") && ClassInjector.UsingReflection.isAvailable();
+ String prefix = relocated ? "org.mockito.codegen.Lock$MockitoMock$" : "java.util.concurrent.locks.Lock$MockitoMock$";
+ assertThat(mock.getClass().getName()).startsWith(prefix);
+ assertThat(mock.tryLock()).isEqualTo(true);
+ } finally {
+ Thread.currentThread().setContextClassLoader(contextLoader);
+ }
+ }
+
@Test
public void inline_mock_maker_can_mock_closed_modules() throws Exception {
assumeThat(Plugins.getMockMaker() instanceof InlineByteBuddyMockMaker, is(true));
From a9d998fff27bc5019ba1ad78fc068bb8a2a424b0 Mon Sep 17 00:00:00 2001
From: shipkit-org
Date: Mon, 11 Feb 2019 17:52:56 +0000
Subject: [PATCH 02/42] 2.24.2 release (previous 2.24.1) + release notes
updated by CI build 3874
[ci skip-release]
---
doc/release-notes/official.md | 5 +++++
version.properties | 4 ++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/doc/release-notes/official.md b/doc/release-notes/official.md
index 58570c9b1e..ce1e9c77a0 100644
--- a/doc/release-notes/official.md
+++ b/doc/release-notes/official.md
@@ -1,5 +1,10 @@
*Release notes were automatically generated by [Shipkit](http://shipkit.org/)*
+#### 2.24.2
+ - 2019-02-11 - [1 commit](https://github.com/mockito/mockito/compare/v2.24.1...v2.24.2) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.2-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.2)
+ - Fix issue with mocking of java.util.* classes [(#1617)](https://github.com/mockito/mockito/pull/1617)
+ - Issue with mocking type in "java.util.*", Java 12 [(#1615)](https://github.com/mockito/mockito/issues/1615)
+
#### 2.24.1
- 2019-02-04 - [1 commit](https://github.com/mockito/mockito/compare/v2.24.0...v2.24.1) by [zoujinhe](https://github.com/zoujinhe) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.1-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.1)
- typo? ... 'thenReturn' instruction if completed -> ... 'thenReturn' instruction is completed [(#1608)](https://github.com/mockito/mockito/pull/1608)
diff --git a/version.properties b/version.properties
index 54435d6413..b930a88249 100644
--- a/version.properties
+++ b/version.properties
@@ -1,8 +1,8 @@
#Currently building Mockito version
-version=2.24.2
+version=2.24.3
#Previous version used to generate release notes delta
-previousVersion=2.24.1
+previousVersion=2.24.2
#Not published currently, see https://github.com/mockito/mockito/issues/962
mockito.testng.version=1.0
From ac9195f740280f1964382acb469b14955a08d359 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcin=20Zaj=C4=85czkowski?=
Date: Mon, 11 Feb 2019 22:05:48 +0100
Subject: [PATCH 03/42] Automatic dependency update with Dependabot (#1600)
http://dependabot.com/
[ci skip-release]
---
.dependabot/config.yml | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 .dependabot/config.yml
diff --git a/.dependabot/config.yml b/.dependabot/config.yml
new file mode 100644
index 0000000000..cd85cf642e
--- /dev/null
+++ b/.dependabot/config.yml
@@ -0,0 +1,9 @@
+version: 1
+
+update_configs:
+ - package_manager: "java:gradle"
+ directory: "/"
+ update_schedule: "daily"
+ # Redundant - default repository branch by default
+ target_branch: "release/2.x"
+
From cbedbe567d5bf902b13e8cebc4a2a2ccfef7758f Mon Sep 17 00:00:00 2001
From: Tim van der Lippe
Date: Tue, 12 Feb 2019 13:14:01 +0000
Subject: [PATCH 04/42] Return null instead of causing a CCE (#1612)
This solves a large number of edge-cases where `null` will actually
remove the runtime ClassCastException. This essentially negates the
whole MockitoCast ErrorProne check. We can still not support every use
case, but causing a NPE instead of a CCE does not seem to make this
worse.
I am still running internal tests within Google to see if there are any
regressions, but I already saw that some of the test failures we had
with ByteBuddy were resolved with this particular patch.
Note that this now fully closes #357. A previous PR resolved the same
issue with ReturnsSmartNulls: #1576.
Fixes #357
---
gradle/errorprone.gradle | 4 ++++
.../defaultanswers/ReturnsDeepStubs.java | 9 ++++++++
.../ReturnsGenericDeepStubsTest.java | 23 +++++++++++++++++++
.../DeepStubsSerializableTest.java | 2 +-
4 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/gradle/errorprone.gradle b/gradle/errorprone.gradle
index 1d9cf7428e..43c8633fcd 100644
--- a/gradle/errorprone.gradle
+++ b/gradle/errorprone.gradle
@@ -10,3 +10,7 @@ if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
dependencies {
errorprone libraries.errorprone
}
+
+tasks.named("compileTestJava").configure {
+ options.errorprone.errorproneArgs << "-Xep:MockitoCast:OFF"
+}
diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
index 3909ff041c..8729171255 100644
--- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
+++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
@@ -53,6 +53,15 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
return delegate().returnValueFor(rawType);
}
+ // When dealing with erasured generics, we only receive the Object type as rawType. At this
+ // point, there is nothing to salvage for Mockito. Instead of trying to be smart and generate
+ // a mock that would potentially match the return signature, instead return `null`. This
+ // is valid per the CheckCast JVM instruction and is better than causing a ClassCastException
+ // on runtime.
+ if (rawType.equals(Object.class)) {
+ return null;
+ }
+
return deepStub(invocation, returnTypeGenericMetadata);
}
diff --git a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
index d91df8c40e..5890f5db0d 100644
--- a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
@@ -14,6 +14,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@SuppressWarnings("unused")
public class ReturnsGenericDeepStubsTest {
@@ -110,4 +111,26 @@ public void as_expected_fail_with_a_CCE_on_callsite_when_erasure_takes_place_for
StringBuilder stringBuilder_assignment_that_should_throw_a_CCE =
mock.twoTypeParams(new StringBuilder()).append(2).append(3);
}
+
+ class WithGenerics {
+ T execute() {
+ throw new IllegalArgumentException();
+ }
+ }
+ class SubClass extends WithGenerics {}
+
+ class UserOfSubClass {
+ SubClass generate() {
+ return null;
+ }
+ }
+
+ @Test
+ public void can_handle_deep_stubs_with_generics_at_end_of_deep_invocation() {
+ UserOfSubClass mock = mock(UserOfSubClass.class, RETURNS_DEEP_STUBS);
+
+ when(mock.generate().execute()).thenReturn("sub");
+
+ assertThat(mock.generate().execute()).isEqualTo("sub");
+ }
}
diff --git a/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java b/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
index 3294614c24..989d3a195c 100644
--- a/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
+++ b/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
@@ -45,7 +45,7 @@ public void should_serialize_and_deserialize_parameterized_class_mocked_with_dee
assertThat(deserialized_deep_stub.iterator().next().add("yes")).isEqualTo(true);
}
- @Test(expected = ClassCastException.class)
+ @Test(expected = NullPointerException.class)
public void should_discard_generics_metadata_when_serialized_then_disabling_deep_stubs_with_generics() throws Exception {
// given
ListContainer deep_stubbed = mock(ListContainer.class, withSettings().defaultAnswer(RETURNS_DEEP_STUBS).serializable());
From 34ebca1a8cd88465dd6e8ba395f78a6593522958 Mon Sep 17 00:00:00 2001
From: shipkit-org
Date: Tue, 12 Feb 2019 13:20:41 +0000
Subject: [PATCH 05/42] 2.24.3 release (previous 2.24.2) + release notes
updated by CI build 3877
[ci skip-release]
---
doc/release-notes/official.md | 7 +++++++
version.properties | 4 ++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/doc/release-notes/official.md b/doc/release-notes/official.md
index ce1e9c77a0..a041c5e6e8 100644
--- a/doc/release-notes/official.md
+++ b/doc/release-notes/official.md
@@ -1,5 +1,12 @@
*Release notes were automatically generated by [Shipkit](http://shipkit.org/)*
+#### 2.24.3
+ - 2019-02-12 - [2 commits](https://github.com/mockito/mockito/compare/v2.24.2...v2.24.3) by [Marcin Zajączkowski](https://github.com/szpak) (1), [Tim van der Lippe](https://github.com/TimvdLippe) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.3-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.3)
+ - [Java 9 support] ClassCastExceptions with JDK9 javac [(#357)](https://github.com/mockito/mockito/issues/357)
+ - Return null instead of causing a CCE [(#1612)](https://github.com/mockito/mockito/pull/1612)
+ - Automatic dependency update with Dependabot [(#1600)](https://github.com/mockito/mockito/pull/1600)
+ - Fix/bug 1551 cce on smart not null answers [(#1576)](https://github.com/mockito/mockito/pull/1576)
+
#### 2.24.2
- 2019-02-11 - [1 commit](https://github.com/mockito/mockito/compare/v2.24.1...v2.24.2) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.2-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.2)
- Fix issue with mocking of java.util.* classes [(#1617)](https://github.com/mockito/mockito/pull/1617)
diff --git a/version.properties b/version.properties
index b930a88249..9daf4d2f34 100644
--- a/version.properties
+++ b/version.properties
@@ -1,8 +1,8 @@
#Currently building Mockito version
-version=2.24.3
+version=2.24.4
#Previous version used to generate release notes delta
-previousVersion=2.24.2
+previousVersion=2.24.3
#Not published currently, see https://github.com/mockito/mockito/issues/962
mockito.testng.version=1.0
From d9cbe3e8ec9cafa521e61371d9e9600b7262cda7 Mon Sep 17 00:00:00 2001
From: Alex Simkin
Date: Thu, 14 Feb 2019 04:04:31 +1100
Subject: [PATCH 06/42] Fixes #1618 : Fix strict stubbing profile serialization
support. (#1620)
---
.../junit/DefaultStubbingLookupListener.java | 5 +-
.../StrictStubsSerializableTest.java | 46 +++++++++++++++++++
2 files changed, 50 insertions(+), 1 deletion(-)
create mode 100644 src/test/java/org/mockitousage/serialization/StrictStubsSerializableTest.java
diff --git a/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java b/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java
index 21212a6754..b6a80c64a3 100644
--- a/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java
+++ b/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java
@@ -12,6 +12,7 @@
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Stubbing;
+import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@@ -22,7 +23,9 @@
* Default implementation of stubbing lookup listener.
* Fails early if stub called with unexpected arguments, but only if current strictness is set to STRICT_STUBS.
*/
-class DefaultStubbingLookupListener implements StubbingLookupListener {
+class DefaultStubbingLookupListener implements StubbingLookupListener, Serializable {
+
+ private static final long serialVersionUID = -6789800638070123629L;
private Strictness currentStrictness;
private boolean mismatchesReported;
diff --git a/src/test/java/org/mockitousage/serialization/StrictStubsSerializableTest.java b/src/test/java/org/mockitousage/serialization/StrictStubsSerializableTest.java
new file mode 100644
index 0000000000..9d786695fc
--- /dev/null
+++ b/src/test/java/org/mockitousage/serialization/StrictStubsSerializableTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitousage.serialization;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.Serializable;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+import static org.mockitoutil.SimpleSerializationUtil.serializeAndBack;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class StrictStubsSerializableTest {
+
+ @Mock(serializable = true) private SampleClass sampleClass;
+
+ @Test
+ public void should_serialize_and_deserialize_mock_created_with_serializable_and_strict_stubs() throws Exception {
+ // given
+ when(sampleClass.isFalse()).thenReturn(true);
+
+ // when
+ SampleClass deserializedSample = serializeAndBack(sampleClass);
+ // to satisfy strict stubbing
+ deserializedSample.isFalse();
+ verify(deserializedSample).isFalse();
+ verify(sampleClass, never()).isFalse();
+
+ // then
+ assertThat(deserializedSample.isFalse()).isEqualTo(true);
+ assertThat(sampleClass.isFalse()).isEqualTo(true);
+ }
+
+ static class SampleClass implements Serializable {
+
+ boolean isFalse() {
+ return false;
+ }
+ }
+}
From 4c254058f1f1606a5de4c4fdc9f1a0b3c10ad15e Mon Sep 17 00:00:00 2001
From: shipkit-org
Date: Wed, 13 Feb 2019 17:10:34 +0000
Subject: [PATCH 07/42] 2.24.4 release (previous 2.24.3) + release notes
updated by CI build 3883
[ci skip-release]
---
doc/release-notes/official.md | 5 +++++
version.properties | 4 ++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/doc/release-notes/official.md b/doc/release-notes/official.md
index a041c5e6e8..baef9ca6d3 100644
--- a/doc/release-notes/official.md
+++ b/doc/release-notes/official.md
@@ -1,5 +1,10 @@
*Release notes were automatically generated by [Shipkit](http://shipkit.org/)*
+#### 2.24.4
+ - 2019-02-13 - [1 commit](https://github.com/mockito/mockito/compare/v2.24.3...v2.24.4) by [Alex Simkin](https://github.com/SimY4) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.4-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.4)
+ - Fixes #1618 : Fix strict stubbing profile serialization support. [(#1620)](https://github.com/mockito/mockito/pull/1620)
+ - Serializable flag doesn't make mock serializable [(#1618)](https://github.com/mockito/mockito/issues/1618)
+
#### 2.24.3
- 2019-02-12 - [2 commits](https://github.com/mockito/mockito/compare/v2.24.2...v2.24.3) by [Marcin Zajączkowski](https://github.com/szpak) (1), [Tim van der Lippe](https://github.com/TimvdLippe) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.3-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.3)
- [Java 9 support] ClassCastExceptions with JDK9 javac [(#357)](https://github.com/mockito/mockito/issues/357)
diff --git a/version.properties b/version.properties
index 9daf4d2f34..3eb3f8c0be 100644
--- a/version.properties
+++ b/version.properties
@@ -1,8 +1,8 @@
#Currently building Mockito version
-version=2.24.4
+version=2.24.5
#Previous version used to generate release notes delta
-previousVersion=2.24.3
+previousVersion=2.24.4
#Not published currently, see https://github.com/mockito/mockito/issues/962
mockito.testng.version=1.0
From 1ba92767c19c2dd3d3bf3ebf697f32851b2b7af9 Mon Sep 17 00:00:00 2001
From: Tim van der Lippe
Date: Mon, 18 Feb 2019 15:07:09 +0000
Subject: [PATCH 08/42] [ci maven-central-release] Release 2.24.4
---
version.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version.properties b/version.properties
index 3eb3f8c0be..3e71f116c8 100644
--- a/version.properties
+++ b/version.properties
@@ -1,5 +1,5 @@
#Currently building Mockito version
-version=2.24.5
+version=2.24.4
#Previous version used to generate release notes delta
previousVersion=2.24.4
From e2e7dc8bd8c4244ba864dd8687a0dc30cace967f Mon Sep 17 00:00:00 2001
From: Tim van der Lippe
Date: Mon, 18 Feb 2019 15:14:14 +0000
Subject: [PATCH 09/42] [ci maven-central-release] Release 2.24.5
---
version.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version.properties b/version.properties
index 3e71f116c8..3eb3f8c0be 100644
--- a/version.properties
+++ b/version.properties
@@ -1,5 +1,5 @@
#Currently building Mockito version
-version=2.24.4
+version=2.24.5
#Previous version used to generate release notes delta
previousVersion=2.24.4
From 41c5606349e13a1e3e060ab8348b412662219d62 Mon Sep 17 00:00:00 2001
From: shipkit-org
Date: Mon, 18 Feb 2019 15:22:08 +0000
Subject: [PATCH 10/42] 2.24.5 release (previous 2.24.4) + release notes
updated by CI build 3887
[ci skip-release]
---
doc/release-notes/official.md | 4 ++++
version.properties | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/doc/release-notes/official.md b/doc/release-notes/official.md
index baef9ca6d3..d15b1d6d24 100644
--- a/doc/release-notes/official.md
+++ b/doc/release-notes/official.md
@@ -1,5 +1,9 @@
*Release notes were automatically generated by [Shipkit](http://shipkit.org/)*
+#### 2.24.5
+ - 2019-02-18 - [2 commits](https://github.com/mockito/mockito/compare/v2.24.4...v2.24.5) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.5-green.svg)](https://bintray.com/mockito/maven/mockito/2.24.5)
+ - No pull requests referenced in commit messages.
+
#### 2.24.4
- 2019-02-13 - [1 commit](https://github.com/mockito/mockito/compare/v2.24.3...v2.24.4) by [Alex Simkin](https://github.com/SimY4) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.4-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.4)
- Fixes #1618 : Fix strict stubbing profile serialization support. [(#1620)](https://github.com/mockito/mockito/pull/1620)
diff --git a/version.properties b/version.properties
index 3eb3f8c0be..ddbd9bc93a 100644
--- a/version.properties
+++ b/version.properties
@@ -1,8 +1,8 @@
#Currently building Mockito version
-version=2.24.5
+version=2.24.6
#Previous version used to generate release notes delta
-previousVersion=2.24.4
+previousVersion=2.24.5
#Not published currently, see https://github.com/mockito/mockito/issues/962
mockito.testng.version=1.0
From 866c5d2d49216b3b4767060737fbde53839eabf2 Mon Sep 17 00:00:00 2001
From: Marcin Stachniuk
Date: Wed, 20 Feb 2019 02:01:12 +0100
Subject: [PATCH 11/42] Make use of shipkit v2.1.0
After this update the site:
https://github.com/mockito/mockito/releases
will be updated by Shipkit
---
build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/build.gradle b/build.gradle
index 0dac0c72f3..1991f9d166 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,7 +11,7 @@ buildscript {
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.6'
//Using buildscript.classpath so that we can resolve shipkit from maven local, during local testing
- classpath 'org.shipkit:shipkit:2.0.28'
+ classpath 'org.shipkit:shipkit:2.1.0'
}
}
@@ -110,7 +110,7 @@ subprojects {
name = rootProject.name + '-' + project.name
}
}
-
+
afterEvaluate {
def lib = publishing.publications.javaLibrary
if(lib && !lib.artifactId.startsWith("mockito-")) {
From bbb2b6961d97e01582dab1bf84d2b2c2075e73e9 Mon Sep 17 00:00:00 2001
From: Szczepan Faber
Date: Wed, 27 Feb 2019 05:39:03 -0800
Subject: [PATCH 12/42] Bumped shipkit to v2.1.3
This way we're picking an upstream bugfix
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 1991f9d166..c8142db658 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,7 +11,7 @@ buildscript {
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.6'
//Using buildscript.classpath so that we can resolve shipkit from maven local, during local testing
- classpath 'org.shipkit:shipkit:2.1.0'
+ classpath 'org.shipkit:shipkit:2.1.3'
}
}
From 3722958ba4db09b6ea45b613317b5f888d39a3f1 Mon Sep 17 00:00:00 2001
From: Brice Dutheil
Date: Tue, 19 Feb 2019 22:26:45 +0100
Subject: [PATCH 13/42] Fixes #1621: Deep stubs didn't extract bounds from
terminal TypeVariable
This case was not handled correctly by the GenericMetadataSupport, the
issue was that in this case it didn't extracted the bounds from the
terminal variable which happen to be a type variable _argument_.
This likely fixes a whole area of generics issues with deep stubs.
---
.../bytebuddy/MockMethodInterceptor.java | 32 +++++++++----------
.../reflection/GenericMetadataSupport.java | 24 +++++++++++---
.../GenericMetadataSupportTest.java | 32 +++++++++++++++++--
.../DeepStubsSerializableTest.java | 20 ++++++++----
.../stubbing/DeepStubbingTest.java | 16 +++++-----
5 files changed, 86 insertions(+), 38 deletions(-)
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 906692768d..e57a82e739 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java
@@ -46,13 +46,11 @@ Object doIntercept(Object mock,
Method invokedMethod,
Object[] arguments,
RealMethod realMethod) throws Throwable {
- return doIntercept(
- mock,
- invokedMethod,
- arguments,
- realMethod,
- new LocationImpl()
- );
+ return doIntercept(mock,
+ invokedMethod,
+ arguments,
+ realMethod,
+ new LocationImpl());
}
Object doIntercept(Object mock,
@@ -108,11 +106,11 @@ public static Object interceptSuperCallable(@This Object mock,
return superCall.call();
}
return interceptor.doIntercept(
- mock,
- invokedMethod,
- arguments,
- new RealMethod.FromCallable(superCall)
- );
+ mock,
+ invokedMethod,
+ arguments,
+ new RealMethod.FromCallable(superCall)
+ );
}
@SuppressWarnings("unused")
@@ -126,11 +124,11 @@ public static Object interceptAbstract(@This Object mock,
return stubValue;
}
return interceptor.doIntercept(
- mock,
- invokedMethod,
- arguments,
- RealMethod.IsIllegal.INSTANCE
- );
+ mock,
+ invokedMethod,
+ arguments,
+ RealMethod.IsIllegal.INSTANCE
+ );
}
}
}
diff --git a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
index 596827c64c..d7838fb612 100644
--- a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
+++ b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
@@ -97,10 +97,20 @@ protected Class> extractRawTypeOf(Type type) {
}
if (type instanceof TypeVariable) {
/*
- * If type is a TypeVariable, then it is needed to gather data elsewhere. Usually TypeVariables are declared
- * on the class definition, such as such as List.
+ * If type is a TypeVariable, then it is needed to gather data elsewhere.
+ * Usually TypeVariables are declared on the class definition, such as
+ * such as List.
+ *
+ * If the data cannot be found in the contextual map, try harder on the
+ * TypeVariable itself looking for defined bounds.
*/
- return extractRawTypeOf(contextualActualTypeParameters.get(type));
+ Type typeArgument = contextualActualTypeParameters.get(type);
+ if (typeArgument == null) {
+ BoundedType boundedType = boundsOf((TypeVariable>) type);
+ contextualActualTypeParameters.put((TypeVariable>) type, boundedType);
+ return extractRawTypeOf(boundedType);
+ }
+ return extractRawTypeOf(typeArgument);
}
throw new MockitoException("Raw extraction not supported for : '" + type + "'");
}
@@ -164,8 +174,12 @@ private BoundedType boundsOf(TypeVariable> typeParameter) {
private BoundedType boundsOf(WildcardType wildCard) {
/*
* According to JLS(http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.5.1):
- * - Lower and upper can't coexist: (for instance, this is not allowed: extends List & super MyInterface>)
- * - Multiple bounds are not supported (for instance, this is not allowed: extends List & MyInterface>)
+ * - Lower and upper can't coexist: (for instance, this is not allowed:
+ * extends List & super MyInterface>)
+ * - Multiple concrete type bounds are not supported (for instance, this is not allowed:
+ * extends ArrayList & MyInterface>)
+ * But the following form is possible where there is a single concrete tyep bound followed by interface type bounds
+ * & Comparable>
*/
WildCardBoundedType wildCardBoundedType = new WildCardBoundedType(wildCard);
diff --git a/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java b/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
index 323efbf843..56fff2069c 100644
--- a/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
+++ b/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
@@ -10,7 +10,12 @@
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
@@ -48,6 +53,17 @@ interface GenericsNest & Cloneable> extends Map { }
+ public interface TopInterface {
+ T generic();
+ }
+ public interface MiddleInterface extends TopInterface { }
+ public class OwningClassWithDeclaredUpperBounds & Comparable> {
+ public abstract class AbstractInner implements MiddleInterface { }
+ }
+ public class OwningClassWithNoDeclaredUpperBounds {
+ public abstract class AbstractInner implements MiddleInterface { }
+ }
+
@Test
public void typeVariable_of_self_type() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsSelfReference.class).resolveGenericReturnType(firstNamedMethod("self", GenericsSelfReference.class));
@@ -56,7 +72,7 @@ public void typeVariable_of_self_type() {
}
@Test
- public void can_get_raw_type_from_Class() throws Exception {
+ public void can_get_raw_type_from_Class() {
assertThat(inferFrom(ListOfAnyNumbers.class).rawType()).isEqualTo(ListOfAnyNumbers.class);
assertThat(inferFrom(ListOfNumbers.class).rawType()).isEqualTo(ListOfNumbers.class);
assertThat(inferFrom(GenericsNest.class).rawType()).isEqualTo(GenericsNest.class);
@@ -199,6 +215,18 @@ public void paramType_with_wildcard_return_type_of____returning_wildcard_with_ty
assertThat(boundedType.interfaceBounds()).contains(Cloneable.class);
}
+ @Test
+ public void can_extract_raw_type_from_bounds_on_terminal_typeVariable() {
+ assertThat(inferFrom(OwningClassWithDeclaredUpperBounds.AbstractInner.class)
+ .resolveGenericReturnType(firstNamedMethod("generic", OwningClassWithDeclaredUpperBounds.AbstractInner.class))
+ .rawType()
+ ).isEqualTo(List.class);
+ assertThat(inferFrom(OwningClassWithNoDeclaredUpperBounds.AbstractInner.class)
+ .resolveGenericReturnType(firstNamedMethod("generic", OwningClassWithNoDeclaredUpperBounds.AbstractInner.class))
+ .rawType()
+ ).isEqualTo(Object.class);
+ }
+
private Type typeVariableValue(Map, Type> typeVariables, String typeVariableName) {
for (Map.Entry, Type> typeVariableTypeEntry : typeVariables.entrySet()) {
if (typeVariableTypeEntry.getKey().getName().equals(typeVariableName)) {
diff --git a/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java b/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
index 989d3a195c..e3891c6047 100644
--- a/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
+++ b/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
@@ -11,7 +11,11 @@
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.*;
+import static org.assertj.core.api.Assertions.fail;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
import static org.mockitoutil.SimpleSerializationUtil.serializeAndBack;
public class DeepStubsSerializableTest {
@@ -45,7 +49,7 @@ public void should_serialize_and_deserialize_parameterized_class_mocked_with_dee
assertThat(deserialized_deep_stub.iterator().next().add("yes")).isEqualTo(true);
}
- @Test(expected = NullPointerException.class)
+ @Test
public void should_discard_generics_metadata_when_serialized_then_disabling_deep_stubs_with_generics() throws Exception {
// given
ListContainer deep_stubbed = mock(ListContainer.class, withSettings().defaultAnswer(RETURNS_DEEP_STUBS).serializable());
@@ -53,10 +57,14 @@ public void should_discard_generics_metadata_when_serialized_then_disabling_deep
ListContainer deserialized_deep_stub = serializeAndBack(deep_stubbed);
- // when stubbing on a deserialized mock
- when(deserialized_deep_stub.iterator().next().get(42)).thenReturn("no");
-
- // then revert to the default RETURNS_DEEP_STUBS and the code will raise a ClassCastException
+ try {
+ // when stubbing on a deserialized mock
+ // then revert to the default RETURNS_DEEP_STUBS and the code will raise a ClassCastException
+ when(deserialized_deep_stub.iterator().next().get(42)).thenReturn("no");
+ fail("Expected an exception to be thrown as deep stubs and serialization does not play well together");
+ } catch (ClassCastException e) {
+ assertThat(e).hasMessageContaining("java.util.List");
+ }
}
static class SampleClass implements Serializable {
diff --git a/src/test/java/org/mockitousage/stubbing/DeepStubbingTest.java b/src/test/java/org/mockitousage/stubbing/DeepStubbingTest.java
index df41f062fb..0e574f0c5e 100644
--- a/src/test/java/org/mockitousage/stubbing/DeepStubbingTest.java
+++ b/src/test/java/org/mockitousage/stubbing/DeepStubbingTest.java
@@ -224,7 +224,7 @@ public void withPatternPrimitive() throws Exception {
Person person = mock(Person.class, RETURNS_DEEP_STUBS);
@Test
- public void shouldStubbingBasicallyWorkFine() throws Exception {
+ public void shouldStubbingBasicallyWorkFine() {
//given
given(person.getAddress().getStreet().getName()).willReturn("Norymberska");
@@ -236,7 +236,7 @@ public void shouldStubbingBasicallyWorkFine() throws Exception {
}
@Test
- public void shouldVerificationBasicallyWorkFine() throws Exception {
+ public void shouldVerificationBasicallyWorkFine() {
//given
person.getAddress().getStreet().getName();
@@ -245,7 +245,7 @@ public void shouldVerificationBasicallyWorkFine() throws Exception {
}
@Test
- public void verification_work_with_argument_Matchers_in_nested_calls() throws Exception {
+ public void verification_work_with_argument_Matchers_in_nested_calls() {
//given
person.getAddress("111 Mock Lane").getStreet();
person.getAddress("111 Mock Lane").getStreet(Locale.ITALIAN).getName();
@@ -257,7 +257,7 @@ public void verification_work_with_argument_Matchers_in_nested_calls() throws Ex
}
@Test
- public void deep_stub_return_same_mock_instance_if_invocation_matchers_matches() throws Exception {
+ public void deep_stub_return_same_mock_instance_if_invocation_matchers_matches() {
when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep");
person.getAddress("the docks").getStreet().getName();
@@ -270,7 +270,7 @@ public void deep_stub_return_same_mock_instance_if_invocation_matchers_matches()
}
@Test
- public void times_never_atLeast_atMost_verificationModes_should_work() throws Exception {
+ public void times_never_atLeast_atMost_verificationModes_should_work() {
when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep");
person.getAddress("the docks").getStreet().getName();
@@ -285,7 +285,7 @@ public void times_never_atLeast_atMost_verificationModes_should_work() throws Ex
@Test
- public void inOrder_only_work_on_the_very_last_mock_but_it_works() throws Exception {
+ public void inOrder_only_work_on_the_very_last_mock_but_it_works() {
when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep");
when(person.getAddress(anyString()).getStreet(Locale.ITALIAN).getName()).thenReturn("deep");
when(person.getAddress(anyString()).getStreet(Locale.CHINESE).getName()).thenReturn("deep");
@@ -307,7 +307,7 @@ public void inOrder_only_work_on_the_very_last_mock_but_it_works() throws Except
}
@Test
- public void verificationMode_only_work_on_the_last_returned_mock() throws Exception {
+ public void verificationMode_only_work_on_the_last_returned_mock() {
// 1st invocation on Address mock (stubbing)
when(person.getAddress("the docks").getStreet().getName()).thenReturn("deep");
@@ -328,7 +328,7 @@ public void verificationMode_only_work_on_the_last_returned_mock() throws Except
}
@Test
- public void shouldFailGracefullyWhenClassIsFinal() throws Exception {
+ public void shouldFailGracefullyWhenClassIsFinal() {
//when
FinalClass value = new FinalClass();
given(person.getFinalClass()).willReturn(value);
From 0cf45e2157e86a06dfd280a7d6e7fce63b4d764b Mon Sep 17 00:00:00 2001
From: Brice Dutheil
Date: Tue, 19 Feb 2019 22:38:30 +0100
Subject: [PATCH 14/42] Fixes #1621: Partly reverting #1612
cbedbe567d5bf902b13e8cebc4a2a2ccfef7758f
`ReturnsDeepStubs` was returning null instead of MockitoMock to avoid a
`ClassCastException` on the call site, this change seems not necessary
after the change done in df9b85eebb06106a6d2a629cf55eb9de5c3bf923.
But keep the MockitoCast check in errorprone disabled as this PR
improves what was done in #1612 by making the generics support cover
additional generics scenarios.
http://errorprone.info/bugpattern/MockitoCast
---
.../internal/stubbing/defaultanswers/ReturnsDeepStubs.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
index 8729171255..cc963679b2 100644
--- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
+++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
@@ -58,9 +58,9 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
// a mock that would potentially match the return signature, instead return `null`. This
// is valid per the CheckCast JVM instruction and is better than causing a ClassCastException
// on runtime.
- if (rawType.equals(Object.class)) {
- return null;
- }
+// if (rawType.equals(Object.class)) {
+// return null;
+// }
return deepStub(invocation, returnTypeGenericMetadata);
}
From c8bc6bc04e087b54a5fe3a8f8805ba5df26fd4e9 Mon Sep 17 00:00:00 2001
From: Brice Dutheil
Date: Tue, 26 Feb 2019 18:27:37 +0100
Subject: [PATCH 15/42] Cleanup, removes non needed `throws exception`
---
.../ReturnsGenericDeepStubsTest.java | 16 +++++------
.../GenericMetadataSupportTest.java | 28 +++++++++----------
2 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
index 5890f5db0d..40b9ecb575 100644
--- a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
@@ -34,7 +34,7 @@ interface GenericsNest & Cloneable> extends Map mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
Set extends Map.Entry extends Cloneable, Set>> entries = mock.entrySet();
@@ -50,7 +50,7 @@ public void generic_deep_mock_frenzy__look_at_these_chained_calls() throws Excep
}
@Test
- public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_of_parameterized_method_is_a_parameterizedtype_that_is_referencing_a_typevar_on_class() throws Exception {
+ public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_of_parameterized_method_is_a_parameterizedType_that_is_referencing_a_typeVar_on_class() {
GenericsNest> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
Cloneable cloneable_bound_that_is_declared_on_typevar_K_in_the_class_which_is_referenced_by_typevar_O_declared_on_the_method =
@@ -60,7 +60,7 @@ public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_
}
@Test
- public void can_create_mock_from_multiple_type_variable_bounds_when_method_return_type_is_referencing_a_typevar_on_class() throws Exception {
+ public void can_create_mock_from_multiple_type_variable_bounds_when_method_return_type_is_referencing_a_typeVar_on_class() {
GenericsNest> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
Cloneable cloneable_bound_of_typevar_K = mock.returningK();
@@ -68,7 +68,7 @@ public void can_create_mock_from_multiple_type_variable_bounds_when_method_retur
}
@Test
- public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_of_parameterized_method_is_a_typevar_that_is_referencing_a_typevar_on_class() throws Exception {
+ public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_of_parameterized_method_is_a_typeVar_that_is_referencing_a_typeVar_on_class() {
GenericsNest> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
Cloneable cloneable_bound_of_typevar_K_referenced_by_typevar_O = (Cloneable) mock.typeVarWithTypeParams();
@@ -76,7 +76,7 @@ public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_
}
@Test
- public void can_create_mock_from_return_types_declared_with_a_bounded_wildcard() throws Exception {
+ public void can_create_mock_from_return_types_declared_with_a_bounded_wildcard() {
GenericsNest> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
List super Integer> objects = mock.returningWildcard();
@@ -85,7 +85,7 @@ public void can_create_mock_from_return_types_declared_with_a_bounded_wildcard()
}
@Test
- public void can_still_work_with_raw_type_in_the_return_type() throws Exception {
+ public void can_still_work_with_raw_type_in_the_return_type() {
GenericsNest> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
Number the_raw_type_that_should_be_returned = mock.returnsNormalType();
@@ -93,7 +93,7 @@ public void can_still_work_with_raw_type_in_the_return_type() throws Exception {
}
@Test
- public void will_return_default_value_on_non_mockable_nested_generic() throws Exception {
+ public void will_return_default_value_on_non_mockable_nested_generic() {
GenericsNest> genericsNest = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
ListOfInteger listOfInteger = mock(ListOfInteger.class, RETURNS_DEEP_STUBS);
AnotherListOfInteger anotherListOfInteger = mock(AnotherListOfInteger.class, RETURNS_DEEP_STUBS);
@@ -104,7 +104,7 @@ public void will_return_default_value_on_non_mockable_nested_generic() throws Ex
}
@Test(expected = ClassCastException.class)
- public void as_expected_fail_with_a_CCE_on_callsite_when_erasure_takes_place_for_example___StringBuilder_is_subject_to_erasure() throws Exception {
+ public void as_expected_fail_with_a_CCE_on_call_site_when_erasure_takes_place_for_example___StringBuilder_is_subject_to_erasure() {
GenericsNest> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
// following assignment needed to create a ClassCastException on the call site (i.e. : here)
diff --git a/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java b/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
index 56fff2069c..57d0cb2925 100644
--- a/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
+++ b/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
@@ -80,7 +80,7 @@ public void can_get_raw_type_from_Class() {
}
@Test
- public void can_get_raw_type_from_ParameterizedType() throws Exception {
+ public void can_get_raw_type_from_ParameterizedType() {
assertThat(inferFrom(ListOfAnyNumbers.class.getGenericInterfaces()[0]).rawType()).isEqualTo(List.class);
assertThat(inferFrom(ListOfNumbers.class.getGenericInterfaces()[0]).rawType()).isEqualTo(List.class);
assertThat(inferFrom(GenericsNest.class.getGenericInterfaces()[0]).rawType()).isEqualTo(Map.class);
@@ -88,7 +88,7 @@ public void can_get_raw_type_from_ParameterizedType() throws Exception {
}
@Test
- public void can_get_type_variables_from_Class() throws Exception {
+ public void can_get_type_variables_from_Class() {
assertThat(inferFrom(GenericsNest.class).actualTypeArguments().keySet()).hasSize(1).extracting("name").contains("K");
assertThat(inferFrom(ListOfNumbers.class).actualTypeArguments().keySet()).isEmpty();
assertThat(inferFrom(ListOfAnyNumbers.class).actualTypeArguments().keySet()).hasSize(1).extracting("name").contains("N");
@@ -105,7 +105,7 @@ public void can_resolve_type_variables_from_ancestors() throws Exception {
}
@Test
- public void can_get_type_variables_from_ParameterizedType() throws Exception {
+ public void can_get_type_variables_from_ParameterizedType() {
assertThat(inferFrom(GenericsNest.class.getGenericInterfaces()[0]).actualTypeArguments().keySet()).hasSize(2).extracting("name").contains("K", "V");
assertThat(inferFrom(ListOfAnyNumbers.class.getGenericInterfaces()[0]).actualTypeArguments().keySet()).hasSize(1).extracting("name").contains("E");
assertThat(inferFrom(Integer.class.getGenericInterfaces()[0]).actualTypeArguments().keySet()).hasSize(1).extracting("name").contains("T");
@@ -114,7 +114,7 @@ public void can_get_type_variables_from_ParameterizedType() throws Exception {
}
@Test
- public void typeVariable_return_type_of____iterator____resolved_to_Iterator_and_type_argument_to_String() throws Exception {
+ public void typeVariable_return_type_of____iterator____resolved_to_Iterator_and_type_argument_to_String() {
GenericMetadataSupport genericMetadata = inferFrom(StringList.class).resolveGenericReturnType(firstNamedMethod("iterator", StringList.class));
assertThat(genericMetadata.rawType()).isEqualTo(Iterator.class);
@@ -122,7 +122,7 @@ public void typeVariable_return_type_of____iterator____resolved_to_Iterator_and_
}
@Test
- public void typeVariable_return_type_of____get____resolved_to_Set_and_type_argument_to_Number() throws Exception {
+ public void typeVariable_return_type_of____get____resolved_to_Set_and_type_argument_to_Number() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("get", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(Set.class);
@@ -130,7 +130,7 @@ public void typeVariable_return_type_of____get____resolved_to_Set_and_type_argum
}
@Test
- public void bounded_typeVariable_return_type_of____returningK____resolved_to_Comparable_and_with_BoundedType() throws Exception {
+ public void bounded_typeVariable_return_type_of____returningK____resolved_to_Comparable_and_with_BoundedType() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returningK", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(Comparable.class);
@@ -139,7 +139,7 @@ public void bounded_typeVariable_return_type_of____returningK____resolved_to_Com
}
@Test
- public void fixed_ParamType_return_type_of____remove____resolved_to_Set_and_type_argument_to_Number() throws Exception {
+ public void fixed_ParamType_return_type_of____remove____resolved_to_Set_and_type_argument_to_Number() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("remove", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(Set.class);
@@ -147,7 +147,7 @@ public void fixed_ParamType_return_type_of____remove____resolved_to_Set_and_type
}
@Test
- public void paramType_return_type_of____values____resolved_to_Collection_and_type_argument_to_Parameterized_Set() throws Exception {
+ public void paramType_return_type_of____values____resolved_to_Collection_and_type_argument_to_Parameterized_Set() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("values", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(Collection.class);
@@ -157,7 +157,7 @@ public void paramType_return_type_of____values____resolved_to_Collection_and_typ
}
@Test
- public void paramType_with_type_parameters_return_type_of____paramType_with_type_params____resolved_to_Collection_and_type_argument_to_Parameterized_Set() throws Exception {
+ public void paramType_with_type_parameters_return_type_of____paramType_with_type_params____resolved_to_Collection_and_type_argument_to_Parameterized_Set() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("paramType_with_type_params", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(List.class);
@@ -166,7 +166,7 @@ public void paramType_with_type_parameters_return_type_of____paramType_with_type
}
@Test
- public void typeVariable_with_type_parameters_return_type_of____typeVar_with_type_params____resolved_K_hence_to_Comparable_and_with_BoundedType() throws Exception {
+ public void typeVariable_with_type_parameters_return_type_of____typeVar_with_type_params____resolved_K_hence_to_Comparable_and_with_BoundedType() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("typeVar_with_type_params", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(Comparable.class);
@@ -175,7 +175,7 @@ public void typeVariable_with_type_parameters_return_type_of____typeVar_with_typ
}
@Test
- public void class_return_type_of____append____resolved_to_StringBuilder_and_type_arguments() throws Exception {
+ public void class_return_type_of____append____resolved_to_StringBuilder_and_type_arguments() {
GenericMetadataSupport genericMetadata = inferFrom(StringBuilder.class).resolveGenericReturnType(firstNamedMethod("append", StringBuilder.class));
assertThat(genericMetadata.rawType()).isEqualTo(StringBuilder.class);
@@ -185,7 +185,7 @@ public void class_return_type_of____append____resolved_to_StringBuilder_and_type
@Test
- public void paramType_with_wildcard_return_type_of____returning_wildcard_with_class_lower_bound____resolved_to_List_and_type_argument_to_Integer() throws Exception {
+ public void paramType_with_wildcard_return_type_of____returning_wildcard_with_class_lower_bound____resolved_to_List_and_type_argument_to_Integer() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returning_wildcard_with_class_lower_bound", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(List.class);
@@ -195,7 +195,7 @@ public void paramType_with_wildcard_return_type_of____returning_wildcard_with_cl
}
@Test
- public void paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_lower_bound____resolved_to_List_and_type_argument_to_Integer() throws Exception {
+ public void paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_lower_bound____resolved_to_List_and_type_argument_to_Integer() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returning_wildcard_with_typeVar_lower_bound", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(List.class);
@@ -205,7 +205,7 @@ public void paramType_with_wildcard_return_type_of____returning_wildcard_with_ty
assertThat(boundedType.interfaceBounds()).contains(Cloneable.class); }
@Test
- public void paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_upper_bound____resolved_to_List_and_type_argument_to_Integer() throws Exception {
+ public void paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_upper_bound____resolved_to_List_and_type_argument_to_Integer() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returning_wildcard_with_typeVar_upper_bound", GenericsNest.class));
assertThat(genericMetadata.rawType()).isEqualTo(List.class);
From aab36909e20fc05660fbf49f706011698f135b1a Mon Sep 17 00:00:00 2001
From: Brice Dutheil
Date: Wed, 27 Feb 2019 16:51:25 +0100
Subject: [PATCH 16/42] Fixes #1621 Now retrieves actual bounds for interfaces
too
It improves the fix in 0cf45e2157e86a06dfd280a7d6e7fce63b4d764b by
looking in early inference phase the bounds of the TypeVariable that
serves as a type argument of a ParameterizedType.
---
.../reflection/GenericMetadataSupport.java | 96 +++++++++-------
.../GenericMetadataSupportTest.java | 107 ++++++++++++++++--
2 files changed, 151 insertions(+), 52 deletions(-)
diff --git a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
index d7838fb612..3c519c1a51 100644
--- a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
+++ b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
@@ -8,8 +8,23 @@
import org.mockito.exceptions.base.MockitoException;
import org.mockito.internal.util.Checks;
-import java.lang.reflect.*;
-import java.util.*;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
/**
@@ -17,20 +32,20 @@
* and accessible members.
*
*
- * The main idea of this code is to create a Map that will help to resolve return types.
- * In order to actually work with nested generics, this map will have to be passed along new instances
- * as a type context.
+ * The main idea of this code is to create a Map that will help to resolve return types.
+ * In order to actually work with nested generics, this map will have to be passed along new instances
+ * as a type context.
*
*
*
- * Hence :
- *
- *
A new instance representing the metadata is created using the {@link #inferFrom(Type)} method from a real
- * Class or from a ParameterizedType, other types are not yet supported.
+ * Hence :
+ *
+ *
A new instance representing the metadata is created using the {@link #inferFrom(Type)} method from a real
+ * Class or from a ParameterizedType, other types are not yet supported.
*
- *
Then from this metadata, we can extract meta-data for a generic return type of a method, using
- * {@link #resolveGenericReturnType(Method)}.
- *
+ *
Then from this metadata, we can extract meta-data for a generic return type of a method, using
+ * {@link #resolveGenericReturnType(Method)}.
+ *
*
*
*
@@ -98,19 +113,10 @@ protected Class> extractRawTypeOf(Type type) {
if (type instanceof TypeVariable) {
/*
* If type is a TypeVariable, then it is needed to gather data elsewhere.
- * Usually TypeVariables are declared on the class definition, such as
- * such as List.
- *
- * If the data cannot be found in the contextual map, try harder on the
- * TypeVariable itself looking for defined bounds.
+ * Usually TypeVariables are declared on the class definition, such as such
+ * as List.
*/
- Type typeArgument = contextualActualTypeParameters.get(type);
- if (typeArgument == null) {
- BoundedType boundedType = boundsOf((TypeVariable>) type);
- contextualActualTypeParameters.put((TypeVariable>) type, boundedType);
- return extractRawTypeOf(boundedType);
- }
- return extractRawTypeOf(typeArgument);
+ return extractRawTypeOf(contextualActualTypeParameters.get(type));
}
throw new MockitoException("Raw extraction not supported for : '" + type + "'");
}
@@ -126,10 +132,21 @@ protected void registerTypeVariablesOn(Type classType) {
TypeVariable> typeParameter = typeParameters[i];
Type actualTypeArgument = actualTypeArguments[i];
- // Prevent registration of a cycle of TypeVariables. This can happen when we are processing
- // type parameters in a Method, while we already processed the type parameters of a class.
- if (actualTypeArgument instanceof TypeVariable && contextualActualTypeParameters.containsKey(typeParameter)) {
- continue;
+ if (actualTypeArgument instanceof TypeVariable) {
+ /*
+ * If actualTypeArgument is a TypeVariable, and it is not present in
+ * the context map then it is needed to try harder to gather more data
+ * from the type argument itself. In some case the type argument do
+ * define upper bounds, this allow to look for them if not in the
+ * context map.
+ */
+ registerTypeVariableIfNotPresent((TypeVariable>) actualTypeArgument);
+
+ // Prevent registration of a cycle of TypeVariables. This can happen when we are processing
+ // type parameters in a Method, while we already processed the type parameters of a class.
+ if (contextualActualTypeParameters.containsKey(typeParameter)) {
+ continue;
+ }
}
if (actualTypeArgument instanceof WildcardType) {
@@ -157,7 +174,7 @@ private void registerTypeVariableIfNotPresent(TypeVariable> typeVariable) {
/**
* @param typeParameter The TypeVariable parameter
* @return A {@link BoundedType} for easy bound information, if first bound is a TypeVariable
- * then retrieve BoundedType of this TypeVariable
+ * then retrieve BoundedType of this TypeVariable
*/
private BoundedType boundsOf(TypeVariable> typeParameter) {
if (typeParameter.getBounds()[0] instanceof TypeVariable) {
@@ -169,7 +186,7 @@ private BoundedType boundsOf(TypeVariable> typeParameter) {
/**
* @param wildCard The WildCard type
* @return A {@link BoundedType} for easy bound information, if first bound is a TypeVariable
- * then retrieve BoundedType of this TypeVariable
+ * then retrieve BoundedType of this TypeVariable
*/
private BoundedType boundsOf(WildcardType wildCard) {
/*
@@ -255,7 +272,7 @@ public GenericMetadataSupport resolveGenericReturnType(Method method) {
// logger.log("Method '" + method.toGenericString() + "' has return type : " + genericReturnType.getClass().getInterfaces()[0].getSimpleName() + " : " + genericReturnType);
int arity = 0;
- while(genericReturnType instanceof GenericArrayType) {
+ while (genericReturnType instanceof GenericArrayType) {
arity++;
genericReturnType = ((GenericArrayType) genericReturnType).getGenericComponentType();
}
@@ -287,8 +304,8 @@ private GenericMetadataSupport resolveGenericType(Type type, Method method) {
* Create an new instance of {@link GenericMetadataSupport} inferred from a {@link Type}.
*
*
- * At the moment type can only be a {@link Class} or a {@link ParameterizedType}, otherwise
- * it'll throw a {@link MockitoException}.
+ * At the moment type can only be a {@link Class} or a {@link ParameterizedType}, otherwise
+ * it'll throw a {@link MockitoException}.
*
*
* @param type The class from which the {@link GenericMetadataSupport} should be built.
@@ -314,7 +331,7 @@ public static GenericMetadataSupport inferFrom(Type type) {
/**
* Generic metadata implementation for {@link Class}.
- *
+ *
* Offer support to retrieve generic metadata on a {@link Class} by reading type parameters and type variables on
* the class and its ancestors and interfaces.
*/
@@ -336,10 +353,10 @@ public Class> rawType() {
/**
* Generic metadata implementation for "standalone" {@link ParameterizedType}.
- *
+ *
* Offer support to retrieve generic metadata on a {@link ParameterizedType} by reading type variables of
* the related raw type and declared type variable of this parameterized type.
- *
+ *
* This class is not designed to work on ParameterizedType returned by {@link Method#getGenericReturnType()}, as
* the ParameterizedType instance return in these cases could have Type Variables that refer to type declaration(s).
* That's what meant the "standalone" word at the beginning of the Javadoc.
@@ -419,7 +436,7 @@ private void readTypeVariables() {
for (Type type : typeVariable.getBounds()) {
registerTypeVariablesOn(type);
}
- registerTypeParametersOn(new TypeVariable[] { typeVariable });
+ registerTypeParametersOn(new TypeVariable[]{typeVariable});
registerTypeVariablesOn(getActualTypeArgumentFor(typeVariable));
}
@@ -456,7 +473,7 @@ public Class>[] rawExtraInterfaces() {
for (Type extraInterface : extraInterfaces) {
Class> rawInterface = extractRawTypeOf(extraInterface);
// avoid interface collision with actual raw type (with typevariables, resolution ca be quite aggressive)
- if(!rawType().equals(rawInterface)) {
+ if (!rawType().equals(rawInterface)) {
rawExtraInterfaces.add(rawInterface);
}
}
@@ -528,7 +545,6 @@ public Class> rawType() {
}
-
/**
* Type representing bounds of a type
*
@@ -551,7 +567,7 @@ public interface BoundedType extends Type {
*
*
If upper bounds are declared with SomeClass and additional interfaces, then firstBound will be SomeClass and
* interfacesBound will be an array of the additional interfaces.
- *
+ *
* i.e. SomeClass.
*
* interface UpperBoundedTypeWithClass & Cloneable> {
diff --git a/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java b/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
index 57d0cb2925..cc5b5885d1 100644
--- a/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
+++ b/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
@@ -8,9 +8,11 @@
import java.io.Serializable;
import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@@ -26,42 +28,66 @@ public class GenericMetadataSupportTest {
interface GenericsSelfReference> {
T self();
}
+
interface UpperBoundedTypeWithClass> {
E get();
}
+
interface UpperBoundedTypeWithInterfaces & Cloneable> {
E get();
}
- interface ListOfNumbers extends List {}
- interface AnotherListOfNumbers extends ListOfNumbers {}
- abstract class ListOfNumbersImpl implements ListOfNumbers {}
- abstract class AnotherListOfNumbersImpl extends ListOfNumbersImpl {}
+ interface ListOfNumbers extends List {
+ }
- interface ListOfAnyNumbers extends List {}
+ interface AnotherListOfNumbers extends ListOfNumbers {
+ }
+
+ abstract class ListOfNumbersImpl implements ListOfNumbers {
+ }
+
+ abstract class AnotherListOfNumbersImpl extends ListOfNumbersImpl {
+ }
+
+ interface ListOfAnyNumbers extends List {
+ }
interface GenericsNest & Cloneable> extends Map> {
Set remove(Object key); // override with fixed ParameterizedType
+
List super Integer> returning_wildcard_with_class_lower_bound();
+
List super K> returning_wildcard_with_typeVar_lower_bound();
+
List extends K> returning_wildcard_with_typeVar_upper_bound();
+
K returningK();
+
List paramType_with_type_params();
+
T two_type_params();
+
O typeVar_with_type_params();
}
- static class StringList extends ArrayList { }
+ static class StringList extends ArrayList {
+ }
public interface TopInterface {
T generic();
}
- public interface MiddleInterface extends TopInterface { }
- public class OwningClassWithDeclaredUpperBounds & Comparable> {
- public abstract class AbstractInner implements MiddleInterface { }
+
+ public interface MiddleInterface extends TopInterface {
+ }
+
+ public class OwningClassWithDeclaredUpperBounds & Comparable & Cloneable> {
+ public abstract class AbstractInner implements MiddleInterface {
+ }
}
+
public class OwningClassWithNoDeclaredUpperBounds {
- public abstract class AbstractInner implements MiddleInterface { }
+ public abstract class AbstractInner implements MiddleInterface {
+ }
}
@Test
@@ -183,7 +209,6 @@ public void class_return_type_of____append____resolved_to_StringBuilder_and_type
}
-
@Test
public void paramType_with_wildcard_return_type_of____returning_wildcard_with_class_lower_bound____resolved_to_List_and_type_argument_to_Integer() {
GenericMetadataSupport genericMetadata = inferFrom(GenericsNest.class).resolveGenericReturnType(firstNamedMethod("returning_wildcard_with_class_lower_bound", GenericsNest.class));
@@ -202,7 +227,8 @@ public void paramType_with_wildcard_return_type_of____returning_wildcard_with_ty
GenericMetadataSupport.BoundedType boundedType = (GenericMetadataSupport.BoundedType) typeVariableValue(genericMetadata.actualTypeArguments(), "E");
assertThat(inferFrom(boundedType.firstBound()).rawType()).isEqualTo(Comparable.class);
- assertThat(boundedType.interfaceBounds()).contains(Cloneable.class); }
+ assertThat(boundedType.interfaceBounds()).contains(Cloneable.class);
+ }
@Test
public void paramType_with_wildcard_return_type_of____returning_wildcard_with_typeVar_upper_bound____resolved_to_List_and_type_argument_to_Integer() {
@@ -227,6 +253,63 @@ public void can_extract_raw_type_from_bounds_on_terminal_typeVariable() {
).isEqualTo(Object.class);
}
+ @Test
+ public void can_extract_interface_type_from_bounds_on_terminal_typeVariable() {
+
+ assertThat(inferFrom(OwningClassWithDeclaredUpperBounds.AbstractInner.class)
+ .resolveGenericReturnType(firstNamedMethod("generic", OwningClassWithDeclaredUpperBounds.AbstractInner.class))
+ .rawExtraInterfaces()
+ ).containsExactly(Comparable.class, Cloneable.class);
+ assertThat(inferFrom(OwningClassWithDeclaredUpperBounds.AbstractInner.class)
+ .resolveGenericReturnType(firstNamedMethod("generic", OwningClassWithDeclaredUpperBounds.AbstractInner.class))
+ .extraInterfaces()
+ ).containsExactly(parameterizedTypeOf(Comparable.class, null, String.class),
+ Cloneable.class);
+
+ assertThat(inferFrom(OwningClassWithNoDeclaredUpperBounds.AbstractInner.class)
+ .resolveGenericReturnType(firstNamedMethod("generic", OwningClassWithNoDeclaredUpperBounds.AbstractInner.class))
+ .extraInterfaces()
+ ).isEmpty();
+ }
+
+ private ParameterizedType parameterizedTypeOf(final Class> rawType, final Class> ownerType, final Type... actualTypeArguments) {
+ return new ParameterizedType() {
+ @Override
+ public Type[] getActualTypeArguments() {
+ return actualTypeArguments;
+ }
+
+ @Override
+ public Type getRawType() {
+ return rawType;
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return ownerType;
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof ParameterizedType) {
+ ParameterizedType otherParamType = (ParameterizedType) other;
+ if (this == otherParamType) {
+ return true;
+ } else {
+ return equals(ownerType, otherParamType.getOwnerType())
+ && equals(rawType, otherParamType.getRawType())
+ && Arrays.equals(actualTypeArguments, otherParamType.getActualTypeArguments());
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private boolean equals(Object a, Object b) {
+ return (a == b) || (a != null && a.equals(b));
+ }
+ };
+ }
+
private Type typeVariableValue(Map, Type> typeVariables, String typeVariableName) {
for (Map.Entry, Type> typeVariableTypeEntry : typeVariables.entrySet()) {
if (typeVariableTypeEntry.getKey().getName().equals(typeVariableName)) {
From 20416a3c3ed6bac2f54a15f20c98f3a75ec7656b Mon Sep 17 00:00:00 2001
From: Szczepan Faber
Date: Thu, 13 Sep 2018 14:55:24 -0700
Subject: [PATCH 17/42] Exposed new public API - StubbingLookupListener
The API was used internally to implement strict stubbing features. We want to expose the lower level public API that we use internally to make Mockito more flexible.
Fixes #793
---
src/main/java/org/mockito/MockSettings.java | 19 +++
.../internal/creation/MockSettingsImpl.java | 27 ++--
.../creation/settings/CreationSettings.java | 8 +-
.../mockito/internal/exceptions/Reporter.java | 4 +-
.../junit/DefaultStubbingLookupListener.java | 4 +-
.../junit/StrictStubsRunnerTestListener.java | 4 +-
.../listeners/StubbingLookupNotifier.java | 2 +
.../listeners/StubbingLookupEvent.java | 2 +-
.../listeners/StubbingLookupListener.java | 18 ++-
.../mockito/mock/MockCreationSettings.java | 9 +-
.../creation/MockSettingsImplTest.java | 68 ++++++++
.../listeners/StubbingLookupNotifierTest.java | 1 +
.../StubbingLookupListenerCallbackTest.java | 153 ++++++++++++++++++
13 files changed, 289 insertions(+), 30 deletions(-)
rename src/main/java/org/mockito/{internal => }/listeners/StubbingLookupEvent.java (95%)
rename src/main/java/org/mockito/{internal => }/listeners/StubbingLookupListener.java (62%)
create mode 100644 src/test/java/org/mockitousage/debugging/StubbingLookupListenerCallbackTest.java
diff --git a/src/main/java/org/mockito/MockSettings.java b/src/main/java/org/mockito/MockSettings.java
index c79c243175..bf98c2af6e 100644
--- a/src/main/java/org/mockito/MockSettings.java
+++ b/src/main/java/org/mockito/MockSettings.java
@@ -9,6 +9,7 @@
import org.mockito.invocation.InvocationFactory;
import org.mockito.invocation.MockHandler;
import org.mockito.listeners.InvocationListener;
+import org.mockito.listeners.StubbingLookupListener;
import org.mockito.listeners.VerificationStartedListener;
import org.mockito.mock.MockCreationSettings;
import org.mockito.mock.SerializableMode;
@@ -203,6 +204,24 @@ public interface MockSettings extends Serializable {
*/
MockSettings verboseLogging();
+ /**
+ * Add stubbing lookup listener to the mock object.
+ *
+ * Multiple listeners may be added and they will be notified in the order they were supplied.
+ *
+ * For use cases and more info see {@link StubbingLookupListener}
+ *
+ * Example:
+ *
+ * List mockWithListener = mock(List.class, withSettings().stubbingLookupListeners(new YourStubbingLookupListener()));
+ *
+ *
+ * @param listeners The stubbing lookup listeners to add. May not be null.
+ * @return settings instance so that you can fluently specify other settings
+ * @since TODO x here and everywhere else
+ */
+ MockSettings stubbingLookupListeners(StubbingLookupListener... listeners);
+
/**
* Registers a listener for method invocations on this mock. The listener is
* notified every time a method on this mock is called.
diff --git a/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java b/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java
index ca67730793..d842e3e8e3 100644
--- a/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java
+++ b/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java
@@ -11,6 +11,7 @@
import org.mockito.internal.util.MockCreationValidator;
import org.mockito.internal.util.MockNameImpl;
import org.mockito.listeners.InvocationListener;
+import org.mockito.listeners.StubbingLookupListener;
import org.mockito.listeners.VerificationStartedListener;
import org.mockito.mock.MockCreationSettings;
import org.mockito.mock.MockName;
@@ -19,17 +20,17 @@
import java.io.Serializable;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import static java.util.Arrays.asList;
import static org.mockito.internal.exceptions.Reporter.defaultAnswerDoesNotAcceptNullParameter;
import static org.mockito.internal.exceptions.Reporter.extraInterfacesAcceptsOnlyInterfaces;
import static org.mockito.internal.exceptions.Reporter.extraInterfacesDoesNotAcceptNullParameters;
import static org.mockito.internal.exceptions.Reporter.extraInterfacesRequiresAtLeastOneInterface;
-import static org.mockito.internal.exceptions.Reporter.invocationListenersRequiresAtLeastOneListener;
import static org.mockito.internal.exceptions.Reporter.methodDoesNotAcceptParameter;
+import static org.mockito.internal.exceptions.Reporter.requiresAtLeastOneListener;
import static org.mockito.internal.util.collections.Sets.newSet;
@SuppressWarnings("unchecked")
@@ -154,7 +155,7 @@ public Object[] getConstructorArgs() {
}
List
*
*
+ *
However this answer does not support generics information when the mock has been deserialized.
+ *
* @see org.mockito.Mockito#RETURNS_DEEP_STUBS
* @see org.mockito.Answers#RETURNS_DEEP_STUBS
*/
@@ -46,21 +48,21 @@ public class ReturnsDeepStubs implements Answer, Serializable {
public Object answer(InvocationOnMock invocation) throws Throwable {
GenericMetadataSupport returnTypeGenericMetadata =
- actualParameterizedType(invocation.getMock()).resolveGenericReturnType(invocation.getMethod());
+ actualParameterizedType(invocation.getMock()).resolveGenericReturnType(invocation.getMethod());
Class> rawType = returnTypeGenericMetadata.rawType();
if (!mockitoCore().isTypeMockable(rawType)) {
return delegate().returnValueFor(rawType);
}
- // When dealing with erasured generics, we only receive the Object type as rawType. At this
+ // When dealing with erased generics, we only receive the Object type as rawType. At this
// point, there is nothing to salvage for Mockito. Instead of trying to be smart and generate
// a mock that would potentially match the return signature, instead return `null`. This
// is valid per the CheckCast JVM instruction and is better than causing a ClassCastException
// on runtime.
-// if (rawType.equals(Object.class)) {
-// return null;
-// }
+ if (rawType.equals(Object.class) && !returnTypeGenericMetadata.hasRawExtraInterfaces()) {
+ return null;
+ }
return deepStub(invocation, returnTypeGenericMetadata);
}
@@ -78,9 +80,9 @@ private Object deepStub(InvocationOnMock invocation, GenericMetadataSupport retu
// record deep stub answer
StubbedInvocationMatcher stubbing = recordDeepStubAnswer(
- newDeepStubMock(returnTypeGenericMetadata, invocation.getMock()),
- container
- );
+ newDeepStubMock(returnTypeGenericMetadata, invocation.getMock()),
+ container
+ );
// deep stubbing creates a stubbing and immediately uses it
// so the stubbing is actually used by the same invocation
@@ -97,24 +99,24 @@ private Object deepStub(InvocationOnMock invocation, GenericMetadataSupport retu
* {@link ReturnsDeepStubs} answer in which we will store the returned type generic metadata.
*
* @param returnTypeGenericMetadata The metadata to use to create the new mock.
- * @param parentMock The parent of the current deep stub mock.
+ * @param parentMock The parent of the current deep stub mock.
* @return The mock
*/
private Object newDeepStubMock(GenericMetadataSupport returnTypeGenericMetadata, Object parentMock) {
MockCreationSettings parentMockSettings = MockUtil.getMockSettings(parentMock);
return mockitoCore().mock(
- returnTypeGenericMetadata.rawType(),
- withSettingsUsing(returnTypeGenericMetadata, parentMockSettings)
- );
+ returnTypeGenericMetadata.rawType(),
+ withSettingsUsing(returnTypeGenericMetadata, parentMockSettings)
+ );
}
private MockSettings withSettingsUsing(GenericMetadataSupport returnTypeGenericMetadata, MockCreationSettings parentMockSettings) {
MockSettings mockSettings = returnTypeGenericMetadata.hasRawExtraInterfaces() ?
- withSettings().extraInterfaces(returnTypeGenericMetadata.rawExtraInterfaces())
- : withSettings();
+ withSettings().extraInterfaces(returnTypeGenericMetadata.rawExtraInterfaces())
+ : withSettings();
return propagateSerializationSettings(mockSettings, parentMockSettings)
- .defaultAnswer(returnsDeepStubsAnswerUsing(returnTypeGenericMetadata));
+ .defaultAnswer(returnsDeepStubsAnswerUsing(returnTypeGenericMetadata));
}
private MockSettings propagateSerializationSettings(MockSettings mockSettings, MockCreationSettings parentMockSettings) {
@@ -148,6 +150,15 @@ public ReturnsDeepStubsSerializationFallback(GenericMetadataSupport returnTypeGe
protected GenericMetadataSupport actualParameterizedType(Object mock) {
return returnTypeGenericMetadata;
}
+
+ /**
+ * Generics support and serialization with deep stubs don't work together.
+ *
+ * The issue is that GenericMetadataSupport is not serializable because
+ * the type elements inferred via reflection are not serializable. Supporting
+ * serialization would require to replace all types coming from the Java reflection
+ * with our own and still managing type equality with the JDK ones.
+ */
private Object writeReplace() throws IOException {
return Mockito.RETURNS_DEEP_STUBS;
}
@@ -161,6 +172,7 @@ private static class DeeplyStubbedAnswer implements Answer, Serializable
DeeplyStubbedAnswer(Object mock) {
this.mock = mock;
}
+
public Object answer(InvocationOnMock invocation) throws Throwable {
return mock;
}
diff --git a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
index 3c519c1a51..80cbf65be3 100644
--- a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
+++ b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
@@ -418,6 +418,7 @@ private static class TypeVariableReturnType extends GenericMetadataSupport {
private final TypeVariable> typeVariable;
private final TypeVariable>[] typeParameters;
private Class> rawType;
+ private List extraInterfaces;
public TypeVariableReturnType(GenericMetadataSupport source, TypeVariable>[] typeParameters, TypeVariable> typeVariable) {
this.typeParameters = typeParameters;
@@ -450,15 +451,18 @@ public Class> rawType() {
@Override
public List extraInterfaces() {
+ if (extraInterfaces != null) {
+ return extraInterfaces;
+ }
Type type = extractActualBoundedTypeOf(typeVariable);
if (type instanceof BoundedType) {
- return Arrays.asList(((BoundedType) type).interfaceBounds());
+ return extraInterfaces = Arrays.asList(((BoundedType) type).interfaceBounds());
}
if (type instanceof ParameterizedType) {
- return Collections.singletonList(type);
+ return extraInterfaces = Collections.singletonList(type);
}
if (type instanceof Class) {
- return Collections.emptyList();
+ return extraInterfaces = Collections.emptyList();
}
throw new MockitoException("Cannot extract extra-interfaces from '" + typeVariable + "' : '" + type + "'");
}
diff --git a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
index 40b9ecb575..b051e124a8 100644
--- a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
@@ -5,11 +5,14 @@
package org.mockito.internal.stubbing.defaultanswers;
import org.junit.Test;
+import org.mockitousage.examples.use.Article;
+import java.io.Closeable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Callable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -18,18 +21,27 @@
@SuppressWarnings("unused")
public class ReturnsGenericDeepStubsTest {
- interface ListOfInteger extends List {}
+ interface ListOfInteger extends List {
+ }
- interface AnotherListOfInteger extends ListOfInteger {}
+ interface AnotherListOfInteger extends ListOfInteger {
+ }
interface GenericsNest & Cloneable> extends Map> {
Set remove(Object key); // override with fixed ParameterizedType
+
List super Number> returningWildcard();
+
Map returningNonMockableNestedGeneric();
+
K returningK();
+
List paramTypeWithTypeParams();
+
T twoTypeParams(S s);
+
O typeVarWithTypeParams();
+
Number returnsNormalType();
}
@@ -38,7 +50,7 @@ public void generic_deep_mock_frenzy__look_at_these_chained_calls() {
GenericsNest> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
Set extends Map.Entry extends Cloneable, Set>> entries = mock.entrySet();
- Iterator extends Map.Entry extends Cloneable,Set>> entriesIterator = mock.entrySet().iterator();
+ Iterator extends Map.Entry extends Cloneable, Set>> entriesIterator = mock.entrySet().iterator();
Map.Entry extends Cloneable, Set> nextEntry = mock.entrySet().iterator().next();
Cloneable cloneableKey = mock.entrySet().iterator().next().getKey();
@@ -54,9 +66,9 @@ public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_
GenericsNest> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
Cloneable cloneable_bound_that_is_declared_on_typevar_K_in_the_class_which_is_referenced_by_typevar_O_declared_on_the_method =
- mock.paramTypeWithTypeParams().get(0);
+ mock.paramTypeWithTypeParams().get(0);
Comparable> comparable_bound_that_is_declared_on_typevar_K_in_the_class_which_is_referenced_by_typevar_O_declared_on_the_method =
- mock.paramTypeWithTypeParams().get(0);
+ mock.paramTypeWithTypeParams().get(0);
}
@Test
@@ -109,7 +121,7 @@ public void as_expected_fail_with_a_CCE_on_call_site_when_erasure_takes_place_fo
// following assignment needed to create a ClassCastException on the call site (i.e. : here)
StringBuilder stringBuilder_assignment_that_should_throw_a_CCE =
- mock.twoTypeParams(new StringBuilder()).append(2).append(3);
+ mock.twoTypeParams(new StringBuilder()).append(2).append(3);
}
class WithGenerics {
@@ -117,7 +129,9 @@ T execute() {
throw new IllegalArgumentException();
}
}
- class SubClass extends WithGenerics {}
+
+ class SubClass extends WithGenerics {
+ }
class UserOfSubClass {
SubClass generate() {
@@ -133,4 +147,49 @@ public void can_handle_deep_stubs_with_generics_at_end_of_deep_invocation() {
assertThat(mock.generate().execute()).isEqualTo("sub");
}
+
+ public interface TopInterface {
+ T generic();
+ }
+
+ public interface MiddleInterface extends TopInterface {
+ }
+
+ public class OwningClassWithDeclaredUpperBounds & Callable & Closeable> {
+ public abstract class AbstractInner implements MiddleInterface {
+ }
+ }
+
+ @Test
+ public void cannot_handle_deep_stubs_with_generics_declared_upper_bounds_at_end_of_deep_invocation() throws Exception {
+ OwningClassWithDeclaredUpperBounds.AbstractInner mock =
+ mock(OwningClassWithDeclaredUpperBounds.AbstractInner.class, RETURNS_DEEP_STUBS);
+
+ // It seems that while the syntax used on OwningClassWithDeclaredUpperBounds.AbstractInner
+ // appear to be legal, the javac compiler does not follow through
+ // hence we need casting, this may also explain why GenericMetadataSupport has trouble to
+ // extract matching data as well.
+
+ assertThat(mock.generic())
+ .describedAs("mock should implement first bound : 'Iterable'")
+ .isInstanceOf(Iterable.class);
+ assertThat(((Iterable) mock.generic()).iterator())
+ .describedAs("Iterable returns Iterator").isInstanceOf(Iterator.class);
+ assertThat(((Iterable) mock.generic()).iterator().next())
+ .describedAs("Cannot yet extract Type argument 'Article' so return null instead of a mock "
+ + "of type Object (which would raise CCE on the call-site)")
+ .isNull();
+
+ assertThat(mock.generic())
+ .describedAs("mock should implement second interface bound : 'Callable'")
+ .isInstanceOf(Callable.class);
+ assertThat(((Callable) mock.generic()).call())
+ .describedAs("Cannot yet extract Type argument 'Article' so return null instead of a mock "
+ + "of type Object (which would raise CCE on the call-site)")
+ .isNull();
+
+ assertThat(mock.generic())
+ .describedAs("mock should implement third interface bound : 'Closeable'")
+ .isInstanceOf(Closeable.class);
+ }
}
diff --git a/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java b/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
index e3891c6047..c26e8d8b57 100644
--- a/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
+++ b/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
@@ -62,8 +62,8 @@ public void should_discard_generics_metadata_when_serialized_then_disabling_deep
// then revert to the default RETURNS_DEEP_STUBS and the code will raise a ClassCastException
when(deserialized_deep_stub.iterator().next().get(42)).thenReturn("no");
fail("Expected an exception to be thrown as deep stubs and serialization does not play well together");
- } catch (ClassCastException e) {
- assertThat(e).hasMessageContaining("java.util.List");
+ } catch (NullPointerException e) {
+ assertThat(e).hasMessage(null);
}
}
From f377d0e27ffe189554367c53dd5f00a09452d2b6 Mon Sep 17 00:00:00 2001
From: epeee
Date: Mon, 4 Mar 2019 18:32:03 +0100
Subject: [PATCH 37/42] Update shipkit plugin (v2.1.6) and increase the version
since we already have a tag for 2.24.8
---
build.gradle | 2 +-
version.properties | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/build.gradle b/build.gradle
index c8142db658..4285ff16ff 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,7 +11,7 @@ buildscript {
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.6'
//Using buildscript.classpath so that we can resolve shipkit from maven local, during local testing
- classpath 'org.shipkit:shipkit:2.1.3'
+ classpath 'org.shipkit:shipkit:2.1.6'
}
}
diff --git a/version.properties b/version.properties
index 5c5d37b0ac..19b0042628 100644
--- a/version.properties
+++ b/version.properties
@@ -1,5 +1,5 @@
#Currently building Mockito version
-version=2.24.8
+version=2.24.9
#Previous version used to generate release notes delta
previousVersion=2.24.7
From 0cf38225c58fcf7dfe49780c987516ff53048c6e Mon Sep 17 00:00:00 2001
From: shipkit-org
Date: Mon, 4 Mar 2019 18:01:24 +0000
Subject: [PATCH 38/42] 2.24.9 release (previous 2.24.7) + release notes
updated by CI build 3944
[ci skip-release]
---
doc/release-notes/official.md | 14 ++++++++++++++
version.properties | 4 ++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/doc/release-notes/official.md b/doc/release-notes/official.md
index fb9e03e427..e627ceeab5 100644
--- a/doc/release-notes/official.md
+++ b/doc/release-notes/official.md
@@ -1,5 +1,19 @@
*Release notes were automatically generated by [Shipkit](http://shipkit.org/)*
+#### 2.24.9
+ - 2019-03-04 - [12 commits](https://github.com/mockito/mockito/compare/v2.24.7...v2.24.9) by 6 authors - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.9-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.9)
+ - Commits: [Brice Dutheil](https://github.com/bric3) (5), [Tim van der Lippe](https://github.com/TimvdLippe) (3), [epeee](https://github.com/epeee) (1), [Fr Jeremy Krieg](https://github.com/kriegfrj) (1), [Paweł Pamuła](https://github.com/PawelPamula) (1), shipkit-org (1)
+ - [Java 9 support] ClassCastExceptions with JDK9 javac [(#357)](https://github.com/mockito/mockito/issues/357)
+ - [Bugfixes] RETURNS_DEEP_STUBS causes "Raw extraction not supported for : 'null'" in some cases [(#1621)](https://github.com/mockito/mockito/issues/1621)
+ - Update shipkit plugin (v2.1.6) [(#1647)](https://github.com/mockito/mockito/pull/1647)
+ - VerificationCollector to handle non-matching args and other assertions [(#1644)](https://github.com/mockito/mockito/pull/1644)
+ - VerificationCollector doesn't work for invocations with non-matching args [(#1642)](https://github.com/mockito/mockito/issues/1642)
+ - Fix returns mocks for final classes [(#1641)](https://github.com/mockito/mockito/pull/1641)
+ - Removes inaccessible links from javadocs in Mockito.java [(#1639)](https://github.com/mockito/mockito/pull/1639)
+ - Mockito.java contains inaccessible links to articles. [(#1638)](https://github.com/mockito/mockito/issues/1638)
+ - Handle terminal type var with bounds [(#1624)](https://github.com/mockito/mockito/pull/1624)
+ - Return null instead of causing a CCE [(#1612)](https://github.com/mockito/mockito/pull/1612)
+
#### 2.24.7
- 2019-02-28 - [2 commits](https://github.com/mockito/mockito/compare/v2.24.6...v2.24.7) by [shipkit-org](https://github.com/shipkit-org) (1), [Tim van der Lippe](https://github.com/TimvdLippe) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.7-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.7)
- Fix handling of generics in ReturnsMocks [(#1635)](https://github.com/mockito/mockito/pull/1635)
diff --git a/version.properties b/version.properties
index 19b0042628..3fa30ed621 100644
--- a/version.properties
+++ b/version.properties
@@ -1,8 +1,8 @@
#Currently building Mockito version
-version=2.24.9
+version=2.24.10
#Previous version used to generate release notes delta
-previousVersion=2.24.7
+previousVersion=2.24.9
#Not published currently, see https://github.com/mockito/mockito/issues/962
mockito.testng.version=1.0
From b5e9400b01f8bfbda436c79ce5f857b3dc613657 Mon Sep 17 00:00:00 2001
From: Tim van der Lippe
Date: Mon, 4 Mar 2019 18:22:03 +0000
Subject: [PATCH 39/42] Prevent NPE in findTypeFromGenericInArguments
There was only a single test failing on this. I think the issue was RETURNS_SMART_NULLS in combination with an ArgumentCaptor, but
couldn't figure that part out. At least this fixes prevented the NPE.
---
.../defaultanswers/RetrieveGenericsForDefaultAnswers.java | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java
index 021283dc65..09fb182b9d 100644
--- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java
+++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java
@@ -114,7 +114,13 @@ private static Class> findTypeFromGenericInArguments(final InvocationOnMock in
for (int i = 0; i < parameterTypes.length; i++) {
Type argType = parameterTypes[i];
if (returnType.equals(argType)) {
- return invocation.getArgument(i).getClass();
+ Object argument = invocation.getArgument(i);
+
+ if (argument == null) {
+ return null;
+ }
+
+ return argument.getClass();
}
if (argType instanceof GenericArrayType) {
argType = ((GenericArrayType) argType).getGenericComponentType();
From 2d21a5abc744084646d9939d5ed9d1825695af9a Mon Sep 17 00:00:00 2001
From: Tim van der Lippe
Date: Tue, 5 Mar 2019 14:49:36 +0000
Subject: [PATCH 40/42] Add regression test
---
.../mockitousage/stubbing/SmartNullsStubbingTest.java | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/test/java/org/mockitousage/stubbing/SmartNullsStubbingTest.java b/src/test/java/org/mockitousage/stubbing/SmartNullsStubbingTest.java
index 9b3dc868d1..8e27f73100 100644
--- a/src/test/java/org/mockitousage/stubbing/SmartNullsStubbingTest.java
+++ b/src/test/java/org/mockitousage/stubbing/SmartNullsStubbingTest.java
@@ -42,6 +42,15 @@ public void shouldSmartNPEPointToUnstubbedCall() throws Exception {
}
}
+ @Test
+ public void should_not_throw_NPE_when_verifying_with_returns_smart_nulls() {
+ Foo mock = mock(Foo.class, RETURNS_SMART_NULLS);
+
+ when(mock.returnsFromArg(null)).thenReturn("Does not fail.");
+
+ assertThat((Object) mock.returnsFromArg(null)).isEqualTo("Does not fail.");
+ }
+
interface Bar {
void boo();
}
@@ -59,6 +68,8 @@ Bar getBarWithParams(int x, String y) {
return null;
}
+ T returnsFromArg(T arg) { return arg; }
+
void boo() {}
}
From 2894895746950be644af81055bf7543ff4e9f832 Mon Sep 17 00:00:00 2001
From: Tim van der Lippe
Date: Tue, 5 Mar 2019 14:52:30 +0000
Subject: [PATCH 41/42] Fix checkstyle warnings
---
.../defaultanswers/RetrieveGenericsForDefaultAnswers.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java
index 09fb182b9d..979c8f7813 100644
--- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java
+++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/RetrieveGenericsForDefaultAnswers.java
@@ -115,11 +115,11 @@ private static Class> findTypeFromGenericInArguments(final InvocationOnMock in
Type argType = parameterTypes[i];
if (returnType.equals(argType)) {
Object argument = invocation.getArgument(i);
-
+
if (argument == null) {
return null;
}
-
+
return argument.getClass();
}
if (argType instanceof GenericArrayType) {
From af2d33be7fbfecad172cef4da2127b8d9a6fbe31 Mon Sep 17 00:00:00 2001
From: shipkit-org
Date: Tue, 5 Mar 2019 15:49:22 +0000
Subject: [PATCH 42/42] 2.24.10 release (previous 2.24.9) + release notes
updated by CI build 3953
[ci skip-release]
---
doc/release-notes/official.md | 4 ++++
version.properties | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/doc/release-notes/official.md b/doc/release-notes/official.md
index e627ceeab5..752360b3c8 100644
--- a/doc/release-notes/official.md
+++ b/doc/release-notes/official.md
@@ -1,5 +1,9 @@
*Release notes were automatically generated by [Shipkit](http://shipkit.org/)*
+#### 2.24.10
+ - 2019-03-05 - [4 commits](https://github.com/mockito/mockito/compare/v2.24.9...v2.24.10) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.10-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.10)
+ - Prevent NPE in findTypeFromGenericInArguments [(#1648)](https://github.com/mockito/mockito/pull/1648)
+
#### 2.24.9
- 2019-03-04 - [12 commits](https://github.com/mockito/mockito/compare/v2.24.7...v2.24.9) by 6 authors - published to [![Bintray](https://img.shields.io/badge/Bintray-2.24.9-green.svg)](https://bintray.com/mockito/maven/mockito-development/2.24.9)
- Commits: [Brice Dutheil](https://github.com/bric3) (5), [Tim van der Lippe](https://github.com/TimvdLippe) (3), [epeee](https://github.com/epeee) (1), [Fr Jeremy Krieg](https://github.com/kriegfrj) (1), [Paweł Pamuła](https://github.com/PawelPamula) (1), shipkit-org (1)
diff --git a/version.properties b/version.properties
index 3fa30ed621..61a6e09815 100644
--- a/version.properties
+++ b/version.properties
@@ -1,8 +1,8 @@
#Currently building Mockito version
-version=2.24.10
+version=2.24.11
#Previous version used to generate release notes delta
-previousVersion=2.24.9
+previousVersion=2.24.10
#Not published currently, see https://github.com/mockito/mockito/issues/962
mockito.testng.version=1.0