mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
663 lines
29 KiB
Java
663 lines
29 KiB
Java
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
|
package com.intellij.roots;
|
|
|
|
import com.intellij.configurationStore.StoreUtil;
|
|
import com.intellij.openapi.application.ApplicationManager;
|
|
import com.intellij.openapi.application.WriteAction;
|
|
import com.intellij.openapi.application.ex.PathManagerEx;
|
|
import com.intellij.openapi.module.Module;
|
|
import com.intellij.openapi.module.ModuleManager;
|
|
import com.intellij.openapi.project.DumbService;
|
|
import com.intellij.openapi.project.Project;
|
|
import com.intellij.openapi.projectRoots.JavaSdk;
|
|
import com.intellij.openapi.projectRoots.ProjectJdkTable;
|
|
import com.intellij.openapi.projectRoots.Sdk;
|
|
import com.intellij.openapi.projectRoots.SdkModificator;
|
|
import com.intellij.openapi.roots.*;
|
|
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
|
|
import com.intellij.openapi.roots.impl.ModifiableModelCommitter;
|
|
import com.intellij.openapi.roots.libraries.Library;
|
|
import com.intellij.openapi.roots.libraries.LibraryTable;
|
|
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
|
|
import com.intellij.openapi.util.SystemInfo;
|
|
import com.intellij.openapi.util.io.FileUtil;
|
|
import com.intellij.openapi.vcs.VcsConfiguration;
|
|
import com.intellij.openapi.vcs.changes.VcsIgnoreManager;
|
|
import com.intellij.openapi.vfs.LocalFileSystem;
|
|
import com.intellij.openapi.vfs.VirtualFile;
|
|
import com.intellij.openapi.vfs.VirtualFileManager;
|
|
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
|
|
import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent;
|
|
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
|
|
import com.intellij.testFramework.JavaModuleTestCase;
|
|
import com.intellij.testFramework.VfsTestUtil;
|
|
import com.intellij.util.TimeoutUtil;
|
|
import com.intellij.util.containers.ContainerUtil;
|
|
import com.intellij.util.messages.MessageBusConnection;
|
|
import com.intellij.util.messages.SimpleMessageBusConnection;
|
|
import com.intellij.util.ui.UIUtil;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.jps.model.java.JavaResourceRootType;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.nio.file.Paths;
|
|
import java.util.List;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
/**
|
|
* Checks that proper {@link ModuleRootListener#rootsChanged} events are sent. Consider adding new tests to {@link LibraryRootsChangedTest}
|
|
* or {@link ModuleRootsChangedTest} which use more convenient API.
|
|
*/
|
|
public class RootsChangedTest extends JavaModuleTestCase {
|
|
private MyModuleRootListener myModuleRootListener;
|
|
|
|
@Override
|
|
protected void setUp() throws Exception {
|
|
super.setUp();
|
|
|
|
getOrCreateProjectBaseDir();
|
|
MessageBusConnection connection = myProject.getMessageBus().connect(getTestRootDisposable());
|
|
myModuleRootListener = new MyModuleRootListener(myProject);
|
|
connection.subscribe(ModuleRootListener.TOPIC, myModuleRootListener);
|
|
}
|
|
|
|
@Override
|
|
protected void tearDown() throws Exception {
|
|
myModuleRootListener = null;
|
|
super.tearDown();
|
|
}
|
|
|
|
public void testEventsAfterFileModifications() {
|
|
File root = new File(FileUtil.getTempDirectory());
|
|
|
|
File dir1 = new File(root, "dir1");
|
|
assertTrue(dir1.mkdirs());
|
|
VirtualFile vDir1 = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir1);
|
|
assertNotNull(vDir1);
|
|
|
|
Module moduleA = createModule("a.iml");
|
|
myModuleRootListener.reset();
|
|
|
|
ModuleRootModificationUtil.addContentRoot(moduleA, vDir1.getPath());
|
|
UIUtil.dispatchAllInvocationEvents();
|
|
|
|
myModuleRootListener.assertEventsCount(1);
|
|
assertSameElements(ModuleRootManager.getInstance(moduleA).getContentRoots(), vDir1);
|
|
|
|
VfsTestUtil.deleteFile(vDir1);
|
|
myModuleRootListener.assertEventsCount(1);
|
|
assertEmpty(ModuleRootManager.getInstance(moduleA).getContentRoots());
|
|
|
|
File dir2 = new File(root, "dir2");
|
|
assertTrue(dir2.mkdirs());
|
|
VirtualFile vDir2 = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir2);
|
|
assertNotNull(vDir2);
|
|
|
|
rename(vDir2, "dir1");
|
|
myModuleRootListener.assertEventsCount(1);
|
|
assertSameElements(ModuleRootManager.getInstance(moduleA).getContentRoots(), vDir2);
|
|
|
|
// when the existing root is renamed, it remains a root
|
|
rename(vDir2, "dir2");
|
|
myModuleRootListener.assertEventsCount(1);
|
|
assertSameElements(ModuleRootManager.getInstance(moduleA).getContentRoots(), vDir2);
|
|
|
|
// and event if it is moved, it's still a root
|
|
File subdir = new File(root, "subdir");
|
|
assertTrue(subdir.mkdirs());
|
|
VirtualFile vSubdir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(subdir);
|
|
assertNotNull(vSubdir);
|
|
|
|
move(vDir2, vSubdir);
|
|
myModuleRootListener.assertEventsCount(1);
|
|
assertSameElements(ModuleRootManager.getInstance(moduleA).getContentRoots(), vDir2);
|
|
}
|
|
|
|
public void testProjectLibraryChangeEvent() {
|
|
final LibraryTable projectLibraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(myProject);
|
|
verifyLibraryTableEditing(projectLibraryTable);
|
|
}
|
|
|
|
public void testGlobalLibraryChangeEvent() {
|
|
final LibraryTable globalLibraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable();
|
|
verifyLibraryTableEditing(globalLibraryTable);
|
|
}
|
|
|
|
public void testProjectLibraryEventsInUncommittedModel() {
|
|
final LibraryTable projectLibraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(myProject);
|
|
verifyLibraryTableEditingInUncommittedModel(projectLibraryTable);
|
|
}
|
|
|
|
public void testGlobalLibraryEventsInUncommittedModel() {
|
|
final LibraryTable globalLibraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable();
|
|
verifyLibraryTableEditingInUncommittedModel(globalLibraryTable);
|
|
}
|
|
|
|
public void testEditLibraryForModuleLoadFromXml() {
|
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
|
Module a = loadModule(Paths.get(PathManagerEx.getHomePath(getClass())).resolve("java/java-tests/testData/moduleRootManager/rootsChanged/emptyModule/a.iml"));
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
final Sdk jdk = ProjectJdkTable.getInstance().createSdk("new-jdk", JavaSdk.getInstance());
|
|
ProjectJdkTable.getInstance().addJdk(jdk, getTestRootDisposable());
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
ModuleRootModificationUtil.setModuleSdk(a, jdk);
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
SdkModificator sdkModificator = jdk.getSdkModificator();
|
|
sdkModificator.addRoot(getTempDir().createVirtualDir(), OrderRootType.CLASSES);
|
|
sdkModificator.commitChanges();
|
|
});
|
|
|
|
myModuleRootListener.assertEventsCount(2);
|
|
}
|
|
|
|
public void testModuleJdkEditing() {
|
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
|
final Module moduleA = createModule("a.iml");
|
|
final Module moduleB = createModule("b.iml");
|
|
myModuleRootListener.assertEventsCount(2);
|
|
|
|
final Sdk jdk = ProjectJdkTable.getInstance().createSdk("new-jdk", JavaSdk.getInstance());
|
|
final Sdk unused = ProjectJdkTable.getInstance().createSdk("unused", JavaSdk.getInstance());
|
|
ProjectJdkTable.getInstance().addJdk(jdk, getTestRootDisposable());
|
|
ProjectJdkTable.getInstance().addJdk(unused, getTestRootDisposable());
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel();
|
|
final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel();
|
|
rootModelA.setSdk(jdk);
|
|
rootModelB.setSdk(jdk);
|
|
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
|
|
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
final SdkModificator sdkModificator = jdk.getSdkModificator();
|
|
sdkModificator.addRoot(getTempDir().createVirtualDir(), OrderRootType.CLASSES);
|
|
sdkModificator.commitChanges();
|
|
myModuleRootListener.assertEventsCount(2);
|
|
|
|
final SdkModificator sdkModificator2 = unused.getSdkModificator();
|
|
sdkModificator2.addRoot(getTempDir().createVirtualDir(), OrderRootType.CLASSES);
|
|
sdkModificator2.commitChanges();
|
|
myModuleRootListener.assertNoEvents();
|
|
});
|
|
}
|
|
|
|
public void testSetupUnknownJdk() {
|
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
|
Module module = createModule("a.iml");
|
|
myModuleRootListener.assertEventsCount(1);
|
|
ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
|
|
model.setInvalidSdk("new-jdk", JavaSdk.getInstance().getName());
|
|
model.commit();
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
Sdk unusedJdk = ProjectJdkTable.getInstance().createSdk("unused-jdk", JavaSdk.getInstance());
|
|
ProjectJdkTable.getInstance().addJdk(unusedJdk, getTestRootDisposable());
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
Sdk jdk = ProjectJdkTable.getInstance().createSdk("new-jdk", JavaSdk.getInstance());
|
|
ProjectJdkTable.getInstance().addJdk(jdk, getTestRootDisposable());
|
|
myModuleRootListener.assertEventsCount(2);
|
|
|
|
final SdkModificator sdkModificator = jdk.getSdkModificator();
|
|
sdkModificator.addRoot(getTempDir().createVirtualDir(), OrderRootType.CLASSES);
|
|
sdkModificator.commitChanges();
|
|
myModuleRootListener.assertEventsCount(2);
|
|
});
|
|
}
|
|
|
|
public void testInheritedJdkEditing() {
|
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
|
final Module moduleA = createModule("a.iml");
|
|
final Module moduleB = createModule("b.iml");
|
|
myModuleRootListener.assertEventsCount(2);
|
|
|
|
final Sdk jdk;
|
|
final Sdk jdkBBB;
|
|
jdk = ProjectJdkTable.getInstance().createSdk("AAA", JavaSdk.getInstance());
|
|
ProjectJdkTable.getInstance().addJdk(jdk, getTestRootDisposable());
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
jdkBBB = ProjectJdkTable.getInstance().createSdk("BBB", JavaSdk.getInstance());
|
|
ProjectJdkTable.getInstance().addJdk(jdk, getTestRootDisposable());
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
ProjectRootManager.getInstance(myProject).setProjectSdk(jdkBBB);
|
|
myModuleRootListener.assertNoEvents(true);
|
|
|
|
final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel();
|
|
final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel();
|
|
rootModelA.inheritSdk();
|
|
rootModelB.inheritSdk();
|
|
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
|
|
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
ProjectRootManager.getInstance(myProject).setProjectSdk(jdk);
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
final SdkModificator sdkModificator = jdk.getSdkModificator();
|
|
sdkModificator.addRoot(getTempDir().createVirtualDir(), OrderRootType.CLASSES);
|
|
sdkModificator.commitChanges();
|
|
myModuleRootListener.assertEventsCount(2);
|
|
});
|
|
}
|
|
|
|
private void verifyLibraryTableEditing(final LibraryTable libraryTable) {
|
|
final Module moduleA = createModule("a.iml");
|
|
final Module moduleB = createModule("b.iml");
|
|
myModuleRootListener.assertEventsCount(2);
|
|
|
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
|
final Library libraryA = libraryTable.createLibrary("A");
|
|
final Library.ModifiableModel libraryModifiableModel = libraryA.getModifiableModel();
|
|
libraryModifiableModel.addRoot(someAbsoluteUrl("a"), OrderRootType.CLASSES);
|
|
libraryModifiableModel.commit();
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel();
|
|
final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel();
|
|
rootModelA.addLibraryEntry(libraryA);
|
|
rootModelB.addLibraryEntry(libraryA);
|
|
rootModelA.addInvalidLibrary("Q", libraryTable.getTableLevel());
|
|
rootModelB.addInvalidLibrary("Q", libraryTable.getTableLevel());
|
|
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
|
|
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
Library.ModifiableModel libraryModifiableModel2 = libraryA.getModifiableModel();
|
|
VirtualFile file = getTempDir().createVirtualDir();
|
|
libraryModifiableModel2.addRoot(file.getUrl(), OrderRootType.CLASSES);
|
|
libraryModifiableModel2.commit();
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
libraryTable.removeLibrary(libraryA);
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
final Library libraryQ = libraryTable.createLibrary("Q");
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
Library.ModifiableModel model = libraryQ.getModifiableModel();
|
|
model.addRoot(getTempDir().createVirtualDir(), OrderRootType.CLASSES);
|
|
model.commit();
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
libraryTable.removeLibrary(libraryQ);
|
|
myModuleRootListener.assertEventsCount(1);
|
|
});
|
|
}
|
|
|
|
@NotNull
|
|
private static String someAbsoluteUrl(@NotNull String name) {
|
|
return SystemInfo.isUnix ? "file:///" + name : "file://C:/"+name;
|
|
}
|
|
|
|
private void verifyLibraryTableEditingInUncommittedModel(LibraryTable libraryTable) {
|
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
|
final Module moduleA = createModule("a.iml");
|
|
final Module moduleB = createModule("b.iml");
|
|
myModuleRootListener.assertEventsCount(2);
|
|
|
|
final Library libraryA = libraryTable.createLibrary("A");
|
|
final Library.ModifiableModel libraryModifiableModel = libraryA.getModifiableModel();
|
|
libraryModifiableModel.addRoot(someAbsoluteUrl("a"), OrderRootType.CLASSES);
|
|
libraryModifiableModel.commit();
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel();
|
|
final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel();
|
|
rootModelA.addLibraryEntry(libraryA);
|
|
rootModelB.addLibraryEntry(libraryA);
|
|
final Library.ModifiableModel libraryModifiableModel2 = libraryA.getModifiableModel();
|
|
libraryModifiableModel2.addRoot(someAbsoluteUrl("b"), OrderRootType.CLASSES);
|
|
libraryModifiableModel2.commit();
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
libraryTable.removeLibrary(libraryA);
|
|
myModuleRootListener.assertNoEvents(true);
|
|
|
|
rootModelA.addInvalidLibrary("Q", libraryTable.getTableLevel());
|
|
rootModelB.addInvalidLibrary("Q", libraryTable.getTableLevel());
|
|
myModuleRootListener.assertNoEvents();
|
|
|
|
final Library libraryQ = libraryTable.createLibrary("Q");
|
|
myModuleRootListener.assertNoEvents(true);
|
|
|
|
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
|
|
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
libraryTable.removeLibrary(libraryQ);
|
|
myModuleRootListener.assertEventsCount(1);
|
|
});
|
|
}
|
|
|
|
static class MyModuleRootListener implements ModuleRootListener {
|
|
private final Project myProject;
|
|
private int beforeCount;
|
|
private int afterCount;
|
|
private long modificationCount;
|
|
|
|
MyModuleRootListener(Project project) {
|
|
myProject = project;
|
|
}
|
|
|
|
@Override
|
|
public void beforeRootsChange(@NotNull ModuleRootEvent event) {
|
|
beforeCount++;
|
|
}
|
|
|
|
@Override
|
|
public void rootsChanged(@NotNull ModuleRootEvent event) {
|
|
afterCount++;
|
|
}
|
|
|
|
void reset() {
|
|
beforeCount = 0;
|
|
afterCount = 0;
|
|
modificationCount = ProjectRootManager.getInstance(myProject).getModificationCount();
|
|
}
|
|
|
|
void assertEventsCountAndIncrementModificationCount(int eventsCount,
|
|
boolean modificationCountMustBeIncremented,
|
|
boolean modificationCountMayBeIncremented) {
|
|
final int beforeCount = this.beforeCount;
|
|
final int afterCount = this.afterCount;
|
|
assertEquals("beforeCount = " + beforeCount + ", afterCount = " + afterCount, beforeCount, afterCount);
|
|
assertEquals(eventsCount, beforeCount);
|
|
long currentModificationCount = ProjectRootManager.getInstance(myProject).getModificationCount();
|
|
if (modificationCountMayBeIncremented) {
|
|
assertTrue(currentModificationCount >= modificationCount);
|
|
}
|
|
else if (modificationCountMustBeIncremented) {
|
|
assertTrue(currentModificationCount > modificationCount);
|
|
}
|
|
else {
|
|
assertEquals(modificationCount, currentModificationCount);
|
|
}
|
|
reset();
|
|
}
|
|
|
|
void assertNoEvents(boolean modificationCountMayBeIncremented) {
|
|
assertEventsCountAndIncrementModificationCount(0, false, modificationCountMayBeIncremented);
|
|
}
|
|
|
|
void assertEventsCount(int count) {
|
|
assertEventsCountAndIncrementModificationCount(count, count != 0, false);
|
|
}
|
|
|
|
void assertNoEvents() {
|
|
assertNoEvents(false);
|
|
}
|
|
}
|
|
|
|
// create ".idea" - based project because it's 1) needed for testShelveChangesMustNotLeadToRootsChangedEvent and 2) is more common
|
|
@Override
|
|
protected boolean isCreateDirectoryBasedProject() {
|
|
return true;
|
|
}
|
|
|
|
public void testShelveChangesMustNotLeadToRootsChangedEvent() {
|
|
// create .idea
|
|
StoreUtil.saveSettings(getProject());
|
|
VirtualFile shelf = createChildDirectory(getProject().getProjectFile().getParent(), "shelf");
|
|
VcsIgnoreManager vcsIgnoreManager = VcsIgnoreManager.getInstance(myProject);
|
|
|
|
myModuleRootListener.reset();
|
|
|
|
VirtualFile xxx = createChildData(shelf, "shelf1.dat");
|
|
assertTrue(vcsIgnoreManager.isPotentiallyIgnoredFile(xxx));
|
|
|
|
assertEquals(myModuleRootListener.modificationCount, ProjectRootManager.getInstance(myProject).getModificationCount());
|
|
|
|
VirtualFile newShelf = createChildDirectory(getOrCreateProjectBaseDir().getParent(), "newShelf");
|
|
VcsConfiguration vcs = VcsConfiguration.getInstance(myProject);
|
|
vcs.USE_CUSTOM_SHELF_PATH = true;
|
|
vcs.CUSTOM_SHELF_PATH = newShelf.getPath();
|
|
myModuleRootListener.reset();
|
|
|
|
VirtualFile xxx2 = createChildData(newShelf, "shelf1.dat");
|
|
assertTrue(vcsIgnoreManager.isPotentiallyIgnoredFile(xxx2));
|
|
}
|
|
|
|
public void testCreationDeletionOfRootDirectoriesMustLeadToRootsChanged() {
|
|
File root = new File(FileUtil.getTempDirectory());
|
|
|
|
File dir1 = new File(root, "dir1");
|
|
assertTrue(dir1.mkdirs());
|
|
VirtualFile contentRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir1);
|
|
assertNotNull(contentRoot);
|
|
|
|
Module moduleA = createModule("a.iml");
|
|
ModuleRootModificationUtil.addContentRoot(moduleA, contentRoot.getPath());
|
|
String excludedUrl = contentRoot.getUrl() + "/excluded";
|
|
String sourceUrl = contentRoot.getUrl() + "/src";
|
|
String testSourceUrl = contentRoot.getUrl() + "/testSrc";
|
|
String outputUrl = contentRoot.getUrl() + "/out";
|
|
String testOutputUrl = contentRoot.getUrl() + "/testOut";
|
|
String resourceUrl = contentRoot.getUrl() + "/res";
|
|
String testResourceUrl = contentRoot.getUrl() + "/testRes";
|
|
|
|
ModuleRootModificationUtil.updateModel(moduleA, model -> {
|
|
ContentEntry entry = ContainerUtil.find(model.getContentEntries(), e-> contentRoot.equals(e.getFile()));
|
|
|
|
entry.addExcludeFolder(excludedUrl);
|
|
entry.addSourceFolder(sourceUrl, false);
|
|
entry.addSourceFolder(testSourceUrl, true);
|
|
entry.addSourceFolder(resourceUrl, JavaResourceRootType.RESOURCE);
|
|
entry.addSourceFolder(testResourceUrl, JavaResourceRootType.TEST_RESOURCE);
|
|
|
|
CompilerModuleExtension moduleExtension = model.getModuleExtension(CompilerModuleExtension.class);
|
|
moduleExtension.inheritCompilerOutputPath(false);
|
|
moduleExtension.setCompilerOutputPath(outputUrl);
|
|
moduleExtension.setCompilerOutputPathForTests(testOutputUrl);
|
|
});
|
|
|
|
checkRootChangedOnDirCreationDeletion(contentRoot, excludedUrl, 1);
|
|
checkRootChangedOnDirCreationDeletion(contentRoot, sourceUrl, 1);
|
|
checkRootChangedOnDirCreationDeletion(contentRoot, testSourceUrl, 1);
|
|
checkRootChangedOnDirCreationDeletion(contentRoot, resourceUrl, 1);
|
|
checkRootChangedOnDirCreationDeletion(contentRoot, testResourceUrl, 1);
|
|
checkRootChangedOnDirCreationDeletion(contentRoot, outputUrl, 1);
|
|
checkRootChangedOnDirCreationDeletion(contentRoot, testOutputUrl, 1);
|
|
checkRootChangedOnDirCreationDeletion(contentRoot, "xxx", 0);
|
|
}
|
|
|
|
private void checkRootChangedOnDirCreationDeletion(VirtualFile contentRoot, String dirUrl, int mustGenerateEvents) {
|
|
myModuleRootListener.reset();
|
|
UIUtil.dispatchAllInvocationEvents();
|
|
|
|
VirtualFile dir = createChildDirectory(contentRoot, new File(dirUrl).getName());
|
|
myModuleRootListener.assertEventsCount(mustGenerateEvents);
|
|
|
|
myModuleRootListener.reset();
|
|
UIUtil.dispatchAllInvocationEvents();
|
|
delete(dir);
|
|
myModuleRootListener.assertEventsCount(mustGenerateEvents);
|
|
}
|
|
|
|
public void testEmptyDirectoryCreatedAndSomeRogueFileListenerImmediatelyCallsGetChildrenPreventingFurtherCreationEventsForFilesThatHappenedToBeAlreadyThereByThatMoment() {
|
|
File ioRoot = new File(FileUtil.getTempDirectory());
|
|
|
|
VirtualFile vRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioRoot);
|
|
vRoot.getChildren();
|
|
|
|
Module module = createModule("a.iml");
|
|
ModuleRootModificationUtil.addContentRoot(module, vRoot.getPath());
|
|
ModuleRootModificationUtil.updateModel(module, model -> model.getContentEntries()[0].addExcludeFolder(vRoot.getUrl() + "/parent/excluded"));
|
|
|
|
MessageBusConnection connect = ApplicationManager.getApplication().getMessageBus().connect(getTestRootDisposable());
|
|
BulkFileListener rogueListenerWhichStupidlyGetChildrenRightAway = new BulkFileListener() {
|
|
@Override
|
|
public void after(@NotNull List<? extends @NotNull VFileEvent> events) {
|
|
for (VFileEvent event : events) {
|
|
VirtualFile file = event.getFile();
|
|
if (event instanceof VFileCreateEvent && file != null) {
|
|
file.getChildren();// aaaaaaaaah!
|
|
}
|
|
}
|
|
}
|
|
};
|
|
connect.subscribe(VirtualFileManager.VFS_CHANGES, rogueListenerWhichStupidlyGetChildrenRightAway);
|
|
|
|
myModuleRootListener.reset();
|
|
|
|
File iParent = new File(ioRoot, "parent");
|
|
assertTrue(iParent.mkdirs());
|
|
vRoot.refresh(true, true);
|
|
|
|
TimeoutUtil.sleep(1000); // hope that now async refresh has found "parent" and is waiting for EDT to fire events
|
|
|
|
File ioExcluded = new File(iParent, "excluded");
|
|
assertTrue(ioExcluded.mkdirs());
|
|
UIUtil.dispatchAllInvocationEvents(); // now events are fired
|
|
|
|
assertNotNull(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioExcluded));
|
|
|
|
myModuleRootListener.assertEventsCount(1);
|
|
}
|
|
|
|
public void testChangesInsideCompilerOutputDirectoryMustNotLeadToRootsChange() {
|
|
File temp = new File(FileUtil.getTempDirectory());
|
|
VirtualFile root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp);
|
|
VirtualFile content = VfsTestUtil.createDir(root, "content");
|
|
|
|
Module module = createModule("a.iml");
|
|
ModuleRootModificationUtil.addContentRoot(module, content.getPath());
|
|
VirtualFile out = VfsTestUtil.createDir(root, "out");
|
|
|
|
ModuleRootModificationUtil.updateModel(module, model -> {
|
|
CompilerModuleExtension moduleExtension = model.getModuleExtension(CompilerModuleExtension.class);
|
|
moduleExtension.inheritCompilerOutputPath(false);
|
|
moduleExtension.setCompilerOutputPath(out);
|
|
moduleExtension.setCompilerOutputPathForTests(out);
|
|
});
|
|
|
|
myModuleRootListener.reset();
|
|
VirtualFile f1 = VfsTestUtil.createFile(out, "x/x.txt");
|
|
VirtualFile f2 = VfsTestUtil.createFile(out, "x/x.class");
|
|
myModuleRootListener.assertEventsCount(0);
|
|
VfsTestUtil.deleteFile(f1);
|
|
VfsTestUtil.deleteFile(f2);
|
|
myModuleRootListener.assertEventsCount(0);
|
|
}
|
|
|
|
public void testBulkRootsChanging() {
|
|
WriteAction.run(() -> {
|
|
myModuleRootListener.reset();
|
|
ProjectRootManagerEx.getInstanceEx(myProject).mergeRootsChangesDuring(() -> {
|
|
for (int i = 0; i < 10; i++) {
|
|
ModifiableRootModel model = ModuleRootManager.getInstance(myModule).getModifiableModel();
|
|
try {
|
|
File dir = createTempDir("src-" + i);
|
|
VirtualFile vDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir);
|
|
model.addContentEntry(vDir);
|
|
}
|
|
catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
model.commit();
|
|
|
|
assertEquals(1, myModuleRootListener.beforeCount);
|
|
assertEquals(0, myModuleRootListener.afterCount);
|
|
}
|
|
});
|
|
myModuleRootListener.assertEventsCount(1);
|
|
});
|
|
}
|
|
|
|
public void testRootDirDeletionDoesntLeadToIndexing() throws IOException {
|
|
File contentRoot = createTempDir("content-root");
|
|
File excludedRoot = new File(contentRoot, "excluded-root");
|
|
assertTrue(excludedRoot.mkdirs());
|
|
VirtualFile excludedRootVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(excludedRoot);
|
|
|
|
ModuleRootModificationUtil.updateModel(myModule, model -> model.addContentEntry(excludedRootVFile.getParent()).addExcludeFolder(excludedRootVFile));
|
|
|
|
AtomicInteger dumbModeCount = new AtomicInteger();
|
|
SimpleMessageBusConnection connection = myProject.getMessageBus().simpleConnect();
|
|
try {
|
|
connection.subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() {
|
|
@Override
|
|
public void enteredDumbMode() {
|
|
dumbModeCount.incrementAndGet();
|
|
}
|
|
});
|
|
|
|
FileUtil.delete(excludedRoot);
|
|
excludedRootVFile.refresh(false, true);
|
|
assertFalse(excludedRootVFile.isValid());
|
|
assertEquals(0, dumbModeCount.get());
|
|
}
|
|
finally {
|
|
connection.disconnect();
|
|
}
|
|
}
|
|
|
|
public void testRootsChangeEventAtCreatingAndMoveFolderUnderJarDir() throws IOException {
|
|
String rootJarDirName = "jarDir";
|
|
|
|
File temp = new File(FileUtil.getTempDirectory());
|
|
VirtualFile root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp);
|
|
VirtualFile jarDir = VfsTestUtil.createDir(root, rootJarDirName);
|
|
|
|
LibraryTable projectLibraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(myProject);
|
|
LibraryTable.ModifiableModel projectLibraryTableModifiableModel = projectLibraryTable.getModifiableModel();
|
|
Library projectLib = projectLibraryTableModifiableModel.createLibrary("lib");
|
|
Library.ModifiableModel modifiableModel = projectLib.getModifiableModel();
|
|
modifiableModel.addJarDirectory(jarDir, false);
|
|
WriteAction.runAndWait(() -> {
|
|
modifiableModel.commit();
|
|
projectLibraryTableModifiableModel.commit();
|
|
});
|
|
|
|
myModuleRootListener.reset();
|
|
// Creating simple file - first event
|
|
VfsTestUtil.createFile(jarDir, "test.txt");
|
|
// Creating folder - second event
|
|
VirtualFile newVirtualDirectory = VfsTestUtil.createDir(jarDir, "foo");
|
|
// Recursive folder creating - third event
|
|
VfsTestUtil.createDir(newVirtualDirectory, "bar");
|
|
myModuleRootListener.assertEventsCount(3);
|
|
|
|
VirtualFile otherFolder = VfsTestUtil.createDir(root, "baz");
|
|
myModuleRootListener.assertNoEvents();
|
|
WriteAction.runAndWait(() -> otherFolder.move(this, newVirtualDirectory));
|
|
myModuleRootListener.assertEventsCount(1);
|
|
}
|
|
|
|
public void testRootsChangeEventAtRenameCopyAndDeleteFileUnderJarDir() throws IOException {
|
|
String rootJarDirName = "jarDir";
|
|
|
|
File temp = new File(FileUtil.getTempDirectory());
|
|
VirtualFile root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp);
|
|
VirtualFile testFileUnderRoot = VfsTestUtil.createFile(root, "test.jar");
|
|
|
|
VirtualFile jarDir = VfsTestUtil.createDir(root, rootJarDirName);
|
|
VirtualFile testFileUnderJarDir = VfsTestUtil.createFile(jarDir, "test.jar");
|
|
|
|
LibraryTable projectLibraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(myProject);
|
|
LibraryTable.ModifiableModel projectLibraryTableModifiableModel = projectLibraryTable.getModifiableModel();
|
|
Library projectLib = projectLibraryTableModifiableModel.createLibrary("lib");
|
|
Library.ModifiableModel modifiableModel = projectLib.getModifiableModel();
|
|
modifiableModel.addJarDirectory(jarDir, false);
|
|
WriteAction.runAndWait(() -> {
|
|
modifiableModel.commit();
|
|
projectLibraryTableModifiableModel.commit();
|
|
});
|
|
|
|
myModuleRootListener.reset();
|
|
WriteAction.runAndWait(() -> testFileUnderJarDir.rename(this, "test2.jar"));
|
|
myModuleRootListener.assertEventsCount(1);
|
|
WriteAction.runAndWait(() -> testFileUnderJarDir.delete(this));
|
|
myModuleRootListener.assertEventsCount(1);
|
|
|
|
WriteAction.runAndWait(() -> testFileUnderRoot.copy(this, jarDir, "test2.jar"));
|
|
myModuleRootListener.assertEventsCount(1);
|
|
}
|
|
}
|