778ae4f759b0a77691ac00790ea19134f98aaf94
[idea/community.git] / java / java-tests / testSrc / com / intellij / openapi / roots / impl / DirectoryIndexTest.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.roots.impl;
17
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.command.WriteCommandAction;
20 import com.intellij.openapi.fileTypes.FileTypeManager;
21 import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx;
22 import com.intellij.openapi.module.ModifiableModuleModel;
23 import com.intellij.openapi.module.Module;
24 import com.intellij.openapi.module.ModuleManager;
25 import com.intellij.openapi.module.StdModuleTypes;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.roots.*;
28 import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
29 import com.intellij.openapi.util.EmptyRunnable;
30 import com.intellij.openapi.util.io.FileUtil;
31 import com.intellij.openapi.vfs.*;
32 import com.intellij.testFramework.*;
33 import gnu.trove.THashSet;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
36 import org.jetbrains.jps.model.java.JavaResourceRootType;
37 import org.jetbrains.jps.model.java.JavaSourceRootType;
38 import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
39
40 import java.io.File;
41 import java.util.*;
42
43 @PlatformTestCase.WrapInCommand
44 public class DirectoryIndexTest extends IdeaTestCase {
45   private DirectoryIndexImpl myIndex;
46
47   private Module myModule2, myModule3;
48   private VirtualFile myRootVFile;
49   private VirtualFile myModule1Dir, myModule2Dir, myModule3Dir;
50   private VirtualFile mySrcDir1, mySrcDir2;
51   private VirtualFile myTestSrc1;
52   private VirtualFile myPack1Dir, myPack2Dir;
53   private VirtualFile myFileLibDir, myFileLibSrc, myFileLibCls;
54   private VirtualFile myLibDir, myLibSrcDir, myLibAdditionalSrcDir, myLibClsDir;
55   private VirtualFile myCvsDir;
56   private VirtualFile myExcludeDir;
57   private VirtualFile myOutputDir;
58   private VirtualFile myModule1OutputDir;
59   private VirtualFile myResDir, myTestResDir;
60   private VirtualFile myExcludedLibSrcDir, myExcludedLibClsDir;
61   private ProjectFileIndex myFileIndex;
62
63   @Override
64   protected void setUp() throws Exception {
65     super.setUp();
66
67     final File root = createTempDirectory();
68
69     ApplicationManager.getApplication().runWriteAction(() -> {
70       /*
71         root
72             lib
73                 file.src
74                 file.cls
75             module1
76                 src1
77                     pack1
78                     testSrc
79                         pack2
80                 res
81                 testRes
82                 lib
83                     src
84                       exc
85                     additional-src
86                     cls
87                       exc
88                 module2
89                     src2
90                         CVS
91                         excluded
92             module3
93             out
94                 module1
95       */
96       myRootVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(root);
97       assertNotNull(myRootVFile);
98
99       myFileLibDir = createChildDirectory(myRootVFile, "lib");
100       myFileLibSrc = createChildData(myFileLibDir, "file.src");
101       myFileLibCls = createChildData(myFileLibDir, "file.cls");
102       myModule1Dir = createChildDirectory(myRootVFile, "module1");
103       mySrcDir1 = createChildDirectory(myModule1Dir, "src1");
104       myPack1Dir = createChildDirectory(mySrcDir1, "pack1");
105       myTestSrc1 = createChildDirectory(mySrcDir1, "testSrc");
106       myPack2Dir = createChildDirectory(myTestSrc1, "pack2");
107       myResDir = createChildDirectory(myModule1Dir, "res");
108       myTestResDir = createChildDirectory(myModule1Dir, "testRes");
109
110       myLibDir = createChildDirectory(myModule1Dir, "lib");
111       myLibSrcDir = createChildDirectory(myLibDir, "src");
112       myExcludedLibSrcDir = createChildDirectory(myLibSrcDir, "exc");
113       myLibAdditionalSrcDir = createChildDirectory(myLibDir, "additional-src");
114       myLibClsDir = createChildDirectory(myLibDir, "cls");
115       myExcludedLibClsDir = createChildDirectory(myLibClsDir, "exc");
116       myModule2Dir = createChildDirectory(myModule1Dir, "module2");
117       mySrcDir2 = createChildDirectory(myModule2Dir, "src2");
118       myCvsDir = createChildDirectory(mySrcDir2, "CVS");
119       myExcludeDir = createChildDirectory(mySrcDir2, "excluded");
120
121       myModule3Dir = createChildDirectory(myRootVFile, "module3");
122
123       myOutputDir = createChildDirectory(myRootVFile, "out");
124       myModule1OutputDir = createChildDirectory(myOutputDir, "module1");
125
126       getCompilerProjectExtension().setCompilerOutputUrl(myOutputDir.getUrl());
127       ModuleManager moduleManager = ModuleManager.getInstance(myProject);
128
129       // fill roots of module1
130       {
131         ModuleRootModificationUtil.setModuleSdk(myModule, null);
132         PsiTestUtil.addContentRoot(myModule, myModule1Dir);
133         PsiTestUtil.addSourceRoot(myModule, mySrcDir1);
134         PsiTestUtil.addSourceRoot(myModule, myTestSrc1, true);
135         PsiTestUtil.addSourceRoot(myModule, myResDir, JavaResourceRootType.RESOURCE);
136         PsiTestUtil.addSourceRoot(myModule, myTestResDir, JavaResourceRootType.TEST_RESOURCE);
137
138         ModuleRootModificationUtil.addModuleLibrary(myModule, "lib.js",
139                                                     Collections.singletonList(myFileLibCls.getUrl()), Collections
140                                                       .singletonList(myFileLibSrc.getUrl()));
141         PsiTestUtil.addExcludedRoot(myModule, myExcludedLibClsDir);
142         PsiTestUtil.addExcludedRoot(myModule, myExcludedLibSrcDir);
143       }
144
145       // fill roots of module2
146       {
147         VirtualFile moduleFile = createChildData(myModule2Dir, "module2.iml");
148         myModule2 = moduleManager.newModule(moduleFile.getPath(), StdModuleTypes.JAVA.getId());
149
150         PsiTestUtil.addContentRoot(myModule2, myModule2Dir);
151         PsiTestUtil.addSourceRoot(myModule2, mySrcDir2);
152         PsiTestUtil.addExcludedRoot(myModule2, myExcludeDir);
153         ModuleRootModificationUtil.addModuleLibrary(myModule2, "lib",
154                                                     Collections.singletonList(myLibClsDir.getUrl()), Collections.singletonList(myLibSrcDir.getUrl()),
155                                                     Arrays.asList(myExcludedLibClsDir.getUrl(), myExcludedLibSrcDir.getUrl()), DependencyScope.COMPILE, true);
156       }
157       PlatformTestUtil.registerExtension(AdditionalLibraryRootsProvider.EP_NAME, new AdditionalLibraryRootsProvider() {
158         @NotNull
159         @Override
160         public Collection<VirtualFile> getAdditionalProjectLibrarySourceRoots(@NotNull Project project) {
161           return Collections.singletonList(myLibAdditionalSrcDir);
162         }
163       }, getTestRootDisposable());
164
165       // fill roots of module3
166       {
167         VirtualFile moduleFile = createChildData(myModule3Dir, "module3.iml");
168         myModule3 = moduleManager.newModule(moduleFile.getPath(), StdModuleTypes.JAVA.getId());
169
170         PsiTestUtil.addContentRoot(myModule3, myModule3Dir);
171         ModuleRootModificationUtil.addDependency(myModule3, myModule2);
172       }
173     });
174
175     myIndex = (DirectoryIndexImpl)DirectoryIndex.getInstance(myProject);
176     myFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
177     // to not interfere with previous test firing vfs events
178     VirtualFileManager.getInstance().syncRefresh();
179   }
180
181   private CompilerProjectExtension getCompilerProjectExtension() {
182     final CompilerProjectExtension instance = CompilerProjectExtension.getInstance(myProject);
183     assertNotNull(instance);
184     return instance;
185   }
186
187   public void testDirInfos() {
188     assertNotInProject(myRootVFile);
189
190     // beware: files in directory index
191     checkInfo(myFileLibSrc, null, false, true, "", null, myModule);
192     checkInfo(myFileLibCls, null, true, false, "", null, myModule);
193
194     checkInfo(myModule1Dir, myModule, false, false, null, null);
195     checkInfo(mySrcDir1, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule);
196     checkInfo(myPack1Dir, myModule, false, false, "pack1", JavaSourceRootType.SOURCE, myModule);
197     checkInfo(myTestSrc1, myModule, false, false, "", JavaSourceRootType.TEST_SOURCE, myModule);
198     checkInfo(myPack2Dir, myModule, false, false, "pack2", JavaSourceRootType.TEST_SOURCE, myModule);
199     checkInfo(myResDir, myModule, false, false, "", JavaResourceRootType.RESOURCE, myModule);
200     checkInfo(myTestResDir, myModule, false, false, "", JavaResourceRootType.TEST_RESOURCE, myModule);
201
202     checkInfo(myLibDir, myModule, false, false, null, null);
203     checkInfo(myLibSrcDir, myModule, false, true, "", null, myModule2, myModule3);
204     checkInfo(myLibClsDir, myModule, true, false, "", null, myModule2, myModule3);
205     
206     assertEquals(myLibSrcDir, assertInProject(myLibSrcDir).getSourceRoot());
207
208     checkInfo(myModule2Dir, myModule2, false, false, null, null);
209     checkInfo(mySrcDir2, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
210     assertNotInProject(myCvsDir);
211     assertExcluded(myExcludeDir, myModule2);
212     assertExcluded(myExcludedLibClsDir, myModule);
213     assertExcluded(myExcludedLibSrcDir, myModule);
214
215     assertEquals(myModule1Dir, assertInProject(myLibClsDir).getContentRoot());
216
217     checkInfo(myModule3Dir, myModule3, false, false, null, null);
218
219     VirtualFile cvs = createChildDirectory(myPack1Dir, "CVS");
220     assertNotInProject(cvs);
221     assertNull(myFileIndex.getPackageNameByDirectory(cvs));
222   }
223
224   public void testDirsByPackageName() {
225     checkPackage("", true, mySrcDir1, myTestSrc1, myResDir, myTestResDir, mySrcDir2, myLibSrcDir, myLibClsDir);
226     checkPackage("", false, mySrcDir1, myTestSrc1, myResDir, myTestResDir, mySrcDir2, myLibClsDir);
227     
228     checkPackage("pack1", true, myPack1Dir);
229     checkPackage("pack1", false, myPack1Dir);
230     
231     checkPackage("pack2", true, myPack2Dir);
232     checkPackage("pack2", false, myPack2Dir);
233     
234     checkPackage(".pack2", false);
235     checkPackage(".pack2", true);
236
237     VirtualFile libClsPack = createChildDirectory(myLibClsDir, "pack1");
238     VirtualFile libSrcPack = createChildDirectory(myLibSrcDir, "pack1");
239     fireRootsChanged();
240     checkPackage("pack1", true, myPack1Dir, libSrcPack, libClsPack);
241     checkPackage("pack1", false, myPack1Dir, libClsPack);
242   }
243
244   public void testDirectoriesWithPackagePrefix() {
245     PsiTestUtil.addSourceRoot(myModule3, myModule3Dir);
246     WriteCommandAction.runWriteCommandAction(myProject, () -> {
247       final ModifiableRootModel model = ModuleRootManager.getInstance(myModule3).getModifiableModel();
248       model.getContentEntries()[0].getSourceFolders()[0].setPackagePrefix("pack1");
249       model.commit();
250     });
251     checkPackage("pack1", true, myPack1Dir, myModule3Dir);
252   }
253
254   public void testPackageDirectoriesWithDots() {
255     VirtualFile fooBar = createChildDirectory(mySrcDir1, "foo.bar");
256     VirtualFile goo1 = createChildDirectory(fooBar, "goo");
257     VirtualFile foo = createChildDirectory(mySrcDir2, "foo");
258     VirtualFile bar = createChildDirectory(foo, "bar");
259     VirtualFile goo2 = createChildDirectory(bar, "goo");
260
261     checkPackage("foo", false, foo);
262     checkPackage("foo.bar", false, bar, fooBar);
263     checkPackage("foo.bar.goo", false, goo2, goo1);
264   }
265
266   public void testCreateDir() {
267     String path = mySrcDir1.getPath().replace('/', File.separatorChar);
268     assertTrue(new File(path + File.separatorChar + "dir1" + File.separatorChar + "dir2").mkdirs());
269     assertTrue(new File(path + File.separatorChar + "CVS").mkdirs());
270     VirtualFileManager.getInstance().syncRefresh();
271   }
272
273   public void testDeleteDir() {
274     VirtualFile subdir1 = createChildDirectory(mySrcDir1, "subdir1");
275     VirtualFile subdir2 = createChildDirectory(subdir1, "subdir2");
276     createChildDirectory(subdir2, "subdir3");
277
278     VfsTestUtil.deleteFile(subdir1);
279   }
280
281   public void testMoveDir() {
282     VirtualFile subdir = createChildDirectory(mySrcDir2, "subdir1");
283     createChildDirectory(subdir, "subdir2");
284
285     move(subdir, mySrcDir1);
286   }
287
288   public void testRenameDir() {
289     VirtualFile subdir = createChildDirectory(mySrcDir2, "subdir1");
290     createChildDirectory(subdir, "subdir2");
291
292     rename(subdir, "abc.d");
293   }
294
295   public void testRenameRoot() {
296     rename(myModule1Dir, "newName");
297   }
298
299   public void testMoveRoot() {
300     move(myModule1Dir, myModule3Dir);
301   }
302
303   public void testAddProjectDir() {
304     new WriteCommandAction.Simple(getProject()) {
305       @Override
306       protected void run() throws Throwable {
307         VirtualFile newDir = createChildDirectory(myModule1Dir.getParent(), "newDir");
308         createChildDirectory(newDir, "subdir");
309
310         PsiTestUtil.addContentRoot(myModule, newDir);
311       }
312     }.execute().throwException();
313   }
314
315   public void testChangeIgnoreList() {
316     VirtualFile newDir = createChildDirectory(myModule1Dir, "newDir");
317
318     assertInProject(newDir);
319
320     final FileTypeManagerEx fileTypeManager = (FileTypeManagerEx)FileTypeManager.getInstance();
321     final String list = fileTypeManager.getIgnoredFilesList();
322     final String list1 = list + ";" + "newDir";
323     try {
324       ApplicationManager.getApplication().runWriteAction(() -> fileTypeManager.setIgnoredFilesList(list1));
325       assertNotInProject(newDir);
326     }
327     finally {
328       ApplicationManager.getApplication().runWriteAction(() -> fileTypeManager.setIgnoredFilesList(list));
329       assertInProject(newDir);
330     }
331   }
332
333   public void testIgnoredFile() {
334     VirtualFile ignoredFile = createChildData(myModule1Dir, "CVS");
335     DirectoryInfo info = myIndex.getInfoForFile(ignoredFile);
336     assertTrue(info.isIgnored());
337     assertTrue(myFileIndex.isExcluded(ignoredFile));
338     assertTrue(myFileIndex.isUnderIgnored(ignoredFile));
339     assertNull(myFileIndex.getContentRootForFile(ignoredFile, false));
340     assertNull(myFileIndex.getModuleForFile(ignoredFile, false));
341   }
342
343   public void testAddModule() {
344     new WriteCommandAction.Simple(getProject()) {
345       @Override
346       protected void run() throws Throwable {
347         VirtualFile newModuleContent = createChildDirectory(myRootVFile, "newModule");
348         createChildDirectory(newModuleContent, "subDir");
349         ModuleManager moduleManager = ModuleManager.getInstance(myProject);
350         Module module = moduleManager.newModule(myRootVFile.getPath() + "/newModule.iml", StdModuleTypes.JAVA.getId());
351         PsiTestUtil.addContentRoot(module, newModuleContent);
352       }
353     }.execute().throwException();
354   }
355
356   public void testModuleUnderIgnoredDir() {
357     final VirtualFile ignored = createChildDirectory(myRootVFile, "RCS");
358     assertTrue(FileTypeManager.getInstance().isFileIgnored(ignored));
359     assertTrue(myFileIndex.isExcluded(ignored));
360     assertTrue(myFileIndex.isUnderIgnored(ignored));
361     final VirtualFile module4 = createChildDirectory(ignored, "module4");
362     assertFalse(FileTypeManager.getInstance().isFileIgnored(module4));
363     assertTrue(myFileIndex.isExcluded(module4));
364     assertTrue(myFileIndex.isUnderIgnored(module4));
365
366     new WriteCommandAction.Simple(getProject()) {
367       @Override
368       protected void run() throws Throwable {
369         ModuleManager moduleManager = ModuleManager.getInstance(myProject);
370         Module module = moduleManager.newModule(myRootVFile.getPath() + "/newModule.iml", StdModuleTypes.JAVA.getId());
371         PsiTestUtil.addContentRoot(module, module4);
372         assertNotInProject(ignored);
373         checkInfo(module4, module, false, false, null, null);
374       }
375     }.execute().throwException();
376   }
377
378   public void testModuleInIgnoredDir() {
379     final VirtualFile ignored = createChildDirectory(myRootVFile, "RCS");
380     assertTrue(FileTypeManager.getInstance().isFileIgnored(ignored));
381     
382     new WriteCommandAction.Simple(getProject()) {
383       @Override
384       protected void run() throws Throwable {
385         ModuleManager moduleManager = ModuleManager.getInstance(myProject);
386         ModifiableModuleModel model = moduleManager.getModifiableModel();
387         model.disposeModule(myModule);
388         model.disposeModule(myModule2);
389         model.disposeModule(myModule3);
390         model.commit();
391         Module module = moduleManager.newModule(myRootVFile.getPath() + "/newModule.iml", StdModuleTypes.JAVA.getId());
392         PsiTestUtil.addContentRoot(module, ignored);
393         checkInfo(ignored, module, false, false, null, null);
394       }
395     }.execute().throwException();
396   }
397
398   public void testExcludedDirsInLibraries() {
399     assertFalse(myFileIndex.isInLibraryClasses(myExcludedLibClsDir));
400     assertTrue(myFileIndex.isExcluded(myExcludedLibClsDir));
401     assertFalse(myFileIndex.isUnderIgnored(myExcludedLibClsDir));
402     assertFalse(myFileIndex.isInLibrarySource(myExcludedLibSrcDir));
403     assertTrue(myFileIndex.isExcluded(myExcludedLibSrcDir));
404     assertFalse(myFileIndex.isUnderIgnored(myExcludedLibSrcDir));
405   }
406
407   public void testExplicitExcludeOfInner() {
408     PsiTestUtil.addExcludedRoot(myModule, myModule2Dir);
409
410     checkInfo(myModule2Dir, myModule2, false, false, null, null);
411     checkInfo(mySrcDir2, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
412   }
413
414   public void testResettingProjectOutputPath() {
415     VirtualFile output1 = createChildDirectory(myModule1Dir, "output1");
416     VirtualFile output2 = createChildDirectory(myModule1Dir, "output2");
417
418     assertInProject(output1);
419     assertInProject(output2);
420
421     getCompilerProjectExtension().setCompilerOutputUrl(output1.getUrl());
422     fireRootsChanged();
423
424     assertExcluded(output1, myModule);
425     assertInProject(output2);
426
427     getCompilerProjectExtension().setCompilerOutputUrl(output2.getUrl());
428     fireRootsChanged();
429
430     assertInProject(output1);
431     assertExcluded(output2, myModule);
432   }
433
434   private void fireRootsChanged() {
435     ApplicationManager.getApplication().runWriteAction(() -> ProjectRootManagerEx.getInstanceEx(getProject()).makeRootsChange(EmptyRunnable.getInstance(), false, true));
436   }
437
438   private static OrderEntry[] toArray(Collection<OrderEntry> orderEntries) {
439     return orderEntries.toArray(new OrderEntry[orderEntries.size()]);
440   }
441
442   public void testModuleSourceAsLibrarySource() {
443     ModuleRootModificationUtil.addModuleLibrary(myModule, "someLib", Collections.emptyList(), Collections.singletonList(mySrcDir1.getUrl()));
444     
445     checkInfo(mySrcDir1, myModule, false, true, "", JavaSourceRootType.SOURCE, myModule, myModule);
446     Collection<OrderEntry> entriesResult = myIndex.getOrderEntries(myIndex.getInfoForFile(mySrcDir1));
447     OrderEntry[] entries = toArray(entriesResult);
448
449     assertInstanceOf(entries[0], LibraryOrderEntry.class);
450     assertInstanceOf(entries[1], ModuleSourceOrderEntry.class);
451
452     checkInfo(myTestSrc1, myModule, false, true, "testSrc", JavaSourceRootType.TEST_SOURCE, myModule, myModule);
453     entriesResult = myIndex.getOrderEntries(myIndex.getInfoForFile(myTestSrc1));
454     entries = toArray(entriesResult);
455     assertInstanceOf(entries[0], LibraryOrderEntry.class);
456     assertInstanceOf(entries[1], ModuleSourceOrderEntry.class);
457   }
458
459   public void testModuleSourceAsLibraryClasses() {
460     ModuleRootModificationUtil.addModuleLibrary(myModule, "someLib", Collections.singletonList(mySrcDir1.getUrl()), Collections.emptyList());
461     checkInfo(mySrcDir1, myModule, true, false, "", JavaSourceRootType.SOURCE, myModule);
462     assertInstanceOf(assertOneElement(toArray(myIndex.getOrderEntries(assertInProject(mySrcDir1)))), ModuleSourceOrderEntry.class);
463   }
464
465   public void testModulesWithSameSourceContentRoot() {
466     // now our API allows this (ReformatCodeActionTest), although UI doesn't. Maybe API shouldn't allow it as well?
467     PsiTestUtil.addContentRoot(myModule2, myModule1Dir);
468     PsiTestUtil.addSourceRoot(myModule2, mySrcDir1);
469
470     checkInfo(myModule1Dir, myModule, false, false, null, null);
471     checkInfo(mySrcDir1, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule3, myModule);
472     checkInfo(myTestSrc1, myModule, false, false, "", JavaSourceRootType.TEST_SOURCE, myModule3, myModule);
473     checkInfo(myResDir, myModule, false, false, "", JavaResourceRootType.RESOURCE, myModule);
474
475     checkInfo(mySrcDir2, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
476     assertEquals(myModule2Dir, myIndex.getInfoForFile(mySrcDir2).getContentRoot());
477   }
478
479   public void testModuleWithSameSourceRoot() {
480     PsiTestUtil.addSourceRoot(myModule2, mySrcDir1);
481     checkInfo(mySrcDir1, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
482     checkInfo(myTestSrc1, myModule2, false, false, "testSrc", JavaSourceRootType.SOURCE, myModule2, myModule3);
483   }
484
485   public void testModuleContentUnderSourceRoot() {
486     PsiTestUtil.addContentRoot(myModule2, myPack1Dir);
487     checkInfo(myPack1Dir, myModule2, false, false, null, null);
488   }
489
490   public void testSameSourceAndOutput() {
491     PsiTestUtil.setCompilerOutputPath(myModule, mySrcDir1.getUrl(), false);
492     assertExcluded(mySrcDir1, myModule);
493   }
494
495   public void testExcludedDirShouldBeExcludedRightAfterItsCreation() {
496     VirtualFile excluded = createChildDirectory(myModule1Dir, "excluded");
497     VirtualFile projectOutput = createChildDirectory(myModule1Dir, "projectOutput");
498     VirtualFile module2Output = createChildDirectory(myModule1Dir, "module2Output");
499     VirtualFile module2TestOutput = createChildDirectory(myModule2Dir, "module2TestOutput");
500
501     assertInProject(excluded);
502     assertInProject(projectOutput);
503     assertInProject(module2Output);
504     assertInProject(module2TestOutput);
505
506     getCompilerProjectExtension().setCompilerOutputUrl(projectOutput.getUrl());
507
508     PsiTestUtil.addExcludedRoot(myModule, excluded);
509     PsiTestUtil.setCompilerOutputPath(myModule2, module2Output.getUrl(), false);
510     PsiTestUtil.setCompilerOutputPath(myModule2, module2TestOutput.getUrl(), true);
511     PsiTestUtil.setExcludeCompileOutput(myModule2, true);
512
513     assertExcluded(excluded, myModule);
514     assertExcluded(projectOutput, myModule);
515     assertExcluded(module2Output, myModule);
516     assertExcluded(module2TestOutput, myModule2);
517
518     VfsTestUtil.deleteFile(excluded);
519     VfsTestUtil.deleteFile(projectOutput);
520     VfsTestUtil.deleteFile(module2Output);
521     VfsTestUtil.deleteFile(module2TestOutput);
522
523     final List<VirtualFile> created = new ArrayList<>();
524     VirtualFileListener l = new VirtualFileAdapter() {
525       @Override
526       public void fileCreated(@NotNull VirtualFileEvent e) {
527         VirtualFile file = e.getFile();
528         String fileName = e.getFileName();
529         assertExcluded(file, fileName.contains("module2TestOutput") ? myModule2 : myModule);
530         created.add(file);
531       }
532     };
533     VirtualFileManager.getInstance().addVirtualFileListener(l, getTestRootDisposable());
534
535     excluded = createChildDirectory(myModule1Dir, excluded.getName());
536     assertExcluded(excluded, myModule);
537
538     projectOutput = createChildDirectory(myModule1Dir, projectOutput.getName());
539     assertExcluded(projectOutput, myModule);
540
541     module2Output = createChildDirectory(myModule1Dir, module2Output.getName());
542     assertExcluded(module2Output, myModule);
543
544     module2TestOutput = createChildDirectory(myModule2Dir, module2TestOutput.getName());
545     assertExcluded(module2TestOutput, myModule2);
546
547     assertEquals(created.toString(), 4, created.size());
548   }
549
550   public void testExcludesShouldBeRecognizedRightOnRefresh() {
551     final VirtualFile dir = createChildDirectory(myModule1Dir, "dir");
552     final VirtualFile excluded = createChildDirectory(dir, "excluded");
553     PsiTestUtil.addExcludedRoot(myModule, excluded);
554     VfsTestUtil.deleteFile(dir);
555
556
557     boolean created = new File(myModule1Dir.getPath(), "dir/excluded/foo").mkdirs();
558     assertTrue(created);
559
560     VirtualFileListener l = new VirtualFileAdapter() {
561       @Override
562       public void fileCreated(@NotNull VirtualFileEvent e) {
563         assertEquals("dir", e.getFileName());
564
565         VirtualFile file = e.getFile();
566         assertInProject(file);
567         assertExcluded(file.findFileByRelativePath("excluded"), myModule);
568         assertExcluded(file.findFileByRelativePath("excluded/foo"), myModule);
569       }
570     };
571
572     VirtualFileManager.getInstance().addVirtualFileListener(l, getTestRootDisposable());
573     VirtualFileManager.getInstance().syncRefresh();
574   }
575
576   public void testProcessingNestedContentRootsOfExcludedDirsOnCreation() {
577     String rootPath = myModule1Dir.getPath();
578     final File f = new File(rootPath, "excludedDir/dir/anotherContentRoot");
579     ApplicationManager.getApplication().runWriteAction(() -> {
580       ModifiableRootModel rootModel = ModuleRootManager.getInstance(myModule).getModifiableModel();
581       rootModel.getContentEntries()[0]
582         .addExcludeFolder(VfsUtilCore.pathToUrl(FileUtil.toSystemIndependentName(f.getParentFile().getParent())));
583       rootModel.commit();
584
585       ModuleRootModificationUtil.addContentRoot(myModule2, FileUtil.toSystemIndependentName(f.getPath()));
586
587       assertTrue(f.getPath(), f.exists() || f.mkdirs());
588       LocalFileSystem.getInstance().refresh(false);
589     });
590
591     assertExcluded(LocalFileSystem.getInstance().findFileByIoFile(f.getParentFile().getParentFile()), myModule);
592     assertInProject(LocalFileSystem.getInstance().findFileByIoFile(f));
593   }
594
595   public void testLibraryDirInContent() {
596     ModuleRootModificationUtil.addModuleLibrary(myModule, myModule1Dir.getUrl());
597
598     checkInfo(myModule1Dir, myModule, true, false, "", null, myModule);
599     checkInfo(mySrcDir1, myModule, true, false, "", JavaSourceRootType.SOURCE, myModule);
600
601     checkInfo(myModule2Dir, myModule2, true, false, "module2", null, myModule);
602     checkInfo(mySrcDir2, myModule2, true, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
603     checkInfo(myExcludeDir, null, true, false, "module2.src2.excluded", null, myModule3);
604
605     checkInfo(myLibDir, myModule, true, false, "lib", null, myModule);
606     checkInfo(myLibClsDir, myModule, true, false, "", null, myModule2, myModule3);
607
608     //myModule is included into order entries instead of myModule2 because classes root for libraries dominates on source roots
609     checkInfo(myLibSrcDir, myModule, true, true, "", null, myModule, myModule3);
610     checkInfo(myLibAdditionalSrcDir, myModule, true, true, null, null, myModule);
611
612     checkInfo(myResDir, myModule, true, false, "", JavaResourceRootType.RESOURCE, myModule);
613     assertInstanceOf(assertOneElement(toArray(myIndex.getOrderEntries(assertInProject(myResDir)))), ModuleSourceOrderEntry.class);
614
615     checkInfo(myExcludedLibSrcDir, null, true, false, "lib.src.exc", null, myModule3, myModule);
616     checkInfo(myExcludedLibClsDir, null, true, false, "lib.cls.exc", null, myModule3);
617
618     checkPackage("lib.src.exc", true, myExcludedLibSrcDir);
619     checkPackage("lib.cls.exc", true, myExcludedLibClsDir);
620     
621     checkPackage("lib.src", true);
622     checkPackage("lib.cls", true);
623     
624     checkPackage("exc", false);
625     checkPackage("exc", true);
626   }
627
628   public void testExcludeCompilerOutputOutsideOfContentRoot() {
629     assertTrue(myFileIndex.isExcluded(myOutputDir));
630     assertFalse(myFileIndex.isUnderIgnored(myOutputDir));
631     assertTrue(myFileIndex.isExcluded(myModule1OutputDir));
632     assertFalse(myFileIndex.isExcluded(myOutputDir.getParent()));
633     assertExcludedFromProject(myOutputDir);
634     assertExcludedFromProject(myModule1OutputDir);
635     String moduleOutputUrl = myModule1OutputDir.getUrl();
636
637     VfsTestUtil.deleteFile(myOutputDir);
638
639     PsiTestUtil.setCompilerOutputPath(myModule, moduleOutputUrl, false);
640     myOutputDir = createChildDirectory(myRootVFile, "out");
641     myModule1OutputDir = createChildDirectory(myOutputDir, "module1");
642
643     assertExcludedFromProject(myOutputDir);
644     assertExcludedFromProject(myModule1OutputDir);
645     assertTrue(myFileIndex.isExcluded(myModule1OutputDir));
646
647     PsiTestUtil.setCompilerOutputPath(myModule, moduleOutputUrl, true);
648     PsiTestUtil.setCompilerOutputPath(myModule2, moduleOutputUrl, false);
649     PsiTestUtil.setCompilerOutputPath(myModule2, moduleOutputUrl, true);
650     PsiTestUtil.setCompilerOutputPath(myModule3, moduleOutputUrl, false);
651     PsiTestUtil.setCompilerOutputPath(myModule3, moduleOutputUrl, true);
652     
653     // now no module inherits project output dir, but it still should be project-excluded
654     assertExcludedFromProject(myOutputDir);
655
656     // project output inside module content shouldn't be projectExcludeRoot
657     VirtualFile projectOutputUnderContent = createChildDirectory(myModule1Dir, "projectOutputUnderContent");
658     getCompilerProjectExtension().setCompilerOutputUrl(projectOutputUnderContent.getUrl());
659     fireRootsChanged();
660
661     assertNotExcluded(myOutputDir);
662     assertExcluded(projectOutputUnderContent, myModule);
663
664     VfsTestUtil.deleteFile(projectOutputUnderContent);
665     projectOutputUnderContent = createChildDirectory(myModule1Dir, "projectOutputUnderContent");
666     assertNotExcluded(myOutputDir);
667     assertExcluded(projectOutputUnderContent, myModule);
668   }
669
670   public void testFileContentAndSourceRoots() {
671     VirtualFile fileRoot = createChildData(myRootVFile, "fileRoot.txt");
672     VirtualFile fileSourceRoot = createChildData(myRootVFile, "fileSourceRoot.txt");
673     VirtualFile fileTestSourceRoot = createChildData(myRootVFile, "fileTestSourceRoot.txt");
674
675     assertNotInProject(fileRoot);
676     assertFalse(myFileIndex.isInContent(fileRoot));
677     assertIteratedContent(myFileIndex, null, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot));
678
679     ContentEntry contentEntry = PsiTestUtil.addContentRoot(myModule, fileRoot);
680     assertNotNull(contentEntry);
681     assertEquals(fileRoot, contentEntry.getFile());
682     checkInfo(fileRoot, myModule, false, false, "", null);
683     assertTrue(myFileIndex.isInContent(fileRoot));
684     assertFalse(myFileIndex.isInSource(fileRoot));
685  
686     PsiTestUtil.addContentRoot(myModule, fileSourceRoot);
687     PsiTestUtil.addSourceRoot(myModule, fileSourceRoot);
688     checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule);
689     assertTrue(myFileIndex.isInContent(fileSourceRoot));
690     assertTrue(myFileIndex.isInSource(fileSourceRoot));
691  
692     PsiTestUtil.addContentRoot(myModule, fileTestSourceRoot);
693     PsiTestUtil.addSourceRoot(myModule, fileTestSourceRoot, true);
694     checkInfo(fileTestSourceRoot, myModule, false, false, "", JavaSourceRootType.TEST_SOURCE, myModule);
695     assertTrue(myFileIndex.isInContent(fileTestSourceRoot));
696     assertTrue(myFileIndex.isInSource(fileTestSourceRoot));
697
698     assertIteratedContent(myFileIndex, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot), null);
699
700     // removing file source root
701     PsiTestUtil.removeSourceRoot(myModule, fileTestSourceRoot);
702     checkInfo(fileTestSourceRoot, myModule, false, false, "", null);
703     assertTrue(myFileIndex.isInContent(fileTestSourceRoot));
704     assertFalse(myFileIndex.isInSource(fileTestSourceRoot));
705     assertIteratedContent(myFileIndex, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot), null);
706  
707     // removing file content root
708     PsiTestUtil.removeContentEntry(myModule, contentEntry.getFile());
709     assertNotInProject(fileRoot);
710     assertFalse(myFileIndex.isInContent(fileRoot));
711     assertFalse(myFileIndex.isInSource(fileRoot));
712     assertIteratedContent(myFileIndex, Arrays.asList(fileSourceRoot, fileTestSourceRoot), Collections.singletonList(fileRoot));
713   }
714
715   private static void assertIteratedContent(ProjectFileIndex fileIndex,
716                                             @Nullable List<VirtualFile> contains,
717                                             @Nullable List<VirtualFile> doesntContain) {
718     final Set<VirtualFile> collected = new THashSet<>();
719     fileIndex.iterateContent(new ContentIterator() {
720       @Override
721       public boolean processFile(VirtualFile fileOrDir) {
722         collected.add(fileOrDir);
723         return true;
724       }
725     });
726     if (contains != null) assertContainsElements(collected, contains);
727     if (doesntContain != null) assertDoesntContain(collected, doesntContain);
728   }
729
730   public void testFileSourceRootsUnderDirContentRoot() {
731     VirtualFile fileSourceRoot = createChildData(myModule1Dir, "fileSourceRoot.txt");
732     assertTrue(myFileIndex.isInContent(fileSourceRoot));
733     assertFalse(myFileIndex.isInSource(fileSourceRoot));
734
735     PsiTestUtil.addSourceRoot(myModule, fileSourceRoot);
736     assertTrue(myFileIndex.isInContent(fileSourceRoot));
737     assertTrue(myFileIndex.isInSource(fileSourceRoot));
738     checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule);
739
740     // removing file source root
741     PsiTestUtil.removeSourceRoot(myModule, fileSourceRoot);
742     assertTrue(myFileIndex.isInContent(fileSourceRoot));
743     assertFalse(myFileIndex.isInSource(fileSourceRoot));
744   }
745
746   public void testFileModuleExcludeRootUnderDirectoryRoot() {
747     VirtualFile fileExcludeRoot = createChildData(mySrcDir1, "fileExcludeRoot.txt");
748     assertTrue(myFileIndex.isInContent(fileExcludeRoot));
749     assertTrue(myFileIndex.isInSource(fileExcludeRoot));
750     assertIteratedContent(myFileIndex, Collections.singletonList(fileExcludeRoot), null);
751
752     PsiTestUtil.addExcludedRoot(myModule, fileExcludeRoot);
753     assertFalse(myFileIndex.isInContent(fileExcludeRoot));
754     assertFalse(myFileIndex.isInSource(fileExcludeRoot));
755     assertNull(myFileIndex.getContentRootForFile(fileExcludeRoot));
756     assertEquals(myModule1Dir, myFileIndex.getContentRootForFile(fileExcludeRoot, false));
757     assertNull(myFileIndex.getModuleForFile(fileExcludeRoot));
758     assertEquals(myModule, myFileIndex.getModuleForFile(fileExcludeRoot, false));
759     assertExcluded(fileExcludeRoot, myModule);
760     assertIteratedContent(myFileIndex, null, Collections.singletonList(fileExcludeRoot));
761
762     // removing file exclude root
763     PsiTestUtil.removeExcludedRoot(myModule, fileExcludeRoot);
764     assertTrue(myFileIndex.isInContent(fileExcludeRoot));
765     assertTrue(myFileIndex.isInSource(fileExcludeRoot));
766     assertIteratedContent(myFileIndex, Collections.singletonList(fileExcludeRoot), null);
767   }
768
769   public void testFileModuleExcludeRootUnderFileRoot() {
770     VirtualFile fileRoot = createChildData(myRootVFile, "fileRoot.txt");
771     PsiTestUtil.addContentRoot(myModule, fileRoot);
772     checkInfo(fileRoot, myModule, false, false, "", null);
773     assertTrue(myFileIndex.isInContent(fileRoot));
774     assertIteratedContent(myFileIndex, Collections.singletonList(fileRoot), null);
775     
776     PsiTestUtil.addExcludedRoot(myModule, fileRoot);
777     assertFalse(myFileIndex.isInContent(fileRoot));
778     assertExcluded(fileRoot, myModule);
779     assertIteratedContent(myFileIndex, null, Collections.singletonList(fileRoot));
780  
781     // removing file exclude root
782     PsiTestUtil.removeExcludedRoot(myModule, fileRoot);
783     checkInfo(fileRoot, myModule, false, false, "", null);
784     assertTrue(myFileIndex.isInContent(fileRoot));
785     assertIteratedContent(myFileIndex, Collections.singletonList(fileRoot), null);
786   }
787
788   public void testFileLibraryInsideFolderLibrary() {
789     VirtualFile file = createChildData(myLibSrcDir, "empty.txt");
790     ModuleRootModificationUtil.addModuleLibrary(myModule2, "lib2",
791                                                 Collections.emptyList(), Collections.singletonList(file.getUrl()),
792                                                 Collections.emptyList(), DependencyScope.COMPILE, true);
793
794     // same for the dir and for the file
795     checkInfo(file, myModule, false, true, "", null, myModule2, myModule3);
796     checkInfo(myLibSrcDir, myModule, false, true, "", null, myModule2, myModule3);
797   }
798
799   public void testFileContentRootsModifications() {
800     assertNotInProject(myRootVFile);
801     VirtualFile temp = createChildDirectory(myRootVFile, "temp");
802
803     VirtualFile fileSourceRoot = createChildData(myRootVFile, "fileSourceRoot.txt");
804     assertNotInProject(fileSourceRoot);
805
806     PsiTestUtil.addContentRoot(myModule, fileSourceRoot);
807     PsiTestUtil.addSourceRoot(myModule, fileSourceRoot);
808     checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule);
809     assertTrue(myFileIndex.isInContent(fileSourceRoot));
810     assertTrue(myFileIndex.isInSource(fileSourceRoot));
811
812     // delete and recreate
813     VfsTestUtil.deleteFile(fileSourceRoot);
814     assertNotInProject(fileSourceRoot);
815     assertFalse(myFileIndex.isInContent(fileSourceRoot));
816     assertFalse(myFileIndex.isInSource(fileSourceRoot));
817     fileSourceRoot = createChildData(myRootVFile, "fileSourceRoot.txt");
818     checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule);
819     assertTrue(myFileIndex.isInContent(fileSourceRoot));
820     assertTrue(myFileIndex.isInSource(fileSourceRoot));
821
822     // delete and move from another dir 
823     VfsTestUtil.deleteFile(fileSourceRoot);
824     assertNotInProject(fileSourceRoot);
825     assertFalse(myFileIndex.isInContent(fileSourceRoot));
826     assertFalse(myFileIndex.isInSource(fileSourceRoot));
827     fileSourceRoot = createChildData(temp, "fileSourceRoot.txt");
828     assertNotInProject(fileSourceRoot);
829     move(fileSourceRoot, myRootVFile);
830     checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule);
831     assertTrue(myFileIndex.isInContent(fileSourceRoot));
832     assertTrue(myFileIndex.isInSource(fileSourceRoot));
833
834     // delete and copy from another dir 
835     VfsTestUtil.deleteFile(fileSourceRoot);
836     assertNotInProject(fileSourceRoot);
837     assertFalse(myFileIndex.isInContent(fileSourceRoot));
838     assertFalse(myFileIndex.isInSource(fileSourceRoot));
839     fileSourceRoot = createChildData(temp, "fileSourceRoot.txt");
840     assertNotInProject(fileSourceRoot);
841     fileSourceRoot = copy(fileSourceRoot, myRootVFile, "fileSourceRoot.txt");
842     checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule);
843     assertTrue(myFileIndex.isInContent(fileSourceRoot));
844     assertTrue(myFileIndex.isInSource(fileSourceRoot));
845     
846     // delete and rename from another file
847     VfsTestUtil.deleteFile(fileSourceRoot);
848     assertNotInProject(fileSourceRoot);
849     assertFalse(myFileIndex.isInContent(fileSourceRoot));
850     assertFalse(myFileIndex.isInSource(fileSourceRoot));
851     fileSourceRoot = createChildData(myRootVFile, "temp_file.txt");
852     assertNotInProject(fileSourceRoot);
853     rename(fileSourceRoot, "fileSourceRoot.txt");
854     checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule);
855     assertTrue(myFileIndex.isInContent(fileSourceRoot));
856     assertTrue(myFileIndex.isInSource(fileSourceRoot));
857   }
858
859   private void checkInfo(VirtualFile file,
860                          @Nullable Module module,
861                          boolean isInLibrary,
862                          boolean isInLibrarySource,
863                          @Nullable String packageName, 
864                          @Nullable final JpsModuleSourceRootType<?> moduleSourceRootType,
865                          Module... modulesOfOrderEntries) {
866     DirectoryInfo info = assertInProject(file);
867     assertEquals(module, info.getModule());
868     if (moduleSourceRootType != null) {
869       assertTrue("isInModuleSource", info.isInModuleSource());
870       assertEquals(moduleSourceRootType, myIndex.getSourceRootType(info));
871     }
872     else {
873       assertFalse("isInModuleSource", info.isInModuleSource());
874     }
875     assertEquals(isInLibrary, info.hasLibraryClassRoot());
876     assertEquals(isInLibrarySource, info.isInLibrarySource());
877
878     if (file.isDirectory()) {
879       assertEquals(packageName, myFileIndex.getPackageNameByDirectory(file));
880     }
881
882     assertEquals(Arrays.toString(toArray(myIndex.getOrderEntries(info))), modulesOfOrderEntries.length, toArray(myIndex.getOrderEntries(info)).length);
883     for (Module aModule : modulesOfOrderEntries) {
884       OrderEntry found = ModuleFileIndexImpl.findOrderEntryWithOwnerModule(aModule, myIndex.getOrderEntries(info));
885       assertNotNull("not found: " + aModule + " in " + Arrays.toString(toArray(myIndex.getOrderEntries(info))), found);
886     }
887   }
888
889   private void assertNotInProject(VirtualFile file) {
890     DirectoryInfo info = myIndex.getInfoForFile(file);
891     assertFalse(info.toString(), info.isInProject());
892     assertFalse(info.toString(), info.isExcluded());
893   }
894
895   private void assertExcluded(VirtualFile file, Module module) {
896     DirectoryInfo info = myIndex.getInfoForFile(file);
897     assertTrue(info.toString(), info.isExcluded());
898     assertEquals(module, info.getModule());
899   }
900
901   private DirectoryInfo assertInProject(VirtualFile file) {
902     DirectoryInfo info = myIndex.getInfoForFile(file);
903     assertTrue(file.toString(), info.isInProject());
904     myIndex.assertConsistency(info);
905     return info;
906   }
907
908   private void assertNotExcluded(VirtualFile file) {
909     assertFalse(myIndex.getInfoForFile(file).isExcluded());
910   }
911
912   private void assertExcludedFromProject(VirtualFile file) {
913     assertExcluded(file, null);
914   }
915
916   private void checkPackage(String packageName, boolean includeLibrarySources, VirtualFile... expectedDirs) {
917     VirtualFile[] actualDirs = myIndex.getDirectoriesByPackageName(packageName, includeLibrarySources).toArray(VirtualFile.EMPTY_ARRAY);
918     assertNotNull(actualDirs);
919     assertOrderedEquals(actualDirs, expectedDirs);
920
921     for (VirtualFile dir : expectedDirs) {
922       String actualName = myIndex.getPackageName(dir);
923       assertEquals("Invalid package name for dir " + dir + ": " + packageName, packageName, actualName);
924     }
925   }
926 }