/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.openapi.vfs.local; import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.impl.local.FileWatcher; import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.events.*; import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; import com.intellij.testFramework.PlatformLangTestCase; import com.intellij.util.Alarm; import com.intellij.util.Function; import com.intellij.util.TimeoutUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.util.*; import java.util.function.Consumer; import static com.intellij.openapi.util.io.IoTestUtil.*; public class FileWatcherTest extends PlatformLangTestCase { private static final int INTER_RESPONSE_DELAY = 500; // time to wait for a next event in a sequence private static final int NATIVE_PROCESS_DELAY = 60000; // time to wait for a native watcher response private static Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.impl.local.FileWatcher"); private FileWatcher myWatcher; private LocalFileSystem myFileSystem; private MessageBusConnection myConnection; private volatile boolean myAccept = false; private Alarm myAlarm; private final Runnable myNotifier = new Runnable() { @Override public void run() { LOG.debug("-- (event, expected=" + myAccept + ")"); if (!myAccept) return; myAlarm.cancelAllRequests(); myAlarm.addRequest(new Runnable() { @Override public void run() { myAccept = false; LOG.debug("** waiting finished"); synchronized (myWaiter) { myWaiter.notifyAll(); } } }, INTER_RESPONSE_DELAY); } }; private final Object myWaiter = new Object(); private int myTimeout = NATIVE_PROCESS_DELAY; private final List<VFileEvent> myEvents = ContainerUtil.newArrayList(); private final List<String> myAcceptedDirectories = ContainerUtil.newArrayList(); @Override protected void setUp() throws Exception { LOG.debug("================== setting up " + getName() + " =================="); super.setUp(); myFileSystem = LocalFileSystem.getInstance(); assertNotNull(myFileSystem); myWatcher = ((LocalFileSystemImpl)myFileSystem).getFileWatcher(); assertNotNull(myWatcher); assertFalse(myWatcher.isOperational()); myWatcher.startup(new Consumer<Boolean>() { @Override public void accept(Boolean reset) { myAlarm.cancelAllRequests(); myAlarm.addRequest(() -> { myAccept = false; LOG.debug("** waiting finished"); synchronized (myWaiter) { myWaiter.notifyAll(); } }, INTER_RESPONSE_DELAY); //if (reset) resetHappened.set(true); } }); assertTrue(myWatcher.isOperational()); myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, getProject()); myTimeout = NATIVE_PROCESS_DELAY; myConnection = ApplicationManager.getApplication().getMessageBus().connect(); myConnection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener.Adapter() { @Override public void after(@NotNull List<? extends VFileEvent> events) { synchronized (myEvents) { myEvents.addAll(events); } } }); ((LocalFileSystemImpl)myFileSystem).cleanupForNextTest(); myAcceptedDirectories.clear(); myAcceptedDirectories.add(FileUtil.getTempDirectory()); LOG.debug("================== setting up " + getName() + " =================="); } @Override protected void tearDown() throws Exception { LOG.debug("================== tearing down " + getName() + " =================="); try { myConnection.disconnect(); myWatcher.shutdown(); assertFalse(myWatcher.isOperational()); } finally { myFileSystem = null; myWatcher = null; super.tearDown(); } LOG.debug("================== tearing down " + getName() + " =================="); } public void testFileRoot() throws Exception { File file = createTestFile("test.txt"); refresh(file); LocalFileSystem.WatchRequest request = watch(file); try { myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, file.getPath()); myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, file.getPath()); myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, file.getPath()); } finally { unwatch(request); delete(file); } } public void testNonCanonicallyNamedFileRoot() throws Exception { if (SystemInfo.isFileSystemCaseSensitive) { System.err.println("Ignored: case-insensitive FS required"); return; } File file = createTestFile("test.txt"); refresh(file); String watchRoot = file.getPath().toUpperCase(Locale.US); LocalFileSystem.WatchRequest request = watch(new File(watchRoot)); try { myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, file.getPath()); myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, file.getPath()); myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, file.getPath()); } finally { unwatch(request); delete(file); } } public void testDirectoryRecursive() throws Exception { File topDir = createTestDir("top"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(topDir); try { myAccept = true; File subDir = createTestDir(topDir, "sub"); assertEvent(VFileCreateEvent.class, subDir.getPath()); refresh(subDir); myAccept = true; File file = createTestFile(subDir, "test.txt"); assertEvent(VFileCreateEvent.class, file.getPath()); myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, file.getPath()); myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, file.getPath()); myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, file.getPath()); } finally { unwatch(request); delete(topDir); } } public void testDirectoryFlat() throws Exception { File topDir = createTestDir("top"); File watchedFile = createTestFile(topDir, "test.txt"); File subDir = createTestDir(topDir, "sub"); File unwatchedFile = createTestFile(subDir, "test.txt"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(topDir, false); try { myAccept = true; FileUtil.writeToFile(watchedFile, "new content"); assertEvent(VFileContentChangeEvent.class, watchedFile.getPath()); myTimeout = 10 * INTER_RESPONSE_DELAY; myAccept = true; FileUtil.writeToFile(unwatchedFile, "new content"); assertEvent(VFileEvent.class); myTimeout = NATIVE_PROCESS_DELAY; } finally { unwatch(request); delete(topDir); } } public void testDirectoryMixed() throws Exception { File topDir = createTestDir("top"); File watchedFile1 = createTestFile(topDir, "test.txt"); File sub1Dir = createTestDir(topDir, "sub1"); File unwatchedFile = createTestFile(sub1Dir, "test.txt"); File sub2Dir = createTestDir(topDir, "sub2"); File sub2subDir = createTestDir(sub2Dir, "sub"); File watchedFile2 = createTestFile(sub2subDir, "test.txt"); refresh(topDir); LocalFileSystem.WatchRequest topRequest = watch(topDir, false); LocalFileSystem.WatchRequest subRequest = watch(sub2Dir); try { myAccept = true; FileUtil.writeToFile(watchedFile1, "new content"); FileUtil.writeToFile(watchedFile2, "new content"); FileUtil.writeToFile(unwatchedFile, "new content"); assertEvent(VFileContentChangeEvent.class, watchedFile1.getPath(), watchedFile2.getPath()); } finally { unwatch(subRequest, topRequest); delete(topDir); } } public void testDirectoryNonExisting() throws Exception { File topDir = createTestDir("top"); File subDir = new File(topDir, "subDir"); File file = new File(subDir, "file.txt"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(subDir); try { myAccept = true; assertTrue(subDir.toString(), subDir.mkdir()); assertEvent(VFileCreateEvent.class, subDir.getPath()); refresh(subDir); myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileCreateEvent.class, file.getPath()); } finally { unwatch(request); delete(topDir); } } public void testIncorrectPath() throws Exception { File topDir = createTestDir("top"); File file = createTestFile(topDir, "file.zip"); File subDir = new File(file, "sub/zip"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(subDir, false); try { myTimeout = 10 * INTER_RESPONSE_DELAY; myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileEvent.class); myTimeout = NATIVE_PROCESS_DELAY; } finally { unwatch(request); delete(topDir); } } public void testDirectoryOverlapping() throws Exception { File topDir = createTestDir("top"); File fileInTopDir = createTestFile(topDir, "file1.txt"); File subDir = createTestDir(topDir, "sub"); File fileInSubDir = createTestFile(subDir, "file2.txt"); File sideDir = createTestDir("side"); File fileInSideDir = createTestFile(sideDir, "file3.txt"); refresh(topDir); refresh(sideDir); LocalFileSystem.WatchRequest requestForSubDir = watch(subDir); LocalFileSystem.WatchRequest requestForSideDir = watch(sideDir); try { myAccept = true; FileUtil.writeToFile(fileInTopDir, "new content"); FileUtil.writeToFile(fileInSubDir, "new content"); FileUtil.writeToFile(fileInSideDir, "new content"); assertEvent(VFileContentChangeEvent.class, fileInSubDir.getPath(), fileInSideDir.getPath()); LocalFileSystem.WatchRequest requestForTopDir = watch(topDir); try { myAccept = true; FileUtil.writeToFile(fileInTopDir, "newer content"); FileUtil.writeToFile(fileInSubDir, "newer content"); FileUtil.writeToFile(fileInSideDir, "newer content"); assertEvent(VFileContentChangeEvent.class, fileInTopDir.getPath(), fileInSubDir.getPath(), fileInSideDir.getPath()); } finally { unwatch(requestForTopDir); } myAccept = true; FileUtil.writeToFile(fileInTopDir, "newest content"); FileUtil.writeToFile(fileInSubDir, "newest content"); FileUtil.writeToFile(fileInSideDir, "newest content"); assertEvent(VFileContentChangeEvent.class, fileInSubDir.getPath(), fileInSideDir.getPath()); myAccept = true; FileUtil.delete(fileInTopDir); FileUtil.delete(fileInSubDir); FileUtil.delete(fileInSideDir); assertEvent(VFileDeleteEvent.class, fileInTopDir.getPath(), fileInSubDir.getPath(), fileInSideDir.getPath()); } finally { unwatch(requestForSubDir, requestForSideDir); delete(topDir); } } /* public void testSymlinkAboveWatchRoot() throws Exception { final File topDir = FileUtil.createTempDirectory("top.", null); final File topLink = IoTestUtil.createTempLink(topDir.getPath(), "link"); final File subDir = FileUtil.createTempDirectory(topDir, "sub.", null); final File file = FileUtil.createTempFile(subDir, "test.", ".txt"); final File fileLink = new File(new File(topLink, subDir.getName()), file.getName()); refresh(topDir); refresh(topLink); final LocalFileSystem.WatchRequest request = watch(topLink); try { myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, fileLink.getPath()); myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, fileLink.getPath()); myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, fileLink.getPath()); } finally { myFileSystem.removeWatchedRoot(request); delete(topLink); delete(topDir); } } public void testSymlinkBelowWatchRoot() throws Exception { final File targetDir = FileUtil.createTempDirectory("top.", null); final File file = FileUtil.createTempFile(targetDir, "test.", ".txt"); final File linkDir = FileUtil.createTempDirectory("link.", null); final File link = new File(linkDir, "link"); IoTestUtil.createTempLink(targetDir.getPath(), link.getPath()); final File fileLink = new File(link, file.getName()); refresh(targetDir); refresh(linkDir); final LocalFileSystem.WatchRequest request = watch(linkDir); try { myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, fileLink.getPath()); myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, fileLink.getPath()); myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, fileLink.getPath()); } finally { myFileSystem.removeWatchedRoot(request); delete(linkDir); delete(targetDir); } } */ public void testSubst() throws Exception { if (!SystemInfo.isWindows) { System.err.println("Ignored: Windows required"); return; } File targetDir = createTestDir("top"); File subDir = createTestDir(targetDir, "sub"); File file = createTestFile(subDir, "test.txt"); File rootFile = createSubst(targetDir.getPath()); VfsRootAccess.allowRootAccess(rootFile.getPath()); VirtualFile vfsRoot = myFileSystem.findFileByIoFile(rootFile); try { assertNotNull(rootFile.getPath(), vfsRoot); File substDir = new File(rootFile, subDir.getName()); File substFile = new File(substDir, file.getName()); refresh(targetDir); refresh(substDir); myAcceptedDirectories.add(substDir.getPath()); LocalFileSystem.WatchRequest request = watch(substDir); try { myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, substFile.getPath()); LocalFileSystem.WatchRequest request2 = watch(targetDir); try { myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, file.getPath(), substFile.getPath()); } finally { unwatch(request2); } myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, substFile.getPath()); } finally { unwatch(request); } } finally { delete(targetDir); deleteSubst(rootFile.getPath()); if (vfsRoot != null) { ((NewVirtualFile)vfsRoot).markDirty(); myFileSystem.refresh(false); } VfsRootAccess.disallowRootAccess(rootFile.getPath()); } } public void testDirectoryRecreation() throws Exception { File rootDir = createTestDir("root"); File topDir = createTestDir(rootDir, "top"); File file1 = createTestFile(topDir, "file1.txt", "abc"); File file2 = createTestFile(topDir, "file2.txt", "123"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(rootDir); try { myAccept = true; assertTrue(FileUtil.delete(topDir)); assertTrue(topDir.mkdir()); TimeoutUtil.sleep(100); assertTrue(file1.createNewFile()); assertTrue(file2.createNewFile()); assertEvent(VFileContentChangeEvent.class, file1.getPath(), file2.getPath()); } finally { unwatch(request); delete(topDir); } } public void testWatchRootRecreation() throws Exception { File rootDir = createTestDir("root"); File file1 = createTestFile(rootDir, "file1.txt", "abc"); File file2 = createTestFile(rootDir, "file2.txt", "123"); refresh(rootDir); LocalFileSystem.WatchRequest request = watch(rootDir); try { myAccept = true; assertTrue(FileUtil.delete(rootDir)); assertTrue(rootDir.mkdir()); if (SystemInfo.isLinux) TimeoutUtil.sleep(1500); // implementation specific assertTrue(file1.createNewFile()); assertTrue(file2.createNewFile()); assertEvent(VFileContentChangeEvent.class, file1.getPath(), file2.getPath()); } finally { unwatch(request); delete(rootDir); } } public void testWatchRootRenameRemove() throws Exception { File topDir = createTestDir("top"); File rootDir = createTestDir(topDir, "root"); File rootDir2 = new File(topDir, "_" + rootDir.getName()); refresh(topDir); LocalFileSystem.WatchRequest request = watch(rootDir); try { myAccept = true; assertTrue(rootDir.renameTo(rootDir2)); assertEvent(VFileEvent.class, rootDir.getPath(), rootDir2.getPath()); myAccept = true; assertTrue(rootDir2.renameTo(rootDir)); assertEvent(VFileEvent.class, rootDir.getPath(), rootDir2.getPath()); myAccept = true; assertTrue(FileUtil.delete(rootDir)); assertEvent(VFileDeleteEvent.class, rootDir.getPath()); myAccept = true; assertTrue(rootDir.mkdirs()); assertEvent(VFileCreateEvent.class, rootDir.getPath()); myAccept = true; assertTrue(FileUtil.delete(topDir)); assertEvent(VFileDeleteEvent.class, topDir.getPath()); // todo[r.sh] current VFS implementation loses watch root once it's removed; this probably should be fixed myAccept = true; assertTrue(rootDir.mkdirs()); assertEvent(VFileCreateEvent.class); } finally { unwatch(request); delete(topDir); } } public void testSwitchingToFsRoot() throws Exception { File topDir = createTestDir("top"); File rootDir = createTestDir(topDir, "root"); File file1 = createTestFile(topDir, "1.txt"); File file2 = createTestFile(rootDir, "2.txt"); refresh(topDir); File fsRoot = new File(SystemInfo.isUnix ? "/" : topDir.getPath().substring(0, topDir.getPath().indexOf(File.separatorChar)) + "\\"); assertTrue("can't guess root of " + topDir, fsRoot.exists()); LocalFileSystem.WatchRequest request = watch(rootDir); try { myAccept = true; FileUtil.writeToFile(file1, "abc"); FileUtil.writeToFile(file2, "abc"); assertEvent(VFileContentChangeEvent.class, file2.getPath()); LocalFileSystem.WatchRequest rootRequest = watch(fsRoot); try { myTimeout = 10 * INTER_RESPONSE_DELAY; myAccept = true; FileUtil.writeToFile(file1, "12345"); FileUtil.writeToFile(file2, "12345"); assertEvent(VFileContentChangeEvent.class, file1.getPath(), file2.getPath()); myTimeout = NATIVE_PROCESS_DELAY; } finally { unwatch(rootRequest); } myAccept = true; FileUtil.writeToFile(file1, ""); FileUtil.writeToFile(file2, ""); assertEvent(VFileContentChangeEvent.class, file2.getPath()); } finally { unwatch(request); } myTimeout = 10 * INTER_RESPONSE_DELAY; myAccept = true; FileUtil.writeToFile(file1, "xyz"); FileUtil.writeToFile(file2, "xyz"); assertEvent(VFileEvent.class); myTimeout = NATIVE_PROCESS_DELAY; } public void testLineBreaksInName() throws Exception { if (!SystemInfo.isUnix) { System.err.println("Ignored: Unix required"); return; } File topDir = createTestDir("topDir"); File testDir = createTestDir(topDir, "weird\ndir\nname"); File testFile = createTestFile(testDir, "weird\nfile\nname"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(topDir); try { myAccept = true; FileUtil.writeToFile(testFile, "abc"); assertEvent(VFileContentChangeEvent.class, testFile.getPath()); } finally { unwatch(request); } } public void testHiddenFiles() throws Exception { if (!SystemInfo.isWindows) { System.err.println("Ignored: Windows required"); return; } File topDir = createTestDir("topDir"); File testDir = createTestDir(topDir, "dir"); File testFile = createTestFile(testDir, "file", "123"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(topDir); try { myAccept = true; setHidden(testFile.getPath(), true); assertEvent(VFilePropertyChangeEvent.class, testFile.getPath()); } finally { unwatch(request); } } public void testFileCaseChange() throws Exception { if (SystemInfo.isFileSystemCaseSensitive) { System.err.println("Ignored: case-insensitive FS required"); return; } File topDir = createTestDir("topDir"); File testFile = createTestFile(topDir, "file.txt", "123"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(topDir); try { myAccept = true; File newFile = new File(testFile.getParent(), StringUtil.capitalize(testFile.getName())); FileUtil.rename(testFile, newFile); assertEvent(VFilePropertyChangeEvent.class, newFile.getPath()); } finally { unwatch(request); } } public void testPartialRefresh() throws Exception { // tests the same scenario with an active file watcher (prevents explicit marking of refreshed paths) File top = createTestDir("top"); LocalFileSystemTest.doTestPartialRefresh(top); } public void testInterruptedRefresh() throws Exception { // tests the same scenario with an active file watcher (prevents explicit marking of refreshed paths) File top = createTestDir("top"); LocalFileSystemTest.doTestInterruptedRefresh(top); } public void testUnicodePaths() throws Exception { if (!SystemInfo.isUnix || SystemInfo.isMac) { System.err.println("Ignored: well-defined FS required"); return; } File topDir = createTestDir("top"); File testDir = createTestDir(topDir, "тест"); File testFile = createTestFile(testDir, "файл.txt"); refresh(topDir); LocalFileSystem.WatchRequest request = watch(topDir); try { myAccept = true; FileUtil.writeToFile(testFile, "abc"); assertEvent(VFileContentChangeEvent.class, testFile.getPath()); } finally { unwatch(request); } } @NotNull private LocalFileSystem.WatchRequest watch(File watchFile) { return watch(watchFile, true); } @NotNull private LocalFileSystem.WatchRequest watch(final File watchFile, final boolean recursive) { final Ref<LocalFileSystem.WatchRequest> request = Ref.create(); getEvents("events to add watch " + watchFile, new Runnable() { @Override public void run() { request.set(myFileSystem.addRootToWatch(watchFile.getPath(), recursive)); } }); assertFalse(request.isNull()); assertFalse(myWatcher.isSettingRoots()); return request.get(); } private void unwatch(final LocalFileSystem.WatchRequest... requests) { getEvents("events to stop watching", new Runnable() { @Override public void run() { myFileSystem.removeWatchedRoots(Arrays.asList(requests)); } }); } private VirtualFile refresh(File file) { VirtualFile vFile = myFileSystem.refreshAndFindFileByIoFile(file); assertNotNull(file.toString(), vFile); VfsUtilCore.visitChildrenRecursively(vFile, new VirtualFileVisitor() { @Override public boolean visitFile(@NotNull VirtualFile file) { file.getChildren(); return true; } }); return vFile; } private void delete(File file) throws IOException { VirtualFile vFile = myFileSystem.findFileByIoFile(file); if (vFile != null) { AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass()); try { vFile.delete(this); } finally { token.finish(); } } if (file.exists()) { FileUtil.delete(file); } } private List<VFileEvent> getEvents(String msg, @Nullable Runnable action) { LOG.debug("** waiting for " + msg); myAccept = true; if (action != null) { action.run(); } long timeout = myTimeout, start = System.currentTimeMillis(); try { synchronized (myWaiter) { //noinspection WaitNotInLoop myWaiter.wait(timeout); } } catch (InterruptedException e) { LOG.warn(e); } LOG.debug("** waited for " + (System.currentTimeMillis() - start) + " of " + timeout); myFileSystem.refresh(false); List<VFileEvent> result; synchronized (myEvents) { result = ContainerUtil.newArrayList(myEvents); myEvents.clear(); } if (!result.isEmpty()) { nextEvent: for (Iterator<VFileEvent> iterator = result.iterator(); iterator.hasNext(); ) { VFileEvent event = iterator.next(); VirtualFile file = event.getFile(); if (file != null) { for (String acceptedDirectory : myAcceptedDirectories) { if (FileUtil.isAncestor(acceptedDirectory, file.getPath(), false)) { continue nextEvent; } } LOG.debug("~~ not accepted: " + event); iterator.remove(); } } } LOG.debug("** events: " + result.size()); return result; } private void assertEvent(Class<? extends VFileEvent> type, String... paths) { List<VFileEvent> events = getEvents(type.getSimpleName(), null); assertEquals(events.toString(), paths.length, events.size()); Set<String> pathSet = ContainerUtil.map2Set(paths, new Function<String, String>() { @Override public String fun(final String path) { return FileUtil.toSystemIndependentName(path); } }); for (VFileEvent event : events) { assertTrue(event.toString(), type.isInstance(event)); VirtualFile eventFile = event.getFile(); assertNotNull(event.toString(), eventFile); assertTrue(eventFile + " not in " + Arrays.toString(paths), pathSet.remove(eventFile.getPath())); } } }