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