Files
openide/plugins/gradle/java/testSources/importing/GradleFindUsagesTest.java
Anna Kozlova 6f6fc3ff64 [gradle] correct test for scope enlarger
old test hasn't created project structure, and thus enlarger didn't work at all

KTIJ-29258

GitOrigin-RevId: c089c2152ba71b0b4f297a3dc308ba96a778354f
2024-05-15 21:31:25 +00:00

331 lines
16 KiB
Java

// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.gradle.importing;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.Trinity;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.containers.ContainerUtil;
import org.gradle.wrapper.PathAssembler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.service.execution.GradleUserHomeUtil;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrSyntheticCodeBlock;
import org.junit.Test;
import org.junit.runners.Parameterized;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static com.intellij.openapi.util.Pair.pair;
import static com.intellij.testFramework.EdtTestUtil.runInEdtAndGet;
/**
* @author Vladislav.Soroka
*/
public class GradleFindUsagesTest extends GradleImportingTestCase {
/**
* It's sufficient to run the test against one gradle version
*/
@SuppressWarnings("MethodOverridesStaticMethodOfSuperclass")
@Parameterized.Parameters(name = "with Gradle-{0}")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{{BASE_GRADLE_VERSION}});
}
@Override
protected void collectAllowedRoots(List<String> roots, PathAssembler.LocalDistribution distribution) {
super.collectAllowedRoots(roots, distribution);
File gradleUserHomeDir = GradleUserHomeUtil.gradleUserHomeDir();
File generatedGradleJarsDir = new File(gradleUserHomeDir, "caches/" + gradleVersion + "/generated-gradle-jars");
roots.add(generatedGradleJarsDir.getPath());
File gradleDistLibDir = new File(distribution.getDistributionDir(), "gradle-" + gradleVersion + "/lib");
roots.add(gradleDistLibDir.getPath());
}
@Test
public void testBuildSrcClassesUsages() throws Exception {
createProjectSubFile("settings.gradle", "rootProject.name = 'multiproject'\n" +
"include ':app'");
createProjectSubFile("buildSrc/src/main/groovy/testBuildSrcClassesUsages/BuildSrcClass.groovy", "package testBuildSrcClassesUsages;\n" +
"public class BuildSrcClass {" +
" public String sayHello() { 'Hello!' }" +
"}");
createProjectSubFile("app/build.gradle", "def foo = new testBuildSrcClassesUsages.BuildSrcClass().sayHello()");
importProject();
assertModules("multiproject", "multiproject.app",
"multiproject.buildSrc", "multiproject.buildSrc.main", "multiproject.buildSrc.test");
Module buildSrcModule = getModule("multiproject.buildSrc.main");
assertNotNull(buildSrcModule);
assertUsages("testBuildSrcClassesUsages.BuildSrcClass", GlobalSearchScope.moduleScope(buildSrcModule), 1);
assertUsages("testBuildSrcClassesUsages.BuildSrcClass", "sayHello", GlobalSearchScope.moduleScope(buildSrcModule), 1);
}
@Test
public void testMultiModuleBuildSrcClassesUsages() throws Exception {
createProjectSubFile("settings.gradle", "rootProject.name = 'multiproject'\n" +
"include ':app'");
// buildSrc module files
createProjectSubFile("buildSrc/settings.gradle", "include 'buildSrcSubProject'");
createProjectSubFile("buildSrc/build.gradle", """
allprojects {
apply plugin: 'groovy'
dependencies {
implementation gradleApi()
implementation localGroovy()
}
repositories {
mavenCentral()
}
if (it != rootProject) {
rootProject.dependencies {
runtimeOnly project(path)
}
}
}
""");
createProjectSubFile("buildSrc/src/main/groovy/testMultiModuleBuildSrcClassesUsages/BuildSrcClass.groovy",
"package testMultiModuleBuildSrcClassesUsages;\n" +
"public class BuildSrcClass {}");
createProjectSubFile("buildSrc/buildSrcSubProject/src/main/java/testMultiModuleBuildSrcClassesUsages/BuildSrcAdditionalClass.java",
"package testMultiModuleBuildSrcClassesUsages;\n" +
"public class BuildSrcAdditionalClass {}");
createProjectSubFile("build.gradle", "def foo = new testMultiModuleBuildSrcClassesUsages.BuildSrcClass()");
createProjectSubFile("app/build.gradle", "def foo1 = new testMultiModuleBuildSrcClassesUsages.BuildSrcClass()\n" +
"def foo2 = new testMultiModuleBuildSrcClassesUsages.BuildSrcAdditionalClass()");
importProject();
assertModules("multiproject", "multiproject.app",
"multiproject.buildSrc", "multiproject.buildSrc.main", "multiproject.buildSrc.test",
"multiproject.buildSrc.buildSrcSubProject", "multiproject.buildSrc.buildSrcSubProject.main", "multiproject.buildSrc.buildSrcSubProject.test");
assertUsages(pair("testMultiModuleBuildSrcClassesUsages.BuildSrcClass", 2),
pair("testMultiModuleBuildSrcClassesUsages.BuildSrcAdditionalClass", 1));
importProjectUsingSingeModulePerGradleProject();
assertModules("multiproject", "multiproject.app",
"multiproject.buildSrc",
"multiproject.buildSrc.buildSrcSubProject");
assertUsages(pair("testMultiModuleBuildSrcClassesUsages.BuildSrcClass", 2),
pair("testMultiModuleBuildSrcClassesUsages.BuildSrcAdditionalClass", 1));
}
@Test
public void testIncludedBuildSrcClassesUsages_nonQN() throws Exception {
createProjectWithIncludedBuildAndBuildSrcModules("testIncludedBuildSrcClassesUsages_nonQN");
// check for non-qualified module names
getCurrentExternalProjectSettings().setUseQualifiedModuleNames(false);
importProject();
assertModules("multiproject", "app",
"multiproject_multiproject-buildSrc", "multiproject_multiproject-buildSrc_main", "multiproject_multiproject-buildSrc_test",
"gradle-plugin", "gradle-plugin_test", "gradle-plugin_main",
"gradle-plugin_gradle-plugin-buildSrc", "gradle-plugin_gradle-plugin-buildSrc_main", "gradle-plugin_gradle-plugin-buildSrc_test");
assertUsages("testIncludedBuildSrcClassesUsages_nonQN.BuildSrcClass", 2);
assertUsages("testIncludedBuildSrcClassesUsages_nonQN.IncludedBuildSrcClass", 1);
assertUsages("testIncludedBuildSrcClassesUsages_nonQN.IncludedBuildClass", 2);
}
@Test
public void testBuildSrcLocalPropertyUsages() throws Exception {
createProjectSubFile("settings.gradle", "rootProject.name = 'multiproject'\n" + "include ':app'");
createProjectSubFile("buildSrc/src/main/groovy/testBuildSrcClassesUsages/BuildSrcClass.groovy", """
package testBuildSrcClassesUsages;
public class BuildSrcClass {\
public String foo() { \
def a = 0
println a\
}\
}""");
createProjectSubFile("app/build.gradle", "def srcClass = new testBuildSrcClassesUsages.BuildSrcClass()");
importProject();
assertModules("multiproject", "multiproject.app", "multiproject.buildSrc", "multiproject.buildSrc.main", "multiproject.buildSrc.test");
Module buildSrcModule = getModule("multiproject.buildSrc.main");
assertNotNull(buildSrcModule);
ReadAction.run(() -> {
PsiClass clazz = JavaPsiFacade.getInstance(myProject)
.findClass("testBuildSrcClassesUsages.BuildSrcClass", GlobalSearchScope.moduleScope(buildSrcModule));
PsiMethod[] methods = clazz.findMethodsByName("foo", false);
assertSize(1, methods);
assertTrue(methods[0] instanceof GrMethod);
@Nullable GrOpenBlock body = ((GrMethod)methods[0]).getBlock();
assertNotNull(body);
GrStatement[] statements = body.getStatements();
assertSize(2, statements);
assertInstanceOf(statements[0], GrVariableDeclaration.class);
GrVariable[] variables = ((GrVariableDeclaration)statements[0]).getVariables();
assertSize(1, variables);
PsiElement localProperty = variables[0];
SearchScope useScope = PsiSearchHelper.getInstance(localProperty.getProject()).getUseScope(localProperty);
assertInstanceOf(useScope, LocalSearchScope.class);
assertNotNull(ContainerUtil.find(((LocalSearchScope)useScope).getScope(), e -> PsiTreeUtil.isAncestor(e, statements[1], false)));
});
}
@Test
public void testIncludedBuildSrcClassesUsages_merged_nonQN() throws Exception {
createProjectWithIncludedBuildAndBuildSrcModules("testIncludedBuildSrcClassesUsages_merged_nonQN");
// check for non-qualified module names
getCurrentExternalProjectSettings().setUseQualifiedModuleNames(false);
importProjectUsingSingeModulePerGradleProject();
assertModules("multiproject", "app",
"multiproject_multiproject-buildSrc",
"gradle-plugin",
"gradle-plugin_gradle-plugin-buildSrc");
assertUsages(pair("testIncludedBuildSrcClassesUsages_merged_nonQN.BuildSrcClass", 2),
pair("testIncludedBuildSrcClassesUsages_merged_nonQN.IncludedBuildSrcClass", 1));
assertUsages("testIncludedBuildSrcClassesUsages_merged_nonQN.IncludedBuildClass", 2);
}
@Test
public void testIncludedBuildSrcClassesUsages_qualified_names() throws Exception {
createProjectWithIncludedBuildAndBuildSrcModules("testIncludedBuildSrcClassesUsages_qualified_names");
importProject();
assertModules("multiproject", "multiproject.app",
"multiproject.buildSrc", "multiproject.buildSrc.main", "multiproject.buildSrc.test",
"gradle-plugin", "gradle-plugin.test", "gradle-plugin.main",
"gradle-plugin.buildSrc", "gradle-plugin.buildSrc.main", "gradle-plugin.buildSrc.test");
assertUsages(pair("testIncludedBuildSrcClassesUsages_qualified_names.BuildSrcClass", 2),
pair("testIncludedBuildSrcClassesUsages_qualified_names.IncludedBuildSrcClass", 1));
assertUsages("testIncludedBuildSrcClassesUsages_qualified_names.IncludedBuildClass", 2);
}
@Test
public void testIncludedBuildSrcClassesUsages_merged_qualified_names() throws Exception {
createProjectWithIncludedBuildAndBuildSrcModules("testIncludedBuildSrcClassesUsages_merged_qualified_names");
// check for qualified module names
getCurrentExternalProjectSettings().setUseQualifiedModuleNames(true);
importProjectUsingSingeModulePerGradleProject();
assertModules("multiproject", "multiproject.app",
"multiproject.buildSrc",
"gradle-plugin",
"gradle-plugin.buildSrc");
assertUsages(pair("testIncludedBuildSrcClassesUsages_merged_qualified_names.BuildSrcClass", 2),
pair("testIncludedBuildSrcClassesUsages_merged_qualified_names.IncludedBuildSrcClass", 1));
assertUsages("testIncludedBuildSrcClassesUsages_merged_qualified_names.IncludedBuildClass", 2);
}
private void createProjectWithIncludedBuildAndBuildSrcModules(@NotNull String classPackage) throws IOException {
createProjectSubFile("settings.gradle", """
rootProject.name = 'multiproject'
include ':app'
includeBuild 'gradle-plugin'""");
createProjectSubFile("buildSrc/src/main/groovy/" + classPackage + "/BuildSrcClass.groovy", "package " + classPackage + ";\n" +
"public class BuildSrcClass {}");
createProjectSubFile("build.gradle", "buildscript {\n" +
" dependencies {\n" +
" classpath 'my.included:gradle-plugin:0'\n" +
" }\n" +
"}\n" +
"def foo1 = new " + classPackage + ".BuildSrcClass()\n" +
"def foo2 = new " + classPackage + ".IncludedBuildClass()");
createProjectSubFile("app/build.gradle", "def foo1 = new " + classPackage + ".BuildSrcClass()\n" +
"def foo2 = new " + classPackage + ".IncludedBuildClass()");
// included build
createProjectSubFile("gradle-plugin/settings.gradle", "");
createProjectSubFile("gradle-plugin/build.gradle", "group 'my.included'\n" +
"apply plugin: 'java'\n" +
"def foo = new " + classPackage + ".IncludedBuildSrcClass()");
createProjectSubFile("gradle-plugin/buildSrc/src/main/groovy/" + classPackage + "/IncludedBuildSrcClass.groovy",
"package " + classPackage + ";\n" +
"public class IncludedBuildSrcClass {}");
createProjectSubFile("gradle-plugin/src/main/java/" + classPackage + "/IncludedBuildClass.java",
"package " + classPackage + ";\n" +
"public class IncludedBuildClass {}");
}
private void assertUsages(String fqn, GlobalSearchScope scope, int count) throws Exception {
assertUsages(fqn, null, scope, count);
}
private void assertUsages(@NotNull String fqn, @Nullable String methodName, GlobalSearchScope scope, int count) throws Exception {
PsiClass[] psiClasses = runInEdtAndGet(() -> JavaPsiFacade.getInstance(myProject).findClasses(fqn, scope));
assertEquals(1, psiClasses.length);
PsiClass aClass = psiClasses[0];
if (methodName != null) {
PsiMethod[] methods = runInEdtAndGet(() -> aClass.findMethodsByName(methodName, false));
List<UsageInfo> actualUsages = new ArrayList<>();
for (PsiMethod method : methods) {
actualUsages.addAll(findUsages(method));
}
assertUsagesCount(count, actualUsages);
}
else {
assertUsagesCount(count, aClass);
}
}
private void assertUsages(String fqn, int count) throws Exception {
assertUsages(fqn, GlobalSearchScope.projectScope(myProject), count);
}
@SafeVarargs
private void assertUsages(Trinity<String, GlobalSearchScope, Integer>... classUsageCount) throws Exception {
for (Trinity<String, GlobalSearchScope, Integer> trinity : classUsageCount) {
assertUsages(trinity.first, trinity.second, trinity.third);
}
}
@SafeVarargs
private void assertUsages(Pair<String, Integer>... classUsageCount) throws Exception {
for (Pair<String, Integer> pair : classUsageCount) {
assertUsages(Trinity.create(pair.first, GlobalSearchScope.projectScope(myProject), pair.second));
}
}
private static void assertUsagesCount(int expectedUsagesCount, PsiElement element) throws Exception {
assertUsagesCount(expectedUsagesCount, findUsages(element));
}
private static void assertUsagesCount(int expectedUsagesCount, Collection<UsageInfo> usages) throws Exception {
String message = "Found usges: " + runInEdtAndGet(() -> {
StringBuilder buf = new StringBuilder();
for (UsageInfo usage : usages) {
buf.append(usage).append(", from ").append(usage.getVirtualFile().getPath());
Segment navigationRange = usage.getNavigationRange();
if (navigationRange != null) {
buf.append(": ").append(usage.getNavigationRange().getStartOffset())
.append(",").append(usage.getNavigationRange().getEndOffset());
}
buf.append(" \n");
}
return buf.toString();
});
assertEquals(message, expectedUsagesCount, usages.size());
}
}