From 50b45f3dea24029d0aca8b7eb36fa085928f2bd2 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Tue, 24 Jan 2017 14:49:57 +0300 Subject: [PATCH] New test runners: Support "unittest pattern" --- python/helpers/pycharm/_jb_unittest_runner.py | 8 +- .../universalTests/PyUniversalPyTest.kt | 4 +- .../universalTests/PyUniversalTestForm.java | 87 +++++++++++++++---- .../PyUniversalTestLegacyInterop.kt | 2 +- .../universalTests/PyUniversalUnitTest.kt | 21 ++++- 5 files changed, 99 insertions(+), 23 deletions(-) diff --git a/python/helpers/pycharm/_jb_unittest_runner.py b/python/helpers/pycharm/_jb_unittest_runner.py index ea74e3de663b..0d8969c765ba 100644 --- a/python/helpers/pycharm/_jb_unittest_runner.py +++ b/python/helpers/pycharm/_jb_unittest_runner.py @@ -10,15 +10,15 @@ if __name__ == '__main__': args = ["python -m unittest"] if path: + discovery_args = ["discover", "-s"] # Unittest does not support script directly, but it can use "discover" to find all tests in some folder # filtering by script - additional_args.append("discover") - additional_args.append("-s") assert os.path.exists(path), "{0}: No such file or directory".format(path) if os.path.isfile(path): - additional_args += [os.path.dirname(path), "-p", os.path.basename(path)] + discovery_args += [os.path.dirname(path), "-p", os.path.basename(path)] else: - additional_args.append(path) + discovery_args.append(path) + additional_args = discovery_args + additional_args else: additional_args += targets args += additional_args diff --git a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalPyTest.kt b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalPyTest.kt index 06ef5c36d000..49eb01554ff7 100644 --- a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalPyTest.kt +++ b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalPyTest.kt @@ -28,7 +28,9 @@ import com.jetbrains.python.testing.PythonTestConfigurationsModel */ class PyUniversalPyTestSettingsEditor(configuration: PyUniversalTestConfiguration) : - PyUniversalTestSettingsEditor(PyUniversalTestForm.create(configuration, PyUniversalPyTestConfiguration::keywords.name)) + PyUniversalTestSettingsEditor( + PyUniversalTestForm.create(configuration, PyUniversalTestForm.CustomOption( + PyUniversalPyTestConfiguration::keywords.name, TestTargetType.PATH, TestTargetType.PYTHON))) class PyUniversalPyTestExecutionEnvironment(configuration: PyUniversalPyTestConfiguration, environment: ExecutionEnvironment) : PyUniversalTestExecutionEnvironment(configuration, environment) { diff --git a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTestForm.java b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTestForm.java index 25b16e275ada..2b4eeaf1c4e4 100644 --- a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTestForm.java +++ b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTestForm.java @@ -15,6 +15,7 @@ */ package com.jetbrains.python.testing.universalTests; +import com.google.common.collect.ObjectArrays; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.ui.TextFieldWithBrowseButton; @@ -25,7 +26,6 @@ import com.intellij.ui.components.JBRadioButton; import com.intellij.ui.components.JBTextField; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.uiDesigner.core.GridLayoutManager; -import com.intellij.util.ArrayUtil; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.run.AbstractPyCommonOptionsForm; import com.jetbrains.python.run.PyCommonOptionsFormFactory; @@ -72,7 +72,7 @@ public final class PyUniversalTestForm implements SimplePropertiesProvider { private final ButtonGroup myButtonGroup = new ButtonGroup(); private AbstractPyCommonOptionsForm myOptionsForm; - private final Map myCustomOptions = new LinkedHashMap<>(); // TDO: Linked -- order + private final Map myCustomOptions = new LinkedHashMap<>(); // TDO: Linked -- order @NotNull JPanel getPanel() { @@ -89,14 +89,14 @@ public final class PyUniversalTestForm implements SimplePropertiesProvider { public void setPropertyValue(@NotNull final String propertyName, @Nullable final String propertyValue) { - myCustomOptions.get(propertyName).setText(propertyValue != null ? propertyValue : ""); + myCustomOptions.get(propertyName).myOptionValue.setText(propertyValue != null ? propertyValue : ""); } @Nullable @Override public String getPropertyValue(@NotNull final String propertyName) { - return myCustomOptions.get(propertyName).getText(); + return myCustomOptions.get(propertyName).myOptionValue.getText(); } private PyUniversalTestForm() { @@ -110,7 +110,7 @@ public final class PyUniversalTestForm implements SimplePropertiesProvider { public static PyUniversalTestForm create(@NotNull final PyUniversalTestConfiguration configuration, @NotNull - final String... customOptions) { // TODO: DOC + final CustomOption... customOptions) { // TODO: DOC final PyUniversalTestForm form = new PyUniversalTestForm(); @@ -135,25 +135,29 @@ public final class PyUniversalTestForm implements SimplePropertiesProvider { form.myLabel.setText(configuration.getTestFrameworkName()); - form.addCustomOptions(ArrayUtil.mergeArrays(customOptions, PyUniversalTestsKt.getAdditionalArgumentsPropertyName())); + + form.addCustomOptions( + ObjectArrays.concat(customOptions, new CustomOption(PyUniversalTestsKt.getAdditionalArgumentsPropertyName(), TestTargetType.values())) + ); configuration.copyTo(ReflectionUtilsKt.getProperties(form, null, true)); return form; } private void addCustomOptions(@NotNull - final String... optionNames) { - if (optionNames.length == 0) { + final CustomOption... customOptions) { + if (customOptions.length == 0) { return; } - for (final String optionName : optionNames) { + final Map optionValueFields = new HashMap<>(); + for (final CustomOption option : customOptions) { final JBTextField textField = new JBTextField(); - myCustomOptions.put(optionName, textField); + optionValueFields.put(option.myName, textField); } - myCustomOptionsPanel.setLayout(new GridLayoutManager(optionNames.length, 2)); + myCustomOptionsPanel.setLayout(new GridLayoutManager(customOptions.length, 2)); - for (int i = 0; i < optionNames.length; i++) { - final String optionName = optionNames[i]; - final JBTextField textField = myCustomOptions.get(optionName); + for (int i = 0; i < customOptions.length; i++) { + final CustomOption option = customOptions[i]; + final JBTextField textField = optionValueFields.get(option.myName); final GridConstraints labelConstraints = new GridConstraints(); labelConstraints.setFill(GridConstraints.FILL_VERTICAL); @@ -161,7 +165,7 @@ public final class PyUniversalTestForm implements SimplePropertiesProvider { labelConstraints.setColumn(0); labelConstraints.setHSizePolicy(GridConstraints.SIZEPOLICY_CAN_SHRINK); - final JLabel label = new JLabel(StringUtil.capitalize(CAPITAL_LETTER.matcher(optionName).replaceAll(" "))); + final JLabel label = new JLabel(StringUtil.capitalize(CAPITAL_LETTER.matcher(option.myName).replaceAll(" "))); label.setHorizontalAlignment(SwingConstants.LEFT); myCustomOptionsPanel.add(label, labelConstraints); @@ -172,6 +176,8 @@ public final class PyUniversalTestForm implements SimplePropertiesProvider { textConstraints.setColumn(1); textConstraints.setHSizePolicy(GridConstraints.SIZEPOLICY_CAN_GROW); myCustomOptionsPanel.add(textField, textConstraints); + + myCustomOptions.put(option.myName, new OptionHolder(option, label, textField)); } } @@ -198,6 +204,10 @@ public final class PyUniversalTestForm implements SimplePropertiesProvider { final TestTargetType targetType = getTargetType(); myTargetText.setVisible(targetType != TestTargetType.CUSTOM); myTargetText.getButton().setVisible(targetType == TestTargetType.PATH); + + for (final OptionHolder optionHolder : myCustomOptions.values()) { + optionHolder.setType(targetType); + } } @SuppressWarnings("WeakerAccess") // Accessor for property @@ -219,4 +229,51 @@ public final class PyUniversalTestForm implements SimplePropertiesProvider { } configureElementsVisibility(); } + + static final class CustomOption { + /** + * Option name + */ + @NotNull + private final String myName; + /** + * Types to display this option for + */ + private final EnumSet mySupportedTypes; + + CustomOption(@NotNull + final String name, + @NotNull + final TestTargetType... supportedTypes) { + myName = name; + mySupportedTypes = EnumSet.copyOf(Arrays.asList(supportedTypes)); + } + } + + private static final class OptionHolder { + @NotNull + private final CustomOption myOption; + @NotNull + private final JLabel myOptionLabel; + @NotNull + private final JTextField myOptionValue; + + private OptionHolder(@NotNull + final CustomOption option, + @NotNull + final JLabel optionLabel, + @NotNull + final JTextField optionValue) { + myOption = option; + myOptionLabel = optionLabel; + myOptionValue = optionValue; + } + + private void setType(@NotNull + final TestTargetType type) { + final boolean visible = myOption.mySupportedTypes.contains(type); + myOptionLabel.setVisible(visible); + myOptionValue.setVisible(visible); + } + } } \ No newline at end of file diff --git a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTestLegacyInterop.kt b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTestLegacyInterop.kt index 62d7dd26cdf3..384b19d9f050 100644 --- a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTestLegacyInterop.kt +++ b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalTestLegacyInterop.kt @@ -243,13 +243,13 @@ private class LegacyConfigurationManagerPyTest(newConfig: PyUniversalPyTestConfi } } -//TODO: Support "pattern" field for unittest private class LegacyConfigurationManagerUnit(newConfig: PyUniversalUnitTestConfiguration) : LegacyConfigurationManager( PythonTestConfigurationType.getInstance().LEGACY_UNITTEST_FACTORY, newConfig) { override fun copyFromLegacy() { super.copyFromLegacy() newConfig.additionalArguments = legacyConfig.params + newConfig.pattern = legacyConfig.pattern } } diff --git a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalUnitTest.kt b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalUnitTest.kt index 8ccf4c21e863..2c5685e8734c 100644 --- a/python/src/com/jetbrains/python/testing/universalTests/PyUniversalUnitTest.kt +++ b/python/src/com/jetbrains/python/testing/universalTests/PyUniversalUnitTest.kt @@ -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.openapi.vfs.LocalFileSystem import com.jetbrains.python.PythonHelper import com.jetbrains.python.testing.PythonTestConfigurationsModel @@ -29,9 +30,11 @@ import com.jetbrains.python.testing.PythonTestConfigurationsModel * unittest */ -//TODO: Support pattern class PyUniversalUnitTestSettingsEditor(configuration: PyUniversalTestConfiguration) : - PyUniversalTestSettingsEditor(PyUniversalTestForm.create(configuration)) + PyUniversalTestSettingsEditor( + PyUniversalTestForm.create(configuration, + PyUniversalTestForm.CustomOption(PyUniversalUnitTestConfiguration::pattern.name, TestTargetType.PATH) + )) class PyUniversalUnitTestExecutionEnvironment(configuration: PyUniversalUnitTestConfiguration, environment: ExecutionEnvironment) : PyUniversalTestExecutionEnvironment(configuration, environment) { @@ -41,12 +44,26 @@ class PyUniversalUnitTestExecutionEnvironment(configuration: PyUniversalUnitTest class PyUniversalUnitTestConfiguration(project: Project, factory: PyUniversalUnitTestFactory) : PyUniversalTestConfiguration(project, factory, runBareFunctions = false) { // Bare functions not supported in unittest: classes only + @ConfigField + var pattern: String? = null + override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? = PyUniversalUnitTestExecutionEnvironment(this, environment) override fun createConfigurationEditor(): SettingsEditor = PyUniversalUnitTestSettingsEditor(this) + override fun getCustomRawArgumentsString(): String { + // Pattern can only be used with folders ("all in folder" in legacy terms) + if ((!pattern.isNullOrEmpty()) && target.targetType != TestTargetType.CUSTOM) { + val path = LocalFileSystem.getInstance().findFileByPath(target.target) ?: return "" + return if (path.isDirectory) "-p $pattern" else "" + } + else { + return "" + } + + } } object PyUniversalUnitTestFactory : PyUniversalTestFactory() {