711cf04a67516b90e2881dff793512ad8260058e
[idea/community.git] / python / testSrc / com / jetbrains / python / refactoring / PyMakeFunctionTopLevelTest.java
1 /*
2  * Copyright 2000-2015 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.jetbrains.python.refactoring;
17
18 import com.intellij.openapi.command.WriteCommandAction;
19 import com.intellij.openapi.roots.ModuleRootManager;
20 import com.intellij.openapi.util.io.FileUtil;
21 import com.intellij.openapi.vfs.VirtualFile;
22 import com.intellij.testFramework.PlatformTestUtil;
23 import com.intellij.util.IncorrectOperationException;
24 import com.jetbrains.python.PyBundle;
25 import com.jetbrains.python.fixtures.PyTestCase;
26 import com.jetbrains.python.psi.LanguageLevel;
27 import com.jetbrains.python.psi.PyFunction;
28 import com.jetbrains.python.psi.impl.PyPsiUtils;
29 import com.jetbrains.python.refactoring.makeFunctionTopLevel.PyMakeLocalFunctionTopLevelProcessor;
30 import com.jetbrains.python.refactoring.makeFunctionTopLevel.PyMakeMethodTopLevelProcessor;
31 import org.jetbrains.annotations.NotNull;
32 import org.jetbrains.annotations.Nullable;
33
34 import java.io.IOException;
35
36 /**
37  * @author Mikhail Golubev
38  */
39 public class PyMakeFunctionTopLevelTest extends PyTestCase {
40
41   public void doTest(@Nullable String errorMessage) {
42     myFixture.configureByFile(getTestName(true) + ".py");
43     runRefactoring(null, errorMessage);
44     if (errorMessage == null) {
45       myFixture.checkResultByFile(getTestName(true) + ".after.py");
46     }
47   }
48
49   private void doTestSuccess() {
50     doTest(null);
51   }
52
53   private void doTestFailure(@NotNull String message) {
54     doTest(message);
55   }
56
57   private void runRefactoring(@Nullable String destination, @Nullable String errorMessage) {
58     final PyFunction function = assertInstanceOf(myFixture.getElementAtCaret(), PyFunction.class);
59     if (destination == null) {
60       destination = PyPsiUtils.getContainingFilePath(function);
61     }
62     else {
63       final VirtualFile srcRoot = ModuleRootManager.getInstance(myFixture.getModule()).getSourceRoots()[0];
64       destination = FileUtil.join(srcRoot.getPath(), destination);
65     }
66     assertNotNull(destination);
67     final String finalDestination = destination;
68     try {
69       WriteCommandAction.runWriteCommandAction(myFixture.getProject(), new Runnable() {
70         @Override
71         public void run() {
72           if (function.getContainingClass() != null) {
73             new PyMakeMethodTopLevelProcessor(function, finalDestination).run();
74           }
75           else {
76             new PyMakeLocalFunctionTopLevelProcessor(function, finalDestination).run();
77           }
78         }
79       });
80     }
81     catch (IncorrectOperationException e) {
82       if (errorMessage == null) {
83         fail("Refactoring failed unexpectedly with message: " + e.getMessage());
84       }
85       assertEquals(errorMessage, e.getMessage());
86     }
87   }
88
89   private void doMultiFileTest(@Nullable String destination, @Nullable String errorMessage) throws IOException {
90     final String rootBeforePath = getTestName(true) + "/before";
91     final String rootAfterPath = getTestName(true) + "/after";
92     final VirtualFile copiedDirectory = myFixture.copyDirectoryToProject(rootBeforePath, "");
93     myFixture.configureByFile("main.py");
94     runRefactoring(destination, errorMessage);
95     if (errorMessage == null) {
96       PlatformTestUtil.assertDirectoriesEqual(getVirtualFileByName(getTestDataPath() + rootAfterPath), copiedDirectory);
97     }
98   }
99
100   //private static boolean isActionEnabled() {
101   //  final PyMakeFunctionTopLevelRefactoring action = new PyMakeFunctionTopLevelRefactoring();
102   //  final TestActionEvent event = new TestActionEvent(action);
103   //  action.beforeActionPerformedUpdate(event);
104   //  return event.getPresentation().isEnabled();
105   //}
106
107   // PY-6637
108   public void testLocalFunctionSimple() {
109     doTestSuccess();
110   }
111
112   // PY-6637
113   //public void testRefactoringAvailability() {
114   //  myFixture.configureByFile(getTestName(true) + ".py");
115   //
116   //  final PsiFile file = myFixture.getFile();
117   //  moveByText("func");
118   //  assertFalse(isActionEnabled());
119   //  moveByText("local");
120   //  assertTrue(isActionEnabled());
121   //
122   //  // move to "def" keyword
123   //  myFixture.getEditor().getCaretModel().moveCaretRelatively(-3, 0, false, false, false);
124   //  final PsiElement tokenAtCaret = file.findElementAt(myFixture.getCaretOffset());
125   //  assertNotNull(tokenAtCaret);
126   //  assertEquals(tokenAtCaret.getNode().getElementType(), PyTokenTypes.DEF_KEYWORD);
127   //  assertTrue(isActionEnabled());
128   //
129   //  moveByText("method");
130   //  assertTrue(isActionEnabled());
131   //
132   //  moveByText("static_method");
133   //  assertFalse(isActionEnabled());
134   //  moveByText("class_method");
135   //  assertFalse(isActionEnabled());
136   //
137   //  // Overridden method
138   //  moveByText("overridden_method");
139   //  assertFalse(isActionEnabled());
140   //
141   //  // Overriding method
142   //  moveByText("upper");
143   //  assertFalse(isActionEnabled());
144   //
145   //  moveByText("property");
146   //  assertFalse(isActionEnabled());
147   //  moveByText("__magic__");
148   //  assertFalse(isActionEnabled());
149   //}
150
151   // PY-6637
152   public void testLocalFunctionNonlocalReferenceToOuterScope() {
153     runWithLanguageLevel(LanguageLevel.PYTHON30,
154                          () -> doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.nonlocal.writes")));
155   }
156
157   // PY-6637
158   public void testLocalFunctionNonlocalReferencesInInnerFunction() {
159     runWithLanguageLevel(LanguageLevel.PYTHON30, () -> doTestSuccess());
160   }
161
162   // PY-6637
163   public void testLocalFunctionReferenceToSelf() {
164     doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.self.reads"));
165   }
166
167   public void testMethodNonlocalReferenceToOuterScope() {
168     runWithLanguageLevel(LanguageLevel.PYTHON30,
169                          () -> doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.nonlocal.writes")));
170   }
171
172   public void testMethodOuterScopeReads() {
173     doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.outer.scope.reads"));
174   }
175
176   public void testMethodOtherMethodCalls() {
177     doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.method.calls"));
178   }
179
180   public void testMethodAttributeWrites() {
181     doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.attribute.writes"));
182   }
183
184   public void testMethodReadPrivateAttributes() {
185     doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.private.attributes"));
186   }
187
188   public void testMethodSelfUsedAsOperand() {
189     doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.special.usage.of.self"));
190   }
191
192   public void testMethodOverriddenSelf() {
193     doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.special.usage.of.self"));
194   }
195
196   public void testMethodSingleAttributeRead() {
197     doTestSuccess();
198   }
199
200   public void testMethodMultipleAttributesReadReferenceQualifier() {
201     doTestSuccess();
202   }
203
204   public void testMethodMultipleAttributesConstructorQualifier() {
205     doTestSuccess();
206   }
207
208   public void testMethodImportUpdates() throws IOException {
209     doMultiFileTest(null, null);
210   }
211
212   public void testMethodMoveToOtherFile() throws IOException {
213     doMultiFileTest("util.py", null);
214   }
215
216   public void testMethodCalledViaClass() {
217     doTestSuccess();
218   }
219
220   public void testMethodUniqueNameOfExtractedQualifier() {
221     doTestSuccess();
222   }
223
224   public void testMethodUniqueParamNames() {
225     doTestSuccess();
226   }
227
228   public void testRecursiveMethod() {
229     doTestSuccess();
230   }
231
232   public void testRecursiveLocalFunction() {
233     doTestSuccess();
234   }
235
236   public void testMethodNoNewParams() {
237     doTestSuccess();
238   }
239
240   @Override
241   protected String getTestDataPath() {
242     return super.getTestDataPath() + "/refactoring/makeFunctionTopLevel/";
243   }
244 }