From 50bf5c6b6cdd258752d9e5d31b87274b1e1f540e Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 24 Aug 2021 12:19:29 +0200 Subject: [PATCH 1/2] Fixes #2399 : Adds defaultAnswer to the MockitoMockKey to distinguish the mock types, i.e. to separate mocks from spies otherwise spy type is reused for a mock or vice versa. --- .../TypeCachingBytecodeGenerator.java | 20 +++++--- .../TypeCachingMockBytecodeGeneratorTest.java | 36 +++++++++++++ .../MockCreationShouldNotAffectSpyTest.java | 51 +++++++++++++++++++ .../SpyCreationShouldNotAffectMockTest.java | 49 ++++++++++++++++++ 4 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/mockitousage/spies/MockCreationShouldNotAffectSpyTest.java create mode 100644 src/test/java/org/mockitousage/spies/SpyCreationShouldNotAffectMockTest.java diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java index 30ed949bf5..2751653cbd 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java @@ -5,12 +5,14 @@ package org.mockito.internal.creation.bytebuddy; import java.lang.ref.ReferenceQueue; +import java.util.Objects; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import net.bytebuddy.TypeCache; import org.mockito.mock.SerializableMode; +import org.mockito.stubbing.Answer; class TypeCachingBytecodeGenerator extends ReferenceQueue implements BytecodeGenerator { @@ -43,7 +45,8 @@ public Class mockClass(final MockFeatures params) { params.mockedType, params.interfaces, params.serializableMode, - params.stripAnnotations), + params.stripAnnotations, + params.defaultAnswer), () -> bytecodeGenerator.mockClass(params), BOOTSTRAP_LOCK); } catch (IllegalArgumentException exception) { @@ -83,15 +86,18 @@ private static class MockitoMockKey extends TypeCache.SimpleKey { private final SerializableMode serializableMode; private final boolean stripAnnotations; + private final Answer defaultAnswer; private MockitoMockKey( - Class type, - Set> additionalType, - SerializableMode serializableMode, - boolean stripAnnotations) { + Class type, + Set> additionalType, + SerializableMode serializableMode, + boolean stripAnnotations, + Answer defaultAnswer) { super(type, additionalType); this.serializableMode = serializableMode; this.stripAnnotations = stripAnnotations; + this.defaultAnswer = defaultAnswer; } @Override @@ -107,7 +113,8 @@ public boolean equals(Object object) { } MockitoMockKey that = (MockitoMockKey) object; return stripAnnotations == that.stripAnnotations - && serializableMode.equals(that.serializableMode); + && serializableMode.equals(that.serializableMode) + && Objects.equals(defaultAnswer, that.defaultAnswer); } @Override @@ -115,6 +122,7 @@ public int hashCode() { int result = super.hashCode(); result = 31 * result + (stripAnnotations ? 1 : 0); result = 31 * result + serializableMode.hashCode(); + result = 31 * result + Objects.hashCode(defaultAnswer); return result; } } diff --git a/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java b/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java index 6ffe72950f..2e30ebf196 100644 --- a/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java +++ b/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java @@ -14,6 +14,8 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Set; import java.util.WeakHashMap; import org.junit.Before; @@ -142,6 +144,40 @@ public void ensure_cache_returns_different_instance_serializableMode() throws Ex assertThat(other_mock_type).isNotSameAs(the_mock_type); } + @Test + public void ensure_cache_returns_different_instance_defaultAnswer() throws Exception { + // given + ClassLoader classloader_with_life_shorter_than_cache = + inMemoryClassLoader() + .withClassDefinition("foo.Bar", makeMarkerInterface("foo.Bar")) + .build(); + + TypeCachingBytecodeGenerator cachingMockBytecodeGenerator = + new TypeCachingBytecodeGenerator(new SubclassBytecodeGenerator(), true); + + Answers[] answers = Answers.values(); + Set> classes = Collections.newSetFromMap(new IdentityHashMap<>()); + classes.add(cachingMockBytecodeGenerator.mockClass( + withMockFeatures( + classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), + Collections.>emptySet(), + SerializableMode.NONE, + false, + null))); + for (Answers answer : answers) { + Class klass = cachingMockBytecodeGenerator.mockClass( + withMockFeatures( + classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), + Collections.>emptySet(), + SerializableMode.NONE, + false, + answer)); + assertThat(classes.add(klass)).isTrue(); + } + + assertThat(classes).hasSize(answers.length + 1); + } + @Test public void validate_simple_code_idea_where_weakhashmap_with_classloader_as_key_get_GCed_when_no_more_references() diff --git a/src/test/java/org/mockitousage/spies/MockCreationShouldNotAffectSpyTest.java b/src/test/java/org/mockitousage/spies/MockCreationShouldNotAffectSpyTest.java new file mode 100644 index 0000000000..e99fc13cfb --- /dev/null +++ b/src/test/java/org/mockitousage/spies/MockCreationShouldNotAffectSpyTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockitousage.spies; + +import org.junit.Test; +import org.mockitoutil.TestBase; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +public class MockCreationShouldNotAffectSpyTest extends TestBase { + + @Test + public void test() { + TestClass instance = new TestClass(42); + + TestClass mock = mock(TestClass.class); + assertEquals(mock.hashCode(), mock.hashCode()); + assertEquals(mock, mock); + + TestClass spy = spy(instance); + assertEquals(instance.hashCode(), spy.hashCode()); + assertEquals(spy, instance); + assertEquals(instance, spy); + } + + static class TestClass { + private final long value; + + TestClass(final long value) + { + this.value = value; + } + + public boolean equals(final Object o) + { + if (!(o instanceof TestClass)) { + return false; + } + return value == ((TestClass)o).value; + } + + public int hashCode() + { + return Long.hashCode(value); + } + } +} diff --git a/src/test/java/org/mockitousage/spies/SpyCreationShouldNotAffectMockTest.java b/src/test/java/org/mockitousage/spies/SpyCreationShouldNotAffectMockTest.java new file mode 100644 index 0000000000..54e7719c21 --- /dev/null +++ b/src/test/java/org/mockitousage/spies/SpyCreationShouldNotAffectMockTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockitousage.spies; + +import org.junit.Test; +import org.mockitoutil.TestBase; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +public class SpyCreationShouldNotAffectMockTest extends TestBase { + + @Test + public void test() { + TestClass instance = new TestClass(Long.MIN_VALUE); + + TestClass spy = spy(instance); + assertEquals(instance.hashCode(), spy.hashCode()); + assertEquals(spy, instance); + assertEquals(instance, spy); + + TestClass mock = mock(TestClass.class); + assertEquals(mock.hashCode(), mock.hashCode()); + assertEquals(mock, mock); + } + + static class TestClass { + private final long value; + + TestClass(final long value) { + this.value = value; + } + + public boolean equals(final Object o) { + if (!(o instanceof TestClass)) + { + return false; + } + return value == ((TestClass)o).value; + } + + public int hashCode() { + return Long.hashCode(value); + } + } +} From 3751acd438ed6a05017ce265481985cee936ef24 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 24 Aug 2021 13:44:23 +0200 Subject: [PATCH 2/2] Fixes formatting issues. --- .../TypeCachingBytecodeGenerator.java | 10 +++---- .../TypeCachingMockBytecodeGeneratorTest.java | 30 ++++++++++--------- .../MockCreationShouldNotAffectSpyTest.java | 11 +++---- .../SpyCreationShouldNotAffectMockTest.java | 5 ++-- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java index 2751653cbd..5ce57b1115 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java @@ -89,11 +89,11 @@ private static class MockitoMockKey extends TypeCache.SimpleKey { private final Answer defaultAnswer; private MockitoMockKey( - Class type, - Set> additionalType, - SerializableMode serializableMode, - boolean stripAnnotations, - Answer defaultAnswer) { + Class type, + Set> additionalType, + SerializableMode serializableMode, + boolean stripAnnotations, + Answer defaultAnswer) { super(type, additionalType); this.serializableMode = serializableMode; this.stripAnnotations = stripAnnotations; diff --git a/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java b/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java index 2e30ebf196..e26b36d531 100644 --- a/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java +++ b/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java @@ -157,21 +157,23 @@ public void ensure_cache_returns_different_instance_defaultAnswer() throws Excep Answers[] answers = Answers.values(); Set> classes = Collections.newSetFromMap(new IdentityHashMap<>()); - classes.add(cachingMockBytecodeGenerator.mockClass( - withMockFeatures( - classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), - Collections.>emptySet(), - SerializableMode.NONE, - false, - null))); + classes.add( + cachingMockBytecodeGenerator.mockClass( + withMockFeatures( + classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), + Collections.>emptySet(), + SerializableMode.NONE, + false, + null))); for (Answers answer : answers) { - Class klass = cachingMockBytecodeGenerator.mockClass( - withMockFeatures( - classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), - Collections.>emptySet(), - SerializableMode.NONE, - false, - answer)); + Class klass = + cachingMockBytecodeGenerator.mockClass( + withMockFeatures( + classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), + Collections.>emptySet(), + SerializableMode.NONE, + false, + answer)); assertThat(classes.add(klass)).isTrue(); } diff --git a/src/test/java/org/mockitousage/spies/MockCreationShouldNotAffectSpyTest.java b/src/test/java/org/mockitousage/spies/MockCreationShouldNotAffectSpyTest.java index e99fc13cfb..c77e589594 100644 --- a/src/test/java/org/mockitousage/spies/MockCreationShouldNotAffectSpyTest.java +++ b/src/test/java/org/mockitousage/spies/MockCreationShouldNotAffectSpyTest.java @@ -30,21 +30,18 @@ public void test() { static class TestClass { private final long value; - TestClass(final long value) - { + TestClass(final long value) { this.value = value; } - public boolean equals(final Object o) - { + public boolean equals(final Object o) { if (!(o instanceof TestClass)) { return false; } - return value == ((TestClass)o).value; + return value == ((TestClass) o).value; } - public int hashCode() - { + public int hashCode() { return Long.hashCode(value); } } diff --git a/src/test/java/org/mockitousage/spies/SpyCreationShouldNotAffectMockTest.java b/src/test/java/org/mockitousage/spies/SpyCreationShouldNotAffectMockTest.java index 54e7719c21..a57ec082c1 100644 --- a/src/test/java/org/mockitousage/spies/SpyCreationShouldNotAffectMockTest.java +++ b/src/test/java/org/mockitousage/spies/SpyCreationShouldNotAffectMockTest.java @@ -35,11 +35,10 @@ static class TestClass { } public boolean equals(final Object o) { - if (!(o instanceof TestClass)) - { + if (!(o instanceof TestClass)) { return false; } - return value == ((TestClass)o).value; + return value == ((TestClass) o).value; } public int hashCode() {