Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Groovy inline #2618

Merged
merged 2 commits into from Apr 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions settings.gradle.kts
Expand Up @@ -6,6 +6,7 @@ include("inline",
"proxy",
"extTest",
"groovyTest",
"groovyInlineTest",
"kotlinTest",
"kotlinReleaseCoroutinesTest",
"android",
Expand Down
Expand Up @@ -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 {

<T> Class<? extends T> mockClass(MockFeatures<T> features);
Expand All @@ -13,4 +19,16 @@ public interface BytecodeGenerator {
void mockClassStatic(Class<?> type);

default void clearAllCaches() {}

static ElementMatcher<MethodDescription> isGroovyMethod(boolean inline) {
ElementMatcher.Junction<MethodDescription> 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;
}
}
}
Expand Up @@ -117,15 +117,19 @@ public InlineBytecodeGenerator(
.or(isEquals())
.or(isDefaultFinalizer())))
.and(
not(
isDeclaredBy(nameStartsWith("java."))
not(isDeclaredBy(nameStartsWith("java."))
.<MethodDescription>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))
Expand Down
Expand Up @@ -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;
Expand All @@ -29,9 +26,7 @@
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.method.MethodDescription;
Expand Down Expand Up @@ -224,7 +219,7 @@ public <T> Class<? extends T> mockClass(MockFeatures<T> features) {
byteBuddy
.subclass(features.mockedType)
.name(name)
.ignoreAlso(isGroovyMethod())
.ignoreAlso(BytecodeGenerator.isGroovyMethod(false))
.annotateType(
features.stripAnnotations
? new Annotation[0]
Expand Down Expand Up @@ -282,22 +277,6 @@ public void mockClassConstruction(Class<?> type) {
"The subclass byte code generator cannot create construction mocks");
}

private <T> Collection<Class<? super T>> getAllTypes(Class<T> type) {
Collection<Class<? super T>> supertypes = new LinkedList<>();
supertypes.add(type);
Class<? super T> superType = type;
while (superType != null) {
supertypes.add(superType);
superType = superType.getSuperclass();
}
return supertypes;
}

private static ElementMatcher<MethodDescription> 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
Expand Down
11 changes: 11 additions & 0 deletions 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
}
@@ -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() { }
}
}