diff --git a/plugins/devkit/devkit-core/src/testAssistant/GotoTestDataAction.java b/plugins/devkit/devkit-core/src/testAssistant/GotoTestDataAction.java index 82526d3b06aa..4a6eb2cf27cd 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/GotoTestDataAction.java +++ b/plugins/devkit/devkit-core/src/testAssistant/GotoTestDataAction.java @@ -40,7 +40,7 @@ class GotoTestDataAction extends AnAction implements Comparable { @Override public void actionPerformed(@NotNull AnActionEvent e) { RelativePoint point = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext()); - TestDataNavigationHandler.navigate(point, Collections.singletonList(myFilePath), myProject); + TestDataNavigationHandler.navigate(point, Collections.singletonList(new TestDataFile.LazyResolved(myFilePath)), myProject); } @Override diff --git a/plugins/devkit/devkit-core/src/testAssistant/NavigateToTestDataAction.java b/plugins/devkit/devkit-core/src/testAssistant/NavigateToTestDataAction.java index 8e8bdfe5a4e3..7acd759b94b6 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/NavigateToTestDataAction.java +++ b/plugins/devkit/devkit-core/src/testAssistant/NavigateToTestDataAction.java @@ -42,7 +42,7 @@ public class NavigateToTestDataAction extends AnAction implements TestTreeViewAc final RelativePoint point = editor != null ? popupFactory.guessBestPopupLocation(editor) : popupFactory.guessBestPopupLocation(dataContext); - List fileNames = findTestDataFiles(dataContext); + List fileNames = findTestDataFiles(dataContext); if (fileNames == null || fileNames.isEmpty()) { PsiMethod method = findTargetMethod(dataContext); fileNames = method == null ? null : TestDataGuessByExistingFilesUtil.guessTestDataName(method); @@ -61,7 +61,7 @@ public class NavigateToTestDataAction extends AnAction implements TestTreeViewAc } @Nullable - static List findTestDataFiles(@NotNull DataContext context) { + static List findTestDataFiles(@NotNull DataContext context) { final PsiMethod method = findTargetMethod(context); if (method == null) { PsiClass parametrizedTestClass = findParametrizedClass(context); diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataAsRelatedFileProvider.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataAsRelatedFileProvider.java index cb9c0fad36c3..2e9ca49b131f 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/TestDataAsRelatedFileProvider.java +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataAsRelatedFileProvider.java @@ -28,7 +28,7 @@ public class TestDataAsRelatedFileProvider extends GotoRelatedProvider { PsiElement ctxElement = uMethod == null ? NavigateToTestDataAction.findParametrizedClass(context) : uMethod.getSourcePsi(); if (ctxElement == null) return Collections.emptyList(); - List testDataFiles = NavigateToTestDataAction.findTestDataFiles(context); + List testDataFiles = NavigateToTestDataAction.findTestDataFiles(context); return testDataFiles == null || testDataFiles.isEmpty() ? Collections.emptyList() : Collections.singletonList(new TestDataRelatedItem(ctxElement, editor, testDataFiles)); diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataFile.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataFile.java new file mode 100644 index 000000000000..94c40189317d --- /dev/null +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataFile.java @@ -0,0 +1,117 @@ +// Copyright 2000-2018 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.testAssistant; + +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.PathUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +interface TestDataFile { + + boolean exists(); + + @Nullable + VirtualFile getVirtualFile(); + + @NotNull + String getPath(); + + @NotNull + String getName(); + + class Existing implements TestDataFile { + private final VirtualFile myFile; + + public Existing(VirtualFile file) {myFile = file;} + + @Override + public boolean exists() { + return true; + } + + @Override + public VirtualFile getVirtualFile() { + return myFile; + } + + @NotNull + @Override + public String getPath() { + return myFile.getPath(); + } + + @NotNull + @Override + public String getName() { + return myFile.getName(); + } + } + + class NonExisting implements TestDataFile { + private final String myPath; + + public NonExisting(String path) {myPath = path;} + + @Override + public boolean exists() { + return false; + } + + @Override + public VirtualFile getVirtualFile() { + return null; + } + + @NotNull + @Override + public String getPath() { + return myPath; + } + + @NotNull + @Override + public String getName() { + return PathUtil.getFileName(getPath()); + } + } + + class LazyResolved implements TestDataFile { + private final String myPath; + private VirtualFile myFile; + private boolean myResolved; + + public LazyResolved(String path) {myPath = path;} + + private void resolve() { + if (!myResolved) { + myResolved = true; + myFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(myPath); + } + } + + @Override + public boolean exists() { + resolve(); + return getVirtualFile() != null; + } + + @Override + public VirtualFile getVirtualFile() { + resolve(); + return myFile; + } + + @NotNull + @Override + public String getName() { + return PathUtil.getFileName(getPath()); + } + + @NotNull + @Override + public String getPath() { + return myPath; + } + } +} diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataGuessByExistingFilesUtil.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataGuessByExistingFilesUtil.java index 0e9a9d57dd46..4e2af3a5b4c6 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/TestDataGuessByExistingFilesUtil.java +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataGuessByExistingFilesUtil.java @@ -19,6 +19,8 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiFileSystemItem; import com.intellij.psi.PsiMethod; @@ -52,22 +54,16 @@ public class TestDataGuessByExistingFilesUtil { private TestDataGuessByExistingFilesUtil() { } - - @NotNull - static List collectTestDataByExistingFiles(@NotNull PsiMethod psiMethod) { - return collectTestDataByExistingFiles(psiMethod, null); - } - /** * Tries to guess what test data files match to the given method if it's test method and there are existing test data * files for the target test class. * * @param psiMethod test method candidate * @param testDataPath test data path if present (e.g. obtained from @TestDataPath annotation value) - * @return List of paths to the test data files for the given test if it's possible to guess them; empty List otherwise + * @return List of existing test data files for the given test if it's possible to guess them; empty List otherwise */ @NotNull - static List collectTestDataByExistingFiles(@NotNull PsiMethod psiMethod, @Nullable String testDataPath) { + static List collectTestDataByExistingFiles(@NotNull PsiMethod psiMethod, @Nullable String testDataPath) { Application application = ApplicationManager.getApplication(); if (!application.isUnitTestMode() && application.isHeadlessEnvironment()) { // shouldn't be invoked under these conditions anyway, just for additional safety @@ -75,10 +71,10 @@ public class TestDataGuessByExistingFilesUtil { return Collections.emptyList(); } - return buildDescriptorFromExistingTestData(psiMethod, testDataPath).generate(); + return buildDescriptorFromExistingTestData(psiMethod, testDataPath).restoreFiles(); } - static List guessTestDataName(PsiMethod method) { + static List guessTestDataName(PsiMethod method) { String testName = getTestName(method); if (testName == null) return null; PsiClass psiClass = method.getContainingClass(); @@ -87,14 +83,14 @@ public class TestDataGuessByExistingFilesUtil { int count = 5; PsiMethod prev = PsiTreeUtil.getPrevSiblingOfType(method, PsiMethod.class); while (prev != null && count-- > 0) { - List testData = guessTestDataBySiblingTest(prev, testDataBasePath, testName); + List testData = guessTestDataBySiblingTest(prev, testDataBasePath, testName); if (!testData.isEmpty()) return testData; prev = PsiTreeUtil.getPrevSiblingOfType(prev, PsiMethod.class); } count = 5; PsiMethod next = PsiTreeUtil.getNextSiblingOfType(method, PsiMethod.class); while (next != null && count-- > 0) { - List testData = guessTestDataBySiblingTest(next, testDataBasePath, testName); + List testData = guessTestDataBySiblingTest(next, testDataBasePath, testName); if (!testData.isEmpty()) return testData; next = PsiTreeUtil.getNextSiblingOfType(next, PsiMethod.class); } @@ -102,8 +98,8 @@ public class TestDataGuessByExistingFilesUtil { } @NotNull - private static List guessTestDataBySiblingTest(PsiMethod psiMethod, String testDataBasePath, String testName) { - return buildDescriptorFromExistingTestData(psiMethod, testDataBasePath).generate(testName, null); + private static List guessTestDataBySiblingTest(PsiMethod psiMethod, String testDataBasePath, String testName) { + return buildDescriptorFromExistingTestData(psiMethod, testDataBasePath).generateByTemplates(testName, null); } @Nullable @@ -161,10 +157,10 @@ public class TestDataGuessByExistingFilesUtil { return buildDescriptor(testName, psiClass, testDataPath); } - public static List suggestTestDataFiles(@NotNull String testName, - String testDataPath, - @NotNull PsiClass psiClass){ - return buildDescriptor(testName, psiClass, testDataPath).generate(testName, testDataPath); + public static List suggestTestDataFiles(@NotNull String testName, + String testDataPath, + @NotNull PsiClass psiClass) { + return buildDescriptor(testName, psiClass, testDataPath).restoreFiles(); } @NotNull @@ -266,7 +262,7 @@ public class TestDataGuessByExistingFilesUtil { List descriptors = ContainerUtil.flatten(descriptorsByFileNames.values()); filterDirsFromOtherModules(descriptors); - return new TestDataDescriptor(descriptors, possibleFileName); + return new TestDataDescriptor(descriptors); } private static Collection getAllFileNames(final String testName, final GotoFileModel model) { @@ -378,10 +374,11 @@ public class TestDataGuessByExistingFilesUtil { } private static class TestLocationDescriptor { - public String pathPrefix; - public String pathSuffix; - public boolean startWithLowerCase; - public boolean isFromCurrentModule; + String pathPrefix; + String pathSuffix; + boolean startWithLowerCase; + boolean isFromCurrentModule; + int matchedVFileId; public boolean isComplete() { return pathPrefix != null && pathSuffix != null; @@ -407,6 +404,7 @@ public class TestDataGuessByExistingFilesUtil { if (module != null) { isFromCurrentModule = module.equals(ModuleUtilCore.findModuleForFile(matched, project)); } + matchedVFileId = ((VirtualFileWithId)matched).getId(); } @Override @@ -438,37 +436,33 @@ public class TestDataGuessByExistingFilesUtil { } private static class TestDataDescriptor { - private static final TestDataDescriptor NOTHING_FOUND = new TestDataDescriptor(Collections.emptyList(), null); + private static final TestDataDescriptor NOTHING_FOUND = new TestDataDescriptor(Collections.emptyList()); private final List myDescriptors = new ArrayList<>(); - private final String myTestName; - TestDataDescriptor(Collection descriptors, String testName) { - myTestName = testName; + TestDataDescriptor(Collection descriptors) { myDescriptors.addAll(descriptors); } @NotNull - public List generate(@NotNull final String testName) { - return generate(testName, null); + public List restoreFiles() { + return ContainerUtil.mapNotNull(myDescriptors, d -> { + VirtualFile file = VirtualFileManager.getInstance().findFileById(d.matchedVFileId); + return file == null ? null : new TestDataFile.Existing(file); + }); } @NotNull - public List generate() { - return generate(myTestName, null); - } - - @NotNull - public List generate(@NotNull final String testName, String root) { - List result = new ArrayList<>(); + public List generateByTemplates(@NotNull String testName, @Nullable String root) { + List result = new ArrayList<>(); if (StringUtil.isEmpty(testName)) { return result; } for (TestLocationDescriptor descriptor : myDescriptors) { if (root != null && !descriptor.pathPrefix.startsWith(root)) continue; - result.add(descriptor.pathPrefix + (descriptor.startWithLowerCase - ? StringUtil.decapitalize(testName) - : StringUtil.capitalize(testName)) + descriptor.pathSuffix); + result.add(new TestDataFile.NonExisting(descriptor.pathPrefix + (descriptor.startWithLowerCase + ? StringUtil.decapitalize(testName) + : StringUtil.capitalize(testName)) + descriptor.pathSuffix)); } return result; } diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataGuessByTestDiscoveryUtil.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataGuessByTestDiscoveryUtil.java index 78acbe14627e..68ced82c05e4 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/TestDataGuessByTestDiscoveryUtil.java +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataGuessByTestDiscoveryUtil.java @@ -13,6 +13,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.io.IOException; @@ -25,7 +26,7 @@ public class TestDataGuessByTestDiscoveryUtil { private static final Logger LOG = Logger.getInstance(TestDataGuessByTestDiscoveryUtil.class); @NotNull - static List collectTestDataByExistingFiles(@NotNull PsiMethod method) { + static List collectTestDataByExistingFiles(@NotNull PsiMethod method) { if (!isEnabled()) return Collections.emptyList(); PsiClass testClass = method.getContainingClass(); if (testClass == null) return Collections.emptyList(); @@ -45,7 +46,7 @@ public class TestDataGuessByTestDiscoveryUtil { } @NotNull - static List collectTestDataByExistingFiles(@NotNull PsiClass parametrizedTestClass) { + static List collectTestDataByExistingFiles(@NotNull PsiClass parametrizedTestClass) { if (!isEnabled()) return Collections.emptyList(); String testClassQualifiedName = parametrizedTestClass.getQualifiedName(); if (testClassQualifiedName == null) return Collections.emptyList(); @@ -87,8 +88,8 @@ public class TestDataGuessByTestDiscoveryUtil { } @NotNull - List getTestData() { - return myTestData; + List getTestData() { + return ContainerUtil.mapNotNull(myTestData, f -> new TestDataFile.LazyResolved(f)); } } diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataNavigationElementFactory.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataNavigationElementFactory.java index afe7cef24b09..f0243e36bbe3 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/TestDataNavigationElementFactory.java +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataNavigationElementFactory.java @@ -8,11 +8,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.FontUtil; -import com.intellij.util.PathUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,12 +27,12 @@ public class TestDataNavigationElementFactory { } @NotNull - public static TestDataNavigationElement createForNonExistingFile(@NotNull Project project, @NotNull String path) { + public static TestDataNavigationElement createForNonExistingFile(@NotNull Project project, @NotNull TestDataFile path) { return new NonExistingTestDataFileNavigationElement(project, path); } @NotNull - public static TestDataNavigationElement createForFile(@NotNull Project project, @NotNull VirtualFile file) { + public static TestDataNavigationElement createForFile(@NotNull Project project, @NotNull TestDataFile file) { return new TestDataFileNavigationElement(project, file); } @@ -44,23 +42,24 @@ public class TestDataNavigationElementFactory { } @NotNull - public static TestDataNavigationElement createForCreateMissingFilesOption(@NotNull List filePaths) { + public static TestDataNavigationElement createForCreateMissingFilesOption(@NotNull List filePaths) { return new CreateMissingTestDataFilesNavigationElement(filePaths); } private static class CreateMissingTestDataFilesNavigationElement implements TestDataNavigationElement { - private final List myFilePaths; + private final List myFilePaths; - private CreateMissingTestDataFilesNavigationElement(List filePaths) { + private CreateMissingTestDataFilesNavigationElement(List filePaths) { myFilePaths = filePaths; } @Override public void performAction(@NotNull Project project) { Set filePathsToCreate = new HashSet<>(); - for (String path : myFilePaths) { - if (LocalFileSystem.getInstance().refreshAndFindFileByPath(path) == null) { - filePathsToCreate.add(path); + for (TestDataFile file : myFilePaths) { + VirtualFile vFile = file.getVirtualFile(); + if (vFile == null || !vFile.isValid()) { + filePathsToCreate.add(file.getPath()); } } @@ -82,7 +81,7 @@ public class TestDataNavigationElementFactory { } filePathsToCreate.forEach(path -> { - VirtualFile file = TestDataUtil.createFileByName(project, path); + VirtualFile file = TestDataUtil.createFileByPath(project, path); PsiNavigationSupport.getInstance().createNavigatable(project, file, -1).navigate(true); }); } @@ -169,9 +168,9 @@ public class TestDataNavigationElementFactory { private static class NonExistingTestDataFileNavigationElement implements TestDataNavigationElement { private final Project myProject; - private final String myPath; + private final TestDataFile myPath; - private NonExistingTestDataFileNavigationElement(@NotNull Project project, @NotNull String path) { + private NonExistingTestDataFileNavigationElement(@NotNull Project project, @NotNull TestDataFile path) { myProject = project; myPath = path; } @@ -190,9 +189,9 @@ public class TestDataNavigationElementFactory { @NotNull @Override public List> getTitleFragments() { - Pair relativePath = TestDataUtil.getRelativePathPairForMissingFile(myProject, myPath); + Pair relativePath = TestDataUtil.getRelativePathPairForMissingFile(myProject, myPath.getPath()); return ContainerUtil.newSmartList( - new Pair<>(PathUtil.getFileName(myPath) + FontUtil.spaceAndThinSpace(), SimpleTextAttributes.GRAYED_ATTRIBUTES), + new Pair<>(myPath.getName() + FontUtil.spaceAndThinSpace(), SimpleTextAttributes.GRAYED_ATTRIBUTES), new Pair<>(relativePath.first == null ? "" : relativePath.first, SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES), new Pair<>(relativePath.first == null ? "" : "/" + relativePath.second, SimpleTextAttributes.GRAYED_ATTRIBUTES) ); @@ -201,32 +200,37 @@ public class TestDataNavigationElementFactory { private static class TestDataFileNavigationElement implements TestDataNavigationElement { private final Project myProject; - private final VirtualFile myFile; + private final TestDataFile myFile; - private TestDataFileNavigationElement(@NotNull Project project, @NotNull VirtualFile file) { + private TestDataFileNavigationElement(@NotNull Project project, @NotNull TestDataFile file) { myProject = project; myFile = file; } @Override public void performAction(@NotNull Project project) { - TestDataUtil.openOrAskToCreateFile(project, myFile.getPath()); + TestDataUtil.openOrAskToCreateFile(project, myFile); } @Nullable @Override public Icon getIcon() { - return myFile.getFileType().getIcon(); + VirtualFile file = myFile.getVirtualFile(); + assert file != null; + return file.getFileType().getIcon(); } @NotNull @Override public List> getTitleFragments() { - Pair relativePath = TestDataUtil.getModuleOrProjectRelativeParentPath(myProject, myFile); + VirtualFile file = myFile.getVirtualFile(); + assert file != null; + Pair relativePath = TestDataUtil.getModuleOrProjectRelativeParentPath(myProject, myFile.getVirtualFile()); if (relativePath == null) { // cannot calculate module/project relative path, use absolute path + return ContainerUtil.newSmartList(new Pair<>( - String.format("%s (%s)", myFile.getName(), myFile.getParent().getPath() + "/"), + String.format("%s (%s)", myFile.getName(), file.getParent().getPath() + "/"), SimpleTextAttributes.REGULAR_ATTRIBUTES)); } diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataNavigationHandler.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataNavigationHandler.java index c3238d368fa3..ee84c81c22a8 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/TestDataNavigationHandler.java +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataNavigationHandler.java @@ -20,43 +20,37 @@ import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; -import static org.jetbrains.idea.devkit.testAssistant.TestDataUtil.getFileByPath; - public class TestDataNavigationHandler implements GutterIconNavigationHandler { @Override public void navigate(MouseEvent e, PsiMethod elt) { - List fileNames = getFileNames(elt); - - if (fileNames.isEmpty()) { - return; - } + List fileNames = getFileNames(elt); + if (fileNames.isEmpty()) return; navigate(new RelativePoint(e), fileNames, elt.getProject()); } @NotNull - static List getFileNames(PsiMethod method) { + static List getFileNames(PsiMethod method) { return getFileNames(method, true); } @NotNull - static List getFileNames(PsiMethod method, boolean collectByExistingFiles) { - List fileNames = null; + static List getFileNames(PsiMethod method, boolean collectByExistingFiles) { + List fileNames = null; String testDataPath = TestDataLineMarkerProvider.getTestDataBasePath(method.getContainingClass()); if (testDataPath != null) { - fileNames = new TestDataReferenceCollector(testDataPath, method.getName().substring(4)) - .collectTestDataReferences(method, collectByExistingFiles); + fileNames = new TestDataReferenceCollector(testDataPath, method.getName().substring(4)).collectTestDataReferences(method, collectByExistingFiles); } if (collectByExistingFiles && (fileNames == null || fileNames.isEmpty())) { fileNames = new ArrayList<>(); - fileNames.addAll(TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(method)); + fileNames.addAll(TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(method, testDataPath)); fileNames.addAll(TestDataGuessByTestDiscoveryUtil.collectTestDataByExistingFiles(method)); } return fileNames == null ? Collections.emptyList() : fileNames; } public static void navigate(@NotNull RelativePoint point, - @NotNull List testDataFiles, + @NotNull List testDataFiles, Project project) { if (testDataFiles.isEmpty()) return; if (testDataFiles.size() == 1) { @@ -75,6 +69,7 @@ public class TestDataNavigationHandler implements GutterIconNavigationHandler fastGetTestDataPathsByRelativePath(@NotNull String testDataFileRelativePath, PsiMethod method) { return getFileNames(method, false).stream() + .map(TestDataFile::getPath) .filter(path -> path.endsWith(testDataFileRelativePath.startsWith("/") ? testDataFileRelativePath : "/" + testDataFileRelativePath)) .distinct() .collect(Collectors.toList()); @@ -86,21 +81,20 @@ public class TestDataNavigationHandler implements GutterIconNavigationHandler filePaths, RelativePoint point) { - Collections.sort(filePaths, String.CASE_INSENSITIVE_ORDER); + private static void showNavigationPopup(Project project, List filePaths, RelativePoint point) { + Collections.sort(filePaths, Comparator.comparing(TestDataFile::getName, String.CASE_INSENSITIVE_ORDER)); List elementsToDisplay = new ArrayList<>(); List nonExistingElementsToDisplay = new ArrayList<>(); - Set files = new HashSet<>(); - for (String p : filePaths) { - VirtualFile f = getFileByPath(p); - if (f == null) { + Set files = new HashSet<>(); + for (TestDataFile testDataFile : filePaths) { + if (!testDataFile.exists()) { if (nonExistingElementsToDisplay.isEmpty()) { nonExistingElementsToDisplay.add(TestDataNavigationElementFactory.createForCreateMissingFilesOption(filePaths)); } - nonExistingElementsToDisplay.add(TestDataNavigationElementFactory.createForNonExistingFile(project, p)); + nonExistingElementsToDisplay.add(TestDataNavigationElementFactory.createForNonExistingFile(project, testDataFile)); } else { - files.add(f); + files.add(testDataFile); } } @@ -128,39 +122,45 @@ public class TestDataNavigationHandler implements GutterIconNavigationHandler files, + @NotNull Set files, @NotNull Consumer consumer) { - for (Map.Entry> e: ContainerUtil.groupBy(files, f -> f.getParent()).entrySet()) { - Collection dirFiles = e.getValue(); - Set usedPaths = new HashSet<>(); + for (Map.Entry> e: ContainerUtil.groupBy(files, f -> { + VirtualFile file = f.getVirtualFile(); + assert file != null; + return file.getParent(); + }).entrySet()) { + Collection dirFiles = e.getValue(); + Set usedPaths = new HashSet<>(); - for (VirtualFile file1 : dirFiles) { - if (usedPaths.contains(file1)) { + for (TestDataFile testDataFile1 : dirFiles) { + if (usedPaths.contains(testDataFile1)) { continue; } boolean groupFound = false; - for (VirtualFile file2 : dirFiles) { - if (file2.equals(file1) || usedPaths.contains(file2)) { + for (TestDataFile testDataFile2 : dirFiles) { + VirtualFile file2 = testDataFile2.getVirtualFile(); + assert file2 != null; + if (testDataFile1.equals(testDataFile2) || usedPaths.contains(testDataFile1)) { continue; } - TestDataGroupVirtualFile group = TestDataUtil.getTestDataGroup(file1, file2); + TestDataGroupVirtualFile group = TestDataUtil.getTestDataGroup(testDataFile1, testDataFile2); if (group == null) { continue; } groupFound = true; consumer.accept(TestDataNavigationElementFactory.createForGroup(project, group)); - usedPaths.add(file1); - usedPaths.add(file2); + usedPaths.add(testDataFile1); + usedPaths.add(testDataFile2); break; } if (!groupFound) { - consumer.accept(TestDataNavigationElementFactory.createForFile(project, file1)); - usedPaths.add(file1); + consumer.accept(TestDataNavigationElementFactory.createForFile(project, testDataFile1)); + usedPaths.add(testDataFile1); } } } diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataReferenceCollector.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataReferenceCollector.java index aab0bb4d3cc6..bf306676ad5c 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/TestDataReferenceCollector.java +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataReferenceCollector.java @@ -5,6 +5,7 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.NullableComputable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.testFramework.PlatformTestUtil; import org.jetbrains.annotations.NotNull; @@ -40,14 +41,14 @@ public class TestDataReferenceCollector { } @NotNull - List collectTestDataReferences(@NotNull final PsiMethod method) { + List collectTestDataReferences(@NotNull final PsiMethod method) { return collectTestDataReferences(method, true); } @NotNull - List collectTestDataReferences(@NotNull final PsiMethod method, boolean collectByExistingFiles) { + List collectTestDataReferences(@NotNull final PsiMethod method, boolean collectByExistingFiles) { myContainingClass = method.getContainingClass(); - List result = collectTestDataReferences(method, new HashMap<>(), new HashSet<>()); + List result = collectTestDataReferences(method, new HashMap<>(), new HashSet<>()); if (!myFoundTestDataParameters) { myLogMessages.add("Found no parameters annotated with @TestDataFile"); } @@ -61,10 +62,10 @@ public class TestDataReferenceCollector { } @NotNull - private List collectTestDataReferences(final PsiMethod method, - final Map> argumentMap, - final HashSet>> proceed) { - final List result = new ArrayList<>(); + private List collectTestDataReferences(PsiMethod method, + Map> argumentMap, + HashSet>> proceed) { + final List result = new ArrayList<>(); if (myTestDataPath == null) { return result; } @@ -115,7 +116,7 @@ public class TestDataReferenceCollector { } private void processCallArgument(UCallExpression expression, Map> argumentMap, - Collection result, int index) { + Collection result, int index) { List arguments = expression.getValueArguments(); if (arguments.size() > index) { handleArgument(arguments.get(index), argumentMap, result); @@ -123,17 +124,17 @@ public class TestDataReferenceCollector { } private void processVarargCallArgument(UCallExpression expression, Map> argumentMap, - Collection result) { + Collection result) { List arguments = expression.getValueArguments(); for (UExpression argument : arguments) { handleArgument(argument, argumentMap, result); } } - private void handleArgument(UExpression argument, Map> argumentMap, Collection result) { + private void handleArgument(UExpression argument, Map> argumentMap, Collection result) { UValue testDataFileValue = UEvaluationContextKt.uValueOf(argument, new TestDataEvaluatorExtension(argumentMap)); if (testDataFileValue instanceof UStringConstant) { - result.add(myTestDataPath + ((UStringConstant) testDataFileValue).getValue()); + result.add(new TestDataFile.LazyResolved(myTestDataPath + ((UStringConstant)testDataFileValue).getValue())); } } }); diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataRelatedItem.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataRelatedItem.java index adca610c5946..76860d1bd273 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/TestDataRelatedItem.java +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataRelatedItem.java @@ -6,17 +6,16 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.psi.PsiElement; import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.PathUtil; import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Objects; public class TestDataRelatedItem extends GotoRelatedItem { - private final List myTestDataFiles; + private final List myTestDataFiles; private final Editor myEditor; - public TestDataRelatedItem(@NotNull PsiElement location, @NotNull Editor editor, @NotNull List testDataFiles) { + public TestDataRelatedItem(@NotNull PsiElement location, @NotNull Editor editor, @NotNull List testDataFiles) { super(location, "Test Data"); myEditor = editor; myTestDataFiles = testDataFiles; @@ -26,7 +25,7 @@ public class TestDataRelatedItem extends GotoRelatedItem { public String getCustomName() { return myTestDataFiles.size() != 1 ? "Test Data" - : PathUtil.getFileName(myTestDataFiles.get(0)); + : myTestDataFiles.get(0).getName(); } @Override diff --git a/plugins/devkit/devkit-core/src/testAssistant/TestDataUtil.java b/plugins/devkit/devkit-core/src/testAssistant/TestDataUtil.java index 7525578c8543..23e802c64617 100644 --- a/plugins/devkit/devkit-core/src/testAssistant/TestDataUtil.java +++ b/plugins/devkit/devkit-core/src/testAssistant/TestDataUtil.java @@ -3,8 +3,6 @@ package org.jetbrains.idea.devkit.testAssistant; import com.intellij.ide.util.PsiNavigationSupport; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; @@ -20,10 +18,10 @@ import com.intellij.util.PathUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import org.jetbrains.idea.devkit.DevKitBundle; import org.jetbrains.idea.devkit.testAssistant.vfs.TestDataGroupVirtualFile; -import javax.swing.*; import java.io.File; import java.io.IOException; import java.util.Objects; @@ -69,15 +67,16 @@ public class TestDataUtil { return beforeName + " | " + afterName; } + @TestOnly @Nullable static TestDataGroupVirtualFile getTestDataGroup(@NotNull String fileName1, @NotNull String fileName2) { - VirtualFile file1 = getFileByPath(fileName1); - VirtualFile file2 = getFileByPath(fileName2); - return getTestDataGroup(file1, file2); + return getTestDataGroup(new TestDataFile.LazyResolved(fileName1), new TestDataFile.LazyResolved(fileName2)); } @Nullable - static TestDataGroupVirtualFile getTestDataGroup(@Nullable VirtualFile file1, @Nullable VirtualFile file2) { + static TestDataGroupVirtualFile getTestDataGroup(@NotNull TestDataFile testDataFile1, @NotNull TestDataFile testDataFile2) { + VirtualFile file1 = testDataFile1.getVirtualFile(); + VirtualFile file2 = testDataFile2.getVirtualFile(); if (file1 == null || file2 == null) { return null; } @@ -137,7 +136,7 @@ public class TestDataUtil { !StringUtil.containsAlphaCharacters(secondNameExt.replace(TESTDATA_FILE_BEFORE_MARKER, "")); } - static VirtualFile createFileByName(final Project project, final String path) { + static VirtualFile createFileByPath(final Project project, final String path) { return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override public VirtualFile compute() { @@ -154,32 +153,22 @@ public class TestDataUtil { }); } - static void openOrAskToCreateFile(@NotNull Project project, @NotNull String path) { - VirtualFile file = getFileByPath(path); + static void openOrAskToCreateFile(@NotNull Project project, @NotNull TestDataFile testDataFile) { + VirtualFile file = testDataFile.getVirtualFile(); if (file != null) { PsiNavigationSupport.getInstance().createNavigatable(project, file, -1).navigate(true); } else { - String displayPath = getHtmlDisplayPathForMissingFile(project, path); + String displayPath = getHtmlDisplayPathForMissingFile(project, testDataFile.getPath()); int rc = Messages.showYesNoDialog(project, DevKitBundle.message("testdata.file.doesn.not.exist", displayPath), DevKitBundle.message("testdata.create.dialog.title"), Messages.getQuestionIcon()); if (rc == Messages.YES) { - VirtualFile vFile = createFileByName(project, path); + VirtualFile vFile = createFileByPath(project, testDataFile.getPath()); PsiNavigationSupport.getInstance().createNavigatable(project, vFile, -1).navigate(true); } } } - @Nullable - static Icon getIcon(@NotNull String path) { - VirtualFile file = getFileByPath(path); - if (file == null) { - return null; - } - FileType fileType = FileTypeManager.getInstance().getFileTypeByFile(file); - return fileType.getIcon(); - } - @Nullable static VirtualFile getFileByPath(String path) { return LocalFileSystem.getInstance().refreshAndFindFileByPath(path); diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/testAssistant/TestDataGuessByExistingFilesUtilTest.java b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/testAssistant/TestDataGuessByExistingFilesUtilTest.java index f5e6ed0a079e..61c5904cda83 100644 --- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/testAssistant/TestDataGuessByExistingFilesUtilTest.java +++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/testAssistant/TestDataGuessByExistingFilesUtilTest.java @@ -25,6 +25,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.TestDataPath; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.idea.devkit.DevkitJavaTestsUtil; import org.jetbrains.jps.model.java.JavaResourceRootType; @@ -69,59 +70,59 @@ public class TestDataGuessByExistingFilesUtilTest extends TestDataPathTestCase { "Test/testdata_file.txt", "TestMore/testdata_file.txt", "TestMoreRelevant/testdata_file.txt"); PsiClass testClass = (PsiClass)testMethod.getParent(); - List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles("testdata_file", null, testClass); - String resultPath = assertOneElement(result); + List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles("testdata_file", null, testClass); + String resultPath = assertOneElement(result).getPath(); assertTrue(resultPath, resultPath.endsWith("TestMoreRelevant/testdata_file.txt")); } public void testCollectTestDataByExistingFilesBeforeAndAfter() { PsiMethod testMethod = getTestMethodWithBeforeAndAfterTestData(); - List result = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(testMethod); + List result = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(testMethod, null); verifyResultForBeforeAndAfter(result); } public void testSuggestTestDataFilesBeforeAndAfter() { PsiMethod testMethod = getTestMethodWithBeforeAndAfterTestData(); - List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles( + List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles( TestDataGuessByExistingFilesUtil.getTestName(testMethod.getName()), null, testMethod.getContainingClass()); verifyResultForBeforeAndAfter(result); } public void testCollectTestDataByExistingFilesBeforeAndSame() { PsiMethod testMethod = getTestMethodWithBeforeAndSameTestData(); - List result = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(testMethod); + List result = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(testMethod, null); verifyResultForBeforeAndSame(result); } public void testSuggestTestDataFilesBeforeAndSame() { PsiMethod testMethod = getTestMethodWithBeforeAndSameTestData(); - List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles( + List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles( TestDataGuessByExistingFilesUtil.getTestName(testMethod.getName()), null, testMethod.getContainingClass()); verifyResultForBeforeAndSame(result); } public void testCollectTestDataByExistingFilesAfterAndSame() { PsiMethod testMethod = getTestMethodWithAfterAndSameTestData(); - List result = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(testMethod); + List result = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(testMethod, null); verifyResultForAfterAndSame(result); } public void testSuggestTestDataFilesAfterAndSame() { PsiMethod testMethod = getTestMethodWithAfterAndSameTestData(); - List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles( + List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles( TestDataGuessByExistingFilesUtil.getTestName(testMethod.getName()), null, testMethod.getContainingClass()); verifyResultForAfterAndSame(result); } public void testCollectTestDataByExistingFilesOnlySame() { PsiMethod testMethod = getTestMethodWithOnlySameTestData(); - List result = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(testMethod); + List result = TestDataGuessByExistingFilesUtil.collectTestDataByExistingFiles(testMethod, null); verifyResultForOnlySame(result); } public void testSuggestTestDataFilesOnlySame() { PsiMethod testMethod = getTestMethodWithOnlySameTestData(); - List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles( + List result = TestDataGuessByExistingFilesUtil.suggestTestDataFiles( TestDataGuessByExistingFilesUtil.getTestName(testMethod.getName()), null, testMethod.getContainingClass()); verifyResultForOnlySame(result); } @@ -154,34 +155,37 @@ public class TestDataGuessByExistingFilesUtilTest extends TestDataPathTestCase { return testMethod; } - - private static void verifyResultForBeforeAndAfter(List names) { + private static void verifyResultForBeforeAndAfter(List testDataFiles) { + List names = ContainerUtil.map(testDataFiles, TestDataFile::getName); assertNotNull(names); assertEquals(names.toString(), 2, names.size()); Collections.sort(names); - assertTrue(names.get(0), names.get(0).endsWith("somethingBA_after.java")); - assertTrue(names.get(1), names.get(1).endsWith("somethingBA_before.java")); + assertEquals("somethingBA_after.java", names.get(0)); + assertEquals("somethingBA_before.java", names.get(1)); } - private static void verifyResultForBeforeAndSame(List names) { + private static void verifyResultForBeforeAndSame(List testDataFiles) { + List names = ContainerUtil.map(testDataFiles, TestDataFile::getName); assertNotNull(names); assertEquals(names.toString(), 2, names.size()); Collections.sort(names); - assertTrue(names.get(0), names.get(0).endsWith("somethingBS.java")); - assertTrue(names.get(1), names.get(1).endsWith("somethingBS_before.java")); + assertEquals("somethingBS.java", names.get(0)); + assertEquals("somethingBS_before.java", names.get(1)); } - private static void verifyResultForAfterAndSame(List names) { + private static void verifyResultForAfterAndSame(List testDataFiles) { + List names = ContainerUtil.map(testDataFiles, TestDataFile::getName); assertNotNull(names); assertEquals(names.toString(), 2, names.size()); Collections.sort(names); - assertTrue(names.get(0), names.get(0).endsWith("somethingAS.java")); - assertTrue(names.get(1), names.get(1).endsWith("somethingAS_after.java")); + assertEquals("somethingAS.java", names.get(0)); + assertEquals("somethingAS_after.java", names.get(1)); } - private static void verifyResultForOnlySame(List names) { + private static void verifyResultForOnlySame(List testDataFiles) { + List names = ContainerUtil.map(testDataFiles, TestDataFile::getName); assertNotNull(names); - assertEquals(names.toString(), 1, names.size()); - assertTrue(names.get(0), names.get(0).endsWith("somethingS.java")); + assertSize(1, names); + assertEquals("somethingS.java", names.get(0)); } } diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/testAssistant/TestDataReferenceCollectorTest.java b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/testAssistant/TestDataReferenceCollectorTest.java index 7055b7587970..f3ab4f947916 100644 --- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/testAssistant/TestDataReferenceCollectorTest.java +++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/testAssistant/TestDataReferenceCollectorTest.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiJavaFile; import com.intellij.psi.PsiMethod; import com.intellij.testFramework.TestDataPath; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.idea.devkit.DevkitJavaTestsUtil; import java.util.List; @@ -66,7 +67,7 @@ public class TestDataReferenceCollectorTest extends LightCodeInsightFixtureTestC for (PsiClass aClass : classes) { if (aClass.getName().equals("ATest")) { final PsiMethod theMethod = aClass.getMethods()[0]; - return new TestDataReferenceCollector("", theMethod.getName().substring(4)).collectTestDataReferences(theMethod); + return ContainerUtil.map(new TestDataReferenceCollector("", theMethod.getName().substring(4)).collectTestDataReferences(theMethod), f -> f.getPath()); } } throw new RuntimeException("Couldn't find class ATest in test data file");