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