From 43ac1c81342660fd77578d363d6444fcf62038ed Mon Sep 17 00:00:00 2001 From: Rafael Winterhalter Date: Wed, 12 Jan 2022 22:34:43 +0100 Subject: [PATCH 1/3] Add ignore matcher for Groovy meta methods for inline Byte Buddy mock maker. Fixes #2522. --- .../creation/bytebuddy/BytecodeGenerator.java | 11 +++++++++++ .../creation/bytebuddy/InlineBytecodeGenerator.java | 1 + .../creation/bytebuddy/SubclassBytecodeGenerator.java | 7 +------ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/BytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/BytecodeGenerator.java index 392392d2d9..5ff6395e18 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/BytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/BytecodeGenerator.java @@ -4,6 +4,12 @@ */ package org.mockito.internal.creation.bytebuddy; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import static net.bytebuddy.matcher.ElementMatchers.*; +import static net.bytebuddy.matcher.ElementMatchers.named; + public interface BytecodeGenerator { Class mockClass(MockFeatures features); @@ -13,4 +19,9 @@ public interface BytecodeGenerator { void mockClassStatic(Class type); default void clearAllCaches() {} + + static ElementMatcher isGroovyMethod() { + return isDeclaredBy(named("groovy.lang.GroovyObjectSupport")) + .or(isAnnotatedWith(named("groovy.transform.Internal"))); + } } diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java index 10b73c81a2..7b8293ff09 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java @@ -387,6 +387,7 @@ public byte[] transform( // ,ClassFileLocator.ForClassLoader.ofSystemLoader() // ) ) + .ignoreAlso(BytecodeGenerator.isGroovyMethod()) // Note: The VM erases parameter meta data from the provided class file // (bug). We just add this information manually. .visit(new ParameterWritingVisitorWrapper(classBeingRedefined)) 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 f67fdfc5a6..fe89070150 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java @@ -224,7 +224,7 @@ public Class mockClass(MockFeatures features) { byteBuddy .subclass(features.mockedType) .name(name) - .ignoreAlso(isGroovyMethod()) + .ignoreAlso(BytecodeGenerator.isGroovyMethod()) .annotateType( features.stripAnnotations ? new Annotation[0] @@ -293,11 +293,6 @@ private Collection> getAllTypes(Class type) { return supertypes; } - private static ElementMatcher isGroovyMethod() { - return isDeclaredBy(named("groovy.lang.GroovyObjectSupport")) - .or(isAnnotatedWith(named("groovy.transform.Internal"))); - } - private boolean isComingFromJDK(Class type) { // Comes from the manifest entry : // Implementation-Title: Java Runtime Environment From b9f01a84e4ae67f7aecbe586cba9a4054f87e50c Mon Sep 17 00:00:00 2001 From: Steve Green Date: Tue, 15 Feb 2022 23:44:09 +0000 Subject: [PATCH 2/3] #2522: Add a new test subproject to verify fixes between mockito-inline and Groovy --- settings.gradle.kts | 1 + .../bytebuddy/SubclassBytecodeGenerator.java | 3 -- .../groovyInlineTest/groovyInlineTest.gradle | 11 +++++ .../mockito/groovy/GroovyMockitoTest.groovy | 46 +++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 subprojects/groovyInlineTest/groovyInlineTest.gradle create mode 100644 subprojects/groovyInlineTest/src/test/groovy/org/mockito/groovy/GroovyMockitoTest.groovy diff --git a/settings.gradle.kts b/settings.gradle.kts index f5a786dfdc..45a4679e4c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,6 +6,7 @@ include("inline", "proxy", "extTest", "groovyTest", + "groovyInlineTest", "kotlinTest", "kotlinReleaseCoroutinesTest", "android", 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 fe89070150..4107d1dabb 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java @@ -12,12 +12,9 @@ import static net.bytebuddy.matcher.ElementMatchers.any; import static net.bytebuddy.matcher.ElementMatchers.hasParameters; import static net.bytebuddy.matcher.ElementMatchers.hasType; -import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; -import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; import static net.bytebuddy.matcher.ElementMatchers.isEquals; import static net.bytebuddy.matcher.ElementMatchers.isHashCode; import static net.bytebuddy.matcher.ElementMatchers.isPackagePrivate; -import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.whereAny; import static org.mockito.internal.util.StringUtil.join; diff --git a/subprojects/groovyInlineTest/groovyInlineTest.gradle b/subprojects/groovyInlineTest/groovyInlineTest.gradle new file mode 100644 index 0000000000..1618ac6009 --- /dev/null +++ b/subprojects/groovyInlineTest/groovyInlineTest.gradle @@ -0,0 +1,11 @@ +apply plugin: 'groovy' + +description = "Integration test for using mockito-inline with Groovy." + +apply from: "$rootDir/gradle/dependencies.gradle" + +dependencies { + testImplementation project(":inline") + testImplementation libraries.groovy + testImplementation libraries.junit4 +} diff --git a/subprojects/groovyInlineTest/src/test/groovy/org/mockito/groovy/GroovyMockitoTest.groovy b/subprojects/groovyInlineTest/src/test/groovy/org/mockito/groovy/GroovyMockitoTest.groovy new file mode 100644 index 0000000000..c327d0e1bb --- /dev/null +++ b/subprojects/groovyInlineTest/src/test/groovy/org/mockito/groovy/GroovyMockitoTest.groovy @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito.groovy + +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +import static org.mockito.Mockito.verify + +@RunWith(MockitoJUnitRunner) +class GroovyMockitoTest { + + @Mock Helper helper + @InjectMocks ClassUnderTest classUnderTest + + /** + * Test that the Groovy class under test can call methods on a mocked Groovy + * helper class. + */ + @Test + void testCallGroovyFromGroovy() { + classUnderTest.methodUnderTest() + verify(helper).helperMethod() + } + + static class ClassUnderTest { + private final Helper helper + + ClassUnderTest(Helper helper) { + this.helper = helper + } + + void methodUnderTest() { + helper.helperMethod() + } + } + + static class Helper { + void helperMethod() { } + } +} From 0c677a23d900d50ec3781ed92d28572cc7320330 Mon Sep 17 00:00:00 2001 From: Rafael Winterhalter Date: Wed, 12 Jan 2022 21:34:43 +0000 Subject: [PATCH 3/3] Add ignore matcher for Groovy meta methods for inline Byte Buddy mock maker. Fixes #2522. --- .../creation/bytebuddy/BytecodeGenerator.java | 13 ++++++++++--- .../creation/bytebuddy/InlineBytecodeGenerator.java | 12 ++++++++---- .../bytebuddy/SubclassBytecodeGenerator.java | 5 ++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/BytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/BytecodeGenerator.java index 5ff6395e18..5040c17573 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/BytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/BytecodeGenerator.java @@ -20,8 +20,15 @@ public interface BytecodeGenerator { default void clearAllCaches() {} - static ElementMatcher isGroovyMethod() { - return isDeclaredBy(named("groovy.lang.GroovyObjectSupport")) - .or(isAnnotatedWith(named("groovy.transform.Internal"))); + static ElementMatcher isGroovyMethod(boolean inline) { + ElementMatcher.Junction matcher = + isDeclaredBy(named("groovy.lang.GroovyObjectSupport")) + .or(isAnnotatedWith(named("groovy.transform.Internal"))); + if (inline) { + return matcher.or( + named("$getStaticMetaClass").and(returns(named("groovy.lang.MetaClass")))); + } else { + return matcher; + } } } diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java index 7b8293ff09..67e7b9906b 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java @@ -117,15 +117,19 @@ public InlineBytecodeGenerator( .or(isEquals()) .or(isDefaultFinalizer()))) .and( - not( - isDeclaredBy(nameStartsWith("java.")) + not(isDeclaredBy(nameStartsWith("java.")) .and( - isPackagePrivate()))), + isPackagePrivate())) + .and( + not( + BytecodeGenerator + .isGroovyMethod( + true)))), Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.class)) .method( - isStatic(), + isStatic().and(not(BytecodeGenerator.isGroovyMethod(true))), Advice.withCustomMapping() .bind(MockMethodAdvice.Identifier.class, identifier) .to(MockMethodAdvice.ForStatic.class)) 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 4107d1dabb..75c287c349 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java @@ -12,9 +12,12 @@ import static net.bytebuddy.matcher.ElementMatchers.any; import static net.bytebuddy.matcher.ElementMatchers.hasParameters; import static net.bytebuddy.matcher.ElementMatchers.hasType; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; import static net.bytebuddy.matcher.ElementMatchers.isEquals; import static net.bytebuddy.matcher.ElementMatchers.isHashCode; import static net.bytebuddy.matcher.ElementMatchers.isPackagePrivate; +import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.whereAny; import static org.mockito.internal.util.StringUtil.join; @@ -221,7 +224,7 @@ public Class mockClass(MockFeatures features) { byteBuddy .subclass(features.mockedType) .name(name) - .ignoreAlso(BytecodeGenerator.isGroovyMethod()) + .ignoreAlso(BytecodeGenerator.isGroovyMethod(false)) .annotateType( features.stripAnnotations ? new Annotation[0]