2 * Copyright 2000-2015 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.jetbrains.python.refactoring;
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;
34 import java.io.IOException;
37 * @author Mikhail Golubev
39 public class PyMakeFunctionTopLevelTest extends PyTestCase {
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");
49 private void doTestSuccess() {
53 private void doTestFailure(@NotNull String message) {
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);
63 final VirtualFile srcRoot = ModuleRootManager.getInstance(myFixture.getModule()).getSourceRoots()[0];
64 destination = FileUtil.join(srcRoot.getPath(), destination);
66 assertNotNull(destination);
67 final String finalDestination = destination;
69 WriteCommandAction.runWriteCommandAction(myFixture.getProject(), new Runnable() {
72 if (function.getContainingClass() != null) {
73 new PyMakeMethodTopLevelProcessor(function, finalDestination).run();
76 new PyMakeLocalFunctionTopLevelProcessor(function, finalDestination).run();
81 catch (IncorrectOperationException e) {
82 if (errorMessage == null) {
83 fail("Refactoring failed unexpectedly with message: " + e.getMessage());
85 assertEquals(errorMessage, e.getMessage());
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);
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();
108 public void testLocalFunctionSimple() {
113 //public void testRefactoringAvailability() {
114 // myFixture.configureByFile(getTestName(true) + ".py");
116 // final PsiFile file = myFixture.getFile();
117 // moveByText("func");
118 // assertFalse(isActionEnabled());
119 // moveByText("local");
120 // assertTrue(isActionEnabled());
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());
129 // moveByText("method");
130 // assertTrue(isActionEnabled());
132 // moveByText("static_method");
133 // assertFalse(isActionEnabled());
134 // moveByText("class_method");
135 // assertFalse(isActionEnabled());
137 // // Overridden method
138 // moveByText("overridden_method");
139 // assertFalse(isActionEnabled());
141 // // Overriding method
142 // moveByText("upper");
143 // assertFalse(isActionEnabled());
145 // moveByText("property");
146 // assertFalse(isActionEnabled());
147 // moveByText("__magic__");
148 // assertFalse(isActionEnabled());
152 public void testLocalFunctionNonlocalReferenceToOuterScope() {
153 runWithLanguageLevel(LanguageLevel.PYTHON30,
154 () -> doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.nonlocal.writes")));
158 public void testLocalFunctionNonlocalReferencesInInnerFunction() {
159 runWithLanguageLevel(LanguageLevel.PYTHON30, () -> doTestSuccess());
163 public void testLocalFunctionReferenceToSelf() {
164 doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.self.reads"));
167 public void testMethodNonlocalReferenceToOuterScope() {
168 runWithLanguageLevel(LanguageLevel.PYTHON30,
169 () -> doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.nonlocal.writes")));
172 public void testMethodOuterScopeReads() {
173 doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.outer.scope.reads"));
176 public void testMethodOtherMethodCalls() {
177 doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.method.calls"));
180 public void testMethodAttributeWrites() {
181 doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.attribute.writes"));
184 public void testMethodReadPrivateAttributes() {
185 doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.private.attributes"));
188 public void testMethodSelfUsedAsOperand() {
189 doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.special.usage.of.self"));
192 public void testMethodOverriddenSelf() {
193 doTestFailure(PyBundle.message("refactoring.make.function.top.level.error.special.usage.of.self"));
196 public void testMethodSingleAttributeRead() {
200 public void testMethodMultipleAttributesReadReferenceQualifier() {
204 public void testMethodMultipleAttributesConstructorQualifier() {
208 public void testMethodImportUpdates() throws IOException {
209 doMultiFileTest(null, null);
212 public void testMethodMoveToOtherFile() throws IOException {
213 doMultiFileTest("util.py", null);
216 public void testMethodCalledViaClass() {
220 public void testMethodUniqueNameOfExtractedQualifier() {
224 public void testMethodUniqueParamNames() {
228 public void testRecursiveMethod() {
232 public void testRecursiveLocalFunction() {
236 public void testMethodNoNewParams() {
241 protected String getTestDataPath() {
242 return super.getTestDataPath() + "/refactoring/makeFunctionTopLevel/";