summaryrefslogtreecommitdiff
path: root/python/testSrc/com/jetbrains
diff options
context:
space:
mode:
Diffstat (limited to 'python/testSrc/com/jetbrains')
-rw-r--r--python/testSrc/com/jetbrains/env/PyEnvSufficiencyTest.java51
-rw-r--r--python/testSrc/com/jetbrains/env/PyEnvTaskRunner.java112
-rw-r--r--python/testSrc/com/jetbrains/env/PyEnvTestCase.java201
-rw-r--r--python/testSrc/com/jetbrains/env/PyExecutionFixtureTestTask.java174
-rw-r--r--python/testSrc/com/jetbrains/env/PyTestTask.java81
-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
-rw-r--r--python/testSrc/com/jetbrains/env/ut/PyDocTestTask.java24
-rw-r--r--python/testSrc/com/jetbrains/env/ut/PyNoseTestTask.java32
-rw-r--r--python/testSrc/com/jetbrains/env/ut/PyTestTestTask.java40
-rw-r--r--python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java241
-rw-r--r--python/testSrc/com/jetbrains/python/PyAddImportTest.java47
-rw-r--r--python/testSrc/com/jetbrains/python/PyTypeTest.java6
-rw-r--r--python/testSrc/com/jetbrains/python/PythonCompletionTest.java98
-rw-r--r--python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java29
-rw-r--r--python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java40
-rw-r--r--python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java5
-rw-r--r--python/testSrc/com/jetbrains/python/refactoring/PyIntroduceConstantTest.java7
-rw-r--r--python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java2
-rw-r--r--python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java142
-rw-r--r--python/testSrc/com/jetbrains/python/sdkTools/SdkCreationType.java20
-rw-r--r--python/testSrc/com/jetbrains/python/sdkTools/package-info.java6
37 files changed, 4062 insertions, 32 deletions
diff --git a/python/testSrc/com/jetbrains/env/PyEnvSufficiencyTest.java b/python/testSrc/com/jetbrains/env/PyEnvSufficiencyTest.java
new file mode 100644
index 000000000000..83846a1bb5f5
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/PyEnvSufficiencyTest.java
@@ -0,0 +1,51 @@
+package com.jetbrains.env;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.testFramework.UsefulTestCase;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author traff
+ */
+public class PyEnvSufficiencyTest extends PyEnvTestCase {
+ private static final List<String> BASE_TAGS =
+ ImmutableList.<String>builder().add("python3", "django", "jython", "ipython", "ipython011", "ipython012", "nose", "pytest").build();
+
+ public void testSufficiency() {
+ if (UsefulTestCase.IS_UNDER_TEAMCITY && IS_ENV_CONFIGURATION) {
+ Set<String> tags = Sets.newHashSet();
+ List<String> roots = getPythonRoots();
+ if (roots.size() == 0) {
+ return; // not on env agent
+ }
+ for (String root : roots) {
+ tags.addAll(loadEnvTags(root));
+ }
+
+ List<String> missing = Lists.newArrayList();
+ for (String tag : necessaryTags()) {
+ if (!tags.contains(tag)) {
+ missing.add(tag);
+ }
+ }
+
+
+ assertEmpty("Agent is missing environments: " + StringUtil.join(missing, ", "), missing);
+ }
+ }
+
+ private static List<String> necessaryTags() {
+ if (SystemInfo.isWindows) {
+ return ImmutableList.<String>builder().addAll(BASE_TAGS).add("iron").build();
+ }
+ else {
+ return ImmutableList.<String>builder().addAll(BASE_TAGS).add("packaging").build();
+ }
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/PyEnvTaskRunner.java b/python/testSrc/com/jetbrains/env/PyEnvTaskRunner.java
new file mode 100644
index 000000000000..baabd5a5e5e1
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/PyEnvTaskRunner.java
@@ -0,0 +1,112 @@
+package com.jetbrains.env;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.jetbrains.python.sdk.PythonSdkType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author traff
+ */
+public class PyEnvTaskRunner {
+ private final List<String> myRoots;
+
+ public PyEnvTaskRunner(List<String> roots) {
+ myRoots = roots;
+ }
+
+ public void runTask(PyTestTask testTask, String testName) {
+ boolean wasExecuted = false;
+
+ List<String> passedRoots = Lists.newArrayList();
+
+ for (String root : myRoots) {
+
+ if (!isSuitableForTask(PyEnvTestCase.loadEnvTags(root), testTask) || !shouldRun(root, testTask)) {
+ continue;
+ }
+
+ try {
+ testTask.setUp(testName);
+ wasExecuted = true;
+ if (isJython(root)) {
+ testTask.useLongTimeout();
+ }
+ else {
+ testTask.useNormalTimeout();
+ }
+ final String executable = getExecutable(root, testTask);
+ if (executable == null) {
+ throw new RuntimeException("Cannot find Python interpreter in " + root);
+ }
+ testTask.runTestOn(executable);
+ passedRoots.add(root);
+ }
+ catch (Throwable e) {
+ throw new RuntimeException(
+ PyEnvTestCase.joinStrings(passedRoots, "Tests passed environments: ") + "Test failed on " + getEnvType() + " environment " + root,
+ e);
+ }
+ finally {
+ try {
+ testTask.tearDown();
+ }
+ catch (Exception e) {
+ throw new RuntimeException("Couldn't tear down task", e);
+ }
+ }
+ }
+
+ if (!wasExecuted) {
+ throw new RuntimeException("test" +
+ testName +
+ " was not executed.\n" +
+ PyEnvTestCase.joinStrings(myRoots, "All roots: ") +
+ "\n" +
+ PyEnvTestCase.joinStrings(testTask.getTags(), "Required tags in tags.txt in root: "));
+ }
+ }
+
+ protected boolean shouldRun(String root, PyTestTask task) {
+ return true;
+ }
+
+ protected String getExecutable(String root, PyTestTask testTask) {
+ return PythonSdkType.getPythonExecutable(root);
+ }
+
+ protected String getEnvType() {
+ return "local";
+ }
+
+ private static boolean isSuitableForTask(List<String> tags, PyTestTask task) {
+ return isSuitableForTags(tags, task.getTags());
+ }
+
+ public static boolean isSuitableForTags(List<String> envTags, Set<String> taskTags) {
+ Set<String> necessaryTags = Sets.newHashSet(taskTags);
+
+ for (String tag : envTags) {
+ necessaryTags.remove(tag.trim());
+ }
+
+ for (String tag : taskTags) {
+ if (tag.startsWith("-")) { //do not run on envs with that tag
+ if (envTags.contains(tag.substring(1))) {
+ return false;
+ }
+ necessaryTags.remove(tag);
+ }
+ }
+
+ return necessaryTags.isEmpty();
+ }
+
+
+ protected static boolean isJython(@NotNull String sdkHome) {
+ return sdkHome.toLowerCase().contains("jython");
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/PyEnvTestCase.java b/python/testSrc/com/jetbrains/env/PyEnvTestCase.java
new file mode 100644
index 000000000000..853a5504de63
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/PyEnvTestCase.java
@@ -0,0 +1,201 @@
+package com.jetbrains.env;
+
+import com.google.common.collect.Lists;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.testFramework.UsefulTestCase;
+import com.intellij.util.SystemProperties;
+import com.intellij.util.ui.UIUtil;
+import com.jetbrains.python.fixtures.PyTestCase;
+import org.hamcrest.Matchers;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Assume;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * @author traff
+ */
+public abstract class PyEnvTestCase extends UsefulTestCase {
+ private static final Logger LOG = Logger.getInstance(PyEnvTestCase.class.getName());
+
+ private static final String TAGS_FILE = "tags.txt";
+ private static final String PYCHARM_PYTHON_ENVS = "PYCHARM_PYTHON_ENVS";
+ private static final String PYCHARM_PYTHON_VIRTUAL_ENVS = "PYCHARM_PYTHON_VIRTUAL_ENVS";
+
+ protected static final boolean IS_ENV_CONFIGURATION = System.getProperty("pycharm.env") != null;
+
+
+ public static final boolean RUN_REMOTE = SystemProperties.getBooleanProperty("pycharm.run_remote", false);
+
+ public static final boolean RUN_LOCAL = SystemProperties.getBooleanProperty("pycharm.run_local", true);
+
+ /**
+ * Tags that should exist between all tags, available on all interpreters for test to run.
+ * See {@link #PyEnvTestCase(String...)}
+ */
+ @Nullable
+ private final String[] myRequiredTags;
+
+ /**
+ * @param requiredTags tags that should exist on some interpreter for this test to run.
+ * if some of these tags do not exist on any interpreter, all test methods would be skipped using
+ * {@link org.junit.Assume}.
+ * See <a href="http://junit.sourceforge.net/javadoc/org/junit/Assume.html">Assume manual</a>.
+ * Check [IDEA-122939] and [TW-25043] as well.
+ */
+ @SuppressWarnings("JUnitTestCaseWithNonTrivialConstructors")
+ protected PyEnvTestCase(@NotNull final String... requiredTags) {
+ myRequiredTags = requiredTags.length > 0 ? requiredTags.clone() : null;
+
+ PyTestCase.initPlatformPrefix();
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ if (myRequiredTags != null) { // Ensure all tags exist between available interpreters
+ Assume.assumeThat(
+ "Can't find some tags between all available interpreter, test (all methods) will be skipped",
+ getAvailableTags(),
+ Matchers.hasItems(myRequiredTags)
+ );
+ }
+ }
+
+ /**
+ * @return all tags available between all interpreters
+ */
+ @NotNull
+ private static Collection<String> getAvailableTags() {
+ final Collection<String> allAvailableTags = new HashSet<String>();
+ for (final String pythonRoot : getPythonRoots()) {
+ allAvailableTags.addAll(loadEnvTags(pythonRoot));
+ }
+ return allAvailableTags;
+ }
+
+ @Override
+ protected void invokeTestRunnable(@NotNull final Runnable runnable) throws Exception {
+ if (runInWriteAction()) {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(runnable);
+ }
+ });
+ }
+ else {
+ runnable.run();
+ }
+ }
+
+ @Override
+ protected boolean runInDispatchThread() {
+ return false;
+ }
+
+ protected boolean runInWriteAction() {
+ return false;
+ }
+
+ public void runPythonTest(final PyTestTask testTask) {
+ runTest(testTask, getTestName(false));
+ }
+
+ public void runTest(@NotNull PyTestTask testTask, @NotNull String testName) {
+ if (notEnvConfiguration()) {
+ fail("Running under teamcity but not by Env configuration. Skipping.");
+ return;
+ }
+
+ List<String> roots = getPythonRoots();
+
+ if (roots.size() == 0) {
+ String msg = testName +
+ ": environments are not defined. Skipping. \nSpecify either " +
+ PYCHARM_PYTHON_ENVS +
+ " or " +
+ PYCHARM_PYTHON_VIRTUAL_ENVS +
+ " environment variable.";
+ LOG.warn(msg);
+ System.out.println(msg);
+ return;
+ }
+
+ doRunTests(testTask, testName, roots);
+ }
+
+ protected void doRunTests(PyTestTask testTask, String testName, List<String> roots) {
+ if (RUN_LOCAL) {
+ PyEnvTaskRunner taskRunner = new PyEnvTaskRunner(roots);
+
+ taskRunner.runTask(testTask, testName);
+ }
+ }
+
+
+ public static boolean notEnvConfiguration() {
+ return UsefulTestCase.IS_UNDER_TEAMCITY && !IS_ENV_CONFIGURATION;
+ }
+
+ public static List<String> getPythonRoots() {
+ List<String> roots = Lists.newArrayList();
+
+ String envs = System.getenv(PYCHARM_PYTHON_ENVS);
+ if (envs != null) {
+ roots.addAll(Lists.newArrayList(envs.split(File.pathSeparator)));
+ }
+
+ String virtualEnvs = System.getenv(PYCHARM_PYTHON_VIRTUAL_ENVS);
+
+ if (virtualEnvs != null) {
+ roots.addAll(readVirtualEnvRoots(virtualEnvs));
+ }
+ return roots;
+ }
+
+ protected static List<String> readVirtualEnvRoots(@NotNull String envs) {
+ List<String> result = Lists.newArrayList();
+ String[] roots = envs.split(File.pathSeparator);
+ for (String root : roots) {
+ File virtualEnvRoot = new File(root);
+ File[] virtualenvs = virtualEnvRoot.listFiles();
+ if (virtualenvs != null) {
+ for (File f : virtualenvs) {
+ result.add(f.getAbsolutePath());
+ }
+ } else {
+ LOG.error(root + " is not a directory of doesn't exist");
+ }
+ }
+
+ return result;
+ }
+
+ public static List<String> loadEnvTags(String env) {
+ List<String> envTags;
+
+ try {
+ File parent = new File(env);
+ if (parent.isFile()) {
+ parent = parent.getParentFile();
+ }
+ envTags = com.intellij.openapi.util.io.FileUtil.loadLines(new File(parent, TAGS_FILE));
+ }
+ catch (IOException e) {
+ envTags = Lists.newArrayList();
+ }
+ return envTags;
+ }
+
+ public static String joinStrings(Collection<String> roots, String rootsName) {
+ return roots.size() > 0 ? rootsName + StringUtil.join(roots, ", ") + "\n" : "";
+ }
+}
+
diff --git a/python/testSrc/com/jetbrains/env/PyExecutionFixtureTestTask.java b/python/testSrc/com/jetbrains/env/PyExecutionFixtureTestTask.java
new file mode 100644
index 000000000000..bdb426dde301
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/PyExecutionFixtureTestTask.java
@@ -0,0 +1,174 @@
+package com.jetbrains.env;
+
+import com.google.common.collect.Lists;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.ide.util.projectWizard.EmptyModuleBuilder;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.ModuleTypeManager;
+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.testFramework.LightProjectDescriptor;
+import com.intellij.testFramework.builders.ModuleFixtureBuilder;
+import com.intellij.testFramework.fixtures.*;
+import com.intellij.testFramework.fixtures.impl.ModuleFixtureBuilderImpl;
+import com.intellij.testFramework.fixtures.impl.ModuleFixtureImpl;
+import com.intellij.util.ui.UIUtil;
+import com.jetbrains.python.PythonModuleTypeBase;
+import com.jetbrains.python.PythonTestUtil;
+import com.jetbrains.python.sdk.InvalidSdkException;
+import com.jetbrains.python.sdkTools.PyTestSdkTools;
+import com.jetbrains.python.sdkTools.SdkCreationType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Assert;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author traff
+ */
+public abstract class PyExecutionFixtureTestTask extends PyTestTask {
+ public static final int NORMAL_TIMEOUT = 30000;
+ public static final int LONG_TIMEOUT = 120000;
+ protected int myTimeout = NORMAL_TIMEOUT;
+ protected CodeInsightTestFixture myFixture;
+
+ public Project getProject() {
+ return myFixture.getProject();
+ }
+
+ public void useNormalTimeout() {
+ myTimeout = NORMAL_TIMEOUT;
+ }
+
+ public void useLongTimeout() {
+ myTimeout = LONG_TIMEOUT;
+ }
+
+ public void setUp(final String testName) throws Exception {
+ initFixtureBuilder();
+
+ final TestFixtureBuilder<IdeaProjectTestFixture> fixtureBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(
+ testName);
+
+ myFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(fixtureBuilder.getFixture());
+
+ UIUtil.invokeAndWaitIfNeeded(
+ new Runnable() {
+ @Override
+ public void run() {
+ ModuleFixtureBuilder moduleFixtureBuilder = fixtureBuilder.addModule(MyModuleFixtureBuilder.class);
+ moduleFixtureBuilder.addSourceContentRoot(myFixture.getTempDirPath());
+ moduleFixtureBuilder.addSourceContentRoot(getTestDataPath());
+ final List<String> contentRoots = getContentRoots();
+ for (String contentRoot : contentRoots) {
+ moduleFixtureBuilder.addContentRoot(getTestDataPath() + contentRoot);
+ }
+ }
+ }
+ );
+
+
+ myFixture.setUp();
+ myFixture.setTestDataPath(getTestDataPath());
+ }
+
+ protected List<String> getContentRoots() {
+ return Lists.newArrayList();
+ }
+
+ protected String getTestDataPath() {
+ return PythonTestUtil.getTestDataPath();
+ }
+
+ protected void initFixtureBuilder() {
+ IdeaTestFixtureFactory.getFixtureFactory().registerFixtureBuilder(MyModuleFixtureBuilder.class, MyModuleFixtureBuilderImpl.class);
+ }
+
+ public void tearDown() throws Exception {
+ if (myFixture != null) {
+ myFixture.tearDown();
+ myFixture = null;
+ }
+ }
+
+ @Nullable
+ protected LightProjectDescriptor getProjectDescriptor() {
+ return null;
+ }
+
+ protected void disposeProcess(ProcessHandler h) throws InterruptedException {
+ h.destroyProcess();
+ if (!waitFor(h)) {
+ new Throwable("Can't stop process").printStackTrace();
+ }
+ }
+
+ protected boolean waitFor(ProcessHandler p) throws InterruptedException {
+ return p.waitFor(myTimeout);
+ }
+
+ protected boolean waitFor(@NotNull Semaphore s) throws InterruptedException {
+ return waitFor(s, myTimeout);
+ }
+
+ protected static boolean waitFor(@NotNull Semaphore s, long timeout) throws InterruptedException {
+ return s.tryAcquire(timeout, TimeUnit.MILLISECONDS);
+ }
+
+ public static class MyModuleFixtureBuilderImpl extends ModuleFixtureBuilderImpl<ModuleFixture> implements MyModuleFixtureBuilder {
+ public MyModuleFixtureBuilderImpl(TestFixtureBuilder<? extends IdeaProjectTestFixture> fixtureBuilder) {
+ super(new PlatformPythonModuleType(), fixtureBuilder);
+ }
+
+ @Override
+ protected ModuleFixture instantiateFixture() {
+ return new ModuleFixtureImpl(this);
+ }
+ }
+
+ public static class PlatformPythonModuleType extends PythonModuleTypeBase<EmptyModuleBuilder> {
+ @NotNull
+ public static PlatformPythonModuleType getInstance() {
+ return (PlatformPythonModuleType)ModuleTypeManager.getInstance().findByID(PYTHON_MODULE);
+ }
+
+
+ @NotNull
+ @Override
+ public EmptyModuleBuilder createModuleBuilder() {
+ return new EmptyModuleBuilder() {
+ @Override
+ public ModuleType getModuleType() {
+ return getInstance();
+ }
+ };
+ }
+ }
+
+
+ /**
+ * Creates SDK by its path
+ *
+ * @param sdkHome path to sdk (probably obtained by {@link #runTestOn(String)})
+ * @param sdkCreationType SDK creation strategy (see {@link com.jetbrains.python.sdkTools.SdkCreationType} doc)
+ * @return sdk
+ */
+ @NotNull
+ protected Sdk createTempSdk(@NotNull final String sdkHome, @NotNull final SdkCreationType sdkCreationType)
+ throws InvalidSdkException, IOException {
+ final VirtualFile sdkHomeFile = LocalFileSystem.getInstance().findFileByPath(sdkHome);
+ Assert.assertNotNull("Interpreter file not found: " + sdkHome, sdkHomeFile);
+ return PyTestSdkTools.createTempSdk(sdkHomeFile, sdkCreationType, myFixture.getModule());
+ }
+
+
+ public interface MyModuleFixtureBuilder extends ModuleFixtureBuilder<ModuleFixture> {
+
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/PyTestTask.java b/python/testSrc/com/jetbrains/env/PyTestTask.java
new file mode 100644
index 000000000000..bfc1a688ebfa
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/PyTestTask.java
@@ -0,0 +1,81 @@
+package com.jetbrains.env;
+
+import com.google.common.collect.Sets;
+import com.intellij.openapi.util.io.FileUtil;
+
+import java.util.Set;
+
+/**
+ * @author traff
+ */
+public abstract class PyTestTask {
+ private String myWorkingFolder;
+ private String myScriptName;
+ private String myScriptParameters;
+
+ public void setWorkingFolder(String workingFolder) {
+ myWorkingFolder = workingFolder;
+ }
+
+ public void setScriptName(String scriptName) {
+ myScriptName = scriptName;
+ }
+
+ public void setScriptParameters(String scriptParameters) {
+ myScriptParameters = scriptParameters;
+ }
+
+ public void setUp(String testName) throws Exception {
+ }
+
+ public void tearDown() throws Exception {
+ }
+
+ /**
+ * Run test on certain SDK path.
+ * To create SDK from path, use {@link PyExecutionFixtureTestTask#createTempSdk(String, com.jetbrains.python.sdkTools.SdkCreationType)}
+ *
+ * @param sdkHome sdk path
+ */
+ public abstract void runTestOn(String sdkHome) throws Exception;
+
+ public void before() throws Exception {
+ }
+
+ public void testing() throws Exception {
+ }
+
+ public void after() throws Exception {
+ }
+
+ public void useNormalTimeout() {
+ }
+
+ public void useLongTimeout() {
+ }
+
+ public String getScriptName() {
+ return myScriptName;
+ }
+
+ public String getScriptPath() {
+ return getFilePath(myScriptName);
+ }
+
+ public String getFilePath(String scriptName) {
+ return FileUtil
+ .toSystemDependentName(myWorkingFolder.endsWith("/") ? myWorkingFolder + scriptName : myWorkingFolder + "/" + scriptName);
+ }
+
+ public String getScriptParameters() {
+ return myScriptParameters;
+ }
+
+ public String getWorkingFolder() {
+ return myWorkingFolder;
+ }
+
+ public Set<String> getTags() {
+ return Sets.newHashSet();
+ }
+}
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());
+ }
+ });
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/ut/PyDocTestTask.java b/python/testSrc/com/jetbrains/env/ut/PyDocTestTask.java
new file mode 100644
index 000000000000..e8228d767287
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/ut/PyDocTestTask.java
@@ -0,0 +1,24 @@
+package com.jetbrains.env.ut;
+
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.openapi.project.Project;
+import com.jetbrains.python.testing.PythonTestConfigurationType;
+
+/**
+ * User : catherine
+ */
+public abstract class PyDocTestTask extends PyUnitTestTask {
+ public PyDocTestTask(String workingFolder, String scriptName, String scriptParameters) {
+ super(workingFolder, scriptName, scriptParameters);
+ }
+
+ public PyDocTestTask(String workingFolder, String scriptName) {
+ this(workingFolder, scriptName, null);
+ }
+
+ public void runTestOn(String sdkHome) throws Exception {
+ final Project project = getProject();
+ final ConfigurationFactory factory = PythonTestConfigurationType.getInstance().PY_DOCTEST_FACTORY;
+ runConfiguration(factory, sdkHome, project);
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/ut/PyNoseTestTask.java b/python/testSrc/com/jetbrains/env/ut/PyNoseTestTask.java
new file mode 100644
index 000000000000..e130dd5717a4
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/ut/PyNoseTestTask.java
@@ -0,0 +1,32 @@
+package com.jetbrains.env.ut;
+
+import com.google.common.collect.ImmutableSet;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.openapi.project.Project;
+import com.jetbrains.python.testing.PythonTestConfigurationType;
+
+import java.util.Set;
+
+/**
+ * User : catherine
+ */
+public abstract class PyNoseTestTask extends PyUnitTestTask {
+ public PyNoseTestTask(String workingFolder, String scriptName, String scriptParameters) {
+ super(workingFolder, scriptName, scriptParameters);
+ }
+
+ public PyNoseTestTask(String workingFolder, String scriptName) {
+ this(workingFolder, scriptName, null);
+ }
+
+ public void runTestOn(String sdkHome) throws Exception {
+ final Project project = getProject();
+ final ConfigurationFactory factory = PythonTestConfigurationType.getInstance().PY_NOSETEST_FACTORY;
+ runConfiguration(factory, sdkHome, project);
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("nose");
+ }
+}
diff --git a/python/testSrc/com/jetbrains/env/ut/PyTestTestTask.java b/python/testSrc/com/jetbrains/env/ut/PyTestTestTask.java
new file mode 100644
index 000000000000..1e4261188206
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/ut/PyTestTestTask.java
@@ -0,0 +1,40 @@
+package com.jetbrains.env.ut;
+
+import com.google.common.collect.ImmutableSet;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.openapi.project.Project;
+import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
+import com.jetbrains.python.testing.PythonTestConfigurationType;
+import com.jetbrains.python.testing.pytest.PyTestRunConfiguration;
+
+import java.util.Set;
+
+/**
+ * User : catherine
+ */
+public abstract class PyTestTestTask extends PyUnitTestTask {
+ public PyTestTestTask(String workingFolder, String scriptName, String scriptParameters) {
+ super(workingFolder, scriptName, scriptParameters);
+ }
+
+ public PyTestTestTask(String workingFolder, String scriptName) {
+ this(workingFolder, scriptName, null);
+ }
+
+ public void runTestOn(String sdkHome) throws Exception {
+ final Project project = getProject();
+ final ConfigurationFactory factory = PythonTestConfigurationType.getInstance().PY_PYTEST_FACTORY;
+ runConfiguration(factory, sdkHome, project);
+ }
+
+ @Override
+ public Set<String> getTags() {
+ return ImmutableSet.of("pytest");
+ }
+
+ protected void configure(AbstractPythonTestRunConfiguration config) {
+ if (config instanceof PyTestRunConfiguration)
+ ((PyTestRunConfiguration)config).setTestToRun(getScriptPath());
+ }
+
+}
diff --git a/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java b/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java
new file mode 100644
index 000000000000..01401ca1ca9a
--- /dev/null
+++ b/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java
@@ -0,0 +1,241 @@
+package com.jetbrains.env.ut;
+
+import com.google.common.collect.Lists;
+import com.intellij.execution.*;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.executors.DefaultRunExecutor;
+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.execution.runners.ExecutionEnvironmentBuilder;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.execution.testframework.Filter;
+import com.intellij.execution.testframework.sm.runner.SMTestProxy;
+import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView;
+import com.intellij.execution.testframework.sm.runner.ui.TestResultsViewer;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.WriteAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Key;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.xdebugger.XDebuggerTestUtil;
+import com.jetbrains.env.PyExecutionFixtureTestTask;
+import com.jetbrains.python.sdk.PythonEnvUtil;
+import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
+import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
+import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
+import com.jetbrains.python.testing.PythonTestConfigurationType;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+/**
+ * @author traff
+ */
+public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask {
+
+ protected ProcessHandler myProcessHandler;
+ private boolean shouldPrintOutput = false;
+ private SMTestProxy.SMRootTestProxy myTestProxy;
+ private boolean mySetUp = false;
+ private SMTRunnerConsoleView myConsoleView;
+ private RunContentDescriptor myDescriptor;
+ private StringBuilder myOutput;
+
+ public PyUnitTestTask() {
+ }
+
+ public PyUnitTestTask(String workingFolder, String scriptName, String scriptParameters) {
+ setWorkingFolder(getTestDataPath() + workingFolder);
+ setScriptName(scriptName);
+ setScriptParameters(scriptParameters);
+ }
+
+ public PyUnitTestTask(String workingFolder, String scriptName) {
+ this(workingFolder, scriptName, null);
+ }
+
+ @Override
+ public void setUp(final String testName) throws Exception {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (myFixture == null) {
+ PyUnitTestTask.super.setUp(testName);
+ mySetUp = true;
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ @NotNull
+ protected String output() {
+ return myOutput.toString();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (mySetUp) {
+ if (myConsoleView != null) {
+ Disposer.dispose(myConsoleView);
+ myConsoleView = null;
+ }
+ if (myDescriptor != null) {
+ Disposer.dispose(myDescriptor);
+ myDescriptor = null;
+ }
+
+
+ PyUnitTestTask.super.tearDown();
+
+ mySetUp = false;
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ );
+ }
+
+ @Override
+ public void runTestOn(String sdkHome) throws Exception {
+ final Project project = getProject();
+ final ConfigurationFactory factory = PythonTestConfigurationType.getInstance().PY_UNITTEST_FACTORY;
+ runConfiguration(factory, sdkHome, project);
+ }
+
+ protected void runConfiguration(ConfigurationFactory factory, String sdkHome, final Project project) throws Exception {
+ final RunnerAndConfigurationSettings settings =
+ RunManager.getInstance(project).createRunConfiguration("test", factory);
+
+ AbstractPythonTestRunConfiguration config = (AbstractPythonTestRunConfiguration)settings.getConfiguration();
+
+
+ config.setSdkHome(sdkHome);
+ config.setScriptName(getScriptPath());
+ config.setWorkingDirectory(getWorkingFolder());
+
+ PythonSdkFlavor sdk = PythonSdkFlavor.getFlavor(sdkHome);
+
+
+ if (sdk instanceof JythonSdkFlavor) {
+ config.setInterpreterOptions(JythonSdkFlavor.getPythonPathCmdLineArgument(Lists.<String>newArrayList(getWorkingFolder())));
+ }
+ else {
+ PythonEnvUtil.addToPythonPath(config.getEnvs(), getWorkingFolder());
+ }
+
+
+ configure(config);
+
+ new WriteAction() {
+ @Override
+ protected void run(@NotNull Result result) throws Throwable {
+ RunManagerEx.getInstanceEx(project).addConfiguration(settings, false);
+ RunManagerEx.getInstanceEx(project).setSelectedConfiguration(settings);
+ Assert.assertSame(settings, RunManagerEx.getInstanceEx(project).getSelectedConfiguration());
+ }
+ }.execute();
+
+ final ExecutionEnvironment environment = ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), settings).build();
+ //noinspection ConstantConditions
+ Assert.assertTrue(environment.getRunner().canRun(DefaultRunExecutor.EXECUTOR_ID, config));
+
+ before();
+
+ final com.intellij.util.concurrency.Semaphore s = new com.intellij.util.concurrency.Semaphore();
+ s.down();
+
+ myOutput = new StringBuilder();
+
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ environment.getRunner().execute(environment, new ProgramRunner.Callback() {
+ @Override
+ public void processStarted(RunContentDescriptor descriptor) {
+ myDescriptor = descriptor;
+ myProcessHandler = myDescriptor.getProcessHandler();
+ myProcessHandler.addProcessListener(new ProcessAdapter() {
+ @Override
+ public void onTextAvailable(ProcessEvent event, Key outputType) {
+ myOutput.append(event.getText());
+ }
+ });
+ myConsoleView = (com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView)descriptor.getExecutionConsole();
+ myTestProxy = myConsoleView.getResultsViewer().getTestsRootNode();
+ myConsoleView.getResultsViewer().addEventsListener(new TestResultsViewer.SMEventsAdapter() {
+ @Override
+ public void onTestingFinished(TestResultsViewer sender) {
+ s.up();
+ }
+ });
+ }
+ });
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ Assert.assertTrue(s.waitFor(60000));
+
+ XDebuggerTestUtil.waitForSwing();
+
+ assertFinished();
+
+ Assert.assertTrue(output(), allTestsCount() > 0);
+
+ after();
+
+ disposeProcess(myProcessHandler);
+ }
+
+ protected void configure(AbstractPythonTestRunConfiguration config) {
+ }
+
+ public void allTestsPassed() {
+ Assert.assertEquals(output(), 0, myTestProxy.getChildren(Filter.NOT_PASSED).size());
+ Assert.assertEquals(output(), 0, failedTestsCount());
+ }
+
+ public int failedTestsCount() {
+ return myTestProxy.collectChildren(NOT_SUIT.and(Filter.FAILED_OR_INTERRUPTED)).size();
+ }
+
+ public int passedTestsCount() {
+ return myTestProxy.collectChildren(NOT_SUIT.and(Filter.PASSED)).size();
+ }
+
+ public void assertFinished() {
+ Assert.assertTrue("State is " + myTestProxy.getMagnitudeInfo().getTitle() + "\n" + output(),
+ myTestProxy.wasLaunched() && !myTestProxy.wasTerminated());
+ }
+
+ public int allTestsCount() {
+ return myTestProxy.collectChildren(NOT_SUIT).size();
+ }
+
+ public static final Filter<SMTestProxy> NOT_SUIT = new Filter<SMTestProxy>() {
+ @Override
+ public boolean shouldAccept(SMTestProxy test) {
+ return !test.isSuite();
+ }
+ };
+}
diff --git a/python/testSrc/com/jetbrains/python/PyAddImportTest.java b/python/testSrc/com/jetbrains/python/PyAddImportTest.java
index 01f83847aa56..f95187aff819 100644
--- a/python/testSrc/com/jetbrains/python/PyAddImportTest.java
+++ b/python/testSrc/com/jetbrains/python/PyAddImportTest.java
@@ -17,8 +17,13 @@ package com.jetbrains.python;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.psi.PsiPolyVariantReference;
import com.jetbrains.python.codeInsight.imports.AddImportHelper;
+import com.jetbrains.python.fixtures.PyResolveTestCase;
import com.jetbrains.python.fixtures.PyTestCase;
+import com.jetbrains.python.psi.PyElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* @author yole
@@ -53,4 +58,46 @@ public class PyAddImportTest extends PyTestCase {
}.execute();
myFixture.checkResultByFile("addImport/" + getTestName(true) + ".after.py");
}
+
+ // PY-6020
+ public void testLocalFromImport() {
+ doAddLocalImport("foo", "package.module");
+ }
+
+ // PY-6020
+ public void testLocalImport() {
+ doAddLocalImport("module", null);
+ }
+
+ // PY-13668
+ public void testLocalImportInlineFunctionBody() {
+ testLocalImport();
+ }
+
+ // PY-13668
+ public void testLocalImportInlineBranch() {
+ testLocalImport();
+ }
+
+ /**
+ * Add local import statement
+ * @param name reference name in corresponding import element
+ * @param qualifier if not {@code null} form {@code from qualifier import name} will be used, otherwise {@code import name}
+ */
+ private void doAddLocalImport(@NotNull final String name, @Nullable final String qualifier) {
+ myFixture.configureByFile("addImport/" + getTestName(true) + ".py");
+ new WriteCommandAction(myFixture.getProject(), myFixture.getFile()) {
+ @Override
+ protected void run(Result result) throws Throwable {
+ final PsiPolyVariantReference reference = PyResolveTestCase.findReferenceByMarker(myFixture.getFile());
+ if (qualifier != null) {
+ AddImportHelper.addLocalFromImportStatement((PyElement)reference.getElement(), qualifier, name);
+ }
+ else {
+ AddImportHelper.addLocalImportStatement((PyElement)reference.getElement(), name);
+ }
+ }
+ }.execute();
+ myFixture.checkResultByFile("addImport/" + getTestName(true) + ".after.py");
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java
index 88243f065a3b..b0e41bcffddc 100644
--- a/python/testSrc/com/jetbrains/python/PyTypeTest.java
+++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java
@@ -829,6 +829,12 @@ public class PyTypeTest extends PyTestCase {
" pass\n");
}
+ // PY-12801
+ public void testTupleConcatenation() {
+ doTest("(int, bool, str)",
+ "expr = (1,) + (True, 'spam') + ()");
+ }
+
private static TypeEvalContext getTypeEvalContext(@NotNull PyExpression element) {
return TypeEvalContext.userInitiated(element.getContainingFile()).withTracing();
}
diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java
index f365eea4da34..a1366ac2e17a 100644
--- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java
@@ -626,23 +626,85 @@ public class PythonCompletionTest extends PyTestCase {
}
// PY-4073
- public void testSpecialFunctionAttributes() throws Exception {
- setLanguageLevel(LanguageLevel.PYTHON27);
- try {
- List<String> suggested = doTestByText("def func(): pass; func.func_<caret>");
- assertNotNull(suggested);
- assertContainsElements(suggested,
- "func_defaults", "func_globals", "func_closure",
- "func_code", "func_name", "func_doc", "func_dict");
-
- suggested = doTestByText("def func(): pass; func.__<caret>");
- assertNotNull(suggested);
- assertContainsElements(suggested, "__defaults__", "__globals__", "__closure__",
- "__code__", "__name__", "__doc__", "__dict__", "__module__");
- assertDoesntContain(suggested, "__annotations__", "__kwdefaults__");
- }
- finally {
- setLanguageLevel(null);
- }
+ public void testFunctionSpecialAttributes() {
+ runWithLanguageLevel(LanguageLevel.PYTHON27, new Runnable() {
+ @Override
+ public void run() {
+ List<String> suggested = doTestByText("def func(): pass; func.func_<caret>");
+ assertNotNull(suggested);
+ assertContainsElements(suggested, PyNames.LEGACY_FUNCTION_SPECIAL_ATTRIBUTES);
+
+ suggested = doTestByText("def func(): pass; func.__<caret>");
+ assertNotNull(suggested);
+ assertContainsElements(suggested, PyNames.FUNCTION_SPECIAL_ATTRIBUTES);
+ assertDoesntContain(suggested, PyNames.PY3_ONLY_FUNCTION_SPECIAL_ATTRIBUTES);
+ }
+ });
+ }
+
+ // PY-9342
+ public void testBoundMethodSpecialAttributes() {
+ List<String> suggested = doTestByText("{}.update.im_<caret>");
+ assertNotNull(suggested);
+ assertContainsElements(suggested, PyNames.LEGACY_METHOD_SPECIAL_ATTRIBUTES);
+
+ suggested = doTestByText("{}.update.__<caret>");
+ assertNotNull(suggested);
+ assertContainsElements(suggested, PyNames.METHOD_SPECIAL_ATTRIBUTES);
+ assertDoesntContain(suggested, PyNames.FUNCTION_SPECIAL_ATTRIBUTES);
+ }
+
+ // PY-9342
+ public void testWeakQualifierBoundMethodAttributes() {
+ assertUnderscoredMethodSpecialAttributesSuggested();
+ }
+
+ private void assertUnderscoredMethodSpecialAttributesSuggested() {
+ myFixture.configureByFile("completion/" + getTestName(true) + ".py");
+ myFixture.completeBasic();
+ final List<String> suggested = myFixture.getLookupElementStrings();
+ assertNotNull(suggested);
+ assertContainsElements(suggested, PyNames.METHOD_SPECIAL_ATTRIBUTES);
+ assertDoesntContain(suggested, PyNames.FUNCTION_SPECIAL_ATTRIBUTES);
+ }
+
+ // PY-9342
+ public void testUnboundMethodSpecialAttributes() {
+ runWithLanguageLevel(LanguageLevel.PYTHON27, new Runnable() {
+ @Override
+ public void run() {
+ assertUnderscoredMethodSpecialAttributesSuggested();
+ }
+ });
+ runWithLanguageLevel(LanguageLevel.PYTHON32, new Runnable() {
+ @Override
+ public void run() {
+ assertUnderscoredFunctionAttributesSuggested();
+ }
+ });
+ }
+
+ // PY-9342
+ public void testStaticMethodSpecialAttributes() {
+ assertUnderscoredFunctionAttributesSuggested();
+ }
+
+ // PY-9342
+ public void testLambdaSpecialAttributes() {
+ assertUnderscoredFunctionAttributesSuggested();
+ }
+
+ // PY-9342
+ public void testReassignedMethodSpecialAttributes() {
+ assertUnderscoredMethodSpecialAttributesSuggested();
+ }
+
+ private void assertUnderscoredFunctionAttributesSuggested() {
+ myFixture.configureByFile("completion/" + getTestName(true) + ".py");
+ myFixture.completeBasic();
+ final List<String> suggested = myFixture.getLookupElementStrings();
+ assertNotNull(suggested);
+ assertContainsElements(suggested, PyNames.FUNCTION_SPECIAL_ATTRIBUTES);
+ assertDoesntContain(suggested, PyNames.METHOD_SPECIAL_ATTRIBUTES);
}
}
diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java
index bbaf31252c3e..65815c112b2e 100644
--- a/python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java
+++ b/python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java
@@ -20,16 +20,15 @@ import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.configurations.ConfigurationType;
-import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.executors.DefaultRunExecutor;
-import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.openapi.project.Project;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.debugger.PyDebugRunner;
import com.jetbrains.python.run.AbstractPythonRunConfiguration;
import com.jetbrains.python.run.PythonCommandLineState;
+import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -59,11 +58,9 @@ public abstract class PyCommandLineTestCase extends PyTestCase {
protected List<String> buildRunCommandLine(AbstractPythonRunConfiguration configuration) {
try {
- final Executor executor = DefaultRunExecutor.getRunExecutorInstance();
- ExecutionEnvironment env = new ExecutionEnvironmentBuilder(myFixture.getProject(), executor).setRunProfile(configuration).build();
- final PythonCommandLineState state = (PythonCommandLineState)configuration.getState(executor, env);
- final GeneralCommandLine generalCommandLine = state.generateCommandLine();
- return generalCommandLine.getParametersList().getList();
+ PythonCommandLineState state = getState(configuration, DefaultRunExecutor.getRunExecutorInstance());
+ assert state != null;
+ return state.generateCommandLine().getParametersList().getList();
}
catch (ExecutionException e) {
throw new RuntimeException(e);
@@ -72,15 +69,21 @@ public abstract class PyCommandLineTestCase extends PyTestCase {
protected List<String> buildDebugCommandLine(AbstractPythonRunConfiguration configuration) {
try {
- final Executor executor = DefaultDebugExecutor.getDebugExecutorInstance();
- ExecutionEnvironment env = new ExecutionEnvironmentBuilder(myFixture.getProject(), executor).setRunProfile(configuration).build();
- final PythonCommandLineState state = (PythonCommandLineState)configuration.getState(executor, env);
- final GeneralCommandLine generalCommandLine =
- state.generateCommandLine(PyDebugRunner.createCommandLinePatchers(configuration.getProject(), state, configuration, PORT));
- return generalCommandLine.getParametersList().getList();
+ PythonCommandLineState state = getState(configuration, DefaultDebugExecutor.getDebugExecutorInstance());
+ assert state != null;
+ return state.generateCommandLine(PyDebugRunner.createCommandLinePatchers(configuration.getProject(), state, configuration, PORT))
+ .getParametersList()
+ .getList();
}
catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
+
+
+ private static PythonCommandLineState getState(@NotNull AbstractPythonRunConfiguration configuration, @NotNull Executor executor) throws ExecutionException {
+ return (PythonCommandLineState)ExecutionEnvironmentBuilder.create(executor, configuration)
+ .build()
+ .getState();
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
index 45d582a783a8..99da2a43aea1 100644
--- a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
+++ b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
@@ -18,6 +18,8 @@ package com.jetbrains.python.fixtures;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ex.QuickFixWrapper;
+import com.intellij.find.findUsages.CustomUsageSearcher;
+import com.intellij.find.findUsages.FindUsagesOptions;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
@@ -33,6 +35,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
+import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.PlatformTestCase;
import com.intellij.testFramework.TestDataPath;
@@ -42,6 +45,10 @@ import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import com.intellij.testFramework.fixtures.TestFixtureBuilder;
import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.usages.Usage;
+import com.intellij.usages.rules.PsiElementUsage;
+import com.intellij.util.CommonProcessors.CollectProcessor;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.PythonMockSdk;
import com.jetbrains.python.PythonModuleTypeBase;
@@ -55,6 +62,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
/**
* @author yole
@@ -184,6 +194,36 @@ public abstract class PyTestCase extends UsefulTestCase {
myFixture.getEditor().getCaretModel().moveToOffset(element.getTextOffset());
}
+ /**
+ * Finds all usages of element. Works much like method in {@link com.intellij.testFramework.fixtures.CodeInsightTestFixture#findUsages(com.intellij.psi.PsiElement)},
+ * but supports {@link com.intellij.find.findUsages.CustomUsageSearcher} and {@link com.intellij.psi.search.searches.ReferencesSearch} as well
+ *
+ * @param element what to find
+ * @return usages
+ */
+ @NotNull
+ protected Collection<PsiElement> findUsage(@NotNull final PsiElement element) {
+ final Collection<PsiElement> result = new ArrayList<PsiElement>();
+ final CollectProcessor<Usage> usageCollector = new CollectProcessor<Usage>();
+ for (final CustomUsageSearcher searcher : CustomUsageSearcher.EP_NAME.getExtensions()) {
+ searcher.processElementUsages(element, usageCollector, new FindUsagesOptions(myFixture.getProject()));
+ }
+ for (final Usage usage : usageCollector.getResults()) {
+ if (usage instanceof PsiElementUsage) {
+ result.add(((PsiElementUsage)usage).getElement());
+ }
+ }
+ for (final PsiReference reference : ReferencesSearch.search(element).findAll()) {
+ result.add(reference.getElement());
+ }
+
+ for (final UsageInfo info : myFixture.findUsages(element)) {
+ result.add(info.getElement());
+ }
+
+ return result;
+ }
+
protected static class PyLightProjectDescriptor implements LightProjectDescriptor {
private final String myPythonVersion;
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
index a0a2a1232b2e..3451712f6bcd 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
@@ -371,6 +371,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase {
doMultiFileTest();
}
+ // PY-9342
+ public void testMethodSpecialAttributes() {
+ doTest();
+ }
+
// PY-11472
public void testUnusedImportBeforeStarImport() {
doMultiFileTest();
diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceConstantTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceConstantTest.java
index 769e72077461..a54c68a0db09 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceConstantTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceConstantTest.java
@@ -51,7 +51,7 @@ public class PyIntroduceConstantTest extends PyIntroduceTestCase {
public void testSuggestUniqueNames() { // PY-4409
doTestSuggestions(PyExpression.class, "S1");
}
-
+
public void testSuggestUniqueNamesGlobalScope() { // PY-4409
doTestSuggestions(PyExpression.class, "S1");
}
@@ -60,6 +60,11 @@ public class PyIntroduceConstantTest extends PyIntroduceTestCase {
doTestInplace(null);
}
+ // PY-13484
+ public void testFromParameterDefaultValue() {
+ doTest();
+ }
+
@Override
protected String getTestDataPath() {
return super.getTestDataPath() + "/refactoring/introduceConstant";
diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java
index f2117977cbf3..33a191f2b9a0 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java
@@ -245,6 +245,8 @@ public class PyIntroduceVariableTest extends PyIntroduceTestCase {
}
}
+ public void testSelectionBreaksBinaryOperator() {doTest();}
+
private void doTestCannotPerform() {
boolean thrownExpectedException = false;
try {
diff --git a/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java b/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java
new file mode 100644
index 000000000000..2d97e747f00b
--- /dev/null
+++ b/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java
@@ -0,0 +1,142 @@
+package com.jetbrains.python.sdkTools;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkModificator;
+import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
+import com.intellij.openapi.roots.ModuleRootModificationUtil;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.UsefulTestCase;
+import com.jetbrains.python.sdk.InvalidSdkException;
+import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher;
+import com.jetbrains.python.sdk.skeletons.SkeletonVersionChecker;
+import org.hamcrest.Matchers;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Engine to create SDK for tests.
+ * See {@link #createTempSdk(com.intellij.openapi.vfs.VirtualFile, SdkCreationType, com.intellij.openapi.module.Module)}
+ *
+ * @author Ilya.Kazakevich
+ */
+public final class PyTestSdkTools {
+
+ private static final Sdk[] NO_SDK = new Sdk[0];
+
+ private PyTestSdkTools() {
+
+ }
+
+ /**
+ * Creates SDK by its path and associates it with module.
+ *
+ * @param sdkHome path to sdk
+ * @param sdkCreationType SDK creation strategy (see {@link SdkCreationType} doc)
+ * @return sdk
+ */
+ @NotNull
+ public static Sdk createTempSdk(@NotNull final VirtualFile sdkHome,
+ @NotNull final SdkCreationType sdkCreationType,
+ @NotNull final Module module
+ )
+ throws InvalidSdkException, IOException {
+ final Ref<Sdk> ref = Ref.create();
+ UsefulTestCase.edt(new Runnable() {
+
+ @Override
+ public void run() {
+ final Sdk sdk = SdkConfigurationUtil.setupSdk(NO_SDK, sdkHome, PythonSdkType.getInstance(), true, null, null);
+ Assert.assertNotNull("Failed to create SDK on " + sdkHome, sdk);
+ ref.set(sdk);
+ }
+ });
+ final Sdk sdk = ref.get();
+ if (sdkCreationType != SdkCreationType.EMPTY_SDK) {
+ generateTempSkeletonsOrPackages(sdk, sdkCreationType == SdkCreationType.SDK_PACKAGES_AND_SKELETONS, module);
+ }
+ UsefulTestCase.edt(new Runnable() {
+ @Override
+ public void run() {
+ SdkConfigurationUtil.addSdk(sdk);
+ }
+ });
+ return sdk;
+ }
+
+
+ /**
+ * Adds installed eggs to SDK, generates skeletons (optionally) and associates it with modle.
+ *
+ * @param sdk sdk to process
+ * @param addSkeletons add skeletons or only packages
+ * @param module module to associate with
+ * @throws InvalidSdkException bas sdk
+ * @throws IOException failed to read eggs
+ */
+ private static void generateTempSkeletonsOrPackages(@NotNull final Sdk sdk,
+ final boolean addSkeletons,
+ @NotNull final Module module)
+ throws InvalidSdkException, IOException {
+ final Project project = module.getProject();
+ ModuleRootModificationUtil.setModuleSdk(module, sdk);
+
+ UsefulTestCase.edt(new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ ProjectRootManager.getInstance(project).setProjectSdk(sdk);
+ }
+ });
+ }
+ });
+
+
+ final SdkModificator modificator = sdk.getSdkModificator();
+ modificator.removeRoots(OrderRootType.CLASSES);
+
+ for (final String path : PythonSdkType.getSysPathsFromScript(sdk.getHomePath())) {
+ PythonSdkType.addSdkRoot(modificator, path);
+ }
+ if (!addSkeletons) {
+ UsefulTestCase.edt(new Runnable() {
+ @Override
+ public void run() {
+ modificator.commitChanges();
+ }
+ });
+ return;
+ }
+
+ final File tempDir = FileUtil.createTempDirectory(PyTestSdkTools.class.getName(), null);
+ final File skeletonsDir = new File(tempDir, PythonSdkType.SKELETON_DIR_NAME);
+ FileUtil.createDirectory(skeletonsDir);
+ final String skeletonsPath = skeletonsDir.toString();
+ PythonSdkType.addSdkRoot(modificator, skeletonsPath);
+
+ UsefulTestCase.edt(new Runnable() {
+ @Override
+ public void run() {
+ modificator.commitChanges();
+ }
+ });
+
+ final SkeletonVersionChecker checker = new SkeletonVersionChecker(0);
+ final PySkeletonRefresher refresher = new PySkeletonRefresher(project, null, sdk, skeletonsPath, null, null);
+ final List<String> errors = refresher.regenerateSkeletons(checker, null);
+ Assert.assertThat("Errors found", errors, Matchers.empty());
+ }
+}
diff --git a/python/testSrc/com/jetbrains/python/sdkTools/SdkCreationType.java b/python/testSrc/com/jetbrains/python/sdkTools/SdkCreationType.java
new file mode 100644
index 000000000000..231f243f564e
--- /dev/null
+++ b/python/testSrc/com/jetbrains/python/sdkTools/SdkCreationType.java
@@ -0,0 +1,20 @@
+package com.jetbrains.python.sdkTools;
+
+/**
+ * SDK creation type
+ * @author Ilya.Kazakevich
+ */
+public enum SdkCreationType {
+ /**
+ * SDK only (no packages nor skeletons)
+ */
+ EMPTY_SDK,
+ /**
+ * SDK + installed packages from syspath
+ */
+ SDK_PACKAGES_ONLY,
+ /**
+ * SDK + installed packages from syspath + skeletons
+ */
+ SDK_PACKAGES_AND_SKELETONS
+}
diff --git a/python/testSrc/com/jetbrains/python/sdkTools/package-info.java b/python/testSrc/com/jetbrains/python/sdkTools/package-info.java
new file mode 100644
index 000000000000..8b8fb74b9167
--- /dev/null
+++ b/python/testSrc/com/jetbrains/python/sdkTools/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Engine to create SDK in tests.
+ * See {@link com.jetbrains.python.sdkTools.PyTestSdkTools}
+ * @author Ilya.Kazakevich
+ */
+package com.jetbrains.python.sdkTools; \ No newline at end of file