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