diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java index 553a02e248..7178927cd9 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java @@ -393,7 +393,8 @@ public Class createMockType(MockCreationSettings settings) { settings.getTypeToMock(), settings.getExtraInterfaces(), settings.getSerializableMode(), - settings.isStripAnnotations())); + settings.isStripAnnotations(), + settings.getDefaultAnswer())); } catch (Exception bytecodeGenerationFailed) { throw prettifyFailure(settings, bytecodeGenerationFailed); } diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/MockFeatures.java b/src/main/java/org/mockito/internal/creation/bytebuddy/MockFeatures.java index 1dbfba1334..ca27be01e1 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/MockFeatures.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/MockFeatures.java @@ -8,6 +8,7 @@ import java.util.Set; import org.mockito.mock.SerializableMode; +import org.mockito.stubbing.Answer; class MockFeatures { @@ -15,23 +16,28 @@ class MockFeatures { final Set> interfaces; final SerializableMode serializableMode; final boolean stripAnnotations; + final Answer defaultAnswer; private MockFeatures( Class mockedType, Set> interfaces, SerializableMode serializableMode, - boolean stripAnnotations) { + boolean stripAnnotations, + Answer defaultAnswer) { this.mockedType = mockedType; this.interfaces = Collections.unmodifiableSet(interfaces); this.serializableMode = serializableMode; this.stripAnnotations = stripAnnotations; + this.defaultAnswer = defaultAnswer; } public static MockFeatures withMockFeatures( Class mockedType, Set> interfaces, SerializableMode serializableMode, - boolean stripAnnotations) { - return new MockFeatures(mockedType, interfaces, serializableMode, stripAnnotations); + boolean stripAnnotations, + Answer defaultAnswer) { + return new MockFeatures( + mockedType, interfaces, serializableMode, stripAnnotations, defaultAnswer); } } diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java index 8bf72feb89..dc1e81752c 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java @@ -79,7 +79,8 @@ public Class createMockType(MockCreationSettings settings) { settings.getTypeToMock(), settings.getExtraInterfaces(), settings.getSerializableMode(), - settings.isStripAnnotations())); + settings.isStripAnnotations(), + settings.getDefaultAnswer())); } catch (Exception bytecodeGenerationFailed) { throw prettifyFailure(settings, bytecodeGenerationFailed); } 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 3dadd3fa46..46ecb7868a 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java @@ -44,6 +44,7 @@ import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.attribute.MethodAttributeAppender; import net.bytebuddy.matcher.ElementMatcher; +import org.mockito.Answers; import org.mockito.codegen.InjectionBase; import org.mockito.exceptions.base.MockitoException; import org.mockito.internal.creation.bytebuddy.ByteBuddyCrossClassLoaderSerializationSupport.CrossClassLoaderSerializableMock; @@ -237,14 +238,24 @@ public Class mockClass(MockFeatures features) { features.stripAnnotations ? MethodAttributeAppender.NoOp.INSTANCE : INCLUDING_RECEIVER) - .method(isHashCode()) - .intercept(hashCode) - .method(isEquals()) - .intercept(equals) .serialVersionUid(42L) .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE) .implement(MockAccess.class) .intercept(FieldAccessor.ofBeanProperty()); + + if (features.defaultAnswer != Answers.CALLS_REAL_METHODS) { + builder = + builder.method(isHashCode()) + .intercept(hashCode) + .method(isEquals()) + .intercept(equals); + } else { + builder = + builder.method(isHashCode()) + .intercept(dispatcher) + .method(isEquals()) + .intercept(dispatcher); + } if (features.serializableMode == SerializableMode.ACROSS_CLASSLOADERS) { builder = builder.implement(CrossClassLoaderSerializableMock.class) diff --git a/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java b/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java index ef475e60c6..6cc7a8c49f 100644 --- a/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java +++ b/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java @@ -77,7 +77,7 @@ public String toString() { @Override public boolean matches(Invocation candidate) { - return invocation.getMock().equals(candidate.getMock()) + return invocation.getMock() == candidate.getMock() && hasSameMethod(candidate) && argumentsMatch(candidate); } 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 d0ed772a68..6ffe72950f 100644 --- a/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java +++ b/src/test/java/org/mockito/internal/creation/bytebuddy/TypeCachingMockBytecodeGeneratorTest.java @@ -18,6 +18,7 @@ import org.junit.Before; import org.junit.Test; +import org.mockito.Answers; import org.mockito.mock.SerializableMode; import org.mockitoutil.VmArgAssumptions; @@ -46,7 +47,8 @@ public void ensure_cache_is_cleared_if_no_reference_to_classloader_and_classes() classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), Collections.>emptySet(), SerializableMode.NONE, - false)); + false, + Answers.RETURNS_DEFAULTS)); ReferenceQueue referenceQueue = new ReferenceQueue(); Reference typeReference = @@ -79,7 +81,8 @@ public void ensure_cache_returns_same_instance() throws Exception { classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), Collections.>emptySet(), SerializableMode.NONE, - false)); + false, + Answers.RETURNS_DEFAULTS)); Class other_mock_type = cachingMockBytecodeGenerator.mockClass( @@ -87,7 +90,8 @@ public void ensure_cache_returns_same_instance() throws Exception { classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), Collections.>emptySet(), SerializableMode.NONE, - false)); + false, + Answers.RETURNS_DEFAULTS)); assertThat(other_mock_type).isSameAs(the_mock_type); @@ -123,7 +127,8 @@ public void ensure_cache_returns_different_instance_serializableMode() throws Ex classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), Collections.>emptySet(), SerializableMode.NONE, - false)); + false, + Answers.RETURNS_DEFAULTS)); Class other_mock_type = cachingMockBytecodeGenerator.mockClass( @@ -131,7 +136,8 @@ public void ensure_cache_returns_different_instance_serializableMode() throws Ex classloader_with_life_shorter_than_cache.loadClass("foo.Bar"), Collections.>emptySet(), SerializableMode.BASIC, - false)); + false, + Answers.RETURNS_DEFAULTS)); assertThat(other_mock_type).isNotSameAs(the_mock_type); } diff --git a/src/test/java/org/mockitousage/spies/SpyingOnRealObjectsTest.java b/src/test/java/org/mockitousage/spies/SpyingOnRealObjectsTest.java index a3ed58cfd4..06b4878fa3 100644 --- a/src/test/java/org/mockitousage/spies/SpyingOnRealObjectsTest.java +++ b/src/test/java/org/mockitousage/spies/SpyingOnRealObjectsTest.java @@ -9,6 +9,7 @@ import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.*; +import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -192,4 +193,13 @@ public void shouldSayNiceMessageWhenSpyingOnPrivateClass() throws Exception { "Most likely it is due to mocking a private class that is not visible to Mockito"); } } + + @Test + public void spysHashCodeEqualsDelegatedToActualMethods() { + List real = new ArrayList<>(); + real.add("one"); + List spy = spy(real); + assertEquals(real.hashCode(), spy.hashCode()); + assertTrue(spy.equals(real)); + } }