PY-20457: Use resolvable name of test instead of one reported by runner

Subtest name is reported as ``spam.TestCase.test_eggs.subTestFoo`` and resolved to``spam.TestCase.test_eggs``. We should provide latter for test runner because subtest rerun is not supported by unittest.
This commit is contained in:
Ilya.Kazakevich
2017-05-10 18:29:31 +03:00
parent 11b93f437d
commit fb9f0725b2
4 changed files with 34 additions and 9 deletions
@@ -62,8 +62,22 @@ fun QualifiedName.getRelativeNameTo(root: QualifiedName): QualifiedName? {
/**
* Resolves qname of any symbol to appropriate PSI element.
* Shortcut for [getElementAndResolvableName]
* @see [getElementAndResolvableName]
*/
fun QualifiedName.resolveToElement(context: QNameResolveContext): PsiElement? {
return getElementAndResolvableName(context)?.element
}
data class NameAndElement(val name:QualifiedName, val element:PsiElement)
/**
* Resolves qname of any symbol to PSI element popping tail until element becomes resolved.
* @return element and longest name that was resolved successfully.
* @see [resolveToElement]
*/
fun QualifiedName.getElementAndResolvableName(context: QNameResolveContext): NameAndElement? {
var currentName = QualifiedName.fromComponents(this.components)
@@ -106,7 +120,7 @@ fun QualifiedName.resolveToElement(context: QNameResolveContext): PsiElement? {
//TODO: Support nested classes
val method = element.findMethodByName(lastElement, true, context.evalContext)
if (method != null) {
return method
return NameAndElement(currentName.append(lastElement), method)
}
}
@@ -122,7 +136,7 @@ fun QualifiedName.resolveToElement(context: QNameResolveContext): PsiElement? {
} else {
pyFile.virtualFile.parent
}
return resolveToElement(context.copy(folderToStart = folder))
return getElementAndResolvableName(context.copy(folderToStart = folder))
}
return element
return if (element != null) NameAndElement(currentName, element) else null
}
@@ -23,6 +23,7 @@ import com.intellij.execution.testframework.AbstractTestProxy
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.psi.PsiElement
import com.jetbrains.extensions.getQName
import com.jetbrains.extenstions.getElementAndResolvableName
import com.jetbrains.extenstions.resolveToElement
import com.jetbrains.python.psi.types.TypeEvalContext
import com.jetbrains.python.run.PythonRunConfiguration
@@ -230,8 +231,11 @@ data class ConfigurationTarget(@com.jetbrains.python.testing.ConfigField var tar
// Try to set path relative to work dir (better than path from closest root)
// If we can resolve element by this path relative to working directory then use it
val qNameInsideOfDirectory = qualifiedNameParts.getElementNamePrependingFile()
if (qNameInsideOfDirectory.resolveToElement(qNameResolveContext.copy(allowInaccurateResult = false)) != null) {
return listOf("--target", qNameInsideOfDirectory.toString())
val elementAndName = qNameInsideOfDirectory.getElementAndResolvableName(qNameResolveContext.copy(allowInaccurateResult = false))
if (elementAndName != null) {
// qNameInsideOfDirectory may contain redundant elements like subtests so we use name that was really resolved
// element.qname can't be used because inherited test resolves to parent
return listOf("--target",elementAndName.name.toString())
}
// Use "full" (path from closest root) otherwise
val name = (element.containingFile as? com.jetbrains.python.psi.PyFile)?.getQName()?.append(qualifiedNameParts.elementName) ?:
@@ -45,10 +45,17 @@ import java.util.Set;
abstract class PyUnitTestProcessWithConsoleTestTask extends PyProcessWithConsoleTestTask<PyUnitTestProcessRunner> {
@NotNull
protected final String myScriptName;
private final int myRerunFailedTests;
PyUnitTestProcessWithConsoleTestTask(@NotNull final String relativePathToTestData, @NotNull final String scriptName) {
this(relativePathToTestData, scriptName, 0);
}
PyUnitTestProcessWithConsoleTestTask(@NotNull final String relativePathToTestData,
@NotNull final String scriptName,
final int rerunFailedTests) {
super(relativePathToTestData, SdkCreationType.SDK_PACKAGES_ONLY);
myScriptName = scriptName;
myRerunFailedTests= rerunFailedTests;
}
@Nullable
@@ -60,7 +67,7 @@ abstract class PyUnitTestProcessWithConsoleTestTask extends PyProcessWithConsole
@NotNull
@Override
protected PyUnitTestProcessRunner createProcessRunner() throws Exception {
return new PyUnitTestProcessRunner(myScriptName, 0);
return new PyUnitTestProcessRunner(myScriptName, myRerunFailedTests);
}
@@ -141,7 +141,7 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
@NotNull
@Override
protected PyUnitTestProcessRunner createProcessRunner() throws Exception {
return new PyUnitTestProcessRunner(toFullPath(myScriptName), 0);
return new PyUnitTestProcessRunner(toFullPath(myScriptName), 1);
}
@Override
@@ -417,7 +417,7 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
@EnvTestTagsRequired(tags = "python3") // No subtest in py2
@Test
public void testSubtest() throws Exception {
runPythonTest(new PyUnitTestProcessWithConsoleTestTask("testRunner/env/unit/", "test_subtest.py") {
runPythonTest(new PyUnitTestProcessWithConsoleTestTask("testRunner/env/unit/", "test_subtest.py", 1) {
@Override
protected void checkTestResults(@NotNull PyUnitTestProcessRunner runner,
@NotNull String stdout,
@@ -446,7 +446,7 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
@EnvTestTagsRequired(tags = "python3") // No subtest in py2
@Test
public void testSubtestSkipped() throws Exception {
runPythonTest(new PyUnitTestProcessWithConsoleTestTask("testRunner/env/unit/", "test_skipped_subtest.py") {
runPythonTest(new PyUnitTestProcessWithConsoleTestTask("testRunner/env/unit/", "test_skipped_subtest.py", 1) {
@Override
protected void checkTestResults(@NotNull PyUnitTestProcessRunner runner,
@NotNull String stdout,