PY-22556, PY-23233, PY-23217: Set working directory for tests that are not in packages

When you want to launch test in folder "tests" which is not a package, you have several troubles:
* Python frameworks report tests relative to this folder (i.e. test_module.foo instead of tests.test_module.foo)
* You can't provide test name as tests.foo.MyTest since "tests" is not package

To solve it, we set "tests" as package. But you can't simply set deepest folder as package: it may break relative imports.
So, newly created configuration should use topmost folder which is not a package.
Consider following layout: tests ( not a package), logic (package), test_module.py
 Here is: "logic.test_module" and "tests" as working directory.

 On Java side, we get working dir reported by python and resolve names against it.
 Several hacks like index lookup of function are not needed now.
This commit is contained in:
Ilya.Kazakevich
2017-03-23 01:56:17 +03:00
parent 9496fd7ad9
commit da2d1d3cb6
16 changed files with 275 additions and 86 deletions
+12 -23
View File
@@ -163,7 +163,8 @@ class NewTeamcityServiceMessages(_old_service_messages):
return
try:
properties["locationHint"] = "python://{0}".format(properties["name"])
# Report directory so Java site knows which folder to resolve names against
properties["locationHint"] = "python<{0}>://{1}".format(os.getcwd(), properties["name"])
except KeyError:
# If message does not have name, then it is not test
# Simply pass it
@@ -324,27 +325,12 @@ class _SymbolName2KSplitter(_SymbolNameSplitter):
def check_is_importable(self, parts, current_step, separator):
import imp
module_to_import = parts[current_step]
try:
(fil, self._path, desc) = imp.find_module(module_to_import, [self._path] if self._path else None)
self._symbol_processed = True
if desc[2] == imp.PKG_DIRECTORY:
# Package
self._path = imp.load_module(module_to_import, fil, self._path, desc).__path__[0]
except ImportError as error:
if not self._symbol_processed:
# First ImportError means there could be folder with out for __init__.py
# See class doc for more info
subdir = os.path.sep.join(parts[:current_step + 1])
dirs = [path for path in map( lambda p: os.path.join(p, subdir), sys.path) if os.path.isdir(path)]
if not dirs:
raise error
elif len(dirs) == 1:
# can be folder with out of __init__.py
self._path = dirs[0]
return
else:
raise Exception("Several folders on sys.path with same name, rename folder: {0}", ",".join(dirs))
raise error
(fil, self._path, desc) = imp.find_module(module_to_import, [self._path] if self._path else None)
self._symbol_processed = True
if desc[2] == imp.PKG_DIRECTORY:
# Package
self._path = imp.load_module(module_to_import, fil, self._path, desc).__path__[0]
class _SymbolName3KSplitter(_SymbolNameSplitter):
@@ -414,6 +400,9 @@ def jb_start_tests():
_jb_utils.OptionDescription('--target', 'Python target to run', "append"))
del sys.argv[1:] # Remove all args
NewTeamcityServiceMessages().message('enteredTheMatrix')
# Working dir should be on path, that is how runners work when launched from command line
sys.path.append(os.getcwd())
return namespace.path, namespace.target, additional_args
@@ -429,4 +418,4 @@ def jb_doc_args(framework_name, args):
Runner encouraged to report its arguments to user with aid of this function
"""
print("Launching {0} with arguments {1}".format(framework_name, " ".join(args)))
print("Launching {0} with arguments {1} in {2}".format(framework_name, " ".join(args), os.getcwd()))
@@ -18,6 +18,7 @@ if __name__ == '__main__':
discovery_args += [os.path.dirname(path), "-p", os.path.basename(path)]
else:
discovery_args.append(path)
discovery_args += ["-t", os.getcwd()] # To force unit calculate path relative to this folder
additional_args = discovery_args + additional_args
elif targets:
additional_args += targets
@@ -31,6 +31,12 @@ import org.jetbrains.annotations.Nullable;
* @author vlan
*/
public interface PyQualifiedNameResolveContext {
/**
* For mode when context resolves element relative to this directory
* @see #copyWithRelative(PsiDirectory)
*/
@Nullable
PsiDirectory getRelativeDirectory();
@Nullable
PsiElement getFoothold();
int getRelativeLevel();
@@ -71,4 +77,10 @@ public interface PyQualifiedNameResolveContext {
PyQualifiedNameResolveContext copyWithRoots();
@NotNull
PyQualifiedNameResolveContext copyWithoutStubs();
/**
* @see #getRelativeDirectory()
*/
@NotNull
PyQualifiedNameResolveContext copyWithRelative(@NotNull PsiDirectory directory);
}
@@ -16,17 +16,21 @@
package com.jetbrains.extenstions
import com.intellij.openapi.module.Module
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.util.QualifiedName
import com.jetbrains.extensions.getSdk
import com.jetbrains.python.psi.PyClass
import com.jetbrains.python.psi.resolve.fromModule
import com.jetbrains.python.psi.resolve.resolveQualifiedName
import com.jetbrains.python.psi.types.TypeEvalContext
import com.jetbrains.python.sdk.PythonSdkType
/**
* Resolves qname of any symbol to appropriate PSI element.
*/
fun QualifiedName.toElement(module: Module, context: TypeEvalContext): PsiElement? {
fun QualifiedName.toElement(module: Module, context: TypeEvalContext, folderToStart: VirtualFile? = null): PsiElement? {
var currentName = QualifiedName.fromComponents(this.components)
@@ -34,9 +38,23 @@ fun QualifiedName.toElement(module: Module, context: TypeEvalContext): PsiElemen
// Drill as deep, as we can
var lastElement: String? = null
while (currentName.componentCount > 0 && element == null) {
element = resolveQualifiedName(currentName, fromModule(module).copyWithMembers()).firstOrNull()
var resolveContext = fromModule(module)
if (folderToStart != null) {
val psiDirectory = PsiManager.getInstance(module.project).findDirectory(folderToStart)
if (psiDirectory != null) {
resolveContext = resolveContext.copyWithRelative(psiDirectory)
}
}
// check for module and set if py3k
if (PythonSdkType.getLanguageLevelForSdk(module.getSdk()).isPy3K) {
resolveContext = resolveContext.copyWithPlainDirectories()
}
while (currentName.componentCount > 0 && element == null) {
element = resolveQualifiedName(currentName, resolveContext.copyWithMembers()).firstOrNull()
if (element != null) {
break
}
@@ -27,6 +27,7 @@ import com.jetbrains.python.psi.PyUtil
data class PyQualifiedNameResolveContextImpl(private val psiManager: PsiManager, private val module: Module?,
private val foothold: PsiElement?, private val sdk: Sdk?,
private val relativeLevel : Int = -1,
private val relativeDirectory: PsiDirectory? = null,
private val withoutRoots : Boolean = false,
private val withoutForeign: Boolean = false,
private val withMembers : Boolean = false,
@@ -48,6 +49,8 @@ data class PyQualifiedNameResolveContextImpl(private val psiManager: PsiManager,
override fun getPsiManager() = psiManager
override fun getRelativeDirectory() = relativeDirectory
override fun getWithMembers() = withMembers
override fun getWithPlainDirectories() = withPlainDirectories
@@ -77,6 +80,8 @@ data class PyQualifiedNameResolveContextImpl(private val psiManager: PsiManager,
return if (relativeLevel > 0) ResolveImportUtil.stepBackFrom(file, relativeLevel) else file.containingDirectory
}
override fun copyWithRelative(directory: PsiDirectory) = copy(relativeDirectory = directory)
override fun getFootholdFile() = when (foothold) {
is PsiDirectory -> foothold.findFile(PyNames.INIT_DOT_PY)
else -> foothold?.containingFile?.originalFile
@@ -228,7 +228,10 @@ private fun isNamespacePackage(element: PsiElement): Boolean {
return false
}
private fun resolveWithRelativeLevel(name: QualifiedName, context : PyQualifiedNameResolveContext): List<PsiElement> {
private fun resolveWithRelativeLevel(name: QualifiedName, context: PyQualifiedNameResolveContext): List<PsiElement> {
if (context.relativeDirectory != null) {
return resolveModuleAt(name, context.relativeDirectory, context)
}
val footholdFile = context.footholdFile
if (context.relativeLevel >= 0 && footholdFile != null && !PyUserSkeletonsUtil.isUnderUserSkeletonsDirectory(footholdFile)) {
return resolveModuleAt(name, context.containingDirectory, context) + relativeResultsForStubsFromRoots(name, context)
@@ -22,6 +22,7 @@ import com.intellij.execution.configurations.RunProfileState
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.options.SettingsEditor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.jetbrains.python.PythonHelper
import com.jetbrains.python.testing.PythonTestConfigurationsModel
import com.jetbrains.python.testing.VFSTestFrameworkListener
@@ -58,6 +59,9 @@ class PyUniversalNoseTestConfiguration(project: Project, factory: PyUniversalNos
}
override fun isFrameworkInstalled() = VFSTestFrameworkListener.getInstance().isNoseTestInstalled(sdk)
//https://github.com/nose-devs/nose/issues/1042
override fun treatFoldersAsPackages(anchor: PsiElement) = true
}
object PyUniversalNoseTestFactory : PyUniversalTestFactory<PyUniversalNoseTestConfiguration>() {
@@ -38,10 +38,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util.JDOMExternalizerUtil
import com.intellij.openapi.util.Pair
import com.intellij.openapi.util.Ref
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileSystem
import com.intellij.openapi.vfs.*
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFileSystemItem
@@ -53,11 +50,8 @@ import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.refactoring.listeners.UndoRefactoringElementAdapter
import com.jetbrains.extenstions.toElement
import com.jetbrains.python.PyBundle
import com.jetbrains.python.psi.PyClass
import com.jetbrains.python.psi.PyFile
import com.jetbrains.python.psi.PyFunction
import com.jetbrains.python.psi.PyQualifiedNameOwner
import com.jetbrains.python.psi.stubs.PyFunctionNameIndex
import com.jetbrains.python.PyNames
import com.jetbrains.python.psi.*
import com.jetbrains.python.psi.types.TypeEvalContext
import com.jetbrains.python.run.AbstractPythonRunConfiguration
import com.jetbrains.python.run.CommandLinePatcher
@@ -70,6 +64,7 @@ import com.jetbrains.reflection.getProperties
import org.jdom.Element
import java.io.File
import java.util.*
import java.util.regex.Pattern
import javax.swing.JComponent
@@ -82,24 +77,56 @@ val factories: Array<PythonConfigurationFactoryBase> = arrayOf(PyUniversalUnitTe
internal fun getAdditionalArgumentsPropertyName() = PyUniversalTestConfiguration::additionalArguments.name
/**
* Checks if configuration can run with provided qname against provided working dir.
* Fixes name and configuration if can't
*/
private fun configureRelative(name: QualifiedName,
configuration: PyUniversalTestConfiguration): QualifiedName {
val module = configuration.module?: return name
val fileSystem = LocalFileSystem.getInstance()
val context = TypeEvalContext.userInitiated(module.project, null)
// Working dir points to project root for newly created configuration
var path = fileSystem.findFileByPath(configuration.workingDirectorySafe)?:return name
// If some element can't be resolved that means one of its parts is not package.
// foo.spam.bar does not work if "foo" is not package
// convert it to "spam.bar" and set "foo" as working dir instead
var currentName = name
while (currentName.toElement(module, context, path) !is PyElement) {
val head = currentName.firstComponent ?: return name
currentName = currentName.removeHead(1)
path = path.findFileByRelativePath(head) ?: return name
}
configuration.workingDirectory = path.canonicalPath
return currentName
}
/**
* For cases like "module.class.test_name.subtest_name" situated somewhere deep in folder which is not package,
* this function tries to resolve test_name using index.
* Checks if configuration can run with provided path against provided working dir.
* Fixes configuration workdir if it can't
*/
private fun findFunctionByPartialName(qualifiedName: QualifiedName, project: Project): PyFunction? {
// TODO: Add to background if too slow
val components = ArrayList(qualifiedName.components)
components.reverse()
components.forEach {
for (function in PyFunctionNameIndex.find(it, project)) {
val name = function.qualifiedName
if (name != null && name.contains(qualifiedName.toString())) {
return function
}
}
private fun configureRelative(path: VirtualFile, configuration: PyUniversalTestConfiguration) {
val workDir = LocalFileSystem.getInstance().findFileByPath(configuration.workingDirectorySafe)?:return
if (! VfsUtil.isAncestor(workDir, path, false)) {
return
}
return null
var currentPath = if(path.isDirectory) {
path
} else {
path.parent
}
//Ensure path is __init__.py based for all between path and configuration
// no init py -- not a package
while (currentPath.findFileByRelativePath(PyNames.INIT_DOT_PY) != null && currentPath != workDir) {
currentPath = currentPath.parent
}
configuration.workingDirectory = currentPath.path
}
/**
@@ -131,19 +158,27 @@ private fun findConfigurationFactoryFromSettings(module: Module): ConfigurationF
}
// folder provided by python side. Resolve test names versus it
private val PATH_URL = Pattern.compile("^python<([^<>]+)>$")
private object PyUniversalTestsLocator : SMTestLocator {
override fun getLocation(protocol: String, path: String, project: Project, scope: GlobalSearchScope): List<Location<out PsiElement>> {
if (scope !is ModuleWithDependenciesScope) {
return listOf()
}
val matcher = PATH_URL.matcher(protocol)
val folder = if (matcher.matches()) {
LocalFileSystem.getInstance().findFileByPath(matcher.group(1))
}
else {
null
}
val qualifiedName = QualifiedName.fromDottedString(path)
// Assume qname id good and resolve it directly
var element = qualifiedName.toElement(scope.module,
TypeEvalContext.codeAnalysis(project, null))
if (element == null) {
// If no luck then resolve it using heuristic
element = findFunctionByPartialName(qualifiedName, project)
}
val element = qualifiedName.toElement(scope.module,
TypeEvalContext.codeAnalysis(project, null), folder)
if (element != null) {
// Path is qualified name of python test according to runners protocol
// Parentheses are part of generators / parametrized tests
@@ -218,9 +253,9 @@ data class ConfigurationTarget(@ConfigField var target: String, @ConfigField var
/**
* Converts target to PSI element if possible
*/
fun asPsiElement(module: Module, context: TypeEvalContext): PsiElement? {
fun asPsiElement(module: Module, context: TypeEvalContext, folderToStart: VirtualFile? = null): PsiElement? {
if (targetType == TestTargetType.PYTHON) {
return QualifiedName.fromDottedString(target).toElement(module, context)
return QualifiedName.fromDottedString(target).toElement(module, context, folderToStart)
}
return null
}
@@ -307,13 +342,6 @@ abstract class PyUniversalTestConfiguration(project: Project,
override fun getRefactoringElementListener(element: PsiElement?): RefactoringElementListener? {
val myModule = module
val targetElement: PsiElement?
if (myModule != null) {
targetElement = target.asPsiElement(myModule, TypeEvalContext.userInitiated(project, null))
}
else {
targetElement = null
}
val targetFile = target.asVirtualFile(LocalFileSystem.getInstance())
val workingDirectoryFile = if (workingDirectory.isNotEmpty()) {
LocalFileSystem.getInstance().findFileByPath(workingDirectory)
@@ -322,6 +350,16 @@ abstract class PyUniversalTestConfiguration(project: Project,
null
}
if (myModule != null) {
targetElement = target.asPsiElement(myModule, TypeEvalContext.userInitiated(project, null), workingDirectoryFile)
}
else {
targetElement = null
}
val targetFile = target.asVirtualFile(LocalFileSystem.getInstance())
if (targetElement != null && PsiTreeUtil.isAncestor(element, targetElement, false)) {
return PyElementTargetRenamer(targetElement, workingDirectoryFile)
}
@@ -487,11 +525,16 @@ abstract class PyUniversalTestConfiguration(project: Project,
is PyClass -> PythonUnitTestUtil.isTestCaseClass(element, TypeEvalContext.userInitiated(element.project, element.containingFile))
else -> false
}
/**
* When checking if configuration is ok we need to know if folders could be packages: i.e. if foo.bar requires init.py in foo to work
*/
open fun treatFoldersAsPackages(anchor: PsiElement) = (!LanguageLevel.forElement(anchor).isPy3K)
}
private fun isTestFile(file: PyFile): Boolean {
return PythonUnitTestUtil.isUnitTestFile(file) ||
PythonUnitTestUtil.getTestCaseClassesFromFile(file, TypeEvalContext.userInitiated(file.project, file)).isNotEmpty()
PythonUnitTestUtil.getTestCaseClassesFromFile(file, TypeEvalContext.userInitiated(file.project, file)).isNotEmpty()
}
abstract class PyUniversalTestFactory<out CONF_T : PyUniversalTestConfiguration> : PythonConfigurationFactoryBase(
@@ -537,7 +580,7 @@ object PyUniversalTestsConfigurationProducer : AbstractPythonTestConfigurationPr
location.target.copyTo(configuration.target)
}
else {
val targetForConfig = getTargetForConfig(configuration, sourceElement.get()) ?: return false
val targetForConfig = getTargetForConfig(configuration, sourceElement.get(), true) ?: return false
targetForConfig.copyTo(configuration.target)
}
configuration.setGeneratedName()
@@ -550,7 +593,10 @@ object PyUniversalTestsConfigurationProducer : AbstractPythonTestConfigurationPr
* @return configuration name and its target
*/
private fun getTargetForConfig(configuration: PyUniversalTestConfiguration,
baseElement: PsiElement): ConfigurationTarget? {
baseElement: PsiElement, fixConfiguration: Boolean = false): ConfigurationTarget? {
val setRelative = (fixConfiguration && configuration.treatFoldersAsPackages(baseElement))
var element = baseElement
// Go up until we reach top of the file
// asking configuration about each element if it is supported or not
@@ -559,14 +605,23 @@ object PyUniversalTestsConfigurationProducer : AbstractPythonTestConfigurationPr
if (configuration.couldBeTestTarget(element)) {
when (element) {
is PyQualifiedNameOwner -> { // Function, class, method
val qualifiedName = element.qualifiedName
var qualifiedName = element.qualifiedName
if (qualifiedName == null) {
Logger.getInstance(PyUniversalTestConfiguration::class.java).warn("$element has no qualified name")
return null
}
if (setRelative) {
qualifiedName = configureRelative(QualifiedName.fromDottedString(qualifiedName), configuration).toString()
}
return ConfigurationTarget(qualifiedName, TestTargetType.PYTHON)
}
is PsiFileSystemItem -> return ConfigurationTarget(element.virtualFile.path, TestTargetType.PATH)
is PsiFileSystemItem -> {
val path = element.virtualFile
if (setRelative) {
configureRelative(path, configuration).toString()
}
return ConfigurationTarget(path.path, TestTargetType.PATH)
}
}
}
element = element.parent
@@ -8,3 +8,17 @@ def test_funeggs():
class EggsTest(TestCase):
def test_metheggs(self):
print("I am method")
class Parent:
def test_first(self):
assert True
def test_second(self):
assert False
class Child(TestCase, Parent):
pass
@@ -1,5 +1,5 @@
import unittest
from testedCode.my_class import *
from .testedCode.my_class import *
class MyClassTest(unittest.TestCase):
def test_foo(self):
@@ -17,9 +17,12 @@ import com.intellij.testFramework.builders.ModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.*;
import com.intellij.testFramework.fixtures.impl.ModuleFixtureBuilderImpl;
import com.intellij.testFramework.fixtures.impl.ModuleFixtureImpl;
import com.jetbrains.extensions.ModuleExtKt;
import com.jetbrains.python.PythonModuleTypeBase;
import com.jetbrains.python.PythonTestUtil;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.sdk.InvalidSdkException;
import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdkTools.PyTestSdkTools;
import com.jetbrains.python.sdkTools.SdkCreationType;
import org.jetbrains.annotations.NotNull;
@@ -136,6 +139,11 @@ public abstract class PyExecutionFixtureTestTask extends PyTestTask {
}
}
@NotNull
public LanguageLevel getLevelForSdk() {
return PythonSdkType.getLanguageLevelForSdk(ModuleExtKt.getSdk(myFixture.getModule()));
}
/**
* @return additional content roots
*/
@@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.xdebugger.XDebuggerTestUtil;
import com.jetbrains.python.sdkTools.SdkCreationType;
import org.jetbrains.annotations.NotNull;
@@ -58,6 +59,11 @@ public abstract class PyProcessWithConsoleTestTask<T extends ProcessWithConsoleR
private static final Logger LOG = Logger.getInstance(PyProcessWithConsoleTestTask.class);
@NotNull
private final SdkCreationType myRequiredSdkType;
/**
* @see #toFullPath(String)
*/
@Nullable
private VirtualFile myLatestUsedScript;
/**
* @param requiredSdkType this task creates sdk and binds it to fixture module. Provide type of SDK your test needs.
@@ -199,4 +205,26 @@ public abstract class PyProcessWithConsoleTestTask<T extends ProcessWithConsoleR
* @param all joined stdout and stderr
*/
protected abstract void checkTestResults(@NotNull T runner, @NotNull String stdout, @NotNull String stderr, @NotNull String all);
/**
* Converts script or folder name to full path and stores internally to retrived with {@link #getWorkingFolderForScript()}
*/
@NotNull
public String toFullPath(@NotNull final String scriptName) {
myLatestUsedScript = myFixture.getTempDirFixture().getFile(scriptName);
assert myLatestUsedScript != null: "File not found " + scriptName;
return myLatestUsedScript.getPath();
}
/**
* @see #toFullPath(String)
*/
@Nullable
public String getWorkingFolderForScript() {
final VirtualFile script = myLatestUsedScript;
if (script == null) {
return null;
}
return (script.isDirectory() ? script : script.getParent()).getPath();
}
}
@@ -104,7 +104,7 @@ abstract class PyUnitTestProcessWithConsoleTestTask extends PyProcessWithConsole
final Location<?> methodLocation = method.getLocation(getProject(), GlobalSearchScope.moduleScope(myFixture.getModule()));
Assert.assertNotNull("Failed to resolve method location", methodLocation);
Assert.assertNotNull("Failed to resolve method location " + method, methodLocation);
final PsiElement methodPsiElement = methodLocation.getPsiElement();
Assert.assertNotNull("Failed to get PSI for method location", methodPsiElement);
Assert.assertThat("Wrong test returned", methodPsiElement, Matchers.instanceOf(PyFunction.class));
@@ -131,8 +131,11 @@ abstract class PyUnitTestProcessWithConsoleTestTask extends PyProcessWithConsole
Assert.assertThat("Function output is broken",
MockPrinter.fillPrinter(method).getStdOut().trim(), Matchers.containsString("I am function"));
}
else if (functionName.endsWith("test_first") || functionName.endsWith("test_second")) {
// No output expected
}
else {
throw new AssertionError("Unknown function" + functionName);
throw new AssertionError("Unknown function " + functionName);
}
}
}
@@ -13,6 +13,8 @@ import com.jetbrains.python.testing.universalTests.PyUniversalNoseTestFactory;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
/**
@@ -28,11 +30,17 @@ public final class PythonNoseTestingTest extends PyEnvTestCase {
@Test
public void testTestsInSubFolderResolvable() throws Exception {
runPythonTest(
new PyUnitTestProcessWithConsoleTestTask.PyTestsInSubFolderRunner<PyNoseTestProcessRunner>("test_metheggs", "test_funeggs") {
new PyUnitTestProcessWithConsoleTestTask.PyTestsInSubFolderRunner<PyNoseTestProcessRunner>("test_metheggs", "test_funeggs", "test_first") {
@NotNull
@Override
protected PyNoseTestProcessRunner createProcessRunner() throws Exception {
return new PyNoseTestProcessRunner("tests", 0);
return new PyNoseTestProcessRunner(toFullPath("tests"), 0) {
@Override
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalNoseTestConfiguration configuration) throws IOException {
super.configurationCreatedAndWillLaunch(configuration);
configuration.setWorkingDirectory(getWorkingFolderForScript());
}
};
}
});
}
@@ -43,11 +51,17 @@ public final class PythonNoseTestingTest extends PyEnvTestCase {
@Test
public void testOutput() throws Exception {
runPythonTest(
new PyUnitTestProcessWithConsoleTestTask.PyTestsOutputRunner<PyNoseTestProcessRunner>("test_metheggs", "test_funeggs") {
new PyUnitTestProcessWithConsoleTestTask.PyTestsOutputRunner<PyNoseTestProcessRunner>("test_metheggs", "test_funeggs", "test_first") {
@NotNull
@Override
protected PyNoseTestProcessRunner createProcessRunner() throws Exception {
return new PyNoseTestProcessRunner("tests", 0);
return new PyNoseTestProcessRunner(toFullPath("tests"), 0) {
@Override
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalNoseTestConfiguration configuration) throws IOException {
super.configurationCreatedAndWillLaunch(configuration);
configuration.setWorkingDirectory(getWorkingFolderForScript());
}
};
}
});
}
@@ -43,11 +43,17 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
@Test
public void testTestsInSubFolderResolvable() throws Exception {
runPythonTest(
new PyUnitTestProcessWithConsoleTestTask.PyTestsInSubFolderRunner<PyTestTestProcessRunner>("test_metheggs", "test_funeggs") {
new PyUnitTestProcessWithConsoleTestTask.PyTestsInSubFolderRunner<PyTestTestProcessRunner>("test_metheggs", "test_funeggs", "test_first") {
@NotNull
@Override
protected PyTestTestProcessRunner createProcessRunner() throws Exception {
return new PyTestTestProcessRunner("tests", 0);
return new PyTestTestProcessRunner(toFullPath("tests"), 0) {
@Override
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalPyTestConfiguration configuration) throws IOException {
super.configurationCreatedAndWillLaunch(configuration);
configuration.setWorkingDirectory(getWorkingFolderForScript());
}
};
}
});
}
@@ -58,11 +64,17 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
@Test
public void testOutput() throws Exception {
runPythonTest(
new PyUnitTestProcessWithConsoleTestTask.PyTestsOutputRunner<PyTestTestProcessRunner>("test_metheggs", "test_funeggs") {
new PyUnitTestProcessWithConsoleTestTask.PyTestsOutputRunner<PyTestTestProcessRunner>("test_metheggs", "test_funeggs", "test_first") {
@NotNull
@Override
protected PyTestTestProcessRunner createProcessRunner() throws Exception {
return new PyTestTestProcessRunner("tests", 0);
return new PyTestTestProcessRunner(toFullPath("tests"), 0) {
@Override
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalPyTestConfiguration configuration) throws IOException {
super.configurationCreatedAndWillLaunch(configuration);
configuration.setWorkingDirectory(getWorkingFolderForScript());
}
};
}
});
}
@@ -225,7 +237,18 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
@NotNull
@Override
protected PyTestTestProcessRunner createProcessRunner() throws Exception {
return new PyTestTestProcessRunner("folder_no_init_py/test_test.py", 2);
if (getLevelForSdk().isPy3K()) {
return new PyTestTestProcessRunner("folder_no_init_py/test_test.py", 2);
}
else {
return new PyTestTestProcessRunner(toFullPath("folder_no_init_py/test_test.py"), 2) {
@Override
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalPyTestConfiguration configuration) throws IOException {
super.configurationCreatedAndWillLaunch(configuration);
configuration.setWorkingDirectory(getWorkingFolderForScript());
}
};
}
}
@Override
@@ -58,11 +58,17 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
@Test
public void testTestsInSubFolderResolvable() throws Exception {
runPythonTest(
new PyUnitTestProcessWithConsoleTestTask.PyTestsInSubFolderRunner<PyUnitTestProcessRunner>("test_metheggs") {
new PyUnitTestProcessWithConsoleTestTask.PyTestsInSubFolderRunner<PyUnitTestProcessRunner>("test_metheggs", "test_first") {
@NotNull
@Override
protected PyUnitTestProcessRunner createProcessRunner() throws Exception {
return new PyUnitTestProcessRunner("tests", 0);
return new PyUnitTestProcessRunner(toFullPath("tests"), 0) {
@Override
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalUnitTestConfiguration configuration) throws IOException {
super.configurationCreatedAndWillLaunch(configuration);
configuration.setWorkingDirectory(getWorkingFolderForScript());
}
};
}
});
}
@@ -73,11 +79,17 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
@Test
public void testOutput() throws Exception {
runPythonTest(
new PyUnitTestProcessWithConsoleTestTask.PyTestsOutputRunner<PyUnitTestProcessRunner>("test_metheggs") {
new PyUnitTestProcessWithConsoleTestTask.PyTestsOutputRunner<PyUnitTestProcessRunner>("test_metheggs", "test_first") {
@NotNull
@Override
protected PyUnitTestProcessRunner createProcessRunner() throws Exception {
return new PyUnitTestProcessRunner("tests", 0);
return new PyUnitTestProcessRunner(toFullPath("tests"), 0) {
@Override
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalUnitTestConfiguration configuration) throws IOException {
super.configurationCreatedAndWillLaunch(configuration);
configuration.setWorkingDirectory(getWorkingFolderForScript());
}
};
}
});
}