diff --git a/python/helpers/pycharm/_jb_runner_tools.py b/python/helpers/pycharm/_jb_runner_tools.py index e90998b2cc4f..ad13339f423f 100644 --- a/python/helpers/pycharm/_jb_runner_tools.py +++ b/python/helpers/pycharm/_jb_runner_tools.py @@ -20,9 +20,13 @@ def _parse_parametrized(part): Support nose generators / py.test parameters and other functions that provides names like foo(1,2) Until https://github.com/JetBrains/teamcity-messages/issues/121, all such tests are provided - with parentheses + with parentheses. + + Tests with docstring are reported in similar way but they have space before parenthesis and should be ignored + by this function + """ - match = re.match("^(.+)(\\(.+\\))$", part) + match = re.match("^([^\s)(]+)(\\(.+\\))$", part) if not match: return [part] else: @@ -164,7 +168,14 @@ class NewTeamcityServiceMessages(_old_service_messages): try: # Report directory so Java site knows which folder to resolve names against - properties["locationHint"] = "python<{0}>://{1}".format(os.getcwd(), properties["name"]) + + # tests with docstrings are reported in format "test.name (some test here)". + # text should be part of name, but not location. + possible_location = str(properties["name"]) + loc = possible_location.find("(") + if loc > 0: + possible_location = possible_location[:loc].strip() + properties["locationHint"] = "python<{0}>://{1}".format(os.getcwd(), possible_location) except KeyError: # If message does not have name, then it is not test # Simply pass it diff --git a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTests.kt b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTests.kt index 0206438bbe36..8a57be16ecd5 100644 --- a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTests.kt +++ b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTests.kt @@ -239,7 +239,7 @@ data class ConfigurationTarget(@ConfigField var target: String, @ConfigField var when (targetType) { TestTargetType.CUSTOM -> emptyList() TestTargetType.PYTHON -> getArgumentsForPythonTarget(configuration) - TestTargetType.PATH -> listOf("--path", target) + TestTargetType.PATH -> listOf("--path", target.trim()) } private fun getArgumentsForPythonTarget(configuration: PyUniversalTestConfiguration): List { @@ -258,7 +258,7 @@ data class ConfigurationTarget(@ConfigField var target: String, @ConfigField var folderToStart = LocalFileSystem.getInstance().findFileByPath(configuration.workingDirectorySafe), allowInaccurateResult = true ) - val qualifiedNameParts = QualifiedName.fromDottedString(target).tryResolveAndSplit(qNameResolveContext) ?: + val qualifiedNameParts = QualifiedName.fromDottedString(target.trim()).tryResolveAndSplit(qNameResolveContext) ?: throw ExecutionException("Can't find file where $target declared. " + "Make sure it is in project root") diff --git a/python/testData/testRunner/env/nose/generators/test_nose_generator.py b/python/testData/testRunner/env/nose/generators/test_nose_generator.py new file mode 100644 index 000000000000..2c0b81413123 --- /dev/null +++ b/python/testData/testRunner/env/nose/generators/test_nose_generator.py @@ -0,0 +1,6 @@ +def test_evens(): + for i in range(0, 5): + yield check_even, i, i*3 + +def check_even(n, nn): + assert n % 2 == 0 or nn % 2 == 0 \ No newline at end of file diff --git a/python/testData/testRunner/env/pytest/parametrized/test_pytest_parametrized.py b/python/testData/testRunner/env/pytest/parametrized/test_pytest_parametrized.py new file mode 100644 index 000000000000..fb6f14b442a9 --- /dev/null +++ b/python/testData/testRunner/env/pytest/parametrized/test_pytest_parametrized.py @@ -0,0 +1,8 @@ +import pytest +@pytest.mark.parametrize("test_input,expected", [ + ("three plus file", 8), + ("(2)+(4)", 6), + (" six times nine.", 42), +]) +def test_eval(test_input, expected): + assert eval(test_input) == expected \ No newline at end of file diff --git a/python/testData/testRunner/env/unit/withDocString/test_test.py b/python/testData/testRunner/env/unit/withDocString/test_test.py new file mode 100644 index 000000000000..54de439fcc89 --- /dev/null +++ b/python/testData/testRunner/env/unit/withDocString/test_test.py @@ -0,0 +1,10 @@ +from unittest import TestCase + +class SomeTestCase(TestCase): + def testSomething(self): + """ Only with docstring test is parsed with extra space""" + self.assertEqual(1 + 1, 2) + + def testSomethingBad(self): + """Fail""" + self.assertEqual(1 + 1, 3) diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonNoseTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonNoseTestingTest.java index 4d6f5de2c9ba..897c86609be5 100644 --- a/python/testSrc/com/jetbrains/env/python/testing/PythonNoseTestingTest.java +++ b/python/testSrc/com/jetbrains/env/python/testing/PythonNoseTestingTest.java @@ -6,7 +6,6 @@ import com.jetbrains.env.PyEnvTestCase; import com.jetbrains.env.PyProcessWithConsoleTestTask; import com.jetbrains.env.python.testing.CreateConfigurationTestTask.PyConfigurationCreationTask; import com.jetbrains.env.ut.PyNoseTestProcessRunner; -import com.jetbrains.env.ut.PyUnitTestProcessRunner; import com.jetbrains.python.sdkTools.SdkCreationType; import com.jetbrains.python.testing.PythonTestConfigurationsModel; import com.jetbrains.python.testing.universalTests.PyUniversalNoseTestConfiguration; @@ -25,6 +24,34 @@ import static org.junit.Assert.assertEquals; @EnvTestTagsRequired(tags = "nose") public final class PythonNoseTestingTest extends PyEnvTestCase { + + @Test + public void testNoseGenerators() { + runPythonTest(new PyProcessWithConsoleTestTask("/testRunner/env/nose/generators", SdkCreationType.EMPTY_SDK) { + @NotNull + @Override + protected PyNoseTestProcessRunner createProcessRunner() throws Exception { + return new PyNoseTestProcessRunner(toFullPath("test_nose_generator.py"), 1); + } + + @Override + protected void checkTestResults(@NotNull final PyNoseTestProcessRunner runner, + @NotNull final String stdout, + @NotNull final String stderr, + @NotNull final String all) { + Assert.assertEquals("Nose genenerator produced bad tree", "Test tree:\n" + + "[root]\n" + + ".test_nose_generator\n" + + "..test_evens\n" + + "...(0, 0)(+)\n" + + "...(1, 3)(-)\n" + + "...(2, 6)(+)\n" + + "...(3, 9)(-)\n" + + "...(4, 12)(+)\n", runner.getFormattedTestTree()); + } + }); + } + // Ensures setup/teardown does not break anything @Test public void testSetupTearDown() throws Exception { diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java index 8551ef5a4f10..a607e2a9e46a 100644 --- a/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java +++ b/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java @@ -77,6 +77,35 @@ public final class PythonPyTestingTest extends PyEnvTestCase { } + @Test + public void testParametrized() throws Exception { + runPythonTest( + new PyProcessWithConsoleTestTask("/testRunner/env/pytest/parametrized", SdkCreationType.EMPTY_SDK) { + + @NotNull + @Override + protected PyTestTestProcessRunner createProcessRunner() throws Exception { + return new PyTestTestProcessRunner("test_pytest_parametrized.py", 1); + } + + @Override + protected void checkTestResults(@NotNull final PyTestTestProcessRunner runner, + @NotNull final String stdout, + @NotNull final String stderr, + @NotNull final String all) { + Assert.assertEquals("Parametrized test produced bad tree", + "Test tree:\n" + + "[root]\n" + + ".test_pytest_parametrized\n" + + "..test_eval\n" + + "...(three plus file-8)(-)\n" + + "...((2)+(4)-6)(+)\n" + + "...( six times nine_-42)(-)\n", runner.getFormattedTestTree()); + } + }); + } + + // Ensure test survives patched strftime @Test public void testMonkeyPatch() throws Exception { diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java index 4a3d2438aa71..67cfc6e16a98 100644 --- a/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java +++ b/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java @@ -52,6 +52,45 @@ import static org.junit.Assert.assertEquals; public final class PythonUnitTestingTest extends PyEnvTestCase { + /** + * tests with docstrings are reported as "test.name (text)" by unittest. + */ + @Test + public void testWithDocString() throws Exception { + + runPythonTest(new PyUnitTestProcessWithConsoleTestTask("testRunner/env/unit/withDocString", "test_test.py") { + + @NotNull + @Override + protected PyUnitTestProcessRunner createProcessRunner() throws Exception { + return new PyUnitTestProcessRunner(toFullPath(myScriptName), 1); + } + + @Override + protected void checkTestResults(@NotNull final PyUnitTestProcessRunner runner, + @NotNull final String stdout, + @NotNull final String stderr, + @NotNull final String all) { + if (runner.getCurrentRerunStep() == 0) { + assertEquals("test with docstring produced bad tree", "Test tree:\n" + + "[root]\n" + + ".test_test\n" + + "..SomeTestCase\n" + + "...testSomething (Only with docstring test is parsed with extra space)(+)\n" + + "...testSomethingBad (Fail)(-)\n", runner.getFormattedTestTree()); + } + else { + assertEquals("test with docstring failed to rerun", + "Test tree:\n" + + "[root]\n" + + ".test_test\n" + + "..SomeTestCase\n" + + "...testSomethingBad (Fail)(-)\n", runner.getFormattedTestTree()); + } + } + }); + } + /** * subtest names may have dots and shall not break test tree */ @@ -71,22 +110,21 @@ public final class PythonUnitTestingTest extends PyEnvTestCase { @NotNull final String stdout, @NotNull final String stderr, @NotNull final String all) { - runner.getFormattedTestTree(); assertEquals("dots in subtest names broke output", "Test tree:\n" + - "[root]\n" + - ".test_test\n" + - "..SampleTest\n" + - "...test_sample\n" + - "....(i='0_0')(-)\n" + - "....(i='1_1')(-)\n" + - "....(i='2_2')(+)\n" + - "....(i='3_3')(+)\n" + - "....(i='4_4')(+)\n" + - "....(i='5_5')(+)\n" + - "....(i='6_6')(+)\n" + - "....(i='7_7')(+)\n" + - "....(i='8_8')(+)\n" + - "....(i='9_9')(+)\n", runner.getFormattedTestTree()); + "[root]\n" + + ".test_test\n" + + "..SampleTest\n" + + "...test_sample\n" + + "....(i='0_0')(-)\n" + + "....(i='1_1')(-)\n" + + "....(i='2_2')(+)\n" + + "....(i='3_3')(+)\n" + + "....(i='4_4')(+)\n" + + "....(i='5_5')(+)\n" + + "....(i='6_6')(+)\n" + + "....(i='7_7')(+)\n" + + "....(i='8_8')(+)\n" + + "....(i='9_9')(+)\n", runner.getFormattedTestTree()); } }); } @@ -109,20 +147,20 @@ public final class PythonUnitTestingTest extends PyEnvTestCase { @NotNull final String all) { runner.getFormattedTestTree(); assertEquals("unittest2 produced wrong tree", "Test tree:\n" + - "[root]\n" + - ".test_test\n" + - "..SampleTest\n" + - "...test_sample\n" + - "....(i=0)(-)\n" + - "....(i=1)(-)\n" + - "....(i=2)(-)\n" + - "....(i=3)(-)\n" + - "....(i=4)(+)\n" + - "....(i=5)(+)\n" + - "....(i=6)(+)\n" + - "....(i=7)(+)\n" + - "....(i=8)(+)\n" + - "....(i=9)(+)\n", runner.getFormattedTestTree()); + "[root]\n" + + ".test_test\n" + + "..SampleTest\n" + + "...test_sample\n" + + "....(i=0)(-)\n" + + "....(i=1)(-)\n" + + "....(i=2)(-)\n" + + "....(i=3)(-)\n" + + "....(i=4)(+)\n" + + "....(i=5)(+)\n" + + "....(i=6)(+)\n" + + "....(i=7)(+)\n" + + "....(i=8)(+)\n" + + "....(i=9)(+)\n", runner.getFormattedTestTree()); } }); }