notifications: Only propagate ACTIVATE events to HyperlinkListener
[idea/community.git] / java / testFramework / src / com / intellij / codeInsight / daemon / quickFix / LightQuickFixTestCase.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.codeInsight.daemon.quickFix;
17
18 import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
19 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
20 import com.intellij.codeInsight.intention.IntentionAction;
21 import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
22 import com.intellij.openapi.application.WriteAction;
23 import com.intellij.openapi.command.CommandProcessor;
24 import com.intellij.openapi.editor.Editor;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.util.io.FileUtil;
27 import com.intellij.openapi.util.text.StringUtil;
28 import com.intellij.openapi.vcs.readOnlyHandler.ReadonlyStatusHandlerImpl;
29 import com.intellij.openapi.vfs.CharsetToolkit;
30 import com.intellij.openapi.vfs.ReadonlyStatusHandler;
31 import com.intellij.psi.PsiFile;
32 import com.intellij.rt.execution.junit.FileComparisonFailure;
33 import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
34 import com.intellij.testFramework.LightPlatformTestCase;
35 import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
36 import com.intellij.util.IncorrectOperationException;
37 import com.intellij.util.ObjectUtils;
38 import com.intellij.util.io.ReadOnlyAttributeUtil;
39 import com.intellij.util.ui.UIUtil;
40 import org.jetbrains.annotations.NonNls;
41 import org.jetbrains.annotations.NotNull;
42
43 import java.io.File;
44 import java.io.IOException;
45 import java.io.UncheckedIOException;
46 import java.util.List;
47
48 public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase {
49   @NonNls protected static final String BEFORE_PREFIX = "before";
50   @NonNls protected static final String AFTER_PREFIX = "after";
51
52   private static QuickFixTestCase myWrapper;
53
54   protected boolean shouldBeAvailableAfterExecution() {
55     return false;
56   }
57
58   @NotNull
59   protected ActionHint parseActionHintImpl(@NotNull PsiFile file, @NotNull String contents) {
60     return ActionHint.parse(file, contents);
61   }
62
63   private static void doTestFor(@NotNull String testName, @NotNull QuickFixTestCase quickFixTestCase) {
64     final String relativePath = ObjectUtils.notNull(quickFixTestCase.getBasePath(), "") + "/" + BEFORE_PREFIX + testName;
65     final String testFullPath = quickFixTestCase.getTestDataPath().replace(File.separatorChar, '/') + relativePath;
66     final File testFile = new File(testFullPath);
67     CommandProcessor.getInstance().executeCommand(quickFixTestCase.getProject(), () -> {
68       try {
69         String contents = StringUtil.convertLineSeparators(FileUtil.loadFile(testFile, CharsetToolkit.UTF8_CHARSET));
70         quickFixTestCase.configureFromFileText(testFile.getName(), contents);
71         quickFixTestCase.bringRealEditorBack();
72         final ActionHint actionHint = quickFixTestCase.parseActionHintImpl(quickFixTestCase.getFile(), contents);
73
74         quickFixTestCase.beforeActionStarted(testName, contents);
75
76         try {
77           myWrapper = quickFixTestCase;
78           quickFixTestCase.doAction(actionHint, testFullPath, testName);
79         }
80         finally {
81           myWrapper = null;
82           quickFixTestCase.afterActionCompleted(testName, contents);
83         }
84       }
85       catch (FileComparisonFailure e){
86         throw e;
87       }
88       catch (Throwable e) {
89         e.printStackTrace();
90         fail(testName);
91       }
92     }, "", "");
93   }
94
95   protected void afterActionCompleted(final String testName, final String contents) {
96   }
97
98   protected void beforeActionStarted(final String testName, final String contents) {
99   }
100
101   public static void doAction(@NotNull ActionHint actionHint,
102                               String testFullPath,
103                               String testName,
104                               QuickFixTestCase quickFix) throws Exception {
105     IntentionAction action = actionHint.findAndCheck(quickFix.getAvailableActions(),
106                                                      () -> "Test: "+testFullPath+"\nInfos: "+quickFix.doHighlighting());
107     if (action != null) {
108       String text = action.getText();
109       quickFix.invoke(action);
110       UIUtil.dispatchAllInvocationEvents();
111       UIUtil.dispatchAllInvocationEvents();
112       if (!quickFix.shouldBeAvailableAfterExecution()) {
113         final IntentionAction afterAction = quickFix.findActionWithText(text);
114         if (afterAction != null) {
115           fail("Action '" + text + "' is still available after its invocation in test " + testFullPath);
116         }
117       }
118       String expectedFilePath = ObjectUtils.notNull(quickFix.getBasePath(), "") + "/" + AFTER_PREFIX + testName;
119       quickFix.checkResultByFile("In file :" + expectedFilePath, expectedFilePath, false);
120     }
121   }
122
123   protected void doAction(@NotNull ActionHint actionHint, final String testFullPath, final String testName)
124     throws Exception {
125     doAction(actionHint, testFullPath, testName, myWrapper);
126   }
127
128   protected void doAction(@NotNull String actionName) {
129     final List<IntentionAction> available = getAvailableActions();
130     final IntentionAction action = findActionWithText(available, actionName);
131     assertNotNull("Action '" + actionName + "' not found among " + available, action);
132     invoke(action);
133   }
134
135   protected static void invoke(@NotNull IntentionAction action) throws IncorrectOperationException {
136     PsiFile file = getFile();
137     WriteAction.run(() -> {
138       try {
139         // Test that action will automatically clear the read-only attribute if modification is necessary.
140         // If your test fails due to this, make sure that your quick-fix/intention has the following line:
141         // if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
142         ReadOnlyAttributeUtil.setReadOnlyAttribute(file.getVirtualFile(), true);
143       }
144       catch (IOException e) {
145         throw new UncheckedIOException(e);
146       }
147     });
148     ReadonlyStatusHandlerImpl handler = (ReadonlyStatusHandlerImpl)ReadonlyStatusHandler.getInstance(file.getProject());
149     handler.setClearReadOnlyInTests(true);
150     try {
151       ShowIntentionActionsHandler.chooseActionAndInvoke(file, getEditor(), action, action.getText());
152       UIUtil.dispatchAllInvocationEvents();
153     }
154     finally {
155       handler.setClearReadOnlyInTests(false);
156     }
157   }
158
159   protected IntentionAction findActionAndCheck(@NotNull ActionHint hint, String testFullPath) {
160     return hint.findAndCheck(getAvailableActions(), () -> "Test: "+testFullPath);
161   }
162
163   protected IntentionAction findActionWithText(@NotNull String text) {
164     return findActionWithText(getAvailableActions(), text);
165   }
166
167   public static IntentionAction findActionWithText(@NotNull List<IntentionAction> actions, @NotNull String text) {
168     for (IntentionAction action : actions) {
169       if (text.equals(action.getText())) {
170         return action;
171       }
172     }
173     return null;
174   }
175
176   /**
177    * @deprecated use {@link LightQuickFixParameterizedTestCase}
178    * to get separate tests for all data files in testData directory.
179    */
180   protected void doAllTests() {
181     doAllTests(createWrapper());
182   }
183
184   public static void doAllTests(QuickFixTestCase testCase) {
185     final File[] files = getBeforeTestFiles(testCase);
186
187     for (File file : files) {
188       final String testName = file.getName().substring(BEFORE_PREFIX.length());
189       doTestFor(testName, testCase);
190     }
191   }
192
193   @NotNull
194   public static File[] getBeforeTestFiles(@NotNull QuickFixTestCase testCase) {
195     assertNotNull("getBasePath() should not return null!", testCase.getBasePath());
196
197     final String testDirPath = testCase.getTestDataPath().replace(File.separatorChar, '/') + testCase.getBasePath();
198     File testDir = new File(testDirPath);
199     final File[] files = testDir.listFiles((dir, name) -> name.startsWith(BEFORE_PREFIX));
200
201     if (files == null || files.length == 0) {
202       fail("Test files not found in " + testDirPath);
203     }
204     return files;
205   }
206
207   protected void doSingleTest(@NotNull String fileSuffix) {
208     doTestFor(fileSuffix, createWrapper());
209   }
210
211   protected void doSingleTest(String fileSuffix, String testDataPath) {
212     doTestFor(fileSuffix, createWrapper(testDataPath));
213   }
214
215   @NotNull
216   protected QuickFixTestCase createWrapper() {
217     return createWrapper(null);
218   }
219
220   @NotNull
221   protected QuickFixTestCase createWrapper(final String testDataPath) {
222     return new QuickFixTestCase() {
223       public String myTestDataPath = testDataPath;
224
225       @Override
226       public String getBasePath() {
227         return LightQuickFixTestCase.this.getBasePath();
228       }
229
230       @NotNull
231       @Override
232       public String getTestDataPath() {
233         if (myTestDataPath == null) {
234           myTestDataPath = LightQuickFixTestCase.this.getTestDataPath();
235         }
236         return myTestDataPath;
237       }
238
239       @NotNull
240       @Override
241       public ActionHint parseActionHintImpl(@NotNull PsiFile file, @NotNull String contents) {
242         return LightQuickFixTestCase.this.parseActionHintImpl(file, contents);
243       }
244
245       @Override
246       public void beforeActionStarted(@NotNull String testName, @NotNull String contents) {
247         LightQuickFixTestCase.this.beforeActionStarted(testName, contents);
248       }
249
250       @Override
251       public void afterActionCompleted(@NotNull String testName, @NotNull String contents) {
252         LightQuickFixTestCase.this.afterActionCompleted(testName, contents);
253       }
254
255       @Override
256       public void doAction(@NotNull ActionHint actionHint, @NotNull String testFullPath, @NotNull String testName) throws Exception {
257         LightQuickFixTestCase.this.doAction(actionHint, testFullPath, testName);
258       }
259
260       @Override
261       public void checkResultByFile(@NotNull String message, @NotNull String expectedFilePath, boolean ignoreTrailingSpaces) throws Exception {
262         LightQuickFixTestCase.this.checkResultByFile(message, expectedFilePath, ignoreTrailingSpaces);
263       }
264
265       @Override
266       public IntentionAction findActionWithText(@NotNull String text) {
267         return LightQuickFixTestCase.this.findActionWithText(text);
268       }
269
270       @Override
271       public boolean shouldBeAvailableAfterExecution() {
272         return LightQuickFixTestCase.this.shouldBeAvailableAfterExecution();
273       }
274
275       @Override
276       public void invoke(@NotNull IntentionAction action) {
277         LightQuickFixTestCase.invoke(action);
278       }
279
280       @NotNull
281       @Override
282       public List<HighlightInfo> doHighlighting() {
283         return LightQuickFixTestCase.this.doHighlighting();
284       }
285
286       @NotNull
287       @Override
288       public List<IntentionAction> getAvailableActions() {
289         return LightQuickFixTestCase.this.getAvailableActions();
290       }
291
292       @Override
293       public void configureFromFileText(@NotNull String name, @NotNull String contents) throws IOException {
294         LightPlatformCodeInsightTestCase.configureFromFileText(name, contents, true);
295       }
296
297       @Override
298       public PsiFile getFile() {
299         return LightPlatformCodeInsightTestCase.getFile();
300       }
301
302       @Override
303       public Project getProject() {
304         return LightPlatformTestCase.getProject();
305       }
306
307       @Override
308       public void bringRealEditorBack() {
309         LightPlatformCodeInsightTestCase.bringRealEditorBack();
310       }
311     };
312   }
313
314   protected List<IntentionAction> getAvailableActions() {
315     doHighlighting();
316     return getAvailableActions(getEditor(), getFile());
317   }
318
319   @NotNull
320   public static List<IntentionAction> getAvailableActions(@NotNull Editor editor, @NotNull PsiFile file) {
321     return CodeInsightTestFixtureImpl.getAvailableIntentions(editor, file);
322   }
323
324   @NonNls protected String getBasePath() {return null;}
325 }