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