summaryrefslogtreecommitdiff
path: root/python/testSrc/com/jetbrains/env/python
diff options
context:
space:
mode:
Diffstat (limited to 'python/testSrc/com/jetbrains/env/python')
-rw-r--r--python/testSrc/com/jetbrains/env/python/IPythonConsoleTest.java100
-rw-r--r--python/testSrc/com/jetbrains/env/python/PyPackageRequirementsInspectionTest.java83
-rw-r--r--python/testSrc/com/jetbrains/env/python/PyPackagingTest.java164
-rw-r--r--python/testSrc/com/jetbrains/env/python/PythonConsoleTest.java130
-rw-r--r--python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java579
-rw-r--r--python/testSrc/com/jetbrains/env/python/PythonGeneratorTest.java24
-rw-r--r--python/testSrc/com/jetbrains/env/python/PythonSkeletonsTest.java202
-rw-r--r--python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java380
-rw-r--r--python/testSrc/com/jetbrains/env/python/debug/PyBaseDebuggerTask.java361
-rw-r--r--python/testSrc/com/jetbrains/env/python/debug/PyDebuggerTask.java211
-rw-r--r--python/testSrc/com/jetbrains/env/python/dotNet/PyIronPythonTest.java145
-rw-r--r--python/testSrc/com/jetbrains/env/python/dotNet/SkeletonTestTask.java142
-rw-r--r--python/testSrc/com/jetbrains/env/python/dotNet/package-info.java5
-rw-r--r--python/testSrc/com/jetbrains/env/python/testing/PythonDocTestingTest.java66
-rw-r--r--python/testSrc/com/jetbrains/env/python/testing/PythonNoseTestingTest.java33
-rw-r--r--python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java33
-rw-r--r--python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java78
17 files changed, 2736 insertions, 0 deletions
diff --git a/python/testSrc/com/jetbrains/env/python/IPythonConsoleTest.java b/python/testSrc/com/jetbrains/env/python/IPythonConsoleTest.java
new file mode 100644
index 000000000000..a039344451d4
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/IPythonConsoleTest.java
@@ -0,0 +1,100 @@
+package com.jetbrains.env.python;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiErrorElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.python.console.PyConsoleTask;
+import org.hamcrest.Matchers;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * @author traff
+ */
+public class IPythonConsoleTest extends PyEnvTestCase {
+ public void testQuestion() throws Exception {
+ runPythonTest(new IPythonTask() {
+ @Override
+ public void testing() throws Exception {
+ exec("import multiprocessing");
+ exec("multiprocessing?");
+ waitForOutput("Type:", "module");
+ }
+ });
+ }
+
+ public void testParsing() throws Exception {
+ runPythonTest(new IPythonTask() {
+ @Override
+ public void testing() throws Exception {
+ waitForReady();
+ addTextToEditor("sys?");
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ PsiFile psi =
+ PsiDocumentManager.getInstance(getProject())
+ .getPsiFile(getConsoleView().getLanguageConsole().getConsoleEditor().getDocument());
+ Assert.assertThat("No errors expected", getErrors(psi), Matchers.empty());
+ }
+ });
+ }
+ });
+ }
+
+ @NotNull
+ private static Collection<String> getErrors(PsiFile psi) { //TODO: NotNull?
+ if (!PsiTreeUtil.hasErrorElements(psi)) {
+ return Collections.emptyList();
+ }
+
+ return Collections2.transform(PsiTreeUtil.findChildrenOfType(psi, PsiErrorElement.class), new Function<PsiErrorElement, String>() {
+ @Override
+ public String apply(PsiErrorElement input) {
+ return input.getErrorDescription();
+ }
+ });
+ }
+
+ public void testParsingNoIPython() throws Exception {
+ runPythonTest(new IPythonTask() {
+ @Override
+ public void testing() throws Exception {
+ waitForReady();
+ addTextToEditor("sys?");
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ PsiFile psi =
+ PsiDocumentManager.getInstance(getProject()).getPsiFile(getConsoleView().getLanguageConsole().getConsoleEditor().getDocument());
+ //TreeUtil.ensureParsed(psi.getNode());
+ assertTrue(PsiTreeUtil.hasErrorElements(psi));
+ }
+ });
+
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("-ipython");
+ }
+ });
+ }
+
+ private static class IPythonTask extends PyConsoleTask {
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("ipython");
+ }
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/PyPackageRequirementsInspectionTest.java b/python/testSrc/com/jetbrains/env/python/PyPackageRequirementsInspectionTest.java
new file mode 100644
index 000000000000..8e3b75dd56a0
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/PyPackageRequirementsInspectionTest.java
@@ -0,0 +1,83 @@
+package com.jetbrains.env.python;
+
+import com.google.common.collect.ImmutableSet;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ModuleRootModificationUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.PsiTestUtil;
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.PyExecutionFixtureTestTask;
+import com.jetbrains.python.PythonTestUtil;
+import com.jetbrains.python.inspections.PyPackageRequirementsInspection;
+import com.jetbrains.python.sdkTools.SdkCreationType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+/**
+ * @author vlan
+ */
+public class PyPackageRequirementsInspectionTest extends PyEnvTestCase {
+ public static final ImmutableSet<String> TAGS = ImmutableSet.of("requirements");
+
+ public void testPartiallySatisfiedRequirementsTxt() {
+ doTest("test1.py");
+ }
+
+ public void testPartiallySatisfiedSetupPy() {
+ doTest("test1.py");
+ }
+
+ public void testImportsNotInRequirementsTxt() {
+ doTest("test1.py");
+ }
+
+ public void testDuplicateInstallAndTests() {
+ doTest("test1.py");
+ }
+
+ private void doTest(@NotNull final String filename) {
+ final String dir = getTestName(false);
+ runPythonTest(new PyExecutionFixtureTestTask() {
+ @Override
+ protected String getTestDataPath() {
+ return PythonTestUtil.getTestDataPath() + "/inspections/PyPackageRequirementsInspection";
+ }
+
+ @Override
+ public void runTestOn(String sdkHome) throws Exception {
+ myFixture.enableInspections(PyPackageRequirementsInspection.class);
+ final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.SDK_PACKAGES_ONLY);
+ final String perSdkDir = Integer.toHexString(System.identityHashCode(sdk));
+ final VirtualFile root = myFixture.copyDirectoryToProject(dir, perSdkDir);
+ assertNotNull(root);
+ final Module module = myFixture.getModule();
+ setupModuleSdk(module, sdk, root);
+ try {
+ final VirtualFile file = root.findFileByRelativePath(filename);
+ assertNotNull(file);
+ edt(new Runnable() {
+ @Override
+ public void run() {
+ myFixture.testHighlighting(true, true, true, file);
+ }
+ });
+ }
+ finally {
+ PsiTestUtil.removeAllRoots(module, sdk);
+ }
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return TAGS;
+ }
+ });
+ }
+
+ private static void setupModuleSdk(@NotNull Module module, @NotNull Sdk sdk, @NotNull VirtualFile root) {
+ ModuleRootModificationUtil.setModuleSdk(module, sdk);
+ PsiTestUtil.addContentRoot(module, root);
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java b/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java
new file mode 100644
index 000000000000..54afb702322b
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java
@@ -0,0 +1,164 @@
+package com.jetbrains.env.python;
+
+import com.google.common.collect.Sets;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.testFramework.UsefulTestCase;
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.PyExecutionFixtureTestTask;
+import com.jetbrains.env.PyTestTask;
+import com.jetbrains.python.packaging.*;
+import com.jetbrains.python.psi.LanguageLevel;
+import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
+import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor;
+import com.jetbrains.python.sdkTools.SdkCreationType;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author vlan
+ */
+public class PyPackagingTest extends PyEnvTestCase {
+ @Override
+ public void runPythonTest(PyTestTask testTask) {
+ if (UsefulTestCase.IS_UNDER_TEAMCITY && SystemInfo.isWindows) {
+ return; //Don't run under Windows as after deleting from created virtualenvs original interpreter got spoiled
+ }
+
+ super.runPythonTest(testTask);
+ }
+
+ public void testGetPackages() {
+ runPythonTest(new PyPackagingTestTask() {
+ @Override
+ public void runTestOn(String sdkHome) throws Exception {
+ final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.EMPTY_SDK);
+ List<PyPackage> packages = null;
+ try {
+ packages = ((PyPackageManagerImpl)PyPackageManager.getInstance(sdk)).getPackages();
+ }
+ catch (PyExternalProcessException e) {
+ final int retcode = e.getRetcode();
+ if (retcode != PyPackageManagerImpl.ERROR_NO_PIP && retcode != PyPackageManagerImpl.ERROR_NO_SETUPTOOLS) {
+ fail(String.format("Error for interpreter '%s': %s", sdk.getHomePath(), e.getMessage()));
+ }
+ }
+ if (packages != null) {
+ assertTrue(packages.size() > 0);
+ for (PyPackage pkg : packages) {
+ assertTrue(pkg.getName().length() > 0);
+ }
+ }
+ }
+ });
+ }
+
+ public void testCreateVirtualEnv() {
+ runPythonTest(new PyPackagingTestTask() {
+ @Override
+ public void runTestOn(String sdkHome) throws Exception {
+ final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.EMPTY_SDK);
+ try {
+ final LanguageLevel languageLevel = PythonSdkType.getLanguageLevelForSdk(sdk);
+ // virtualenv >= 0.10 supports Python >= 2.6
+ if (languageLevel.isOlderThan(LanguageLevel.PYTHON26)) {
+ return;
+ }
+ final File tempDir = FileUtil.createTempDirectory(getTestName(false), null);
+ final File venvDir = new File(tempDir, "venv");
+ final String venvSdkHome = ((PyPackageManagerImpl)PyPackageManagerImpl.getInstance(sdk)).createVirtualEnv(venvDir.toString(),
+ false);
+ final Sdk venvSdk = createTempSdk(venvSdkHome, SdkCreationType.EMPTY_SDK);
+ assertNotNull(venvSdk);
+ assertTrue(PythonSdkType.isVirtualEnv(venvSdk));
+ assertInstanceOf(PythonSdkFlavor.getPlatformIndependentFlavor(venvSdk.getHomePath()), VirtualEnvSdkFlavor.class);
+ final List<PyPackage> packages = ((PyPackageManagerImpl)PyPackageManagerImpl.getInstance(venvSdk)).getPackages();
+ final PyPackage setuptools = findPackage("setuptools", packages);
+ assertNotNull(setuptools);
+ assertEquals("setuptools", setuptools.getName());
+ assertEquals(PyPackageManagerImpl.SETUPTOOLS_VERSION, setuptools.getVersion());
+ final PyPackage pip = findPackage("pip", packages);
+ assertNotNull(pip);
+ assertEquals("pip", pip.getName());
+ assertEquals(PyPackageManagerImpl.PIP_VERSION, pip.getVersion());
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ catch (PyExternalProcessException e) {
+ throw new RuntimeException(String.format("Error for interpreter '%s': %s", sdk.getHomePath(), e.getMessage()), e);
+ }
+ }
+ });
+ }
+
+ public void testInstallPackage() {
+ runPythonTest(new PyPackagingTestTask() {
+
+ @Override
+ public void runTestOn(String sdkHome) throws Exception {
+ final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.EMPTY_SDK);
+ try {
+ final File tempDir = FileUtil.createTempDirectory(getTestName(false), null);
+ final File venvDir = new File(tempDir, "venv");
+ final String venvSdkHome = ((PyPackageManagerImpl)PyPackageManager.getInstance(sdk)).createVirtualEnv(venvDir.getPath(), false);
+ final Sdk venvSdk = createTempSdk(venvSdkHome, SdkCreationType.EMPTY_SDK);
+ assertNotNull(venvSdk);
+ final PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManager.getInstance(venvSdk);
+ final List<PyPackage> packages1 = manager.getPackages();
+ // TODO: Install Markdown from a local file
+ manager.install(list(PyRequirement.fromString("Markdown<2.2"),
+ new PyRequirement("httplib2")), Collections.<String>emptyList());
+ final List<PyPackage> packages2 = manager.getPackages();
+ final PyPackage markdown2 = findPackage("Markdown", packages2);
+ assertNotNull(markdown2);
+ assertTrue(markdown2.isInstalled());
+ final PyPackage pip1 = findPackage("pip", packages1);
+ assertNotNull(pip1);
+ assertEquals("pip", pip1.getName());
+ assertEquals(PyPackageManagerImpl.PIP_VERSION, pip1.getVersion());
+ manager.uninstall(list(pip1));
+ final List<PyPackage> packages3 = manager.getPackages();
+ final PyPackage pip2 = findPackage("pip", packages3);
+ assertNull(pip2);
+ }
+ catch (PyExternalProcessException e) {
+ new RuntimeException(String.format("Error for interpreter '%s': %s", sdk.getHomePath(), e.getMessage()), e);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ @Nullable
+ private static PyPackage findPackage(String name, List<PyPackage> packages) {
+ for (PyPackage pkg : packages) {
+ if (name.equals(pkg.getName())) {
+ return pkg;
+ }
+ }
+ return null;
+ }
+
+ private static <T> List<T> list(T... xs) {
+ return Arrays.asList(xs);
+ }
+
+
+ private abstract static class PyPackagingTestTask extends PyExecutionFixtureTestTask {
+ @Override
+ public Set<String> getTags() {
+ return Sets.newHashSet("packaging");
+ }
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/PythonConsoleTest.java b/python/testSrc/com/jetbrains/env/python/PythonConsoleTest.java
new file mode 100644
index 000000000000..4134b1697851
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/PythonConsoleTest.java
@@ -0,0 +1,130 @@
+package com.jetbrains.env.python;
+
+import com.google.common.collect.Sets;
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.python.console.PyConsoleTask;
+import org.junit.Assert;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author traff
+ */
+public class PythonConsoleTest extends PyEnvTestCase {
+ public void testConsolePrint() throws Exception {
+ runPythonTest(new PyConsoleTask() {
+ @Override
+ public void testing() throws Exception {
+ exec("x = 96");
+ exec("x += 1");
+ exec("print(1)");
+ exec("print(x)");
+ waitForOutput("97");
+ }
+ });
+ }
+
+ public void testExecuteMultiline() throws Exception { //PY-4329
+ runPythonTest(new PyConsoleTask() {
+ @Override
+ public void testing() throws Exception {
+ exec("if True:\n" +
+ " x=1\n" +
+ "y=x+100\n" +
+ "for i in range(1):\n" +
+ " print(y)\n");
+ waitForOutput("101");
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return Sets.newHashSet("-jython"); //jython doesn't support multiline execution: http://bugs.jython.org/issue2106
+ }
+ });
+ }
+
+ public void testInterruptAsync() throws Exception {
+ runPythonTest(new PyConsoleTask() {
+ @Override
+ public void testing() throws Exception {
+ exec("import time");
+ execNoWait("for i in range(10000):\n" +
+ " print(i)\n" +
+ " time.sleep(0.1)");
+ waitForOutput("3\n4\n5");
+ Assert.assertFalse(canExecuteNow());
+ interrupt();
+ waitForFinish();
+ waitForReady();
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return Sets.newHashSet("-iron", "-jython");
+ }
+ });
+ }
+
+ public void testLineByLineInput() throws Exception {
+ runPythonTest(new PyConsoleTask() {
+ @Override
+ public void testing() throws Exception {
+ exec("x = 96");
+ exec("x +=1");
+ exec("if True:");
+ exec(" print(x)");
+ exec("");
+ exec("");
+ waitForOutput("97");
+ }
+ });
+ }
+
+
+ public void testVariablesView() throws Exception {
+ runPythonTest(new PyConsoleTask() {
+ @Override
+ public void testing() throws Exception {
+ exec("x = 1");
+ exec("print(x)");
+ waitForOutput("1");
+
+ assertTrue("Variable has wrong value",
+ hasValue("x", "1"));
+ }
+ });
+ }
+
+ public void testCompoundVariable() throws Exception {
+ runPythonTest(new PyConsoleTask() {
+ @Override
+ public void testing() throws Exception {
+ exec("x = [1, 2, 3]");
+ exec("print(x)");
+ waitForOutput("[1, 2, 3]");
+
+ List<String> values = getCompoundValueChildren(getValue("x"));
+ Collections.sort(values);
+ assertContainsElements(values, "1", "2", "3", "3");
+ }
+ });
+ }
+
+ public void testChangeVariable() throws Exception {
+ runPythonTest(new PyConsoleTask() {
+ @Override
+ public void testing() throws Exception {
+ exec("x = 1");
+ exec("print(x)");
+ waitForOutput("1");
+
+ setValue("x", "2");
+
+ assertTrue("Variable has wrong value",
+ hasValue("x", "2"));
+ }
+ });
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java
new file mode 100644
index 000000000000..4372715371eb
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java
@@ -0,0 +1,579 @@
+package com.jetbrains.env.python;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
+import com.intellij.xdebugger.XDebuggerTestUtil;
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.python.debug.PyDebuggerTask;
+import com.jetbrains.env.ut.PyUnitTestTask;
+import com.jetbrains.python.PythonHelpersLocator;
+import com.jetbrains.python.console.pydev.PydevCompletionVariant;
+import com.jetbrains.python.debugger.PyDebuggerException;
+import com.jetbrains.python.debugger.PyExceptionBreakpointProperties;
+import com.jetbrains.python.debugger.PyExceptionBreakpointType;
+import com.jetbrains.python.debugger.pydev.ProcessDebugger;
+import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author traff
+ */
+
+public class PythonDebuggerTest extends PyEnvTestCase {
+ public void testBreakpointStopAndEval() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test1.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 3);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+
+ eval("i").hasValue("0");
+
+ resume();
+
+ waitForPause();
+
+ eval("i").hasValue("1");
+
+ resume();
+
+ waitForPause();
+
+ eval("i").hasValue("2");
+ }
+ });
+ }
+
+ public void testDebugger() {
+ runPythonTest(new PyUnitTestTask("", "test_debug.py") {
+ @Override
+ protected String getTestDataPath() {
+ return PythonHelpersLocator.getPythonCommunityPath() + "/helpers/pydev";
+ }
+
+ @Override
+ public void after() {
+ allTestsPassed();
+ }
+ });
+ }
+
+ public void testConditionalBreakpoint() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test1.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 3);
+ XDebuggerTestUtil.setBreakpointCondition(getProject(), 3, "i == 1 or i == 11 or i == 111");
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+
+ eval("i").hasValue("1");
+
+ resume();
+
+ waitForPause();
+
+ eval("i").hasValue("11");
+
+ resume();
+
+ waitForPause();
+
+ eval("i").hasValue("111");
+ }
+ });
+ }
+
+ public void testDebugConsole() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test1.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 3);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+
+ eval("i").hasValue("0");
+
+ resume();
+
+ waitForPause();
+
+ consoleExec("'i=%d'%i");
+
+ waitForOutput("'i=1'");
+
+ consoleExec("x");
+
+ waitForOutput("name 'x' is not defined");
+
+ consoleExec("1-;");
+
+ waitForOutput("SyntaxError");
+
+ resume();
+ }
+
+ private void consoleExec(String command) {
+ myDebugProcess.consoleExec(command, new ProcessDebugger.DebugCallback<String>() {
+ @Override
+ public void ok(String value) {
+
+ }
+
+ @Override
+ public void error(PyDebuggerException exception) {
+ }
+ });
+ }
+ });
+ }
+
+
+ public void testDebugCompletion() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test4.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 3);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+
+ List<PydevCompletionVariant> list = myDebugProcess.getCompletions("xvalu");
+ assertEquals(2, list.size());
+ }
+ });
+ }
+
+ public void testBreakpointLogExpression() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test1.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 3);
+ XDebuggerTestUtil.setBreakpointLogExpression(getProject(), 3, "'i = %d'%i");
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ resume();
+ waitForOutput("i = 1");
+ }
+ });
+ }
+
+ public void testStepOver() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test2.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 5);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ stepOver();
+ waitForPause();
+ stepOver();
+ waitForPause();
+ eval("z").hasValue("2");
+ }
+ });
+ }
+
+ public void testStepInto() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test2.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 5);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ stepInto();
+ waitForPause();
+ eval("x").hasValue("1");
+ stepOver();
+ waitForPause();
+ eval("y").hasValue("3");
+ stepOver();
+ waitForPause();
+ eval("z").hasValue("1");
+ }
+ });
+ }
+
+ public void testSmartStepInto() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test3.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 14);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ smartStepInto("foo");
+ waitForPause();
+ stepOver();
+ waitForPause();
+ eval("y").hasValue("4");
+ }
+ });
+ }
+
+ public void testSmartStepInto2() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test3.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 18);
+ toggleBreakpoint(getScriptPath(), 25);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ toggleBreakpoint(getScriptPath(), 18);
+ smartStepInto("foo");
+ waitForPause();
+ eval("a.z").hasValue("1");
+ }
+ });
+ }
+
+ public void testInput() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_input.py") {
+ @Override
+ public void before() throws Exception {
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForOutput("print command >");
+ input("GO!");
+ waitForOutput("command was GO!");
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("-jython"); //can't run on jython
+ }
+ });
+ }
+
+ public void testRunToLine() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_runtoline.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 1);
+ toggleBreakpoint(getScriptPath(), 7);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ eval("x").hasValue("0");
+ runToLine(4);
+ eval("x").hasValue("1");
+ resume();
+ waitForPause();
+ eval("x").hasValue("12");
+ resume();
+
+ waitForOutput("x = 12");
+ }
+ });
+ }
+
+ private static void addExceptionBreakpoint(IdeaProjectTestFixture fixture, PyExceptionBreakpointProperties properties) {
+ XDebuggerTestUtil.addBreakpoint(fixture.getProject(), PyExceptionBreakpointType.class, properties);
+ }
+
+ public void testExceptionBreakpointOnTerminate() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_exceptbreak.py") {
+ @Override
+ public void before() throws Exception {
+ createExceptionBreak(myFixture, true, false, false);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ eval("__exception__[0].__name__").hasValue("'ZeroDivisionError'");
+ resume();
+ waitForTerminate();
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("-iron");
+ }
+ });
+ }
+
+ private static void createExceptionBreak(IdeaProjectTestFixture fixture,
+ boolean notifyOnTerminate,
+ boolean notifyAlways,
+ boolean notifyOnFirst) {
+ XDebuggerTestUtil.removeAllBreakpoints(fixture.getProject());
+ XDebuggerTestUtil.setDefaultBreakpointEnabled(fixture.getProject(), PyExceptionBreakpointType.class, false);
+
+ PyExceptionBreakpointProperties properties = new PyExceptionBreakpointProperties("exceptions.ZeroDivisionError");
+ properties.setNotifyOnTerminate(notifyOnTerminate);
+ properties.setNotifyAlways(notifyAlways);
+ properties.setNotifyOnlyOnFirst(notifyOnFirst);
+ addExceptionBreakpoint(fixture, properties);
+ properties = new PyExceptionBreakpointProperties("builtins.ZeroDivisionError"); //for python 3
+ properties.setNotifyOnTerminate(notifyOnTerminate);
+ properties.setNotifyAlways(notifyAlways);
+ properties.setNotifyOnlyOnFirst(notifyOnFirst);
+ addExceptionBreakpoint(fixture, properties);
+ }
+
+ public void testExceptionBreakpointAlways() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_exceptbreak.py") {
+ @Override
+ public void before() throws Exception {
+ createExceptionBreak(myFixture, false, true, false);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ eval("__exception__[0].__name__").hasValue("'ZeroDivisionError'");
+ resume();
+ waitForPause();
+ resume();
+ waitForPause();
+ resume();
+ waitForTerminate();
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("-pypy"); //TODO: fix it for Pypy
+ }
+ });
+ }
+
+ public void testExceptionBreakpointOnFirstRaise() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_exceptbreak.py") {
+ @Override
+ public void before() throws Exception {
+ createExceptionBreak(myFixture, false, false, true);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ eval("__exception__[0].__name__").hasValue("'ZeroDivisionError'");
+ resume();
+ waitForTerminate();
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("-iron");
+ }
+ });
+ }
+
+ public void testMultithreading() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_multithread.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 9);
+ toggleBreakpoint(getScriptPath(), 13);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ eval("y").hasValue("2");
+ resume();
+ waitForPause();
+ eval("z").hasValue("102");
+ resume();
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("-pypy"); //TODO: fix that for PyPy
+ }
+ });
+ }
+
+ public void testEggDebug() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_egg.py") {
+ @Override
+ public void before() throws Exception {
+ String egg = getFilePath("Adder-0.1.egg");
+ toggleBreakpointInEgg(egg, "adder/adder.py", 2);
+ PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(getRunConfiguration().getSdkHome());
+ if (flavor != null) {
+ flavor.initPythonPath(Lists.newArrayList(egg), getRunConfiguration().getEnvs());
+ }
+ else {
+ getRunConfiguration().getEnvs().put("PYTHONPATH", egg);
+ }
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ eval("ret").hasValue("16");
+ resume();
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("-jython"); //TODO: fix that for Jython if anybody needs it
+ }
+ });
+ }
+
+ public void testStepOverConditionalBreakpoint() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_stepOverCondition.py") {
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 1);
+ toggleBreakpoint(getScriptPath(), 2);
+ XDebuggerTestUtil.setBreakpointCondition(getProject(), 2, "y == 3");
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+ stepOver();
+ waitForPause();
+ eval("y").hasValue("2");
+ }
+ });
+ }
+
+ public void testMultiprocess() throws Exception {
+ runPythonTest(new PyDebuggerTask("/debug", "test_multiprocess.py") {
+ @Override
+ protected void init() {
+ setMultiprocessDebug(true);
+ }
+
+ @Override
+ public void before() throws Exception {
+ toggleBreakpoint(getScriptPath(), 9);
+ }
+
+ @Override
+ public void testing() throws Exception {
+ waitForPause();
+
+ eval("i").hasValue("'Result:OK'");
+
+ resume();
+
+ waitForOutput("Result:OK");
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return Sets.newHashSet("python3");
+ }
+ });
+ }
+
+
+ //TODO: fix me as I don't work properly sometimes (something connected with process termination on agent)
+ //public void testResume() throws Exception {
+ // runPythonTest(new PyDebuggerTask("/debug", "Test_Resume.py") {
+ // @Override
+ // public void before() throws Exception {
+ // toggleBreakpoint(getScriptPath(), 2);
+ // }
+ //
+ // @Override
+ // public void testing() throws Exception {
+ // waitForPause();
+ // eval("x").hasValue("1");
+ // resume();
+ // waitForPause();
+ // eval("x").hasValue("2");
+ // resume();
+ // }
+ // });
+ //}
+
+
+ //TODO: first fix strange hanging of that test
+ //public void testRemoteDebug() throws Exception {
+ // runPythonTest(new PyRemoteDebuggerTask("/debug", "test_remote.py") {
+ // @Override
+ // public void before() throws Exception {
+ // }
+ //
+ // @Override
+ // public void testing() throws Exception {
+ // waitForPause();
+ // eval("x").hasValue("0");
+ // stepOver();
+ // waitForPause();
+ // eval("x").hasValue("1");
+ // stepOver();
+ // waitForPause();
+ // eval("x").hasValue("2");
+ // resume();
+ // }
+ //
+ // @Override
+ // protected void checkOutput(ProcessOutput output) {
+ // assertEmpty(output.getStderr());
+ // assertEquals("OK", output.getStdout().trim());
+ // }
+ //
+ // @Override
+ // public void after() throws Exception {
+ // stopDebugServer();
+ // }
+ // });
+ //}
+
+ //TODO: That doesn't work now: case from test_continuation.py and test_continuation2.py are treated differently by interpreter
+ // (first line is executed in first case and last line in second)
+
+ //public void testBreakOnContinuationLine() throws Exception {
+ // runPythonTest(new PyDebuggerTask("/debug", "test_continuation.py") {
+ // @Override
+ // public void before() throws Exception {
+ // toggleBreakpoint(getScriptPath(), 13);
+ // }
+ //
+ // @Override
+ // public void testing() throws Exception {
+ // waitForPause();
+ // eval("x").hasValue("0");
+ // stepOver();
+ // waitForPause();
+ // eval("x").hasValue("1");
+ // stepOver();
+ // waitForPause();
+ // eval("x").hasValue("2");
+ // }
+ // });
+ //}
+}
+
diff --git a/python/testSrc/com/jetbrains/env/python/PythonGeneratorTest.java b/python/testSrc/com/jetbrains/env/python/PythonGeneratorTest.java
new file mode 100644
index 000000000000..273cb3f94011
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/PythonGeneratorTest.java
@@ -0,0 +1,24 @@
+package com.jetbrains.env.python;
+
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.ut.PyUnitTestTask;
+import com.jetbrains.python.PythonHelpersLocator;
+
+/**
+ * @author traff
+ */
+public class PythonGeneratorTest extends PyEnvTestCase{
+ public void testGenerator() {
+ runPythonTest(new PyUnitTestTask("", "test_generator.py") {
+ @Override
+ protected String getTestDataPath() {
+ return PythonHelpersLocator.getPythonCommunityPath() + "/helpers";
+ }
+
+ @Override
+ public void after() {
+ allTestsPassed();
+ }
+ });
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/PythonSkeletonsTest.java b/python/testSrc/com/jetbrains/env/python/PythonSkeletonsTest.java
new file mode 100644
index 000000000000..c6b150f31359
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/PythonSkeletonsTest.java
@@ -0,0 +1,202 @@
+package com.jetbrains.env.python;
+
+import com.google.common.collect.ImmutableSet;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.PyExecutionFixtureTestTask;
+import com.jetbrains.env.PyTestTask;
+import com.jetbrains.python.PythonFileType;
+import com.jetbrains.python.PythonTestUtil;
+import com.jetbrains.python.documentation.PythonDocumentationProvider;
+import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.impl.PyBuiltinCache;
+import com.jetbrains.python.psi.resolve.PythonSdkPathCache;
+import com.jetbrains.python.psi.types.PyType;
+import com.jetbrains.python.psi.types.TypeEvalContext;
+import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher;
+import com.jetbrains.python.sdk.skeletons.SkeletonVersionChecker;
+import com.jetbrains.python.sdkTools.SdkCreationType;
+import com.jetbrains.python.toolbox.Maybe;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.Set;
+
+/**
+ * Heavyweight integration tests of skeletons of Python binary modules.
+ * <p/>
+ * An environment test environment must have a 'skeletons' tag in order to be compatible with this test case. No specific packages are
+ * required currently. Both Python 2 and Python 3 are OK. All platforms are OK. At least one Python 2.6+ environment is required.
+ *
+ * @author vlan
+ */
+public class PythonSkeletonsTest extends PyEnvTestCase {
+ public static final ImmutableSet<String> TAGS = ImmutableSet.of("skeletons");
+
+ public void testBuiltins() {
+ runTest(new SkeletonsTask() {
+ @Override
+ public void runTestOn(@NotNull Sdk sdk) {
+ // Check the builtin skeleton header
+ final Project project = myFixture.getProject();
+ final PyFile builtins = PyBuiltinCache.getBuiltinsForSdk(project, sdk);
+ assertNotNull(builtins);
+ final VirtualFile virtualFile = builtins.getVirtualFile();
+ assertNotNull(virtualFile);
+ assertTrue(virtualFile.isInLocalFileSystem());
+ final String path = virtualFile.getPath();
+ final PySkeletonRefresher.SkeletonHeader header = PySkeletonRefresher.readSkeletonHeader(new File(path));
+ assertNotNull(header);
+ final int version = header.getVersion();
+ assertTrue("Header version must be > 0, currently it is " + version, version > 0);
+ assertEquals(SkeletonVersionChecker.BUILTIN_NAME, header.getBinaryFile());
+
+ // Run inspections on a file that uses builtins
+ myFixture.configureByFile(getTestName(false) + ".py");
+
+
+ PsiFile expr = myFixture.getFile();
+
+ final Module module = ModuleUtil.findModuleForPsiElement(expr);
+
+ final Sdk sdkFromModule = PythonSdkType.findPythonSdk(module);
+ assertNotNull(sdkFromModule);
+
+ final Sdk sdkFromPsi = PyBuiltinCache.findSdkForFile(expr.getContainingFile());
+ final PyFile builtinsFromSdkCache = PythonSdkPathCache.getInstance(project, sdkFromPsi).getBuiltins().getBuiltinsFile();
+ assertNotNull(builtinsFromSdkCache);
+ assertEquals(builtins, builtinsFromSdkCache);
+
+ final PyFile builtinsFromPsi = PyBuiltinCache.getInstance(expr).getBuiltinsFile();
+ assertNotNull(builtinsFromPsi);
+ assertEquals(builtins, builtinsFromPsi);
+
+ myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
+ edt(new Runnable() {
+ @Override
+ public void run() {
+ myFixture.checkHighlighting(true, false, false);
+ }
+ });
+ }
+ });
+ }
+
+ // PY-4349
+ public void testFakeNamedTuple() {
+ runTest(new SkeletonsTask() {
+ @Override
+ protected void runTestOn(@NotNull Sdk sdk) {
+ final LanguageLevel languageLevel = PythonSdkType.getLanguageLevelForSdk(sdk);
+ // Named tuples have been introduced in Python 2.6
+ if (languageLevel.isOlderThan(LanguageLevel.PYTHON26)) {
+ return;
+ }
+
+ // XXX: A workaround for invalidating VFS cache with the test file copied to our temp directory
+ LocalFileSystem.getInstance().refresh(false);
+
+ // Run inspections on code that uses named tuples
+ myFixture.configureByFile(getTestName(false) + ".py");
+ myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
+
+ edt(new Runnable() {
+ @Override
+ public void run() {
+ myFixture.checkHighlighting(true, false, false);
+ }
+ });
+ }
+ });
+ }
+
+ public void testKnownPropertiesTypes() {
+ runTest(new SkeletonsTask() {
+ @Override
+ protected void runTestOn(@NotNull Sdk sdk) {
+ myFixture.configureByText(PythonFileType.INSTANCE,
+ "expr = slice(1, 2).start\n");
+ final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
+ final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getFile());
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ final PyType type = context.getType(expr);
+ final String actualType = PythonDocumentationProvider.getTypeName(type, context);
+ assertEquals("int", actualType);
+ }
+ });
+ }
+ });
+ }
+
+ // PY-9797
+ public void testReadWriteDeletePropertyDefault() {
+ runTest(new SkeletonsTask() {
+ @Override
+ protected void runTestOn(@NotNull Sdk sdk) {
+ final LanguageLevel languageLevel = PythonSdkType.getLanguageLevelForSdk(sdk);
+ // We rely on int.real property that is not explicitly annotated in the skeletons generator
+ if (languageLevel.isOlderThan(LanguageLevel.PYTHON26)) {
+ return;
+ }
+ final Project project = myFixture.getProject();
+ final PyFile builtins = PyBuiltinCache.getBuiltinsForSdk(project, sdk);
+ assertNotNull(builtins);
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ final PyClass cls = builtins.findTopLevelClass("int");
+ assertNotNull(cls);
+ final Property prop = cls.findProperty("real", true);
+ assertNotNull(prop);
+ assertIsNotNull(prop.getGetter());
+ assertIsNotNull(prop.getSetter());
+ assertIsNotNull(prop.getDeleter());
+ }
+ });
+ }
+
+ private void assertIsNotNull(Maybe<Callable> accessor) {
+ if (accessor.isDefined()) {
+ assertNotNull(accessor.valueOrNull());
+ }
+ }
+ });
+ }
+
+
+ private void runTest(@NotNull PyTestTask task) {
+ runPythonTest(task);
+ }
+
+
+ private abstract class SkeletonsTask extends PyExecutionFixtureTestTask {
+ @Override
+ protected String getTestDataPath() {
+ return PythonTestUtil.getTestDataPath() + "/skeletons/";
+ }
+
+ @Override
+ public void runTestOn(String sdkHome) throws Exception {
+ final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.SDK_PACKAGES_AND_SKELETONS);
+ runTestOn(sdk);
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return TAGS;
+ }
+
+ protected abstract void runTestOn(@NotNull Sdk sdk);
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java b/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java
new file mode 100644
index 000000000000..9a242934042d
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java
@@ -0,0 +1,380 @@
+package com.jetbrains.env.python.console;
+
+import com.google.common.collect.Lists;
+import com.intellij.execution.console.LanguageConsoleView;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.WriteAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.xdebugger.frame.XValueChildrenList;
+import com.jetbrains.env.PyExecutionFixtureTestTask;
+import com.jetbrains.python.console.*;
+import com.jetbrains.python.console.pydev.ConsoleCommunicationListener;
+import com.jetbrains.python.debugger.PyDebugValue;
+import com.jetbrains.python.debugger.PyDebuggerException;
+import com.jetbrains.python.sdkTools.SdkCreationType;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+import java.util.List;
+import java.util.concurrent.Semaphore;
+
+/**
+ * @author traff
+ */
+public class PyConsoleTask extends PyExecutionFixtureTestTask {
+ private boolean myProcessCanTerminate;
+
+ protected PyConsoleProcessHandler myProcessHandler;
+ protected PydevConsoleCommunication myCommunication;
+
+ private boolean shouldPrintOutput = false;
+ private PythonConsoleView myConsoleView;
+ private Semaphore mySemaphore;
+ private Semaphore mySemaphore0;
+ private PydevConsoleExecuteActionHandler myExecuteHandler;
+
+ public PyConsoleTask() {
+ setWorkingFolder(getTestDataPath());
+ }
+
+ public PythonConsoleView getConsoleView() {
+ return myConsoleView;
+ }
+
+ @Override
+ public void setUp(final String testName) throws Exception {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (myFixture == null) {
+ PyConsoleTask.super.setUp(testName);
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ @NotNull
+ protected String output() {
+ return myConsoleView.getConsole().getHistoryViewer().getDocument().getText();
+ }
+
+ public void setProcessCanTerminate(boolean processCanTerminate) {
+ myProcessCanTerminate = processCanTerminate;
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (myConsoleView != null) {
+ disposeConsole();
+ }
+ PyConsoleTask.super.tearDown();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ private void disposeConsole() throws InterruptedException {
+ if (myCommunication != null) {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ myCommunication.close();
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ myCommunication = null;
+ }
+ });
+ }
+
+ disposeConsoleProcess();
+
+ if (myConsoleView != null) {
+ new WriteAction() {
+ @Override
+ protected void run(@NotNull Result result) throws Throwable {
+ Disposer.dispose(myConsoleView);
+ myConsoleView = null;
+ }
+ }.execute();
+ }
+ }
+
+ @Override
+ public void runTestOn(final String sdkHome) throws Exception {
+ final Project project = getProject();
+
+ final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.EMPTY_SDK);
+
+ setProcessCanTerminate(false);
+
+ PydevConsoleRunner consoleRunner = PydevConsoleRunner.create(project, sdk, PyConsoleType.PYTHON, getWorkingFolder());
+ before();
+
+ mySemaphore0 = new Semaphore(0);
+
+ consoleRunner.addConsoleListener(new PydevConsoleRunner.ConsoleListener() {
+ @Override
+ public void handleConsoleInitialized(LanguageConsoleView consoleView) {
+ mySemaphore0.release();
+ }
+ });
+
+ consoleRunner.run();
+
+ waitFor(mySemaphore0);
+
+ mySemaphore = new Semaphore(0);
+
+ myConsoleView = consoleRunner.getConsoleView();
+ myProcessHandler = (PyConsoleProcessHandler)consoleRunner.getProcessHandler();
+
+ myExecuteHandler = (PydevConsoleExecuteActionHandler)consoleRunner.getConsoleExecuteActionHandler();
+
+ myCommunication = consoleRunner.getPydevConsoleCommunication();
+
+ myCommunication.addCommunicationListener(new ConsoleCommunicationListener() {
+ @Override
+ public void commandExecuted(boolean more) {
+ mySemaphore.release();
+ }
+
+ @Override
+ public void inputRequested() {
+ }
+ });
+
+ myProcessHandler.addProcessListener(new ProcessAdapter() {
+ @Override
+ public void processTerminated(ProcessEvent event) {
+ if (event.getExitCode() != 0 && !myProcessCanTerminate) {
+ Assert.fail("Process terminated unexpectedly\n" + output());
+ }
+ }
+ });
+
+ OutputPrinter myOutputPrinter = null;
+ if (shouldPrintOutput) {
+ myOutputPrinter = new OutputPrinter();
+ myOutputPrinter.start();
+ }
+
+ waitForOutput("PyDev console");
+
+ try {
+ testing();
+ after();
+ }
+ finally {
+ setProcessCanTerminate(true);
+
+ if (myOutputPrinter != null) {
+ myOutputPrinter.stop();
+ }
+
+ disposeConsole();
+ }
+ }
+
+ private void disposeConsoleProcess() throws InterruptedException {
+ myProcessHandler.destroyProcess();
+
+ waitFor(myProcessHandler);
+
+ if (!myProcessHandler.isProcessTerminated()) {
+ if (!waitFor(myProcessHandler)) {
+ if (!myProcessHandler.isProcessTerminated()) {
+ throw new RuntimeException("Cannot stop console process");
+ }
+ }
+ }
+ myProcessHandler = null;
+ }
+
+ /**
+ * Waits until all passed strings appear in output.
+ * If they don't appear in time limit, then exception is raised.
+ *
+ * @param string
+ * @throws InterruptedException
+ */
+ public void waitForOutput(String... string) throws InterruptedException {
+ int count = 0;
+ while (true) {
+ List<String> missing = Lists.newArrayList();
+ String out = output();
+ boolean flag = true;
+ for (String s : string) {
+ if (!out.contains(s)) {
+ flag = false;
+ missing.add(s);
+ }
+ }
+ if (flag) {
+ break;
+ }
+ if (count > 10) {
+ Assert.fail("Strings: <--\n" + StringUtil.join(missing, "\n---\n") + "-->" + "are not present in output.\n" + output());
+ }
+ Thread.sleep(2000);
+ count++;
+ }
+ }
+
+ protected void waitForReady() throws InterruptedException {
+ int count = 0;
+ while (!myExecuteHandler.isEnabled() || !canExecuteNow()) {
+ if (count > 10) {
+ Assert.fail("Console is not ready");
+ }
+ Thread.sleep(300);
+ count++;
+ }
+ }
+
+ protected boolean canExecuteNow() {
+ return myExecuteHandler.canExecuteNow();
+ }
+
+ public void setShouldPrintOutput(boolean shouldPrintOutput) {
+ this.shouldPrintOutput = shouldPrintOutput;
+ }
+
+ private class OutputPrinter {
+ private Thread myThread;
+ private int myLen = 0;
+
+ public void start() {
+ myThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ doJob();
+ }
+ });
+ myThread.setDaemon(true);
+ myThread.start();
+ }
+
+ private void doJob() {
+ try {
+ while (true) {
+ printToConsole();
+
+ Thread.sleep(500);
+ }
+ }
+ catch (Exception ignored) {
+ }
+ }
+
+ private synchronized void printToConsole() {
+ String s = output();
+ if (s.length() > myLen) {
+ System.out.print(s.substring(myLen));
+ }
+ myLen = s.length();
+ }
+
+ public void stop() {
+ printToConsole();
+ myThread.interrupt();
+ }
+ }
+
+ protected void exec(String command) throws InterruptedException {
+ waitForReady();
+ int p = mySemaphore.availablePermits();
+ myConsoleView.executeInConsole(command);
+ mySemaphore.acquire(p + 1);
+ //waitForOutput(">>> " + command);
+ }
+
+ protected boolean hasValue(String varName, String value) throws PyDebuggerException {
+ PyDebugValue val = getValue(varName);
+ return val != null && value.equals(val.getValue());
+ }
+
+ protected void setValue(String varName, String value) throws PyDebuggerException {
+ PyDebugValue val = getValue(varName);
+ myCommunication.changeVariable(val, value);
+ }
+
+ protected PyDebugValue getValue(String varName) throws PyDebuggerException {
+ XValueChildrenList l = myCommunication.loadFrame();
+
+ if (l == null) {
+ return null;
+ }
+ for (int i = 0; i < l.size(); i++) {
+ String name = l.getName(i);
+ if (varName.equals(name)) {
+ return (PyDebugValue)l.getValue(i);
+ }
+ }
+
+ return null;
+ }
+
+ protected List<String> getCompoundValueChildren(PyDebugValue value) throws PyDebuggerException {
+ XValueChildrenList list = myCommunication.loadVariable(value);
+ List<String> result = Lists.newArrayList();
+ for (int i = 0; i<list.size(); i++) {
+ result.add(((PyDebugValue)list.getValue(i)).getValue());
+ }
+ return result;
+ }
+
+ protected void input(String text) {
+ myConsoleView.executeInConsole(text);
+ }
+
+ protected void waitForFinish() throws InterruptedException {
+ waitFor(mySemaphore);
+ }
+
+ protected void execNoWait(final String command) {
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ myConsoleView.executeCode(command, null);
+ }
+ });
+ }
+
+ protected void interrupt() {
+ myCommunication.interrupt();
+ }
+
+
+ public void addTextToEditor(final String text) {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ getConsoleView().getLanguageConsole().setInputText(text);
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ }
+ }
+ );
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/debug/PyBaseDebuggerTask.java b/python/testSrc/com/jetbrains/env/python/debug/PyBaseDebuggerTask.java
new file mode 100644
index 000000000000..38eed736c7ef
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/debug/PyBaseDebuggerTask.java
@@ -0,0 +1,361 @@
+package com.jetbrains.env.python.debug;
+
+import com.google.common.collect.Sets;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.WriteAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.JarFileSystem;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.xdebugger.*;
+import com.intellij.xdebugger.frame.XValue;
+import com.jetbrains.env.PyExecutionFixtureTestTask;
+import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
+import com.jetbrains.python.debugger.PyDebugProcess;
+import com.jetbrains.python.debugger.PyDebugValue;
+import com.jetbrains.python.debugger.PyDebuggerException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Assert;
+
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+
+/**
+ * @author traff
+ */
+public abstract class PyBaseDebuggerTask extends PyExecutionFixtureTestTask {
+ private Set<Pair<String, Integer>> myBreakpoints = Sets.newHashSet();
+ protected PyDebugProcess myDebugProcess;
+ protected XDebugSession mySession;
+ protected Semaphore myPausedSemaphore;
+ protected Semaphore myTerminateSemaphore;
+ protected boolean shouldPrintOutput = false;
+ protected boolean myProcessCanTerminate;
+
+ protected void waitForPause() throws InterruptedException, InvocationTargetException {
+ Assert.assertTrue("Debugger didn't stopped within timeout\nOutput:" + output(), waitFor(myPausedSemaphore));
+
+ XDebuggerTestUtil.waitForSwing();
+ }
+
+ protected void waitForTerminate() throws InterruptedException, InvocationTargetException {
+ setProcessCanTerminate(true);
+
+ Assert.assertTrue("Debugger didn't terminated within timeout\nOutput:" + output(), waitFor(myTerminateSemaphore));
+ XDebuggerTestUtil.waitForSwing();
+ }
+
+ protected void runToLine(int line) throws InvocationTargetException, InterruptedException {
+ XDebugSession currentSession = XDebuggerManager.getInstance(getProject()).getCurrentSession();
+ XSourcePosition position = currentSession.getCurrentPosition();
+
+
+ currentSession.runToPosition(XDebuggerUtil.getInstance().createPosition(position.getFile(), line), false);
+
+ waitForPause();
+ }
+
+ protected void resume() {
+ XDebugSession currentSession = XDebuggerManager.getInstance(getProject()).getCurrentSession();
+
+ Assert.assertTrue(currentSession.isSuspended());
+ Assert.assertEquals(0, myPausedSemaphore.availablePermits());
+
+ currentSession.resume();
+ }
+
+ protected void stepOver() {
+ XDebugSession currentSession = XDebuggerManager.getInstance(getProject()).getCurrentSession();
+
+ Assert.assertTrue(currentSession.isSuspended());
+ Assert.assertEquals(0, myPausedSemaphore.availablePermits());
+
+ currentSession.stepOver(false);
+ }
+
+ protected void stepInto() {
+ XDebugSession currentSession = XDebuggerManager.getInstance(getProject()).getCurrentSession();
+
+ Assert.assertTrue(currentSession.isSuspended());
+ Assert.assertEquals(0, myPausedSemaphore.availablePermits());
+
+ currentSession.stepInto();
+ }
+
+ protected void smartStepInto(String funcName) {
+ XDebugSession currentSession = XDebuggerManager.getInstance(getProject()).getCurrentSession();
+
+ Assert.assertTrue(currentSession.isSuspended());
+ Assert.assertEquals(0, myPausedSemaphore.availablePermits());
+
+ myDebugProcess.startSmartStepInto(funcName);
+ }
+
+ @NotNull
+ protected String output() {
+ if (mySession != null && mySession.getConsoleView() != null) {
+ PythonDebugLanguageConsoleView pydevConsoleView = (PythonDebugLanguageConsoleView)mySession.getConsoleView();
+ if (pydevConsoleView != null) {
+ return XDebuggerTestUtil.getConsoleText(pydevConsoleView.getTextConsole());
+ }
+ }
+ return "Console output not available.";
+ }
+
+ protected void input(String text) {
+ PrintWriter pw = new PrintWriter(myDebugProcess.getProcessHandler().getProcessInput());
+ pw.println(text);
+ pw.flush();
+ }
+
+ private void outputContains(String substring) {
+ Assert.assertTrue(output().contains(substring));
+ }
+
+ public void setProcessCanTerminate(boolean processCanTerminate) {
+ myProcessCanTerminate = processCanTerminate;
+ }
+
+ protected void clearAllBreakpoints() {
+
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ XDebuggerTestUtil.removeAllBreakpoints(getProject());
+ }
+ });
+ }
+
+ /**
+ * Toggles breakpoint
+ *
+ * @param file getScriptPath() or path to script
+ * @param line starting with 0
+ */
+ protected void toggleBreakpoint(final String file, final int line) {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ doToggleBreakpoint(file, line);
+ }
+ });
+
+ addOrRemoveBreakpoint(file, line);
+ }
+
+ private void addOrRemoveBreakpoint(String file, int line) {
+ if (myBreakpoints.contains(Pair.create(file, line))) {
+ myBreakpoints.remove(Pair.create(file, line));
+ }
+ else {
+ myBreakpoints.add(Pair.create(file, line));
+ }
+ }
+
+ protected void toggleBreakpointInEgg(final String file, final String innerPath, final int line) {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ VirtualFile f = LocalFileSystem.getInstance().findFileByPath(file);
+ Assert.assertNotNull(f);
+ final VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(f);
+ Assert.assertNotNull(jarRoot);
+ VirtualFile innerFile = jarRoot.findFileByRelativePath(innerPath);
+ Assert.assertNotNull(innerFile);
+ XDebuggerTestUtil.toggleBreakpoint(getProject(), innerFile, line);
+ }
+ });
+
+ addOrRemoveBreakpoint(file, line);
+ }
+
+ public boolean canPutBreakpointAt(Project project, String file, int line) {
+ VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(file);
+ Assert.assertNotNull(vFile);
+ return XDebuggerUtil.getInstance().canPutBreakpointAt(project, vFile, line);
+ }
+
+ private void doToggleBreakpoint(String file, int line) {
+ Assert.assertTrue(canPutBreakpointAt(getProject(), file, line));
+ XDebuggerTestUtil.toggleBreakpoint(getProject(), LocalFileSystem.getInstance().findFileByPath(file), line);
+ }
+
+ protected Variable eval(String name) throws InterruptedException {
+ Assert.assertTrue("Eval works only while suspended", mySession.isSuspended());
+ XValue var = XDebuggerTestUtil.evaluate(mySession, name).first;
+ Assert.assertNotNull("There is no variable named " + name, var);
+ return new Variable(var);
+ }
+
+ protected void setVal(String name, String value) throws InterruptedException, PyDebuggerException {
+ XValue var = XDebuggerTestUtil.evaluate(mySession, name).first;
+ myDebugProcess.changeVariable((PyDebugValue)var, value);
+ }
+
+ public void waitForOutput(String ... string) throws InterruptedException {
+ long started = System.currentTimeMillis();
+
+ while (!containsOneOf(output(), string)) {
+ if (System.currentTimeMillis() - started > myTimeout) {
+ Assert.fail("None of '" + StringUtil.join(string, ", ") + "'" + " is not present in output.\n" + output());
+ }
+ Thread.sleep(2000);
+ }
+ }
+
+ protected boolean containsOneOf(String output, String[] strings) {
+ for (String s: strings) {
+ if (output.contains(s)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ public void setShouldPrintOutput(boolean shouldPrintOutput) {
+ this.shouldPrintOutput = shouldPrintOutput;
+ }
+
+ @Override
+ public void setUp(final String testName) throws Exception {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (myFixture == null) {
+ PyBaseDebuggerTask.super.setUp(testName);
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ public void run() {
+ try {
+ if (mySession != null) {
+ finishSession();
+ }
+ PyBaseDebuggerTask.super.tearDown();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ protected void finishSession() throws InterruptedException {
+ disposeDebugProcess();
+
+ if (mySession != null) {
+ new WriteAction() {
+ protected void run(Result result) throws Throwable {
+ mySession.stop();
+ }
+ }.execute();
+
+ waitFor(mySession.getDebugProcess().getProcessHandler()); //wait for process termination after session.stop() which is async
+
+ XDebuggerTestUtil.disposeDebugSession(mySession);
+ mySession = null;
+ myDebugProcess = null;
+ myPausedSemaphore = null;
+ }
+ }
+
+ protected abstract void disposeDebugProcess() throws InterruptedException;
+
+ protected void doTest(@Nullable OutputPrinter myOutputPrinter) throws InterruptedException {
+ try {
+ testing();
+ after();
+ }
+ catch (Throwable e) {
+ throw new RuntimeException(output(), e);
+ }
+ finally {
+ clearAllBreakpoints();
+
+ setProcessCanTerminate(true);
+
+ if (myOutputPrinter != null) {
+ myOutputPrinter.stop();
+ }
+
+ finishSession();
+ }
+ }
+
+ protected static class Variable {
+ private final XTestValueNode myValueNode;
+
+ public Variable(XValue value) throws InterruptedException {
+ myValueNode = XDebuggerTestUtil.computePresentation(value);
+ }
+
+ public Variable hasValue(String value) {
+ Assert.assertEquals(value, myValueNode.myValue);
+ return this;
+ }
+
+ public Variable hasType(String type) {
+ Assert.assertEquals(type, myValueNode.myType);
+ return this;
+ }
+
+ public Variable hasName(String name) {
+ Assert.assertEquals(name, myValueNode.myName);
+ return this;
+ }
+ }
+
+ public class OutputPrinter {
+ private Thread myThread;
+
+ public void start() {
+ myThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ doJob();
+ }
+ });
+ myThread.setDaemon(true);
+ myThread.start();
+ }
+
+ private void doJob() {
+ int len = 0;
+ try {
+ while (true) {
+ String s = output();
+ if (s.length() > len) {
+ System.out.print(s.substring(len));
+ }
+ len = s.length();
+
+ Thread.sleep(500);
+ }
+ }
+ catch (Exception e) {
+ }
+ }
+
+ public void stop() {
+ myThread.interrupt();
+ }
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/debug/PyDebuggerTask.java b/python/testSrc/com/jetbrains/env/python/debug/PyDebuggerTask.java
new file mode 100644
index 000000000000..7de13d1ebed6
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/debug/PyDebuggerTask.java
@@ -0,0 +1,211 @@
+package com.jetbrains.env.python.debug;
+
+import com.intellij.execution.*;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.process.KillableColoredProcessHandler;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.WriteAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.xdebugger.*;
+import com.jetbrains.python.debugger.PyDebugProcess;
+import com.jetbrains.python.debugger.PyDebugRunner;
+import com.jetbrains.python.run.PythonCommandLineState;
+import com.jetbrains.python.run.PythonConfigurationType;
+import com.jetbrains.python.run.PythonRunConfiguration;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.concurrent.Semaphore;
+
+/**
+ * @author traff
+ */
+public class PyDebuggerTask extends PyBaseDebuggerTask {
+
+ private boolean myMultiprocessDebug = false;
+ private PythonRunConfiguration myRunConfiguration;
+
+ public PyDebuggerTask() {
+ init();
+ }
+
+ public PyDebuggerTask(String workingFolder, String scriptName, String scriptParameters) {
+ setWorkingFolder(getTestDataPath() + workingFolder);
+ setScriptName(scriptName);
+ setScriptParameters(scriptParameters);
+ init();
+ }
+
+ public PyDebuggerTask(String workingFolder, String scriptName) {
+ this(workingFolder, scriptName, null);
+ }
+
+ protected void init() {
+
+ }
+
+ public void runTestOn(String sdkHome) throws Exception {
+ final Project project = getProject();
+
+ final ConfigurationFactory factory = PythonConfigurationType.getInstance().getConfigurationFactories()[0];
+
+
+ final RunnerAndConfigurationSettings settings =
+ RunManager.getInstance(project).createRunConfiguration("test", factory);
+
+ myRunConfiguration = (PythonRunConfiguration)settings.getConfiguration();
+
+ myRunConfiguration.setSdkHome(sdkHome);
+ myRunConfiguration.setScriptName(getScriptPath());
+ myRunConfiguration.setWorkingDirectory(getWorkingFolder());
+ myRunConfiguration.setScriptParameters(getScriptParameters());
+
+ new WriteAction() {
+ @Override
+ protected void run(Result result) throws Throwable {
+ RunManagerEx.getInstanceEx(project).addConfiguration(settings, false);
+ RunManagerEx.getInstanceEx(project).setSelectedConfiguration(settings);
+ Assert.assertSame(settings, RunManagerEx.getInstanceEx(project).getSelectedConfiguration());
+ }
+ }.execute();
+
+ final PyDebugRunner runner = (PyDebugRunner)ProgramRunnerUtil.getRunner(DefaultDebugExecutor.EXECUTOR_ID, settings);
+ Assert.assertTrue(runner.canRun(DefaultDebugExecutor.EXECUTOR_ID, myRunConfiguration));
+
+ final Executor executor = DefaultDebugExecutor.getDebugExecutorInstance();
+ final ExecutionEnvironment env = new ExecutionEnvironment(executor, runner, settings, project);
+
+ final PythonCommandLineState pyState = (PythonCommandLineState)myRunConfiguration.getState(executor, env);
+
+ assert pyState != null;
+ pyState.setMultiprocessDebug(isMultiprocessDebug());
+
+ final ServerSocket serverSocket;
+ try {
+ //noinspection SocketOpenedButNotSafelyClosed
+ serverSocket = new ServerSocket(0);
+ }
+ catch (IOException e) {
+ throw new ExecutionException("Failed to find free socket port", e);
+ }
+
+
+ final int serverLocalPort = serverSocket.getLocalPort();
+ final RunProfile profile = env.getRunProfile();
+
+ before();
+
+ setProcessCanTerminate(false);
+
+ myTerminateSemaphore = new Semaphore(0);
+
+ new WriteAction<ExecutionResult>() {
+ @Override
+ protected void run(@NotNull Result<ExecutionResult> result) throws Throwable {
+ final ExecutionResult res =
+ pyState.execute(executor, PyDebugRunner.createCommandLinePatchers(myFixture.getProject(), pyState, profile, serverLocalPort));
+
+ mySession = XDebuggerManager.getInstance(getProject()).
+ startSession(runner, env, env.getContentToReuse(), new XDebugProcessStarter() {
+ @NotNull
+ public XDebugProcess start(@NotNull final XDebugSession session) {
+ myDebugProcess =
+ new PyDebugProcess(session, serverSocket, res.getExecutionConsole(), res.getProcessHandler(), isMultiprocessDebug());
+
+ myDebugProcess.getProcessHandler().addProcessListener(new ProcessAdapter() {
+
+ @Override
+ public void onTextAvailable(ProcessEvent event, Key outputType) {
+ }
+
+ @Override
+ public void processTerminated(ProcessEvent event) {
+ myTerminateSemaphore.release();
+ if (event.getExitCode() != 0 && !myProcessCanTerminate) {
+ Assert.fail("Process terminated unexpectedly\n" + output());
+ }
+ }
+ });
+
+
+ myDebugProcess.getProcessHandler().startNotify();
+
+ return myDebugProcess;
+ }
+ });
+ result.setResult(res);
+ }
+ }.execute().getResultObject();
+
+ OutputPrinter myOutputPrinter = null;
+ if (shouldPrintOutput) {
+ myOutputPrinter = new OutputPrinter();
+ myOutputPrinter.start();
+ }
+
+
+ myPausedSemaphore = new Semaphore(0);
+
+
+ mySession.addSessionListener(new XDebugSessionAdapter() {
+ @Override
+ public void sessionPaused() {
+ if (myPausedSemaphore != null) {
+ myPausedSemaphore.release();
+ }
+ }
+ });
+
+ doTest(myOutputPrinter);
+ }
+
+ public PythonRunConfiguration getRunConfiguration() {
+ return myRunConfiguration;
+ }
+
+ private boolean isMultiprocessDebug() {
+ return myMultiprocessDebug;
+ }
+
+ public void setMultiprocessDebug(boolean multiprocessDebug) {
+ myMultiprocessDebug = multiprocessDebug;
+ }
+
+ @Override
+ protected void disposeDebugProcess() throws InterruptedException {
+ if (myDebugProcess != null) {
+ ProcessHandler processHandler = myDebugProcess.getProcessHandler();
+
+ myDebugProcess.stop();
+
+ waitFor(processHandler);
+
+ if (!processHandler.isProcessTerminated()) {
+ killDebugProcess();
+ if (!waitFor(processHandler)) {
+ new Throwable("Cannot stop debugger process").printStackTrace();
+ }
+ }
+ }
+ }
+
+ private void killDebugProcess() {
+ if (myDebugProcess.getProcessHandler() instanceof KillableColoredProcessHandler) {
+ KillableColoredProcessHandler h = (KillableColoredProcessHandler)myDebugProcess.getProcessHandler();
+
+ h.killProcess();
+ }
+ else {
+ myDebugProcess.getProcessHandler().destroyProcess();
+ }
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/dotNet/PyIronPythonTest.java b/python/testSrc/com/jetbrains/env/python/dotNet/PyIronPythonTest.java
new file mode 100644
index 000000000000..a6f9dd68971d
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/dotNet/PyIronPythonTest.java
@@ -0,0 +1,145 @@
+package com.jetbrains.env.python.dotNet;
+
+import com.intellij.openapi.application.ReadAction;
+import com.intellij.openapi.application.Result;
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.python.psi.PyFile;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+/**
+ * IronPython.NET specific tests
+ *
+ * @author Ilya.Kazakevich
+ */
+public class PyIronPythonTest extends PyEnvTestCase {
+
+ /**
+ * IronPython tag
+ */
+ static final String IRON_TAG = "iron";
+
+ public PyIronPythonTest() {
+ super(IRON_TAG);
+ }
+
+ /**
+ * Tests skeleton generation
+ */
+ public void testSkeletons() throws Exception {
+ runPythonTest(new SkeletonTestTask(
+ "dotNet/expected.skeleton.java.py",
+ "com.just.like.java",
+ "testSkeleton.py",
+ null
+ ));
+ }
+
+ /**
+ * Tests skeleton generation with "from" statements
+ */
+ public void testClassFromModule() throws Exception {
+ runPythonTest(new SkeletonTestTask(
+ "dotNet/expected.skeleton.java.py",
+ "com.just.like.java",
+ "import_class_from_module.py",
+ null
+ ));
+ }
+
+ /**
+ * Tests skeleton generation when imported as alias
+ */
+ public void testClassFromModuleAlias() throws Exception {
+ runPythonTest(new SkeletonTestTask(
+ "dotNet/expected.skeleton.java.py",
+ "com.just.like.java",
+ "import_class_from_module_alias.py",
+ null
+ ));
+ }
+
+ /**
+ * Tests skeleton generation when module is imported
+ */
+ public void testModuleFromPackage() throws Exception {
+ runPythonTest(new SkeletonTestTask(
+ "dotNet/expected.skeleton.java.py",
+ "com.just.like.java",
+ "import_module_from_package.py",
+ null
+ ));
+ }
+
+ /**
+ * Tests skeleton generation when several classes are imported
+ */
+ public void testSeveralClasses() throws Exception {
+ runPythonTest(new SkeletonTestTask(
+ "dotNet/expected.skeleton.java.py",
+ "com.just.like.java",
+ "import_several_classes_from_module.py",
+ "com.just.like.java.LikeJavaClass"
+ ));
+ }
+
+ /**
+ * Tests skeletons for built-in classes. We can't compare files (CLR class may be changed from version to version),
+ * but we are sure there should be class System.Web.AspNetHostingPermissionLevel which is part of public API
+ */
+ public void testImportBuiltInSystem() throws Exception {
+ final SkeletonTestTask task = new SkeletonTestTask(
+ null,
+ "System.Web",
+ "import_system.py",
+ null
+ );
+ runPythonTest(task);
+ final PyFile skeleton = task.getGeneratedSkeleton();
+ new ReadAction() {
+ @Override
+ protected void run(@NotNull Result result) throws Throwable {
+ Assert.assertNotNull("System.Web does not contain class AspNetHostingPermissionLevel. Error generating stub? It has classes " +
+ skeleton.getTopLevelClasses(),
+ skeleton.findTopLevelClass("AspNetHostingPermissionLevel"));
+ }
+ }.execute();
+
+ }
+
+ /**
+ * Test importing of inner classes
+ */
+ public void testImportInnerClass() throws Exception {
+ runPythonTest(new SkeletonTestTask(
+ "dotNet/expected.skeleton.Deep.py",
+ "SingleNameSpace.Some.Deep",
+ "inner_class.py",
+ null
+ ));
+ }
+
+ /**
+ * Test importing of the whole namespace
+ */
+ public void testWholeNameSpace() throws Exception {
+ runPythonTest(new SkeletonTestTask(
+ "dotNet/expected.skeleton.SingleNameSpace.py",
+ "SingleNameSpace",
+ "whole_namespace.py",
+ null
+ ));
+ }
+
+ /**
+ * Test importing of single class
+ */
+ public void testSingleClass() throws Exception {
+ runPythonTest(new SkeletonTestTask(
+ "dotNet/expected.skeleton.SingleNameSpace.py",
+ "SingleNameSpace",
+ "single_class.py",
+ null
+ ));
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/dotNet/SkeletonTestTask.java b/python/testSrc/com/jetbrains/env/python/dotNet/SkeletonTestTask.java
new file mode 100644
index 000000000000..e10916cbe7de
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/dotNet/SkeletonTestTask.java
@@ -0,0 +1,142 @@
+package com.jetbrains.env.python.dotNet;
+
+import com.google.common.collect.Sets;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ex.QuickFixWrapper;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.progress.util.AbstractProgressIndicatorBase;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.util.ui.UIUtil;
+import com.jetbrains.env.PyExecutionFixtureTestTask;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.inspections.quickfix.GenerateBinaryStubsFix;
+import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.sdk.InvalidSdkException;
+import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.sdkTools.SdkCreationType;
+import org.hamcrest.Matchers;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Task for test that checks skeleton generation
+ *
+ * @author Ilya.Kazakevich
+ */
+class SkeletonTestTask extends PyExecutionFixtureTestTask {
+
+ /**
+ * Tags for this task to run
+ */
+ private static final Set<String> IRON_TAGS = Sets.newHashSet(PyIronPythonTest.IRON_TAG);
+ /**
+ * Number of seconds we wait for skeleton generation external process (should be enough)
+ */
+ private static final int SECONDS_TO_WAIT_FOR_SKELETON_GENERATION = 20;
+
+ @Nullable
+ private final String myExpectedSkeletonFile;
+ @NotNull
+ private final String myModuleNameToBeGenerated;
+ @NotNull
+ private final String mySourceFileToRunGenerationOn;
+ @NotNull
+ private final String myUseQuickFixWithThisModuleOnly;
+ private PyFile myGeneratedSkeleton;
+
+ /**
+ * @param expectedSkeletonFile if you want test to compare generated result with some file, provide its name.
+ * Pass null if you do not want to compare result with anything (you may do it yourself with {@link #getGeneratedSkeleton()})
+ * @param moduleNameToBeGenerated name of module you think we should generate in dotted notation (like "System.Web" or "com.myModule").
+ * System will wait for skeleton file for this module to be generated
+ * @param sourceFileToRunGenerationOn Source file where we should run "generate stubs" on. Be sure to place "caret" on appropriate place!
+ * @param useQuickFixWithThisModuleOnly If there are several quick fixes in code, you may run fix only on this module.
+ * Pass null if you are sure there would be only one quickfix
+ */
+ SkeletonTestTask(@Nullable final String expectedSkeletonFile,
+ @NotNull final String moduleNameToBeGenerated,
+ @NotNull final String sourceFileToRunGenerationOn,
+ @Nullable final String useQuickFixWithThisModuleOnly) {
+ myExpectedSkeletonFile = expectedSkeletonFile;
+ myModuleNameToBeGenerated = moduleNameToBeGenerated.replace('.', '/');
+ mySourceFileToRunGenerationOn = sourceFileToRunGenerationOn;
+ myUseQuickFixWithThisModuleOnly = useQuickFixWithThisModuleOnly != null ? useQuickFixWithThisModuleOnly : "";
+ }
+
+
+ @Override
+ public void runTestOn(@NotNull final String sdkHome) throws IOException, InvalidSdkException {
+ final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.SDK_PACKAGES_ONLY);
+ final File skeletonsPath = new File(PythonSdkType.getSkeletonsPath(PathManager.getSystemPath(), sdk.getHomePath()));
+ File skeletonFileOrDirectory = new File(skeletonsPath, myModuleNameToBeGenerated); // File with module skeleton
+
+ // Module may be stored in "moduleName.py" or "moduleName/__init__.py"
+ if (skeletonFileOrDirectory.isDirectory()) {
+ skeletonFileOrDirectory = new File(skeletonFileOrDirectory, PyNames.INIT_DOT_PY);
+ }
+ else {
+ skeletonFileOrDirectory = new File(skeletonFileOrDirectory.getAbsolutePath() + PyNames.DOT_PY);
+ }
+
+ final File skeletonFile = skeletonFileOrDirectory;
+
+ if (skeletonFile.exists()) { // To make sure we do not reuse it
+ assert skeletonFile.delete() : "Failed to delete file " + skeletonFile;
+ }
+
+ myFixture.copyFileToProject("dotNet/" + mySourceFileToRunGenerationOn, mySourceFileToRunGenerationOn); // File that uses CLR library
+ myFixture.copyFileToProject("dotNet/PythonLibs.dll", "PythonLibs.dll"); // Library itself
+ myFixture.copyFileToProject("dotNet/SingleNameSpace.dll", "SingleNameSpace.dll"); // Another library
+ myFixture.configureByFile(mySourceFileToRunGenerationOn);
+ myFixture.enableInspections(PyUnresolvedReferencesInspection.class); // This inspection should suggest us to generate stubs
+
+
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ PsiDocumentManager.getInstance(myFixture.getProject()).commitAllDocuments();
+ final String intentionName = PyBundle.message("sdk.gen.stubs.for.binary.modules", myUseQuickFixWithThisModuleOnly);
+ final IntentionAction intention = myFixture.findSingleIntention(intentionName);
+ Assert.assertNotNull("No intention found to generate skeletons!", intention);
+ Assert.assertThat("Intention should be quick fix to run", intention, Matchers.instanceOf(QuickFixWrapper.class));
+ final LocalQuickFix quickFix = ((QuickFixWrapper)intention).getFix();
+ Assert.assertThat("Quick fix should be 'generate binary skeletons' fix to run", quickFix,
+ Matchers.instanceOf(GenerateBinaryStubsFix.class));
+ final Task fixTask = ((GenerateBinaryStubsFix)quickFix).getFixTask(myFixture.getFile());
+ fixTask.run(new AbstractProgressIndicatorBase());
+ }
+ });
+
+ FileUtil.copy(skeletonFile, new File(myFixture.getTempDirPath(), skeletonFile.getName()));
+ if (myExpectedSkeletonFile != null) {
+ myFixture.checkResultByFile(skeletonFile.getName(), myExpectedSkeletonFile, false);
+ }
+ myGeneratedSkeleton = (PyFile)myFixture.configureByFile(skeletonFile.getName());
+ }
+
+
+ @Override
+ public Set<String> getTags() {
+ return Collections.unmodifiableSet(IRON_TAGS);
+ }
+
+ /**
+ * @return File for generated skeleton. Call it after {@link #runTestOn(String)} only!
+ */
+ @NotNull
+ PyFile getGeneratedSkeleton() {
+ return myGeneratedSkeleton;
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/dotNet/package-info.java b/python/testSrc/com/jetbrains/env/python/dotNet/package-info.java
new file mode 100644
index 000000000000..e56e6203b98d
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/dotNet/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * IronPython tests. Install IronPython, .NET and add "iron" to "tags.txt" file. Check for more info: http://confluence.jetbrains.com/display/PYINT/Env+Tests
+ * @author Ilya.Kazakevich
+ */
+package com.jetbrains.env.python.dotNet; \ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonDocTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonDocTestingTest.java
new file mode 100644
index 000000000000..411b6049350a
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/testing/PythonDocTestingTest.java
@@ -0,0 +1,66 @@
+package com.jetbrains.env.python.testing;
+
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.ut.PyDocTestTask;
+
+/**
+ * User : catherine
+ */
+public class PythonDocTestingTest extends PyEnvTestCase{
+ public void testUTRunner() {
+ runPythonTest(new PyDocTestTask("/testRunner/env/doc", "test1.py") {
+
+ @Override
+ public void after() {
+ assertEquals(3, allTestsCount());
+ assertEquals(3, passedTestsCount());
+ allTestsPassed();
+ }
+ });
+ }
+
+ public void testClass() {
+ runPythonTest(new PyDocTestTask("/testRunner/env/doc", "test1.py::FirstGoodTest") {
+
+ @Override
+ public void after() {
+ assertEquals(1, allTestsCount());
+ assertEquals(1, passedTestsCount());
+ }
+ });
+ }
+
+ public void testMethod() {
+ runPythonTest(new PyDocTestTask("/testRunner/env/doc", "test1.py::SecondGoodTest::test_passes") {
+
+ @Override
+ public void after() {
+ assertEquals(1, allTestsCount());
+ assertEquals(1, passedTestsCount());
+ }
+ });
+ }
+
+ public void testFunction() {
+ runPythonTest(new PyDocTestTask("/testRunner/env/doc", "test1.py::factorial") {
+
+ @Override
+ public void after() {
+ assertEquals(1, allTestsCount());
+ assertEquals(1, passedTestsCount());
+ }
+ });
+ }
+
+ public void testUTRunner2() {
+ runPythonTest(new PyDocTestTask("/testRunner/env/doc", "test2.py") {
+
+ @Override
+ public void after() {
+ assertEquals(3, allTestsCount());
+ assertEquals(1, passedTestsCount());
+ assertEquals(2, failedTestsCount());
+ }
+ });
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonNoseTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonNoseTestingTest.java
new file mode 100644
index 000000000000..33250ae17fa4
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/testing/PythonNoseTestingTest.java
@@ -0,0 +1,33 @@
+package com.jetbrains.env.python.testing;
+
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.ut.PyNoseTestTask;
+
+/**
+ * User : catherine
+ */
+public class PythonNoseTestingTest extends PyEnvTestCase{
+ public void testNoseRunner() {
+ runPythonTest(new PyNoseTestTask("/testRunner/env/nose", "test1.py") {
+
+ @Override
+ public void after() {
+ assertEquals(3, allTestsCount());
+ assertEquals(3, passedTestsCount());
+ allTestsPassed();
+ }
+ });
+ }
+
+ public void testNoseRunner2() {
+ runPythonTest(new PyNoseTestTask("/testRunner/env/nose", "test2.py") {
+
+ @Override
+ public void after() {
+ assertEquals(8, allTestsCount());
+ assertEquals(5, passedTestsCount());
+ assertEquals(3, failedTestsCount());
+ }
+ });
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java
new file mode 100644
index 000000000000..ab3dee60c5b0
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java
@@ -0,0 +1,33 @@
+package com.jetbrains.env.python.testing;
+
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.ut.PyTestTestTask;
+
+/**
+ * User : catherine
+ */
+public class PythonPyTestingTest extends PyEnvTestCase{
+ public void testPytestRunner() {
+ runPythonTest(new PyTestTestTask("/testRunner/env/pytest", "test1.py") {
+
+ @Override
+ public void after() {
+ assertEquals(3, allTestsCount());
+ assertEquals(3, passedTestsCount());
+ allTestsPassed();
+ }
+ });
+ }
+
+ public void testPytestRunner2() {
+ runPythonTest(new PyTestTestTask("/testRunner/env/pytest", "test2.py") {
+
+ @Override
+ public void after() {
+ assertEquals(8, allTestsCount());
+ assertEquals(5, passedTestsCount());
+ assertEquals(3, failedTestsCount());
+ }
+ });
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java
new file mode 100644
index 000000000000..682eb8160285
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java
@@ -0,0 +1,78 @@
+package com.jetbrains.env.python.testing;
+
+import com.jetbrains.env.PyEnvTestCase;
+import com.jetbrains.env.ut.PyUnitTestTask;
+import junit.framework.Assert;
+
+/**
+ * @author traff
+ */
+public class PythonUnitTestingTest extends PyEnvTestCase{
+ public void testUTRunner() {
+ runPythonTest(new PyUnitTestTask("/testRunner/env/unit", "test1.py") {
+
+ @Override
+ public void after() {
+ Assert.assertEquals(2, allTestsCount());
+ Assert.assertEquals(2, passedTestsCount());
+ allTestsPassed();
+ }
+ });
+ }
+
+ public void testUTRunner2() {
+ runPythonTest(new PyUnitTestTask("/testRunner/env/unit", "test2.py") {
+
+ @Override
+ public void after() {
+ assertEquals(3, allTestsCount());
+ assertEquals(1, passedTestsCount());
+ assertEquals(2, failedTestsCount());
+ }
+ });
+ }
+
+ public void testClass() {
+ runPythonTest(new PyUnitTestTask("/testRunner/env/unit", "test_file.py::GoodTest") {
+
+ @Override
+ public void after() {
+ assertEquals(1, allTestsCount());
+ assertEquals(1, passedTestsCount());
+ }
+ });
+ }
+
+ public void testMethod() {
+ runPythonTest(new PyUnitTestTask("/testRunner/env/unit", "test_file.py::GoodTest::test_passes") {
+
+ @Override
+ public void after() {
+ assertEquals(1, allTestsCount());
+ assertEquals(1, passedTestsCount());
+ }
+ });
+ }
+
+ public void testFolder() {
+ runPythonTest(new PyUnitTestTask("/testRunner/env/unit", "test_folder/") {
+
+ @Override
+ public void after() {
+ assertEquals(5, allTestsCount());
+ assertEquals(3, passedTestsCount());
+ }
+ });
+ }
+
+ public void testDependent() {
+ runPythonTest(new PyUnitTestTask("/testRunner/env/unit", "dependentTests/test_my_class.py") {
+
+ @Override
+ public void after() {
+ assertEquals(1, allTestsCount());
+ assertEquals(1, passedTestsCount());
+ }
+ });
+ }
+}