485701fb2277acabccd2c7a655eb73aaa2441c2e
[idea/community.git] / platform / platform-tests / testSrc / com / intellij / openapi / vfs / local / LocalFileSystemTest.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.vfs.local;
17
18 import com.intellij.ide.GeneralSettings;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.application.WriteAction;
21 import com.intellij.openapi.util.SystemInfo;
22 import com.intellij.openapi.util.ThrowableComputable;
23 import com.intellij.openapi.util.io.FileAttributes;
24 import com.intellij.openapi.util.io.FileSystemUtil;
25 import com.intellij.openapi.util.io.FileUtil;
26 import com.intellij.openapi.util.io.IoTestUtil;
27 import com.intellij.openapi.util.text.StringUtil;
28 import com.intellij.openapi.vfs.*;
29 import com.intellij.openapi.vfs.newvfs.*;
30 import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent;
31 import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent;
32 import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent;
33 import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
34 import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
35 import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
36 import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
37 import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
38 import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl;
39 import com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker;
40 import com.intellij.testFramework.PlatformTestCase;
41 import com.intellij.testFramework.PlatformTestUtil;
42 import com.intellij.util.ArrayUtil;
43 import com.intellij.util.ObjectUtils;
44 import com.intellij.util.messages.MessageBusConnection;
45 import org.jetbrains.annotations.NotNull;
46
47 import java.io.File;
48 import java.io.IOException;
49 import java.util.Arrays;
50 import java.util.Collections;
51 import java.util.List;
52 import java.util.Locale;
53
54 public class LocalFileSystemTest extends PlatformTestCase {
55   private LocalFileSystem myFS;
56
57   @Override
58   protected void setUp() throws Exception {
59     super.setUp();
60
61     MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect(getTestRootDisposable());
62     connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
63       @Override public void before(@NotNull List<? extends VFileEvent> events) { checkFiles(events, true); }
64
65       @Override public void after(@NotNull List<? extends VFileEvent> events) { checkFiles(events, false); }
66
67       private void checkFiles(List<? extends VFileEvent> events, boolean before) {
68         for (VFileEvent event : events) {
69           VirtualFile file = event.getFile();
70           if (file != null) {
71             boolean shouldBeInvalid =
72               event instanceof VFileCreateEvent && before && !((VFileCreateEvent)event).isReCreation() ||
73               event instanceof VFileDeleteEvent && !before;
74             assertEquals(event.toString(), !shouldBeInvalid, file.isValid());
75           }
76         }
77       }
78     });
79
80     myFS = LocalFileSystem.getInstance();
81   }
82
83   @Override
84   protected void tearDown() throws Exception {
85     myFS = null;
86     super.tearDown();
87   }
88
89   public void testBasics() throws IOException {
90     VirtualFile dir = myFS.refreshAndFindFileByIoFile(createTempDirectory(false));
91     assertTrue(dir.isValid());
92     assertEquals(0, dir.getChildren().length);
93
94     VirtualFile child = WriteAction.compute(() -> dir.createChildData(this, "child.txt"));
95     assertTrue(child.isValid());
96     assertTrue(new File(child.getPath()).exists());
97     assertEquals(1, dir.getChildren().length);
98     assertEquals(child, dir.getChildren()[0]);
99
100     WriteAction.run(() -> child.delete(this));
101     assertFalse(child.isValid());
102     assertFalse(new File(child.getPath()).exists());
103     assertEquals(0, dir.getChildren().length);
104   }
105
106   public void testChildrenAccessedButNotCached() throws Exception {
107     File dir = createTempDirectory(false);
108     ManagingFS managingFS = ManagingFS.getInstance();
109
110     VirtualFile vFile = myFS.refreshAndFindFileByPath(dir.getPath().replace(File.separatorChar, '/'));
111     assertNotNull(vFile);
112     assertFalse(managingFS.areChildrenLoaded(vFile));
113     assertFalse(managingFS.wereChildrenAccessed(vFile));
114
115     File child = new File(dir, "child");
116     boolean created = child.createNewFile();
117     assertTrue(created);
118
119     File subdir = new File(dir, "subdir");
120     boolean subdirCreated = subdir.mkdir();
121     assertTrue(subdirCreated);
122
123     File subChild = new File(subdir, "subdir");
124     boolean subChildCreated = subChild.createNewFile();
125     assertTrue(subChildCreated);
126
127     VirtualFile childVFile = myFS.refreshAndFindFileByPath(child.getPath().replace(File.separatorChar, '/'));
128     assertNotNull(childVFile);
129     assertFalse(managingFS.areChildrenLoaded(vFile));
130     assertTrue(managingFS.wereChildrenAccessed(vFile));
131
132     VirtualFile subdirVFile = myFS.refreshAndFindFileByPath(subdir.getPath().replace(File.separatorChar, '/'));
133     assertNotNull(subdirVFile);
134     assertFalse(managingFS.areChildrenLoaded(subdirVFile));
135     assertFalse(managingFS.wereChildrenAccessed(subdirVFile));
136     assertFalse(managingFS.areChildrenLoaded(vFile));
137     assertTrue(managingFS.wereChildrenAccessed(vFile));
138
139     vFile.getChildren();
140     assertTrue(managingFS.areChildrenLoaded(vFile));
141     assertTrue(managingFS.wereChildrenAccessed(vFile));
142     assertFalse(managingFS.areChildrenLoaded(subdirVFile));
143     assertFalse(managingFS.wereChildrenAccessed(subdirVFile));
144
145     VirtualFile subChildVFile = myFS.refreshAndFindFileByPath(subChild.getPath().replace(File.separatorChar, '/'));
146     assertNotNull(subChildVFile);
147     assertTrue(managingFS.areChildrenLoaded(vFile));
148     assertTrue(managingFS.wereChildrenAccessed(vFile));
149     assertFalse(managingFS.areChildrenLoaded(subdirVFile));
150     assertTrue(managingFS.wereChildrenAccessed(subdirVFile));
151   }
152
153   public void testRefreshAndFindFile() throws Exception {
154     File dir = createTempDirectory();
155
156     VirtualFile vFile = myFS.refreshAndFindFileByPath(dir.getPath().replace(File.separatorChar, '/'));
157     assertNotNull(vFile);
158     vFile.getChildren();
159
160     for (int i = 0; i < 100; i++) {
161       File subdir = new File(dir, "a" + i);
162       assertTrue(subdir.mkdir());
163     }
164
165     File subdir = new File(dir, "aaa");
166     assertTrue(subdir.mkdir());
167
168     VirtualFile file = myFS.refreshAndFindFileByPath(subdir.getPath().replace(File.separatorChar, '/'));
169     assertNotNull(file);
170   }
171
172   public void testCopyFile() throws Exception {
173     File fromDir = createTempDirectory();
174     File toDir = createTempDirectory();
175
176     VirtualFile fromVDir = myFS.findFileByPath(fromDir.getPath().replace(File.separatorChar, '/'));
177     VirtualFile toVDir = myFS.findFileByPath(toDir.getPath().replace(File.separatorChar, '/'));
178     assertNotNull(fromVDir);
179     assertNotNull(toVDir);
180     final VirtualFile fileToCopy = createChildData(fromVDir, "temp_file");
181     final byte[] byteContent = {0, 1, 2, 3};
182     setBinaryContent(fileToCopy,byteContent);
183     final String newName = "new_temp_file";
184     final VirtualFile copy = copy(fileToCopy, toVDir, newName);
185     assertEquals(newName, copy.getName());
186     assertTrue(Arrays.equals(byteContent, copy.contentsToByteArray()));
187   }
188
189   public void testCopyDir() throws Exception {
190     File fromDir = createTempDirectory();
191     File toDir = createTempDirectory();
192
193     VirtualFile fromVDir = myFS.findFileByPath(fromDir.getPath().replace(File.separatorChar, '/'));
194     VirtualFile toVDir = myFS.findFileByPath(toDir.getPath().replace(File.separatorChar, '/'));
195     assertNotNull(fromVDir);
196     assertNotNull(toVDir);
197     final VirtualFile dirToCopy = createChildDirectory(fromVDir, "dir");
198     final VirtualFile file = createChildData(dirToCopy, "temp_file");
199     setBinaryContent(file,new byte[]{0, 1, 2, 3});
200     final String newName = "dir";
201     final VirtualFile dirCopy = copy(dirToCopy, toVDir, newName);
202     assertEquals(newName, dirCopy.getName());
203     PlatformTestUtil.assertDirectoriesEqual(toVDir, fromVDir);
204   }
205
206   public void testUnicodeNames() throws Exception {
207     final File dirFile = createTempDirectory();
208     final String name = "a-\u00df-123123123.txt";
209     final File childFile = new File(dirFile, name);
210     boolean created = childFile.createNewFile();
211     assertTrue(created || childFile.exists());
212
213     final VirtualFile dir = myFS.refreshAndFindFileByIoFile(dirFile);
214     assertNotNull(dir);
215
216     final VirtualFile child = myFS.refreshAndFindFileByIoFile(childFile);
217     assertNotNull(Arrays.toString(dir.getChildren()), child);
218
219     assertTrue(childFile.delete());
220   }
221
222   public void testFindRoot() throws IOException {
223     VirtualFile root = myFS.findFileByPath("wrong_path");
224     assertNull(root);
225
226     VirtualFile root2;
227     if (SystemInfo.isWindows) {
228       root = myFS.findFileByPath("\\\\unit-133");
229       assertNotNull(root);
230       root2 = myFS.findFileByPath("//UNIT-133");
231       assertNotNull(root2);
232       assertEquals(String.valueOf(root2), root, root2);
233       RefreshQueue.getInstance().processSingleEvent(new VFileDeleteEvent(this, root, false));
234
235       root = myFS.findFileByIoFile(new File("\\\\unit-133"));
236       assertNotNull(root);
237       RefreshQueue.getInstance().processSingleEvent(new VFileDeleteEvent(this, root, false));
238
239       if (new File("c:").exists()) {
240         root = myFS.findFileByPath("c:");
241         assertNotNull(root);
242         assertEquals("C:/", root.getPath());
243
244         root2 = myFS.findFileByPath("C:\\");
245         assertSame(String.valueOf(root), root, root2);
246
247         VirtualFileManager fm = VirtualFileManager.getInstance();
248         root = fm.findFileByUrl("file://C:/");
249         assertNotNull(root);
250         root2 = fm.findFileByUrl("file:///c:/");
251         assertSame(String.valueOf(root), root, root2);
252       }
253     }
254     else if (SystemInfo.isUnix) {
255       root = myFS.findFileByPath("/");
256       assertNotNull(root);
257       assertEquals("/", root.getPath());
258     }
259
260     root = myFS.findFileByPath("");
261     assertNotNull(root);
262
263     File jarFile = IoTestUtil.createTestJar();
264     assertNotNull(getVirtualFile(jarFile));
265     root = VirtualFileManager.getInstance().findFileByUrl("jar://" + jarFile.getPath() + "!/");
266     assertNotNull(root);
267
268     root2 = VirtualFileManager.getInstance().findFileByUrl("jar://" + jarFile.getPath().replace(File.separator, "//") + "!/");
269     assertEquals(String.valueOf(root2), root, root2);
270
271     if (!SystemInfo.isFileSystemCaseSensitive) {
272       root2 = VirtualFileManager.getInstance().findFileByUrl("jar://" + jarFile.getPath().toUpperCase(Locale.US) + "!/");
273       assertEquals(String.valueOf(root2), root, root2);
274     }
275   }
276
277   public void testFileLength() throws Exception {
278     File file = FileUtil.createTempFile("test", "txt");
279     FileUtil.writeToFile(file, "hello");
280     VirtualFile virtualFile = myFS.refreshAndFindFileByIoFile(file);
281     assertNotNull(virtualFile);
282     String s = VfsUtilCore.loadText(virtualFile);
283     assertEquals("hello", s);
284     assertEquals(5, virtualFile.getLength());
285
286     FileUtil.writeToFile(file, "new content");
287     ((PersistentFSImpl)PersistentFS.getInstance()).cleanPersistedContents();
288     s = VfsUtilCore.loadText(virtualFile);
289     assertEquals("new content", s);
290     assertEquals(11, virtualFile.getLength());
291   }
292
293   public void testHardLinks() throws Exception {
294     if (!SystemInfo.isWindows && !SystemInfo.isUnix) {
295       System.err.println(getName() + " skipped: " + SystemInfo.OS_NAME);
296       return;
297     }
298
299     final boolean safeWrite = GeneralSettings.getInstance().isUseSafeWrite();
300     final File dir = FileUtil.createTempDirectory("hardlinks.", ".dir", false);
301     final SafeWriteRequestor requestor = new SafeWriteRequestor() { };
302     try {
303       GeneralSettings.getInstance().setUseSafeWrite(false);
304
305       final File targetFile = new File(dir, "targetFile");
306       assertTrue(targetFile.createNewFile());
307       final File hardLinkFile = IoTestUtil.createHardLink(targetFile.getAbsolutePath(), "hardLinkFile");
308
309       final VirtualFile file = myFS.refreshAndFindFileByIoFile(targetFile);
310       assertNotNull(file);
311       setBinaryContent(file,"hello".getBytes(CharsetToolkit.UTF8_CHARSET), 0, 0, requestor);
312       assertTrue(file.getLength() > 0);
313
314       final VirtualFile check = myFS.refreshAndFindFileByIoFile(hardLinkFile);
315       assertNotNull(check);
316       assertEquals(file.getLength(), check.getLength());
317       assertEquals("hello", VfsUtilCore.loadText(check));
318     }
319     finally {
320       GeneralSettings.getInstance().setUseSafeWrite(safeWrite);
321       FileUtil.delete(dir);
322     }
323   }
324
325   public void testWindowsHiddenDirectory() throws Exception {
326     if (!SystemInfo.isWindows) {
327       System.err.println(getName() + " skipped: " + SystemInfo.OS_NAME);
328       return;
329     }
330
331     File file = new File("C:\\Documents and Settings\\desktop.ini");
332     if (!file.exists()) {
333       System.err.println(getName() + " skipped: missing " + file);
334       return;
335     }
336
337     String parent = FileUtil.toSystemIndependentName(file.getParent());
338     VfsRootAccess.allowRootAccess(getTestRootDisposable(), parent);
339
340     VirtualFile virtualFile = myFS.refreshAndFindFileByIoFile(file);
341     assertNotNull(virtualFile);
342
343     NewVirtualFileSystem fs = (NewVirtualFileSystem)virtualFile.getFileSystem();
344     FileAttributes attributes = fs.getAttributes(virtualFile);
345     assertNotNull(attributes);
346     assertEquals(FileAttributes.Type.FILE, attributes.type);
347     assertEquals(FileAttributes.HIDDEN, attributes.flags);
348   }
349
350   public void testRefreshSeesLatestDirectoryContents() throws Exception {
351     File testDir = FileUtil.createTempDirectory("RefreshChildrenTest." + getName(), null);
352     String content = "";
353     FileUtil.writeToFile(new File(testDir, "Foo.java"), content);
354
355     VirtualFile virtualDir = getVirtualFile(testDir);
356     assertNotNull(virtualDir);
357     virtualDir.getChildren();
358     virtualDir.refresh(false, true);
359     checkChildCount(virtualDir, 1);
360
361     FileUtil.writeToFile(new File(testDir, "Bar.java"), content);
362     virtualDir.refresh(false, true);
363     checkChildCount(virtualDir, 2);
364   }
365
366   private static void checkChildCount(VirtualFile virtualDir, int expectedCount) {
367     VirtualFile[] children = virtualDir.getChildren();
368     if (children.length != expectedCount) {
369       System.err.println("children:");
370       for (VirtualFile child : children) {
371         System.err.println(child.getPath());
372       }
373     }
374     assertEquals(expectedCount, children.length);
375   }
376
377   public void testSingleFileRootRefresh() throws Exception {
378     File file = FileUtil.createTempFile("test.", ".txt");
379     VirtualFile virtualFile = myFS.refreshAndFindFileByIoFile(file);
380     assertNotNull(virtualFile);
381     assertTrue(virtualFile.exists());
382     assertTrue(virtualFile.isValid());
383
384     virtualFile.refresh(false, false);
385     assertFalse(((VirtualFileSystemEntry)virtualFile).isDirty());
386
387     FileUtil.delete(file);
388     assertFalse(file.exists());
389     virtualFile.refresh(false, false);
390     assertFalse(virtualFile.exists());
391     assertFalse(virtualFile.isValid());
392   }
393
394   public void testBadFileName() throws Exception {
395     if (!SystemInfo.isUnix) {
396       System.err.println(getName() + " skipped: " + SystemInfo.OS_NAME);
397       return;
398     }
399
400     final File dir = FileUtil.createTempDirectory("test.", ".dir");
401     final File file = FileUtil.createTempFile(dir, "test\\", "\\txt", true);
402
403     final VirtualFile vDir = myFS.refreshAndFindFileByIoFile(dir);
404     assertNotNull(vDir);
405     assertEquals(0, vDir.getChildren().length);
406
407     ((VirtualFileSystemEntry)vDir).markDirtyRecursively();
408     vDir.refresh(false, true);
409
410     final VirtualFile vFile = myFS.refreshAndFindFileByIoFile(file);
411     assertNull(vFile);
412   }
413
414   public void testNoMoreFakeRoots() throws Exception {
415     try {
416       PersistentFS.getInstance().findRoot("", myFS);
417       fail("should fail by assertion in PersistentFsImpl.findRoot()");
418     }
419     catch (Throwable t) {
420       String message = t.getMessage();
421       assertTrue(message, message.startsWith("Invalid root"));
422     }
423   }
424
425   public void testCopyToPointDir() throws Exception {
426     File top = createTempDirectory(false);
427     File sub = IoTestUtil.createTestDir(top, "sub");
428     File file = IoTestUtil.createTestFile(top, "file.txt", "hi there");
429
430     VirtualFile topDir = myFS.refreshAndFindFileByIoFile(top);
431     assertNotNull(topDir);
432     VirtualFile sourceFile = myFS.refreshAndFindFileByIoFile(file);
433     assertNotNull(sourceFile);
434     VirtualFile parentDir = myFS.refreshAndFindFileByIoFile(sub);
435     assertNotNull(parentDir);
436     assertEquals(2, topDir.getChildren().length);
437
438     try {
439       sourceFile.copy(this, parentDir, ".");
440       fail("Copying a file into a '.' path should have failed");
441     }
442     catch (IOException e) {
443       System.out.println(e.getMessage());
444     }
445
446     topDir.refresh(false, true);
447     assertTrue(topDir.exists());
448     assertEquals(2, topDir.getChildren().length);
449   }
450
451   public void testCaseInsensitiveRename() throws IOException {
452     File file = createTempFile("file.txt", "");
453     File home = file.getParentFile();
454     assertOrderedEquals(Collections.singletonList("file.txt"), home.list());
455
456     VirtualFile vFile = myFS.refreshAndFindFileByIoFile(file);
457     assertNotNull(vFile);
458     WriteAction.run(() -> vFile.rename(LocalFileSystemTest.class, "FILE.txt"));
459
460     assertEquals("FILE.txt", vFile.getName());
461     assertOrderedEquals(Collections.singletonList("FILE.txt"), home.list());
462   }
463
464   public void testFileCaseChange() throws Exception {
465     if (SystemInfo.isFileSystemCaseSensitive) {
466       System.err.println("Ignored: case-insensitive FS required");
467       return;
468     }
469
470     File top = createTempDirectory(false);
471     File file = IoTestUtil.createTestFile(top, "file.txt", "test");
472
473     VirtualFile topDir = myFS.refreshAndFindFileByIoFile(top);
474     assertNotNull(topDir);
475     VirtualFile sourceFile = myFS.refreshAndFindFileByIoFile(file);
476     assertNotNull(sourceFile);
477
478     String newName = StringUtil.capitalize(file.getName());
479     FileUtil.rename(file, newName);
480     topDir.refresh(false, true);
481     assertFalse(((VirtualDirectoryImpl)topDir).allChildrenLoaded());
482     assertTrue(sourceFile.isValid());
483     assertEquals(newName, sourceFile.getName());
484
485     topDir.getChildren();
486     newName = newName.toLowerCase(Locale.ENGLISH);
487     FileUtil.rename(file, newName);
488     topDir.refresh(false, true);
489     assertTrue(((VirtualDirectoryImpl)topDir).allChildrenLoaded());
490     assertTrue(sourceFile.isValid());
491     assertEquals(newName, sourceFile.getName());
492   }
493
494   public void testPartialRefresh() throws Exception {
495     File top = createTempDirectory(false);
496     doTestPartialRefresh(top);
497   }
498
499   public static void doTestPartialRefresh(@NotNull File top) throws IOException {
500     File sub = IoTestUtil.createTestDir(top, "sub");
501     File file = IoTestUtil.createTestFile(top, "sub.txt");
502     LocalFileSystem lfs = LocalFileSystem.getInstance();
503     NewVirtualFile topDir = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(top);
504     assertNotNull(topDir);
505     NewVirtualFile subDir = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(sub);
506     assertNotNull(subDir);
507     NewVirtualFile subFile = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(file);
508     assertNotNull(subFile);
509     topDir.refresh(false, true);
510     assertFalse(topDir.isDirty());
511     assertFalse(subDir.isDirty());
512     assertFalse(subFile.isDirty());
513
514     subFile.markDirty();
515     subDir.markDirty();
516     assertTrue(topDir.isDirty());
517     assertTrue(subFile.isDirty());
518     assertTrue(subDir.isDirty());
519
520     topDir.refresh(false, false);
521     assertFalse(subFile.isDirty());
522     assertTrue(subDir.isDirty());  // should stay unvisited after non-recursive refresh
523
524     topDir.refresh(false, true);
525     assertFalse(topDir.isDirty());
526     assertFalse(subFile.isDirty());
527     assertFalse(subDir.isDirty());
528   }
529
530   public void testSymlinkTargetBlink() throws Exception {
531     if (!SystemInfo.areSymLinksSupported) {
532       System.err.println("Ignored: symlinks not supported");
533       return;
534     }
535
536     File top = createTempDirectory(true);
537     File target = IoTestUtil.createTestDir(top, "target");
538     File link = IoTestUtil.createSymLink(target.getPath(), top.getPath() + "/link");
539
540     VirtualFile vTop = myFS.refreshAndFindFileByIoFile(top);
541     assertNotNull(vTop);
542     assertTrue(vTop.isValid());
543     VirtualFile vTarget = myFS.refreshAndFindFileByIoFile(target);
544     assertNotNull(vTarget);
545     assertTrue(vTarget.isValid());
546     VirtualFile vLink = myFS.refreshAndFindFileByIoFile(link);
547     assertNotNull(vLink);
548     assertTrue(vLink.isValid());
549     assertTrue(vLink.isDirectory());
550
551     FileUtil.delete(target);
552     vTop.refresh(false, true);
553     assertFalse(vTarget.isValid());
554     assertFalse(vLink.isValid());
555     vLink = myFS.refreshAndFindFileByIoFile(link);
556     assertNotNull(vLink);
557     assertTrue(vLink.isValid());
558     assertFalse(vLink.isDirectory());
559
560     FileUtil.createDirectory(target);
561     vTop.refresh(false, true);
562     assertFalse(vLink.isValid());
563     vLink = myFS.refreshAndFindFileByIoFile(link);
564     assertNotNull(vLink);
565     assertTrue(vLink.isValid());
566     assertTrue(vLink.isDirectory());
567   }
568
569   public void testInterruptedRefresh() throws Exception {
570     File top = createTempDirectory(false);
571     doTestInterruptedRefresh(top);
572   }
573
574   public static void doTestInterruptedRefresh(@NotNull File top) throws Exception {
575     File sub = IoTestUtil.createTestDir(top, "sub");
576     File subSub = IoTestUtil.createTestDir(sub, "sub_sub");
577     File file1 = IoTestUtil.createTestFile(sub, "sub_file_to_stop_at");
578     File file2 = IoTestUtil.createTestFile(subSub, "sub_sub_file");
579     LocalFileSystem lfs = LocalFileSystem.getInstance();
580     NewVirtualFile topDir = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(top);
581     assertNotNull(topDir);
582     NewVirtualFile subFile1 = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(file1);
583     assertNotNull(subFile1);
584     NewVirtualFile subFile2 = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(file2);
585     assertNotNull(subFile2);
586     topDir.refresh(false, true);
587     assertFalse(topDir.isDirty());
588     assertFalse(subFile1.isDirty());
589     assertFalse(subFile2.isDirty());
590
591     try {
592       subFile1.markDirty();
593       subFile2.markDirty();
594       RefreshWorker.setCancellingCondition(file -> "sub_file_to_stop_at".equals(file.getName()));
595       topDir.refresh(false, true);
596       // should remain dirty after aborted refresh
597       assertTrue(subFile1.isDirty());
598       assertTrue(subFile2.isDirty());
599
600       RefreshWorker.setCancellingCondition(null);
601       topDir.refresh(false, true);
602       assertFalse(topDir.isDirty());
603       assertFalse(subFile1.isDirty());
604       assertFalse(subFile2.isDirty());
605     }
606     finally {
607       RefreshWorker.setCancellingCondition(null);
608     }
609   }
610
611   public void testInvalidFileName() throws IOException {
612     WriteAction.run(() -> {
613       VirtualFile tempDir = myFS.refreshAndFindFileByIoFile(createTempDirectory());
614       assertNotNull(tempDir);
615       try {
616         tempDir.createChildData(this, "a/b");
617         fail("invalid file name should have been rejected");
618       }
619       catch (IOException e) {
620         assertEquals(VfsBundle.message("file.invalid.name.error", "a/b"), e.getMessage());
621       }
622     });
623   }
624
625   public void testDuplicateViaRename() throws IOException {
626     WriteAction.run(() -> {
627       VirtualFile tempDir = myFS.refreshAndFindFileByIoFile(createTempDirectory());
628       assertNotNull(tempDir);
629
630       VirtualFile file1 = tempDir.createChildData(this, "a.txt");
631       FileUtil.delete(VfsUtilCore.virtualToIoFile(file1));
632
633       VirtualFile file2 = tempDir.createChildData(this, "b.txt");
634       try {
635         file2.rename(this, "a.txt");
636         fail("duplicate file name should have been rejected");
637       }
638       catch (IOException e) {
639         assertEquals(VfsBundle.message("vfs.target.already.exists.error", file1.getPath()), e.getMessage());
640       }
641     });
642   }
643
644   public void testBrokenSymlinkMove() throws IOException, InterruptedException {
645     if (!SystemInfo.areSymLinksSupported) {
646       System.err.println(getName() + " skipped: " + SystemInfo.OS_NAME);
647       return;
648     }
649
650     File srcDir = IoTestUtil.createTestDir("src");
651     File link = IoTestUtil.createSymLink(srcDir.getPath() + "/missing", srcDir.getPath() + "/link", false);
652     File dstDir = IoTestUtil.createTestDir("dst");
653
654     WriteAction.run(() -> {
655       VirtualFile file = myFS.refreshAndFindFileByIoFile(link);
656       assertNotNull(file);
657
658       VirtualFile target = myFS.refreshAndFindFileByIoFile(dstDir);
659       assertNotNull(target);
660
661       myFS.moveFile(this, file, target);
662     });
663
664     assertOrderedEquals(ArrayUtil.EMPTY_STRING_ARRAY, srcDir.list());
665     assertOrderedEquals(new String[]{link.getName()}, dstDir.list());
666   }
667
668   public void testFileContentChangeEvents() throws IOException {
669     File file = IoTestUtil.createTestFile("file.txt");
670     long stamp = file.lastModified();
671     VirtualFile vFile = myFS.refreshAndFindFileByIoFile(file);
672     assertNotNull(vFile);
673
674     int[] updated = {0};
675     MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect(getTestRootDisposable());
676     connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener.Adapter() {
677       @Override
678       public void after(@NotNull List<? extends VFileEvent> events) {
679         for (VFileEvent event : events) {
680           if (event instanceof VFileContentChangeEvent && vFile.equals(event.getFile())) {
681             updated[0]++;
682             break;
683           }
684         }
685       }
686     });
687
688     FileUtil.writeToFile(file, "content");
689     assertTrue(file.setLastModified(stamp));
690     vFile.refresh(false, false);
691     assertEquals(1, updated[0]);
692
693     FileUtil.writeToFile(file, "more content");
694     assertTrue(file.setLastModified(stamp));
695     vFile.refresh(false, false);
696     assertEquals(2, updated[0]);
697   }
698
699   public void testReadOnly() throws IOException {
700     File file = IoTestUtil.createTestFile("file.txt");
701     VirtualFile vFile = myFS.refreshAndFindFileByIoFile(file);
702     assertNotNull(vFile);
703     assertWritable(file, vFile, true);
704
705     ApplicationManager.getApplication().runWriteAction((ThrowableComputable<Object, IOException>)() -> {
706       vFile.setWritable(false);
707       return null;
708     });
709
710     assertWritable(file, vFile, false);
711     vFile.refresh(false, false);
712     assertWritable(file, vFile, false);
713
714     ApplicationManager.getApplication().runWriteAction((ThrowableComputable<Object, IOException>)() -> {
715       vFile.setWritable(true);
716       return null;
717     });
718     assertWritable(file, vFile, true);
719     vFile.refresh(false, false);
720     assertWritable(file, vFile, true);
721   }
722
723   public void testModCountIncreases() throws IOException {
724     File file = IoTestUtil.createTestFile("file.txt");
725     VirtualFile vFile = myFS.refreshAndFindFileByIoFile(file);
726     assertNotNull(vFile);
727     assertWritable(file, vFile, true);
728     ManagingFS managingFS = ManagingFS.getInstance();
729     final int globalModCount = managingFS.getFilesystemModificationCount();
730     final int parentModCount = managingFS.getModificationCount(vFile.getParent());
731
732     ApplicationManager.getApplication().runWriteAction((ThrowableComputable<Object, IOException>)() -> {
733       vFile.setWritable(false);
734       return null;
735     });
736
737     assertEquals(globalModCount + 1, managingFS.getModificationCount(vFile));
738     assertEquals(globalModCount + 1, managingFS.getFilesystemModificationCount());
739     assertEquals(globalModCount + 1, managingFS.getModificationCount(vFile.getParent()));
740   }
741
742   private static void assertWritable(File file, VirtualFile vFile, boolean expected) {
743     assertEquals(expected, file.canWrite());
744     assertEquals(expected, ObjectUtils.assertNotNull(FileSystemUtil.getAttributes(file)).isWritable());
745     assertEquals(expected, vFile.isWritable());
746   }
747 }