PY-6637 Add test cases on detection of nonlocal references inside escalated function
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 30 Sep 2015 16:05:40 +0000 (19:05 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Mon, 5 Oct 2015 10:09:02 +0000 (13:09 +0300)
python/src/com/jetbrains/python/refactoring/convertTopLevelFunction/PyConvertLocalFunctionToTopLevelFunctionAction.java
python/testData/refactoring/convertTopLevel/nonlocalReferenceToOuterScope.py [new file with mode: 0644]
python/testData/refactoring/convertTopLevel/nonlocalReferencesInInnerFunction.after.py [new file with mode: 0644]
python/testData/refactoring/convertTopLevel/nonlocalReferencesInInnerFunction.py [new file with mode: 0644]
python/testSrc/com/jetbrains/python/refactoring/PyConvertLocalFunctionToTopLevelFunctionTest.java

index dc3a2966dcc1332318611f57be6cbc2c78870b2b..005a23ae7abaa5703fa4f9f2699c120f277e6ef9 100644 (file)
@@ -17,6 +17,7 @@ package com.jetbrains.python.refactoring.convertTopLevelFunction;
 
 import com.intellij.openapi.actionSystem.CommonDataKeys;
 import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.PsiElement;
@@ -97,6 +98,9 @@ public class PyConvertLocalFunctionToTopLevelFunctionAction extends PyBaseRefact
               new PyMakeFunctionTopLevelProcessor(function, editor).run();
             }
             catch (IncorrectOperationException e) {
+              if (ApplicationManager.getApplication().isUnitTestMode()) {
+                throw e;
+              }
               CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), e.getMessage(), ID, project);
             }
           }
diff --git a/python/testData/refactoring/convertTopLevel/nonlocalReferenceToOuterScope.py b/python/testData/refactoring/convertTopLevel/nonlocalReferenceToOuterScope.py
new file mode 100644 (file)
index 0000000..54b6286
--- /dev/null
@@ -0,0 +1,7 @@
+def func():
+    x = True
+    def loc<caret>al():
+        def nested():
+            nonlocal x
+            x = False
+            
diff --git a/python/testData/refactoring/convertTopLevel/nonlocalReferencesInInnerFunction.after.py b/python/testData/refactoring/convertTopLevel/nonlocalReferencesInInnerFunction.after.py
new file mode 100644 (file)
index 0000000..d19afe6
--- /dev/null
@@ -0,0 +1,9 @@
+def func():
+    pass
+
+
+def local():
+    x = True
+    def nested():
+        nonlocal x
+        x = False
\ No newline at end of file
diff --git a/python/testData/refactoring/convertTopLevel/nonlocalReferencesInInnerFunction.py b/python/testData/refactoring/convertTopLevel/nonlocalReferencesInInnerFunction.py
new file mode 100644 (file)
index 0000000..ca46376
--- /dev/null
@@ -0,0 +1,6 @@
+def func():
+    def lo<caret>cal():
+        x = True
+        def nested():
+            nonlocal x
+            x = False
\ No newline at end of file
index d45e385e6aa74c7539877e3d6ea74bb31506b546..f7cae5d744dabcec6b96b8e4ef13cd9361649c28 100644 (file)
  */
 package com.jetbrains.python.refactoring;
 
+import com.intellij.testFramework.TestActionEvent;
+import com.intellij.util.IncorrectOperationException;
+import com.jetbrains.python.PyBundle;
 import com.jetbrains.python.fixtures.PyTestCase;
+import com.jetbrains.python.psi.LanguageLevel;
 import com.jetbrains.python.refactoring.convertTopLevelFunction.PyConvertLocalFunctionToTopLevelFunctionAction;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * @author Mikhail Golubev
  */
 public class PyConvertLocalFunctionToTopLevelFunctionTest extends PyTestCase {
 
-  public void doTest() {
+  public void doTest(boolean enabled, @Nullable String message) {
     myFixture.configureByFile(getTestName(true) + ".py");
-    myFixture.testAction(new PyConvertLocalFunctionToTopLevelFunctionAction());
-    myFixture.checkResultByFile(getTestName(true) + ".after.py");
+    final PyConvertLocalFunctionToTopLevelFunctionAction action = new PyConvertLocalFunctionToTopLevelFunctionAction();
+    // Similar to com.intellij.testFramework.fixtures.CodeInsightTestFixture.testAction()
+    final TestActionEvent event = new TestActionEvent(action);
+    action.beforeActionPerformedUpdate(event);
+    assertEquals(enabled, event.getPresentation().isEnabledAndVisible());
+    if (enabled) {
+      try {
+        action.actionPerformed(event);
+        myFixture.checkResultByFile(getTestName(true) + ".after.py");
+      }
+      catch (IncorrectOperationException e) {
+        if (message == null) {
+          fail("Refactoring wasn't expected to fail");
+        }
+        assertEquals(message, e.getMessage());
+      }
+    }
+  }
+
+  private void doTest() {
+    doTest(true, null);
+  }
+
+  public boolean isActionEnabled() {
+    final PyConvertLocalFunctionToTopLevelFunctionAction action = new PyConvertLocalFunctionToTopLevelFunctionAction();
+    final TestActionEvent event = new TestActionEvent(action);
+    action.beforeActionPerformedUpdate(event);
+    return event.getPresentation().isEnabled(); 
   }
 
   // PY-6637
@@ -38,9 +69,29 @@ public class PyConvertLocalFunctionToTopLevelFunctionTest extends PyTestCase {
   public void testLocalFunctionDetection() {
     myFixture.configureByFile(getTestName(true) + ".py");
     moveByText("func");
-    assertFalse(myFixture.testAction(new PyConvertLocalFunctionToTopLevelFunctionAction()).isEnabled());
+    assertFalse(isActionEnabled());
     moveByText("local");
-    assertTrue(myFixture.testAction(new PyConvertLocalFunctionToTopLevelFunctionAction()).isEnabled());
+    assertTrue(isActionEnabled());
+  }
+
+  // PY-6637
+  public void testNonlocalReferenceToOuterScope() {
+    runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() {
+      @Override
+      public void run() {
+        doTest(true, PyBundle.message("refactoring.make.method.top.level.error.nonlocal.writes"));
+      }
+    });
+  }
+
+  // PY-6637
+  public void testNonlocalReferencesInInnerFunction() {
+    runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() {
+      @Override
+      public void run() {
+        doTest();
+      }
+    });
   }
 
   @Override