mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-23279, PY-9963: Use CommandLine language to parse arguments passed as additional
* GeneralCommandLine does not support "as is" command line: it should be splitted to arguments (due to ProcessBuilder interface).
This commit is contained in:
@@ -71,6 +71,9 @@ public class PyElementGeneratorImpl extends PyElementGenerator {
|
||||
return createDummyFile(langLevel, contents, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use {@link PsiFileFactory} instead?
|
||||
*/
|
||||
public PsiFile createDummyFile(LanguageLevel langLevel, String contents, boolean physical) {
|
||||
final PsiFileFactory factory = PsiFileFactory.getInstance(myProject);
|
||||
final String name = getDummyFileName();
|
||||
|
||||
@@ -15,14 +15,22 @@
|
||||
*/
|
||||
package com.jetbrains.python.testing.universalTests
|
||||
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.module.ModuleUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiErrorElement
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
import com.intellij.psi.PsiFileSystemItem
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.util.QualifiedName
|
||||
import com.jetbrains.commandInterface.commandLine.CommandLineLanguage
|
||||
import com.jetbrains.commandInterface.commandLine.CommandLinePart
|
||||
import com.jetbrains.commandInterface.commandLine.psi.CommandLineArgument
|
||||
import com.jetbrains.commandInterface.commandLine.psi.CommandLineFile
|
||||
import com.jetbrains.commandInterface.commandLine.psi.CommandLineOption
|
||||
import com.jetbrains.extensions.getQName
|
||||
import com.jetbrains.python.PyNames
|
||||
import com.jetbrains.python.psi.PyFile
|
||||
@@ -30,6 +38,7 @@ import com.jetbrains.python.psi.PyQualifiedNameOwner
|
||||
import com.jetbrains.python.psi.PyUtil
|
||||
import com.jetbrains.python.psi.resolve.fromModule
|
||||
import com.jetbrains.python.psi.resolve.resolveModuleAt
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author Ilya.Kazakevich
|
||||
@@ -106,3 +115,45 @@ private fun findVFSItemRoot(virtualFile: VirtualFile, project: Project): Virtual
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emulates command line processor by parsing command line to arguments that can be provided as argv.
|
||||
* Escape chars are not supported but quotes work.
|
||||
* @throws ExecutionException if can't be parsed
|
||||
*/
|
||||
fun getParsedAdditionalArguments(project: Project, additionalArguments: String): List<String> {
|
||||
val factory = PsiFileFactory.getInstance(project)
|
||||
val file = factory.createFileFromText(CommandLineLanguage.INSTANCE,
|
||||
String.format("fake_command %s", additionalArguments)) as CommandLineFile
|
||||
|
||||
if (file.children.any { it is PsiErrorElement }) {
|
||||
throw ExecutionException("Additional arguments can't be parsed. Please check they are valid: $additionalArguments")
|
||||
}
|
||||
|
||||
|
||||
val additionalArgsList = ArrayList<String>()
|
||||
var skipArgument = false
|
||||
file.children.filterIsInstance(CommandLinePart::class.java).forEach {
|
||||
when (it) {
|
||||
is CommandLineOption -> {
|
||||
val optionText = it.text
|
||||
val possibleArgument = it.findArgument()
|
||||
if (possibleArgument != null) {
|
||||
additionalArgsList.add(optionText + possibleArgument.valueNoQuotes)
|
||||
skipArgument = true
|
||||
}
|
||||
else {
|
||||
additionalArgsList.add(optionText)
|
||||
}
|
||||
}
|
||||
is CommandLineArgument -> {
|
||||
if (!skipArgument) {
|
||||
additionalArgsList.add(it.valueNoQuotes)
|
||||
}
|
||||
skipArgument = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return additionalArgsList
|
||||
}
|
||||
|
||||
|
||||
@@ -385,7 +385,7 @@ abstract class PyUniversalTestConfiguration(project: Project,
|
||||
private fun generateRawArguments(): List<String> {
|
||||
val rawArguments = additionalArguments + " " + getCustomRawArgumentsString()
|
||||
if (rawArguments.isNotBlank()) {
|
||||
return listOf("--") + rawArguments.trim().split(" ")
|
||||
return listOf("--") + getParsedAdditionalArguments(project, additionalArguments)
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_slow():
|
||||
pass
|
||||
|
||||
|
||||
def test_fast():
|
||||
pass
|
||||
@@ -31,6 +31,39 @@ import static org.junit.Assert.assertEquals;
|
||||
@EnvTestTagsRequired(tags = "pytest")
|
||||
public final class PythonPyTestingTest extends PyEnvTestCase {
|
||||
|
||||
// Ensure slow test is not run when -m "not slow" is provided
|
||||
@Test
|
||||
public void testMarkerWithSpaces() throws Exception {
|
||||
runPythonTest(
|
||||
new PyProcessWithConsoleTestTask<PyTestTestProcessRunner>("/testRunner/env/pytest/test_with_markers", SdkCreationType.EMPTY_SDK) {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PyTestTestProcessRunner createProcessRunner() throws Exception {
|
||||
return new PyTestTestProcessRunner("test_with_markers.py", 0) {
|
||||
@Override
|
||||
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalPyTestConfiguration configuration) throws IOException {
|
||||
super.configurationCreatedAndWillLaunch(configuration);
|
||||
configuration.setAdditionalArguments("-m 'not slow'");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void checkTestResults(@NotNull PyTestTestProcessRunner runner,
|
||||
@NotNull String stdout,
|
||||
@NotNull String stderr,
|
||||
@NotNull String all) {
|
||||
Assert.assertEquals("Marker support broken", "Test tree:\n" +
|
||||
"[root]\n" +
|
||||
".test_with_markers\n" +
|
||||
"..test_fast(+)\n",
|
||||
runner.getFormattedTestTree());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigurationProducer() throws Exception {
|
||||
runPythonTest(
|
||||
@@ -49,7 +82,8 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
|
||||
@Test
|
||||
public void testTestsInSubFolderResolvable() throws Exception {
|
||||
runPythonTest(
|
||||
new PyUnitTestProcessWithConsoleTestTask.PyTestsInSubFolderRunner<PyTestTestProcessRunner>("test_metheggs", "test_funeggs", "test_first") {
|
||||
new PyUnitTestProcessWithConsoleTestTask.PyTestsInSubFolderRunner<PyTestTestProcessRunner>("test_metheggs", "test_funeggs",
|
||||
"test_first") {
|
||||
@NotNull
|
||||
@Override
|
||||
protected PyTestTestProcessRunner createProcessRunner() throws Exception {
|
||||
@@ -110,7 +144,8 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
|
||||
@Test
|
||||
public void testProduceConfigurationOnFile() throws Exception {
|
||||
runPythonTest(
|
||||
new CreateConfigurationByFileTask<PyUniversalPyTestConfiguration>(PythonTestConfigurationsModel.PY_TEST_NAME, PyUniversalPyTestConfiguration.class, "spam.py") {
|
||||
new CreateConfigurationByFileTask<PyUniversalPyTestConfiguration>(PythonTestConfigurationsModel.PY_TEST_NAME,
|
||||
PyUniversalPyTestConfiguration.class, "spam.py") {
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiElement getElementToRightClickOnByFile(@NotNull final String fileName) {
|
||||
@@ -246,7 +281,7 @@ public final class PythonPyTestingTest extends PyEnvTestCase {
|
||||
if (getLevelForSdk().isPy3K()) {
|
||||
return new PyTestTestProcessRunner("folder_no_init_py/test_test.py", 2);
|
||||
}
|
||||
else {
|
||||
else {
|
||||
return new PyTestTestProcessRunner(toFullPath("folder_no_init_py/test_test.py"), 2) {
|
||||
@Override
|
||||
protected void configurationCreatedAndWillLaunch(@NotNull PyUniversalPyTestConfiguration configuration) throws IOException {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.testing.universalTests
|
||||
|
||||
import com.jetbrains.python.fixtures.PyTestCase
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* @author Ilya.Kazakevich
|
||||
*/
|
||||
class PyTestRunnerUtilsKtTest : PyTestCase() {
|
||||
@Test
|
||||
fun testGetParsedAdditionalArguments() {
|
||||
var list = getParsedAdditionalArguments(myFixture.project, "-v --color=red -m 'spam and eggs'")
|
||||
Assert.assertEquals("List parsed incorrectly", listOf("-v", "--color=red", "-m", "spam and eggs"), list)
|
||||
|
||||
list = getParsedAdditionalArguments(myFixture.project, "--eggs=spam --foo=\"eggs and spam\"")
|
||||
Assert.assertEquals("List parsed incorrectly", listOf("--eggs=spam", "--foo=eggs and spam"), list)
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user