diff --git a/python/src/com/jetbrains/python/testing/PyTestsShared.kt b/python/src/com/jetbrains/python/testing/PyTestsShared.kt index ef5a95496295..4b3df52a074b 100644 --- a/python/src/com/jetbrains/python/testing/PyTestsShared.kt +++ b/python/src/com/jetbrains/python/testing/PyTestsShared.kt @@ -59,6 +59,7 @@ import com.jetbrains.python.run.targetBasedConfiguration.TargetWithVariant import com.jetbrains.python.run.targetBasedConfiguration.createRefactoringListenerIfPossible import com.jetbrains.python.run.targetBasedConfiguration.targetAsPsiElement import com.jetbrains.python.sdk.PythonSdkUtil +import com.jetbrains.python.sdk.baseDir import com.jetbrains.python.testing.doctest.PythonDocTestUtil import jetbrains.buildServer.messages.serviceMessages.ServiceMessage import jetbrains.buildServer.messages.serviceMessages.TestStdErr @@ -801,7 +802,7 @@ internal class PyTestsConfigurationProducer : AbstractPythonTestConfigurationPro val module = configuration.module ?: return null val elementFile = element.containingFile as? PyFile ?: return null - val workingDirectory = getDirectoryForFileToBeImportedFrom(elementFile) ?: return null + val workingDirectory = getDirectoryForFileToBeImportedFrom(elementFile, module) ?: return null val context = QNameResolveContext(ModuleBasedContextAnchor(module), evalContext = TypeEvalContext.userInitiated(configuration.project, null), @@ -814,7 +815,7 @@ internal class PyTestsConfigurationProducer : AbstractPythonTestConfigurationPro val virtualFile = element.virtualFile val workingDirectory: VirtualFile = when (element) { - is PyFile -> getDirectoryForFileToBeImportedFrom(element)?.virtualFile + is PyFile -> getDirectoryForFileToBeImportedFrom(element, configuration.module)?.virtualFile is PsiDirectory -> virtualFile else -> return null } ?: return null @@ -828,11 +829,15 @@ internal class PyTestsConfigurationProducer : AbstractPythonTestConfigurationPro * Returns test root for this file. Either it is specified explicitly or calculated using following strategy: * Inspect file relative imports, find farthest and return folder with imported file */ - private fun getDirectoryForFileToBeImportedFrom(file: PyFile): PsiDirectory? { + private fun getDirectoryForFileToBeImportedFrom(file: PyFile, module: Module?): PsiDirectory? { getExplicitlyConfiguredTestRoot(file)?.let { return PsiManager.getInstance(file.project).findDirectory(it) } + module?.baseDir?.let { + return file.manager.findDirectory(it) + } + val maxRelativeLevel = file.fromImports.map { it.relativeLevel }.maxOrNull() ?: 0 var elementFolder = file.parent ?: return null for (i in 1..maxRelativeLevel) { diff --git a/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/pyproject.toml b/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/pyproject.toml new file mode 100644 index 000000000000..a9ffff9bd28d --- /dev/null +++ b/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/pyproject.toml @@ -0,0 +1 @@ +[tool.pytest.ini_options] \ No newline at end of file diff --git a/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/tests/conftest.py b/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/tests/conftest.py new file mode 100644 index 000000000000..03d54c9e27a6 --- /dev/null +++ b/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/tests/conftest.py @@ -0,0 +1,6 @@ +import pytest + + +@pytest.fixture +def myfixture(): + return 42 diff --git a/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/tests/subdir/test_test.py b/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/tests/subdir/test_test.py new file mode 100644 index 000000000000..bd8fa7576c54 --- /dev/null +++ b/python/testData/testRunner/env/createConfigurationTest/conftest_in_parent_dir/tests/subdir/test_test.py @@ -0,0 +1,2 @@ +def test_myfixture(myfixture): + assert myfixture == 42 diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java index 7c39f1bb546e..4416342042bc 100644 --- a/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java +++ b/python/testSrc/com/jetbrains/env/python/testing/PythonPyTestingTest.java @@ -33,6 +33,7 @@ import com.jetbrains.python.sdk.InvalidSdkException; import com.jetbrains.python.testing.*; import com.jetbrains.python.tools.sdkTools.SdkCreationType; import org.hamcrest.Matcher; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.jdom.Element; import org.jdom.JDOMException; @@ -653,6 +654,32 @@ public final class PythonPyTestingTest extends PyEnvTestCase { }); } + /** + * New configuration should have the module root as the working directory in the absence of an explicit test root + */ + @Test + public void testWorkDirIsModuleRoot() { + runPythonTest(new CreateConfigurationTestTask<>(getFrameworkId(), PyTestConfiguration.class) { + @NotNull + @Override + protected List getPsiElementsToRightClickOn() { + myFixture.configureByFile("conftest_in_parent_dir/tests/subdir/test_test.py"); + final PyFunction test = myFixture.findElementByText("test_myfixture", PyFunction.class); + assert test != null; + return Collections.singletonList(test); + } + + @Override + protected void checkConfiguration(@NotNull PyTestConfiguration configuration, @NotNull PsiElement elementToRightClickOn) { + super.checkConfiguration(configuration, elementToRightClickOn); + final String moduleRoot = myFixture.getTempDirPath(); + MatcherAssert.assertThat("Wrong configuration directory set on new config", + configuration.getWorkingDirectory(), + Matchers.equalTo(moduleRoot)); + } + }); + } + /** * In case when workdir is not set we should use closest src */