Merge remote-tracking branch 'origin/master'
[idea/community.git] / platform / testFramework / src / com / intellij / testFramework / fixtures / impl / CodeInsightTestFixtureImpl.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.fixtures.impl;
17
18 import com.intellij.analysis.AnalysisScope;
19 import com.intellij.codeInsight.TargetElementUtil;
20 import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
21 import com.intellij.codeInsight.completion.CompletionProgressIndicator;
22 import com.intellij.codeInsight.completion.CompletionType;
23 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
24 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
25 import com.intellij.codeInsight.daemon.GutterMark;
26 import com.intellij.codeInsight.daemon.impl.*;
27 import com.intellij.codeInsight.folding.CodeFoldingManager;
28 import com.intellij.codeInsight.highlighting.actions.HighlightUsagesAction;
29 import com.intellij.codeInsight.intention.IntentionAction;
30 import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
31 import com.intellij.codeInsight.lookup.Lookup;
32 import com.intellij.codeInsight.lookup.LookupElement;
33 import com.intellij.codeInsight.lookup.LookupManager;
34 import com.intellij.codeInsight.lookup.impl.LookupImpl;
35 import com.intellij.codeInspection.InspectionManager;
36 import com.intellij.codeInspection.InspectionProfileEntry;
37 import com.intellij.codeInspection.InspectionToolProvider;
38 import com.intellij.codeInspection.LocalInspectionTool;
39 import com.intellij.codeInspection.ex.*;
40 import com.intellij.facet.Facet;
41 import com.intellij.facet.FacetManager;
42 import com.intellij.find.FindManager;
43 import com.intellij.find.findUsages.FindUsagesHandler;
44 import com.intellij.find.findUsages.FindUsagesOptions;
45 import com.intellij.find.impl.FindManagerImpl;
46 import com.intellij.ide.startup.StartupManagerEx;
47 import com.intellij.ide.startup.impl.StartupManagerImpl;
48 import com.intellij.ide.structureView.StructureViewBuilder;
49 import com.intellij.ide.structureView.newStructureView.StructureViewComponent;
50 import com.intellij.injected.editor.DocumentWindow;
51 import com.intellij.injected.editor.EditorWindow;
52 import com.intellij.internal.DumpLookupElementWeights;
53 import com.intellij.lang.LanguageStructureViewBuilder;
54 import com.intellij.lang.annotation.HighlightSeverity;
55 import com.intellij.openapi.Disposable;
56 import com.intellij.openapi.actionSystem.*;
57 import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
58 import com.intellij.openapi.application.AccessToken;
59 import com.intellij.openapi.application.ApplicationManager;
60 import com.intellij.openapi.application.Result;
61 import com.intellij.openapi.application.WriteAction;
62 import com.intellij.openapi.command.CommandProcessor;
63 import com.intellij.openapi.command.WriteCommandAction;
64 import com.intellij.openapi.editor.*;
65 import com.intellij.openapi.editor.actionSystem.DocCommandGroupId;
66 import com.intellij.openapi.editor.actionSystem.EditorActionManager;
67 import com.intellij.openapi.editor.ex.EditorEx;
68 import com.intellij.openapi.editor.ex.util.EditorUtil;
69 import com.intellij.openapi.editor.impl.DocumentImpl;
70 import com.intellij.openapi.editor.impl.DocumentMarkupModel;
71 import com.intellij.openapi.editor.markup.RangeHighlighter;
72 import com.intellij.openapi.extensions.ExtensionPoint;
73 import com.intellij.openapi.extensions.ExtensionPointName;
74 import com.intellij.openapi.extensions.ExtensionsArea;
75 import com.intellij.openapi.fileEditor.*;
76 import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
77 import com.intellij.openapi.fileTypes.FileType;
78 import com.intellij.openapi.fileTypes.FileTypeManager;
79 import com.intellij.openapi.module.Module;
80 import com.intellij.openapi.progress.ProcessCanceledException;
81 import com.intellij.openapi.project.DumbService;
82 import com.intellij.openapi.project.Project;
83 import com.intellij.openapi.util.*;
84 import com.intellij.openapi.util.io.FileUtil;
85 import com.intellij.openapi.util.text.StringUtil;
86 import com.intellij.openapi.vfs.*;
87 import com.intellij.profile.Profile;
88 import com.intellij.profile.codeInspection.InspectionProfileManager;
89 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
90 import com.intellij.psi.*;
91 import com.intellij.psi.impl.DebugUtil;
92 import com.intellij.psi.impl.PsiManagerEx;
93 import com.intellij.psi.impl.PsiManagerImpl;
94 import com.intellij.psi.impl.PsiModificationTrackerImpl;
95 import com.intellij.psi.impl.cache.CacheManager;
96 import com.intellij.psi.impl.cache.impl.todo.TodoIndex;
97 import com.intellij.psi.impl.source.PsiFileImpl;
98 import com.intellij.psi.impl.source.tree.FileElement;
99 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
100 import com.intellij.psi.search.GlobalSearchScope;
101 import com.intellij.psi.search.SearchScope;
102 import com.intellij.psi.search.UsageSearchContext;
103 import com.intellij.psi.stubs.StubUpdatingIndex;
104 import com.intellij.psi.util.PsiTreeUtil;
105 import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor;
106 import com.intellij.refactoring.rename.*;
107 import com.intellij.rt.execution.junit.FileComparisonFailure;
108 import com.intellij.testFramework.*;
109 import com.intellij.testFramework.fixtures.*;
110 import com.intellij.usageView.UsageInfo;
111 import com.intellij.util.*;
112 import com.intellij.util.containers.ContainerUtil;
113 import com.intellij.util.indexing.FileBasedIndex;
114 import com.intellij.util.ui.UIUtil;
115 import junit.framework.ComparisonFailure;
116 import org.jetbrains.annotations.NotNull;
117 import org.jetbrains.annotations.Nullable;
118 import org.jetbrains.annotations.TestOnly;
119 import org.junit.Assert;
120
121 import javax.swing.*;
122 import java.io.File;
123 import java.io.IOException;
124 import java.util.*;
125
126 /**
127  * @author Dmitry Avdeev
128  */
129 @SuppressWarnings({"TestMethodWithIncorrectSignature", "JUnitTestCaseWithNoTests", "JUnitTestClassNamingConvention", "TestOnlyProblems"})
130 public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsightTestFixture {
131   private static final Function<IntentionAction, String> INTENTION_NAME_FUN = new Function<IntentionAction, String>() {
132     @Override
133     public String fun(final IntentionAction intentionAction) {
134       return "\"" + intentionAction.getText() + "\"";
135     }
136   };
137
138   private static final String START_FOLD = "<fold\\stext=\'[^\']*\'(\\sexpand=\'[^\']*\')*>";
139   private static final String END_FOLD = "</fold>";
140
141   private final IdeaProjectTestFixture myProjectFixture;
142   private final TempDirTestFixture myTempDirFixture;
143   private PsiManagerImpl myPsiManager;
144   private VirtualFile myFile;
145   private Editor myEditor;
146   private String myTestDataPath;
147   private boolean myEmptyLookup;
148   private VirtualFileFilter myVirtualFileFilter = new FileTreeAccessFilter();
149   private boolean myAllowDirt;
150   private boolean myCaresAboutInjection = true;
151
152   @SuppressWarnings("JUnitTestCaseWithNonTrivialConstructors")
153   public CodeInsightTestFixtureImpl(@NotNull IdeaProjectTestFixture projectFixture, @NotNull TempDirTestFixture tempDirTestFixture) {
154     myProjectFixture = projectFixture;
155     myTempDirFixture = tempDirTestFixture;
156   }
157
158   @NotNull
159   @TestOnly
160   public static GlobalInspectionContextForTests createGlobalContextForTool(@NotNull AnalysisScope scope,
161                                                                            @NotNull final Project project,
162                                                                            @NotNull InspectionManagerEx inspectionManager,
163                                                                            @NotNull final InspectionToolWrapper... toolWrappers) {
164     final InspectionProfileImpl profile = InspectionProfileImpl.createSimple("test", project, toolWrappers);
165     GlobalInspectionContextForTests context = new GlobalInspectionContextForTests(project, inspectionManager.getContentManager()) {
166       @NotNull
167       @Override
168       protected List<Tools> getUsedTools() {
169         return InspectionProfileImpl.initAndDo(new Computable<List<Tools>>() {
170           @Override
171           public List<Tools> compute() {
172             for (InspectionToolWrapper tool : toolWrappers) {
173               profile.enableTool(tool.getShortName(), project);
174             }
175             return profile.getAllEnabledInspectionTools(project);
176           }
177         });
178       }
179     };
180     context.setCurrentScope(scope);
181
182     return context;
183   }
184
185   private static void addGutterIconRenderer(final GutterMark renderer,
186                                             final int offset,
187                                             @NotNull SortedMap<Integer, List<GutterMark>> result) {
188     if (renderer == null) return;
189
190     List<GutterMark> renderers = result.get(offset);
191     if (renderers == null) {
192       result.put(offset, renderers = new SmartList<GutterMark>());
193     }
194     renderers.add(renderer);
195   }
196
197   public static void configureInspections(@NotNull InspectionProfileEntry[] tools,
198                                           @NotNull final Project project,
199                                           @NotNull final Collection<String> disabledInspections,
200                                           @NotNull Disposable parentDisposable) {
201     InspectionToolWrapper[] wrapped =
202       ContainerUtil.map2Array(tools, InspectionToolWrapper.class, new Function<InspectionProfileEntry, InspectionToolWrapper>() {
203         @Override
204         public InspectionToolWrapper fun(InspectionProfileEntry tool) {
205           return InspectionToolRegistrar.wrapTool(tool);
206         }
207       });
208
209     final InspectionProfileImpl profile = InspectionProfileImpl.createSimple(LightPlatformTestCase.PROFILE, project, wrapped);
210     profile.disableToolByDefault(new ArrayList<String>(disabledInspections), project);
211
212     final InspectionProfileManager inspectionProfileManager = InspectionProfileManager.getInstance();
213     final Profile oldRootProfile = inspectionProfileManager.getRootProfile();
214     inspectionProfileManager.addProfile(profile);
215     Disposer.register(parentDisposable, new Disposable() {
216       @Override
217       public void dispose() {
218         inspectionProfileManager.deleteProfile(profile.getName());
219         inspectionProfileManager.setRootProfile(oldRootProfile.getName());
220         clearAllToolsIn(InspectionProfileImpl.getDefaultProfile(), project);
221       }
222     });
223     inspectionProfileManager.setRootProfile(profile.getName());
224     InspectionProfileImpl.initAndDo(new Computable() {
225       @Override
226       public Object compute() {
227         InspectionProjectProfileManager.getInstance(project).updateProfile(profile);
228         InspectionProjectProfileManager.getInstance(project).setProjectProfile(profile.getName());
229         return null;
230       }
231     });
232   }
233
234   private static void clearAllToolsIn(@NotNull InspectionProfileImpl profile, @NotNull Project project) {
235     List<ScopeToolState> tools = profile.getAllTools(project);
236     for (ScopeToolState state : tools) {
237       InspectionToolWrapper wrapper = state.getTool();
238       if (wrapper.getExtension() != null) {
239         ReflectionUtil.resetField(wrapper, InspectionProfileEntry.class, "myTool"); // make it not initialized
240       }
241     }
242   }
243
244   private static void removeDuplicatedRangesForInjected(@NotNull List<HighlightInfo> infos) {
245     Collections.sort(infos, new Comparator<HighlightInfo>() {
246       @Override
247       public int compare(@NotNull HighlightInfo o1, @NotNull HighlightInfo o2) {
248         final int i = o2.startOffset - o1.startOffset;
249         return i != 0 ? i : o1.getSeverity().myVal - o2.getSeverity().myVal;
250       }
251     });
252     HighlightInfo prevInfo = null;
253     for (Iterator<HighlightInfo> it = infos.iterator(); it.hasNext();) {
254       final HighlightInfo info = it.next();
255       if (prevInfo != null &&
256           info.getSeverity() == HighlightInfoType.SYMBOL_TYPE_SEVERITY &&
257           info.getDescription() == null &&
258           info.startOffset == prevInfo.startOffset &&
259           info.endOffset == prevInfo.endOffset) {
260         it.remove();
261       }
262       prevInfo = info.type == HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT ? info : null;
263     }
264   }
265
266   @NotNull
267   public static List<HighlightInfo> instantiateAndRun(@NotNull PsiFile file,
268                                                       @NotNull Editor editor,
269                                                       @NotNull int[] toIgnore,
270                                                       boolean canChangeDocument) {
271     Project project = file.getProject();
272     ensureIndexesUpToDate(project);
273     DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project);
274     TextEditor textEditor = TextEditorProvider.getInstance().getTextEditor(editor);
275     ProcessCanceledException exception = null;
276     for (int i = 0; i < 1000; i++) {
277       try {
278         List<HighlightInfo> infos = codeAnalyzer.runPasses(file, editor.getDocument(), textEditor, toIgnore, canChangeDocument, null);
279         infos.addAll(DaemonCodeAnalyzerEx.getInstanceEx(project).getFileLevelHighlights(project, file));
280         return infos;
281       }
282       catch (ProcessCanceledException e) {
283         PsiDocumentManager.getInstance(project).commitAllDocuments();
284         UIUtil.dispatchAllInvocationEvents();
285         exception = e;
286       }
287     }
288     // unable to highlight after 100 retries
289     throw exception;
290   }
291
292   public static void ensureIndexesUpToDate(@NotNull Project project) {
293     if (!DumbService.isDumb(project)) {
294       FileBasedIndex.getInstance().ensureUpToDate(StubUpdatingIndex.INDEX_ID, project, null);
295       FileBasedIndex.getInstance().ensureUpToDate(TodoIndex.NAME, project, null);
296     }
297   }
298
299   @NotNull
300   public static List<IntentionAction> getAvailableIntentions(@NotNull final Editor editor, @NotNull final PsiFile file) {
301     return ApplicationManager.getApplication().runReadAction(new Computable<List<IntentionAction>>() {
302       @Override
303       public List<IntentionAction> compute() {
304         return doGetAvailableIntentions(editor, file);
305       }
306     });
307   }
308
309   @NotNull
310   private static List<IntentionAction> doGetAvailableIntentions(@NotNull Editor editor, @NotNull PsiFile file) {
311     ShowIntentionsPass.IntentionsInfo intentions = new ShowIntentionsPass.IntentionsInfo();
312     ShowIntentionsPass.getActionsToShow(editor, file, intentions, -1);
313     List<HighlightInfo.IntentionActionDescriptor> descriptors = new ArrayList<HighlightInfo.IntentionActionDescriptor>();
314     descriptors.addAll(intentions.intentionsToShow);
315     descriptors.addAll(intentions.errorFixesToShow);
316     descriptors.addAll(intentions.inspectionFixesToShow);
317     descriptors.addAll(intentions.guttersToShow);
318
319     final int fileOffset = editor.getCaretModel().getOffset();
320     PsiElement hostElement = file.getViewProvider().findElementAt(fileOffset, file.getLanguage());
321     PsiElement injectedElement = InjectedLanguageUtil.findElementAtNoCommit(file, fileOffset);
322
323     PsiFile injectedFile = injectedElement != null ? injectedElement.getContainingFile() : null;
324     Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
325
326     List<IntentionAction> result = new ArrayList<IntentionAction>();
327
328     List<HighlightInfo> infos = DaemonCodeAnalyzerEx.getInstanceEx(file.getProject()).getFileLevelHighlights(file.getProject(), file);
329     for (HighlightInfo info : infos) {
330       for (Pair<HighlightInfo.IntentionActionDescriptor, TextRange> pair : info.quickFixActionRanges) {
331         HighlightInfo.IntentionActionDescriptor actionInGroup = pair.first;
332         final IntentionAction action = actionInGroup.getAction();
333
334         if (ShowIntentionActionsHandler.availableFor(file, editor, action)
335             ||
336             injectedElement != null && hostElement != injectedElement && ShowIntentionActionsHandler.availableFor(injectedFile, injectedEditor, action)) {
337           descriptors.add(actionInGroup);
338         }
339       }
340     }
341
342     // add all intention options for simplicity
343     for (HighlightInfo.IntentionActionDescriptor descriptor : descriptors) {
344       result.add(descriptor.getAction());
345
346       if (injectedElement != null && injectedElement != hostElement) {
347         List<IntentionAction> options = descriptor.getOptions(injectedElement, injectedEditor);
348         if (options != null) {
349           for (IntentionAction option : options) {
350             if (ShowIntentionActionsHandler.availableFor(injectedFile, injectedEditor, option)) {
351               result.add(option);
352             }
353           }
354         }
355       }
356
357       if (hostElement != null) {
358         List<IntentionAction> options = descriptor.getOptions(hostElement, editor);
359         if (options != null) {
360           for (IntentionAction option : options) {
361             if (ShowIntentionActionsHandler.availableFor(file, editor, option)) {
362               result.add(option);
363             }
364           }
365         }
366       }
367     }
368     return result;
369   }
370
371   @NotNull
372   @Override
373   public String getTempDirPath() {
374     return myTempDirFixture.getTempDirPath();
375   }
376
377   @NotNull
378   @Override
379   public TempDirTestFixture getTempDirFixture() {
380     return myTempDirFixture;
381   }
382
383   @NotNull
384   @Override
385   public VirtualFile copyFileToProject(@NotNull String sourcePath) {
386     return copyFileToProject(sourcePath, sourcePath);
387   }
388
389   @NotNull
390   @Override
391   public VirtualFile copyFileToProject(@NotNull String sourcePath, @NotNull String targetPath) {
392     String testDataPath = getTestDataPath();
393     File sourceFile = FileUtil.findFirstThatExist(testDataPath + '/' + sourcePath, sourcePath);
394     VirtualFile targetFile = myTempDirFixture.getFile(targetPath);
395
396     if (sourceFile == null && targetFile != null && targetPath.equals(sourcePath)) {
397       return targetFile;
398     }
399
400     Assert.assertNotNull("Cannot find source file: " + sourcePath + "; test data path: " + testDataPath, sourceFile);
401     Assert.assertTrue("Not a file: " + sourceFile, sourceFile.isFile());
402
403     if (targetFile == null) {
404       targetFile = myTempDirFixture.createFile(targetPath);
405       VfsTestUtil.assertFilePathEndsWithCaseSensitivePath(targetFile, sourcePath);
406       targetFile.putUserData(VfsTestUtil.TEST_DATA_FILE_PATH, sourceFile.getAbsolutePath());
407     }
408
409     final File _source = sourceFile;
410     final VirtualFile _target = targetFile;
411     new WriteAction() {
412       @Override
413       protected void run(@NotNull Result result) throws IOException {
414         _target.setBinaryContent(FileUtil.loadFileBytes(_source));
415       }
416     }.execute();
417
418     return targetFile;
419   }
420
421   @NotNull
422   @Override
423   public VirtualFile copyDirectoryToProject(@NotNull String sourcePath, @NotNull String targetPath) {
424     final String testDataPath = getTestDataPath();
425
426     final File fromFile = new File(testDataPath + "/" + sourcePath);
427     if (myTempDirFixture instanceof LightTempDirTestFixtureImpl) {
428       return myTempDirFixture.copyAll(fromFile.getPath(), targetPath);
429     }
430     final File targetFile = new File(getTempDirPath() + "/" + targetPath);
431     try {
432       FileUtil.copyDir(fromFile, targetFile);
433     }
434     catch (IOException e) {
435       throw new RuntimeException(e);
436     }
437
438     final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(targetFile);
439     Assert.assertNotNull(file);
440     file.refresh(false, true);
441     return file;
442   }
443
444   @Override
445   public void enableInspections(@NotNull InspectionProfileEntry... inspections) {
446     assertInitialized();
447     for (InspectionProfileEntry inspection : inspections) {
448       LightPlatformTestCase.enableInspectionTool(getProject(), InspectionToolRegistrar.wrapTool(inspection));
449     }
450   }
451
452   @Override
453   public void enableInspections(@NotNull final Class<? extends LocalInspectionTool>... inspections) {
454     enableInspections(Arrays.asList(inspections));
455   }
456
457   @Override
458   public void enableInspections(@NotNull final Collection<Class<? extends LocalInspectionTool>> inspections) {
459     List<LocalInspectionTool> tools = new ArrayList<LocalInspectionTool>();
460     for (Class<? extends LocalInspectionTool> clazz : inspections) {
461       try {
462         LocalInspectionTool inspection = clazz.getConstructor().newInstance();
463         tools.add(inspection);
464       }
465       catch (Exception e) {
466         throw new RuntimeException("Cannot instantiate " + clazz);
467       }
468     }
469     enableInspections(tools.toArray(new LocalInspectionTool[tools.size()]));
470   }
471
472   @Override
473   public void disableInspections(@NotNull InspectionProfileEntry... inspections) {
474     InspectionProfileImpl profile = (InspectionProfileImpl)InspectionProjectProfileManager.getInstance(getProject()).getInspectionProfile();
475     for (InspectionProfileEntry inspection : inspections) {
476       profile.disableTool(inspection.getShortName(), getProject());
477     }
478   }
479
480   @Override
481   public void enableInspections(@NotNull InspectionToolProvider... providers) {
482     List<LocalInspectionTool> tools = new ArrayList<LocalInspectionTool>();
483     for (InspectionToolProvider provider : providers) {
484       for (Class<?> clazz : provider.getInspectionClasses()) {
485         try {
486           Object o = clazz.getConstructor().newInstance();
487           if (o instanceof LocalInspectionTool) {
488             LocalInspectionTool inspection = (LocalInspectionTool)o;
489             tools.add(inspection);
490           }
491         }
492         catch (Exception e) {
493           throw new RuntimeException("Cannot instantiate " + clazz, e);
494         }
495       }
496     }
497     enableInspections(tools.toArray(new LocalInspectionTool[tools.size()]));
498   }
499
500   @Override
501   public long testHighlighting(final boolean checkWarnings,
502                                final boolean checkInfos,
503                                final boolean checkWeakWarnings,
504                                @NotNull final String... filePaths) {
505     if (filePaths.length > 0) {
506       configureByFilesInner(filePaths);
507     }
508     try {
509       return collectAndCheckHighlighting(checkWarnings, checkInfos, checkWeakWarnings);
510     }
511     catch (Exception e) {
512       throw new RuntimeException(e);
513     }
514   }
515
516   @Override
517   public long testHighlightingAllFiles(final boolean checkWarnings,
518                                        final boolean checkInfos,
519                                        final boolean checkWeakWarnings,
520                                        @NotNull final String... filePaths) {
521     final ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
522     for (String path : filePaths) {
523       files.add(copyFileToProject(path));
524     }
525     return testHighlightingAllFiles(checkWarnings, checkInfos, checkWeakWarnings, VfsUtilCore.toVirtualFileArray(files));
526   }
527
528   @Override
529   public long testHighlightingAllFiles(final boolean checkWarnings,
530                                        final boolean checkInfos,
531                                        final boolean checkWeakWarnings,
532                                        @NotNull final VirtualFile... files) {
533     return collectAndCheckHighlightings(checkWarnings, checkInfos, checkWeakWarnings, files);
534   }
535
536   private long collectAndCheckHighlightings(final boolean checkWarnings,
537                                             final boolean checkInfos,
538                                             final boolean checkWeakWarnings,
539                                             @NotNull VirtualFile[] files) {
540     final List<Trinity<PsiFile, Editor, ExpectedHighlightingData>> datas =
541       ContainerUtil.map2List(files, new Function<VirtualFile, Trinity<PsiFile, Editor, ExpectedHighlightingData>>() {
542         @Override
543         public Trinity<PsiFile, Editor, ExpectedHighlightingData> fun(final VirtualFile file) {
544           final PsiFile psiFile = myPsiManager.findFile(file);
545           Assert.assertNotNull(psiFile);
546           final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(psiFile);
547           Assert.assertNotNull(document);
548           ExpectedHighlightingData data = new ExpectedHighlightingData(document, checkWarnings, checkWeakWarnings, checkInfos, psiFile);
549           data.init();
550           return Trinity.create(psiFile, createEditor(file), data);
551         }
552       });
553     long elapsed = 0;
554     for (Trinity<PsiFile, Editor, ExpectedHighlightingData> trinity : datas) {
555       myEditor = trinity.second;
556       myFile = trinity.first.getVirtualFile();
557       elapsed += collectAndCheckHighlighting(trinity.third);
558     }
559     return elapsed;
560   }
561
562   @Override
563   public long checkHighlighting(final boolean checkWarnings, final boolean checkInfos, final boolean checkWeakWarnings) {
564     return checkHighlighting(checkWarnings, checkInfos, checkWeakWarnings, false);
565   }
566
567   @Override
568   public long checkHighlighting(final boolean checkWarnings, final boolean checkInfos, final boolean checkWeakWarnings, boolean ignoreExtraHighlighting) {
569     try {
570       return collectAndCheckHighlighting(checkWarnings, checkInfos, checkWeakWarnings, ignoreExtraHighlighting);
571     }
572     catch (Exception e) {
573       throw new RuntimeException(e);
574     }
575   }
576
577   @Override
578   public long checkHighlighting() {
579     return checkHighlighting(true, false, true);
580   }
581
582   @Override
583   public long testHighlighting(@NotNull final String... filePaths) {
584     return testHighlighting(true, false, true, filePaths);
585   }
586
587   @Override
588   public long testHighlighting(final boolean checkWarnings,
589                                final boolean checkInfos,
590                                final boolean checkWeakWarnings,
591                                @NotNull final VirtualFile file) {
592     openFileInEditor(file);
593     try {
594       return collectAndCheckHighlighting(checkWarnings, checkInfos, checkWeakWarnings);
595     }
596     catch (Exception e) {
597       throw new RuntimeException(e);
598     }
599   }
600
601   @NotNull
602   @Override
603   public HighlightTestInfo testFile(@NotNull String... filePath) {
604     return new HighlightTestInfo(getTestRootDisposable(), filePath) {
605       @Override
606       public HighlightTestInfo doTest() {
607         configureByFiles(filePaths);
608         ExpectedHighlightingData data = new ExpectedHighlightingData(myEditor.getDocument(), checkWarnings, checkWeakWarnings, checkInfos, getFile());
609         if (checkSymbolNames) data.checkSymbolNames();
610         data.init();
611         collectAndCheckHighlighting(data);
612         return this;
613       }
614     };
615   }
616
617   @Override
618   public void openFileInEditor(@NotNull final VirtualFile file) {
619     myFile = file;
620     myEditor = createEditor(file);
621   }
622
623   @Override
624   public void testInspection(@NotNull String testDir, @NotNull InspectionToolWrapper toolWrapper) {
625     VirtualFile sourceDir = copyDirectoryToProject(new File(testDir, "src").getPath(), "src");
626     PsiDirectory psiDirectory = getPsiManager().findDirectory(sourceDir);
627     Assert.assertNotNull(psiDirectory);
628
629     AnalysisScope scope = new AnalysisScope(psiDirectory);
630     scope.invalidate();
631
632     InspectionManagerEx inspectionManager = (InspectionManagerEx)InspectionManager.getInstance(getProject());
633     GlobalInspectionContextForTests globalContext = createGlobalContextForTool(scope, getProject(), inspectionManager, toolWrapper);
634
635     InspectionTestUtil.runTool(toolWrapper, scope, globalContext);
636     InspectionTestUtil.compareToolResults(globalContext, toolWrapper, false, new File(getTestDataPath(), testDir).getPath());
637   }
638
639   @Override
640   @Nullable
641   public PsiReference getReferenceAtCaretPosition(@NotNull final String... filePaths) {
642     if (filePaths.length > 0) {
643       configureByFilesInner(filePaths);
644     }
645     return getFile().findReferenceAt(myEditor.getCaretModel().getOffset());
646   }
647
648   @Override
649   @NotNull
650   public PsiReference getReferenceAtCaretPositionWithAssertion(@NotNull final String... filePaths) {
651     final PsiReference reference = getReferenceAtCaretPosition(filePaths);
652     Assert.assertNotNull("no reference found at " + myEditor.getCaretModel().getLogicalPosition(), reference);
653     return reference;
654   }
655
656   @Override
657   @NotNull
658   public List<IntentionAction> getAvailableIntentions(@NotNull final String... filePaths) {
659     if (filePaths.length > 0) {
660       configureByFilesInner(filePaths);
661     }
662     return getAvailableIntentions();
663   }
664
665   @Override
666   @NotNull
667   public List<IntentionAction> getAllQuickFixes(@NotNull final String... filePaths) {
668     if (filePaths.length != 0) {
669       configureByFilesInner(filePaths);
670     }
671     List<HighlightInfo> infos = doHighlighting();
672     ArrayList<IntentionAction> actions = new ArrayList<IntentionAction>();
673     for (HighlightInfo info : infos) {
674       if (info.quickFixActionRanges != null) {
675         for (Pair<HighlightInfo.IntentionActionDescriptor, TextRange> pair : info.quickFixActionRanges) {
676           actions.add(pair.getFirst().getAction());
677         }
678       }
679     }
680     return actions;
681   }
682
683   @Override
684   @NotNull
685   public List<IntentionAction> getAvailableIntentions() {
686     doHighlighting();
687     PsiFile file = getFile();
688     Editor editor = getEditor();
689     if (editor instanceof EditorWindow) {
690       editor = ((EditorWindow)editor).getDelegate();
691       file = InjectedLanguageUtil.getTopLevelFile(file);
692     }
693     Assert.assertNotNull(file);
694     return getAvailableIntentions(editor, file);
695   }
696
697   @NotNull
698   @Override
699   public List<IntentionAction> filterAvailableIntentions(@NotNull final String hint) {
700     final List<IntentionAction> availableIntentions = getAvailableIntentions();
701     return ContainerUtil.findAll(availableIntentions, new Condition<IntentionAction>() {
702       @Override
703       public boolean value(final IntentionAction intentionAction) {
704         return intentionAction.getText().startsWith(hint);
705       }
706     });
707   }
708
709   @Override
710   public IntentionAction findSingleIntention(@NotNull final String hint) {
711     final List<IntentionAction> list = filterAvailableIntentions(hint);
712     if (list.isEmpty()) {
713       Assert.fail("\"" + hint + "\" not in [" + StringUtil.join(getAvailableIntentions(), INTENTION_NAME_FUN, ", ") + "]");
714     }
715     else if (list.size() > 1) {
716       Assert.fail("Too many intentions found for \"" + hint + "\": [" + StringUtil.join(list, INTENTION_NAME_FUN, ", ") + "]");
717     }
718     return UsefulTestCase.assertOneElement(list);
719   }
720
721   @Override
722   public IntentionAction getAvailableIntention(@NotNull final String intentionName, @NotNull final String... filePaths) {
723     List<IntentionAction> intentions = getAvailableIntentions(filePaths);
724     IntentionAction action = CodeInsightTestUtil.findIntentionByText(intentions, intentionName);
725     if (action == null) {
726       System.out.println(intentionName + " not found among " + StringUtil.join(intentions, new Function<IntentionAction, String>() {
727         @Override
728         public String fun(IntentionAction action) {
729           return action.getText();
730         }
731       }, ","));
732     }
733     return action;
734   }
735
736   @Override
737   public void launchAction(@NotNull final IntentionAction action) {
738     ShowIntentionActionsHandler.chooseActionAndInvoke(getFile(), getEditor(), action, action.getText());
739     UIUtil.dispatchAllInvocationEvents();
740   }
741
742   @Override
743   public void testCompletion(@NotNull String[] filesBefore, @NotNull @TestDataFile String fileAfter) {
744     testCompletionTyping(filesBefore, "", fileAfter);
745   }
746
747   @Override
748   public void testCompletionTyping(@NotNull final String[] filesBefore, @NotNull String toType, @NotNull final String fileAfter) {
749     assertInitialized();
750     configureByFiles(filesBefore);
751     complete(CompletionType.BASIC);
752     type(toType);
753     try {
754       checkResultByFile(fileAfter);
755     }
756     catch (RuntimeException e) {
757       System.out.println("LookupElementStrings = " + getLookupElementStrings());
758       throw e;
759     }
760   }
761
762   protected void assertInitialized() {
763     Assert.assertNotNull("setUp() hasn't been called", myPsiManager);
764   }
765
766   @Override
767   public void testCompletion(@NotNull String fileBefore, @NotNull String fileAfter, @NotNull final String... additionalFiles) {
768     testCompletionTyping(fileBefore, "", fileAfter, additionalFiles);
769   }
770
771   @Override
772   public void testCompletionTyping(@NotNull @TestDataFile String fileBefore,
773                                    @NotNull String toType,
774                                    @NotNull @TestDataFile String fileAfter,
775                                    @NotNull String... additionalFiles) {
776     testCompletionTyping(ArrayUtil.reverseArray(ArrayUtil.append(additionalFiles, fileBefore)), toType, fileAfter);
777   }
778
779   @Override
780   public void testCompletionVariants(@NotNull final String fileBefore, @NotNull final String... expectedItems) {
781     assertInitialized();
782     final List<String> result = getCompletionVariants(fileBefore);
783     Assert.assertNotNull(result);
784     UsefulTestCase.assertSameElements(result, expectedItems);
785   }
786
787   @Override
788   public List<String> getCompletionVariants(@NotNull final String... filesBefore) {
789     assertInitialized();
790     configureByFiles(filesBefore);
791     final LookupElement[] items = complete(CompletionType.BASIC);
792     Assert.assertNotNull("No lookup was shown, probably there was only one lookup element that was inserted automatically", items);
793     return getLookupElementStrings();
794   }
795
796   @Override
797   @Nullable
798   public List<String> getLookupElementStrings() {
799     assertInitialized();
800     final LookupElement[] elements = getLookupElements();
801     if (elements == null) return null;
802
803     return ContainerUtil.map(elements, new Function<LookupElement, String>() {
804       @Override
805       public String fun(final LookupElement lookupItem) {
806         return lookupItem.getLookupString();
807       }
808     });
809   }
810
811   @Override
812   public void finishLookup(final char completionChar) {
813     CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
814       @Override
815       public void run() {
816         ((LookupImpl)LookupManager.getActiveLookup(getEditor())).finishLookup(completionChar);
817       }
818     }, null, null);
819   }
820
821   @Override
822   public void testRename(@NotNull final String fileBefore, @NotNull final String fileAfter, @NotNull final String newName, @NotNull final String... additionalFiles) {
823     assertInitialized();
824     configureByFiles(ArrayUtil.reverseArray(ArrayUtil.append(additionalFiles, fileBefore)));
825     testRename(fileAfter, newName);
826   }
827
828   @Override
829   public void testRename(@NotNull final String fileAfter, @NotNull final String newName) {
830     renameElementAtCaret(newName);
831     checkResultByFile(fileAfter);
832   }
833
834   @Override
835   @NotNull
836   public PsiElement getElementAtCaret() {
837     assertInitialized();
838     Editor editor = getCompletionEditor();
839     int findTargetFlags = TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED | TargetElementUtil.ELEMENT_NAME_ACCEPTED;
840     PsiElement element = TargetElementUtil.findTargetElement(editor, findTargetFlags);
841
842     // if no references found in injected fragment, try outer document
843     if (element == null && editor instanceof EditorWindow) {
844       element = TargetElementUtil.findTargetElement(((EditorWindow)editor).getDelegate(), findTargetFlags);
845     }
846
847     if (element == null) {
848       Assert.fail("element not found in file " + myFile.getName() +
849                   " at caret position offset " + myEditor.getCaretModel().getOffset() +  "," +
850                   " psi structure:\n" + DebugUtil.psiToString(getFile(), true, true));
851     }
852     return element;
853   }
854
855   @Override
856   public void renameElementAtCaret(@NotNull final String newName) {
857     renameElement(getElementAtCaret(), newName);
858   }
859
860   @Override
861   public void renameElementAtCaretUsingHandler(@NotNull final String newName) {
862       final DataContext editorContext = ((EditorEx)myEditor).getDataContext();
863       final DataContext context = new DataContext() {
864         @Override
865         public Object getData(final String dataId) {
866           return PsiElementRenameHandler.DEFAULT_NAME.getName().equals(dataId)
867                  ? newName
868                  : editorContext.getData(dataId);
869         }
870       };
871       final RenameHandler renameHandler = RenameHandlerRegistry.getInstance().getRenameHandler(context);
872       Assert.assertNotNull("No handler for this context", renameHandler);
873
874       renameHandler.invoke(getProject(), myEditor, getFile(), context);
875   }
876
877   @Override
878   public void renameElement(@NotNull final PsiElement element, @NotNull final String newName) {
879     final boolean searchInComments = false;
880     final boolean searchTextOccurrences = false;
881     renameElement(element, newName, searchInComments, searchTextOccurrences);
882   }
883
884   @Override
885   public void renameElement(@NotNull final PsiElement element,
886                             @NotNull final String newName,
887                             final boolean searchInComments,
888                             final boolean searchTextOccurrences) {
889     final PsiElement substitution = RenamePsiElementProcessor.forElement(element).substituteElementToRename(element, myEditor);
890     if (substitution == null) return;
891     new RenameProcessor(getProject(), substitution, newName, searchInComments, searchTextOccurrences).run();
892   }
893
894   @Override
895   public <T extends PsiElement> T findElementByText(@NotNull String text, @NotNull Class<T> elementClass) {
896     int pos = PsiDocumentManager.getInstance(getProject()).getDocument(getFile()).getText().indexOf(text);
897     Assert.assertTrue(text, pos >= 0);
898     return PsiTreeUtil.getParentOfType(getFile().findElementAt(pos), elementClass);
899   }
900
901   @Override
902   public void type(final char c) {
903     assertInitialized();
904     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
905       @Override
906       public void run() {
907         final EditorActionManager actionManager = EditorActionManager.getInstance();
908         if (c == '\b') {
909           performEditorAction(IdeActions.ACTION_EDITOR_BACKSPACE);
910           return;
911         }
912         if (c == '\n') {
913           if (_performEditorAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM)) {
914             return;
915           }
916           if (_performEditorAction(IdeActions.ACTION_EDITOR_NEXT_TEMPLATE_VARIABLE)) {
917             return;
918           }
919
920           performEditorAction(IdeActions.ACTION_EDITOR_ENTER);
921           return;
922         }
923         if (c == '\t') {
924           if (_performEditorAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_REPLACE)) {
925             return;
926           }
927           if (_performEditorAction(IdeActions.ACTION_EXPAND_LIVE_TEMPLATE_BY_TAB)) {
928             return;
929           }
930           if (_performEditorAction(IdeActions.ACTION_EDITOR_NEXT_TEMPLATE_VARIABLE)) {
931             return;
932           }
933           if (_performEditorAction(IdeActions.ACTION_EDITOR_TAB)) {
934             return;
935           }
936         }
937         if (c == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) {
938           if (_performEditorAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_COMPLETE_STATEMENT)) {
939             return;
940           }
941         }
942
943         CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
944           @Override
945           public void run() {
946             CommandProcessor.getInstance().setCurrentCommandGroupId(myEditor.getDocument());
947             ActionManagerEx.getInstanceEx().fireBeforeEditorTyping(c, getEditorDataContext());
948             actionManager.getTypedAction().actionPerformed(getEditor(), c, getEditorDataContext());
949           }
950         }, null, DocCommandGroupId.noneGroupId(myEditor.getDocument()));
951       }
952     });
953   }
954
955   @NotNull
956   private DataContext getEditorDataContext() {
957     return ((EditorEx)myEditor).getDataContext();
958   }
959
960   @Override
961   public void type(@NotNull String s) {
962     for (int i = 0; i < s.length(); i++) {
963       type(s.charAt(i));
964     }
965   }
966
967   @Override
968   public void performEditorAction(@NotNull final String actionId) {
969     assertInitialized();
970     _performEditorAction(actionId);
971   }
972
973   private boolean _performEditorAction(@NotNull String actionId) {
974     final DataContext dataContext = getEditorDataContext();
975
976     final ActionManagerEx managerEx = ActionManagerEx.getInstanceEx();
977     final AnAction action = managerEx.getAction(actionId);
978     final AnActionEvent event = new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, new Presentation(), managerEx, 0);
979
980     return WriteCommandAction.runWriteCommandAction(getProject(), new Computable<Boolean>() {
981       @Override
982       public Boolean compute() {
983         action.update(event);
984
985         if (!event.getPresentation().isEnabled()) {
986           return false;
987         }
988
989         managerEx.fireBeforeActionPerformed(action, dataContext, event);
990
991         action.actionPerformed(event);
992
993         managerEx.fireAfterActionPerformed(action, dataContext, event);
994         return true;
995       }
996     });
997   }
998
999   @NotNull
1000   @Override
1001   public Presentation testAction(@NotNull AnAction action) {
1002     TestActionEvent e = new TestActionEvent(action);
1003     action.beforeActionPerformedUpdate(e);
1004     if (e.getPresentation().isEnabled() && e.getPresentation().isVisible()) {
1005       action.actionPerformed(e);
1006     }
1007     return e.getPresentation();
1008   }
1009
1010   @NotNull
1011   @Override
1012   public Collection<UsageInfo> testFindUsages(@NotNull final String... fileNames) {
1013     assertInitialized();
1014     configureByFiles(fileNames);
1015     final PsiElement targetElement = TargetElementUtil
1016       .findTargetElement(getEditor(), TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED);
1017     Assert.assertNotNull("Cannot find referenced element", targetElement);
1018     return findUsages(targetElement);
1019   }
1020
1021   @NotNull
1022   @Override
1023   public Collection<UsageInfo> findUsages(@NotNull final PsiElement targetElement) {
1024     return findUsages(targetElement, null);
1025   }
1026
1027   @NotNull
1028   public Collection<UsageInfo> findUsages(@NotNull final PsiElement targetElement, @Nullable SearchScope scope) {
1029     final Project project = getProject();
1030     final FindUsagesHandler handler =
1031       ((FindManagerImpl)FindManager.getInstance(project)).getFindUsagesManager().getFindUsagesHandler(targetElement, false);
1032
1033     final CommonProcessors.CollectProcessor<UsageInfo> processor = new CommonProcessors.CollectProcessor<UsageInfo>();
1034     Assert.assertNotNull("Cannot find handler for: " + targetElement, handler);
1035     final PsiElement[] psiElements = ArrayUtil.mergeArrays(handler.getPrimaryElements(), handler.getSecondaryElements());
1036     final FindUsagesOptions options = handler.getFindUsagesOptions(null);
1037     if (scope != null) options.searchScope = scope; 
1038     for (PsiElement psiElement : psiElements) {
1039       handler.processElementUsages(psiElement, processor, options);
1040     }
1041     return processor.getResults();
1042   }
1043
1044   @NotNull
1045   @Override
1046   public RangeHighlighter[] testHighlightUsages(@NotNull final String... files) {
1047     configureByFiles(files);
1048     testAction(new HighlightUsagesAction());
1049     final Editor editor = getEditor();
1050     //final Editor editor = com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR.getData(DataManager.getInstance().getDataContext());
1051     //assert editor != null;
1052     //HighlightUsagesHandler.invoke(getProject(), editor, getFile());
1053     return editor.getMarkupModel().getAllHighlighters();
1054   }
1055
1056   @Override
1057   public void moveFile(@NotNull final String filePath, @NotNull final String to, @NotNull final String... additionalFiles) {
1058     assertInitialized();
1059     final Project project = getProject();
1060     configureByFiles(ArrayUtil.reverseArray(ArrayUtil.append(additionalFiles, filePath)));
1061     final VirtualFile file = findFileInTempDir(to);
1062     Assert.assertNotNull("Directory " + to + " not found", file);
1063     Assert.assertTrue(to + " is not a directory", file.isDirectory());
1064     final PsiDirectory directory = myPsiManager.findDirectory(file);
1065     new MoveFilesOrDirectoriesProcessor(project, new PsiElement[]{getFile()}, directory,
1066                                         false, false, null, null).run();
1067   }
1068
1069   @Override
1070   @Nullable
1071   public GutterMark findGutter(@NotNull final String filePath) {
1072     configureByFilesInner(filePath);
1073     CommonProcessors.FindFirstProcessor<GutterMark> processor = new CommonProcessors.FindFirstProcessor<GutterMark>();
1074     findGutters(processor);
1075     return processor.getFoundValue();
1076   }
1077
1078   @NotNull
1079   @Override
1080   public List<GutterMark> findGuttersAtCaret() {
1081     CommonProcessors.CollectProcessor<GutterMark> processor = new CommonProcessors.CollectProcessor<GutterMark>();
1082     findGutters(processor);
1083     return new ArrayList<GutterMark>(processor.getResults());
1084   }
1085
1086   private void findGutters(Processor<GutterMark> processor) {
1087     int offset = myEditor.getCaretModel().getOffset();
1088
1089     final Collection<HighlightInfo> infos = doHighlighting();
1090     for (HighlightInfo info : infos) {
1091       if (info.endOffset >= offset && info.startOffset <= offset) {
1092         final GutterMark renderer = info.getGutterIconRenderer();
1093         if (renderer != null && !processor.process(renderer)) {
1094           return;
1095         }
1096       }
1097     }
1098     RangeHighlighter[] highlighters = DocumentMarkupModel.forDocument(myEditor.getDocument(), getProject(), true).getAllHighlighters();
1099     for (RangeHighlighter highlighter : highlighters) {
1100       if (highlighter.getEndOffset() >= offset && highlighter.getStartOffset() <= offset) {
1101         GutterMark renderer = highlighter.getGutterIconRenderer();
1102         if (renderer != null && !processor.process(renderer)) {
1103           return;
1104         }
1105       }
1106     }
1107   }
1108
1109   @Override
1110   @NotNull
1111   public List<GutterMark> findAllGutters(@NotNull final String filePath) {
1112     configureByFilesInner(filePath);
1113     return findAllGutters();
1114   }
1115
1116   @Override
1117   @NotNull
1118   public List<GutterMark> findAllGutters() {
1119     final Project project = getProject();
1120     final SortedMap<Integer, List<GutterMark>> result = new TreeMap<Integer, List<GutterMark>>();
1121
1122     List<HighlightInfo> infos = doHighlighting();
1123     for (HighlightInfo info : infos) {
1124       addGutterIconRenderer(info.getGutterIconRenderer(), info.startOffset, result);
1125     }
1126
1127     RangeHighlighter[] highlighters = DocumentMarkupModel.forDocument(myEditor.getDocument(), project, true).getAllHighlighters();
1128     for (final RangeHighlighter highlighter : highlighters) {
1129       if (!highlighter.isValid()) continue;
1130       addGutterIconRenderer(highlighter.getGutterIconRenderer(), highlighter.getStartOffset(), result);
1131     }
1132     return ContainerUtil.concat(result.values());
1133   }
1134
1135   @Override
1136   public PsiFile addFileToProject(@NotNull final String relativePath, @NotNull final String fileText) {
1137     assertInitialized();
1138     return addFileToProject(getTempDirPath(), relativePath, fileText);
1139   }
1140
1141   protected PsiFile addFileToProject(@NotNull final String rootPath, @NotNull final String relativePath, @NotNull final String fileText) {
1142     return new WriteCommandAction<PsiFile>(getProject()) {
1143       @Override
1144       protected void run(@NotNull Result<PsiFile> result) throws Throwable {
1145         try {
1146           if (myTempDirFixture instanceof LightTempDirTestFixtureImpl) {
1147             final VirtualFile file = myTempDirFixture.createFile(relativePath, fileText);
1148             result.setResult(PsiManager.getInstance(getProject()).findFile(file));
1149           }
1150           else {
1151             result.setResult(((HeavyIdeaTestFixture)myProjectFixture).addFileToProject(rootPath, relativePath, fileText));
1152           }
1153         }
1154         catch (IOException e) {
1155           throw new RuntimeException(e);
1156         }
1157         finally {
1158           ((PsiModificationTrackerImpl)PsiManager.getInstance(getProject()).getModificationTracker()).incCounter();
1159         }
1160       }
1161     }.execute().getResultObject();
1162   }
1163
1164   public <T> void registerExtension(final ExtensionsArea area, final ExtensionPointName<T> epName, final T extension) {
1165     assertInitialized();
1166     final ExtensionPoint<T> extensionPoint = area.getExtensionPoint(epName);
1167     extensionPoint.registerExtension(extension);
1168     Disposer.register(getTestRootDisposable(), new Disposable() {
1169       @Override
1170       public void dispose() {
1171         extensionPoint.unregisterExtension(extension);
1172       }
1173     });
1174   }
1175
1176   @NotNull
1177   @Override
1178   public PsiManager getPsiManager() {
1179     return myPsiManager;
1180   }
1181
1182   @Override
1183   public LookupElement[] complete(@NotNull CompletionType type) {
1184     return complete(type, 1);
1185   }
1186
1187   @Override
1188   public LookupElement[] complete(@NotNull final CompletionType type, final int invocationCount) {
1189     assertInitialized();
1190     myEmptyLookup = false;
1191     return UIUtil.invokeAndWaitIfNeeded(new Computable<LookupElement[]>() {
1192       @Override
1193       public LookupElement[] compute() {
1194         CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
1195           @Override
1196           public void run() {
1197             final CodeCompletionHandlerBase handler = new CodeCompletionHandlerBase(type) {
1198
1199               @Override
1200               protected void completionFinished(CompletionProgressIndicator indicator, boolean hasModifiers) {
1201                 myEmptyLookup = indicator.getLookup().getItems().isEmpty();
1202                 super.completionFinished(indicator, hasModifiers);
1203               }
1204             };
1205             Editor editor = getCompletionEditor();
1206             handler.invokeCompletion(getProject(), editor, invocationCount);
1207             PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); // to compare with file text
1208           }
1209         }, null, null);
1210         return getLookupElements();
1211       }
1212     });
1213   }
1214
1215   @Nullable
1216   protected Editor getCompletionEditor() {
1217     return InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(myEditor, getFile());
1218   }
1219
1220   @Override
1221   @Nullable
1222   public LookupElement[] completeBasic() {
1223     return complete(CompletionType.BASIC);
1224   }
1225
1226   @Override
1227   @NotNull
1228   public final List<LookupElement> completeBasicAllCarets(@Nullable final Character charToTypeAfterCompletion) {
1229     final CaretModel caretModel = myEditor.getCaretModel();
1230     final List<Caret> carets = caretModel.getAllCarets();
1231
1232     final List<Integer> originalOffsets = new ArrayList<Integer>(carets.size());
1233
1234     for (final Caret caret : carets) {
1235       originalOffsets.add(caret.getOffset());
1236     }
1237     caretModel.removeSecondaryCarets();
1238
1239     // We do it in reverse order because completions would affect offsets
1240     // i.e.: when you complete "spa" to "spam", next caret offset increased by 1
1241     Collections.reverse(originalOffsets);
1242     final List<LookupElement> result = new ArrayList<LookupElement>();
1243     for (final int originalOffset : originalOffsets) {
1244       caretModel.moveToOffset(originalOffset);
1245       final LookupElement[] lookupElements = completeBasic();
1246       if (charToTypeAfterCompletion != null) {
1247         type(charToTypeAfterCompletion);
1248       }
1249       if (lookupElements != null) {
1250         result.addAll(Arrays.asList(lookupElements));
1251       }
1252     }
1253     return result;
1254   }
1255
1256   @Override
1257   public void saveText(@NotNull final VirtualFile file, @NotNull final String text) {
1258     new WriteAction() {
1259       @Override
1260       protected void run(@NotNull Result result) throws Throwable {
1261         VfsUtil.saveText(file, text);
1262       }
1263     }.execute().throwException();
1264
1265   }
1266
1267   @Override
1268   @Nullable
1269   public LookupElement[] getLookupElements() {
1270     LookupImpl lookup = getLookup();
1271     if (lookup == null) {
1272       return myEmptyLookup ? LookupElement.EMPTY_ARRAY : null;
1273     }
1274     else {
1275       final List<LookupElement> list = lookup.getItems();
1276       return list.toArray(new LookupElement[list.size()]);
1277     }
1278   }
1279
1280   @Override
1281   public void checkResult(@NotNull final String text) {
1282     checkResult(text, false);
1283   }
1284
1285   @Override
1286   public void checkResult(@NotNull final String text, final boolean stripTrailingSpaces) {
1287     new WriteCommandAction(getProject()) {
1288       @Override
1289       protected void run(@NotNull Result result) throws Throwable {
1290         PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
1291         EditorUtil.fillVirtualSpaceUntilCaret(myEditor);
1292         checkResult("TEXT", stripTrailingSpaces, SelectionAndCaretMarkupLoader.fromText(text), getHostFile().getText());
1293       }
1294     }.execute();
1295   }
1296
1297   @Override
1298   public void checkResultByFile(@NotNull final String expectedFile) {
1299     checkResultByFile(expectedFile, false);
1300   }
1301
1302   @Override
1303   public void checkResultByFile(@NotNull final String expectedFile, final boolean ignoreTrailingWhitespaces) {
1304     assertInitialized();
1305     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
1306       @Override
1307       public void run() {
1308         try {
1309           checkResultByFile(expectedFile, getHostFile(), ignoreTrailingWhitespaces);
1310         }
1311         catch (IOException e) {
1312           throw new RuntimeException(e);
1313         }
1314       }
1315     });
1316   }
1317
1318   @Override
1319   public void checkResultByFile(@NotNull final String filePath, @NotNull final String expectedFile, final boolean ignoreTrailingWhitespaces) {
1320     assertInitialized();
1321
1322     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
1323       @Override
1324       public void run() {
1325         final String path = filePath.replace(File.separatorChar, '/');
1326         final VirtualFile copy = findFileInTempDir(path);
1327         if (copy == null) {
1328           throw new IllegalArgumentException("could not find results file " + path);
1329         }
1330         final PsiFile psiFile = myPsiManager.findFile(copy);
1331         Assert.assertNotNull(copy.getPath(), psiFile);
1332         try {
1333           checkResultByFile(expectedFile, psiFile, ignoreTrailingWhitespaces);
1334         }
1335         catch (IOException e) {
1336           throw new RuntimeException(e);
1337         }
1338       }
1339     });
1340   }
1341
1342   @Override
1343   public void setUp() throws Exception {
1344     super.setUp();
1345
1346     TestRunnerUtil.replaceIdeEventQueueSafely();
1347     EdtTestUtil.runInEdtAndWait(new ThrowableRunnable<Throwable>() {
1348       @Override
1349       public void run() throws Throwable {
1350         myProjectFixture.setUp();
1351         myTempDirFixture.setUp();
1352
1353         VirtualFile tempDir = myTempDirFixture.getFile("");
1354         PlatformTestCase.synchronizeTempDirVfs(tempDir);
1355
1356         myPsiManager = (PsiManagerImpl)PsiManager.getInstance(getProject());
1357         configureInspections(LocalInspectionTool.EMPTY_ARRAY, getProject(), Collections.<String>emptyList(), getTestRootDisposable());
1358
1359         DaemonCodeAnalyzerImpl daemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject());
1360         daemonCodeAnalyzer.prepareForTest();
1361
1362         DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(false);
1363         ensureIndexesUpToDate(getProject());
1364         ((StartupManagerImpl)StartupManagerEx.getInstanceEx(getProject())).runPostStartupActivities();
1365       }
1366     });
1367   }
1368
1369   @Override
1370   public void tearDown() throws Exception {
1371     try {
1372       EdtTestUtil.runInEdtAndWait(new ThrowableRunnable<Throwable>() {
1373         @Override
1374         public void run() throws Throwable {
1375           try {
1376             DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(true); // return default value to avoid unnecessary save
1377             FileEditorManager editorManager = FileEditorManager.getInstance(getProject());
1378             PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
1379             VirtualFile[] openFiles = editorManager.getOpenFiles();
1380             for (VirtualFile openFile : openFiles) {
1381               editorManager.closeFile(openFile);
1382             }
1383           }
1384           finally {
1385             myEditor = null;
1386             myFile = null;
1387             myPsiManager = null;
1388
1389             try {
1390               myProjectFixture.tearDown();
1391             }
1392             finally {
1393               myTempDirFixture.tearDown();
1394             }
1395           }
1396         }
1397       });
1398     }
1399     finally {
1400       super.tearDown();
1401     }
1402   }
1403
1404   @NotNull
1405   private PsiFile[] configureByFilesInner(@NotNull String... filePaths) {
1406     assertInitialized();
1407     myFile = null;
1408     myEditor = null;
1409     PsiFile[] psiFiles = new PsiFile[filePaths.length];
1410     for (int i = filePaths.length - 1; i >= 0; i--) {
1411       psiFiles[i] = configureByFileInner(filePaths[i]);
1412     }
1413     return psiFiles;
1414   }
1415
1416   @Override
1417   public PsiFile configureByFile(@NotNull final String file) {
1418     configureByFilesInner(file);
1419     return getFile();
1420   }
1421
1422   @NotNull
1423   @Override
1424   public PsiFile[] configureByFiles(@NotNull final String... files) {
1425     return configureByFilesInner(files);
1426   }
1427
1428   @Override
1429   public PsiFile configureByText(@NotNull final FileType fileType, @NotNull final String text) {
1430     assertInitialized();
1431     final String extension = fileType.getDefaultExtension();
1432     final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
1433     if (fileTypeManager.getFileTypeByExtension(extension) != fileType) {
1434       new WriteCommandAction(getProject()) {
1435         @Override
1436         protected void run(@NotNull Result result) throws Exception {
1437           fileTypeManager.associateExtension(fileType, extension);
1438         }
1439       }.execute();
1440     }
1441     final String fileName = "aaa." + extension;
1442     return configureByText(fileName, text);
1443   }
1444
1445   @Override
1446   public PsiFile configureByText(@NotNull final String fileName, @NotNull final String text) {
1447     assertInitialized();
1448     return new WriteCommandAction<PsiFile>(getProject()) {
1449       @Override
1450       protected void run(@NotNull Result<PsiFile> result) throws Throwable {
1451         final VirtualFile vFile;
1452         if (myTempDirFixture instanceof LightTempDirTestFixtureImpl) {
1453           final VirtualFile root = LightPlatformTestCase.getSourceRoot();
1454           root.refresh(false, false);
1455           vFile = root.findOrCreateChildData(this, fileName);
1456           Assert.assertNotNull(fileName + " not found in " + root.getPath(), vFile);
1457         }
1458         else if (myTempDirFixture instanceof TempDirTestFixtureImpl) {
1459           final File tempFile = ((TempDirTestFixtureImpl)myTempDirFixture).createTempFile(fileName);
1460           vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempFile);
1461           Assert.assertNotNull(tempFile + " not found", vFile);
1462         }
1463         else {
1464           vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(getTempDirPath(), fileName));
1465           Assert.assertNotNull(fileName + " not found in " + getTempDirPath(), vFile);
1466         }
1467
1468         prepareVirtualFile(vFile);
1469
1470         final Document document = FileDocumentManager.getInstance().getCachedDocument(vFile);
1471         if (document != null) {
1472           PsiDocumentManager.getInstance(getProject()).doPostponedOperationsAndUnblockDocument(document);
1473           FileDocumentManager.getInstance().saveDocument(document);
1474         }
1475
1476         VfsUtil.saveText(vFile, text);
1477         configureInner(vFile, SelectionAndCaretMarkupLoader.fromFile(vFile));
1478         result.setResult(getFile());
1479       }
1480     }.execute().getResultObject();
1481   }
1482
1483   @Override
1484   public Document getDocument(@NotNull final PsiFile file) {
1485     assertInitialized();
1486     return PsiDocumentManager.getInstance(getProject()).getDocument(file);
1487   }
1488
1489   private PsiFile configureByFileInner(@NotNull String filePath) {
1490     assertInitialized();
1491     final VirtualFile file = copyFileToProject(filePath);
1492     return configureByFileInner(file);
1493   }
1494
1495   @Override
1496   public PsiFile configureFromTempProjectFile(@NotNull final String filePath) {
1497     final VirtualFile fileInTempDir = findFileInTempDir(filePath);
1498     if (fileInTempDir == null) {
1499       throw new IllegalArgumentException("Could not find file in temp dir: " + filePath);
1500     }
1501     return configureByFileInner(fileInTempDir);
1502   }
1503
1504   @Override
1505   public void configureFromExistingVirtualFile(@NotNull VirtualFile virtualFile) {
1506     configureByFileInner(virtualFile);
1507   }
1508
1509   private PsiFile configureByFileInner(@NotNull VirtualFile copy) {
1510     return configureInner(copy, SelectionAndCaretMarkupLoader.fromFile(copy));
1511   }
1512   
1513   private PsiFile configureInner(@NotNull final VirtualFile copy, @NotNull final SelectionAndCaretMarkupLoader loader) {
1514     assertInitialized();
1515
1516     EdtTestUtil.runInEdtAndWait(new ThrowableRunnable<Throwable>() {
1517       @Override
1518       public void run() {
1519         if (!copy.getFileType().isBinary()) {
1520           AccessToken token = WriteAction.start();
1521           try {
1522             copy.setBinaryContent(loader.newFileText.getBytes(copy.getCharset()));
1523           }
1524           catch (IOException e) {
1525             throw new RuntimeException(e);
1526           }
1527           finally {
1528             token.finish();
1529           }
1530         }
1531         myFile = copy;
1532         myEditor = createEditor(copy);
1533         if (myEditor == null) {
1534           Assert.fail("editor couldn't be created for: " + copy.getPath() + ", use copyFileToProject() instead of configureByFile()");
1535         }
1536
1537         EditorTestUtil.setCaretsAndSelection(myEditor, loader.caretState);
1538
1539         Module module = getModule();
1540         if (module != null) {
1541           for (Facet facet : FacetManager.getInstance(module).getAllFacets()) {
1542             module.getMessageBus().syncPublisher(FacetManager.FACETS_TOPIC).facetConfigurationChanged(facet);
1543           }
1544         }
1545         PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
1546
1547         if (myCaresAboutInjection) {
1548           setupEditorForInjectedLanguage();
1549         }
1550       }
1551     });
1552
1553     return getFile();
1554   }
1555
1556   protected void prepareVirtualFile(@NotNull VirtualFile file) {
1557   }
1558
1559   private void setupEditorForInjectedLanguage() {
1560     Editor editor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(myEditor, getFile());
1561     if (editor instanceof EditorWindow) {
1562       myFile = ((EditorWindow)editor).getInjectedFile().getViewProvider().getVirtualFile();
1563       myEditor = editor;
1564     }
1565   }
1566
1567   @Override
1568   public VirtualFile findFileInTempDir(@NotNull final String filePath) {
1569     if (myTempDirFixture instanceof LightTempDirTestFixtureImpl) {
1570       return myTempDirFixture.getFile(filePath);
1571     }
1572     String fullPath = getTempDirPath() + "/" + filePath;
1573
1574     final VirtualFile copy = LocalFileSystem.getInstance().refreshAndFindFileByPath(fullPath.replace(File.separatorChar, '/'));
1575     Assert.assertNotNull("file " + fullPath + " not found", copy);
1576     VfsTestUtil.assertFilePathEndsWithCaseSensitivePath(copy, filePath);
1577     return copy;
1578   }
1579
1580   @Nullable
1581   protected Editor createEditor(@NotNull VirtualFile file) {
1582     final Project project = getProject();
1583     final FileEditorManager instance = FileEditorManager.getInstance(project);
1584     PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
1585
1586     Editor editor = instance.openTextEditor(new OpenFileDescriptor(project, file), false);
1587     if (editor != null) {
1588       DaemonCodeAnalyzer.getInstance(getProject()).restart();
1589     }
1590     return editor;
1591   }
1592
1593   private long collectAndCheckHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings) throws Exception {
1594     return collectAndCheckHighlighting(checkWarnings, checkInfos, checkWeakWarnings, false);
1595   }
1596
1597   private long collectAndCheckHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings,
1598                                            boolean ignoreExtraHighlighting) throws Exception {
1599     ExpectedHighlightingData data = new ExpectedHighlightingData(myEditor.getDocument(),
1600                                                                  checkWarnings, checkWeakWarnings, checkInfos, ignoreExtraHighlighting, getHostFile());
1601     data.init();
1602     return collectAndCheckHighlighting(data);
1603   }
1604
1605   private PsiFile getHostFile() {
1606     return InjectedLanguageUtil.getTopLevelFile(getFile());
1607   }
1608
1609   private long collectAndCheckHighlighting(@NotNull ExpectedHighlightingData data) {
1610     final Project project = getProject();
1611     PsiDocumentManager.getInstance(project).commitAllDocuments();
1612
1613     PsiFileImpl file = (PsiFileImpl)getHostFile();
1614     FileElement hardRefToFileElement = file.calcTreeElement();//to load text
1615
1616     //to initialize caches
1617     if (!DumbService.isDumb(project)) {
1618       CacheManager.SERVICE.getInstance(project).getFilesWithWord("XXX", UsageSearchContext.IN_COMMENTS, GlobalSearchScope.allScope(project), true);
1619     }
1620
1621     final long start = System.currentTimeMillis();
1622     final VirtualFileFilter fileTreeAccessFilter = myVirtualFileFilter;
1623     Disposable disposable = Disposer.newDisposable();
1624     if (fileTreeAccessFilter != null) {
1625       PsiManagerEx.getInstanceEx(project).setAssertOnFileLoadingFilter(fileTreeAccessFilter, disposable);
1626     }
1627
1628     //    ProfilingUtil.startCPUProfiling();
1629     List<HighlightInfo> infos;
1630     try {
1631       infos = doHighlighting();
1632       removeDuplicatedRangesForInjected(infos);
1633     }
1634     finally {
1635       Disposer.dispose(disposable);
1636     }
1637     //    ProfilingUtil.captureCPUSnapshot("testing");
1638     final long elapsed = System.currentTimeMillis() - start;
1639
1640     data.checkResult(infos, file.getText());
1641     hardRefToFileElement.hashCode(); // use it so gc won't collect it
1642     return elapsed;
1643   }
1644
1645   public void setVirtualFileFilter(@Nullable VirtualFileFilter filter) {
1646     myVirtualFileFilter = filter;
1647   }
1648
1649   @Override
1650   @NotNull
1651   public List<HighlightInfo> doHighlighting() {
1652     final Project project = getProject();
1653     PsiDocumentManager.getInstance(project).commitAllDocuments();
1654
1655     PsiFile file = getFile();
1656     Editor editor = getEditor();
1657     if (editor instanceof EditorWindow) {
1658       editor = ((EditorWindow)editor).getDelegate();
1659       file = InjectedLanguageUtil.getTopLevelFile(file);
1660     }
1661     return instantiateAndRun(file, editor, ArrayUtil.EMPTY_INT_ARRAY, myAllowDirt);
1662   }
1663
1664   @NotNull
1665   @Override
1666   public List<HighlightInfo> doHighlighting(@NotNull final HighlightSeverity minimalSeverity) {
1667     return ContainerUtil.filter(doHighlighting(), new Condition<HighlightInfo>() {
1668       @Override
1669       public boolean value(HighlightInfo info) {
1670         return info.getSeverity().compareTo(minimalSeverity) >= 0;
1671       }
1672     });
1673   }
1674
1675   @NotNull
1676   @Override
1677   public String getTestDataPath() {
1678     return myTestDataPath;
1679   }
1680
1681   @Override
1682   public void setTestDataPath(@NotNull String dataPath) {
1683     myTestDataPath = dataPath;
1684   }
1685
1686   @Override
1687   public Project getProject() {
1688     return myProjectFixture.getProject();
1689   }
1690
1691   @Override
1692   public Module getModule() {
1693     return myProjectFixture.getModule();
1694   }
1695
1696   @Override
1697   public Editor getEditor() {
1698     return myEditor;
1699   }
1700
1701   @Override
1702   public int getCaretOffset() {
1703     return myEditor.getCaretModel().getOffset();
1704   }
1705
1706   @Override
1707   public PsiFile getFile() {
1708     return myFile == null ? null : ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
1709       @Override
1710       public PsiFile compute() {
1711         return PsiManager.getInstance(getProject()).findFile(myFile);
1712       }
1713     });
1714   }
1715
1716   @Override
1717   public void allowTreeAccessForFile(@NotNull final VirtualFile file) {
1718     assert myVirtualFileFilter instanceof FileTreeAccessFilter : "configured filter does not support this method";
1719     ((FileTreeAccessFilter)myVirtualFileFilter).allowTreeAccessForFile(file);
1720   }
1721
1722   @Override
1723   public void allowTreeAccessForAllFiles() {
1724     assert myVirtualFileFilter instanceof FileTreeAccessFilter : "configured filter does not support this method";
1725     ((FileTreeAccessFilter)myVirtualFileFilter).allowTreeAccessForAllFiles();
1726   }
1727
1728   private void checkResultByFile(@NotNull String expectedFile,
1729                                  @NotNull PsiFile originalFile,
1730                                  boolean stripTrailingSpaces) throws IOException {
1731     if (!stripTrailingSpaces) {
1732       EditorUtil.fillVirtualSpaceUntilCaret(myEditor);
1733     }
1734     PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
1735
1736     final String fileText = originalFile.getText();
1737     final String path = getTestDataPath() + "/" + expectedFile;
1738
1739     /*final VirtualFile result = LocalFileSystem.getInstance().findFileByPath(path);
1740     final int caret = myEditor.getCaretModel().getOffset();
1741     final String newText = myFile == originalFile ? fileText.substring(0, caret) + "<caret>" + fileText.substring(caret) : fileText;
1742     VfsUtil.saveText(result, newText);*/
1743
1744     VirtualFile virtualFile = originalFile.getVirtualFile();
1745     String charset = virtualFile == null? null : virtualFile.getCharset().name();
1746     checkResult(expectedFile, stripTrailingSpaces, SelectionAndCaretMarkupLoader.fromFile(path, charset), fileText);
1747
1748   }
1749
1750   private void checkResult(@NotNull String expectedFile,
1751                            final boolean stripTrailingSpaces,
1752                            @NotNull SelectionAndCaretMarkupLoader loader,
1753                            @NotNull String actualText) {
1754     assertInitialized();
1755     Project project = getProject();
1756     Editor editor = getEditor();
1757     if (editor instanceof EditorWindow) {
1758       editor = ((EditorWindow)editor).getDelegate();
1759     }
1760
1761     UsefulTestCase.doPostponedFormatting(getProject());
1762     if (stripTrailingSpaces) {
1763       actualText = stripTrailingSpaces(actualText);
1764     }
1765
1766     PsiDocumentManager.getInstance(project).commitAllDocuments();
1767
1768     String newFileText1 = loader.newFileText;
1769     if (stripTrailingSpaces) {
1770       newFileText1 = stripTrailingSpaces(newFileText1);
1771     }
1772
1773     actualText = StringUtil.convertLineSeparators(actualText);
1774
1775     if (!Comparing.equal(newFileText1, actualText)) {
1776       if (loader.filePath != null) {
1777         throw new FileComparisonFailure(expectedFile, newFileText1, actualText, loader.filePath);
1778       }
1779       else {
1780         throw new ComparisonFailure(expectedFile, newFileText1, actualText);
1781       }
1782     }
1783
1784     EditorTestUtil.verifyCaretAndSelectionState(editor, loader.caretState, expectedFile);
1785   }
1786
1787   @NotNull
1788   private String stripTrailingSpaces(@NotNull String actualText) {
1789     final Document document = EditorFactory.getInstance().createDocument(actualText);
1790     ((DocumentImpl)document).stripTrailingSpaces(getProject());
1791     actualText = document.getText();
1792     return actualText;
1793   }
1794
1795   public void canChangeDocumentDuringHighlighting(boolean canI) {
1796     myAllowDirt = canI;
1797   }
1798
1799   @NotNull
1800   public String getFoldingDescription(boolean withCollapseStatus) {
1801     CodeFoldingManager.getInstance(getProject()).buildInitialFoldings(myEditor);
1802
1803     final FoldingModel model = myEditor.getFoldingModel();
1804     final FoldRegion[] foldingRegions = model.getAllFoldRegions();
1805     final List<Border> borders = new LinkedList<Border>();
1806
1807     for (FoldRegion region : foldingRegions) {
1808       borders.add(new Border(Border.LEFT, region.getStartOffset(), region.getPlaceholderText(), region.isExpanded()));
1809       borders.add(new Border(Border.RIGHT, region.getEndOffset(), "", region.isExpanded()));
1810     }
1811     Collections.sort(borders);
1812
1813     StringBuilder result = new StringBuilder(myEditor.getDocument().getText());
1814     for (Border border : borders) {
1815       result.insert(border.getOffset(), border.isSide() == Border.LEFT ? "<fold text=\'" + border.getText() + "\'" +
1816                                                                          (withCollapseStatus ? " expand=\'" +
1817                                                                                                     border.isExpanded() +
1818                                                                                                     "\'" : "") +
1819                                                                           ">" : END_FOLD);
1820     }
1821
1822     return result.toString();
1823   }
1824
1825   private void testFoldingRegions(@NotNull String verificationFileName, @Nullable String destinationFileName, boolean doCheckCollapseStatus) {
1826     String expectedContent;
1827     try {
1828       expectedContent = FileUtil.loadFile(new File(verificationFileName));
1829     }
1830     catch (IOException e) {
1831       throw new RuntimeException(e);
1832     }
1833     Assert.assertNotNull(expectedContent);
1834
1835     expectedContent = StringUtil.replace(expectedContent, "\r", "");
1836     final String cleanContent = expectedContent.replaceAll(START_FOLD, "").replaceAll(END_FOLD, "");
1837     if (destinationFileName == null) {
1838       configureByText(FileTypeManager.getInstance().getFileTypeByFileName(verificationFileName), cleanContent);
1839     }
1840     else {
1841       try {
1842         FileUtil.writeToFile(new File(destinationFileName), cleanContent);
1843         configureFromExistingVirtualFile(LocalFileSystem.getInstance().refreshAndFindFileByPath(destinationFileName));
1844       }
1845       catch (IOException e) {
1846         throw new RuntimeException(e);
1847       }
1848     }
1849     final String actual = getFoldingDescription(doCheckCollapseStatus);
1850     Assert.assertEquals(expectedContent, actual);
1851   }
1852
1853   @Override
1854   public void testFoldingWithCollapseStatus(@NotNull final String verificationFileName) {
1855     testFoldingRegions(verificationFileName, null, true);
1856   }
1857
1858   @Override
1859   public void testFoldingWithCollapseStatus(@NotNull final String verificationFileName, @Nullable String destinationFileName) {
1860     testFoldingRegions(verificationFileName, destinationFileName, true);
1861   }
1862
1863   @Override
1864   public void testFolding(@NotNull final String verificationFileName) {
1865     testFoldingRegions(verificationFileName, null, false);
1866   }
1867
1868   @Override
1869   public void assertPreferredCompletionItems(final int selected, @NotNull final String... expected) {
1870     final LookupImpl lookup = getLookup();
1871     Assert.assertNotNull("No lookup is shown", lookup);
1872
1873     final JList list = lookup.getList();
1874     List<String> strings = getLookupElementStrings();
1875     Assert.assertNotNull(strings);
1876     final List<String> actual = strings.subList(0, Math.min(expected.length, strings.size()));
1877     if (!actual.equals(Arrays.asList(expected))) {
1878       UsefulTestCase.assertOrderedEquals(DumpLookupElementWeights.getLookupElementWeights(lookup, false), expected);
1879     }
1880     if (selected != list.getSelectedIndex()) {
1881       System.out.println(DumpLookupElementWeights.getLookupElementWeights(lookup, false));
1882     }
1883     Assert.assertEquals(selected, list.getSelectedIndex());
1884   }
1885
1886   @Override
1887   public void testStructureView(@NotNull Consumer<StructureViewComponent> consumer) {
1888     Assert.assertNotNull("configure first", myFile);
1889
1890     final FileEditor fileEditor = FileEditorManager.getInstance(getProject()).getSelectedEditor(myFile);
1891     Assert.assertNotNull("editor not opened for " + myFile, myFile);
1892
1893     final StructureViewBuilder builder = LanguageStructureViewBuilder.INSTANCE.getStructureViewBuilder(getFile());
1894     Assert.assertNotNull("no builder for " + myFile, myFile);
1895
1896     StructureViewComponent component = null;
1897     try {
1898       component = (StructureViewComponent)builder.createStructureView(fileEditor, myProjectFixture.getProject());
1899       consumer.consume(component);
1900     }
1901     finally {
1902       if (component != null) Disposer.dispose(component);
1903     }
1904   }
1905
1906   @Override
1907   public void setCaresAboutInjection(boolean caresAboutInjection) {
1908     myCaresAboutInjection = caresAboutInjection;
1909   }
1910
1911   @Override
1912   public LookupImpl getLookup() {
1913     return (LookupImpl)LookupManager.getActiveLookup(myEditor);
1914   }
1915
1916   protected void bringRealEditorBack() {
1917     PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
1918     if (myEditor instanceof EditorWindow) {
1919       Document document = ((DocumentWindow)myEditor.getDocument()).getDelegate();
1920       myFile = FileDocumentManager.getInstance().getFile(document);
1921       myEditor = ((EditorWindow)myEditor).getDelegate();
1922     }
1923   }
1924
1925   private static class SelectionAndCaretMarkupLoader {
1926     private final String filePath;
1927     private final String newFileText;
1928     private final EditorTestUtil.CaretAndSelectionState caretState;
1929
1930     private SelectionAndCaretMarkupLoader(@NotNull String fileText, String filePath) {
1931       this.filePath = filePath;
1932       final Document document = EditorFactory.getInstance().createDocument(fileText);
1933       caretState = EditorTestUtil.extractCaretAndSelectionMarkers(document);
1934       newFileText = document.getText();
1935     }
1936
1937     @NotNull
1938     private static SelectionAndCaretMarkupLoader fromFile(@NotNull String path, String charset) throws IOException {
1939       return new SelectionAndCaretMarkupLoader(StringUtil.convertLineSeparators(FileUtil.loadFile(new File(path), charset)), path);
1940     }
1941
1942     @NotNull
1943     static SelectionAndCaretMarkupLoader fromFile(@NotNull VirtualFile file) {
1944       final String text;
1945       try {
1946         text = VfsUtilCore.loadText(file);
1947       }
1948       catch (IOException e) {
1949         throw new RuntimeException(e);
1950       }
1951       return new SelectionAndCaretMarkupLoader(StringUtil.convertLineSeparators(text), file.getPath());
1952     }
1953
1954     @NotNull
1955     static SelectionAndCaretMarkupLoader fromText(@NotNull String text) {
1956       return new SelectionAndCaretMarkupLoader(text, null);
1957     }
1958   }
1959
1960   private static class Border implements Comparable<Border> {
1961     private static final boolean LEFT = true;
1962     private static final boolean RIGHT = false;
1963     private final boolean mySide;
1964     private final int myOffset;
1965     private final String myText;
1966     private final boolean myIsExpanded;
1967
1968     private Border(boolean side, int offset, String text, boolean isExpanded) {
1969       mySide = side;
1970       myOffset = offset;
1971       myText = text;
1972       myIsExpanded = isExpanded;
1973     }
1974
1975     public boolean isExpanded() {
1976       return myIsExpanded;
1977     }
1978
1979     public boolean isSide() {
1980       return mySide;
1981     }
1982
1983     public int getOffset() {
1984       return myOffset;
1985     }
1986
1987     public String getText() {
1988       return myText;
1989     }
1990
1991     @Override
1992     public int compareTo(@NotNull Border o) {
1993       return getOffset() < o.getOffset() ? 1 : -1;
1994     }
1995   }
1996 }