diff --git a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfiguration.kt b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfiguration.kt index 208e86fe..936033e1 100644 --- a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfiguration.kt +++ b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfiguration.kt @@ -1,9 +1,9 @@ package dev.robotcode.robotcode4ij.execution import com.intellij.execution.Executor +import com.intellij.execution.configuration.EnvironmentVariablesData import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.execution.configurations.LocatableConfigurationBase -import com.intellij.execution.configurations.RunConfiguration import com.intellij.execution.configurations.RunProfileState import com.intellij.execution.runners.ExecutionEnvironment import com.intellij.execution.testframework.sm.runner.SMRunnerConsolePropertiesProvider @@ -17,32 +17,49 @@ class RobotCodeRunConfiguration(project: Project, factory: ConfigurationFactory) LocatableConfigurationBase (project, factory, "Robot Framework"), SMRunnerConsolePropertiesProvider { - override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState { - return RobotCodeRunProfileState(this, environment) - } + // Environment variables + var environmentVariables: EnvironmentVariablesData = EnvironmentVariablesData.DEFAULT - override fun getConfigurationEditor(): SettingsEditor { - // TODO: Implement configuration editor - return RobotCodeRunConfigurationEditor() - } + // Variables + var variables: String? = null + + // Test suite path + var testSuitePath: String? = null - var includedTestItems: List = emptyList() + // Additional arguments + var additionalArguments: String? = null - var paths: List = emptyList() + var includedTestItems: String? = null + + override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState { + return RobotCodeRunProfileState(this, environment) + } override fun createTestConsoleProperties(executor: Executor): SMTRunnerConsoleProperties { return RobotRunnerConsoleProperties(this, "Robot Framework", executor) } + override fun getConfigurationEditor(): SettingsEditor { + return RobotCodeRunConfigurationEditor(project) + } + override fun writeExternal(element: Element) { super.writeExternal(element) - // TODO: Implement serialization - // XmlSerializer.serializeInto(this, element) + // Save data to XML + environmentVariables.writeExternal(element) + element.setAttribute("testitems", includedTestItems ?: "") + element.setAttribute("variables", variables ?: "") + element.setAttribute("testSuitePath", testSuitePath ?: "") + element.setAttribute("additionalArguments", additionalArguments ?: "") } override fun readExternal(element: Element) { super.readExternal(element) - // TODO: Implement deserialization - // XmlSerializer.deserializeInto(this, element) + // Read data from XML + environmentVariables = EnvironmentVariablesData.readExternal(element) + variables = element.getAttributeValue("variables") + testSuitePath = element.getAttributeValue("testSuitePath") + additionalArguments = element.getAttributeValue("additionalArguments") + includedTestItems = element.getAttributeValue("testitems") } } diff --git a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfigurationEditor.kt b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfigurationEditor.kt index 5fe189ad..6bb3b76f 100644 --- a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfigurationEditor.kt +++ b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfigurationEditor.kt @@ -1,17 +1,43 @@ package dev.robotcode.robotcode4ij.execution import com.intellij.execution.configuration.EnvironmentVariablesComponent +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.options.SettingsEditor +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.TextFieldWithBrowseButton +import com.intellij.ui.CheckBoxList import com.intellij.ui.RawCommandLineEditor import com.intellij.ui.dsl.builder.AlignX import com.intellij.ui.dsl.builder.panel import com.intellij.util.ui.ComponentWithEmptyText +import dev.robotcode.robotcode4ij.testing.testManger import javax.swing.JComponent +import javax.swing.JScrollPane -class RobotCodeRunConfigurationEditor : SettingsEditor() { +class RobotCodeRunConfigurationEditor(private val project: Project) : SettingsEditor() { private val environmentVariablesField = EnvironmentVariablesComponent() + private val variablesField = + RawCommandLineEditor().apply { + if (textField is ComponentWithEmptyText) { + (textField as ComponentWithEmptyText).emptyText.text = "Define variables, e.g. VAR1=value1, VAR2=value2" + } + } + + private val includedTestItemsField = CheckBoxList().apply { + toolTipText = "Select test items to include in the configuration." + } + + private val testSuitePathField = TextFieldWithBrowseButton().apply { + addBrowseFolderListener( + project, + FileChooserDescriptorFactory.createSingleFileDescriptor() + .withTitle("Select Test Suite") + .withDescription("Select the path to the test suite") + ) + } + private val argumentsField = RawCommandLineEditor().apply { if (textField is ComponentWithEmptyText) { @@ -21,23 +47,66 @@ class RobotCodeRunConfigurationEditor : SettingsEditor + includedTestItemsField.addItem(item, item, selectedItems.contains(item)) + } } override fun applyEditorTo(s: RobotCodeRunConfiguration) { - // TODO("Not yet implemented") + // Apply the environment variables field + s.environmentVariables = environmentVariablesField.envData + + // Apply the variables field + s.variables = variablesField.text.ifBlank { null } + + // Apply the test suite path field + s.testSuitePath = testSuitePathField.text.ifBlank { null } + + // Apply the additional arguments field + s.additionalArguments = argumentsField.text.ifBlank { null } + + // Apply the included test items field + s.includedTestItems = includedTestItemsField.checkedItems.joinToString(",") } override fun createEditor(): JComponent { + val testItems = project.testManger.flattenTestItemLongNames() + includedTestItemsField.clear() + testItems.forEach { item -> + includedTestItemsField.addItem(item, item, false) // Initially unselected + } return panel { - row("&Robot:") { - textField().label("Suite:") + row("Test Suite Path:") { + cell(testSuitePathField).align(AlignX.FILL) + } + row("Included Test Items:") { + cell(JScrollPane(includedTestItemsField)).align(AlignX.FILL) } - row(environmentVariablesField.label) { + row("Environment Variables:") { cell(environmentVariablesField.component).align(AlignX.FILL) } - row("A&rguments:") { cell(argumentsField).align(AlignX.FILL) } + row("Variables:") { + cell(variablesField).align(AlignX.FILL) + } + row("Additional Arguments:") { + cell(argumentsField).align(AlignX.FILL) + } } } - } diff --git a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfigurationProducer.kt b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfigurationProducer.kt index 6b00e560..8714aa5a 100644 --- a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfigurationProducer.kt +++ b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/execution/RobotCodeRunConfigurationProducer.kt @@ -40,7 +40,7 @@ class RobotCodeRunConfigurationProducer : LazyRunConfigurationProducer() - for (test in profile.includedTestItems) { - included.add("-bl") - included.add(test.longname) + + if (testSuitePath != null){ + val testitem = profile.project.testManger.findTestItem(Path(testSuitePath).toUri().toString()) + if (testitem != null) { + included.add("-bl") + included.add(testitem.longname) + } + } + if (!profile.includedTestItems.isNullOrEmpty()) { + val testItemLongNames = profile.includedTestItems!!.split(",").map { it.trim() }.filter { it.isNotEmpty() } + for (testItemLongName in testItemLongNames){ + included.add("-bl") + included.add(testItemLongName) + } } val connection = mutableListOf() - val port = findFreePort(DEBUGGER_DEFAULT_PORT) if (port != DEBUGGER_DEFAULT_PORT) { included.add("--tcp") included.add(port.toString()) } + // Combine all parts into the final command line val commandLine = project.buildRobotCodeCommandLine( arrayOf( *defaultPaths, "debug", *connection.toTypedArray(), *(if (!debug) arrayOf("--no-debug") else arrayOf()), - *(included.toTypedArray()) - ), noColor = false // ,extraArgs = arrayOf("-v", "--log", "--log-level", "TRACE") + *included.toTypedArray(), + *variables, + *additionalArguments + ), + noColor = false + ) + + // Apply environment variables + val environmentVariables = profile.environmentVariables.envs + for ((key, value) in environmentVariables) { + commandLine.environment[key] = value + } + // Apply "passParentEnvironment" if set to false + commandLine.withParentEnvironmentType( + if (profile.environmentVariables.isPassParentEnvs) { + GeneralCommandLine.ParentEnvironmentType.CONSOLE + } else { + GeneralCommandLine.ParentEnvironmentType.NONE + } ) - val handler = KillableColoredProcessHandler(commandLine) // handler.setHasPty(true) + val handler = KillableColoredProcessHandler(commandLine) handler.putUserData(DEBUG_PORT, port) ProcessTerminatedListener.attach(handler) handler.addProcessListener(this) - // RunContentManager.getInstance(project).showRunContent(environment.executor, handler) - return handler } @@ -142,8 +183,8 @@ class RobotCodeRunProfileState(private val config: RobotCodeRunConfiguration, en consoleProperties.state = this } - var splitterPropertyName = SMTestRunnerConnectionUtil.getSplitterPropertyName(TESTFRAMEWORK_NAME) - var consoleView = RobotCodeRunnerConsoleView(consoleProperties, splitterPropertyName) + val splitterPropertyName = SMTestRunnerConnectionUtil.getSplitterPropertyName(TESTFRAMEWORK_NAME) + val consoleView = RobotCodeRunnerConsoleView(consoleProperties, splitterPropertyName) SMTestRunnerConnectionUtil.initConsoleView(consoleView, TESTFRAMEWORK_NAME) consoleView.attachToProcess(processHandler) consoleRef.set(consoleView) @@ -192,7 +233,7 @@ class RobotCodeRunProfileState(private val config: RobotCodeRunConfiguration, en @OptIn(ExperimentalUuidApi::class) override fun startNotified(event: ProcessEvent) { runBlocking(Dispatchers.IO) { - var port = event.processHandler.getUserData(DEBUG_PORT) ?: throw CantRunException("No debug port found.") + val port = event.processHandler.getUserData(DEBUG_PORT) ?: throw CantRunException("No debug port found.") socket = tryConnectToServerWithTimeout("127.0.0.1", port, 10000, retryIntervalMillis = 100) ?: throw CantRunException("Unable to establish connection to debug server.") @@ -232,7 +273,7 @@ class RobotCodeRunProfileState(private val config: RobotCodeRunConfiguration, en } afterConfigurationDone.fire(Unit) - debugServer.attach(emptyMap()) + debugServer.attach(emptyMap()) } } diff --git a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/testing/RobotCodeTestManager.kt b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/testing/RobotCodeTestManager.kt index 5b32d2f1..7b9ab3ce 100644 --- a/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/testing/RobotCodeTestManager.kt +++ b/intellij-client/src/main/kotlin/dev/robotcode/robotcode4ij/testing/RobotCodeTestManager.kt @@ -36,7 +36,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import java.nio.file.Paths @@ -333,6 +332,16 @@ import java.util.* val result = findTestItem(containingFile.virtualFile.uri, lineNumber.toUInt()) return result } + + fun flattenTestItemLongNames(): List { + return flattenLongNames(testItems) + } + + private fun flattenLongNames(items: Array?): List{ + return items?.flatMap { item -> + listOf(item.longname) + flattenLongNames(item.children) + } ?: emptyList() + } } private fun getRfcCompliantUri(virtualFile: VirtualFile): String {