mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-178996 References for @TestDataFile-annotated method arguments for @TestDataPath-annotated testcases
This commit is contained in:
@@ -174,6 +174,7 @@
|
||||
<implicitUsageProvider implementation="org.jetbrains.idea.devkit.inspections.DevKitImplicitUsageProvider"/>
|
||||
<psi.referenceContributor language="XML" implementation="org.jetbrains.idea.devkit.dom.impl.I18nReferenceContributor"/>
|
||||
<psi.referenceContributor implementation="org.jetbrains.idea.devkit.references.IconsReferencesContributor"/>
|
||||
<psi.referenceContributor implementation="org.jetbrains.idea.devkit.references.TestDataFilesReferencesContributor" />
|
||||
<referencesSearch implementation="org.jetbrains.idea.devkit.references.IconsReferencesContributor"/>
|
||||
<unusedDeclarationFixProvider implementation="org.jetbrains.idea.devkit.inspections.quickfix.RegisterExtensionFixProvider"/>
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
// Copyright 2000-2017 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.idea.devkit.references;
|
||||
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.patterns.PsiJavaElementPattern;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.testFramework.TestDataFile;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.devkit.testAssistant.TestDataNavigationHandler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiMethod;
|
||||
|
||||
public class TestDataFilesReferencesContributor extends PsiReferenceContributor {
|
||||
private static final String TEST_DATA_FILE_ANNOTATION_QUALIFIED_NAME = TestDataFile.class.getCanonicalName();
|
||||
|
||||
@Override
|
||||
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
|
||||
PsiJavaElementPattern.Capture<PsiElement> capture = psiElement().methodCallParameter(psiMethod());
|
||||
registrar.registerReferenceProvider(capture, new PsiReferenceProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
|
||||
PsiLiteralExpression expression = (PsiLiteralExpression)element;
|
||||
PsiElement expressionParent = expression.getParent();
|
||||
if (!(expressionParent instanceof PsiExpressionList)) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
PsiExpressionList expressionList = (PsiExpressionList)expressionParent;
|
||||
PsiExpression[] expressions = expressionList.getExpressions();
|
||||
|
||||
int index = getExpressionIndex(expression, expressions);
|
||||
if (index < 0) {
|
||||
// shouldn't happen
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
PsiMethodCallExpression methodCallExpression = getMethodCallExpression(expression);
|
||||
PsiParameter targetParameter = getTargetParameter(index, methodCallExpression);
|
||||
if (!checkTestDataFileAnnotationPresent(targetParameter)) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
String testDataFilePath = getTestDataFilePath(expression, methodCallExpression);
|
||||
if (testDataFilePath == null) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
String directory = PathUtil.getParentPath(testDataFilePath);
|
||||
FileReferenceSet fileReferenceSet = new FileReferenceSet(element);
|
||||
fileReferenceSet.addCustomization(
|
||||
FileReferenceSet.DEFAULT_PATH_EVALUATOR_OPTION,
|
||||
ignore -> {
|
||||
VirtualFile file = LocalFileSystem.getInstance().findFileByPath(directory);
|
||||
return file == null ? null : Collections.singleton(element.getManager().findDirectory(file));
|
||||
});
|
||||
|
||||
return fileReferenceSet.getAllReferences();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static int getExpressionIndex(@NotNull PsiLiteralExpression expression, @NotNull PsiExpression[] expressions) {
|
||||
int index = -1;
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
PsiExpression e = expressions[i];
|
||||
if (expression.equals(e)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethodCallExpression getMethodCallExpression(@NotNull PsiLiteralExpression expression) {
|
||||
PsiElement expressionContext = expression.getContext();
|
||||
if (expressionContext == null) {
|
||||
return null;
|
||||
}
|
||||
PsiElement methodCallExpression = expressionContext.getContext();
|
||||
if (!(methodCallExpression instanceof PsiMethodCallExpression)) {
|
||||
return null;
|
||||
}
|
||||
return (PsiMethodCallExpression)methodCallExpression;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiParameter getTargetParameter(int index, @Nullable PsiMethodCallExpression methodCallExpression) {
|
||||
if (methodCallExpression == null) {
|
||||
return null;
|
||||
}
|
||||
PsiMethod callMethod = methodCallExpression.resolveMethod();
|
||||
if (callMethod == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiParameter[] parameters = callMethod.getParameterList().getParameters();
|
||||
// index may be greater than parameters length in case of varargs
|
||||
return index >= parameters.length ? parameters[parameters.length - 1] : parameters[index];
|
||||
}
|
||||
|
||||
private static boolean checkTestDataFileAnnotationPresent(@Nullable PsiParameter targetParameter) {
|
||||
if (targetParameter == null) {
|
||||
return false;
|
||||
}
|
||||
PsiAnnotation[] annotations = targetParameter.getAnnotations();
|
||||
for (PsiAnnotation annotation : annotations) {
|
||||
if (TEST_DATA_FILE_ANNOTATION_QUALIFIED_NAME.equals(annotation.getQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getTestDataFilePath(@NotNull PsiLiteralExpression expression,
|
||||
@NotNull PsiMethodCallExpression methodCallExpression) {
|
||||
Object value = expression.getValue();
|
||||
if (!(value instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String relativePath = (String)value;
|
||||
PsiMethod testMethod = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethod.class);
|
||||
if (testMethod == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> filePaths = TestDataNavigationHandler.fastGetTestDataPathsByRelativePath(relativePath, testMethod);
|
||||
if (filePaths.size() != 1) {
|
||||
return null;
|
||||
}
|
||||
return filePaths.get(0);
|
||||
}
|
||||
}
|
||||
@@ -74,11 +74,11 @@ public class TestDataGuessByExistingFilesUtil {
|
||||
* @return collection of paths to the test data files for the given test if it's possible to guess them;
|
||||
* {@code null} otherwise
|
||||
*/
|
||||
@Nullable
|
||||
@NotNull
|
||||
static List<String> collectTestDataByExistingFiles(@NotNull PsiMethod psiMethod) {
|
||||
TestDataDescriptor descriptor = buildDescriptorFromExistingTestData(psiMethod);
|
||||
if (descriptor == null || !descriptor.isComplete()) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return descriptor.generate();
|
||||
}
|
||||
@@ -108,7 +108,7 @@ public class TestDataGuessByExistingFilesUtil {
|
||||
@Nullable
|
||||
private static String getFilePath(PsiMethod psiMethod, String testName) {
|
||||
List<String> strings = collectTestDataByExistingFiles(psiMethod);
|
||||
if (strings != null && !strings.isEmpty()) {
|
||||
if (!strings.isEmpty()) {
|
||||
String s = strings.get(0);
|
||||
return new File(new File(s).getParent(), testName + "." + FileUtilRt.getExtension(new File(s).getName())).getPath();
|
||||
}
|
||||
|
||||
@@ -26,35 +26,43 @@ import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.devkit.testAssistant.vfs.TestDataGroupVirtualFile;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TestDataNavigationHandler implements GutterIconNavigationHandler<PsiMethod> {
|
||||
@Override
|
||||
public void navigate(MouseEvent e, PsiMethod elt) {
|
||||
List<String> fileNames = getFileNames(elt);
|
||||
|
||||
if (fileNames == null || fileNames.isEmpty()) {
|
||||
if (fileNames.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
navigate(new RelativePoint(e), fileNames, elt.getProject());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
static List<String> getFileNames(PsiMethod method) {
|
||||
return getFileNames(method, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static List<String> getFileNames(PsiMethod method, boolean collectByExistingFiles) {
|
||||
List<String> fileNames = null;
|
||||
String testDataPath = TestDataLineMarkerProvider.getTestDataBasePath(method.getContainingClass());
|
||||
if (testDataPath != null) {
|
||||
fileNames = new TestDataReferenceCollector(testDataPath, method.getName().substring(4)).collectTestDataReferences(method);
|
||||
}
|
||||
|
||||
if (fileNames == null || fileNames.isEmpty()) {
|
||||
if (collectByExistingFiles && (fileNames == null || fileNames.isEmpty())) {
|
||||
fileNames = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(method);
|
||||
}
|
||||
if (fileNames == null) {
|
||||
fileNames = Collections.emptyList();
|
||||
}
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
@@ -75,6 +83,14 @@ public class TestDataNavigationHandler implements GutterIconNavigationHandler<Ps
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<String> fastGetTestDataPathsByRelativePath(@NotNull String testDataFileRelativePath, PsiMethod method) {
|
||||
return getFileNames(method, false).stream()
|
||||
.filter(path -> path.endsWith(testDataFileRelativePath.startsWith("/") ? testDataFileRelativePath : "/" + testDataFileRelativePath))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows navigation popup with list of testdata files and (optionally) "Create missing files" option.
|
||||
* @param project project.
|
||||
|
||||
@@ -54,7 +54,7 @@ public class TestDataReferenceCollector {
|
||||
myTestName = testName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
List<String> collectTestDataReferences(@NotNull final PsiMethod method) {
|
||||
myContainingClass = method.getContainingClass();
|
||||
List<String> result = collectTestDataReferences(method, new HashMap<>(), new HashSet<>());
|
||||
|
||||
Reference in New Issue
Block a user