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