cleanup
[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   private static void doTestFor(@NotNull String testName, @NotNull QuickFixTestCase quickFixTestCase) {
59     final String relativePath = ObjectUtils.notNull(quickFixTestCase.getBasePath(), "") + "/" + BEFORE_PREFIX + testName;
60     final String testFullPath = quickFixTestCase.getTestDataPath().replace(File.separatorChar, '/') + relativePath;
61     final File testFile = new File(testFullPath);
62     CommandProcessor.getInstance().executeCommand(quickFixTestCase.getProject(), () -> {
63       try {
64         String contents = StringUtil.convertLineSeparators(FileUtil.loadFile(testFile, CharsetToolkit.UTF8_CHARSET));
65         quickFixTestCase.configureFromFileText(testFile.getName(), contents);
66         quickFixTestCase.bringRealEditorBack();
67         final ActionHint actionHint = quickFixTestCase.parseActionHintImpl(quickFixTestCase.getFile(), contents);
68
69         quickFixTestCase.beforeActionStarted(testName, contents);
70
71         try {
72           myWrapper = quickFixTestCase;
73           quickFixTestCase.doAction(actionHint, testFullPath, testName);
74         }
75         finally {
76           myWrapper = null;
77           quickFixTestCase.afterActionCompleted(testName, contents);
78         }
79       }
80       catch (FileComparisonFailure e){
81         throw e;
82       }
83       catch (Throwable e) {
84         e.printStackTrace();
85         fail(testName);
86       }
87     }, "", "");
88   }
89
90   protected void afterActionCompleted(final String testName, final String contents) {
91   }
92
93   protected void beforeActionStarted(final String testName, final String contents) {
94   }
95
96   public static void doAction(@NotNull ActionHint actionHint,
97                               String testFullPath,
98                               String testName,
99                               QuickFixTestCase quickFix) throws Exception {
100     IntentionAction action = actionHint.findAndCheck(quickFix.getAvailableActions(),
101                                                      () -> "Test: "+testFullPath+"\nInfos: "+quickFix.doHighlighting());
102     if (action != null) {
103       String text = action.getText();
104       quickFix.invoke(action);
105       UIUtil.dispatchAllInvocationEvents();
106       UIUtil.dispatchAllInvocationEvents();
107       if (!quickFix.shouldBeAvailableAfterExecution()) {
108         final IntentionAction afterAction = quickFix.findActionWithText(text);
109         if (afterAction != null) {
110           fail("Action '" + text + "' is still available after its invocation in test " + testFullPath);
111         }
112       }
113       String expectedFilePath = ObjectUtils.notNull(quickFix.getBasePath(), "") + "/" + AFTER_PREFIX + testName;
114       quickFix.checkResultByFile("In file :" + expectedFilePath, expectedFilePath, false);
115     }
116   }
117
118   protected void doAction(@NotNull ActionHint actionHint, final String testFullPath, final String testName)
119     throws Exception {
120     doAction(actionHint, testFullPath, testName, myWrapper);
121   }
122
123   protected void doAction(@NotNull String actionName) {
124     final List<IntentionAction> available = getAvailableActions();
125     final IntentionAction action = findActionWithText(available, actionName);
126     assertNotNull("Action '" + actionName + "' not found among " + available, action);
127     invoke(action);
128   }
129
130   protected static void invoke(@NotNull IntentionAction action) throws IncorrectOperationException {
131     PsiFile file = getFile();
132     WriteAction.run(() -> {
133       try {
134         // Test that action will automatically clear the read-only attribute if modification is necessary.
135         // If your test fails due to this, make sure that your quick-fix/intention has the following line:
136         // if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
137         ReadOnlyAttributeUtil.setReadOnlyAttribute(file.getVirtualFile(), true);
138       }
139       catch (IOException e) {
140         throw new UncheckedIOException(e);
141       }
142     });
143     ReadonlyStatusHandlerImpl handler = (ReadonlyStatusHandlerImpl)ReadonlyStatusHandler.getInstance(file.getProject());
144     handler.setClearReadOnlyInTests(true);
145     try {
146       ShowIntentionActionsHandler.chooseActionAndInvoke(file, getEditor(), action, action.getText());
147       UIUtil.dispatchAllInvocationEvents();
148     }
149     finally {
150       handler.setClearReadOnlyInTests(false);
151     }
152   }
153
154   protected IntentionAction findActionAndCheck(@NotNull ActionHint hint, String testFullPath) {
155     return hint.findAndCheck(getAvailableActions(), () -> "Test: "+testFullPath);
156   }
157
158   protected IntentionAction findActionWithText(@NotNull String text) {
159     return findActionWithText(getAvailableActions(), text);
160   }
161
162   public static IntentionAction findActionWithText(@NotNull List<IntentionAction> actions, @NotNull String text) {
163     for (IntentionAction action : actions) {
164       if (text.equals(action.getText())) {
165         return action;
166       }
167     }
168     return null;
169   }
170
171   /**
172    * @deprecated use {@link LightQuickFixParameterizedTestCase}
173    * to get separate tests for all data files in testData directory.
174    */
175   protected void doAllTests() {
176     doAllTests(createWrapper());
177   }
178
179   public static void doAllTests(QuickFixTestCase testCase) {
180     final File[] files = getBeforeTestFiles(testCase);
181
182     for (File file : files) {
183       final String testName = file.getName().substring(BEFORE_PREFIX.length());
184       doTestFor(testName, testCase);
185     }
186   }
187
188   @NotNull
189   public static File[] getBeforeTestFiles(@NotNull QuickFixTestCase testCase) {
190     assertNotNull("getBasePath() should not return null!", testCase.getBasePath());
191
192     final String testDirPath = testCase.getTestDataPath().replace(File.separatorChar, '/') + testCase.getBasePath();
193     File testDir = new File(testDirPath);
194     final File[] files = testDir.listFiles((dir, name) -> name.startsWith(BEFORE_PREFIX));
195
196     if (files == null || files.length == 0) {
197       fail("Test files not found in " + testDirPath);
198     }
199     return files;
200   }
201
202   protected void doSingleTest(@NotNull String fileSuffix) {
203     doTestFor(fileSuffix, createWrapper());
204   }
205
206   protected void doSingleTest(String fileSuffix, String testDataPath) {
207     doTestFor(fileSuffix, createWrapper(testDataPath));
208   }
209
210   @NotNull
211   protected QuickFixTestCase createWrapper() {
212     return createWrapper(null);
213   }
214
215   @NotNull
216   protected QuickFixTestCase createWrapper(final String testDataPath) {
217     return new QuickFixTestCase() {
218       public String myTestDataPath = testDataPath;
219
220       @Override
221       public String getBasePath() {
222         return LightQuickFixTestCase.this.getBasePath();
223       }
224
225       @NotNull
226       @Override
227       public String getTestDataPath() {
228         if (myTestDataPath == null) {
229           myTestDataPath = LightQuickFixTestCase.this.getTestDataPath();
230         }
231         return myTestDataPath;
232       }
233
234       @NotNull
235       @Override
236       public ActionHint parseActionHintImpl(@NotNull PsiFile file, @NotNull String contents) {
237         return ActionHint.parse(file, contents);
238       }
239
240       @Override
241       public void beforeActionStarted(@NotNull String testName, @NotNull String contents) {
242         LightQuickFixTestCase.this.beforeActionStarted(testName, contents);
243       }
244
245       @Override
246       public void afterActionCompleted(@NotNull String testName, @NotNull String contents) {
247         LightQuickFixTestCase.this.afterActionCompleted(testName, contents);
248       }
249
250       @Override
251       public void doAction(@NotNull ActionHint actionHint, @NotNull String testFullPath, @NotNull String testName) throws Exception {
252         LightQuickFixTestCase.this.doAction(actionHint, testFullPath, testName);
253       }
254
255       @Override
256       public void checkResultByFile(@NotNull String message, @NotNull String expectedFilePath, boolean ignoreTrailingSpaces) throws Exception {
257         LightQuickFixTestCase.this.checkResultByFile(message, expectedFilePath, ignoreTrailingSpaces);
258       }
259
260       @Override
261       public IntentionAction findActionWithText(@NotNull String text) {
262         return LightQuickFixTestCase.this.findActionWithText(text);
263       }
264
265       @Override
266       public boolean shouldBeAvailableAfterExecution() {
267         return LightQuickFixTestCase.this.shouldBeAvailableAfterExecution();
268       }
269
270       @Override
271       public void invoke(@NotNull IntentionAction action) {
272         LightQuickFixTestCase.invoke(action);
273       }
274
275       @NotNull
276       @Override
277       public List<HighlightInfo> doHighlighting() {
278         return LightQuickFixTestCase.this.doHighlighting();
279       }
280
281       @NotNull
282       @Override
283       public List<IntentionAction> getAvailableActions() {
284         return LightQuickFixTestCase.this.getAvailableActions();
285       }
286
287       @Override
288       public void configureFromFileText(@NotNull String name, @NotNull String contents) throws IOException {
289         LightPlatformCodeInsightTestCase.configureFromFileText(name, contents, true);
290       }
291
292       @Override
293       public PsiFile getFile() {
294         return LightPlatformCodeInsightTestCase.getFile();
295       }
296
297       @Override
298       public Project getProject() {
299         return LightPlatformTestCase.getProject();
300       }
301
302       @Override
303       public void bringRealEditorBack() {
304         LightPlatformCodeInsightTestCase.bringRealEditorBack();
305       }
306     };
307   }
308
309   protected List<IntentionAction> getAvailableActions() {
310     doHighlighting();
311     return getAvailableActions(getEditor(), getFile());
312   }
313
314   @NotNull
315   public static List<IntentionAction> getAvailableActions(@NotNull Editor editor, @NotNull PsiFile file) {
316     return CodeInsightTestFixtureImpl.getAvailableIntentions(editor, file);
317   }
318
319   @NonNls protected String getBasePath() {return null;}
320 }