fix SingleInspectionProfilePanelTest
[idea/community.git] / platform / testFramework / src / com / intellij / testFramework / LightPlatformTestCase.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.testFramework;
17
18 import com.intellij.ProjectTopics;
19 import com.intellij.codeInsight.completion.CompletionProgressIndicator;
20 import com.intellij.codeInsight.hint.HintManager;
21 import com.intellij.codeInsight.hint.HintManagerImpl;
22 import com.intellij.codeInsight.lookup.LookupManager;
23 import com.intellij.codeInspection.InspectionProfileEntry;
24 import com.intellij.codeInspection.LocalInspectionTool;
25 import com.intellij.ide.highlighter.ProjectFileType;
26 import com.intellij.ide.startup.StartupManagerEx;
27 import com.intellij.ide.startup.impl.StartupManagerImpl;
28 import com.intellij.idea.IdeaLogger;
29 import com.intellij.idea.IdeaTestApplication;
30 import com.intellij.mock.MockApplication;
31 import com.intellij.openapi.Disposable;
32 import com.intellij.openapi.actionSystem.DataProvider;
33 import com.intellij.openapi.application.Application;
34 import com.intellij.openapi.application.ApplicationManager;
35 import com.intellij.openapi.application.ex.ApplicationEx;
36 import com.intellij.openapi.application.impl.ApplicationInfoImpl;
37 import com.intellij.openapi.command.WriteCommandAction;
38 import com.intellij.openapi.command.impl.UndoManagerImpl;
39 import com.intellij.openapi.command.undo.UndoManager;
40 import com.intellij.openapi.editor.Document;
41 import com.intellij.openapi.editor.Editor;
42 import com.intellij.openapi.editor.EditorFactory;
43 import com.intellij.openapi.editor.impl.EditorFactoryImpl;
44 import com.intellij.openapi.editor.impl.EditorImpl;
45 import com.intellij.openapi.fileEditor.FileDocumentManager;
46 import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
47 import com.intellij.openapi.fileTypes.FileType;
48 import com.intellij.openapi.fileTypes.FileTypeManager;
49 import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl;
50 import com.intellij.openapi.module.EmptyModuleType;
51 import com.intellij.openapi.module.Module;
52 import com.intellij.openapi.module.ModuleType;
53 import com.intellij.openapi.project.DumbService;
54 import com.intellij.openapi.project.ModuleAdapter;
55 import com.intellij.openapi.project.Project;
56 import com.intellij.openapi.project.ProjectManager;
57 import com.intellij.openapi.project.ex.ProjectManagerEx;
58 import com.intellij.openapi.project.impl.ProjectImpl;
59 import com.intellij.openapi.project.impl.ProjectManagerImpl;
60 import com.intellij.openapi.projectRoots.Sdk;
61 import com.intellij.openapi.roots.ModuleRootManager;
62 import com.intellij.openapi.roots.OrderRootType;
63 import com.intellij.openapi.startup.StartupManager;
64 import com.intellij.openapi.util.Disposer;
65 import com.intellij.openapi.util.EmptyRunnable;
66 import com.intellij.openapi.util.io.FileUtil;
67 import com.intellij.openapi.vfs.LocalFileSystem;
68 import com.intellij.openapi.vfs.VirtualFile;
69 import com.intellij.openapi.vfs.encoding.EncodingManager;
70 import com.intellij.openapi.vfs.encoding.EncodingManagerImpl;
71 import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
72 import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
73 import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl;
74 import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
75 import com.intellij.psi.PsiDocumentManager;
76 import com.intellij.psi.PsiFile;
77 import com.intellij.psi.PsiFileFactory;
78 import com.intellij.psi.PsiManager;
79 import com.intellij.psi.codeStyle.CodeStyleSchemes;
80 import com.intellij.psi.codeStyle.CodeStyleSettings;
81 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
82 import com.intellij.psi.impl.DocumentCommitThread;
83 import com.intellij.psi.impl.PsiDocumentManagerImpl;
84 import com.intellij.psi.impl.PsiManagerImpl;
85 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl;
86 import com.intellij.psi.templateLanguages.TemplateDataLanguageMappings;
87 import com.intellij.util.*;
88 import com.intellij.util.containers.ContainerUtil;
89 import com.intellij.util.indexing.UnindexedFilesUpdater;
90 import com.intellij.util.lang.CompoundRuntimeException;
91 import com.intellij.util.messages.MessageBusConnection;
92 import com.intellij.util.ui.UIUtil;
93 import junit.framework.TestCase;
94 import org.jetbrains.annotations.NonNls;
95 import org.jetbrains.annotations.NotNull;
96 import org.jetbrains.annotations.Nullable;
97 import org.jetbrains.annotations.TestOnly;
98
99 import javax.swing.*;
100 import java.io.ByteArrayOutputStream;
101 import java.io.File;
102 import java.io.IOException;
103 import java.io.PrintStream;
104 import java.lang.management.GarbageCollectorMXBean;
105 import java.lang.management.ManagementFactory;
106 import java.util.Arrays;
107 import java.util.List;
108 import java.util.function.Consumer;
109
110 /**
111  * @author yole
112  */
113 public abstract class LightPlatformTestCase extends UsefulTestCase implements DataProvider {
114   @NonNls private static final String LIGHT_PROJECT_MARK = "Light project: ";
115
116   private static IdeaTestApplication ourApplication;
117   @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
118   protected static Project ourProject;
119   private static Module ourModule;
120   private static PsiManager ourPsiManager;
121   private static boolean ourAssertionsInTestDetected;
122   private static VirtualFile ourSourceRoot;
123   private static TestCase ourTestCase;
124   public static Thread ourTestThread;
125   private static LightProjectDescriptor ourProjectDescriptor;
126
127   private ThreadTracker myThreadTracker;
128
129   static {
130     PlatformTestUtil.registerProjectCleanup(LightPlatformTestCase::closeAndDeleteProject);
131   }
132
133   /**
134    * @return Project to be used in tests for example for project components retrieval.
135    */
136   public static Project getProject() {
137     return ourProject;
138   }
139
140   /**
141    * @return Module to be used in tests for example for module components retrieval.
142    */
143   public static Module getModule() {
144     return ourModule;
145   }
146
147   /**
148    * Shortcut to PsiManager.getInstance(getProject())
149    */
150   @NotNull
151   public static PsiManager getPsiManager() {
152     if (ourPsiManager == null) {
153       ourPsiManager = PsiManager.getInstance(ourProject);
154     }
155     return ourPsiManager;
156   }
157
158   @NotNull
159   public static IdeaTestApplication initApplication() {
160     ourApplication = IdeaTestApplication.getInstance();
161     return ourApplication;
162   }
163
164   @TestOnly
165   public static void disposeApplication() {
166     if (ourApplication != null) {
167       ApplicationManager.getApplication().runWriteAction(() -> Disposer.dispose(ourApplication));
168
169       ourApplication = null;
170     }
171   }
172
173   public static IdeaTestApplication getApplication() {
174     return ourApplication;
175   }
176
177   @SuppressWarnings("UseOfSystemOutOrSystemErr")
178   public static void reportTestExecutionStatistics() {
179     System.out.println("----- TEST STATISTICS -----");
180     UsefulTestCase.logSetupTeardownCosts();
181     System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.appInstancesCreated' value='%d']",
182                                      MockApplication.INSTANCES_CREATED));
183     System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.projectInstancesCreated' value='%d']",
184                                      ProjectManagerImpl.TEST_PROJECTS_CREATED));
185     long totalGcTime = 0;
186     for (GarbageCollectorMXBean mxBean : ManagementFactory.getGarbageCollectorMXBeans()) {
187       totalGcTime += mxBean.getCollectionTime();
188     }
189     System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.gcTimeMs' value='%d']", totalGcTime));
190     System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.classesLoaded' value='%d']",
191                                      ManagementFactory.getClassLoadingMXBean().getTotalLoadedClassCount()));
192   }
193
194   protected void resetAllFields() {
195     resetClassFields(getClass());
196   }
197
198   private void resetClassFields(@NotNull Class<?> aClass) {
199     try {
200       UsefulTestCase.clearDeclaredFields(this, aClass);
201     }
202     catch (IllegalAccessException e) {
203       throw new RuntimeException(e);
204     }
205
206     if (aClass == LightPlatformTestCase.class) return;
207     resetClassFields(aClass.getSuperclass());
208   }
209
210   private static void cleanPersistedVFSContent() {
211     ((PersistentFSImpl)PersistentFS.getInstance()).cleanPersistedContents();
212   }
213
214   private static void initProject(@NotNull final LightProjectDescriptor descriptor) throws Exception {
215     ourProjectDescriptor = descriptor;
216
217     if (ourProject != null) {
218       closeAndDeleteProject();
219     }
220     ApplicationManager.getApplication().runWriteAction(LightPlatformTestCase::cleanPersistedVFSContent);
221
222     final File projectFile = FileUtil.createTempFile(ProjectImpl.LIGHT_PROJECT_NAME, ProjectFileType.DOT_DEFAULT_EXTENSION);
223     LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectFile);
224
225     ByteArrayOutputStream buffer = new ByteArrayOutputStream();
226     new Throwable(projectFile.getPath()).printStackTrace(new PrintStream(buffer));
227
228     ourProject = PlatformTestCase.createProject(projectFile, LIGHT_PROJECT_MARK + buffer);
229     ourPathToKeep = projectFile.getPath();
230     ourPsiManager = null;
231
232     ourProjectDescriptor.setUpProject(ourProject, new LightProjectDescriptor.SetupHandler() {
233       @Override
234       public void moduleCreated(@NotNull Module module) {
235         //noinspection AssignmentToStaticFieldFromInstanceMethod
236         ourModule = module;
237       }
238
239       @Override
240       public void sourceRootCreated(@NotNull VirtualFile sourceRoot) {
241         //noinspection AssignmentToStaticFieldFromInstanceMethod
242         ourSourceRoot = sourceRoot;
243       }
244     });
245
246     // project creation may make a lot of pointers, do not regard them as leak
247     ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).storePointers();
248   }
249
250   /**
251    * @return The only source root
252    */
253   public static VirtualFile getSourceRoot() {
254     return ourSourceRoot;
255   }
256
257   @Override
258   protected void setUp() throws Exception {
259     EdtTestUtil.runInEdtAndWait((ThrowableRunnable<Throwable>)() -> {
260       super.setUp();
261       initApplication();
262       ApplicationInfoImpl.setInPerformanceTest(isPerformanceTest());
263
264       ourApplication.setDataProvider(this);
265       LightProjectDescriptor descriptor = new SimpleLightProjectDescriptor(getModuleType(), getProjectJDK());
266       doSetup(descriptor, configureLocalInspectionTools(), getTestRootDisposable());
267       InjectedLanguageManagerImpl.pushInjectors(getProject());
268
269       storeSettings();
270
271       myThreadTracker = new ThreadTracker();
272       ModuleRootManager.getInstance(ourModule).orderEntries().getAllLibrariesAndSdkClassesRoots();
273       VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
274       filePointerManager.storePointers();
275     });
276   }
277
278   public static void doSetup(@NotNull LightProjectDescriptor descriptor,
279                              @NotNull LocalInspectionTool[] localInspectionTools,
280                              @NotNull Disposable parentDisposable) throws Exception {
281     assertNull("Previous test " + ourTestCase + " hasn't called tearDown(). Probably overridden without super call.", ourTestCase);
282     IdeaLogger.ourErrorsOccurred = null;
283     ApplicationManager.getApplication().assertIsDispatchThread();
284     boolean reusedProject = true;
285     if (ourProject == null || ourProjectDescriptor == null || !ourProjectDescriptor.equals(descriptor)) {
286       initProject(descriptor);
287       reusedProject = false;
288     }
289
290     ProjectManagerEx projectManagerEx = ProjectManagerEx.getInstanceEx();
291     projectManagerEx.openTestProject(ourProject);
292     if (reusedProject) {
293       DumbService.getInstance(ourProject).queueTask(new UnindexedFilesUpdater(ourProject, false));
294     }
295
296     MessageBusConnection connection = ourProject.getMessageBus().connect(parentDisposable);
297     connection.subscribe(ProjectTopics.MODULES, new ModuleAdapter() {
298       @Override
299       public void moduleAdded(@NotNull Project project, @NotNull Module module) {
300         fail("Adding modules is not permitted in LightIdeaTestCase.");
301       }
302     });
303
304     clearUncommittedDocuments(getProject());
305
306     InspectionsKt.configureInspections(localInspectionTools, getProject(), parentDisposable);
307
308     assertFalse(getPsiManager().isDisposed());
309     Boolean passed = null;
310     try {
311       passed = StartupManagerEx.getInstanceEx(getProject()).startupActivityPassed();
312     }
313     catch (Exception ignored) {
314
315     }
316     assertTrue("open: " + getProject().isOpen() +
317                "; disposed:" + getProject().isDisposed() +
318                "; startup passed:" + passed +
319                "; all open projects: " + Arrays.asList(ProjectManager.getInstance().getOpenProjects()), getProject().isInitialized());
320
321     CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(new CodeStyleSettings());
322
323     final FileDocumentManager manager = FileDocumentManager.getInstance();
324     if (manager instanceof FileDocumentManagerImpl) {
325       Document[] unsavedDocuments = manager.getUnsavedDocuments();
326       manager.saveAllDocuments();
327       ApplicationManager.getApplication().runWriteAction(((FileDocumentManagerImpl)manager)::dropAllUnsavedDocuments);
328
329       assertEmpty("There are unsaved documents", Arrays.asList(unsavedDocuments));
330     }
331     UIUtil.dispatchAllInvocationEvents(); // startup activities
332
333     ((FileTypeManagerImpl)FileTypeManager.getInstance()).drainReDetectQueue();
334   }
335
336   //protected void enableInspectionTools(@NotNull Class<? extends InspectionProfileEntry>[] classes) {
337   //  for (InspectionProfileEntry tool : InspectionTestUtil.instantiateTools(Arrays.asList(classes))) {
338   //    enableInspectionTool(tool);
339   //  }
340   //}
341
342   protected void enableInspectionTools(@NotNull InspectionProfileEntry... tools) {
343     for (InspectionProfileEntry tool : tools) {
344       enableInspectionTool(tool);
345     }
346   }
347
348   //protected void enableInspectionTool(@NotNull InspectionToolWrapper toolWrapper) {
349   //  InspectionsKt.enableInspectionTool(getProject(), toolWrapper, myTestRootDisposable);
350   //}
351
352   protected void enableInspectionTool(@NotNull InspectionProfileEntry tool) {
353     InspectionsKt.enableInspectionTool(getProject(), tool, myTestRootDisposable);
354   }
355
356   @NotNull
357   protected LocalInspectionTool[] configureLocalInspectionTools() {
358     return LocalInspectionTool.EMPTY_ARRAY;
359   }
360
361   @SuppressWarnings("TearDownDoesntCallSuperTearDown")
362   @Override
363   protected void tearDown() throws Exception {
364     Project project = getProject();
365     List<Throwable> errors = new SmartList<>();
366     Consumer<ThrowableRunnable<?>> runSafe = c -> {
367       try {
368         c.run();
369       }
370       catch (Throwable e) {
371         errors.add(e);
372       }
373     };
374     try {
375       runSafe.accept(() -> CodeStyleSettingsManager.getInstance(project).dropTemporarySettings());
376       runSafe.accept(() -> checkForSettingsDamage(errors));
377       runSafe.accept(() -> doTearDown(project, ourApplication, true, errors));
378       runSafe.accept(super::tearDown);
379       runSafe.accept(() -> myThreadTracker.checkLeak());
380       runSafe.accept(() -> InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project));
381       runSafe.accept(() -> ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).assertPointersAreDisposed());
382     }
383     catch (Throwable e) {
384       errors.add(e);
385     }
386     finally {
387       CompoundRuntimeException.throwIfNotEmpty(errors);
388     }
389   }
390
391   public static void doTearDown(@NotNull final Project project, @NotNull IdeaTestApplication application, boolean checkForEditors, @NotNull List<Throwable> exceptions) throws Exception {
392     PsiDocumentManagerImpl documentManager;
393     try {
394       ((FileTypeManagerImpl)FileTypeManager.getInstance()).drainReDetectQueue();
395       DocumentCommitThread.getInstance().clearQueue();
396       CodeStyleSettingsManager.getInstance(project).dropTemporarySettings();
397
398       checkJavaSwingTimersAreDisposed(exceptions);
399
400       UsefulTestCase.doPostponedFormatting(project);
401
402       LookupManager lookupManager = LookupManager.getInstance(project);
403       if (lookupManager != null) {
404         lookupManager.hideActiveLookup();
405       }
406       ((StartupManagerImpl)StartupManager.getInstance(project)).prepareForNextTest();
407       if (ProjectManager.getInstance() == null) {
408         exceptions.add(new AssertionError("Application components damaged"));
409       }
410
411       ContainerUtil.addIfNotNull(exceptions, new WriteCommandAction.Simple(project) {
412         @Override
413         protected void run() throws Throwable {
414           if (ourSourceRoot != null) {
415             try {
416               final VirtualFile[] children = ourSourceRoot.getChildren();
417               for (VirtualFile child : children) {
418                 child.delete(this);
419               }
420             }
421             catch (IOException e) {
422               //noinspection CallToPrintStackTrace
423               e.printStackTrace();
424             }
425           }
426           EncodingManager encodingManager = EncodingManager.getInstance();
427           if (encodingManager instanceof EncodingManagerImpl) ((EncodingManagerImpl)encodingManager).clearDocumentQueue();
428
429           FileDocumentManager manager = FileDocumentManager.getInstance();
430
431           ApplicationManager.getApplication().runWriteAction(EmptyRunnable.getInstance()); // Flush postponed formatting if any.
432           manager.saveAllDocuments();
433           if (manager instanceof FileDocumentManagerImpl) {
434             ((FileDocumentManagerImpl)manager).dropAllUnsavedDocuments();
435           }
436         }
437       }.execute().getThrowable());
438
439       assertFalse(PsiManager.getInstance(project).isDisposed());
440       if (!ourAssertionsInTestDetected) {
441         if (IdeaLogger.ourErrorsOccurred != null) {
442           throw IdeaLogger.ourErrorsOccurred;
443         }
444       }
445       documentManager = clearUncommittedDocuments(project);
446       ((HintManagerImpl)HintManager.getInstance()).cleanup();
447       DocumentCommitThread.getInstance().clearQueue();
448
449       EdtTestUtil.runInEdtAndWait((Runnable)() -> {
450         ((UndoManagerImpl)UndoManager.getGlobalInstance()).dropHistoryInTests();
451         ((UndoManagerImpl)UndoManager.getInstance(project)).dropHistoryInTests();
452
453         UIUtil.dispatchAllInvocationEvents();
454       });
455
456       TemplateDataLanguageMappings.getInstance(project).cleanupForNextTest();
457     }
458     finally {
459       ProjectManagerEx.getInstanceEx().closeTestProject(project);
460       application.setDataProvider(null);
461       ourTestCase = null;
462       ((PsiManagerImpl)PsiManager.getInstance(project)).cleanupForNextTest();
463       CompletionProgressIndicator.cleanupForNextTest();
464     }
465
466     if (checkForEditors) {
467       checkEditorsReleased(exceptions);
468     }
469     documentManager.clearUncommittedDocuments();
470     
471     if (ourTestCount++ % 100 == 0) {
472       // some tests are written in Groovy, and running all of them may result in some 40M of memory wasted on bean infos
473       // so let's clear the cache every now and then to ensure it doesn't grow too large
474       GCUtil.clearBeanInfoCache();
475     }
476   }
477   
478   private static int ourTestCount;
479
480   public static PsiDocumentManagerImpl clearUncommittedDocuments(@NotNull Project project) {
481     PsiDocumentManagerImpl documentManager = (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project);
482     documentManager.clearUncommittedDocuments();
483
484     ProjectManagerImpl projectManager = (ProjectManagerImpl)ProjectManager.getInstance();
485     if (projectManager.isDefaultProjectInitialized()) {
486       Project defaultProject = projectManager.getDefaultProject();
487       ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(defaultProject)).clearUncommittedDocuments();
488     }
489     return documentManager;
490   }
491
492   public static void checkEditorsReleased(@NotNull List<Throwable> exceptions) {
493     Editor[] allEditors = EditorFactory.getInstance().getAllEditors();
494     if (allEditors.length == 0) {
495       return;
496     }
497
498     for (Editor editor : allEditors) {
499       try {
500         EditorFactoryImpl.throwNotReleasedError(editor);
501       }
502       catch (Throwable e) {
503         exceptions.add(e);
504       }
505       finally {
506         EditorFactory.getInstance().releaseEditor(editor);
507       }
508     }
509
510     try {
511       ((EditorImpl)allEditors[0]).throwDisposalError("Unreleased editors: " + allEditors.length);
512     }
513     catch (Throwable e) {
514       exceptions.add(e);
515     }
516   }
517
518   @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
519   @Override
520   public final void runBare() throws Throwable {
521     if (!shouldRunTest()) {
522       return;
523     }
524
525     TestRunnerUtil.replaceIdeEventQueueSafely();
526     EdtTestUtil.runInEdtAndWait((ThrowableRunnable<Throwable>)() -> {
527       try {
528         ourTestThread = Thread.currentThread();
529         startRunAndTear();
530       }
531       finally {
532         ourTestThread = null;
533         try {
534           Application application = ApplicationManager.getApplication();
535           if (application instanceof ApplicationEx) {
536             PlatformTestCase.cleanupApplicationCaches(ourProject);
537           }
538           resetAllFields();
539         }
540         catch (Throwable e) {
541           //noinspection CallToPrintStackTrace
542           e.printStackTrace();
543         }
544       }
545     });
546
547     // just to make sure all deferred Runnables to finish
548     SwingUtilities.invokeAndWait(EmptyRunnable.getInstance());
549
550     if (IdeaLogger.ourErrorsOccurred != null) {
551       throw IdeaLogger.ourErrorsOccurred;
552     }
553   }
554
555   @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
556   private void startRunAndTear() throws Throwable {
557     setUp();
558     try {
559       ourAssertionsInTestDetected = true;
560       runTest();
561       ourAssertionsInTestDetected = false;
562     }
563     finally {
564       //try{
565       tearDown();
566       //}
567       //catch(Throwable th){
568       //  noinspection CallToPrintStackTrace
569       //th.printStackTrace();
570       //}
571     }
572   }
573
574   @Override
575   public Object getData(String dataId) {
576     return ourProject == null || ourProject.isDisposed() ? null : new TestDataProvider(ourProject).getData(dataId);
577   }
578
579   protected Sdk getProjectJDK() {
580     return null;
581   }
582
583   @NotNull
584   protected ModuleType getModuleType() {
585     return EmptyModuleType.getInstance();
586   }
587
588   /**
589    * Creates dummy source file. One is not placed under source root so some PSI functions like resolve to external classes
590    * may not work. Though it works significantly faster and yet can be used if you need to create some PSI structures for
591    * test purposes
592    *
593    * @param fileName - name of the file to create. Extension is used to choose what PSI should be created like java, jsp, aj, xml etc.
594    * @param text     - file text.
595    * @return dummy psi file.
596    *
597    */
598   @NotNull
599   protected static PsiFile createFile(@NonNls @NotNull String fileName, @NonNls @NotNull String text) throws IncorrectOperationException {
600     FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName);
601     return PsiFileFactory.getInstance(getProject())
602       .createFileFromText(fileName, fileType, text, LocalTimeCounter.currentTime(), true, false);
603   }
604
605   @NotNull
606   protected static PsiFile createLightFile(@NonNls @NotNull String fileName, @NotNull String text) throws IncorrectOperationException {
607     FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName);
608     return PsiFileFactory.getInstance(getProject())
609       .createFileFromText(fileName, fileType, text, LocalTimeCounter.currentTime(), false, false);
610   }
611
612   /**
613    * Convenient conversion of testSomeTest -> someTest | SomeTest where testSomeTest is the name of current test.
614    *
615    * @param lowercaseFirstLetter - whether first letter after test should be lowercased.
616    */
617   @NotNull
618   @Override
619   protected String getTestName(boolean lowercaseFirstLetter) {
620     String name = getName();
621     assertTrue("Test name should start with 'test': " + name, name.startsWith("test"));
622     name = name.substring("test".length());
623     if (!name.isEmpty() && lowercaseFirstLetter && !PlatformTestUtil.isAllUppercaseName(name)) {
624       name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
625     }
626     return name;
627   }
628
629   protected static void commitDocument(@NotNull Document document) {
630     PsiDocumentManager.getInstance(getProject()).commitDocument(document);
631   }
632
633   protected static void commitAllDocuments() {
634     PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
635   }
636
637   @NotNull
638   @Override
639   protected CodeStyleSettings getCurrentCodeStyleSettings() {
640     if (CodeStyleSchemes.getInstance().getCurrentScheme() == null) return new CodeStyleSettings();
641     return CodeStyleSettingsManager.getSettings(getProject());
642   }
643
644   protected static Document getDocument(@NotNull PsiFile file) {
645     return PsiDocumentManager.getInstance(getProject()).getDocument(file);
646   }
647
648   @SuppressWarnings("NonPrivateFieldAccessedInSynchronizedContext")
649   public static synchronized void closeAndDeleteProject() {
650     if (ourProject == null) {
651       return;
652     }
653     if (ApplicationManager.getApplication().isWriteAccessAllowed()) {
654       throw new IllegalStateException("Must not call closeAndDeleteProject from under write action");
655     }
656
657     if (!ourProject.isDisposed()) {
658       @SuppressWarnings("ConstantConditions")
659       File ioFile = new File(ourProject.getProjectFilePath());
660       Disposer.dispose(ourProject);
661       if (ioFile.exists()) {
662         File dir = ioFile.getParentFile();
663         if (dir.getName().startsWith(UsefulTestCase.TEMP_DIR_MARKER)) {
664           FileUtil.delete(dir);
665         }
666         else {
667           FileUtil.delete(ioFile);
668         }
669       }
670     }
671
672     ProjectManagerEx.getInstanceEx().closeAndDispose(ourProject);
673
674     // project may be disposed but empty folder may still be there
675     if (ourPathToKeep != null) {
676       File parent = new File(ourPathToKeep).getParentFile();
677       if (parent.getName().startsWith(UsefulTestCase.TEMP_DIR_MARKER)) {
678         // delete only empty folders
679         //noinspection ResultOfMethodCallIgnored
680         parent.delete();
681       }
682     }
683
684     ourProject = null;
685     ourPathToKeep = null;
686   }
687
688   private static class SimpleLightProjectDescriptor extends LightProjectDescriptor {
689     @NotNull private final ModuleType myModuleType;
690     @Nullable private final Sdk mySdk;
691
692     SimpleLightProjectDescriptor(@NotNull ModuleType moduleType, @Nullable Sdk sdk) {
693       myModuleType = moduleType;
694       mySdk = sdk;
695     }
696
697     @NotNull
698     @Override
699     public ModuleType getModuleType() {
700       return myModuleType;
701     }
702
703     @Nullable 
704     @Override
705     public Sdk getSdk() {
706       return mySdk;
707     }
708
709     @Override
710     public boolean equals(Object o) {
711       if (this == o) return true;
712       if (o == null || getClass() != o.getClass()) return false;
713
714       SimpleLightProjectDescriptor that = (SimpleLightProjectDescriptor)o;
715
716       if (!myModuleType.equals(that.myModuleType)) return false;
717       return areJdksEqual(that.getSdk());
718     }
719
720     @Override
721     public int hashCode() {
722       return myModuleType.hashCode();
723     }
724
725     private boolean areJdksEqual(final Sdk newSdk) {
726       if (mySdk == null || newSdk == null) return mySdk == newSdk;
727
728       final String[] myUrls = mySdk.getRootProvider().getUrls(OrderRootType.CLASSES);
729       final String[] newUrls = newSdk.getRootProvider().getUrls(OrderRootType.CLASSES);
730       return ContainerUtil.newHashSet(myUrls).equals(ContainerUtil.newHashSet(newUrls));
731     }
732   }
733 }