Merge branch 'db/javac-ast'
[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(final String testName, final 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(String fileSuffix) {
208     doTestFor(fileSuffix, createWrapper());
209   }
210
211   protected void doSingleTest(String fileSuffix, String testDataPath) {
212     doTestFor(fileSuffix, createWrapper(testDataPath));
213   }
214
215   protected QuickFixTestCase createWrapper() {
216     return createWrapper(null);
217   }
218
219   protected QuickFixTestCase createWrapper(final String testDataPath) {
220     return new QuickFixTestCase() {
221       public String myTestDataPath = testDataPath;
222
223       @Override
224       public String getBasePath() {
225         return LightQuickFixTestCase.this.getBasePath();
226       }
227
228       @Override
229       public String getTestDataPath() {
230         if (myTestDataPath == null) {
231           myTestDataPath = LightQuickFixTestCase.this.getTestDataPath();
232         }
233         return myTestDataPath;
234       }
235
236       @NotNull
237       @Override
238       public ActionHint parseActionHintImpl(@NotNull PsiFile file, @NotNull String contents) {
239         return LightQuickFixTestCase.this.parseActionHintImpl(file, contents);
240       }
241
242       @Override
243       public void beforeActionStarted(String testName, String contents) {
244         LightQuickFixTestCase.this.beforeActionStarted(testName, contents);
245       }
246
247       @Override
248       public void afterActionCompleted(String testName, String contents) {
249         LightQuickFixTestCase.this.afterActionCompleted(testName, contents);
250       }
251
252       @Override
253       public void doAction(ActionHint actionHint, String testFullPath, String testName) throws Exception {
254         LightQuickFixTestCase.this.doAction(actionHint, testFullPath, testName);
255       }
256
257       @Override
258       public void checkResultByFile(String s, @NotNull String expectedFilePath, boolean b) throws Exception {
259         LightQuickFixTestCase.this.checkResultByFile(s, expectedFilePath, b);
260       }
261
262       @Override
263       public IntentionAction findActionWithText(String text) {
264         return LightQuickFixTestCase.this.findActionWithText(text);
265       }
266
267       @Override
268       public boolean shouldBeAvailableAfterExecution() {
269         return LightQuickFixTestCase.this.shouldBeAvailableAfterExecution();
270       }
271
272       @Override
273       public void invoke(IntentionAction action) {
274         LightQuickFixTestCase.invoke(action);
275       }
276
277       @NotNull
278       @Override
279       public List<HighlightInfo> doHighlighting() {
280         return LightQuickFixTestCase.this.doHighlighting();
281       }
282
283       @NotNull
284       @Override
285       public List<IntentionAction> getAvailableActions() {
286         return LightQuickFixTestCase.this.getAvailableActions();
287       }
288
289       @Override
290       public void configureFromFileText(String name, String contents) throws IOException {
291         LightPlatformCodeInsightTestCase.configureFromFileText(name, contents, true);
292       }
293
294       @Override
295       public PsiFile getFile() {
296         return LightPlatformCodeInsightTestCase.getFile();
297       }
298
299       @Override
300       public Project getProject() {
301         return LightPlatformTestCase.getProject();
302       }
303
304       @Override
305       public void bringRealEditorBack() {
306         LightPlatformCodeInsightTestCase.bringRealEditorBack();
307       }
308     };
309   }
310
311   protected List<IntentionAction> getAvailableActions() {
312     doHighlighting();
313     return getAvailableActions(getEditor(), getFile());
314   }
315
316   public static List<IntentionAction> getAvailableActions(@NotNull Editor editor, @NotNull PsiFile file) {
317     return CodeInsightTestFixtureImpl.getAvailableIntentions(editor, file);
318   }
319
320   @NonNls protected String getBasePath() {return null;}
321 }