Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/kotlin/io/kotest/plugin/intellij/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Constants {
// kotst 4.1.x -> 4.6.x protocol string
val OldLocatorProtocol = "kotest"
val FrameworkId = "ioKotest"

val gradleTaskName = "kotest"
}

// flip this bit in tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.configurations.ConfigurationType
import com.intellij.execution.configurations.RunConfiguration
import com.intellij.openapi.project.Project
import io.kotest.plugin.intellij.run.KotestRunConfiguration

class KotestConfigurationFactory(configurationType: ConfigurationType) : ConfigurationFactory(configurationType) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsActi
import com.intellij.execution.testframework.sm.runner.SMTestLocator
import com.intellij.execution.ui.ConsoleView
import com.intellij.psi.search.GlobalSearchScope
import io.kotest.plugin.intellij.run.KotestRunConfiguration

@Deprecated("Migrating to Kotest external system runner")
class KotestTestConsoleProperties(
config: KotestRunConfiguration,
executor: Executor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.kotest.plugin.intellij
import com.intellij.execution.Location
import com.intellij.execution.PsiLocation
import com.intellij.execution.testframework.sm.runner.SMTestLocator
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.PsiElement
Expand All @@ -23,7 +24,7 @@ import io.kotest.plugin.intellij.psi.toPsiLocation
*
* Kotest 4 reported it's located hints as kotest://class:linenumber
*/
class KotestTestLocator : SMTestLocator {
class KotestTestLocator : SMTestLocator, DumbAware {

override fun getLocation(
protocol: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.execution.testframework.SourceScope
import com.intellij.execution.ui.ConsoleView
import com.intellij.openapi.module.Module
import io.kotest.plugin.intellij.run.KotestRunConfiguration
import io.kotest.plugin.intellij.run.KotestRunnableState

class RerunFailedTestsAction(consoleView: ConsoleView,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import io.kotest.plugin.intellij.KotestConfigurationFactory
import io.kotest.plugin.intellij.KotestConfigurationType
import io.kotest.plugin.intellij.KotestRunConfiguration
import io.kotest.plugin.intellij.run.KotestRunConfiguration
import io.kotest.plugin.intellij.run.generateName
import io.kotest.plugin.intellij.toolwindow.ModuleNodeDescriptor
import io.kotest.plugin.intellij.toolwindow.SpecNodeDescriptor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigu
/**
* Shows a gradle run icon if the test runner is set to gradle or choose per test.
*/
@Deprecated("Migrating to Kotest specific tasks")
class GradleSpecRunConfigurationProducer : TestClassGradleConfigurationProducer() {

override fun getPsiClassForLocation(contextLocation: Location<*>): PsiClass? {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package io.kotest.plugin.intellij.run

import com.intellij.execution.JavaRunConfigurationExtensionManager
import com.intellij.execution.RunManager
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.execution.actions.ConfigurationFromContext
import com.intellij.execution.actions.RunConfigurationProducer
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.openapi.module.Module
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement
import io.kotest.plugin.intellij.Constants
import io.kotest.plugin.intellij.Test
import io.kotest.plugin.intellij.psi.enclosingKtClass
import io.kotest.plugin.intellij.styles.SpecStyle
import org.jetbrains.plugins.gradle.execution.GradleRunnerUtil
import org.jetbrains.plugins.gradle.execution.build.CachedModuleDataFinder
import org.jetbrains.plugins.gradle.service.execution.GradleExternalTaskConfigurationType
import org.jetbrains.plugins.gradle.service.execution.GradleRunConfiguration
import org.jetbrains.plugins.gradle.service.project.GradleTasksIndices
import org.jetbrains.plugins.gradle.util.GradleModuleData

/**
* Runs a Kotest individual test using the Kotest custom gradle task.
*/
class GradleTestRunConfigurationProducer : RunConfigurationProducer<GradleRunConfiguration>(true) {

override fun getConfigurationFactory(): ConfigurationFactory {
return GradleExternalTaskConfigurationType.getInstance().factory
}

/**
* When two configurations are created from the same context by two different producers, checks if the configuration created by
* this producer should be discarded in favor of the other one.
*
* We always return true because no one else should be creating Kotest configurations.
*/
override fun isPreferredConfiguration(self: ConfigurationFromContext?, other: ConfigurationFromContext?): Boolean {
return true
}

override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean {
return false
}

/**
* This function is called to check if the given context is applicable to this run producer as
* well as configure the configuration based on the template.
*
* In other words, it's used to determine if this run producer should act on the run context that
* was initialized by the user. In our case, we want to act when the user clicks run on a test case.
*/
override fun setupConfigurationFromContext(
configuration: GradleRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>
): Boolean {

if (!hasKotestTask(context.module)) return false

val element = sourceElement.get()
if (element != null) {
val test = findTest(element)
if (test != null) {

val spec = element.enclosingKtClass() ?: return false
val fqn = spec.fqName ?: return false

val project = context.project ?: return false
val module = context.module ?: return false

val externalProjectPath = resolveProjectPath(module) ?: return false
val location = context.location ?: return false

val gradleModuleData = CachedModuleDataFinder.getGradleModuleData(module) ?: return false
val path = gradleModuleData.getTaskPath(Constants().gradleTaskName)

configuration.name = generateName(spec, test)
configuration.setDebugServerProcess(false)

val runManager = RunManager.getInstance(project)
runManager.setUniqueNameIfNeeded(configuration)

configuration.settings.externalProjectPath = externalProjectPath
configuration.settings.taskNames =
listOf(
path,
"--tests '${fqn.asString()}'"
)
configuration.settings.scriptParameters = ""

JavaRunConfigurationExtensionManager.instance.extendCreatedConfiguration(configuration, location)
return true
}
}
return false
}

private fun hasKotestTask(module: Module): Boolean {
val externalProjectPath = resolveProjectPath(module) ?: return false
return GradleTasksIndices.getInstance(module.project)
.findTasks(externalProjectPath)
.any { it.name.endsWith(Constants().gradleTaskName) }
}

/**
* This function is called to check if the given configuration should be re-used.
* This stops a new context being created every time the user runs the same test.
*/
override fun isConfigurationFromContext(
configuration: GradleRunConfiguration,
context: ConfigurationContext
): Boolean {

if (!hasKotestTask(context.module)) return false

val element = context.psiLocation
if (element != null) {
val test = findTest(element)
if (test != null) {
val spec = element.enclosingKtClass()
return false

// return configuration.getTestPath() == test.testPath()
// && configuration.getPackageName().isNullOrBlank()
// && configuration.getSpecName() == spec?.fqName?.asString()
}
}
return false
}

private fun findTest(element: PsiElement): Test? {
return SpecStyle.styles.asSequence()
.filter { it.isContainedInSpec(element) }
.mapNotNull { it.findAssociatedTest(element) }
.firstOrNull()
}

private fun resolveProjectPath(module: Module): String? {
val gradleModuleData: GradleModuleData = CachedModuleDataFinder.getGradleModuleData(module) ?: return null
val isGradleProjectDirUsedToRunTasks = gradleModuleData.directoryToRunTask == gradleModuleData.gradleProjectDir
if (!isGradleProjectDirUsedToRunTasks) {
return gradleModuleData.directoryToRunTask
}
return GradleRunnerUtil.resolveProjectPath(module)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.kotest.plugin.intellij.run

import com.intellij.execution.Executor
import com.intellij.execution.Location
import com.intellij.execution.testframework.JavaAwareTestConsoleProperties
import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties
import com.intellij.execution.testframework.sm.runner.SMTestLocator
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration
import com.intellij.pom.Navigatable
import io.kotest.plugin.intellij.KotestTestLocator
import javax.swing.tree.TreeSelectionModel

class KotestConsoleProperties(conf: ExternalSystemRunConfiguration, executor: Executor) :
SMTRunnerConsoleProperties(conf, "kotest", executor) {
override fun getTestLocator(): SMTestLocator = KotestTestLocator()
override fun isIdBasedTestTree(): Boolean = true
override fun isEditable(): Boolean = true
override fun isPrintTestingStartedTime(): Boolean = true
override fun getSelectionMode(): Int = TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION
override fun getErrorNavigatable(location: Location<*>, stacktrace: String): Navigatable? {
return JavaAwareTestConsoleProperties.getStackTraceErrorNavigatable(location, stacktrace)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package io.kotest.plugin.intellij.run
import com.intellij.execution.JavaTestFrameworkDebuggerRunner
import com.intellij.execution.configurations.RunProfile
import io.kotest.plugin.intellij.Constants
import io.kotest.plugin.intellij.KotestRunConfiguration

@Deprecated("Migrating to Kotest external system runner")
class KotestDebuggerRunner : JavaTestFrameworkDebuggerRunner() {

override fun validForProfile(profile: RunProfile): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@file:Suppress("RedundantOverride")

package io.kotest.plugin.intellij
package io.kotest.plugin.intellij.run

import com.intellij.execution.AlternativeJrePathConverter
import com.intellij.execution.Executor
Expand All @@ -24,14 +24,13 @@ import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.refactoring.listeners.RefactoringElementListener
import io.kotest.plugin.intellij.run.KotestRunnableState
import io.kotest.plugin.intellij.run.RunData
import io.kotest.plugin.intellij.run.suggestedName
import io.kotest.plugin.intellij.KotestTestConsoleProperties
import io.kotest.plugin.intellij.ui.KotestSettingsEditor
import org.jdom.Element
import org.jetbrains.jps.model.serialization.PathMacroUtil
import org.jetbrains.kotlin.psi.KtClassOrObject

@Deprecated("Migrating to Kotest external system runner")
class KotestRunConfiguration(name: String, factory: ConfigurationFactory, project: Project) :
JavaTestConfigurationBase(name, JavaRunConfigurationModule(project, false), factory),
TargetEnvironmentAwareRunProfile {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.kotest.plugin.intellij.run

class KotestRunConfigurationProducer {
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import com.intellij.execution.testframework.TestSearchScope
import com.intellij.openapi.module.Module
import com.intellij.util.PathUtil
import io.kotest.plugin.intellij.Constants
import io.kotest.plugin.intellij.KotestRunConfiguration
import java.io.File

class KotestRunnableState(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.kotest.plugin.intellij.run

import com.intellij.build.BuildViewSettingsProvider
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView
import com.intellij.execution.ui.ConsoleViewContentType

class KotestSMTRunnerConsoleView(
consoleProperties: KotestConsoleProperties,
splitterPropertyName: String
) : SMTRunnerConsoleView(consoleProperties, splitterPropertyName), BuildViewSettingsProvider {

private var lastMessageWasEmptyLine = false

override fun isExecutionViewHidden() = true

override fun print(s: String, contentType: ConsoleViewContentType) {
if (detectUnwantedEmptyLine(s)) return;
super.print(s, contentType);
}

// IJ test runner events protocol produces many unwanted empty strings
// this is a workaround to avoid the trash in the console
private fun detectUnwantedEmptyLine(s: String): Boolean {
if (com.intellij.execution.Platform.current().lineSeparator == s) {
if (lastMessageWasEmptyLine) return true
lastMessageWasEmptyLine = true
} else {
lastMessageWasEmptyLine = false
}
return false
}
}
Loading
Loading