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